From a4a0e386ebdd9d9095247e7cb12f95eb0ed072c1 Mon Sep 17 00:00:00 2001 From: RivoLink Date: Fri, 26 Jun 2026 20:07:24 +0300 Subject: [PATCH] feat: editor config path placeholder Extend editor config placeholders with {$path} --- README.md | 6 ++++++ config.toml | 3 +++ src/config.rs | 2 +- src/editor.rs | 7 +++++-- src/main.rs | 2 +- src/runtime/mouse.rs | 2 +- src/tests/editor.rs | 40 ++++++++++++++++++++++++++++++---------- 7 files changed, 47 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 8bc61c0..fb724aa 100644 --- a/README.md +++ b/README.md @@ -181,6 +181,12 @@ editor = 'nano +{$line}' editor = 'nvim +{$line} +"normal! zz"' ``` +For further customization, `{$path}` is also available for the file path: + +```toml +editor = 'code -g {$path}:{$line}' +``` + Without `{$line}`, the editor opens at the top of the file. ## Extra Files diff --git a/config.toml b/config.toml index 3de4edd..d5bfe42 100644 --- a/config.toml +++ b/config.toml @@ -40,6 +40,9 @@ theme = "ocean" # editor = 'nano +{$line}' # editor = 'nvim +{$line} +"normal! zz"' # +# Also, {$path} offers more customization options: +# editor = 'code -g {$path}:{$line}' +# # Priority: --editor flag > LEAF_EDITOR > this setting > nano (notepad on Windows) # editor = "nano" diff --git a/src/config.rs b/src/config.rs index 88376b3..ad8234b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -148,7 +148,7 @@ fn open_config_in_editor(path: &Path) -> anyhow::Result<()> { } fn launch_editor(editor: &str, path: &Path) { - let expanded = crate::editor::expand_line_placeholder(editor, 1); + let expanded = crate::editor::expand_editor_placeholders(editor, 1, path); if try_launch_editor(&expanded, path) { return; } diff --git a/src/editor.rs b/src/editor.rs index 331c9dd..d22c7c7 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -2,9 +2,12 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; const EDITOR_LINE_PLACEHOLDER: &str = "{$line}"; +const EDITOR_PATH_PLACEHOLDER: &str = "{$path}"; -pub(crate) fn expand_line_placeholder(editor_cmd: &str, line: usize) -> String { - editor_cmd.replace(EDITOR_LINE_PLACEHOLDER, &line.to_string()) +pub(crate) fn expand_editor_placeholders(editor_cmd: &str, line: usize, path: &Path) -> String { + editor_cmd + .replace(EDITOR_LINE_PLACEHOLDER, &line.to_string()) + .replace(EDITOR_PATH_PLACEHOLDER, &path.display().to_string()) } #[derive(Clone, Copy, Debug, PartialEq, Eq)] diff --git a/src/main.rs b/src/main.rs index 19dc911..11588e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,7 +36,7 @@ const MAX_STDIN_BYTES: usize = 8 * 1024 * 1024; pub(crate) use config::{config_path, LeafConfig}; #[cfg(test)] pub(crate) use editor::{ - binary_name, classify, expand_line_placeholder, resolve_editor, selection_modifier_label, + binary_name, classify, expand_editor_placeholders, resolve_editor, selection_modifier_label, split_editor_cmd, try_new_tab_command, EditorKind, TerminalEmulator, }; #[cfg(test)] diff --git a/src/runtime/mouse.rs b/src/runtime/mouse.rs index e4d8a57..988bebe 100644 --- a/src/runtime/mouse.rs +++ b/src/runtime/mouse.rs @@ -233,7 +233,7 @@ pub(super) fn handle_open_in_editor( let editor_cmd = match app.editor_config() { Some(e) => { let visible_source_line = app.source_line_at(app.scroll()); - editor::expand_line_placeholder(e, visible_source_line) + editor::expand_editor_placeholders(e, visible_source_line, &filepath) } None => { app.set_editor_flash(EditorFlash::EditorNotFound("no editor configured".into())); diff --git a/src/tests/editor.rs b/src/tests/editor.rs index 8a597cf..5c3d180 100644 --- a/src/tests/editor.rs +++ b/src/tests/editor.rs @@ -261,35 +261,55 @@ fn resolve_editor_config_takes_priority_over_fallback() { } #[test] -fn expand_line_placeholder_no_placeholder_returns_unchanged() { - let result = expand_line_placeholder("nvim", 42); +fn expand_editor_placeholders_no_placeholder_returns_unchanged() { + let result = expand_editor_placeholders("nvim", 42, Path::new("")); assert_eq!(result, "nvim"); } #[test] -fn expand_line_placeholder_substitutes_single_occurrence() { - let result = expand_line_placeholder("nvim +{$line}", 42); +fn expand_editor_placeholders_substitutes_single_occurrence() { + let result = expand_editor_placeholders("nvim +{$line}", 42, Path::new("")); assert_eq!(result, "nvim +42"); } #[test] -fn expand_line_placeholder_substitutes_all_occurrences() { - let result = expand_line_placeholder("code -g {$line}:{$line}", 7); +fn expand_editor_placeholders_substitutes_all_occurrences() { + let result = expand_editor_placeholders("code -g {$line}:{$line}", 7, Path::new("")); assert_eq!(result, "code -g 7:7"); } #[test] -fn expand_line_placeholder_preserves_surrounding_chars() { - let result = expand_line_placeholder(r#"nvim +{$line} +"normal! zz""#, 123); +fn expand_editor_placeholders_preserves_surrounding_chars() { + let result = expand_editor_placeholders(r#"nvim +{$line} +"normal! zz""#, 123, Path::new("")); assert_eq!(result, r#"nvim +123 +"normal! zz""#); } #[test] -fn expand_line_placeholder_ignores_unsupported_variants() { - let result = expand_line_placeholder("nvim +${line} +{line} +{$LINE}", 5); +fn expand_editor_placeholders_ignores_unsupported_variants() { + let result = expand_editor_placeholders("nvim +${line} +{line} +{$LINE}", 5, Path::new("")); assert_eq!(result, "nvim +${line} +{line} +{$LINE}"); } +#[test] +fn expand_editor_placeholders_line_and_path() { + let result = expand_editor_placeholders("code -g {$path}:{$line}", 0, Path::new("file.rs")); + assert_eq!(result, "code -g file.rs:0"); +} + +#[test] +fn expand_editor_placeholders_multiple_occurrences() { + let result = + expand_editor_placeholders("code {$path} && echo {$path}", 1, Path::new("test.md")); + assert_eq!(result, "code test.md && echo test.md"); +} + +#[test] +fn expand_editor_placeholders_full_path() { + let result = + expand_editor_placeholders("code -g {$path}:{$line}", 8, Path::new("/tmp/file.rs")); + assert_eq!(result, "code -g /tmp/file.rs:8"); +} + #[test] fn split_editor_cmd_quoted_arg_with_space() { let (bin, args) = split_editor_cmd(r#"nvim +123 +"normal! zz""#);