From adb4a9857bc1f788478f820fe09c9940d1f852a7 Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Fri, 30 Apr 2021 01:26:35 -0400 Subject: [PATCH 01/13] first pass at updating the tag stack for jump to definition --- src/language_client.rs | 12 ++++++++++++ src/types.rs | 2 ++ src/vim.rs | 25 ++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/language_client.rs b/src/language_client.rs index 0204c7cf..06e39551 100644 --- a/src/language_client.rs +++ b/src/language_client.rs @@ -1036,6 +1036,8 @@ impl LanguageClient { let position = self.vim()?.get_position(params)?; let current_word = self.vim()?.get_current_word(params)?; let goto_cmd = self.vim()?.get_goto_cmd(params)?; + let bufnr = self.vim()?.get_bufnr(&filename, params)?; + let winnr = self.vim()?.get_winnr(params)?; let params = serde_json::to_value(TextDocumentPositionParams { text_document: TextDocumentIdentifier { @@ -1068,6 +1070,16 @@ impl LanguageClient { match locations.len() { 0 => self.vim()?.echowarn("Not found!")?, 1 => { + // update the tag stack + self.vim()?.appendtagstack( + winnr, + bufnr, + position.line + 1, + position.character + 1, + 0, + ¤t_word, + )?; + let loc = locations.get(0).ok_or_else(|| anyhow!("Not found!"))?; let path = loc.uri.filepath()?.to_string_lossy().into_owned(); self.edit(&goto_cmd, path)?; diff --git a/src/types.rs b/src/types.rs index 05ee4168..7c6e156e 100644 --- a/src/types.rs +++ b/src/types.rs @@ -110,6 +110,8 @@ pub type Id = u64; pub type LanguageId = Option; /// Buffer id/handle. pub type Bufnr = i64; +/// Window id/handle. +pub type Winnr = u32; #[derive(Debug, Serialize, Deserialize)] pub enum Message { diff --git a/src/vim.rs b/src/vim.rs index 215d7f0e..cebe3f31 100644 --- a/src/vim.rs +++ b/src/vim.rs @@ -1,7 +1,7 @@ use crate::{ rpcclient::RpcClient, sign::Sign, - types::{Bufnr, QuickfixEntry, VimExp, VirtualText}, + types::{Bufnr, QuickfixEntry, VimExp, VirtualText, Winnr}, utils::Canonicalize, viewport::Viewport, }; @@ -131,6 +131,12 @@ impl Vim { try_get(key, params)?.map_or_else(|| self.eval(format!("bufnr('{}')", filename)), Ok) } + pub fn get_winnr(&self, params: &Value) -> Result { + let key = "winnr"; + + try_get(key, params)?.map_or_else(|| self.eval("winnr()"), Ok) + } + pub fn get_viewport(&self, params: &Value) -> Result { let key = "viewport"; let expr = "LSP#viewport()"; @@ -275,4 +281,21 @@ impl Vim { pub fn set_signs(&self, filename: &str, signs: &[Sign]) -> Result { self.rpcclient.call("s:set_signs", json!([filename, signs])) } + + pub fn appendtagstack( + &self, + winnr: Winnr, + bufnr: Bufnr, + lnum: u32, + col: u32, + off: u32, + tagname: &str, + ) -> Result<()> { + let mut stack: Value = self.rpcclient.call("gettagstack", ())?; + let items = stack.get_mut("items").unwrap().as_array_mut().unwrap(); + items.clear(); + items.push(json!({"bufnr": bufnr, "from": [bufnr, lnum, col, off], "tagname": tagname})); + self.rpcclient + .notify("settagstack", json!([winnr, stack, "a"])) + } } From 91c92f1cd547f1a33cebf2d6d474198328390fae Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Fri, 30 Apr 2021 02:37:59 -0400 Subject: [PATCH 02/13] add serde_tuple --- Cargo.lock | 22 ++++++++++++++++++++++ Cargo.toml | 1 + 2 files changed, 23 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index a79da02a..9dc6c052 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -458,6 +458,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", + "serde_tuple", "shellexpand", "thiserror", "tracing", @@ -881,6 +882,27 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_tuple" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f025b91216f15a2a32aa39669329a475733590a015835d1783549a56d09427" +dependencies = [ + "serde", + "serde_tuple_macros", +] + +[[package]] +name = "serde_tuple_macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4076151d1a2b688e25aaf236997933c66e18b870d0369f8b248b8ab2be630d7e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_yaml" version = "0.8.13" diff --git a/Cargo.toml b/Cargo.toml index 721f2554..d0dbc92a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ maplit = "1" serde = "1" serde_derive = "1" serde_json = "1" +serde_tuple = "0.5.0" json-patch = "0.2" crossbeam = "0.7.3" jsonrpc-core = "15" From 7a584139b35e6185101eba3d71f0de86fe4302c0 Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Fri, 30 Apr 2021 02:38:29 -0400 Subject: [PATCH 03/13] add rust types for the vim tagstack --- src/types.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/types.rs b/src/types.rs index 7c6e156e..0d9bfc65 100644 --- a/src/types.rs +++ b/src/types.rs @@ -22,6 +22,7 @@ use maplit::hashmap; use pathdiff::diff_paths; use serde::{Deserialize, Serialize}; use serde_json::Value; +use serde_tuple::{Deserialize_tuple, Serialize_tuple}; use std::{ collections::HashMap, io::{BufRead, BufReader, BufWriter, Write}, @@ -1201,3 +1202,26 @@ pub struct WorkspaceEditWithCursor { pub workspace_edit: WorkspaceEdit, pub cursor_position: Option, } + +#[derive(Debug, Serialize, Deserialize)] +pub struct TagStack { + pub curidx: u32, + pub items: Vec, + pub length: u32, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct TagStackItem { + pub bufnr: Bufnr, + pub from: Pos, + pub matchnr: Option, + pub tagname: String, +} + +#[derive(Debug, Serialize_tuple, Deserialize_tuple)] +pub struct Pos { + pub bufnr: Bufnr, + pub lnum: u32, + pub col: u32, + pub off: u32, +} From 0b2d7da74e35e3c2cc706172c87deebfebb3e14f Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Fri, 30 Apr 2021 02:39:55 -0400 Subject: [PATCH 04/13] use rust types to interact with tagstack --- src/vim.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/vim.rs b/src/vim.rs index cebe3f31..676e138b 100644 --- a/src/vim.rs +++ b/src/vim.rs @@ -1,7 +1,7 @@ use crate::{ rpcclient::RpcClient, sign::Sign, - types::{Bufnr, QuickfixEntry, VimExp, VirtualText, Winnr}, + types::{Bufnr, Pos, QuickfixEntry, TagStack, TagStackItem, VimExp, VirtualText, Winnr}, utils::Canonicalize, viewport::Viewport, }; @@ -291,10 +291,19 @@ impl Vim { off: u32, tagname: &str, ) -> Result<()> { - let mut stack: Value = self.rpcclient.call("gettagstack", ())?; - let items = stack.get_mut("items").unwrap().as_array_mut().unwrap(); - items.clear(); - items.push(json!({"bufnr": bufnr, "from": [bufnr, lnum, col, off], "tagname": tagname})); + let mut stack: TagStack = self.rpcclient.call("gettagstack", ())?; + stack.items.clear(); + stack.items.push(TagStackItem { + bufnr, + from: Pos { + bufnr, + lnum, + col, + off, + }, + matchnr: None, + tagname: tagname.to_string(), + }); self.rpcclient .notify("settagstack", json!([winnr, stack, "a"])) } From 0080b0986010641f41ad39ec1ae74007bfa40332 Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Fri, 30 Apr 2021 02:51:06 -0400 Subject: [PATCH 05/13] use `t` instead of `a` to update the stack stack The `a` operation appends to the tag stack, the `t` operation clears everything from the current position to the top of the stack and then appends new entries. We want the latter behavior. --- src/vim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vim.rs b/src/vim.rs index 676e138b..e7bfa6d9 100644 --- a/src/vim.rs +++ b/src/vim.rs @@ -305,6 +305,6 @@ impl Vim { tagname: tagname.to_string(), }); self.rpcclient - .notify("settagstack", json!([winnr, stack, "a"])) + .notify("settagstack", json!([winnr, stack, "t"])) } } From d8f800e3530eab2779c3386693e8ab1e47397c03 Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Fri, 30 Apr 2021 02:54:15 -0400 Subject: [PATCH 06/13] rename `appendtagstack` to `update_tagstack` --- src/language_client.rs | 3 +-- src/vim.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/language_client.rs b/src/language_client.rs index 06e39551..a402d8f3 100644 --- a/src/language_client.rs +++ b/src/language_client.rs @@ -1070,8 +1070,7 @@ impl LanguageClient { match locations.len() { 0 => self.vim()?.echowarn("Not found!")?, 1 => { - // update the tag stack - self.vim()?.appendtagstack( + self.vim()?.update_tagstack( winnr, bufnr, position.line + 1, diff --git a/src/vim.rs b/src/vim.rs index e7bfa6d9..00398e33 100644 --- a/src/vim.rs +++ b/src/vim.rs @@ -282,7 +282,7 @@ impl Vim { self.rpcclient.call("s:set_signs", json!([filename, signs])) } - pub fn appendtagstack( + pub fn update_tagstack( &self, winnr: Winnr, bufnr: Bufnr, From 9a8e228519e6ab71d3a4d237bd0a5b6dd1b69462 Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Fri, 30 Apr 2021 02:56:09 -0400 Subject: [PATCH 07/13] remove unnecessary `off` param --- src/language_client.rs | 1 - src/vim.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/language_client.rs b/src/language_client.rs index a402d8f3..00796c05 100644 --- a/src/language_client.rs +++ b/src/language_client.rs @@ -1075,7 +1075,6 @@ impl LanguageClient { bufnr, position.line + 1, position.character + 1, - 0, ¤t_word, )?; diff --git a/src/vim.rs b/src/vim.rs index 00398e33..ec0918ea 100644 --- a/src/vim.rs +++ b/src/vim.rs @@ -288,7 +288,6 @@ impl Vim { bufnr: Bufnr, lnum: u32, col: u32, - off: u32, tagname: &str, ) -> Result<()> { let mut stack: TagStack = self.rpcclient.call("gettagstack", ())?; From b432f3171ae41d7acc08f9514bde31203d10ffa1 Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Fri, 30 Apr 2021 03:05:04 -0400 Subject: [PATCH 08/13] force caller to construct TagStackItem This matches the style of other vim.rs functions. --- src/language_client.rs | 15 +++++++++++---- src/vim.rs | 23 +++-------------------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/language_client.rs b/src/language_client.rs index 00796c05..a78071e8 100644 --- a/src/language_client.rs +++ b/src/language_client.rs @@ -1072,10 +1072,17 @@ impl LanguageClient { 1 => { self.vim()?.update_tagstack( winnr, - bufnr, - position.line + 1, - position.character + 1, - ¤t_word, + TagStackItem { + bufnr, + from: Pos { + bufnr, + lnum: position.line + 1, + col: position.character + 1, + off: 0, + }, + matchnr: None, + tagname: current_word.clone(), + }, )?; let loc = locations.get(0).ok_or_else(|| anyhow!("Not found!"))?; diff --git a/src/vim.rs b/src/vim.rs index ec0918ea..9a8f5104 100644 --- a/src/vim.rs +++ b/src/vim.rs @@ -1,7 +1,7 @@ use crate::{ rpcclient::RpcClient, sign::Sign, - types::{Bufnr, Pos, QuickfixEntry, TagStack, TagStackItem, VimExp, VirtualText, Winnr}, + types::{Bufnr, QuickfixEntry, TagStack, TagStackItem, VimExp, VirtualText, Winnr}, utils::Canonicalize, viewport::Viewport, }; @@ -282,27 +282,10 @@ impl Vim { self.rpcclient.call("s:set_signs", json!([filename, signs])) } - pub fn update_tagstack( - &self, - winnr: Winnr, - bufnr: Bufnr, - lnum: u32, - col: u32, - tagname: &str, - ) -> Result<()> { + pub fn update_tagstack(&self, winnr: Winnr, item: TagStackItem) -> Result<()> { let mut stack: TagStack = self.rpcclient.call("gettagstack", ())?; stack.items.clear(); - stack.items.push(TagStackItem { - bufnr, - from: Pos { - bufnr, - lnum, - col, - off, - }, - matchnr: None, - tagname: tagname.to_string(), - }); + stack.items.push(item); self.rpcclient .notify("settagstack", json!([winnr, stack, "t"])) } From 8ed2d974d5ecee47a2e93be3287557a9d725d544 Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Fri, 30 Apr 2021 03:11:20 -0400 Subject: [PATCH 09/13] document Pos type --- src/types.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/types.rs b/src/types.rs index 0d9bfc65..8f3f847a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1218,6 +1218,10 @@ pub struct TagStackItem { pub tagname: String, } +/// This represents a position in a buffer. +/// +/// Vim returns this as a List from the `getpos()` function. It is also used as the `from` value in +/// tag stack items. #[derive(Debug, Serialize_tuple, Deserialize_tuple)] pub struct Pos { pub bufnr: Bufnr, From 01d310436d29e9f67c2ba05f87a38633d8651871 Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Fri, 30 Apr 2021 03:25:06 -0400 Subject: [PATCH 10/13] update tagstack after successful jump --- src/language_client.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/language_client.rs b/src/language_client.rs index a78071e8..59b850f8 100644 --- a/src/language_client.rs +++ b/src/language_client.rs @@ -1070,6 +1070,19 @@ impl LanguageClient { match locations.len() { 0 => self.vim()?.echowarn("Not found!")?, 1 => { + let loc = locations.get(0).ok_or_else(|| anyhow!("Not found!"))?; + let path = loc.uri.filepath()?.to_string_lossy().into_owned(); + self.edit(&goto_cmd, path)?; + self.vim()? + .cursor(loc.range.start.line + 1, loc.range.start.character + 1)?; + let cur_file: String = self.vim()?.eval("expand('%')")?; + self.vim()?.echomsg_ellipsis(format!( + "{} {}:{}", + cur_file, + loc.range.start.line + 1, + loc.range.start.character + 1 + ))?; + self.vim()?.update_tagstack( winnr, TagStackItem { @@ -1084,19 +1097,6 @@ impl LanguageClient { tagname: current_word.clone(), }, )?; - - let loc = locations.get(0).ok_or_else(|| anyhow!("Not found!"))?; - let path = loc.uri.filepath()?.to_string_lossy().into_owned(); - self.edit(&goto_cmd, path)?; - self.vim()? - .cursor(loc.range.start.line + 1, loc.range.start.character + 1)?; - let cur_file: String = self.vim()?.eval("expand('%')")?; - self.vim()?.echomsg_ellipsis(format!( - "{} {}:{}", - cur_file, - loc.range.start.line + 1, - loc.range.start.character + 1 - ))?; } _ => { let title = format!("[LC]: search for {}", current_word); From 89f44356dd10680e7a4017fcc4fef21868a41e1d Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Fri, 30 Apr 2021 11:01:33 -0400 Subject: [PATCH 11/13] fix clippy lint --- src/language_client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/language_client.rs b/src/language_client.rs index 59b850f8..00eaa99b 100644 --- a/src/language_client.rs +++ b/src/language_client.rs @@ -1094,7 +1094,7 @@ impl LanguageClient { off: 0, }, matchnr: None, - tagname: current_word.clone(), + tagname: current_word, }, )?; } From ea87a70f29fcaa471b60369c093cf2dbab058648 Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Fri, 30 Apr 2021 11:07:42 -0400 Subject: [PATCH 12/13] pass `winnr` when calling `gettagstack` --- src/vim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vim.rs b/src/vim.rs index 9a8f5104..98001dfb 100644 --- a/src/vim.rs +++ b/src/vim.rs @@ -283,7 +283,7 @@ impl Vim { } pub fn update_tagstack(&self, winnr: Winnr, item: TagStackItem) -> Result<()> { - let mut stack: TagStack = self.rpcclient.call("gettagstack", ())?; + let mut stack: TagStack = self.rpcclient.call("gettagstack", winnr)?; stack.items.clear(); stack.items.push(item); self.rpcclient From 6b46e8af7dfc235e6f8a9c32d863fb4ec0d192ee Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Fri, 30 Apr 2021 11:08:41 -0400 Subject: [PATCH 13/13] use a tuple when calling `settagstack` --- src/vim.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vim.rs b/src/vim.rs index 98001dfb..408b6af5 100644 --- a/src/vim.rs +++ b/src/vim.rs @@ -286,7 +286,6 @@ impl Vim { let mut stack: TagStack = self.rpcclient.call("gettagstack", winnr)?; stack.items.clear(); stack.items.push(item); - self.rpcclient - .notify("settagstack", json!([winnr, stack, "t"])) + self.rpcclient.notify("settagstack", (winnr, stack, "t")) } }