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" diff --git a/src/language_client.rs b/src/language_client.rs index 0204c7cf..00eaa99b 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 { @@ -1080,6 +1082,21 @@ impl LanguageClient { loc.range.start.line + 1, loc.range.start.character + 1 ))?; + + self.vim()?.update_tagstack( + winnr, + TagStackItem { + bufnr, + from: Pos { + bufnr, + lnum: position.line + 1, + col: position.character + 1, + off: 0, + }, + matchnr: None, + tagname: current_word, + }, + )?; } _ => { let title = format!("[LC]: search for {}", current_word); diff --git a/src/types.rs b/src/types.rs index 05ee4168..8f3f847a 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}, @@ -110,6 +111,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 { @@ -1199,3 +1202,30 @@ 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, +} + +/// 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, + pub lnum: u32, + pub col: u32, + pub off: u32, +} diff --git a/src/vim.rs b/src/vim.rs index 215d7f0e..408b6af5 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, TagStack, TagStackItem, 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,11 @@ impl Vim { pub fn set_signs(&self, filename: &str, signs: &[Sign]) -> Result { self.rpcclient.call("s:set_signs", json!([filename, signs])) } + + pub fn update_tagstack(&self, winnr: Winnr, item: TagStackItem) -> Result<()> { + let mut stack: TagStack = self.rpcclient.call("gettagstack", winnr)?; + stack.items.clear(); + stack.items.push(item); + self.rpcclient.notify("settagstack", (winnr, stack, "t")) + } }