From aa27bc7b4a1e82172d5215b655eb94eefadeb9cb Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Mon, 30 Dec 2024 04:57:13 -0800 Subject: [PATCH 01/16] feat: add support for basic icons --- helix-term/src/ui/editor.rs | 12 +- helix-term/src/ui/statusline.rs | 43 ++++-- helix-view/src/editor.rs | 6 + helix-view/src/editor/config.rs | 250 ++++++++++++++++++++++++++++++++ helix-view/src/gutter.rs | 18 ++- 5 files changed, 307 insertions(+), 22 deletions(-) create mode 100644 helix-view/src/editor/config.rs diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 6fecd512..b1d5fb2e 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -24,7 +24,7 @@ use helix_core::{ }; use helix_view::{ annotations::diagnostics::DiagnosticFilter, - document::{Mode, SCRATCH_BUFFER_NAME}, + document::{Mode, DEFAULT_LANGUAGE_NAME, SCRATCH_BUFFER_NAME}, editor::{CompleteAction, CursorShapeConfig}, graphics::{Color, CursorKind, Modifier, Rect, Style}, input::{KeyEvent, MouseButton, MouseEvent, MouseEventKind}, @@ -646,7 +646,15 @@ impl EditorView { bufferline_inactive }; - let text = format!(" {}{} ", fname, if doc.is_modified() { "[+]" } else { "" }); + let lang = doc.language_name().unwrap_or(DEFAULT_LANGUAGE_NAME); + let config = editor.config(); + let icon = config.icons.mime.lang(lang); + + let text = format!( + " {icon} {}{} ", + fname, + if doc.is_modified() { "[+]" } else { "" } + ); let used_width = viewport.x.saturating_sub(x); let rem_width = surface.area.width.saturating_sub(used_width); diff --git a/helix-term/src/ui/statusline.rs b/helix-term/src/ui/statusline.rs index 7437cbd0..b096a475 100644 --- a/helix-term/src/ui/statusline.rs +++ b/helix-term/src/ui/statusline.rs @@ -243,7 +243,13 @@ where if warnings > 0 { write( context, - "●".to_string(), + context + .editor + .config() + .icons + .diagnostic + .warning() + .to_string(), Some(context.editor.theme.get("warning")), ); write(context, format!(" {} ", warnings), None); @@ -252,7 +258,7 @@ where if errors > 0 { write( context, - "●".to_string(), + context.editor.config().icons.diagnostic.error().to_string(), Some(context.editor.theme.get("error")), ); write(context, format!(" {} ", errors), None); @@ -285,7 +291,13 @@ where if warnings > 0 { write( context, - "●".to_string(), + context + .editor + .config() + .icons + .diagnostic + .warning() + .to_string(), Some(context.editor.theme.get("warning")), ); write(context, format!(" {} ", warnings), None); @@ -294,7 +306,7 @@ where if errors > 0 { write( context, - "●".to_string(), + context.editor.config().icons.diagnostic.error().to_string(), Some(context.editor.theme.get("error")), ); write(context, format!(" {} ", errors), None); @@ -410,9 +422,11 @@ fn render_file_type<F>(context: &mut RenderContext, write: F) where F: Fn(&mut RenderContext, String, Option<Style>) + Copy, { - let file_type = context.doc.language_name().unwrap_or(DEFAULT_LANGUAGE_NAME); + let mime = &context.editor.config().icons.mime; - write(context, format!(" {} ", file_type), None); + let icon = mime.lang(context.doc.language_name().unwrap_or(DEFAULT_LANGUAGE_NAME)); + + write(context, format!(" {} ", icon), None); } fn render_file_name<F>(context: &mut RenderContext, write: F) @@ -514,13 +528,18 @@ fn render_version_control<F>(context: &mut RenderContext, write: F) where F: Fn(&mut RenderContext, String, Option<Style>) + Copy, { - let head = context - .doc - .version_control_head() - .unwrap_or_default() - .to_string(); + let head = context.doc.version_control_head().unwrap_or_default(); - write(context, head, None); + let config = context.editor.config(); + let icon = config.icons.vcs.icon(); + + let vcs = if head.is_empty() { + format!("{head}") + } else { + format!("{icon}{head}") + }; + + write(context, vcs, None); } fn render_register<F>(context: &mut RenderContext, write: F) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 739dcfb4..004d0bf1 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -14,6 +14,7 @@ use crate::{ tree::{self, Tree}, Document, DocumentId, View, ViewId, }; +use config::Icons; use dap::StackFrame; use helix_event::dispatch; use helix_vcs::DiffProviderRegistry; @@ -23,6 +24,8 @@ use futures_util::{future, StreamExt}; use helix_lsp::{Call, LanguageServerId}; use tokio_stream::wrappers::UnboundedReceiverStream; +mod config; + use std::{ borrow::Cow, cell::Cell, @@ -360,6 +363,8 @@ pub struct Config { pub end_of_line_diagnostics: DiagnosticFilter, // Set to override the default clipboard provider pub clipboard_provider: ClipboardProvider, + + pub icons: Icons, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] @@ -1001,6 +1006,7 @@ impl Default for Config { inline_diagnostics: InlineDiagnosticsConfig::default(), end_of_line_diagnostics: DiagnosticFilter::Disable, clipboard_provider: ClipboardProvider::default(), + icons: Icons::default(), } } } diff --git a/helix-view/src/editor/config.rs b/helix-view/src/editor/config.rs new file mode 100644 index 00000000..5f645f88 --- /dev/null +++ b/helix-view/src/editor/config.rs @@ -0,0 +1,250 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +// TODO: Dap: verified ●, unverified ◯ + +#[derive(Debug, Serialize, Deserialize, Default, PartialEq, Eq, Clone)] +pub struct Icons { + pub mime: Mime, + pub lsp: Lsp, + pub diagnostic: Diagnostic, + pub vcs: Vcs, +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol +#[derive(Debug, Serialize, Deserialize, Default, PartialEq, Eq, Clone)] +pub struct Lsp { + file: Option<String>, + module: Option<String>, + namespace: Option<String>, + package: Option<String>, + class: Option<String>, + method: Option<String>, + property: Option<String>, + field: Option<String>, + constructor: Option<String>, + #[serde(rename = "enum")] + r#enum: Option<String>, + interface: Option<String>, + function: Option<String>, + variable: Option<String>, + constant: Option<String>, + string: Option<String>, + number: Option<String>, + boolean: Option<String>, + array: Option<String>, + object: Option<String>, + key: Option<String>, + null: Option<String>, + enum_member: Option<String>, + #[serde(rename = "struct")] + r#struct: Option<String>, + event: Option<String>, + operator: Option<String>, + type_parameter: Option<String>, +} + +impl Lsp { + const DEFAULT: &str = "*"; + + pub fn file(&self) -> &str { + self.file.as_ref().map_or(Self::DEFAULT, |file| file) + } + pub fn module(&self) -> &str { + self.module.as_ref().map_or(Self::DEFAULT, |module| module) + } + pub fn namespace(&self) -> &str { + self.namespace + .as_ref() + .map_or(Self::DEFAULT, |namespace| namespace) + } + pub fn package(&self) -> &str { + self.package + .as_ref() + .map_or(Self::DEFAULT, |package| package) + } + pub fn class(&self) -> &str { + self.class.as_ref().map_or(Self::DEFAULT, |class| class) + } + pub fn method(&self) -> &str { + self.method.as_ref().map_or(Self::DEFAULT, |method| method) + } + pub fn property(&self) -> &str { + self.property + .as_ref() + .map_or(Self::DEFAULT, |property| property) + } + pub fn field(&self) -> &str { + self.field.as_ref().map_or(Self::DEFAULT, |field| field) + } + pub fn constructor(&self) -> &str { + self.constructor + .as_ref() + .map_or(Self::DEFAULT, |constructor| constructor) + } + pub fn r#enum(&self) -> &str { + self.r#enum.as_ref().map_or(Self::DEFAULT, |r#enum| r#enum) + } + pub fn interface(&self) -> &str { + self.interface + .as_ref() + .map_or(Self::DEFAULT, |interface| interface) + } + pub fn function(&self) -> &str { + self.function + .as_ref() + .map_or(Self::DEFAULT, |function| function) + } + pub fn variable(&self) -> &str { + self.variable + .as_ref() + .map_or(Self::DEFAULT, |variable| variable) + } + pub fn constant(&self) -> &str { + self.constant + .as_ref() + .map_or(Self::DEFAULT, |constant| constant) + } + pub fn string(&self) -> &str { + self.string.as_ref().map_or(Self::DEFAULT, |string| string) + } + pub fn number(&self) -> &str { + self.number.as_ref().map_or(Self::DEFAULT, |number| number) + } + pub fn boolean(&self) -> &str { + self.boolean + .as_ref() + .map_or(Self::DEFAULT, |boolean| boolean) + } + pub fn array(&self) -> &str { + self.array.as_ref().map_or(Self::DEFAULT, |array| array) + } + pub fn object(&self) -> &str { + self.object.as_ref().map_or(Self::DEFAULT, |object| object) + } + pub fn key(&self) -> &str { + self.key.as_ref().map_or(Self::DEFAULT, |key| key) + } + pub fn null(&self) -> &str { + self.null.as_ref().map_or(Self::DEFAULT, |null| null) + } + pub fn enum_member(&self) -> &str { + self.enum_member + .as_ref() + .map_or(Self::DEFAULT, |enum_member| enum_member) + } + pub fn r#struct(&self) -> &str { + self.r#struct + .as_ref() + .map_or(Self::DEFAULT, |r#struct| r#struct) + } + pub fn event(&self) -> &str { + self.event.as_ref().map_or(Self::DEFAULT, |event| event) + } + pub fn operator(&self) -> &str { + self.operator + .as_ref() + .map_or(Self::DEFAULT, |operator| operator) + } + pub fn type_parameter(&self) -> &str { + self.type_parameter + .as_ref() + .map_or(Self::DEFAULT, |type_parameter| type_parameter) + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] +pub struct Diagnostic { + hint: Option<String>, + info: Option<String>, + warning: Option<String>, + error: Option<String>, +} + +impl Default for Diagnostic { + fn default() -> Self { + Self { + hint: Some(String::from("○")), + info: Some(String::from("●")), + warning: Some(String::from("▲")), + error: Some(String::from("■")), + } + } +} + +impl Diagnostic { + const DEFAULT: &str = "●"; + + pub fn hint(&self) -> &str { + self.hint.as_ref().map_or(Self::DEFAULT, |hint| hint) + } + pub fn info(&self) -> &str { + self.info.as_ref().map_or(Self::DEFAULT, |info| info) + } + pub fn warning(&self) -> &str { + self.warning + .as_ref() + .map_or(Self::DEFAULT, |warning| warning) + } + pub fn error(&self) -> &str { + self.error.as_ref().map_or(Self::DEFAULT, |error| error) + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] +pub struct Vcs { + icon: Option<String>, +} + +impl Default for Vcs { + fn default() -> Self { + Self { + icon: Some(String::from(" ")), + } + } +} + +impl Vcs { + const DEFAULT: &str = ""; + + pub fn icon(&self) -> &str { + self.icon + .as_ref() + .map_or(Self::DEFAULT, |icon| icon.as_str()) + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] +pub struct Mime { + directory: Option<String>, + mime: HashMap<String, String>, +} + +impl Default for Mime { + fn default() -> Self { + Self { + directory: None, + mime: { + let mut mime = HashMap::new(); + mime.insert(String::from("rust"), String::from(" ")); + mime.insert(String::from("markdown"), String::from(" ")); + mime.insert(String::from("css"), String::from(" ")); + mime.insert(String::from("toml"), String::from(" ")); + mime.insert(String::from("lock"), String::from(" ")); + mime.insert(String::from("text"), String::from(" ")); + mime + }, + } + } +} + +impl Mime { + pub fn directory(&self) -> &str { + self.directory.as_ref().map_or("🖿 ", |directory| directory) + } + + pub fn lang(&self, mime: &str) -> &str { + self.mime.get(mime).map_or("*", |mime| mime) + } +} diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 7cd91271..bac4a380 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -46,7 +46,7 @@ impl GutterType { } pub fn diagnostic<'doc>( - _editor: &'doc Editor, + editor: &'doc Editor, doc: &'doc Document, _view: &View, theme: &Theme, @@ -57,6 +57,7 @@ pub fn diagnostic<'doc>( let info = theme.get("info"); let hint = theme.get("hint"); let diagnostics = &doc.diagnostics; + let symbols = editor.config().icons.diagnostic.clone(); Box::new( move |line: usize, _selected: bool, first_visual_line: bool, out: &mut String| { @@ -74,13 +75,14 @@ pub fn diagnostic<'doc>( .any(|ls| ls.id() == d.provider) }); diagnostics_on_line.max_by_key(|d| d.severity).map(|d| { - write!(out, "●").ok(); - match d.severity { - Some(Severity::Error) => error, - Some(Severity::Warning) | None => warning, - Some(Severity::Info) => info, - Some(Severity::Hint) => hint, - } + let (style, symbol) = match d.severity { + Some(Severity::Error) => (error, symbols.error()), + Some(Severity::Warning) | None => (warning, symbols.warning()), + Some(Severity::Info) => (info, symbols.info()), + Some(Severity::Hint) => (hint, symbols.hint()), + }; + out.push_str(symbol); + style }) }, ) From 0ef7bad77ea32526070badcbff058c4164f5cea4 Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Mon, 30 Dec 2024 07:15:30 -0800 Subject: [PATCH 02/16] lint: add 'static lifetime to const's --- helix-view/src/editor/config.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/helix-view/src/editor/config.rs b/helix-view/src/editor/config.rs index 5f645f88..00100ff5 100644 --- a/helix-view/src/editor/config.rs +++ b/helix-view/src/editor/config.rs @@ -46,7 +46,7 @@ pub struct Lsp { } impl Lsp { - const DEFAULT: &str = "*"; + const DEFAULT: &'static str = "*"; pub fn file(&self) -> &str { self.file.as_ref().map_or(Self::DEFAULT, |file| file) @@ -174,7 +174,7 @@ impl Default for Diagnostic { } impl Diagnostic { - const DEFAULT: &str = "●"; + const DEFAULT: &'static str = "●"; pub fn hint(&self) -> &str { self.hint.as_ref().map_or(Self::DEFAULT, |hint| hint) @@ -206,7 +206,7 @@ impl Default for Vcs { } impl Vcs { - const DEFAULT: &str = ""; + const DEFAULT: &'static str = ""; pub fn icon(&self) -> &str { self.icon From 55ead2f0ae5c7207c7854bd7aa9c21de9afa07fc Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Mon, 30 Dec 2024 09:07:56 -0800 Subject: [PATCH 03/16] feat: add dap symbols to config --- helix-view/src/editor/config.rs | 26 ++++++++++++++++++++++++-- helix-view/src/gutter.rs | 8 +++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/helix-view/src/editor/config.rs b/helix-view/src/editor/config.rs index 00100ff5..5c7f5345 100644 --- a/helix-view/src/editor/config.rs +++ b/helix-view/src/editor/config.rs @@ -2,14 +2,13 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; -// TODO: Dap: verified ●, unverified ◯ - #[derive(Debug, Serialize, Deserialize, Default, PartialEq, Eq, Clone)] pub struct Icons { pub mime: Mime, pub lsp: Lsp, pub diagnostic: Diagnostic, pub vcs: Vcs, + pub dap: Dap, } // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol @@ -248,3 +247,26 @@ impl Mime { self.mime.get(mime).map_or("*", |mime| mime) } } + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Default)] +pub struct Dap { + verified: Option<String>, + unverified: Option<String>, +} + +impl Dap { + const DEFAULT_VERIFIED: &'static str = "●"; + const DEFAULT_UNVERIFIED: &'static str = "◯"; + + pub fn verified(&self) -> &str { + self.verified + .as_ref() + .map_or(Self::DEFAULT_VERIFIED, |verified| verified) + } + + pub fn unverified(&self) -> &str { + self.verified + .as_ref() + .map_or(Self::DEFAULT_UNVERIFIED, |verified| verified) + } +} diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index bac4a380..ac5c2f0b 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -265,7 +265,13 @@ pub fn breakpoints<'doc>( breakpoint_style }; - let sym = if breakpoint.verified { "●" } else { "◯" }; + let config = editor.config(); + + let sym = if breakpoint.verified { + config.icons.dap.verified() + } else { + config.icons.dap.unverified() + }; write!(out, "{}", sym).unwrap(); Some(style) }, From 88da9ee7bf6e5e1ec76fe4d2ab684699230280a8 Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Mon, 30 Dec 2024 09:35:06 -0800 Subject: [PATCH 04/16] refactor: remove `Default` impls and add config parsing --- helix-term/src/ui/editor.rs | 2 +- helix-term/src/ui/statusline.rs | 4 +-- helix-view/src/editor/config.rs | 52 ++++++--------------------------- 3 files changed, 12 insertions(+), 46 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index b1d5fb2e..4f5b1cc3 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -648,7 +648,7 @@ impl EditorView { let lang = doc.language_name().unwrap_or(DEFAULT_LANGUAGE_NAME); let config = editor.config(); - let icon = config.icons.mime.lang(lang); + let icon = config.icons.mime.get(lang); let text = format!( " {icon} {}{} ", diff --git a/helix-term/src/ui/statusline.rs b/helix-term/src/ui/statusline.rs index b096a475..0034db61 100644 --- a/helix-term/src/ui/statusline.rs +++ b/helix-term/src/ui/statusline.rs @@ -424,7 +424,7 @@ where { let mime = &context.editor.config().icons.mime; - let icon = mime.lang(context.doc.language_name().unwrap_or(DEFAULT_LANGUAGE_NAME)); + let icon = mime.get(context.doc.language_name().unwrap_or(DEFAULT_LANGUAGE_NAME)); write(context, format!(" {} ", icon), None); } @@ -536,7 +536,7 @@ where let vcs = if head.is_empty() { format!("{head}") } else { - format!("{icon}{head}") + format!("{icon} {head}") }; write(context, vcs, None); diff --git a/helix-view/src/editor/config.rs b/helix-view/src/editor/config.rs index 5c7f5345..db0fbe63 100644 --- a/helix-view/src/editor/config.rs +++ b/helix-view/src/editor/config.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Default, PartialEq, Eq, Clone)] +#[serde(default)] pub struct Icons { pub mime: Mime, pub lsp: Lsp, @@ -153,7 +154,7 @@ impl Lsp { } } -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Default)] pub struct Diagnostic { hint: Option<String>, info: Option<String>, @@ -161,17 +162,6 @@ pub struct Diagnostic { error: Option<String>, } -impl Default for Diagnostic { - fn default() -> Self { - Self { - hint: Some(String::from("○")), - info: Some(String::from("●")), - warning: Some(String::from("▲")), - error: Some(String::from("■")), - } - } -} - impl Diagnostic { const DEFAULT: &'static str = "●"; @@ -191,19 +181,11 @@ impl Diagnostic { } } -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Default)] pub struct Vcs { icon: Option<String>, } -impl Default for Vcs { - fn default() -> Self { - Self { - icon: Some(String::from(" ")), - } - } -} - impl Vcs { const DEFAULT: &'static str = ""; @@ -214,37 +196,21 @@ impl Vcs { } } -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Default)] pub struct Mime { directory: Option<String>, + #[serde(flatten)] mime: HashMap<String, String>, } -impl Default for Mime { - fn default() -> Self { - Self { - directory: None, - mime: { - let mut mime = HashMap::new(); - mime.insert(String::from("rust"), String::from(" ")); - mime.insert(String::from("markdown"), String::from(" ")); - mime.insert(String::from("css"), String::from(" ")); - mime.insert(String::from("toml"), String::from(" ")); - mime.insert(String::from("lock"), String::from(" ")); - mime.insert(String::from("text"), String::from(" ")); - mime - }, - } - } -} - impl Mime { pub fn directory(&self) -> &str { - self.directory.as_ref().map_or("🖿 ", |directory| directory) + self.directory.as_ref().map_or("", |directory| directory) } - pub fn lang(&self, mime: &str) -> &str { - self.mime.get(mime).map_or("*", |mime| mime) + // Returns the symbol that matches the name, if any, otherwise returns the name back. + pub fn get<'name, 'mime: 'name>(&'mime self, r#type: &'name str) -> &'name str { + self.mime.get(r#type).map_or(r#type, |mime| mime) } } From 0e94d21d18430622bd0be5ae1370b4eb50c22446 Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Mon, 30 Dec 2024 09:43:06 -0800 Subject: [PATCH 05/16] chore: add comment for default diagnostic symbols --- helix-view/src/editor/config.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/helix-view/src/editor/config.rs b/helix-view/src/editor/config.rs index db0fbe63..52528ad2 100644 --- a/helix-view/src/editor/config.rs +++ b/helix-view/src/editor/config.rs @@ -162,6 +162,19 @@ pub struct Diagnostic { error: Option<String>, } +// NOTE: #6646 can be achieved by uncommenting this or adding the symbols +// to the `map_or` default. +// impl Default for Diagnostic { +// fn default() -> Self { +// Self { +// hint: Some(String::from("○")), +// info: Some(String::from("●")), +// warning: Some(String::from("▲")), +// error: Some(String::from("■")), +// } +// } +// } + impl Diagnostic { const DEFAULT: &'static str = "●"; From c18a71deba3d94577537ad54a8aa0c4ef8e15d00 Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Mon, 30 Dec 2024 10:10:38 -0800 Subject: [PATCH 06/16] perf: add `#[inline]` attribute to getters --- helix-view/src/editor/config.rs | 63 +++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/helix-view/src/editor/config.rs b/helix-view/src/editor/config.rs index 52528ad2..a404e852 100644 --- a/helix-view/src/editor/config.rs +++ b/helix-view/src/editor/config.rs @@ -48,105 +48,156 @@ pub struct Lsp { impl Lsp { const DEFAULT: &'static str = "*"; + #[inline] pub fn file(&self) -> &str { self.file.as_ref().map_or(Self::DEFAULT, |file| file) } + + #[inline] pub fn module(&self) -> &str { self.module.as_ref().map_or(Self::DEFAULT, |module| module) } + + #[inline] pub fn namespace(&self) -> &str { self.namespace .as_ref() .map_or(Self::DEFAULT, |namespace| namespace) } + + #[inline] pub fn package(&self) -> &str { self.package .as_ref() .map_or(Self::DEFAULT, |package| package) } + + #[inline] pub fn class(&self) -> &str { self.class.as_ref().map_or(Self::DEFAULT, |class| class) } + + #[inline] pub fn method(&self) -> &str { self.method.as_ref().map_or(Self::DEFAULT, |method| method) } + + #[inline] pub fn property(&self) -> &str { self.property .as_ref() .map_or(Self::DEFAULT, |property| property) } + + #[inline] pub fn field(&self) -> &str { self.field.as_ref().map_or(Self::DEFAULT, |field| field) } + + #[inline] pub fn constructor(&self) -> &str { self.constructor .as_ref() .map_or(Self::DEFAULT, |constructor| constructor) } + + #[inline] pub fn r#enum(&self) -> &str { self.r#enum.as_ref().map_or(Self::DEFAULT, |r#enum| r#enum) } + + #[inline] pub fn interface(&self) -> &str { self.interface .as_ref() .map_or(Self::DEFAULT, |interface| interface) } + + #[inline] pub fn function(&self) -> &str { self.function .as_ref() .map_or(Self::DEFAULT, |function| function) } + + #[inline] pub fn variable(&self) -> &str { self.variable .as_ref() .map_or(Self::DEFAULT, |variable| variable) } + + #[inline] pub fn constant(&self) -> &str { self.constant .as_ref() .map_or(Self::DEFAULT, |constant| constant) } + + #[inline] pub fn string(&self) -> &str { self.string.as_ref().map_or(Self::DEFAULT, |string| string) } + + #[inline] pub fn number(&self) -> &str { self.number.as_ref().map_or(Self::DEFAULT, |number| number) } + + #[inline] pub fn boolean(&self) -> &str { self.boolean .as_ref() .map_or(Self::DEFAULT, |boolean| boolean) } + + #[inline] pub fn array(&self) -> &str { self.array.as_ref().map_or(Self::DEFAULT, |array| array) } + + #[inline] pub fn object(&self) -> &str { self.object.as_ref().map_or(Self::DEFAULT, |object| object) } + + #[inline] pub fn key(&self) -> &str { self.key.as_ref().map_or(Self::DEFAULT, |key| key) } + + #[inline] pub fn null(&self) -> &str { self.null.as_ref().map_or(Self::DEFAULT, |null| null) } + + #[inline] pub fn enum_member(&self) -> &str { self.enum_member .as_ref() .map_or(Self::DEFAULT, |enum_member| enum_member) } + + #[inline] pub fn r#struct(&self) -> &str { self.r#struct .as_ref() .map_or(Self::DEFAULT, |r#struct| r#struct) } + + #[inline] pub fn event(&self) -> &str { self.event.as_ref().map_or(Self::DEFAULT, |event| event) } + + #[inline] pub fn operator(&self) -> &str { self.operator .as_ref() .map_or(Self::DEFAULT, |operator| operator) } + + #[inline] pub fn type_parameter(&self) -> &str { self.type_parameter .as_ref() @@ -178,17 +229,24 @@ pub struct Diagnostic { impl Diagnostic { const DEFAULT: &'static str = "●"; + #[inline] pub fn hint(&self) -> &str { self.hint.as_ref().map_or(Self::DEFAULT, |hint| hint) } + + #[inline] pub fn info(&self) -> &str { self.info.as_ref().map_or(Self::DEFAULT, |info| info) } + + #[inline] pub fn warning(&self) -> &str { self.warning .as_ref() .map_or(Self::DEFAULT, |warning| warning) } + + #[inline] pub fn error(&self) -> &str { self.error.as_ref().map_or(Self::DEFAULT, |error| error) } @@ -202,6 +260,7 @@ pub struct Vcs { impl Vcs { const DEFAULT: &'static str = ""; + #[inline] pub fn icon(&self) -> &str { self.icon .as_ref() @@ -217,11 +276,13 @@ pub struct Mime { } impl Mime { + #[inline] pub fn directory(&self) -> &str { self.directory.as_ref().map_or("", |directory| directory) } // Returns the symbol that matches the name, if any, otherwise returns the name back. + #[inline] pub fn get<'name, 'mime: 'name>(&'mime self, r#type: &'name str) -> &'name str { self.mime.get(r#type).map_or(r#type, |mime| mime) } @@ -237,12 +298,14 @@ impl Dap { const DEFAULT_VERIFIED: &'static str = "●"; const DEFAULT_UNVERIFIED: &'static str = "◯"; + #[inline] pub fn verified(&self) -> &str { self.verified .as_ref() .map_or(Self::DEFAULT_VERIFIED, |verified| verified) } + #[inline] pub fn unverified(&self) -> &str { self.verified .as_ref() From 7f7d9f080275fe4134b2afcf6d5bbc722b3daa05 Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Mon, 30 Dec 2024 16:23:18 -0800 Subject: [PATCH 07/16] refactor: add nerdfont defaults for common mime types --- helix-view/src/editor/config.rs | 286 ++++++++++++++++++++++---------- 1 file changed, 195 insertions(+), 91 deletions(-) diff --git a/helix-view/src/editor/config.rs b/helix-view/src/editor/config.rs index a404e852..34d2a2cb 100644 --- a/helix-view/src/editor/config.rs +++ b/helix-view/src/editor/config.rs @@ -15,6 +15,8 @@ pub struct Icons { // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol #[derive(Debug, Serialize, Deserialize, Default, PartialEq, Eq, Clone)] pub struct Lsp { + enabled: bool, + file: Option<String>, module: Option<String>, namespace: Option<String>, @@ -46,162 +48,221 @@ pub struct Lsp { } impl Lsp { - const DEFAULT: &'static str = "*"; - #[inline] pub fn file(&self) -> &str { - self.file.as_ref().map_or(Self::DEFAULT, |file| file) + if self.enabled { + return self.file.as_ref().map_or("", |file| file); + } + "" } #[inline] pub fn module(&self) -> &str { - self.module.as_ref().map_or(Self::DEFAULT, |module| module) + if self.enabled { + return self.module.as_ref().map_or("", |module| module); + } + "" } #[inline] pub fn namespace(&self) -> &str { - self.namespace - .as_ref() - .map_or(Self::DEFAULT, |namespace| namespace) + if self.enabled { + return self.namespace.as_ref().map_or("", |namespace| namespace); + } + "" } #[inline] pub fn package(&self) -> &str { - self.package - .as_ref() - .map_or(Self::DEFAULT, |package| package) + if self.enabled { + return self.package.as_ref().map_or("", |package| package); + } + "" } #[inline] pub fn class(&self) -> &str { - self.class.as_ref().map_or(Self::DEFAULT, |class| class) + if self.enabled { + return self.class.as_ref().map_or("", |class| class); + } + "" } #[inline] pub fn method(&self) -> &str { - self.method.as_ref().map_or(Self::DEFAULT, |method| method) + if self.enabled { + return self.method.as_ref().map_or("", |method| method); + } + "" } #[inline] pub fn property(&self) -> &str { - self.property - .as_ref() - .map_or(Self::DEFAULT, |property| property) + if self.enabled { + return self.property.as_ref().map_or("", |property| property); + } + "" } #[inline] pub fn field(&self) -> &str { - self.field.as_ref().map_or(Self::DEFAULT, |field| field) + if self.enabled { + return self.field.as_ref().map_or("", |field| field); + } + "" } #[inline] pub fn constructor(&self) -> &str { - self.constructor - .as_ref() - .map_or(Self::DEFAULT, |constructor| constructor) + if self.enabled { + return self + .constructor + .as_ref() + .map_or("", |constructor| constructor); + } + "" } #[inline] pub fn r#enum(&self) -> &str { - self.r#enum.as_ref().map_or(Self::DEFAULT, |r#enum| r#enum) + if self.enabled { + return self.r#enum.as_ref().map_or("", |r#enum| r#enum); + } + "" } #[inline] pub fn interface(&self) -> &str { - self.interface - .as_ref() - .map_or(Self::DEFAULT, |interface| interface) + if self.enabled { + return self.interface.as_ref().map_or("", |interface| interface); + } + "" } #[inline] pub fn function(&self) -> &str { - self.function - .as_ref() - .map_or(Self::DEFAULT, |function| function) + if self.enabled { + return self.function.as_ref().map_or("", |function| function); + } + "" } #[inline] pub fn variable(&self) -> &str { - self.variable - .as_ref() - .map_or(Self::DEFAULT, |variable| variable) + if self.enabled { + return self.variable.as_ref().map_or("", |variable| variable); + } + "" } #[inline] pub fn constant(&self) -> &str { - self.constant - .as_ref() - .map_or(Self::DEFAULT, |constant| constant) + if self.enabled { + return self.constant.as_ref().map_or("", |constant| constant); + } + "" } #[inline] pub fn string(&self) -> &str { - self.string.as_ref().map_or(Self::DEFAULT, |string| string) + if self.enabled { + return self.string.as_ref().map_or("", |string| string); + } + "" } #[inline] pub fn number(&self) -> &str { - self.number.as_ref().map_or(Self::DEFAULT, |number| number) + if self.enabled { + return self.number.as_ref().map_or("", |number| number); + } + "" } #[inline] pub fn boolean(&self) -> &str { - self.boolean - .as_ref() - .map_or(Self::DEFAULT, |boolean| boolean) + if self.enabled { + return self.boolean.as_ref().map_or("", |boolean| boolean); + } + "" } #[inline] pub fn array(&self) -> &str { - self.array.as_ref().map_or(Self::DEFAULT, |array| array) + if self.enabled { + return self.array.as_ref().map_or("", |array| array); + } + "" } #[inline] pub fn object(&self) -> &str { - self.object.as_ref().map_or(Self::DEFAULT, |object| object) + if self.enabled { + return self.object.as_ref().map_or("", |object| object); + } + "" } #[inline] pub fn key(&self) -> &str { - self.key.as_ref().map_or(Self::DEFAULT, |key| key) + if self.enabled { + return self.key.as_ref().map_or("", |key| key); + } + "" } #[inline] pub fn null(&self) -> &str { - self.null.as_ref().map_or(Self::DEFAULT, |null| null) + if self.enabled { + return self.null.as_ref().map_or("", |null| null); + } + "" } #[inline] pub fn enum_member(&self) -> &str { - self.enum_member - .as_ref() - .map_or(Self::DEFAULT, |enum_member| enum_member) + if self.enabled { + return self + .enum_member + .as_ref() + .map_or("", |enum_member| enum_member); + } + "" } #[inline] pub fn r#struct(&self) -> &str { - self.r#struct - .as_ref() - .map_or(Self::DEFAULT, |r#struct| r#struct) + if self.enabled { + return self.r#struct.as_ref().map_or("", |r#struct| r#struct); + } + "" } #[inline] pub fn event(&self) -> &str { - self.event.as_ref().map_or(Self::DEFAULT, |event| event) + if self.enabled { + return self.event.as_ref().map_or("", |event| event); + } + "" } #[inline] pub fn operator(&self) -> &str { - self.operator - .as_ref() - .map_or(Self::DEFAULT, |operator| operator) + if self.enabled { + return self.operator.as_ref().map_or("", |operator| operator); + } + "" } #[inline] pub fn type_parameter(&self) -> &str { - self.type_parameter - .as_ref() - .map_or(Self::DEFAULT, |type_parameter| type_parameter) + if self.enabled { + return self + .type_parameter + .as_ref() + .map_or("", |type_parameter| type_parameter); + } + "" } } @@ -213,78 +274,128 @@ pub struct Diagnostic { error: Option<String>, } -// NOTE: #6646 can be achieved by uncommenting this or adding the symbols -// to the `map_or` default. -// impl Default for Diagnostic { -// fn default() -> Self { -// Self { -// hint: Some(String::from("○")), -// info: Some(String::from("●")), -// warning: Some(String::from("▲")), -// error: Some(String::from("■")), -// } -// } -// } - impl Diagnostic { - const DEFAULT: &'static str = "●"; - #[inline] pub fn hint(&self) -> &str { - self.hint.as_ref().map_or(Self::DEFAULT, |hint| hint) + self.hint.as_ref().map_or("○", |hint| hint) } #[inline] pub fn info(&self) -> &str { - self.info.as_ref().map_or(Self::DEFAULT, |info| info) + self.info.as_ref().map_or("●", |info| info) } #[inline] pub fn warning(&self) -> &str { - self.warning - .as_ref() - .map_or(Self::DEFAULT, |warning| warning) + self.warning.as_ref().map_or("▲", |warning| warning) } #[inline] pub fn error(&self) -> &str { - self.error.as_ref().map_or(Self::DEFAULT, |error| error) + self.error.as_ref().map_or("■", |error| error) } } #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Default)] pub struct Vcs { + enabled: bool, icon: Option<String>, } impl Vcs { - const DEFAULT: &'static str = ""; - #[inline] pub fn icon(&self) -> &str { - self.icon - .as_ref() - .map_or(Self::DEFAULT, |icon| icon.as_str()) + if self.enabled { + return self.icon.as_ref().map_or("", |icon| icon.as_str()); + } + "" } } #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Default)] pub struct Mime { + enabled: bool, directory: Option<String>, #[serde(flatten)] mime: HashMap<String, String>, } +static MIMES: once_cell::sync::Lazy<HashMap<String, String>> = once_cell::sync::Lazy::new(|| { + let mut mimes = HashMap::new(); + + mimes.insert(String::from("rust"), String::from("")); + mimes.insert(String::from("python"), String::from("")); + mimes.insert(String::from("c"), String::from("")); + mimes.insert(String::from("cpp"), String::from("")); + mimes.insert(String::from("c-sharp"), String::from("")); + mimes.insert(String::from("d"), String::from("")); + mimes.insert(String::from("elixir"), String::from("")); + mimes.insert(String::from("fsharp"), String::from("")); + mimes.insert(String::from("go"), String::from("")); + mimes.insert(String::from("haskell"), String::from("")); + mimes.insert(String::from("java"), String::from("")); + mimes.insert(String::from("javascript"), String::from("")); + mimes.insert(String::from("kotlin"), String::from("")); + mimes.insert(String::from("html"), String::from("")); + mimes.insert(String::from("css"), String::from("")); + mimes.insert(String::from("typescript"), String::from("")); + mimes.insert(String::from("bash"), String::from("")); + mimes.insert(String::from("php"), String::from("")); + mimes.insert(String::from("powershell"), String::from("")); + mimes.insert(String::from("dart"), String::from("")); + mimes.insert(String::from("ruby"), String::from("")); + mimes.insert(String::from("swift"), String::from("")); + mimes.insert(String::from("r"), String::from("")); + mimes.insert(String::from("groovy"), String::from("")); + mimes.insert(String::from("scala"), String::from("")); + mimes.insert(String::from("perl"), String::from("")); + mimes.insert(String::from("closure"), String::from("")); + mimes.insert(String::from("julia"), String::from("")); + mimes.insert(String::from("zig"), String::from("")); + mimes.insert(String::from("fortran"), String::from("")); + mimes.insert(String::from("erlang"), String::from("")); + mimes.insert(String::from("ocaml"), String::from("")); + mimes.insert(String::from("crystal"), String::from("")); + mimes.insert(String::from("svelte"), String::from("")); + mimes.insert(String::from("gdscript"), String::from("")); + mimes.insert(String::from("nim"), String::from("")); + + mimes.insert(String::from("docker"), String::from("")); + mimes.insert(String::from("make"), String::from("")); + mimes.insert(String::from("cmake"), String::from("")); + mimes.insert(String::from("nix"), String::from("")); + + mimes.insert(String::from("text"), String::from("")); + mimes.insert(String::from("markdown"), String::from("")); + mimes.insert(String::from("json"), String::from("")); + mimes.insert(String::from("toml"), String::from("")); + mimes.insert(String::from("xml"), String::from("")); + + mimes +}); + impl Mime { #[inline] pub fn directory(&self) -> &str { - self.directory.as_ref().map_or("", |directory| directory) + if self.enabled { + return self.directory.as_ref().map_or("", |directory| directory); + } else if let Some(directory) = &self.directory { + return directory; + } + "" } // Returns the symbol that matches the name, if any, otherwise returns the name back. #[inline] pub fn get<'name, 'mime: 'name>(&'mime self, r#type: &'name str) -> &'name str { - self.mime.get(r#type).map_or(r#type, |mime| mime) + if self.enabled { + if let Some(symbol) = self.mime.get(r#type) { + return symbol; + } else if let Some(symbol) = MIMES.get(r#type) { + return symbol; + } + } + r#type } } @@ -295,20 +406,13 @@ pub struct Dap { } impl Dap { - const DEFAULT_VERIFIED: &'static str = "●"; - const DEFAULT_UNVERIFIED: &'static str = "◯"; - #[inline] pub fn verified(&self) -> &str { - self.verified - .as_ref() - .map_or(Self::DEFAULT_VERIFIED, |verified| verified) + self.verified.as_ref().map_or("●", |verified| verified) } #[inline] pub fn unverified(&self) -> &str { - self.verified - .as_ref() - .map_or(Self::DEFAULT_UNVERIFIED, |verified| verified) + self.verified.as_ref().map_or("◯", |verified| verified) } } From 0865ca281210b7abb6842752262b052b5c663dd7 Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Mon, 30 Dec 2024 16:31:49 -0800 Subject: [PATCH 08/16] perf: switch from `String` to `SmartString` --- Cargo.lock | 2 ++ helix-view/Cargo.toml | 2 ++ helix-view/src/editor/config.rs | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 8531d0a3..bff6e1db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1564,6 +1564,7 @@ dependencies = [ "serde", "serde_json", "slotmap", + "smartstring", "tempfile", "thiserror 2.0.11", "tokio", @@ -2419,6 +2420,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" dependencies = [ "autocfg", + "serde", "static_assertions", "version_check", ] diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index da9f52a2..eb1b660f 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -52,6 +52,8 @@ log = "~0.4" parking_lot = "0.12.3" thiserror.workspace = true +smartstring = { version = "1.0.1", features = ["serde"]} + [target.'cfg(windows)'.dependencies] clipboard-win = { version = "5.4", features = ["std"] } diff --git a/helix-view/src/editor/config.rs b/helix-view/src/editor/config.rs index 34d2a2cb..7865bd95 100644 --- a/helix-view/src/editor/config.rs +++ b/helix-view/src/editor/config.rs @@ -2,6 +2,10 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; +use smartstring::{LazyCompact, SmartString}; + +type String = SmartString<LazyCompact>; + #[derive(Debug, Serialize, Deserialize, Default, PartialEq, Eq, Clone)] #[serde(default)] pub struct Icons { From 952c9721674bf43975ccff10e8544b40bfbc3281 Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Tue, 31 Dec 2024 03:34:17 -0800 Subject: [PATCH 09/16] refactor: rename config.rs to icons.rs and move to top level --- helix-view/src/editor.rs | 5 ++--- helix-view/src/{editor/config.rs => icons.rs} | 0 helix-view/src/lib.rs | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) rename helix-view/src/{editor/config.rs => icons.rs} (100%) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 004d0bf1..eb30db62 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -7,6 +7,7 @@ use crate::{ events::DocumentFocusLost, graphics::{CursorKind, Rect}, handlers::Handlers, + icons, info::Info, input::KeyEvent, register::Registers, @@ -14,18 +15,16 @@ use crate::{ tree::{self, Tree}, Document, DocumentId, View, ViewId, }; -use config::Icons; use dap::StackFrame; use helix_event::dispatch; use helix_vcs::DiffProviderRegistry; +use icons::Icons; use futures_util::stream::select_all::SelectAll; use futures_util::{future, StreamExt}; use helix_lsp::{Call, LanguageServerId}; use tokio_stream::wrappers::UnboundedReceiverStream; -mod config; - use std::{ borrow::Cow, cell::Cell, diff --git a/helix-view/src/editor/config.rs b/helix-view/src/icons.rs similarity index 100% rename from helix-view/src/editor/config.rs rename to helix-view/src/icons.rs diff --git a/helix-view/src/lib.rs b/helix-view/src/lib.rs index d54b49ef..a5b45159 100644 --- a/helix-view/src/lib.rs +++ b/helix-view/src/lib.rs @@ -10,6 +10,7 @@ pub mod events; pub mod graphics; pub mod gutter; pub mod handlers; +pub mod icons; pub mod info; pub mod input; pub mod keyboard; From cec003ce99b35232f9da023b07f0e728666cea48 Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Tue, 31 Dec 2024 03:38:39 -0800 Subject: [PATCH 10/16] refactor: rename mime get param from type to name --- helix-view/src/icons.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/helix-view/src/icons.rs b/helix-view/src/icons.rs index 7865bd95..9d736973 100644 --- a/helix-view/src/icons.rs +++ b/helix-view/src/icons.rs @@ -391,15 +391,15 @@ impl Mime { // Returns the symbol that matches the name, if any, otherwise returns the name back. #[inline] - pub fn get<'name, 'mime: 'name>(&'mime self, r#type: &'name str) -> &'name str { + pub fn get<'name, 'mime: 'name>(&'mime self, name: &'name str) -> &'name str { if self.enabled { - if let Some(symbol) = self.mime.get(r#type) { + if let Some(symbol) = self.mime.get(name) { return symbol; - } else if let Some(symbol) = MIMES.get(r#type) { + } else if let Some(symbol) = MIMES.get(name) { return symbol; } } - r#type + name } } From 7267097e91dcdd2766d93b0ef77565b9a1acdf79 Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Tue, 31 Dec 2024 03:50:51 -0800 Subject: [PATCH 11/16] refactor: small renames for better clarity --- helix-term/src/ui/statusline.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/helix-term/src/ui/statusline.rs b/helix-term/src/ui/statusline.rs index 0034db61..f02b4b88 100644 --- a/helix-term/src/ui/statusline.rs +++ b/helix-term/src/ui/statusline.rs @@ -422,9 +422,11 @@ fn render_file_type<F>(context: &mut RenderContext, write: F) where F: Fn(&mut RenderContext, String, Option<Style>) + Copy, { - let mime = &context.editor.config().icons.mime; + let icons = &context.editor.config().icons; - let icon = mime.get(context.doc.language_name().unwrap_or(DEFAULT_LANGUAGE_NAME)); + let icon = icons + .mime + .get(context.doc.language_name().unwrap_or(DEFAULT_LANGUAGE_NAME)); write(context, format!(" {} ", icon), None); } @@ -530,8 +532,8 @@ where { let head = context.doc.version_control_head().unwrap_or_default(); - let config = context.editor.config(); - let icon = config.icons.vcs.icon(); + let icons = &context.editor.config().icons; + let icon = icons.vcs.icon(); let vcs = if head.is_empty() { format!("{head}") From c8e3a569ce071ba492d6b55a330c77d66067f415 Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Tue, 31 Dec 2024 03:51:19 -0800 Subject: [PATCH 12/16] doc: add description for `Icons` in `Editor` --- helix-view/src/editor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index eb30db62..f48eb77b 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -362,7 +362,7 @@ pub struct Config { pub end_of_line_diagnostics: DiagnosticFilter, // Set to override the default clipboard provider pub clipboard_provider: ClipboardProvider, - + /// Centralized location for icons that can be used throughout the UI pub icons: Icons, } From 0d3e4f3bb89ad4bffd32d85ca250abe8eb4b3e32 Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Tue, 31 Dec 2024 08:10:54 -0800 Subject: [PATCH 13/16] refactor: tweak with bufferline icon spacing --- helix-term/src/ui/editor.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 4f5b1cc3..267e63cc 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -650,11 +650,16 @@ impl EditorView { let config = editor.config(); let icon = config.icons.mime.get(lang); - let text = format!( - " {icon} {}{} ", - fname, - if doc.is_modified() { "[+]" } else { "" } - ); + let text = if lang == icon { + format!(" {} {}", fname, if doc.is_modified() { "[+] " } else { "" }) + } else { + format!( + " {icon} {} {}", + fname, + if doc.is_modified() { "[+] " } else { "" } + ) + }; + let used_width = viewport.x.saturating_sub(x); let rem_width = surface.area.width.saturating_sub(used_width); From 4a37fe0f58fa95dddeb72c0fe6399cefa0ab1dcd Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Sat, 4 Jan 2025 07:44:22 -0800 Subject: [PATCH 14/16] refactor: change lsp icons to `nf-cod-symbol` where possible --- helix-view/src/icons.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/helix-view/src/icons.rs b/helix-view/src/icons.rs index 9d736973..c46e1dcf 100644 --- a/helix-view/src/icons.rs +++ b/helix-view/src/icons.rs @@ -170,7 +170,7 @@ impl Lsp { #[inline] pub fn string(&self) -> &str { if self.enabled { - return self.string.as_ref().map_or("", |string| string); + return self.string.as_ref().map_or("", |string| string); } "" } @@ -178,7 +178,7 @@ impl Lsp { #[inline] pub fn number(&self) -> &str { if self.enabled { - return self.number.as_ref().map_or("", |number| number); + return self.number.as_ref().map_or("", |number| number); } "" } @@ -210,7 +210,7 @@ impl Lsp { #[inline] pub fn key(&self) -> &str { if self.enabled { - return self.key.as_ref().map_or("", |key| key); + return self.key.as_ref().map_or("", |key| key); } "" } From fd54ee930cce4f1fc6c63aad2abd7c9fec62177b Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Sat, 4 Jan 2025 09:01:31 -0800 Subject: [PATCH 15/16] feat: add more icons for supported languages --- helix-view/src/icons.rs | 44 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/helix-view/src/icons.rs b/helix-view/src/icons.rs index c46e1dcf..d22ed522 100644 --- a/helix-view/src/icons.rs +++ b/helix-view/src/icons.rs @@ -6,6 +6,7 @@ use smartstring::{LazyCompact, SmartString}; type String = SmartString<LazyCompact>; + #[derive(Debug, Serialize, Deserialize, Default, PartialEq, Eq, Clone)] #[serde(default)] pub struct Icons { @@ -342,6 +343,7 @@ static MIMES: once_cell::sync::Lazy<HashMap<String, String>> = once_cell::sync:: mimes.insert(String::from("kotlin"), String::from("")); mimes.insert(String::from("html"), String::from("")); mimes.insert(String::from("css"), String::from("")); + mimes.insert(String::from("scss"), String::from("")); mimes.insert(String::from("typescript"), String::from("")); mimes.insert(String::from("bash"), String::from("")); mimes.insert(String::from("php"), String::from("")); @@ -353,7 +355,7 @@ static MIMES: once_cell::sync::Lazy<HashMap<String, String>> = once_cell::sync:: mimes.insert(String::from("groovy"), String::from("")); mimes.insert(String::from("scala"), String::from("")); mimes.insert(String::from("perl"), String::from("")); - mimes.insert(String::from("closure"), String::from("")); + mimes.insert(String::from("clojure"), String::from("")); mimes.insert(String::from("julia"), String::from("")); mimes.insert(String::from("zig"), String::from("")); mimes.insert(String::from("fortran"), String::from("")); @@ -363,17 +365,57 @@ static MIMES: once_cell::sync::Lazy<HashMap<String, String>> = once_cell::sync:: mimes.insert(String::from("svelte"), String::from("")); mimes.insert(String::from("gdscript"), String::from("")); mimes.insert(String::from("nim"), String::from("")); + mimes.insert(String::from("jsx"), String::from("")); + mimes.insert(String::from("tsx"), String::from("")); + mimes.insert(String::from("twig"), String::from("")); + mimes.insert(String::from("lua"), String::from("")); + mimes.insert(String::from("vue"), String::from("")); + mimes.insert(String::from("prolog"), String::from("")); + mimes.insert(String::from("common-lisp"), String::from("")); + mimes.insert(String::from("elm"), String::from("")); + mimes.insert(String::from("rescript"), String::from("")); + mimes.insert(String::from("solidity"), String::from("")); + mimes.insert(String::from("vala"), String::from("")); + mimes.insert(String::from("scheme"), String::from("")); + mimes.insert(String::from("v"), String::from("")); + mimes.insert(String::from("prisma"), String::from("")); + mimes.insert(String::from("ada"), String::from("")); + mimes.insert(String::from("astro"), String::from("")); + mimes.insert(String::from("matlab"), String::from("")); + mimes.insert(String::from("rst"), String::from("")); + mimes.insert(String::from("opencl"), String::from("")); + mimes.insert(String::from("nunjuks"), String::from("")); + mimes.insert(String::from("jinja"), String::from("")); + + mimes.insert(String::from("bicep"), String::from("")); + + mimes.insert(String::from("wasm"), String::from("")); mimes.insert(String::from("docker"), String::from("")); + mimes.insert(String::from("docker-compose"), String::from("")); mimes.insert(String::from("make"), String::from("")); mimes.insert(String::from("cmake"), String::from("")); mimes.insert(String::from("nix"), String::from("")); + mimes.insert(String::from("awk"), String::from("")); + mimes.insert(String::from("llvm"), String::from("")); + mimes.insert(String::from("llvm-mir"), String::from("")); + mimes.insert(String::from("regex"), String::from("")); + mimes.insert(String::from("graphql"), String::from("")); mimes.insert(String::from("text"), String::from("")); mimes.insert(String::from("markdown"), String::from("")); + mimes.insert(String::from("typst"), String::from("")); mimes.insert(String::from("json"), String::from("")); mimes.insert(String::from("toml"), String::from("")); mimes.insert(String::from("xml"), String::from("")); + mimes.insert(String::from("latex"), String::from("")); + mimes.insert(String::from("git-commit"), String::from("")); + mimes.insert(String::from("git-rebase"), String::from("")); + mimes.insert(String::from("git-config"), String::from("")); + mimes.insert(String::from("todotxt"), String::from("")); + mimes.insert(String::from("hyprlang"), String::from("")); + mimes.insert(String::from("helm"), String::from("")); + mimes.insert(String::from("nginx"), String::from("")); mimes }); From f445f86d26737bdff6bc88cf974928dfa09f0d05 Mon Sep 17 00:00:00 2001 From: Rolo <roloedits@gmail.com> Date: Sat, 4 Jan 2025 09:02:52 -0800 Subject: [PATCH 16/16] todo: outline more icon domains and sets --- helix-view/src/icons.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/helix-view/src/icons.rs b/helix-view/src/icons.rs index d22ed522..f7e1984e 100644 --- a/helix-view/src/icons.rs +++ b/helix-view/src/icons.rs @@ -6,6 +6,9 @@ use smartstring::{LazyCompact, SmartString}; type String = SmartString<LazyCompact>; +// TODO: Vcs { added , removed , ignored , modified , renamed } +// TODO: Snippet {enabled, icon } +// TODO: Text/Spellcheck { enabled, icon } #[derive(Debug, Serialize, Deserialize, Default, PartialEq, Eq, Clone)] #[serde(default)]