From ccaeca30e279b6ccafdc4f227517d0ec3fa32ac4 Mon Sep 17 00:00:00 2001
From: Sergey Vlasov <sergey@vlasov.me>
Date: Tue, 8 Mar 2022 23:17:35 +0200
Subject: [PATCH] Add support for LspSwitchSourceHeader command

---
 autoload/lsp/handlers.vim  | 14 ++++++++++++++
 autoload/lsp/lsp.vim       | 10 ++++++++++
 autoload/lsp/lspserver.vim | 11 +++++++++++
 doc/lsp.txt                |  4 ++++
 plugin/lsp.vim             |  3 +++
 5 files changed, 42 insertions(+)

diff --git a/autoload/lsp/handlers.vim b/autoload/lsp/handlers.vim
index d86156f..b6fe263 100644
--- a/autoload/lsp/handlers.vim
+++ b/autoload/lsp/handlers.vim
@@ -146,6 +146,19 @@ def ProcessDefDeclReply(lspserver: dict<any>, req: dict<any>, reply: dict<any>):
   symbol.GotoSymbol(lspserver, location, req.method)
 enddef
 
+# process the 'textDocument/switchSourceHeader' reply from the LSP server
+# Result: URI | null
+def ProcessSwitchHeaderReply(lspserver: dict<any>, req: dict<any>, reply: dict<any>): void
+  var fname = util.LspUriToFile(reply.result)
+  if (&modified && !&hidden) || &buftype != ''
+    # if the current buffer has unsaved changes and 'hidden' is not set,
+    # or if the current buffer is a special buffer, then ask to save changes
+    exe 'confirm edit ' .. fname
+  else
+    exe 'edit  ' .. fname
+  endif
+enddef
+
 # process the 'textDocument/signatureHelp' reply from the LSP server
 # Result: SignatureHelp | null
 def ProcessSignaturehelpReply(lspserver: dict<any>, req: dict<any>, reply: dict<any>): void
@@ -710,6 +723,7 @@ export def ProcessReply(lspserver: dict<any>, req: dict<any>, reply: dict<any>):
       'textDocument/definition': ProcessDefDeclReply,
       'textDocument/declaration': ProcessDefDeclReply,
       'textDocument/typeDefinition': ProcessDefDeclReply,
+      'textDocument/switchSourceHeader': ProcessSwitchHeaderReply,
       'textDocument/implementation': ProcessDefDeclReply,
       'textDocument/signatureHelp': ProcessSignaturehelpReply,
       'textDocument/completion': ProcessCompletionReply,
diff --git a/autoload/lsp/lsp.vim b/autoload/lsp/lsp.vim
index e4b1c95..19abc90 100644
--- a/autoload/lsp/lsp.vim
+++ b/autoload/lsp/lsp.vim
@@ -215,6 +215,16 @@ export def GotoDefinition(peek: bool)
   lspserver.gotoDefinition(peek)
 enddef
 
+# Switch source header using "textDocument/switchSourceHeader" LSP request
+export def SwitchSourceHeader()
+  var lspserver: dict<any> = CurbufGetServerChecked()
+  if lspserver->empty()
+    return
+  endif
+
+  lspserver.switchSourceHeader()
+enddef
+
 # Go to a declaration using "textDocument/declaration" LSP request
 export def GotoDeclaration(peek: bool)
   var lspserver: dict<any> = CurbufGetServerChecked()
diff --git a/autoload/lsp/lspserver.vim b/autoload/lsp/lspserver.vim
index 968eefe..e99d941 100644
--- a/autoload/lsp/lspserver.vim
+++ b/autoload/lsp/lspserver.vim
@@ -477,6 +477,16 @@ def GotoDefinition(lspserver: dict<any>, peek: bool)
   lspserver.waitForReponse(req)
 enddef
 
+# Request: "textDocument/switchSourceHeader"
+# Param: TextDocumentIdentifier
+def SwitchSourceHeader(lspserver: dict<any>)
+  var req = lspserver.createRequest('textDocument/switchSourceHeader')
+  req.params->extend({uri: util.LspFileToUri(@%)})
+  lspserver.sendMessage(req)
+
+  lspserver.waitForReponse(req)
+enddef
+
 # Request: "textDocument/declaration"
 # Param: DeclarationParams
 def GotoDeclaration(lspserver: dict<any>, peek: bool): void
@@ -1059,6 +1069,7 @@ export def NewLspServer(path: string, args: list<string>): dict<any>
     sendInitializedNotif: function(SendInitializedNotif, [lspserver]),
     getCompletion: function(GetCompletion, [lspserver]),
     gotoDefinition: function(GotoDefinition, [lspserver]),
+    switchSourceHeader: function(SwitchSourceHeader, [lspserver]),
     gotoDeclaration: function(GotoDeclaration, [lspserver]),
     gotoTypeDef: function(GotoTypeDef, [lspserver]),
     gotoImplementation: function(GotoImplementation, [lspserver]),
diff --git a/doc/lsp.txt b/doc/lsp.txt
index 93ed7cc..7f631ce 100644
--- a/doc/lsp.txt
+++ b/doc/lsp.txt
@@ -101,6 +101,7 @@ The following commands are provided:
 :LspPeekReferences	Display the list of references to the keyword under
 			cursor in a location list associated with the preview
 			window.
+:LspSwitchSourceHeader	Switch between source and header files.
 :LspHighlight		Highlight all the matches for the keyword under cursor
 :LspHighlightClear	Clear all the matches highlighted by :LspHighlight
 :LspOutline		Show the list of symbols defined in the current file
@@ -317,6 +318,9 @@ diagnostic messages, you can add the following line to your .vimrc file:
 <
 			Default is false.
 
+						*:LspSwitchSourceHeader*
+:LspSwitchSourceHeader	Switch between source and header files.
+
 						*:LspDiagShow*
 :LspDiagShow		Creates a new location list with the diagnostics
 			messages (if any) from the LSP server for the current
diff --git a/plugin/lsp.vim b/plugin/lsp.vim
index a03eb65..d305778 100644
--- a/plugin/lsp.vim
+++ b/plugin/lsp.vim
@@ -44,6 +44,7 @@ if has('patch-8.2.4257')
   lspf.hover = lsp.Hover
   lspf.selectionExpand = lsp.SelectionExpand
   lspf.selectionShrink = lsp.SelectionShrink
+  lspf.switchSourceHeader = lsp.SwitchSourceHeader
   lspf.foldDocument = lsp.FoldDocument
   lspf.listWorkspaceFolders = lsp.ListWorkspaceFolders
   lspf.addWorkspaceFolder = lsp.AddWorkspaceFolder
@@ -211,6 +212,7 @@ var TsymbolSearch = lspf.symbolSearch
 var Thover = lspf.hover
 var TselectionExpand = lspf.selectionExpand
 var TselectionShrink = lspf.selectionShrink
+var TswitchSourceHeader = lspf.switchSourceHeader
 var TfoldDocument = lspf.foldDocument
 var TlistWorkspaceFolders = lspf.listWorkspaceFolders
 var TaddWorkspaceFolder = lspf.addWorkspaceFolder
@@ -254,6 +256,7 @@ command! -nargs=0 -bar LspDiagHighlightEnable call TdiagHighlightEnable()
 command! -nargs=0 -bar LspDiagHighlightDisable call TdiagHighlightDisable()
 command! -nargs=0 -bar LspShowReferences call TshowReferences(v:false)
 command! -nargs=0 -bar LspPeekReferences call TshowReferences(v:true)
+command! -nargs=0 -bar LspSwitchSourceHeader call TswitchSourceHeader()
 command! -nargs=0 -bar LspHighlight call LspDocHighlight()
 command! -nargs=0 -bar LspHighlightClear call LspDocHighlightClear()
 command! -nargs=0 -bar LspOutline call Toutline()
-- 
2.51.0