@@ -38,8 +38,6 @@ pub struct EditorView {
38 autoinfo: Option<Info>,
38 autoinfo: Option<Info>,
41−pub const GUTTER_OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
43impl Default for EditorView {
41impl Default for EditorView {
44 fn default() -> Self {
42 fn default() -> Self {
45 Self::new(Keymaps::default())
43 Self::new(Keymaps::default())
@@ -74,15 +72,10 @@ impl EditorView {
74 loader: &syntax::Loader,
72 loader: &syntax::Loader,
75 config: &helix_view::editor::Config,
73 config: &helix_view::editor::Config,
77− let area = Rect::new(
75+ let inner = view.inner_area();
78− view.area.x + GUTTER_OFFSET,
76+ let area = view.area;
80− view.area.width - GUTTER_OFFSET,
81− view.area.height.saturating_sub(1),
82− ); // - 1 for statusline
83− let height = view.area.height.saturating_sub(1); // - 1 for statusline
85− let highlights = Self::doc_syntax_highlights(doc, view.offset, height, theme, loader);
78+ let highlights = Self::doc_syntax_highlights(doc, view.offset, inner.height, theme, loader);
86 let highlights = syntax::merge(highlights, Self::doc_diagnostics_highlights(doc, theme));
79 let highlights = syntax::merge(highlights, Self::doc_diagnostics_highlights(doc, theme));
87 let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused {
80 let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused {
88 Box::new(syntax::merge(
81 Box::new(syntax::merge(
@@ -93,11 +86,11 @@ impl EditorView {
93 Box::new(highlights)
86 Box::new(highlights)
96− Self::render_text_highlights(doc, view.offset, area, surface, theme, highlights);
89+ Self::render_text_highlights(doc, view.offset, inner, surface, theme, highlights);
97− Self::render_gutter(doc, view, area, surface, theme, config);
90+ Self::render_gutter(doc, view, view.area, surface, theme, is_focused, config);
99 if is_focused {
92 if is_focused {
100− Self::render_focused_view_elements(view, doc, area, theme, surface);
93+ Self::render_focused_view_elements(view, doc, inner, theme, surface);
103 // if we're not at the edge of the screen, draw a right border
96 // if we're not at the edge of the screen, draw a right border
@@ -113,7 +106,7 @@ impl EditorView {
116− self.render_diagnostics(doc, view, area, surface, theme);
109+ self.render_diagnostics(doc, view, inner, surface, theme);
118 let area = Rect::new(
111 let area = Rect::new(
119 view.area.x,
112 view.area.x,
@@ -369,7 +362,7 @@ impl EditorView {
372− /// Render brace match, selected line numbers, etc (meant for the focused view only)
365+ /// Render brace match, etc (meant for the focused view only)
373 pub fn render_focused_view_elements(
366 pub fn render_focused_view_elements(
374 view: &View,
367 view: &View,
375 doc: &Document,
368 doc: &Document,
@@ -377,77 +370,29 @@ impl EditorView {
377 theme: &Theme,
370 theme: &Theme,
378 surface: &mut Surface,
371 surface: &mut Surface,
373+ // Highlight matching braces
374+ if let Some(syntax) = doc.syntax() {
380− let text = doc.text().slice(..);
375+ let text = doc.text().slice(..);
376+ use helix_core::match_brackets;
381− let selection = doc.selection(view.id);
377+ let pos = doc.selection(view.id).primary().cursor(text);
382− let last_line = view.last_line(doc);
378+
383− let screen = {
379+ let pos = match_brackets::find(syntax, doc.text(), pos)
384− let start = text.line_to_char(view.offset.row);
380+ .and_then(|pos| view.screen_coords_at_pos(doc, text, pos));
385− let end = text.line_to_char(last_line + 1) + 1; // +1 for cursor at end of text.
381+
386− Range::new(start, end)
382+ if let Some(pos) = pos {
387− };
383+ // ensure col is on screen
388−
384+ if (pos.col as u16) < viewport.width + view.offset.col as u16
389− // render selected linenr(s)
385+ && pos.col >= view.offset.col
390− let linenr_select: Style = theme
386+ {
391− .try_get("ui.linenr.selected")
387+ let style = theme.try_get("ui.cursor.match").unwrap_or_else(|| {
392− .unwrap_or_else(|| theme.get("ui.linenr"));
388+ Style::default()
393−
389+ .add_modifier(Modifier::REVERSED)
394− // Whether to draw the line number for the last line of the
390+ .add_modifier(Modifier::DIM)
395− // document or not. We only draw it if it's not an empty line.
396− let draw_last = text.line_to_byte(last_line) < text.len_bytes();
398− for selection in selection.iter().filter(|range| range.overlaps(&screen)) {
399− let head = view.screen_coords_at_pos(
402− if selection.head > selection.anchor {
408− if let Some(head) = head {
409− // Highlight line number for selected lines.
410− let line_number = view.offset.row + head.row;
411− let line_number_text = if line_number == last_line && !draw_last {
414− format!("{:>5}", line_number + 1)
416− surface.set_stringn(
417− viewport.x - GUTTER_OFFSET + 1,
418− viewport.y + head.row as u16,
424− // Highlight matching braces
425− // TODO: set cursor position for IME
426− if let Some(syntax) = doc.syntax() {
427− use helix_core::match_brackets;
431− .cursor(doc.text().slice(..));
432− let pos = match_brackets::find(syntax, doc.text(), pos)
433− .and_then(|pos| view.screen_coords_at_pos(doc, text, pos));
435− if let Some(pos) = pos {
436− // ensure col is on screen
437− if (pos.col as u16) < viewport.width + view.offset.col as u16
438− && pos.col >= view.offset.col
440− let style = theme.try_get("ui.cursor.match").unwrap_or_else(|| {
442− .add_modifier(Modifier::REVERSED)
443− .add_modifier(Modifier::DIM)
447− .get_mut(viewport.x + pos.col as u16, viewport.y + pos.row as u16)
394+ .get_mut(viewport.x + pos.col as u16, viewport.y + pos.row as u16)
448− .set_style(style);
395+ .set_style(style);
@@ -460,12 +405,15 @@ impl EditorView {
460 viewport: Rect,
405 viewport: Rect,
461 surface: &mut Surface,
406 surface: &mut Surface,
462 theme: &Theme,
407 theme: &Theme,
463 config: &helix_view::editor::Config,
409 config: &helix_view::editor::Config,
465 let text = doc.text().slice(..);
411 let text = doc.text().slice(..);
466 let last_line = view.last_line(doc);
412 let last_line = view.last_line(doc);
468 let linenr = theme.get("ui.linenr");
414 let linenr = theme.get("ui.linenr");
415+ let linenr_select: Style = theme.try_get("ui.linenr.selected").unwrap_or(linenr);
469 let warning = theme.get("warning");
417 let warning = theme.get("warning");
470 let error = theme.get("error");
418 let error = theme.get("error");
471 let info = theme.get("info");
419 let info = theme.get("info");
@@ -478,11 +426,21 @@ impl EditorView {
478 let current_line = doc
426 let current_line = doc
480 .char_to_line(doc.selection(view.id).primary().anchor);
428 .char_to_line(doc.selection(view.id).primary().anchor);
430+ // it's used inside an iterator so the collect isn't needless:
431+ // https://github.com/rust-lang/rust-clippy/issues/6164
432+ #[allow(clippy::clippy::needless_collect)]
433+ let cursors: Vec<_> = doc
436+ .map(|range| range.cursor_line(text))
481 for (i, line) in (view.offset.row..(last_line + 1)).enumerate() {
439 for (i, line) in (view.offset.row..(last_line + 1)).enumerate() {
482 use helix_core::diagnostic::Severity;
440 use helix_core::diagnostic::Severity;
483 if let Some(diagnostic) = doc.diagnostics().iter().find(|d| d.line == line) {
441 if let Some(diagnostic) = doc.diagnostics().iter().find(|d| d.line == line) {
484 surface.set_stringn(
442 surface.set_stringn(
485− viewport.x - GUTTER_OFFSET,
443+ viewport.x,
486 viewport.y + i as u16,
444 viewport.y + i as u16,
@@ -495,25 +453,27 @@ impl EditorView {
498− // Line numbers having selections are rendered
456+ let selected = cursors.contains(&line);
499− // differently, further below.
457+
500− let line_number_text = if line == last_line && !draw_last {
458+ let text = if line == last_line && !draw_last {
501 " ~".into()
459 " ~".into()
503− match config.line_number {
461+ let line = match config.line_number {
504− LineNumber::Absolute => format!("{:>5}", line + 1),
462+ LineNumber::Absolute => line + 1,
505− LineNumber::Relative => {
463+ LineNumber::Relative => abs_diff(current_line, line),
506− let relative_line = abs_diff(current_line, line);
464+ };
507− format!("{:>5}", relative_line)
465+ format!("{:>5}", line)
511 surface.set_stringn(
467 surface.set_stringn(
512− viewport.x + 1 - GUTTER_OFFSET,
468+ viewport.x + 1,
513 viewport.y + i as u16,
469 viewport.y + i as u16,
514− line_number_text,
470+ text,
472+ if selected && is_focused {