remote ssh: Make "get permalink to line" work (#19366)

This makes the `editor: copy permalink to line` and `editor: copy
permalink to line` actions work in SSH remote projects.

Previously it would only work in local projects.

Demo:


https://github.com/user-attachments/assets/a8012152-b631-4b34-9ff2-e4d033c97dee




Release Notes:

- N/A
This commit is contained in:
Thorsten Ball 2024-10-17 17:07:42 +02:00 committed by GitHub
parent c186e99a3d
commit 4be9da2641
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 219 additions and 79 deletions

View file

@ -48,7 +48,6 @@ mod signature_help;
pub mod test;
use ::git::diff::DiffHunkStatus;
use ::git::{parse_git_remote_url, BuildPermalinkParams, GitHostingProviderRegistry};
pub(crate) use actions::*;
use aho_corasick::AhoCorasick;
use anyhow::{anyhow, Context as _, Result};
@ -11488,11 +11487,8 @@ impl Editor {
snapshot.line_len(buffer_row) == 0
}
fn get_permalink_to_line(&mut self, cx: &mut ViewContext<Self>) -> Result<url::Url> {
let (path, selection, repo) = maybe!({
let project_handle = self.project.as_ref()?.clone();
let project = project_handle.read(cx);
fn get_permalink_to_line(&mut self, cx: &mut ViewContext<Self>) -> Task<Result<url::Url>> {
let buffer_and_selection = maybe!({
let selection = self.selections.newest::<Point>(cx);
let selection_range = selection.range();
@ -11516,64 +11512,58 @@ impl Editor {
(buffer.clone(), selection)
};
let path = buffer
.read(cx)
.file()?
.as_local()?
.path()
.to_str()?
.to_string();
let repo = project.get_repo(&buffer.read(cx).project_path(cx)?, cx)?;
Some((path, selection, repo))
Some((buffer, selection))
});
let Some((buffer, selection)) = buffer_and_selection else {
return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
};
let Some(project) = self.project.as_ref() else {
return Task::ready(Err(anyhow!("editor does not have project")));
};
project.update(cx, |project, cx| {
project.get_permalink_to_line(&buffer, selection, cx)
})
.ok_or_else(|| anyhow!("unable to open git repository"))?;
const REMOTE_NAME: &str = "origin";
let origin_url = repo
.remote_url(REMOTE_NAME)
.ok_or_else(|| anyhow!("remote \"{REMOTE_NAME}\" not found"))?;
let sha = repo
.head_sha()
.ok_or_else(|| anyhow!("failed to read HEAD SHA"))?;
let (provider, remote) =
parse_git_remote_url(GitHostingProviderRegistry::default_global(cx), &origin_url)
.ok_or_else(|| anyhow!("failed to parse Git remote URL"))?;
Ok(provider.build_permalink(
remote,
BuildPermalinkParams {
sha: &sha,
path: &path,
selection: Some(selection),
},
))
}
pub fn copy_permalink_to_line(&mut self, _: &CopyPermalinkToLine, cx: &mut ViewContext<Self>) {
let permalink = self.get_permalink_to_line(cx);
let permalink_task = self.get_permalink_to_line(cx);
let workspace = self.workspace();
match permalink {
Ok(permalink) => {
cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
}
Err(err) => {
let message = format!("Failed to copy permalink: {err}");
Err::<(), anyhow::Error>(err).log_err();
if let Some(workspace) = self.workspace() {
workspace.update(cx, |workspace, cx| {
struct CopyPermalinkToLine;
workspace.show_toast(
Toast::new(NotificationId::unique::<CopyPermalinkToLine>(), message),
cx,
)
cx.spawn(|_, mut cx| async move {
match permalink_task.await {
Ok(permalink) => {
cx.update(|cx| {
cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
})
.ok();
}
Err(err) => {
let message = format!("Failed to copy permalink: {err}");
Err::<(), anyhow::Error>(err).log_err();
if let Some(workspace) = workspace {
workspace
.update(&mut cx, |workspace, cx| {
struct CopyPermalinkToLine;
workspace.show_toast(
Toast::new(
NotificationId::unique::<CopyPermalinkToLine>(),
message,
),
cx,
)
})
.ok();
}
}
}
}
})
.detach();
}
pub fn copy_file_location(&mut self, _: &CopyFileLocation, cx: &mut ViewContext<Self>) {
@ -11586,29 +11576,41 @@ impl Editor {
}
pub fn open_permalink_to_line(&mut self, _: &OpenPermalinkToLine, cx: &mut ViewContext<Self>) {
let permalink = self.get_permalink_to_line(cx);
let permalink_task = self.get_permalink_to_line(cx);
let workspace = self.workspace();
match permalink {
Ok(permalink) => {
cx.open_url(permalink.as_ref());
}
Err(err) => {
let message = format!("Failed to open permalink: {err}");
Err::<(), anyhow::Error>(err).log_err();
if let Some(workspace) = self.workspace() {
workspace.update(cx, |workspace, cx| {
struct OpenPermalinkToLine;
workspace.show_toast(
Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
cx,
)
cx.spawn(|_, mut cx| async move {
match permalink_task.await {
Ok(permalink) => {
cx.update(|cx| {
cx.open_url(permalink.as_ref());
})
.ok();
}
Err(err) => {
let message = format!("Failed to open permalink: {err}");
Err::<(), anyhow::Error>(err).log_err();
if let Some(workspace) = workspace {
workspace
.update(&mut cx, |workspace, cx| {
struct OpenPermalinkToLine;
workspace.show_toast(
Toast::new(
NotificationId::unique::<OpenPermalinkToLine>(),
message,
),
cx,
)
})
.ok();
}
}
}
}
})
.detach();
}
/// Adds a row highlight for the given range. If a row has multiple highlights, the