diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 95310c1fec71..8ac80c6a29e1 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -39,7 +39,7 @@ use helix_view::{ keyboard::KeyCode, tree, view::View, - Document, DocumentId, Editor, ViewId, + Document, DocumentId, Editor, Theme, ViewId, }; use anyhow::{anyhow, bail, ensure, Context as _}; @@ -1989,7 +1989,7 @@ fn global_search(cx: &mut Context) { impl ui::menu::Item for FileResult { type Data = Option; - fn format(&self, current_path: &Self::Data) -> Row { + fn format(&self, current_path: &Self::Data, _theme: Option<&Theme>) -> Row { let relative_path = helix_core::path::get_relative_path(&self.path) .to_string_lossy() .into_owned(); @@ -2459,7 +2459,7 @@ fn buffer_picker(cx: &mut Context) { impl ui::menu::Item for BufferMeta { type Data = (); - fn format(&self, _data: &Self::Data) -> Row { + fn format(&self, _data: &Self::Data, _theme: Option<&Theme>) -> Row { let path = self .path .as_deref() @@ -2523,7 +2523,7 @@ fn jumplist_picker(cx: &mut Context) { impl ui::menu::Item for JumpMeta { type Data = (); - fn format(&self, _data: &Self::Data) -> Row { + fn format(&self, _data: &Self::Data, _theme: Option<&Theme>) -> Row { let path = self .path .as_deref() @@ -2603,7 +2603,7 @@ fn jumplist_picker(cx: &mut Context) { impl ui::menu::Item for MappableCommand { type Data = ReverseKeymap; - fn format(&self, keymap: &Self::Data) -> Row { + fn format(&self, keymap: &Self::Data, _theme: Option<&Theme>) -> Row { let fmt_binding = |bindings: &Vec>| -> String { bindings.iter().fold(String::new(), |mut acc, bind| { if !acc.is_empty() { diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index 8efdc9cfa516..29a6a00345a7 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -8,7 +8,7 @@ use dap::{StackFrame, Thread, ThreadStates}; use helix_core::syntax::{DebugArgumentValue, DebugConfigCompletion, DebugTemplate}; use helix_dap::{self as dap, Client}; use helix_lsp::block_on; -use helix_view::editor::Breakpoint; +use helix_view::{editor::Breakpoint, Theme}; use serde_json::{to_value, Value}; use tokio_stream::wrappers::UnboundedReceiverStream; @@ -25,7 +25,7 @@ use helix_view::handlers::dap::{breakpoints_changed, jump_to_stack_frame, select impl ui::menu::Item for StackFrame { type Data = (); - fn format(&self, _data: &Self::Data) -> Row { + fn format(&self, _data: &Self::Data, _theme: Option<&Theme>) -> Row { self.name.as_str().into() // TODO: include thread_states in the label } } @@ -33,7 +33,7 @@ impl ui::menu::Item for StackFrame { impl ui::menu::Item for DebugTemplate { type Data = (); - fn format(&self, _data: &Self::Data) -> Row { + fn format(&self, _data: &Self::Data, _theme: Option<&Theme>) -> Row { self.name.as_str().into() } } @@ -41,7 +41,7 @@ impl ui::menu::Item for DebugTemplate { impl ui::menu::Item for Thread { type Data = ThreadStates; - fn format(&self, thread_states: &Self::Data) -> Row { + fn format(&self, thread_states: &Self::Data, _theme: Option<&Theme>) -> Row { format!( "{} ({})", self.name, diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 7a26b3cf6024..7bf9e69af418 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -20,7 +20,7 @@ use helix_view::{ document::{DocumentInlayHints, DocumentInlayHintsId, Mode}, editor::Action, theme::Style, - Document, View, + Document, Theme, View, }; use crate::{ @@ -57,7 +57,7 @@ impl ui::menu::Item for lsp::Location { /// Current working directory. type Data = PathBuf; - fn format(&self, cwdir: &Self::Data) -> Row { + fn format(&self, cwdir: &Self::Data, _theme: Option<&Theme>) -> Row { // The preallocation here will overallocate a few characters since it will account for the // URL's scheme, which is not used most of the time since that scheme will be "file://". // Those extra chars will be used to avoid allocating when writing the line number (in the @@ -91,7 +91,7 @@ impl ui::menu::Item for lsp::SymbolInformation { /// Path to currently focussed document type Data = Option; - fn format(&self, current_doc_path: &Self::Data) -> Row { + fn format(&self, current_doc_path: &Self::Data, _theme: Option<&Theme>) -> Row { if current_doc_path.as_ref() == Some(&self.location.uri) { self.name.as_str().into() } else { @@ -121,7 +121,7 @@ struct PickerDiagnostic { impl ui::menu::Item for PickerDiagnostic { type Data = (DiagnosticStyles, DiagnosticsFormat); - fn format(&self, (styles, format): &Self::Data) -> Row { + fn format(&self, (styles, format): &Self::Data, _theme: Option<&Theme>) -> Row { let mut style = self .diag .severity @@ -476,7 +476,7 @@ pub fn workspace_diagnostics_picker(cx: &mut Context) { impl ui::menu::Item for lsp::CodeActionOrCommand { type Data = (); - fn format(&self, _data: &Self::Data) -> Row { + fn format(&self, _data: &Self::Data, _theme: Option<&Theme>) -> Row { match self { lsp::CodeActionOrCommand::CodeAction(action) => action.title.as_str().into(), lsp::CodeActionOrCommand::Command(command) => command.title.as_str().into(), @@ -672,7 +672,7 @@ pub fn code_action(cx: &mut Context) { impl ui::menu::Item for lsp::Command { type Data = (); - fn format(&self, _data: &Self::Data) -> Row { + fn format(&self, _data: &Self::Data, _theme: Option<&Theme>) -> Row { self.title.as_str().into() } } diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index bc216509f3ca..3656e176159c 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -3,7 +3,7 @@ use helix_view::{ document::SavePoint, editor::CompleteAction, theme::{Modifier, Style}, - ViewId, + Theme, ViewId, }; use tui::{buffer::Buffer as Surface, text::Span}; @@ -33,11 +33,57 @@ impl menu::Item for CompletionItem { .into() } - fn format(&self, _data: &Self::Data) -> menu::Row { + // fn label(&self, _data: &Self::Data) -> Spans { + // self.label.as_str().into() + // } + + fn format(&self, _data: &Self::Data, theme: Option<&Theme>) -> menu::Row { + let (lsp_type_label, style) = match self.kind { + Some(lsp::CompletionItemKind::TEXT) => ("text", Some("ui.text")), + Some(lsp::CompletionItemKind::METHOD) => ("method", Some("function.method")), + Some(lsp::CompletionItemKind::FUNCTION) => ("function", Some("function")), + Some(lsp::CompletionItemKind::CONSTRUCTOR) => ("constructor", Some("constructor")), + Some(lsp::CompletionItemKind::FIELD) => ("field", Some("variable.other.member")), + Some(lsp::CompletionItemKind::VARIABLE) => ("variable", Some("variable")), + Some(lsp::CompletionItemKind::CLASS) => ("class", Some("type")), + Some(lsp::CompletionItemKind::INTERFACE) => ("interface", Some("type")), + Some(lsp::CompletionItemKind::MODULE) => ("module", Some("module")), + Some(lsp::CompletionItemKind::PROPERTY) => ("property", Some("attributes")), + Some(lsp::CompletionItemKind::UNIT) => ("unit", Some("constant")), + Some(lsp::CompletionItemKind::VALUE) => ("value", Some("string")), + Some(lsp::CompletionItemKind::ENUM) => ("enum", Some("type")), + Some(lsp::CompletionItemKind::KEYWORD) => ("keyword", Some("keyword")), + Some(lsp::CompletionItemKind::SNIPPET) => ("snippet", None), + Some(lsp::CompletionItemKind::COLOR) => ("color", None), + Some(lsp::CompletionItemKind::FILE) => ("file", None), + Some(lsp::CompletionItemKind::REFERENCE) => ("reference", None), + Some(lsp::CompletionItemKind::FOLDER) => ("folder", None), + Some(lsp::CompletionItemKind::ENUM_MEMBER) => { + ("enum_member", Some("type.enum.variant")) + } + Some(lsp::CompletionItemKind::CONSTANT) => ("constant", Some("constant")), + Some(lsp::CompletionItemKind::STRUCT) => ("struct", Some("type")), + Some(lsp::CompletionItemKind::EVENT) => ("event", None), + Some(lsp::CompletionItemKind::OPERATOR) => ("operator", Some("operator")), + Some(lsp::CompletionItemKind::TYPE_PARAMETER) => { + ("type_param", Some("function.parameter")) + } + Some(kind) => unimplemented!("{:?}", kind), + None => ("", None), + }; + let mut lsp_type_style = theme + .zip(style) + .map(|(theme, style)| theme.get(style)) + .unwrap_or_default() + .remove_modifier(Modifier::all()) + .add_modifier(Modifier::ITALIC); + lsp_type_style.bg = None; + let deprecated = self.deprecated.unwrap_or_default() || self.tags.as_ref().map_or(false, |tags| { tags.contains(&lsp::CompletionItemTag::DEPRECATED) }); + menu::Row::new(vec![ menu::Cell::from(Span::styled( self.label.as_str(), @@ -47,38 +93,7 @@ impl menu::Item for CompletionItem { Style::default() }, )), - menu::Cell::from(match self.kind { - Some(lsp::CompletionItemKind::TEXT) => "text", - Some(lsp::CompletionItemKind::METHOD) => "method", - Some(lsp::CompletionItemKind::FUNCTION) => "function", - Some(lsp::CompletionItemKind::CONSTRUCTOR) => "constructor", - Some(lsp::CompletionItemKind::FIELD) => "field", - Some(lsp::CompletionItemKind::VARIABLE) => "variable", - Some(lsp::CompletionItemKind::CLASS) => "class", - Some(lsp::CompletionItemKind::INTERFACE) => "interface", - Some(lsp::CompletionItemKind::MODULE) => "module", - Some(lsp::CompletionItemKind::PROPERTY) => "property", - Some(lsp::CompletionItemKind::UNIT) => "unit", - Some(lsp::CompletionItemKind::VALUE) => "value", - Some(lsp::CompletionItemKind::ENUM) => "enum", - Some(lsp::CompletionItemKind::KEYWORD) => "keyword", - Some(lsp::CompletionItemKind::SNIPPET) => "snippet", - Some(lsp::CompletionItemKind::COLOR) => "color", - Some(lsp::CompletionItemKind::FILE) => "file", - Some(lsp::CompletionItemKind::REFERENCE) => "reference", - Some(lsp::CompletionItemKind::FOLDER) => "folder", - Some(lsp::CompletionItemKind::ENUM_MEMBER) => "enum_member", - Some(lsp::CompletionItemKind::CONSTANT) => "constant", - Some(lsp::CompletionItemKind::STRUCT) => "struct", - Some(lsp::CompletionItemKind::EVENT) => "event", - Some(lsp::CompletionItemKind::OPERATOR) => "operator", - Some(lsp::CompletionItemKind::TYPE_PARAMETER) => "type_param", - Some(kind) => { - log::error!("Received unknown completion item kind: {:?}", kind); - "" - } - None => "", - }), + menu::Cell::from(lsp_type_label).style(lsp_type_style), // self.detail.as_deref().unwrap_or("") // self.label_details // .as_ref() diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index bdad2e408392..a97b630e468f 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -11,22 +11,22 @@ pub use tui::widgets::{Cell, Row}; use fuzzy_matcher::skim::SkimMatcherV2 as Matcher; use fuzzy_matcher::FuzzyMatcher; -use helix_view::{graphics::Rect, Editor}; +use helix_view::{graphics::Rect, Editor, Theme}; use tui::layout::Constraint; pub trait Item { /// Additional editor state that is used for label calculation. type Data; - fn format(&self, data: &Self::Data) -> Row; + fn format(&self, data: &Self::Data, _theme: Option<&Theme>) -> Row; fn sort_text(&self, data: &Self::Data) -> Cow { - let label: String = self.format(data).cell_text().collect(); + let label: String = self.format(data, None).cell_text().collect(); label.into() } fn filter_text(&self, data: &Self::Data) -> Cow { - let label: String = self.format(data).cell_text().collect(); + let label: String = self.format(data, None).cell_text().collect(); label.into() } } @@ -35,7 +35,7 @@ impl Item for PathBuf { /// Root prefix to strip. type Data = PathBuf; - fn format(&self, root_path: &Self::Data) -> Row { + fn format(&self, root_path: &Self::Data, _theme: Option<&Theme>) -> Row { self.strip_prefix(root_path) .unwrap_or(self) .to_string_lossy() @@ -142,10 +142,10 @@ impl Menu { let n = self .options .first() - .map(|option| option.format(&self.editor_data).cells.len()) + .map(|option| option.format(&self.editor_data, None).cells.len()) .unwrap_or_default(); let max_lens = self.options.iter().fold(vec![0; n], |mut acc, option| { - let row = option.format(&self.editor_data); + let row = option.format(&self.editor_data, None); // maintain max for each column for (acc, cell) in acc.iter_mut().zip(row.cells.iter()) { let width = cell.content.width(); @@ -331,7 +331,7 @@ impl Component for Menu { let rows = options .iter() - .map(|option| option.format(&self.editor_data)); + .map(|option| option.format(&self.editor_data, Some(theme))); let table = Table::new(rows) .style(style) .highlight_style(selected) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index e7a7de9095db..ae4d4c673fd3 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -485,10 +485,10 @@ impl Picker { let n = self .options .first() - .map(|option| option.format(&self.editor_data).cells.len()) + .map(|option| option.format(&self.editor_data, None).cells.len()) .unwrap_or_default(); let max_lens = self.options.iter().fold(vec![0; n], |mut acc, option| { - let row = option.format(&self.editor_data); + let row = option.format(&self.editor_data, None); // maintain max for each column for (acc, cell) in acc.iter_mut().zip(row.cells.iter()) { let width = cell.content.width(); @@ -779,7 +779,7 @@ impl Component for Picker { .skip(offset) .take(rows as usize) .map(|pmatch| &self.options[pmatch.index]) - .map(|option| option.format(&self.editor_data)) + .map(|option| option.format(&self.editor_data, None)) .map(|mut row| { const TEMP_CELL_SEP: &str = " ";