Skip to content

Add Hover + Go-to Definition Request Support #717

Closed
betterclever wants to merge 17 commits intoxi-editor:masterfrom
betterclever:hover-support
Closed

Add Hover + Go-to Definition Request Support #717
betterclever wants to merge 17 commits intoxi-editor:masterfrom
betterclever:hover-support

Conversation

@betterclever
Copy link
Copy Markdown
Member

@betterclever betterclever commented Jun 19, 2018

Tracking Issues: #659 #693

Current Stage:
Hover: Working. On Option+Click in the Client. Markdown is not being parsed in Client yet.
Go-to definition: Work completed from Plugin Side. Needs attention from Client.

@betterclever betterclever force-pushed the hover-support branch 3 times, most recently from b407b8b to 96f95de Compare June 21, 2018 17:54
@betterclever
Copy link
Copy Markdown
Member Author

@cmyr @nangtrongvuon You may have a look at this stage. I added an RPC for making Hover request on the client side. Currently, it may be mapped to a key-binding to trigger request at the current cursor location i.e. skipping position argument in RPC.

I would like if a separate branch in xi-mac with preliminary support for that can be made to facilitate further testing 😃

@nangtrongvuon
Copy link
Copy Markdown
Member

nangtrongvuon commented Jun 24, 2018

You can test this on my branch hover-definition. I put in a request to call for a hover when you move the mouse.

@betterclever
Copy link
Copy Markdown
Member Author

@nangtrongvuon I updated https://github.com/nangtrongvuon/xi-mac/blob/hover-definition/XiEditor/EditViewController.swift#L540 to match the RPC.

document.sendRpcAsync("request_hover_definition", params: ["request_id": 1, "position": ["type": "utf8_line_char", "line": hoverPosition.line, "character": hoverPosition.column]])

Now, I am also forwarding the hover result to client, see this diff

@nangtrongvuon
Copy link
Copy Markdown
Member

Looks good, I'll work on that further!

@betterclever betterclever changed the title WIP: Add Hover Definition Request Support WIP: Add Hover + Go-to Definition Request Support Jun 28, 2018
Copy link
Copy Markdown
Member

@cmyr cmyr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only got about halfway through review and I'm running out of gas, will pick this back up tomorrow. Here's the first half, though, in case it's useful. :)

Comment thread rust/core-lib/src/client.rs Outdated
use config::Table;
use styles::ThemeSettings;
use plugins::rpc::ClientPluginInfo;
use plugins::rpc::{ClientPluginInfo};
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: we don't include the {braces} on single-item imports.

Comment thread rust/core-lib/src/client.rs Outdated
pub strings: Vec<String>,
}

#[derive(Serialize, Deserialize)]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: public types should include at least some documentation.

Comment thread rust/core-lib/src/client.rs Outdated
pub range: Option<Range>
}

/* impl From<PluginHoverResult> for HoverResult {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleanup?

Resize(Size),
RequestLines(LineRange),
RequestHover { request_id: usize, position: Option<Position> },
RequestDefinition { request_id: usize, position: Option<Position> }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add these to the frontend docs?

Comment thread rust/core-lib/src/editor.rs Outdated
view.invalidate_styles(&self.text, start, end_offset);
}

pub fn get_text_rope(&self, rev: RevToken) -> Option<Cow<Rope>> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be public? In general I now prefer pub(crate) where possible, because it helps the compiler warn us when code becomes unused.

Also, maybe we could call this get_rev? We already have get_buffer, which returns the current head.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if we're adding this method (which seems good) we should also use it in plugin_get_data, below.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. It needs to be public. It is being used in editor.rs . Applied other suggestions.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pub(crate) fn foo(..) is still useable from other files in the same crate.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I made this a pub (crate) function already.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yea okay github isn't great at showing changes after review.

Comment thread rust/core-lib/src/event_context.rs Outdated
self.render_if_needed();
}

pub fn get_client_hover_result(&mut self, rev: u64, result: HoverResult) -> ClientHoverResult {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this needs to be pub.

Comment thread rust/core-lib/src/event_context.rs Outdated
}

fn request_hover(&mut self, request_id: usize, position: Option<Position>) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this line contains whitespace

Comment thread rust/core-lib/src/event_context.rs Outdated

fn request_hover(&mut self, request_id: usize, position: Option<Position>) {

let position = position.or_else(|| self.view.borrow().get_caret_offset()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unclear to me that we need to send Position structs to the plugins; we currently expect all plugins to be handling utf-8 offsets, so we could just use that.

I could imagine at some point allowing plugins to specify the format that they receive positions in, but even in that case we wouldn't need to send the enum, we would only ever send one type to each plugin.

If you do want to keep it this way, these two functions can share a lot of code; maybe add a fn resolve_position(&self, position: Option<Position>) helper?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am confused. If Plugins specify their preference i.e Utf16 Line/Char or Utf8 or anything else, how will that be handled without enum?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, plugins only get sent utf8 offsets, and that isn't going to change soon.

If at some point in the future, we allow a plugin to specify it's preferred unit, the RPC it receives will still just be (probably) hover { position: { line: 0, col: 3 }, it will just know that col is in utf16 code units. We could represent this internally as an enum, (and that might be best) but we might not send it as an enum to the plugin; we could switch internally and modify the json as needed. (I'm not sure this is a good idea, just a thought).

Comment thread rust/core-lib/src/event_context.rs Outdated
}

fn request_defintion(&mut self, request_id: usize, position: Option<Position>) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more whitespace

Comment thread rust/core-lib/src/event_context.rs Outdated
ed.is_pristine())
}

fn request_hover(&mut self, request_id: usize, position: Option<Position>) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mentioned above, we would call this do_request_hover.

@betterclever betterclever force-pushed the hover-support branch 3 times, most recently from b51983c to 41055f2 Compare July 10, 2018 15:11
Comment thread rust/core-lib/src/editor.rs Outdated
max_size: usize,
rev: RevToken) -> Option<GetDataResponse> {
let _t = trace_block("Editor::plugin_get_data", &["core"]);
pub (crate) fn get_rev(&self, rev: RevToken) -> Option<Cow<Rope>> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rust style has solidified on having no space between pub and (crate). I was also writing this like you are, but I'm changing to pub(crate) now.

Comment thread rust/core-lib/src/editor.rs Outdated
max_size: usize,
rev: RevToken) -> Option<GetDataResponse> {
let _t = trace_block("Editor::plugin_get_data", &["core"]);
let text_cow = match self.get_rev(rev) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can get fancy now and just do let text_cow = self.get_rev(rev)?;.

Copy link
Copy Markdown
Member

@cmyr cmyr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I've gone through the rest of the core-lib changes. Still have to look at the lsp-lib stuff, hopefully later today.

I have some general concerns about the utf16 stuff. Specifically, I think that the best way of handling the utf8-utf16 conversions would be to add a new Metric to the Rope crate. I'd also like conversion routines to have unit tests, since it's an easy way to introduce hard-to-catch bugs.

I think this is probably worth doing right. I would suggest doing this in two parts, adding the Metric stuff and then fixing this up to use it. If we want to merge something temporary that would be possible, but I would add a FIXME for all the code we would be removing.

Comment thread rust/core-lib/src/event_context.rs Outdated
}

fn do_request_hover(&mut self, request_id: usize, position: Option<Position>) {
let position = position.or_else(|| self.view.borrow().get_caret_offset()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we share more code between these two functions?

One thing that we might want to consider is having a helper on EventContext, with a signature like:

fn with_each_plugin<F: FnMut(&Plugin)>(&self, f: F) { .. }

"changes": changes}))
}

pub fn get_hover(&self, view_id: ViewId, request_id: usize, position: &Position) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mentioned earlier, and just an observation: we may at some point want to have these two methods be RPC requests, that return results; that would let us more easily keep track of when all responses to a message had been received, in case we want to show that no hover or no definition is available.

(This is future work, no change needed now, but just something to think about).

Comment thread rust/core-lib/src/plugins/rpc.rs Outdated
RemoveStatusItem { key: String }
RemoveStatusItem { key: String },
ShowHover { request_id: usize, result: Result<Hover, LanguageResponseError>, rev: u64 },
ShowDefinition { request_id: usize, result: Result<Definition, LanguageResponseError>, rev: u64}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I would add a trailing ,, so that the next time an item is added to this enum this item doesn't show up in the diff (like how RemoveStatusItem shows up in this diff, because we had to add the trailing ,).

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "type")]
pub enum Position {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like some documentation for any public item in this file, because this file is currently the only real documentation available of the plugin protocol.

Comment thread rust/core-lib/src/plugins/rpc.rs Outdated
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
pub struct CompletionItem {
pub label: String,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to be part of this PR? It looks like it's part of the completions work.

In any case, I would also document what these various fields mean, and how they should be used.

Comment thread rust/core-lib/src/plugins/rpc.rs Outdated

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
pub struct TextEdit {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is interesting. We of course have our own edit facilities, based on deltas and document revisions, so it's hard to know how meaningful this type is. We should at least be associating completion items with a rev. This also introduces a subtle problem with garbage collection of old revisions; I believe it would be possible for us to end up with completion items that are associated with a revision that no longer exists.

What we might want to do is convert this to a delta internally, and then transform that delta over its lifespan to keep it up to date with any new edits.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea was to receive such a TextEdit from Plugin and convert it to Delta in the Core, since it involves the same problem like converting Utf-16 Line/Char Range to Utf8 offsets in the Plugin, so I resorted to forwarding it to core.

Comment thread rust/core-lib/src/rpc.rs Outdated
//!
//! [Serde]: https://serde.rs

use internal::plugins::rpc::Position;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary internal

Comment thread rust/core-lib/src/view.rs Outdated
}


pub fn offset_to_line_col_utf16(&self, text: &Rope, offset: usize) -> (usize, usize) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this ever used?

Copy link
Copy Markdown
Member Author

@betterclever betterclever Jul 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. One thing we might do is to send Utf16 L/C to Plugin directly after doing conversion from here though. But at this point it is not being used anywhere.

@@ -0,0 +1,130 @@
use lsp_types::*;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a header / copyright notice

use types::DefinitionResult;
use xi_plugin_lib::{Hover as CoreHover};
use xi_plugin_lib::LanguageResponseError;
use xi_plugin_lib::{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can combine all of these imports I think?

@betterclever betterclever force-pushed the hover-support branch 2 times, most recently from 3ce7482 to 626bad2 Compare July 11, 2018 01:54
@betterclever betterclever changed the title WIP: Add Hover + Go-to Definition Request Support Add Hover + Go-to Definition Request Support Jul 11, 2018
Copy link
Copy Markdown
Member

@cmyr cmyr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, here's the last of my first pass here. As mentioned earlier I think we should do the utf8/utf16 conversion stuff in the rope crate; otherwise this is mainly little stuff.

Comment thread rust/core-lib/src/event_context.rs Outdated
}

fn get_client_hover(&mut self, rev: u64, result: Hover) -> client::Hover {
return client::Hover {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the return is unnecessary here?

Comment thread rust/core-lib/src/event_context.rs Outdated
}

fn with_each_plugin<F: FnMut(&Plugin)>(&self, mut f:F) {
self.plugins.iter().for_each(|p| {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just be self.plugins.iter().for_each(f)

Comment thread rust/core-lib/src/plugins/rpc.rs Outdated
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "type")]
/// Position formats that can be sent/received from to Plugins
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More nit stuff: we put the /// comments above the #[macro]s. Also, in general I would prefer to have a trailing , on the last item of each enum/struct, for the reasons mentioned earlier 😎

Comment thread rust/core-lib/src/view.rs Outdated
offset
}

pub fn line_col_utf16_to_offset(&self, text: &Rope, line: usize, col: usize) -> usize {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a big comment here yesterday, I think, but it maybe got lost?

three things:

  • at an immediate level, this function is duplicating a ton of work that's done elsewhere. I think this could be made a lot simpler by just converting the utf16 col to a utf8, and then forwarding that to our line_col_to_offset fn.

  • at a higher level, these conversion utilities should be implemented in the rope crate. Specifically, converting between utf8 and utf16 should be done by a new Metric type.

  • In any case, these functions deserve unit tests. It's easy to have bugs here, and they're going to be annoying bugs to find later.

Comment thread rust/lsp-lib/src/conversion_utils.rs Outdated
let line_num = view.line_of_offset(offset)?;
let line_offset = view.offset_of_line(line_num)?;

let char_offset: usize = count_utf16(&(view.get_line(line_num)?[0..(offset - line_offset)]));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we shouldn't need this type annotation

Comment thread rust/lsp-lib/src/conversion_utils.rs Outdated
View,
};

pub fn marked_string_to_string(marked_string: &MarkedString) -> String {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these can probably be pub(crate).


}

fn remove_status_item(&mut self, id: &String) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, prefer &str to &String.

"telemetry/event" => {

},
misc @ _ => match self.language_id.to_lowercase().as_ref() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general when working with these big match statements for RPCs, I find it's cleanest to just use the match arms to call some function that can perform the logic; otherwise you end up with 200+ line functions. 😎


fn config_changed(&mut self, _view: &mut View<Self::Cache>, _changes: &ConfigTable) {}

fn get_hover(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three functions duplicate a lot of code, which makes me uneasy. I think we could probably refactor this more to reuse more code?

Comment thread rust/lsp-lib/src/lsp_plugin.rs Outdated
Err(error) => {
eprintln!("Can't convert location to offset. Error {:?}", error);
let err = LanguageResponseError::PositionConversionError(format!("{:?}",error));
ls_client.core.display_hover_result(view_id, request_id, Err(err), rev);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is display_hover_result the correct fn here?

@betterclever betterclever force-pushed the hover-support branch 2 times, most recently from 5086343 to d186bbb Compare July 11, 2018 16:52
@betterclever betterclever force-pushed the hover-support branch 2 times, most recently from 1bc8f19 to f28410e Compare July 12, 2018 10:45
@betterclever
Copy link
Copy Markdown
Member Author

betterclever commented Jul 12, 2018

I have done most of the changes suggested, however I am not sure about how to reduce duplicity of code in the lsp_plugin.rs

@cmyr
Copy link
Copy Markdown
Member

cmyr commented Jul 12, 2018

@betterclever okay, I'll take a look and see if I can come up with some more concrete suggestions.

Copy link
Copy Markdown
Member

@cmyr cmyr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the documentation, it looks good.

I've added a few more little nits, as usual. 🤓

This is a big patch, and I'm struggling to keep it all in my head at once. At a high level, two things jump out at me as not feeling totally consistent: the position conversions, and the error handling.

Unfortunately, i'm having trouble being much more precise in my criticism than, "I have a funny feeling".

Conversions

to recap: internally, xi generally represents positions as utf8 offsets. In communicating with the frontend, sometimes xi will receive positions as a line/col pair, where col is a utf8 offset; in this case we generally convert to a pure offset as early as possible.

The language server protocol uses utf16 line/col for most things. IIRC, we decided to handle conversion between utf16 and utf8 internally, because core is better suited to handle this logic.

This means that some plugins will, for some RPCs, be sent line/cols in utf16 space.

Q: How do we decide what plugins or what methods are sent utf-16?

receiving line/cols in different formats isn't the end of the world, since we can just pass them through some normalizer. Sending them is trickier, though, since we need to know for each recipient what we should be sending.

In any case, we would like to ensure that this conversion logic happens in one place, one time. If a plugin is going to handle utf-16, it should be converted in core. If a plugin is going to send utf-16, it will be converted in core. We do not want to duplicate this conversion logic between core and the plugin-lib; ideally what we want is some single method that Position and related types get passed to right before and after the RPC boundary, that performs the necessary conversion.

one option for this (at least for core->plugin methods) would be to always send line/col pairs in both utf-8 and utf-16. This would save us from having to do any fancy conversion in core, and would leave the plugin free to pick whichever encoding suited it best.

What about the client?

We added utf16 support for the language server stuff because we don't control all language server implementations, and language servers are using utf16 already.

We do get to dictate things to frontends, though, and to date we have told them to work with utf-8. This is minorly inconvenient, sometimes, because utf-16 is used in lots of gui toolkits, but conversion is relatively easy.

Using utf-16 with plugins shouldn't (directly) imply that we use it with clients as well. It is unclear to me that supporting utf-16 as an equal peer to utf-8 is worth the added complexity. I'm open to having my mind changed, but right now this seems like too much hassle.

Error handling

Something else in this PR that seems slightly inconsistent is the error handling story. I encouraged you to add some error handling in an earlier revision, and I appreciate that you've moved in that direction; however the error handling right now still feels somewhat bolted on.

  • There's a PositionConversionError, but we only seem to use this when the plugin-lib has failed to fetch data from the core, e.g. internal plugin-lib methods like get_line have failed. This isn't really an error with conversions, this represents a fundamental IO error, and is probably not recoverable. As above, it isn't even clear that we should be doing any conversions in the lsp-lib.

  • In core, We send out a get_hover notification, and then we receive a show_hover notification, which contains a Result. If there's an error message, we print it.
    but here is easier?

  • In the lsp-plugin, we get a get_hover notification, and then we send document/hover to the actual language server. If we get an error we print it, and then send it on to core.

At no point do we actually do anything with this error; it doesn't effect any program logic.We would achieve the same result by just printing a log from the LSP client, and then not calling core back at all.

Is this a better approach? That depends on what exactly the error means, and whether or not core can do anything about it.

What might core do with it?

One thing we could imagine is that, when no hover information is available, we might want the client to show an empty hover view with some placeholder text saying "no definition found" or something. We can only know there's no definition after we've heard a response from each plugin; so in this case after sending get_hover (or whatever) to each plugin, we would wait for each plugin to call us back; if all plugins had called us back and we had no definition, we could then call the client and tell it that we had no definition.

The major question is: "what does this error mean, and who is it for?"

I think I'm rambling, but maybe we should have a screenshare and I can try and walk through some of this a bit more?

.spawn()
.expect("Error Occurred");

for var in std::env::vars() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we don't want to commit this?

#[derive(Serialize, Deserialize, Debug)]
/// Range to be sent to client specified in utf-8 offsets
pub struct Range {
// Utf-8 offsets will be sent to clients only
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's confusing that we only send utf-8 offsets, but we accept utf-16?

.language_server_clients
.get(&view_info.ls_identifier)
.unwrap();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the very least all of this boilerplate for getting the ls_client can be moved into a helper function.

let path = view.get_path().clone().unwrap();
get_workspace_root_uri(workspace_identifier, path).ok()
let q = get_workspace_root_uri(workspace_identifier, path);
eprintln!("PATH {:?}", q);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in general there are a lot of print statements in this PR. Some print statements are fine, especially when they are used to report unexpected behaviour, but too much printing in routine situations can end up just cluttering the logs.

pub end: usize
}

#[derive(Serialize, Deserialize, Debug)]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we haven't been super consistent here, but our preference is for /// comments to come before #[annotations].

.get(&view_info.ls_identifier)
.unwrap();

let position_ls = lsp_position_from_core_position(view, position);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't we decide to do this conversion in core? We shouldn't need to have conversion logic in both core and in the plugin lib. (see my top level comment)

}
Err(error) => {
eprintln!("Can't convert location to offset. Error {:?}", error);
let err = LanguageResponseError::PositionConversionError(format!("{:?}",error));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to impl From<_> to do this conversion, and then we could just have ls_client.core.display_hover(..., err.into()); although I have bigger questions about this, see my top level comment.

@cmyr
Copy link
Copy Markdown
Member

cmyr commented Jul 13, 2018

Oh, one more thing:

I realize what the problem is about linebreaks and line/col. The client sends line/col that include soft breaks; however each language server plugin has its own copy of the document, and these don't include soft breaks. When we send a position to the language server plugin, we need to ensure that it is only using hard breaks; this means that we should be calling view methods to get the position for the plugin, we should only be calling methods on the Rope.

Similarly, when we get a position back from the plugin, we need to avoid using the view methods when we convert that position, or we will be accidentally taking the soft wraps into account and will get incorrect results again.

@betterclever
Copy link
Copy Markdown
Member Author

Closing in favour of #753

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants