on master help sign in
Reuse a text buffer for each gutter line
27c1a84Blaž Hrastnik
helix-term/src/ui/editor.rs+30−16
@@ -421,6 +421,8 @@ impl EditorView {
421 .map(|range| range.cursor_line(text))
421 .map(|range| range.cursor_line(text))
422 .collect();
422 .collect();
423
423
424+ use std::fmt::Write;
425+
424 fn diagnostic<'doc>(
426 fn diagnostic<'doc>(
425 doc: &'doc Document,
427 doc: &'doc Document,
426 _view: &View,
428 _view: &View,
@@ -435,18 +437,16 @@ impl EditorView {
435 let hint = theme.get("hint");
437 let hint = theme.get("hint");
436 let diagnostics = doc.diagnostics();
438 let diagnostics = doc.diagnostics();
437
439
438− Box::new(move |line: usize, _selected: bool| {
440+ Box::new(move |line: usize, _selected: bool, out: &mut String| {
439 use helix_core::diagnostic::Severity;
441 use helix_core::diagnostic::Severity;
440 if let Some(diagnostic) = diagnostics.iter().find(|d| d.line == line) {
442 if let Some(diagnostic) = diagnostics.iter().find(|d| d.line == line) {
441− return Some((
443+ write!(out, "●").unwrap();
442− "●".to_string(),
443− match diagnostic.severity {
444+ return Some(match diagnostic.severity {
444− Some(Severity::Error) => error,
445+ Some(Severity::Error) => error,
445− Some(Severity::Warning) | None => warning,
446+ Some(Severity::Warning) | None => warning,
446− Some(Severity::Info) => info,
447+ Some(Severity::Info) => info,
447− Some(Severity::Hint) => hint,
448+ Some(Severity::Hint) => hint,
448− },
449− ));
449+ });
450 }
450 }
451 None
451 None
452 })
452 })
@@ -475,9 +475,10 @@ impl EditorView {
475
475
476 let config = config.line_number;
476 let config = config.line_number;
477
477
478− Box::new(move |line: usize, selected: bool| {
478+ Box::new(move |line: usize, selected: bool, out: &mut String| {
479 if line == last_line && !draw_last {
479 if line == last_line && !draw_last {
480− Some((format!("{:>1$}", '~', width), linenr))
480+ write!(out, "{:>1$}", '~', width).unwrap();
481+ Some(linenr)
481 } else {
482 } else {
482 let line = match config {
483 let line = match config {
483 LineNumber::Absolute => line + 1,
484 LineNumber::Absolute => line + 1,
@@ -494,25 +495,38 @@ impl EditorView {
494 } else {
495 } else {
495 linenr
496 linenr
496 };
497 };
497− Some((format!("{:>1$}", line, width), style))
498+ write!(out, "{:>1$}", line, width).unwrap();
499+ Some(style)
498 }
500 }
499 })
501 })
500 }
502 }
501
503
502− type GutterFn<'doc> = Box<dyn Fn(usize, bool) -> Option<(String, Style)> + 'doc>;
504+ type GutterFn<'doc> = Box<dyn Fn(usize, bool, &mut String) -> Option<Style> + 'doc>;
503 type Gutter =
505 type Gutter =
504 for<'doc> fn(&'doc Document, &View, &Theme, &Config, bool, usize) -> GutterFn<'doc>;
506 for<'doc> fn(&'doc Document, &View, &Theme, &Config, bool, usize) -> GutterFn<'doc>;
505 let gutters: &[(Gutter, usize)] = &[(diagnostic, 1), (line_number, 5)];
507 let gutters: &[(Gutter, usize)] = &[(diagnostic, 1), (line_number, 5)];
506
508
507 let mut offset = 0;
509 let mut offset = 0;
510+
511+ // avoid lots of small allocations by reusing a text buffer for each line
512+ let mut text = String::with_capacity(8);
513+
508 for (constructor, width) in gutters {
514 for (constructor, width) in gutters {
509 let gutter = constructor(doc, view, theme, config, is_focused, *width);
515 let gutter = constructor(doc, view, theme, config, is_focused, *width);
516+ text.reserve(*width); // ensure there's enough space for the gutter
510 for (i, line) in (view.offset.row..(last_line + 1)).enumerate() {
517 for (i, line) in (view.offset.row..(last_line + 1)).enumerate() {
511 let selected = cursors.contains(&line);
518 let selected = cursors.contains(&line);
512
519
513− if let Some((text, style)) = gutter(line, selected) {
520+ if let Some(style) = gutter(line, selected, &mut text) {
514− surface.set_stringn(viewport.x + offset, viewport.y + i as u16, text, 5, style);
521+ surface.set_stringn(
522+ viewport.x + offset,
523+ viewport.y + i as u16,
524+ &text,
525+ *width,
526+ style,
527+ );
515 }
528 }
529+ text.clear();
516 }
530 }
517 offset += *width as u16;
531 offset += *width as u16;
518 }
532 }