From 71921db245410f7f08251729eac579284238c741 Mon Sep 17 00:00:00 2001
From: danielrainer <34983953+danielrainer@users.noreply.github.com>
Date: Tue, 6 Aug 2024 02:59:42 +0000
Subject: [PATCH] feat: enable localDocs (#1261)

Opening docs (rust-analyzer.openDocs) was broken by commit
1410329b4625f3b6b02bb96675ec5313ba0fab25. This commit contains changes
preparing for the rust-analyzer "localDocs" feature
https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#local-documentation
However, this feature is only activated by specifying the "localDocs"
capability. This commits does so in src/client.ts.

To actually make use of the local documentation, the
src/commands.ts:openDocs function also needs adjustment.
I wrote it such that if a local URI is provided and a corresponding file
exists, it is opened.
Otherwise, if a web link is provided, this link is opened.

Note that "vscode.open" would open the local URI in the editor instead
of the browser.

Whether local documentation exists depends on whether 'cargo doc' has
been executed. If it has been executed but not recently, the
documentation might be outdated, so it might be reasonable to generate
local documentation before trying to open it.
This is not done so far, but could be added.
It might make sense to run 'cargo doc --no-deps'.

Co-authored-by: Daniel Rainer <daniel.rainer@localhost>
---
 src/client.ts   |  1 +
 src/commands.ts | 19 ++++++++++++++++---
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/src/client.ts b/src/client.ts
index 23086304..1c5e630c 100644
--- a/src/client.ts
+++ b/src/client.ts
@@ -24,6 +24,7 @@ class ExperimentalFeatures implements StaticFeature {
     const caps: any = capabilities.experimental ?? {};
     caps.snippetTextEdit = true;
     caps.serverStatusNotification = true;
+    caps.localDocs = true;
     caps.commands = {
       commands: [
         'rust-analyzer.runSingle',
diff --git a/src/commands.ts b/src/commands.ts
index c4ad78f6..f5e6fe2b 100644
--- a/src/commands.ts
+++ b/src/commands.ts
@@ -14,9 +14,10 @@ import {
   window,
   workspace,
   type WorkspaceEdit,
+  nvim,
 } from 'coc.nvim';
 import { randomBytes } from 'node:crypto';
-import { writeFileSync } from 'node:fs';
+import { existsSync, writeFileSync } from 'node:fs';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
 import readline from 'node:readline';
@@ -695,9 +696,21 @@ export function openDocs(ctx: Ctx): Cmd {
       textDocument: { uri: document.uri },
       position,
     };
+    // TODO: Should 'cargo doc' run at this point? Or 'cargo doc --no-deps'?
     const doclink = await ctx.client.sendRequest(ra.openDocs, param);
-    if (doclink?.web) {
-      await commands.executeCommand('vscode.open', Uri.parse(doclink.web));
+    if (doclink) {
+      if (doclink.local) {
+        // remove leading 'file://'
+        const absolutePath = doclink.local.substring(7);
+        const isReadable = existsSync(absolutePath);
+        if (isReadable) {
+          await nvim.call('coc#ui#open_url', doclink.local);
+          return;
+        }
+      }
+      if (doclink.web) {
+        await commands.executeCommand('vscode.open', Uri.parse(doclink.web));
+      }
     }
   };
 }