Skip to content

Commit

Permalink
apply helix-editor#5492 to latest
Browse files Browse the repository at this point in the history
  • Loading branch information
Schuyler Mortimer committed Jul 2, 2024
1 parent fc97ecc commit 34837a4
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 64 deletions.
5 changes: 5 additions & 0 deletions helix-lsp/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,11 @@ impl Client {
..Default::default()
}),
window: Some(lsp::WindowClientCapabilities {
show_message: Some(lsp::ShowMessageRequestClientCapabilities {
message_action_item: Some(lsp::MessageActionItemCapabilities {
additional_properties_support: Some(true),
}),
}),
work_done_progress: Some(true),
..Default::default()
}),
Expand Down
4 changes: 4 additions & 0 deletions helix-lsp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ pub enum MethodCall {
RegisterCapability(lsp::RegistrationParams),
UnregisterCapability(lsp::UnregistrationParams),
ShowDocument(lsp::ShowDocumentParams),
ShowMessageRequest(lsp::ShowMessageRequestParams),
}

impl MethodCall {
Expand Down Expand Up @@ -598,6 +599,9 @@ impl MethodCall {
let params: lsp::ShowDocumentParams = params.parse()?;
Self::ShowDocument(params)
}
lsp::request::ShowMessageRequest::METHOD => {
Self::ShowMessageRequest(params.parse::<lsp::ShowMessageRequestParams>()?)
}
_ => {
return Err(Error::Unhandled);
}
Expand Down
94 changes: 75 additions & 19 deletions helix-term/src/application.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use arc_swap::{access::Map, ArcSwap};
use futures_util::Stream;
use helix_core::{diagnostic::Severity, pos_at_coords, syntax, Selection};
use helix_core::{diagnostic::Severity, pos_at_coords, syntax, Rope, Selection};
use helix_lsp::{
lsp::{self, notification::Notification},
lsp::{self, notification::Notification, MessageType},
util::lsp_range_to_range,
LanguageServerId, LspProgressMap,
};
Expand All @@ -26,7 +26,7 @@ use crate::{
handlers,
job::Jobs,
keymap::Keymaps,
ui::{self, overlay::overlaid},
ui::{self, overlay::overlaid, FileLocation, Picker, Popup},
};

use log::{debug, error, info, warn};
Expand Down Expand Up @@ -960,11 +960,11 @@ impl Application {
"Language Server: Method {} not found in request {}",
method, id
);
Err(helix_lsp::jsonrpc::Error {
Some(Err(helix_lsp::jsonrpc::Error {
code: helix_lsp::jsonrpc::ErrorCode::MethodNotFound,
message: format!("Method not found: {}", method),
data: None,
})
}))
}
Err(err) => {
log::error!(
Expand All @@ -973,11 +973,11 @@ impl Application {
id,
err
);
Err(helix_lsp::jsonrpc::Error {
Some(Err(helix_lsp::jsonrpc::Error {
code: helix_lsp::jsonrpc::ErrorCode::ParseError,
message: format!("Malformed method call: {}", method),
data: None,
})
}))
}
Ok(MethodCall::WorkDoneProgressCreate(params)) => {
self.lsp_progress.create(server_id, params.token);
Expand All @@ -991,7 +991,7 @@ impl Application {
spinner.start();
}

Ok(serde_json::Value::Null)
Some(Ok(serde_json::Value::Null))
}
Ok(MethodCall::ApplyWorkspaceEdit(params)) => {
let language_server = language_server!();
Expand All @@ -1001,25 +1001,73 @@ impl Application {
.editor
.apply_workspace_edit(offset_encoding, &params.edit);

Ok(json!(lsp::ApplyWorkspaceEditResponse {
Some(Ok(json!(lsp::ApplyWorkspaceEditResponse {
applied: res.is_ok(),
failure_reason: res.as_ref().err().map(|err| err.kind.to_string()),
failed_change: res
.as_ref()
.err()
.map(|err| err.failed_change_idx as u32),
}))
})))
} else {
Err(helix_lsp::jsonrpc::Error {
Some(Err(helix_lsp::jsonrpc::Error {
code: helix_lsp::jsonrpc::ErrorCode::InvalidRequest,
message: "Server must be initialized to request workspace edits"
.to_string(),
data: None,
})
}))
}
}
Ok(MethodCall::WorkspaceFolders) => {
Ok(json!(&*language_server!().workspace_folders().await))
Some(Ok(json!(&*language_server!().workspace_folders().await)))
}
Ok(MethodCall::ShowMessageRequest(params)) => {
if let Some(actions) = params.actions {
let call_id = id.clone();
let message_type = match params.typ {
MessageType::ERROR => "ERROR",
MessageType::WARNING => "WARNING",
MessageType::INFO => "INFO",
_ => "LOG",
};
let message = format!("{}: {}", message_type, &params.message);
let rope = Rope::from(message);
let picker =
Picker::new(actions, (), move |ctx, message_action, _event| {
let server_from_id =
ctx.editor.language_servers.get_by_id(server_id);
let language_server = match server_from_id {
Some(language_server) => language_server,
None => {
warn!(
"can't find language server with id `{server_id}`"
);
return;
}
};
let response = match message_action {
Some(item) => json!(item),
None => serde_json::Value::Null,
};
tokio::spawn(
language_server.reply(call_id.clone(), Ok(response)),
);
})
.with_preview(
move |_editor, _value| {
let file_location: FileLocation =
(rope.clone().into(), None);
Some(file_location)
},
);
let popup_id = "show-message-request";
let popup = Popup::new(popup_id, picker);
self.compositor.replace_or_push(popup_id, popup);
// do not send a reply just yet
None
} else {
Some(Ok(serde_json::Value::Null))
}
}
Ok(MethodCall::WorkspaceConfiguration(params)) => {
let language_server = language_server!();
Expand All @@ -1039,7 +1087,7 @@ impl Application {
Some(config)
})
.collect();
Ok(json!(result))
Some(Ok(json!(result)))
}
Ok(MethodCall::RegisterCapability(params)) => {
if let Some(client) = self.editor.language_servers.get_by_id(server_id) {
Expand Down Expand Up @@ -1077,7 +1125,7 @@ impl Application {
}
}

Ok(serde_json::Value::Null)
Some(Ok(serde_json::Value::Null))
}
Ok(MethodCall::UnregisterCapability(params)) => {
for unreg in params.unregisterations {
Expand All @@ -1093,18 +1141,26 @@ impl Application {
}
}
}
Ok(serde_json::Value::Null)
Some(Ok(serde_json::Value::Null))
}
Ok(MethodCall::ShowDocument(params)) => {
let language_server = language_server!();
let offset_encoding = language_server.offset_encoding();

let result = self.handle_show_document(params, offset_encoding);
Ok(json!(result))
Some(Ok(json!(result)))
}
};

tokio::spawn(language_server!().reply(id, reply));
if let Some(reply) = reply {
let lanaguage_server = match self.editor.language_servers.get_by_id(server_id) {
Some(language_server) => language_server,
None => {
warn!("can't find language server with id `{}`", server_id);
return;
}
};
tokio::spawn(lanaguage_server.reply(id, reply));
}
}
Call::Invalid { id } => log::error!("LSP invalid method call id={:?}", id),
}
Expand Down
19 changes: 14 additions & 5 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2425,7 +2425,10 @@ fn global_search(cx: &mut Context) {
let picker = Picker::with_stream(
picker,
injector,
move |cx, FileResult { path, line_num }, action| {
move |cx, file_result, action| {
let Some(FileResult { path, line_num }) = file_result else {
return;
};
let doc = match cx.editor.open(path, action) {
Ok(id) => doc_mut!(cx.editor, &id),
Err(e) => {
Expand Down Expand Up @@ -2941,7 +2944,8 @@ fn buffer_picker(cx: &mut Context) {
// mru
items.sort_unstable_by_key(|item| std::cmp::Reverse(item.focused_at));

let picker = Picker::new(items, (), |cx, meta, action| {
let picker = Picker::new(items, (), |cx, buffer_meta, action| {
let Some(meta) = buffer_meta else { return };
cx.editor.switch(meta.id, action);
})
.with_preview(|editor, meta| {
Expand Down Expand Up @@ -3030,7 +3034,8 @@ fn jumplist_picker(cx: &mut Context) {
})
.collect(),
(),
|cx, meta, action| {
|cx, jump_meta, action| {
let Some(meta) = jump_meta else { return };
cx.editor.switch(meta.id, action);
let config = cx.editor.config();
let (view, doc) = (view_mut!(cx.editor), doc_mut!(cx.editor, &meta.id));
Expand Down Expand Up @@ -3108,7 +3113,8 @@ fn changed_file_picker(cx: &mut Context) {
style_deleted: deleted,
style_renamed: renamed,
},
|cx, meta: &FileChange, action| {
|cx, file_meta: Option<&FileChange>, action| {
let Some(meta) = file_meta else { return };
let path_to_open = meta.path();
if let Err(e) = cx.editor.open(path_to_open, action) {
let err = if let Some(err) = e.source() {
Expand Down Expand Up @@ -3184,7 +3190,10 @@ pub fn command_palette(cx: &mut Context) {
}
}));

let picker = Picker::new(commands, keymap, move |cx, command, _action| {
let picker = Picker::new(commands, keymap, move |cx, mappable_command, _action| {
let Some(command) = mappable_command else {
return;
};
let mut ctx = Context {
register,
count,
Expand Down
11 changes: 8 additions & 3 deletions helix-term/src/commands/dap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ fn thread_picker(

let thread_states = debugger.thread_states.clone();
let picker = Picker::new(threads, thread_states, move |cx, thread, _action| {
callback_fn(cx.editor, thread)
let Some(t) = thread else { return };
callback_fn(cx.editor, t)
})
.with_preview(move |editor, thread| {
let frames = editor.debugger.as_ref()?.stack_frames.get(&thread.id)?;
Expand Down Expand Up @@ -271,7 +272,10 @@ pub fn dap_launch(cx: &mut Context) {
cx.push_layer(Box::new(overlaid(Picker::new(
templates,
(),
|cx, template, _action| {
|cx, debug_template, _action| {
let Some(template) = debug_template else {
return;
};
if template.completion.is_empty() {
if let Err(err) = dap_start_impl(cx, Some(&template.name), None, None) {
cx.editor.set_error(err.to_string());
Expand Down Expand Up @@ -736,7 +740,8 @@ pub fn dap_switch_stack_frame(cx: &mut Context) {

let frames = debugger.stack_frames[&thread_id].clone();

let picker = Picker::new(frames, (), move |cx, frame, _action| {
let picker = Picker::new(frames, (), move |cx, stack_frame, _action| {
let Some(frame) = stack_frame else { return };
let debugger = debugger!(cx.editor);
// TODO: this should be simpler to find
let pos = debugger.stack_frames[&thread_id]
Expand Down
29 changes: 20 additions & 9 deletions helix-term/src/commands/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ type SymbolPicker = Picker<SymbolInformationItem>;

fn sym_picker(symbols: Vec<SymbolInformationItem>, current_path: Option<lsp::Url>) -> SymbolPicker {
// TODO: drop current_path comparison and instead use workspace: bool flag?
Picker::new(symbols, current_path, move |cx, item, action| {
Picker::new(symbols, current_path, move |cx, symbol_item, action| {
let Some(item) = symbol_item else { return };
jump_to_location(
cx.editor,
&item.symbol.location,
Expand Down Expand Up @@ -296,13 +297,15 @@ fn diag_picker(
Picker::new(
flat_diag,
(styles, format),
move |cx,
PickerDiagnostic {
path,
diag,
offset_encoding,
},
action| {
move |cx, picker_diagnostic, action| {
let Some(PickerDiagnostic {
path,
diag,
offset_encoding,
}) = picker_diagnostic
else {
return;
};
jump_to_position(cx.editor, path, diag.range, *offset_encoding, action)
},
)
Expand Down Expand Up @@ -509,6 +512,13 @@ impl ui::menu::Item for CodeActionOrCommandItem {
}
}

impl ui::menu::Item for lsp::MessageActionItem {
type Data = ();
fn format(&self, _data: &Self::Data) -> Row {
self.title.as_str().into()
}
}

/// Determines the category of the `CodeAction` using the `CodeAction::kind` field.
/// Returns a number that represent these categories.
/// Categories with a lower number should be displayed first.
Expand Down Expand Up @@ -818,7 +828,8 @@ fn goto_impl(
[] => unreachable!("`locations` should be non-empty for `goto_impl`"),
_locations => {
let picker = Picker::new(locations, cwdir, move |cx, location, action| {
jump_to_location(cx.editor, location, offset_encoding, action)
let Some(l) = location else { return };
jump_to_location(cx.editor, l, offset_encoding, action)
})
.with_preview(move |_editor, location| Some(location_to_file_location(location)));
compositor.push(Box::new(overlaid(picker)));
Expand Down
3 changes: 2 additions & 1 deletion helix-term/src/commands/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1399,7 +1399,8 @@ fn lsp_workspace_command(
let call: job::Callback = Callback::EditorCompositor(Box::new(
move |_editor: &mut Editor, compositor: &mut Compositor| {
let picker = ui::Picker::new(commands, (), move |cx, command, _action| {
execute_lsp_command(cx.editor, language_server_id, command.clone());
let Some(c) = command else { return };
execute_lsp_command(cx.editor, language_server_id, c.clone());
});
compositor.push(Box::new(overlaid(picker)))
},
Expand Down
25 changes: 15 additions & 10 deletions helix-term/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,16 +217,21 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> Picker
});
log::debug!("file_picker init {:?}", Instant::now().duration_since(now));

let picker = Picker::new(Vec::new(), root, move |cx, path: &PathBuf, action| {
if let Err(e) = cx.editor.open(path, action) {
let err = if let Some(err) = e.source() {
format!("{}", err)
} else {
format!("unable to open \"{}\"", path.display())
};
cx.editor.set_error(err);
}
})
let picker = Picker::new(
Vec::new(),
root,
move |cx, path_buff: Option<&PathBuf>, action| {
let Some(path) = path_buff else { return };
if let Err(e) = cx.editor.open(path, action) {
let err = if let Some(err) = e.source() {
format!("{}", err)
} else {
format!("unable to open \"{}\"", path.display())
};
cx.editor.set_error(err);
}
},
)
.with_preview(|_editor, path| Some((path.clone().into(), None)));
let injector = picker.injector();
let timeout = std::time::Instant::now() + std::time::Duration::from_millis(30);
Expand Down
Loading

0 comments on commit 34837a4

Please sign in to comment.