Skip to content

Commit

Permalink
feat(lsp): implement show document request
Browse files Browse the repository at this point in the history
Implement [window.showDocument](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_showDocument)
LSP server-sent request.

This PR builds on top of helix-editor#5820,
moves the external-URL opening functionality into shared crate-level
function that returns a callback that is now used by both the
`open_file` command as well as the window.showDocument handler if
the URL is marked as external.
  • Loading branch information
matoous committed Dec 13, 2023
1 parent 7c55190 commit c85e95c
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 20 deletions.
5 changes: 5 additions & 0 deletions helix-lsp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@ pub enum MethodCall {
WorkspaceConfiguration(lsp::ConfigurationParams),
RegisterCapability(lsp::RegistrationParams),
UnregisterCapability(lsp::UnregistrationParams),
ShowDocument(lsp::ShowDocumentParams),
}

impl MethodCall {
Expand Down Expand Up @@ -576,6 +577,10 @@ impl MethodCall {
let params: lsp::UnregistrationParams = params.parse()?;
Self::UnregisterCapability(params)
}
lsp::request::ShowDocument::METHOD => {
let params: lsp::ShowDocumentParams = params.parse()?;
Self::ShowDocument(params)
}
_ => {
return Err(Error::Unhandled);
}
Expand Down
59 changes: 58 additions & 1 deletion helix-term/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use helix_core::{
};
use helix_lsp::{
lsp::{self, notification::Notification},
util::lsp_pos_to_pos,
util::{lsp_pos_to_pos, lsp_range_to_range},
LspProgressMap,
};
use helix_view::{
Expand Down Expand Up @@ -1134,6 +1134,63 @@ impl Application {
}
Ok(serde_json::Value::Null)
}
Ok(MethodCall::ShowDocument(params)) => {
let language_server = language_server!();
let offset_encoding = language_server.offset_encoding();

if params.external.unwrap_or_default() {
self.jobs
.callback(crate::open_external_url_callback(params.uri));
return;
}

let path = match params.uri.to_file_path() {
Ok(path) => path,
Err(_) => {
log::error!("Unsupported file URI: {}", params.uri);
return;
}
};

let action = match params.take_focus {
Some(true) => helix_view::editor::Action::Replace,
_ => helix_view::editor::Action::HorizontalSplit,
};

let doc = match self.editor.open(&path, action) {
Ok(id) => doc_mut!(self.editor, &id),
Err(err) => {
log::error!("failed to open path: {:?}: {:?}", params.uri, err);
return;
}
};

if let Some(range) = params.selection {
// TODO: convert inside server
let new_range = if let Some(new_range) =
lsp_range_to_range(doc.text(), range, offset_encoding)
{
new_range
} else {
log::warn!("lsp position out of bounds - {:?}", range);
return;
};

let view = view_mut!(self.editor);

// we flip the range so that the cursor sits on the start of the symbol
// (for example start of the function).
doc.set_selection(
view.id,
Selection::single(new_range.head, new_range.anchor),
);
if action.align_view(view, doc.id()) {
align_view(doc, view, Align::Center);
}
}

Ok(serde_json::Value::Null)
}
};

tokio::spawn(language_server!().reply(id, reply));
Expand Down
23 changes: 4 additions & 19 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1227,7 +1227,7 @@ fn open_url(cx: &mut Context, url: Url, action: Action) {
.unwrap_or_default();

if url.scheme() != "file" {
return open_external_url(cx, url);
return cx.jobs.callback(crate::open_external_url_callback(url));
}

let content_type = std::fs::File::open(url.path()).and_then(|file| {
Expand All @@ -1240,7 +1240,9 @@ fn open_url(cx: &mut Context, url: Url, action: Action) {
// we attempt to open binary files - files that can't be open in helix - using external
// program as well, e.g. pdf files or images
match content_type {
Ok(content_inspector::ContentType::BINARY) => open_external_url(cx, url),
Ok(content_inspector::ContentType::BINARY) => {
cx.jobs.callback(crate::open_external_url_callback(url))
}
Ok(_) | Err(_) => {
let path = &rel_path.join(url.path());
if path.is_dir() {
Expand All @@ -1253,23 +1255,6 @@ fn open_url(cx: &mut Context, url: Url, action: Action) {
}
}

/// Opens URL in external program.
fn open_external_url(cx: &mut Context, url: Url) {
let commands = open::commands(url.as_str());
cx.jobs.callback(async {
for cmd in commands {
let mut command = tokio::process::Command::new(cmd.get_program());
command.args(cmd.get_args());
if command.output().await.is_ok() {
return Ok(job::Callback::Editor(Box::new(|_| {})));
}
}
Ok(job::Callback::Editor(Box::new(move |editor| {
editor.set_error("Opening URL in external program failed")
})))
});
}

fn extend_word_impl<F>(cx: &mut Context, extend_fn: F)
where
F: Fn(RopeSlice, Range, usize) -> Range,
Expand Down
23 changes: 23 additions & 0 deletions helix-term/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ pub mod keymap;
pub mod ui;
use std::path::Path;

use futures_util::Future;
use ignore::DirEntry;

pub use keymap::macros::*;

use url::Url;

#[cfg(not(windows))]
fn true_color() -> bool {
std::env::var("COLORTERM")
Expand Down Expand Up @@ -47,3 +51,22 @@ fn filter_picker_entry(entry: &DirEntry, root: &Path, dedup_symlinks: bool) -> b

true
}

/// Opens URL in external program.
fn open_external_url_callback(
url: Url,
) -> impl Future<Output = Result<job::Callback, anyhow::Error>> + Send + 'static {
let commands = open::commands(url.as_str());
async {
for cmd in commands {
let mut command = tokio::process::Command::new(cmd.get_program());
command.args(cmd.get_args());
if command.output().await.is_ok() {
return Ok(job::Callback::Editor(Box::new(|_| {})));
}
}
Ok(job::Callback::Editor(Box::new(move |editor| {
editor.set_error("Opening URL in external program failed")
})))
}
}

0 comments on commit c85e95c

Please sign in to comment.