From 3e5f24a9d5cec26697a75e515bff46de418b32da Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Wed, 14 Apr 2021 15:30:15 +0900 Subject: lsp: support both utf-8 and utf-16 offsets. Still need to implement the clangd encoding negotiation, but it's a start. Should also manually override to utf8 for pyls. --- helix-term/src/application.rs | 16 +++++++-- helix-term/src/commands.rs | 79 ++++++++++++++++++++++++++++++----------- helix-term/src/ui/completion.rs | 14 ++++++-- helix-term/src/ui/editor.rs | 3 +- helix-term/src/ui/mod.rs | 2 +- 5 files changed, 87 insertions(+), 27 deletions(-) (limited to 'helix-term') diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 71c6fba1..b3ddbe15 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -175,8 +175,20 @@ impl Application { }; use helix_lsp::{lsp, util::lsp_pos_to_pos}; use lsp::DiagnosticSeverity; - let start = lsp_pos_to_pos(text, diagnostic.range.start); - let end = lsp_pos_to_pos(text, diagnostic.range.end); + + let language_server = doc.language_server().unwrap(); + + // TODO: convert inside server + let start = lsp_pos_to_pos( + text, + diagnostic.range.start, + language_server.offset_encoding(), + ); + let end = lsp_pos_to_pos( + text, + diagnostic.range.end, + language_server.offset_encoding(), + ); Diagnostic { range: Range { start, end }, diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 3854f416..4c04b0a2 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -16,6 +16,7 @@ use helix_view::{ use helix_lsp::{ lsp, util::{lsp_pos_to_pos, pos_to_lsp_pos, range_to_lsp_range}, + OffsetEncoding, }; use crate::{ @@ -1117,18 +1118,24 @@ pub fn exit_select_mode(cx: &mut Context) { cx.doc().mode = Mode::Normal; } -fn _goto(cx: &mut Context, locations: Vec) { +fn _goto(cx: &mut Context, locations: Vec, offset_encoding: OffsetEncoding) { use helix_view::editor::Action; push_jump(cx); - fn jump_to(editor: &mut Editor, location: &lsp::Location, action: Action) { + fn jump_to( + editor: &mut Editor, + location: &lsp::Location, + offset_encoding: OffsetEncoding, + action: Action, + ) { let id = editor .open(PathBuf::from(location.uri.path()), action) .expect("editor.open failed"); let (view, doc) = editor.current(); let definition_pos = location.range.start; - let new_pos = lsp_pos_to_pos(doc.text(), definition_pos); + // TODO: convert inside server + let new_pos = lsp_pos_to_pos(doc.text(), definition_pos, offset_encoding); doc.set_selection(view.id, Selection::point(new_pos)); let line = doc.text().char_to_line(new_pos); view.first_line = line.saturating_sub(view.area.height as usize / 2); @@ -1136,7 +1143,7 @@ fn _goto(cx: &mut Context, locations: Vec) { match locations.as_slice() { [location] => { - jump_to(cx.editor, location, Action::Replace); + jump_to(cx.editor, location, offset_encoding, Action::Replace); } [] => (), // maybe show user message that no definition was found? _locations => { @@ -1147,7 +1154,9 @@ fn _goto(cx: &mut Context, locations: Vec) { let line = location.range.start.line; format!("{}:{}", file, line).into() }, - move |editor: &mut Editor, location, action| jump_to(editor, location, action), + move |editor: &mut Editor, location, action| { + jump_to(editor, location, offset_encoding, action) + }, ); cx.push_layer(Box::new(picker)); } @@ -1161,12 +1170,14 @@ pub fn goto_definition(cx: &mut Context) { None => return, }; - let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor()); + let offset_encoding = language_server.offset_encoding(); + + let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding); // TODO: handle fails let res = smol::block_on(language_server.goto_definition(doc.identifier(), pos)).unwrap_or_default(); - _goto(cx, res); + _goto(cx, res, offset_encoding); } pub fn goto_type_definition(cx: &mut Context) { @@ -1176,12 +1187,14 @@ pub fn goto_type_definition(cx: &mut Context) { None => return, }; - let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor()); + let offset_encoding = language_server.offset_encoding(); + + let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding); // TODO: handle fails let res = smol::block_on(language_server.goto_type_definition(doc.identifier(), pos)) .unwrap_or_default(); - _goto(cx, res); + _goto(cx, res, offset_encoding); } pub fn goto_implementation(cx: &mut Context) { @@ -1191,12 +1204,14 @@ pub fn goto_implementation(cx: &mut Context) { None => return, }; - let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor()); + let offset_encoding = language_server.offset_encoding(); + + let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding); // TODO: handle fails let res = smol::block_on(language_server.goto_implementation(doc.identifier(), pos)) .unwrap_or_default(); - _goto(cx, res); + _goto(cx, res, offset_encoding); } pub fn goto_reference(cx: &mut Context) { @@ -1206,12 +1221,14 @@ pub fn goto_reference(cx: &mut Context) { None => return, }; - let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor()); + let offset_encoding = language_server.offset_encoding(); + + let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding); // TODO: handle fails let res = smol::block_on(language_server.goto_reference(doc.identifier(), pos)).unwrap_or_default(); - _goto(cx, res); + _goto(cx, res, offset_encoding); } pub fn signature_help(cx: &mut Context) { @@ -1222,7 +1239,11 @@ pub fn signature_help(cx: &mut Context) { None => return, }; - let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor()); + let pos = pos_to_lsp_pos( + doc.text(), + doc.selection(view.id).cursor(), + language_server.offset_encoding(), + ); // TODO: handle fails @@ -1579,10 +1600,15 @@ pub fn format_selections(cx: &mut Context) { // via lsp if available // else via tree-sitter indentation calculations + let language_server = match doc.language_server() { + Some(language_server) => language_server, + None => return, + }; + let ranges: Vec = doc .selection(view.id) .iter() - .map(|range| range_to_lsp_range(doc.text(), *range)) + .map(|range| range_to_lsp_range(doc.text(), *range, language_server.offset_encoding())) .collect(); for range in ranges { @@ -1590,7 +1616,6 @@ pub fn format_selections(cx: &mut Context) { Some(language_server) => language_server, None => return, }; - // TODO: handle fails // TODO: concurrent map let edits = smol::block_on(language_server.text_document_range_formatting( @@ -1600,7 +1625,11 @@ pub fn format_selections(cx: &mut Context) { )) .unwrap_or_default(); - let transaction = helix_lsp::util::generate_transaction_from_edits(doc.text(), edits); + let transaction = helix_lsp::util::generate_transaction_from_edits( + doc.text(), + edits, + language_server.offset_encoding(), + ); doc.apply(&transaction, view.id); } @@ -1726,7 +1755,13 @@ pub fn completion(cx: &mut Context) { None => return, }; - let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor()); + let offset_encoding = language_server.offset_encoding(); + + let pos = pos_to_lsp_pos( + doc.text(), + doc.selection(view.id).cursor(), + language_server.offset_encoding(), + ); // TODO: handle fails let res = smol::block_on(language_server.completion(doc.identifier(), pos)).unwrap(); @@ -1754,7 +1789,7 @@ pub fn completion(cx: &mut Context) { let size = compositor.size(); let ui = compositor.find("hx::ui::editor::EditorView").unwrap(); if let Some(ui) = ui.as_any_mut().downcast_mut::() { - ui.set_completion(items, trigger_offset, size); + ui.set_completion(items, offset_encoding, trigger_offset, size); }; } }, @@ -1779,7 +1814,11 @@ pub fn hover(cx: &mut Context) { // TODO: blocking here is not ideal, make commands async fn? // not like we can process additional input meanwhile though - let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor()); + let pos = pos_to_lsp_pos( + doc.text(), + doc.selection(view.id).cursor(), + language_server.offset_encoding(), + ); // TODO: handle fails let res = smol::block_on(language_server.text_document_hover(doc.identifier(), pos)) diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index a804b5f2..7a8413f8 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -26,7 +26,11 @@ pub struct Completion { } impl Completion { - pub fn new(items: Vec, trigger_offset: usize) -> Self { + pub fn new( + items: Vec, + offset_encoding: helix_lsp::OffsetEncoding, + trigger_offset: usize, + ) -> Self { // let items: Vec = Vec::new(); let mut menu = Menu::new( items, @@ -99,8 +103,12 @@ impl Completion { doc.apply(&remove, view.id); } - let transaction = - util::generate_transaction_from_edits(doc.text(), vec![edit]); + use helix_lsp::OffsetEncoding; + let transaction = util::generate_transaction_from_edits( + doc.text(), + vec![edit], + offset_encoding, // TODO: should probably transcode in Client + ); doc.apply(&transaction, view.id); } _ => (), diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 8879612c..227ccdaa 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -517,10 +517,11 @@ impl EditorView { pub fn set_completion( &mut self, items: Vec, + offset_encoding: helix_lsp::OffsetEncoding, trigger_offset: usize, size: Rect, ) { - let mut completion = Completion::new(items, trigger_offset); + let mut completion = Completion::new(items, offset_encoding, trigger_offset); // TODO : propagate required size on resize to completion too completion.required_size((size.width, size.height)); self.completion = Some(completion); diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index d9a05a9c..105ba7ad 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -20,7 +20,7 @@ pub use tui::layout::Rect; pub use tui::style::{Color, Modifier, Style}; use helix_core::regex::Regex; -use helix_view::{View, Document, Editor}; +use helix_view::{Document, Editor, View}; use std::path::{Path, PathBuf}; -- cgit v1.2.3-70-g09d2