Skip to content

Commit

Permalink
editor: In OpenFile check if file with path_suffix exists (#17805)
Browse files Browse the repository at this point in the history
Demo:


https://github.com/user-attachments/assets/6acb6c1e-bb15-4205-9dcb-2aa4bb99dcf9



Release Notes:

- When using `OpenFile` (`gf` in Vim mode) and the word under the cursor
is not an existing file path, we now fall back and additionally check
whether a file called
`<word-under-cursor>.<language-specific-path-suffixes>` exists. That's
similar to Vim's `suffixesadd` option.

---------

Co-authored-by: Abdelhakim Qbaich <abdelhakim@qbaich.com>
Co-authored-by: Pete LeVasseur <plevasseur@gmail.com>
  • Loading branch information
3 people authored Sep 13, 2024
1 parent 8f833ea commit adbe973
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 9 deletions.
69 changes: 60 additions & 9 deletions crates/editor/src/hover_links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -713,17 +713,42 @@ pub(crate) async fn find_file(
cx: &mut AsyncWindowContext,
) -> Option<(Range<text::Anchor>, ResolvedPath)> {
let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot()).ok()?;

let scope = snapshot.language_scope_at(position);
let (range, candidate_file_path) = surrounding_filename(snapshot, position)?;

let existing_path = project
.update(cx, |project, cx| {
project.resolve_existing_file_path(&candidate_file_path, buffer, cx)
})
.ok()?
.await?;
async fn check_path(
candidate_file_path: &str,
project: &Model<Project>,
buffer: &Model<language::Buffer>,
cx: &mut AsyncWindowContext,
) -> Option<ResolvedPath> {
project
.update(cx, |project, cx| {
project.resolve_existing_file_path(&candidate_file_path, buffer, cx)
})
.ok()?
.await
}

Some((range, existing_path))
if let Some(existing_path) = check_path(&candidate_file_path, &project, buffer, cx).await {
return Some((range, existing_path));
}

if let Some(scope) = scope {
for suffix in scope.path_suffixes() {
if candidate_file_path.ends_with(format!(".{suffix}").as_str()) {
continue;
}

let suffixed_candidate = format!("{candidate_file_path}.{suffix}");
if let Some(existing_path) = check_path(&suffixed_candidate, &project, buffer, cx).await
{
return Some((range, existing_path));
}
}
}

None
}

fn surrounding_filename(
Expand Down Expand Up @@ -1490,7 +1515,8 @@ mod tests {
You can't go to a file that does_not_exist.txt.
Go to file2.rs if you want.
Or go to ../dir/file2.rs if you want.
Or go to /root/dir/file2.rs if project is local.ˇ
Or go to /root/dir/file2.rs if project is local.
Or go to /root/dir/file2 if this is a Rust file.ˇ
"});

// File does not exist
Expand All @@ -1499,6 +1525,7 @@ mod tests {
Go to file2.rs if you want.
Or go to ../dir/file2.rs if you want.
Or go to /root/dir/file2.rs if project is local.
Or go to /root/dir/file2 if this is a Rust file.
"});
cx.simulate_mouse_move(screen_coord, None, Modifiers::secondary_key());
// No highlight
Expand All @@ -1517,6 +1544,7 @@ mod tests {
Go to fˇile2.rs if you want.
Or go to ../dir/file2.rs if you want.
Or go to /root/dir/file2.rs if project is local.
Or go to /root/dir/file2 if this is a Rust file.
"});

cx.simulate_mouse_move(screen_coord, None, Modifiers::secondary_key());
Expand All @@ -1525,6 +1553,7 @@ mod tests {
Go to «file2.rsˇ» if you want.
Or go to ../dir/file2.rs if you want.
Or go to /root/dir/file2.rs if project is local.
Or go to /root/dir/file2 if this is a Rust file.
"});

// Moving the mouse over a relative path that does exist should highlight it
Expand All @@ -1533,6 +1562,7 @@ mod tests {
Go to file2.rs if you want.
Or go to ../dir/fˇile2.rs if you want.
Or go to /root/dir/file2.rs if project is local.
Or go to /root/dir/file2 if this is a Rust file.
"});

cx.simulate_mouse_move(screen_coord, None, Modifiers::secondary_key());
Expand All @@ -1541,6 +1571,7 @@ mod tests {
Go to file2.rs if you want.
Or go to «../dir/file2.rsˇ» if you want.
Or go to /root/dir/file2.rs if project is local.
Or go to /root/dir/file2 if this is a Rust file.
"});

// Moving the mouse over an absolute path that does exist should highlight it
Expand All @@ -1549,6 +1580,7 @@ mod tests {
Go to file2.rs if you want.
Or go to ../dir/file2.rs if you want.
Or go to /root/diˇr/file2.rs if project is local.
Or go to /root/dir/file2 if this is a Rust file.
"});

cx.simulate_mouse_move(screen_coord, None, Modifiers::secondary_key());
Expand All @@ -1557,6 +1589,25 @@ mod tests {
Go to file2.rs if you want.
Or go to ../dir/file2.rs if you want.
Or go to «/root/dir/file2.rsˇ» if project is local.
Or go to /root/dir/file2 if this is a Rust file.
"});

// Moving the mouse over a path that exists, if we add the language-specific suffix, it should highlight it
let screen_coord = cx.pixel_position(indoc! {"
You can't go to a file that does_not_exist.txt.
Go to file2.rs if you want.
Or go to ../dir/file2.rs if you want.
Or go to /root/dir/file2.rs if project is local.
Or go to /root/diˇr/file2 if this is a Rust file.
"});

cx.simulate_mouse_move(screen_coord, None, Modifiers::secondary_key());
cx.assert_editor_text_highlights::<HoveredLinkState>(indoc! {"
You can't go to a file that does_not_exist.txt.
Go to file2.rs if you want.
Or go to ../dir/file2.rs if you want.
Or go to /root/dir/file2.rs if project is local.
Or go to «/root/dir/file2ˇ» if this is a Rust file.
"});

cx.simulate_click(screen_coord, Modifiers::secondary_key());
Expand Down
4 changes: 4 additions & 0 deletions crates/language/src/language.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,10 @@ impl Language {
}

impl LanguageScope {
pub fn path_suffixes(&self) -> &[String] {
&self.language.path_suffixes()
}

pub fn language_name(&self) -> LanguageName {
self.language.config.name.clone()
}
Expand Down
19 changes: 19 additions & 0 deletions crates/vim/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,9 @@ mod test {
fs.as_fake()
.insert_file("/root/dir/file2.rs", "This is file2.rs".as_bytes().to_vec())
.await;
fs.as_fake()
.insert_file("/root/dir/file3.rs", "go to file3".as_bytes().to_vec())
.await;

// Put the path to the second file into the currently open buffer
cx.set_state(indoc! {"go to fiˇle2.rs"}, Mode::Normal);
Expand All @@ -981,5 +984,21 @@ mod test {
cx.workspace(|workspace, cx| {
assert_active_item(workspace, "/root/dir/file2.rs", "This is file2.rs", cx);
});

// Update editor to point to `file2.rs`
cx.editor = cx.workspace(|workspace, cx| workspace.active_item_as::<Editor>(cx).unwrap());

// Put the path to the third file into the currently open buffer,
// but remove its suffix, because we want that lookup to happen automatically.
cx.set_state(indoc! {"go to fiˇle3"}, Mode::Normal);

// Go to file3.rs
cx.simulate_keystrokes("g f");

// We now have three items
cx.workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 3));
cx.workspace(|workspace, cx| {
assert_active_item(workspace, "/root/dir/file3.rs", "go to file3", cx);
});
}
}

0 comments on commit adbe973

Please sign in to comment.