Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--helix-term/src/commands.rs67
-rw-r--r--helix-term/tests/test/commands.rs22
2 files changed, 70 insertions, 19 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 7f43fa9c..99e7608f 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -4,7 +4,10 @@ pub(crate) mod typed;
pub use dap::*;
use helix_event::status;
-use helix_stdx::rope::{self, RopeSliceExt};
+use helix_stdx::{
+ path::expand_tilde,
+ rope::{self, RopeSliceExt},
+};
use helix_vcs::{FileChange, Hunk};
pub use lsp::*;
use tui::{
@@ -1196,25 +1199,51 @@ fn goto_file_impl(cx: &mut Context, action: Action) {
let primary = selections.primary();
// Checks whether there is only one selection with a width of 1
if selections.len() == 1 && primary.len() == 1 {
- let count = cx.count();
- let text_slice = text.slice(..);
- // In this case it selects the WORD under the cursor
- let current_word = textobject::textobject_word(
- text_slice,
- primary,
- textobject::TextObject::Inside,
- count,
- true,
- );
- // Trims some surrounding chars so that the actual file is opened.
- let surrounding_chars: &[_] = &['\'', '"', '(', ')'];
paths.clear();
- paths.push(
- current_word
- .fragment(text_slice)
- .trim_matches(surrounding_chars)
- .to_string(),
- );
+
+ let is_valid_path_char = |c: &char| {
+ #[cfg(target_os = "windows")]
+ let valid_chars = &[
+ '@', '/', '\\', '.', '-', '_', '+', '#', '$', '%', '{', '}', '[', ']', ':', '!',
+ '~', '=',
+ ];
+ #[cfg(not(target_os = "windows"))]
+ let valid_chars = &['@', '/', '.', '-', '_', '+', '#', '$', '%', '~', '=', ':'];
+
+ valid_chars.contains(c) || c.is_alphabetic() || c.is_numeric()
+ };
+
+ let cursor_pos = primary.cursor(text.slice(..));
+ let pre_cursor_pos = cursor_pos.saturating_sub(1);
+ let post_cursor_pos = cursor_pos + 1;
+ let start_pos = if is_valid_path_char(&text.char(cursor_pos)) {
+ cursor_pos
+ } else if is_valid_path_char(&text.char(pre_cursor_pos)) {
+ pre_cursor_pos
+ } else {
+ post_cursor_pos
+ };
+
+ let prefix_len = text
+ .chars_at(start_pos)
+ .reversed()
+ .take_while(is_valid_path_char)
+ .count();
+
+ let postfix_len = text
+ .chars_at(start_pos)
+ .take_while(is_valid_path_char)
+ .count();
+
+ let path: Cow<str> = text
+ .slice((start_pos - prefix_len)..(start_pos + postfix_len))
+ .into();
+ log::debug!("Goto file path: {}", path);
+
+ match expand_tilde(PathBuf::from(path.as_ref())).to_str() {
+ Some(path) => paths.push(path.to_string()),
+ None => cx.editor.set_error("Couldn't get string out of path."),
+ };
}
for sel in paths {
diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs
index aaa442f3..351f07fe 100644
--- a/helix-term/tests/test/commands.rs
+++ b/helix-term/tests/test/commands.rs
@@ -153,6 +153,28 @@ async fn test_goto_file_impl() -> anyhow::Result<()> {
)
.await?;
+ // ';' is behind the path
+ test_key_sequence(
+ &mut AppBuilder::new().with_file(file.path(), None).build()?,
+ Some("iimport 'one.js';<esc>B;gf"),
+ Some(&|app| {
+ assert_eq!(1, match_paths(app, vec!["one.js"]));
+ }),
+ false,
+ )
+ .await?;
+
+ // allow numeric values in path
+ test_key_sequence(
+ &mut AppBuilder::new().with_file(file.path(), None).build()?,
+ Some("iimport 'one123.js'<esc>B;gf"),
+ Some(&|app| {
+ assert_eq!(1, match_paths(app, vec!["one123.js"]));
+ }),
+ false,
+ )
+ .await?;
+
Ok(())
}