From 29143bfa9a41c7e4779e3ef74dadf03910b9d17b Mon Sep 17 00:00:00 2001 From: Rolo Date: Wed, 25 Dec 2024 22:39:57 -0800 Subject: [PATCH] refactor: make `CustomTypableCommands` cheaper to clone --- helix-term/src/commands/typed.rs | 36 +++++++------------ helix-view/src/commands/custom.rs | 60 ++++++++++++++----------------- helix-view/src/editor.rs | 1 + 3 files changed, 41 insertions(+), 56 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 1797647f35fe..39adbd434e1e 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1,7 +1,6 @@ use std::fmt::Write; use std::io::BufReader; use std::ops::Deref; -use std::sync::Arc; use crate::job::Job; @@ -3060,9 +3059,7 @@ pub static TYPABLE_COMMAND_MAP: Lazy>() - } else { - TYPABLE_COMMAND_LIST - .iter() - .map(|command| command.name) - .chain(names) - .map(|name| name.to_string()) - .collect::>() - }; + let items = TYPABLE_COMMAND_LIST + .iter() + .map(|command| command.name) + .chain(commands.names()) + // HACK: `to_string` because of lifetimes: + // + // captured variable cannot escape `FnMut` closure body + // `FnMut` closures only have access to their captured variables while they are executing + // therefore, they cannot allow references to captured variables to escape + .map(|name| name.to_string()); if command.is_empty() || (shellwords.args().next().is_none() && !shellwords.ends_with_whitespace()) @@ -3298,11 +3288,11 @@ pub(super) fn command_mode(cx: &mut Context) { }, ); - let commands = arced.clone(); + let commands = cx.editor.config().commands.clone(); prompt.doc_fn = Box::new(move |input: &str| { let shellwords = Shellwords::from(input); - if let Some(command) = commands.clone().get(input) { + if let Some(command) = commands.get(input) { return Some(command.prompt().into()); } else if let Some(typed::TypableCommand { doc, aliases, .. }) = typed::TYPABLE_COMMAND_MAP.get(shellwords.command()) diff --git a/helix-view/src/commands/custom.rs b/helix-view/src/commands/custom.rs index b9069b8b0b99..5cfa4f1e743e 100644 --- a/helix-view/src/commands/custom.rs +++ b/helix-view/src/commands/custom.rs @@ -4,15 +4,11 @@ // TODO: Need to get access to a new table in the config: [commands]. // TODO: Could add an `aliases` to `CustomTypableCommand` and then add those as well? -use std::fmt::Write; +use std::{fmt::Write, sync::Arc}; -use serde::{Deserialize, Serialize}; - -// TODO: Might need to manually implement Serialize and Deserialize -// -Will need to do so if want to use `Arc` to make cloning cheaper. -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct CustomTypeableCommands { - pub commands: Vec, + pub commands: Arc<[CustomTypableCommand]>, } impl Default for CustomTypeableCommands { @@ -20,30 +16,29 @@ impl Default for CustomTypeableCommands { Self { commands: vec![ CustomTypableCommand { - name: String::from(":lg"), - desc: Some(String::from("runs lazygit in a floating pane")), - commands: vec![String::from( - ":sh wezterm cli spawn --floating-pane lazygit", - )], + name: Arc::from(":lg"), + desc: Some(Arc::from("runs lazygit in a floating pane")), + commands: vec![Arc::from(":sh wezterm cli spawn --floating-pane lazygit")] + .into(), accepts: None, completer: None, }, CustomTypableCommand { - name: String::from(":w"), - desc: Some(String::from( - "writes buffer forcefully and changes directory", - )), + name: Arc::from(":w"), + desc: Some(Arc::from("writes buffer forcefully and changes directory")), commands: vec![ - String::from(":write --force %{arg}"), - String::from(":cd %sh{ %{arg} | path dirname }"), - String::from(":cd %sh{ %{arg} | path dirname }"), - String::from(":cd %sh{ %{arg} | path dirname }"), - String::from(":cd %sh{ %{arg} | path dirname }"), - ], - accepts: Some(String::from("")), - completer: Some(String::from(":write")), + Arc::from(":write --force %{arg}"), + Arc::from(":cd %sh{ %{arg} | path dirname }"), + Arc::from(":cd %sh{ %{arg} | path dirname }"), + Arc::from(":cd %sh{ %{arg} | path dirname }"), + Arc::from(":cd %sh{ %{arg} | path dirname }"), + ] + .into(), + accepts: Some(Arc::from("")), + completer: Some(Arc::from(":write")), }, - ], + ] + .into(), } } } @@ -62,18 +57,17 @@ impl CustomTypeableCommands { self.commands .iter() // ":wbc!" -> "wbc!" - .map(|command| command.name.as_str().trim_start_matches(':')) + .map(|command| command.name.as_ref()) } } -// TODO: Arc ? -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct CustomTypableCommand { - pub name: String, - pub desc: Option, - pub commands: Vec, - pub accepts: Option, - pub completer: Option, + pub name: Arc, + pub desc: Option>, + pub commands: Arc<[Arc]>, + pub accepts: Option>, + pub completer: Option>, } impl CustomTypableCommand { diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 2e648302c281..776ef90f7454 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -361,6 +361,7 @@ pub struct Config { pub end_of_line_diagnostics: DiagnosticFilter, // Set to override the default clipboard provider pub clipboard_provider: ClipboardProvider, + #[serde(skip)] /// Custom typeable commands pub commands: CustomTypeableCommands, }