diff options
Diffstat (limited to 'helix-term/src/ui')
-rw-r--r-- | helix-term/src/ui/editor.rs | 289 | ||||
-rw-r--r-- | helix-term/src/ui/markdown.rs | 7 | ||||
-rw-r--r-- | helix-term/src/ui/mod.rs | 11 |
3 files changed, 142 insertions, 165 deletions
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 0e243271..96c5f083 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -18,7 +18,6 @@ use helix_core::{ use helix_dap::{Breakpoint, SourceBreakpoint, StackFrame}; use helix_view::{ document::{Mode, SCRATCH_BUFFER_NAME}, - editor::LineNumber, graphics::{Color, CursorKind, Modifier, Rect, Style}, info::Info, input::KeyEvent, @@ -392,7 +391,7 @@ impl EditorView { use helix_core::match_brackets; let pos = doc.selection(view.id).primary().cursor(text); - let pos = match_brackets::find(syntax, doc.text(), pos) + let pos = match_brackets::find_matching_bracket(syntax, doc.text(), pos) .and_then(|pos| view.screen_coords_at_pos(doc, text, pos)); if let Some(pos) = pos { @@ -430,22 +429,6 @@ impl EditorView { let text = doc.text().slice(..); let last_line = view.last_line(doc); - let linenr = theme.get("ui.linenr"); - let linenr_select: Style = theme.try_get("ui.linenr.selected").unwrap_or(linenr); - - let warning = theme.get("warning"); - let error = theme.get("error"); - let info = theme.get("info"); - let hint = theme.get("hint"); - - // 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 current_line = doc - .text() - .char_to_line(doc.selection(view.id).primary().cursor(text)); - // it's used inside an iterator so the collect isn't needless: // https://github.com/rust-lang/rust-clippy/issues/6164 #[allow(clippy::needless_collect)] @@ -455,146 +438,137 @@ impl EditorView { .map(|range| range.cursor_line(text)) .collect(); - let mut breakpoints: Option<&Vec<SourceBreakpoint>> = None; - let mut stack_frame: Option<&StackFrame> = None; - if let Some(path) = doc.path() { - breakpoints = all_breakpoints.get(path); - if let Some(debugger) = debugger { - // if we have a frame, and the frame path matches document - if let (Some(frame), Some(thread_id)) = (debugger.active_frame, debugger.thread_id) - { - let frame = debugger - .stack_frames - .get(&thread_id) - .and_then(|bt| bt.get(frame)); // TODO: drop the clone.. - if let Some(StackFrame { - source: Some(source), - .. - }) = &frame - { - if source.path.as_ref() == Some(path) { - stack_frame = frame; - } - }; - }; - } + use helix_view::gutter::GutterFn; + fn breakpoints<'doc>( + doc: &'doc Document, + _view: &View, + theme: &Theme, + _config: &Config, + _is_focused: bool, + _width: usize, + ) -> GutterFn<'doc> { + Box::new(move |line: usize, _selected: bool, out: &mut String| { + // + }) } - - for (i, line) in (view.offset.row..(last_line + 1)).enumerate() { - use helix_core::diagnostic::Severity; - if let Ok(diagnostic) = doc.diagnostics().binary_search_by_key(&line, |d| d.line) { - let diagnostic = &doc.diagnostics()[diagnostic]; - surface.set_stringn( - viewport.x, - viewport.y + i as u16, - "●", - 1, - match diagnostic.severity { - Some(Severity::Error) => error, - Some(Severity::Warning) | None => warning, - Some(Severity::Info) => info, - Some(Severity::Hint) => hint, - }, - ); - } - - let selected = cursors.contains(&line); - - // TODO: debugger should translate received breakpoints to 0-indexing - - if let Some(user) = breakpoints.as_ref() { - let debugger_breakpoint = if let Some(debugger) = dbg_breakpoints.as_ref() { - debugger.iter().find(|breakpoint| { - if breakpoint.source.is_some() - && doc.path().is_some() - && breakpoint.source.as_ref().unwrap().path == doc.path().cloned() - { - match (breakpoint.line, breakpoint.end_line) { - #[allow(clippy::int_plus_one)] - (Some(l), Some(el)) => l - 1 <= line && line <= el - 1, - (Some(l), None) => l - 1 == line, - _ => false, - } - } else { - false - } - }) - } else { - None - }; - - if let Some(breakpoint) = user.iter().find(|breakpoint| breakpoint.line - 1 == line) - { - let verified = debugger_breakpoint.map(|b| b.verified).unwrap_or(false); - let mut style = - if breakpoint.condition.is_some() && breakpoint.log_message.is_some() { - error.add_modifier(Modifier::UNDERLINED) - } else if breakpoint.condition.is_some() { - error - } else if breakpoint.log_message.is_some() { - info - } else { - warning - }; - if !verified { - // Faded colors - style = if let Some(Color::Rgb(r, g, b)) = style.fg { - style.fg(Color::Rgb( - ((r as f32) * 0.4).floor() as u8, - ((g as f32) * 0.4).floor() as u8, - ((b as f32) * 0.4).floor() as u8, - )) - } else { - style.fg(Color::Gray) - } - }; - surface.set_stringn(viewport.x, viewport.y + i as u16, "▲", 1, style); - } else if let Some(breakpoint) = debugger_breakpoint { - let style = if breakpoint.verified { - info - } else { - info.fg(Color::Gray) - }; - surface.set_stringn(viewport.x, viewport.y + i as u16, "⊚", 1, style); - } - } - - if let Some(frame) = stack_frame { - if frame.line - 1 == line { - surface.set_style( - Rect::new(viewport.x, viewport.y + i as u16, 6, 1), - helix_view::graphics::Style::default() - .bg(helix_view::graphics::Color::LightYellow), + // let mut breakpoints: Option<&Vec<SourceBreakpoint>> = None; + // let mut stack_frame: Option<&StackFrame> = None; + // if let Some(path) = doc.path() { + // breakpoints = all_breakpoints.get(path); + // if let Some(debugger) = debugger { + // // if we have a frame, and the frame path matches document + // if let (Some(frame), Some(thread_id)) = (debugger.active_frame, debugger.thread_id) + // { + // let frame = debugger + // .stack_frames + // .get(&thread_id) + // .and_then(|bt| bt.get(frame)); // TODO: drop the clone.. + // if let Some(StackFrame { + // source: Some(source), + // .. + // }) = &frame + // { + // if source.path.as_ref() == Some(path) { + // stack_frame = frame; + // } + // }; + // }; + // } + // } + + // TODO: debugger should translate received breakpoints to 0-indexing + + // if let Some(user) = breakpoints.as_ref() { + // let debugger_breakpoint = if let Some(debugger) = dbg_breakpoints.as_ref() { + // debugger.iter().find(|breakpoint| { + // if breakpoint.source.is_some() + // && doc.path().is_some() + // && breakpoint.source.as_ref().unwrap().path == doc.path().cloned() + // { + // match (breakpoint.line, breakpoint.end_line) { + // #[allow(clippy::int_plus_one)] + // (Some(l), Some(el)) => l - 1 <= line && line <= el - 1, + // (Some(l), None) => l - 1 == line, + // _ => false, + // } + // } else { + // false + // } + // }) + // } else { + // None + // }; + + // if let Some(breakpoint) = user.iter().find(|breakpoint| breakpoint.line - 1 == line) + // { + // let verified = debugger_breakpoint.map(|b| b.verified).unwrap_or(false); + // let mut style = + // if breakpoint.condition.is_some() && breakpoint.log_message.is_some() { + // error.add_modifier(Modifier::UNDERLINED) + // } else if breakpoint.condition.is_some() { + // error + // } else if breakpoint.log_message.is_some() { + // info + // } else { + // warning + // }; + // if !verified { + // // Faded colors + // style = if let Some(Color::Rgb(r, g, b)) = style.fg { + // style.fg(Color::Rgb( + // ((r as f32) * 0.4).floor() as u8, + // ((g as f32) * 0.4).floor() as u8, + // ((b as f32) * 0.4).floor() as u8, + // )) + // } else { + // style.fg(Color::Gray) + // } + // }; + // surface.set_stringn(viewport.x, viewport.y + i as u16, "▲", 1, style); + // } else if let Some(breakpoint) = debugger_breakpoint { + // let style = if breakpoint.verified { + // info + // } else { + // info.fg(Color::Gray) + // }; + // surface.set_stringn(viewport.x, viewport.y + i as u16, "⊚", 1, style); + // } + // } + + // if let Some(frame) = stack_frame { + // if frame.line - 1 == line { + // surface.set_style( + // Rect::new(viewport.x, viewport.y + i as u16, 6, 1), + // helix_view::graphics::Style::default() + // .bg(helix_view::graphics::Color::LightYellow), + // ); + // } + // } + + let mut offset = 0; + + // avoid lots of small allocations by reusing a text buffer for each line + let mut text = String::with_capacity(8); + + for (constructor, width) in view.gutters() { + let gutter = constructor(doc, view, theme, config, is_focused, *width); + text.reserve(*width); // ensure there's enough space for the gutter + for (i, line) in (view.offset.row..(last_line + 1)).enumerate() { + let selected = cursors.contains(&line); + + if let Some(style) = gutter(line, selected, &mut text) { + surface.set_stringn( + viewport.x + offset, + viewport.y + i as u16, + &text, + *width, + style, ); } + text.clear(); } - let text = if line == last_line && !draw_last { - " ~".into() - } else { - let line = match config.line_number { - LineNumber::Absolute => line + 1, - LineNumber::Relative => { - if current_line == line { - line + 1 - } else { - abs_diff(current_line, line) - } - } - }; - format!("{:>5}", line) - }; - surface.set_stringn( - viewport.x + 1, - viewport.y + i as u16, - text, - 5, - if selected && is_focused { - linenr_select - } else { - linenr - }, - ); + offset += *width as u16; } } @@ -1364,12 +1338,3 @@ fn canonicalize_key(key: &mut KeyEvent) { key.modifiers.remove(KeyModifiers::SHIFT) } } - -#[inline] -const fn abs_diff(a: usize, b: usize) -> usize { - if a > b { - a - b - } else { - b - a - } -} diff --git a/helix-term/src/ui/markdown.rs b/helix-term/src/ui/markdown.rs index 61630d55..ca8303dd 100644 --- a/helix-term/src/ui/markdown.rs +++ b/helix-term/src/ui/markdown.rs @@ -55,7 +55,7 @@ fn parse<'a>( fn to_span(text: pulldown_cmark::CowStr) -> Span { use std::ops::Deref; Span::raw::<std::borrow::Cow<_>>(match text { - CowStr::Borrowed(s) => s.to_string().into(), // could retain borrow + CowStr::Borrowed(s) => s.into(), CowStr::Boxed(s) => s.to_string().into(), CowStr::Inlined(s) => s.deref().to_owned().into(), }) @@ -179,7 +179,9 @@ fn parse<'a>( spans.push(Span::raw(" ")); } Event::Rule => { - lines.push(Spans::from("---")); + let mut span = Span::raw("---"); + span.style = code_style; + lines.push(Spans::from(span)); lines.push(Spans::default()); } // TaskListMarker(bool) true if checked @@ -226,6 +228,7 @@ impl Component for Markdown { return None; } let contents = parse(&self.contents, None, &self.config_loader); + // TODO: account for tab width let max_text_width = (viewport.0 - padding).min(120); let mut text_width = 0; let mut height = padding; diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 9d3b0bc5..3c203326 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -93,13 +93,22 @@ pub fn regex_prompt( ) } -pub fn file_picker(root: PathBuf) -> FilePicker<PathBuf> { +pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePicker<PathBuf> { use ignore::{types::TypesBuilder, WalkBuilder}; use std::time; // We want to exclude files that the editor can't handle yet let mut type_builder = TypesBuilder::new(); let mut walk_builder = WalkBuilder::new(&root); + walk_builder + .hidden(config.file_picker.hidden) + .parents(config.file_picker.parents) + .ignore(config.file_picker.ignore) + .git_ignore(config.file_picker.git_ignore) + .git_global(config.file_picker.git_global) + .git_exclude(config.file_picker.git_exclude) + .max_depth(config.file_picker.max_depth); + let walk_builder = match type_builder.add( "compressed", "*.{zip,gz,bz2,zst,lzo,sz,tgz,tbz2,lz,lz4,lzma,lzo,z,Z,xz,7z,rar,cab}", |