Skip to content

Commit 834726e

Browse files
committed
list document symbols!!!
1 parent 726ebeb commit 834726e

File tree

6 files changed

+193
-65
lines changed

6 files changed

+193
-65
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
"reason.path.bsb": "./node_modules/.bin/bsb",
88
"editor.codeLens": true,
99
"reason_language_server.location": "./lib/bs/native/bin.native",
10-
"reason_language_server.reloadOnChange": true
10+
"reason_language_server.reloadOnChange": true,
11+
"editor.tabSize": 2
1112
}

client/src/index.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@ const vscode = require("vscode");
77
const {LanguageClient} = require("vscode-languageclient");
88
const path = require('path')
99
const fs = require('fs')
10-
// const DEV = false;
1110

12-
const getLocation = () => {
11+
const getLocation = (context) => {
1312
let config = vscode.workspace.getConfiguration('reason_language_server')
1413

1514
let binaryLocation = config.get('location')
1615

1716
if (!binaryLocation) {
18-
binaryLocation = path.join(vscode.workspace.rootPath, 'node_modules', '@jaredly', 'reason-language-server', 'lib', 'bs', 'native', 'bin.native')
19-
// binaryLocation = path.join(vscode.workspace.rootPath, '..', 'lib', 'bs', 'native', 'bin.native')
17+
// see if it's bundled with the extension
18+
// hmm actually I could bundle one for each platform & probably be fine
19+
// I guess it's 9mb binary. I wonder if I can cut that down?
20+
binaryLocation = context.asAbsolutePath('../bin.native')
21+
if (!fs.existsSync(binaryLocation)) {
22+
binaryLocation = path.join(vscode.workspace.rootPath, 'node_modules', '@jaredly', 'reason-language-server', 'lib', 'bs', 'native', 'bin.native')
23+
}
2024
} else {
2125
if (!binaryLocation.startsWith('/')) {
2226
binaryLocation = path.join(vscode.workspace.rootPath, binaryLocation)
@@ -44,7 +48,6 @@ function activate(context) {
4448
synchronize: {
4549
// Synchronize the setting section 'reason_language_server' to the server
4650
configurationSection: 'reason_language_server',
47-
// Notify the server about file changes to '.clientrc files contain in the workspace
4851
fileEvents: vscode.workspace.createFileSystemWatcher('**/bsconfig.json')
4952
}
5053
};
@@ -69,6 +72,16 @@ function activate(context) {
6972
context.subscriptions.push({dispose: () => clearInterval(checkForBinaryChange)})
7073
}
7174

75+
/**
76+
* client.sendRequest(...).then(response => {
77+
* })
78+
*
79+
* client.sendNotification()....
80+
* that could be a way to implement the code actions that I want to do.
81+
*
82+
* alsooo I think I want
83+
*/
84+
7285
const restart = () => {
7386
if (client) {
7487
client.stop();

package.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@
22
"name": "@jaredly/reason-language-server",
33
"version": "1.0.0",
44
"scripts": {
5-
"start": "bsb -make-world -backend native",
5+
"start": "bsb -make-world -backend native -w",
66
"clean": "bsb -clean-world",
77
"watch": "bsb -make-world -backend native -w",
88
"package": "npm run package:bundle",
9-
"// package:cp": "rm -rf tmp; mkdir tmp; cp -r bsconfig.json package.json src omd odoc_parser bin lib tmp; mkdir tmp/node_modules; cp package.thin.json tmp/package.json",
10-
"// package:remap": "sed -i .bak 's/file:\\.\\.\\//file:..\\/tmp/' client/package.json",
119
"package:bundle": "cd client && npm i && vsce package",
12-
"// package:done": "mv client/package.json.bak client/package.json && rm -rf tmp",
1310
"postinstall": "bsb -make-world -backend native"
1411
},
1512
"keywords": [

src/Completions.re

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ let rec showItem = (name, item) =>
6666
}
6767
};
6868

69-
let isCapitalized = name => name.[0] >= 'A' && name.[0] <= 'Z';
69+
let isCapitalized = name => name != "" && (name.[0] >= 'A' && name.[0] <= 'Z');
7070

7171
open Infix;
7272

@@ -159,6 +159,7 @@ let get = (topModule, opens, parts, state, localData, pos) => {
159159
};
160160
switch parts {
161161
| [] => []
162+
| [""] => []
162163
| [single] =>
163164
let localResults = switch (localData) {
164165
| None => []

src/MessageHandlers.re

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,44 @@ let handlers: list((string, (state, Json.t) => result((state, Json.t), string)))
244244
}
245245
}),
246246

247+
("textDocument/documentSymbol", (state, params) => {
248+
open InfixResult;
249+
params |> RJson.get("textDocument") |?> RJson.get("uri") |?> RJson.string
250+
|?> uri => {
251+
open Infix;
252+
/* let items = */
253+
let items = State.getCompilationResult(uri, state) |> AsYouType.getResult |?>> snd
254+
|?# lazy(State.getLastDefinitions(uri, state))
255+
|?>> ((({Definition.topLevel, stamps})) => {
256+
let rec getItems = (path, stamp) => {
257+
let (name, loc, item, docs, scopeRange) = Hashtbl.find(stamps, stamp);
258+
let res = switch (item) {
259+
| Module(contents) => {
260+
let children = contents |> List.map(((_, stamp)) => getItems(path @ [name], stamp)) |> List.concat;
261+
Some((`Module, children))
262+
}
263+
| Type(t) => Some((Protocol.typeKind(t), []))
264+
| Constructor(_) => None
265+
| Attribute(_) => None
266+
| Value(v) => Some((Protocol.variableKind(v), []))
267+
};
268+
res |?>> ((((typ, children))) => [(name, typ, loc, path), ...children]) |? []
269+
};
270+
topLevel |> List.map(((name, stamp)) => getItems([], stamp)) |> List.concat;
271+
});
272+
(items |?>> items => {
273+
open Rpc.J;
274+
Ok((state, l(items |> List.map(((name, typ, loc, path)) => o([
275+
("name", s(name)),
276+
("kind", i(Protocol.symbolKind(typ))),
277+
("location", Protocol.locationOfLoc(loc)),
278+
("containerName", s(String.concat(".", path)))
279+
])))))
280+
281+
}) |? Ok((state, Json.Null))
282+
}
283+
}),
284+
247285
("textDocument/formatting", (state, params) => {
248286
open InfixResult;
249287
params |> RJson.get("textDocument") |?> RJson.get("uri") |?> RJson.string

src/util/Protocol.re

Lines changed: 132 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,140 @@
1-
21
open Rpc.J;
32

43
let pos = (~line, ~character) => o([("line", i(line)), ("character", i(character))]);
54

65
let range = (~start, ~end_) => o([("start", start), ("end", end_)]);
76

87
open Infix;
9-
let getTextDocument = doc => Json.get("uri", doc) |?> Json.string
10-
|?> uri => Json.get("version", doc) |?> Json.number
11-
|?> version => Json.get("text", doc) |?> Json.string
12-
|?>> text => (uri, version, text);
13-
14-
let getPosition = pos => Json.get("line", pos) |?> Json.number
15-
|?> line => Json.get("character", pos) |?> Json.number
16-
|?>> character => (int_of_float(line), int_of_float(character));
17-
18-
let rgetPosition = pos => (Result.InfixResult.(RJson.get("line", pos) |?> RJson.number
19-
|?> line => RJson.get("character", pos) |?> RJson.number
20-
|?>> character => (int_of_float(line), int_of_float(character))));
21-
22-
let rgetRange = pos => (Result.InfixResult.(RJson.get("start", pos) |?> rgetPosition
23-
|?> start => RJson.get("end", pos) |?> rgetPosition
24-
|?>> end_ => (start, end_)));
25-
26-
let rPositionParams = params => Result.InfixResult.(
27-
RJson.get("textDocument", params) |?> RJson.get("uri") |?> RJson.string
28-
|?> uri => RJson.get("position", params) |?> rgetPosition
29-
|?>> pos => (uri, pos)
30-
);
31-
32-
let posOfLexing = ({Lexing.pos_lnum, pos_cnum, pos_bol}) => o([
33-
("line", i(pos_lnum - 1)),
34-
("character", i(pos_cnum - pos_bol))
35-
]);
36-
37-
let tupleOfLexing = ({Lexing.pos_lnum, pos_cnum, pos_bol}) => (
38-
pos_lnum - 1,
39-
pos_cnum - pos_bol
40-
);
41-
42-
let markup = text => Json.Object([("kind", Json.String("markdown")), ("value", Json.String(text))]);
43-
44-
let rangeOfLoc = ({Location.loc_start, loc_end}) => o([
45-
("start", posOfLexing(loc_start)),
46-
("end", posOfLexing(loc_end))
47-
]);
48-
49-
let locationOfLoc = (~fname=?, {Location.loc_start: {Lexing.pos_fname}} as loc) => o([
8+
9+
let getTextDocument = (doc) =>
10+
Json.get("uri", doc)
11+
|?> Json.string
12+
|?> (
13+
(uri) =>
14+
Json.get("version", doc)
15+
|?> Json.number
16+
|?> (
17+
(version) => Json.get("text", doc) |?> Json.string |?>> ((text) => (uri, version, text))
18+
)
19+
);
20+
21+
let getPosition = (pos) =>
22+
Json.get("line", pos)
23+
|?> Json.number
24+
|?> (
25+
(line) =>
26+
Json.get("character", pos)
27+
|?> Json.number
28+
|?>> ((character) => (int_of_float(line), int_of_float(character)))
29+
);
30+
31+
let rgetPosition = (pos) =>
32+
Result.InfixResult.(
33+
RJson.get("line", pos)
34+
|?> RJson.number
35+
|?> (
36+
(line) =>
37+
RJson.get("character", pos)
38+
|?> RJson.number
39+
|?>> ((character) => (int_of_float(line), int_of_float(character)))
40+
)
41+
);
42+
43+
let rgetRange = (pos) =>
44+
Result.InfixResult.(
45+
RJson.get("start", pos)
46+
|?> rgetPosition
47+
|?> ((start) => RJson.get("end", pos) |?> rgetPosition |?>> ((end_) => (start, end_)))
48+
);
49+
50+
let rPositionParams = (params) =>
51+
Result.InfixResult.(
52+
RJson.get("textDocument", params)
53+
|?> RJson.get("uri")
54+
|?> RJson.string
55+
|?> ((uri) => RJson.get("position", params) |?> rgetPosition |?>> ((pos) => (uri, pos)))
56+
);
57+
58+
let posOfLexing = ({Lexing.pos_lnum, pos_cnum, pos_bol}) =>
59+
o([("line", i(pos_lnum - 1)), ("character", i(pos_cnum - pos_bol))]);
60+
61+
let tupleOfLexing = ({Lexing.pos_lnum, pos_cnum, pos_bol}) => (pos_lnum - 1, pos_cnum - pos_bol);
62+
63+
let markup = (text) =>
64+
Json.Object([("kind", Json.String("markdown")), ("value", Json.String(text))]);
65+
66+
let rangeOfLoc = ({Location.loc_start, loc_end}) =>
67+
o([("start", posOfLexing(loc_start)), ("end", posOfLexing(loc_end))]);
68+
69+
let locationOfLoc = (~fname=?, {Location.loc_start: {Lexing.pos_fname}} as loc) =>
70+
o([
5071
("range", rangeOfLoc(loc)),
51-
("uri", s((switch fname { | Some(x) => x | None => "file://" ++ pos_fname}))),
52-
]);
53-
54-
let rangeOfInts = (l0, c0, l1, c1) => o([
55-
("start", pos(~line=l0, ~character=c0)),
56-
("end", pos(~line=l1, ~character=c1)),
57-
]);
58-
59-
let locationContains = ({Location.loc_start, loc_end}, pos) => {
60-
tupleOfLexing(loc_start) <= pos &&
61-
tupleOfLexing(loc_end) >= pos
62-
};
72+
(
73+
"uri",
74+
s(
75+
switch fname {
76+
| Some(x) => x
77+
| None => "file://" ++ pos_fname
78+
}
79+
)
80+
)
81+
]);
82+
83+
let rangeOfInts = (l0, c0, l1, c1) =>
84+
o([("start", pos(~line=l0, ~character=c0)), ("end", pos(~line=l1, ~character=c1))]);
85+
86+
let locationContains = ({Location.loc_start, loc_end}, pos) =>
87+
tupleOfLexing(loc_start) <= pos && tupleOfLexing(loc_end) >= pos;
88+
89+
let symbolKind = (kind) =>
90+
switch kind {
91+
| `File => 1
92+
| `Module => 2
93+
| `Namespace => 3
94+
| `Package => 4
95+
| `Class => 5
96+
| `Method => 6
97+
| `Property => 7
98+
| `Field => 8
99+
| `Constructor => 9
100+
| `Enum => 10
101+
| `Interface => 11
102+
| `Function => 12
103+
| `Variable => 13
104+
| `Constant => 14
105+
| `String => 15
106+
| `Number => 16
107+
| `Boolean => 17
108+
| `Array => 18
109+
| `Object => 19
110+
| `Key => 20
111+
| `Null => 21
112+
| `EnumMember => 22
113+
| `Struct => 23
114+
| `Event => 24
115+
| `Operator => 25
116+
| `TypeParameter => 26
117+
};
118+
119+
let rec variableKind = (t) =>
120+
switch t.Types.desc {
121+
| Tlink(t) => variableKind(t)
122+
| Tsubst(t) => variableKind(t)
123+
| Tarrow(_) => `Function
124+
| Ttuple(_) => `Array
125+
| Tconstr(_) => `Variable
126+
| Tobject(_) => `Object
127+
| Tnil => `Null
128+
| Tvariant(_) => `EnumMember
129+
| Tpoly(_) => `EnumMember
130+
| Tpackage(_) => `Module
131+
| _ => `Variable
132+
};
133+
134+
let typeKind = (t) =>
135+
switch t.Types.type_kind {
136+
| Type_open
137+
| Type_abstract => `TypeParameter
138+
| Type_record(_) => `Interface
139+
| Type_variant(_) => `Enum
140+
};

0 commit comments

Comments
 (0)