use std::fmt::Write; use crate::{editor::Config, graphics::Style, Document, Theme, View}; pub type GutterFn<'doc> = Box<dyn Fn(usize, bool, &mut String) -> Option<Style> + 'doc>; pub type Gutter = for<'doc> fn(&'doc Document, &View, &Theme, &Config, bool, usize) -> GutterFn<'doc>; pub fn diagnostic<'doc>( doc: &'doc Document, _view: &View, theme: &Theme, _config: &Config, _is_focused: bool, _width: usize, ) -> GutterFn<'doc> { let warning = theme.get("warning"); let error = theme.get("error"); let info = theme.get("info"); let hint = theme.get("hint"); let diagnostics = doc.diagnostics(); Box::new(move |line: usize, _selected: bool, out: &mut String| { use helix_core::diagnostic::Severity; if let Ok(index) = diagnostics.binary_search_by_key(&line, |d| d.line) { let diagnostic = &diagnostics[index]; write!(out, "●").unwrap(); return Some(match diagnostic.severity { Some(Severity::Error) => error, Some(Severity::Warning) | None => warning, Some(Severity::Info) => info, Some(Severity::Hint) => hint, }); } None }) } pub fn line_number<'doc>( doc: &'doc Document, view: &View, theme: &Theme, config: &Config, is_focused: bool, width: usize, ) -> GutterFn<'doc> { let text = doc.text().slice(..); let last_line = view.last_line(doc); // Whether to draw the line number for the last line of the // document or not. We only draw it if it's not an empty line. let draw_last = text.line_to_byte(last_line) < text.len_bytes(); let linenr = theme.get("ui.linenr"); let linenr_select: Style = theme.try_get("ui.linenr.selected").unwrap_or(linenr); let current_line = doc .text() .char_to_line(doc.selection(view.id).primary().cursor(text)); let config = config.line_number; Box::new(move |line: usize, selected: bool, out: &mut String| { if line == last_line && !draw_last { write!(out, "{:>1$}", '~', width).unwrap(); Some(linenr) } else { use crate::editor::LineNumber; let line = match config { LineNumber::Absolute => line + 1, LineNumber::Relative => { if current_line == line { line + 1 } else { abs_diff(current_line, line) } } }; let style = if selected && is_focused { linenr_select } else { linenr }; write!(out, "{:>1$}", line, width).unwrap(); Some(style) } }) } #[inline(always)] const fn abs_diff(a: usize, b: usize) -> usize { if a > b { a - b } else { b - a } }