Skip to content
This repository was archived by the owner on May 4, 2024. It is now read-only.

Commit 3c47a95

Browse files
authored
[move-analyzer] Add Docstring rendering on-hover (#328)
* [move-analyzer] Add docstring rendering for consts, structs, functions * [move-analyzer] Optimize docstring construction * [move-analyzer] Add rendering for docstrings across other modules * [move-analyzer] Fix M1.move tests * [move-analyzer] Add unit tests for docstring construction * [move-analyzer] Add integration tests for docstring construction * [move-analyzer] Add support for /** .. */ docstring comments * [move-analyzer] Update unit/integration tests to test asterix-based docstrings * [move-analyzer] Fix general PR comments * [move-analyzer] Improve extract_doc_string readability * [move-analyzer] Fix linter issues
1 parent 9169307 commit 3c47a95

File tree

10 files changed

+570
-9
lines changed

10 files changed

+570
-9
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
**/target
55
**/*.rs.bk
66
.idea/
7+
**/.vscode
78

89
# Ignore wallet mnemonic files used for deterministic key derivation
910
*.mnemonic

language/move-analyzer/editors/code/.eslintrc.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110
"max-len": [
111111
"warn",
112112
{
113-
"code": 100,
113+
"code": 120,
114114
"ignoreUrls": true
115115
}
116116
],

language/move-analyzer/editors/code/src/commands/lsp_command.ts

+20-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type {
33
SymbolInformation,
44
DocumentSymbol,
55
} from 'vscode-languageclient';
6-
import { DocumentSymbolRequest } from 'vscode-languageclient';
6+
import { DocumentSymbolRequest, HoverRequest } from 'vscode-languageclient';
77
import type { Context } from '../context';
88

99
/**
@@ -12,7 +12,7 @@ import type { Context } from '../context';
1212
export async function textDocumentDocumentSymbol(
1313
context: Readonly<Context>,
1414
params: DocumentSymbolParams,
15-
)
15+
)
1616
: Promise<SymbolInformation[] | DocumentSymbol[] | null> {
1717
const client = context.getClient();
1818
if (client === undefined) {
@@ -22,3 +22,21 @@ export async function textDocumentDocumentSymbol(
2222
// Send the request to the language client.
2323
return client.sendRequest(DocumentSymbolRequest.type, params);
2424
}
25+
26+
27+
/**
28+
* An LSP command textDocument/hover
29+
*/
30+
export async function textDocumentHover(
31+
context: Readonly<Context>,
32+
params: DocumentSymbolParams,
33+
)
34+
: Promise<SymbolInformation[] | DocumentSymbol[] | null> {
35+
const client = context.getClient();
36+
if (client === undefined) {
37+
return Promise.reject(new Error('No language client connected.'));
38+
}
39+
40+
// Send the request to the language client.
41+
return client.sendRequest(HoverRequest.method, params);
42+
}

language/move-analyzer/editors/code/src/main.ts

+1
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,5 @@ export async function activate(extensionContext: Readonly<vscode.ExtensionContex
7474
// All other utilities provided by this extension occur via the language server.
7575
await context.startClient();
7676
context.registerCommand('textDocumentDocumentSymbol', commands.textDocumentDocumentSymbol);
77+
context.registerCommand('textDocumentHover', commands.textDocumentHover);
7778
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module Symbols::M2 {
2+
3+
/// Constant containing the answer to the universe
4+
const DOCUMENTED_CONSTANT: u64 = 42;
5+
6+
/**
7+
This is a multiline docstring
8+
9+
This docstring has empty lines.
10+
11+
It uses the ** format instead of ///
12+
*/
13+
fun other_doc_struct(): Symbols::M3::OtherDocStruct {
14+
Symbols::M3::create_other_struct(DOCUMENTED_CONSTANT)
15+
}
16+
17+
use Symbols::M3::{Self, OtherDocStruct};
18+
19+
fun other_doc_struct_import(): OtherDocStruct {
20+
M3::create_other_struct(7)
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module Symbols::M3 {
2+
3+
/// Documented struct in another module
4+
struct OtherDocStruct has drop {
5+
some_field: u64,
6+
}
7+
8+
/// Documented initializer in another module
9+
public fun create_other_struct(v: u64): OtherDocStruct {
10+
OtherDocStruct { some_field: v }
11+
}
12+
}

language/move-analyzer/editors/code/tests/lsp.test.ts

+79
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as Mocha from 'mocha';
33
import * as path from 'path';
44
import * as vscode from 'vscode';
55
import * as lc from 'vscode-languageclient';
6+
import type { MarkupContent } from 'vscode-languageclient';
67

78
Mocha.suite('LSP', () => {
89
Mocha.test('textDocument/documentSymbol', async () => {
@@ -49,4 +50,82 @@ Mocha.suite('LSP', () => {
4950
assert.deepStrictEqual(syms[0]?.children[3].name, 'this_is_a_test');
5051
assert.deepStrictEqual(syms[0]?.children[3]?.detail, '["test", "expected_failure"]');
5152
});
53+
54+
Mocha.test('textDocument/hover for definition in the same module', async () => {
55+
const ext = vscode.extensions.getExtension('move.move-analyzer');
56+
assert.ok(ext);
57+
58+
await ext.activate(); // Synchronous waiting for activation to complete
59+
60+
// 1. get workdir
61+
const workDir = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? '';
62+
63+
// 2. open doc
64+
const docs = await vscode.workspace.openTextDocument(
65+
path.join(workDir, 'sources/M2.move'),
66+
);
67+
await vscode.window.showTextDocument(docs);
68+
69+
// 3. execute command
70+
const params: lc.HoverParams = {
71+
textDocument: {
72+
uri: docs.uri.toString(),
73+
},
74+
position: {
75+
line: 12,
76+
character: 8,
77+
},
78+
};
79+
80+
const hoverResult: lc.Hover | undefined =
81+
await vscode.commands.executeCommand(
82+
'move-analyzer.textDocumentHover',
83+
params,
84+
);
85+
86+
assert.ok(hoverResult);
87+
assert.deepStrictEqual((hoverResult.contents as MarkupContent).value,
88+
// eslint-disable-next-line max-len
89+
'fun Symbols::M2::other_doc_struct(): Symbols::M3::OtherDocStruct\n\n\nThis is a multiline docstring\n\nThis docstring has empty lines.\n\nIt uses the ** format instead of ///\n\n');
90+
91+
});
92+
93+
Mocha.test('textDocument/hover for definition in an external module', async () => {
94+
const ext = vscode.extensions.getExtension('move.move-analyzer');
95+
assert.ok(ext);
96+
97+
await ext.activate(); // Synchronous waiting for activation to complete
98+
99+
// 1. get workdir
100+
const workDir = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? '';
101+
102+
// 2. open doc
103+
const docs = await vscode.workspace.openTextDocument(
104+
path.join(workDir, 'sources/M2.move'),
105+
);
106+
await vscode.window.showTextDocument(docs);
107+
108+
// 3. execute command
109+
const params: lc.HoverParams = {
110+
textDocument: {
111+
uri: docs.uri.toString(),
112+
},
113+
position: {
114+
line: 18,
115+
character: 35,
116+
},
117+
};
118+
119+
const hoverResult: lc.Hover | undefined =
120+
await vscode.commands.executeCommand(
121+
'move-analyzer.textDocumentHover',
122+
params,
123+
);
124+
125+
126+
assert.ok(hoverResult);
127+
assert.deepStrictEqual((hoverResult.contents as MarkupContent).value,
128+
'Symbols::M3::OtherDocStruct\n\nDocumented struct in another module\n');
129+
130+
});
52131
});

0 commit comments

Comments
 (0)