Skip to content

Commit 04b169c

Browse files
committed
Truly integrate the recently merged rescript-editor-support
We did a subtree merge. Now it's time to adapt
1 parent dfa0667 commit 04b169c

File tree

10 files changed

+216
-90
lines changed

10 files changed

+216
-90
lines changed

.github/workflows/ci.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
branches: [ master ]
8+
9+
jobs:
10+
test:
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
os: [macos-latest, ubuntu-latest, windows-latest]
15+
16+
runs-on: ${{matrix.os}}
17+
18+
steps:
19+
- uses: actions/checkout@v2.3.4
20+
21+
- name: Cache OCaml's opam
22+
uses: actions/cache@v2.1.5
23+
with:
24+
path: ~/.opam
25+
key: ${{matrix.os}}-latest-ocaml-4.06.1
26+
27+
- name: Use OCaml
28+
uses: avsm/setup-ocaml@v1.1.10
29+
with:
30+
ocaml-version: 4.06.1
31+
32+
- name: Use Node.js
33+
uses: actions/setup-node@v2.1.5
34+
with:
35+
node-version: 14.4.0
36+
37+
- run: npm ci
38+
39+
# These 2 runs (or just the second?) are for when you have opam dependencies. We don't.
40+
# Don't add deps. But if you ever do, un-comment these
41+
# - run: opam pin add rescript-editor-support.dev . --no-action
42+
# - run: opam install . --deps-only --with-doc --with-test
43+
44+
- run: eval $(opam env) && cd analysis && make test
45+
if: matrix.os != 'windows-latest'
46+
# CI windows running the binary somehow stucks. Not sure why. Disable for now.
47+
- run: "cd analysis && & $env:CYGWIN_ROOT\\bin\\ocaml-env exec -- make"
48+
if: matrix.os == 'windows-latest'
49+
50+
# Also avoids artifacts upload permission loss:
51+
# https://github.com/actions/upload-artifact/tree/ee69f02b3dfdecd58bb31b4d133da38ba6fe3700#permission-loss
52+
- name: Compress files
53+
run: tar -cvf binary.tar -C server/analysis_binaries current-platform.exe
54+
55+
- uses: actions/upload-artifact@v2
56+
with:
57+
name: ${{matrix.os}}.exe
58+
path: binary.tar

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
out
33
node_modules
44
client/server
5-
.vscode-test
5+
.vscode-test
6+
*.exe

analysis/.gitignore

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
.DS_Store
21
.merlin
32
!/.merlin
4-
npm-debug.log
53
*.install
64
examples/*/lib
75
tests/lib
@@ -11,5 +9,3 @@ node_modules
119
*.cmti
1210
*.cmx
1311
*.o
14-
lib/*
15-
!lib/README.md

analysis/Makefile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ OCAMLOPT = ocamlopt.opt
66
OCAMLFLAGS = -g -w +26+27+32+33+39 -bin-annot -I +compiler-libs $(INCLUDES)
77
OCAMLDEP = ocamldep.opt
88

9+
OUTPUT = ../server/analysis_binaries/current-platform.exe
10+
911
%.cmi : %.mli
1012
@echo Building $@
1113
@$(OCAMLOPT) $(OCAMLFLAGS) -c $<
@@ -19,16 +21,16 @@ depend:
1921

2022
SOURCE_FILES = $(shell $(OCAMLDEP) -sort `find src -name "*.ml"` | sed -E "s/\.ml/.cmx/g")
2123

22-
lib/rescript-editor-support.exe: $(SOURCE_FILES)
24+
$(OUTPUT): $(SOURCE_FILES)
2325
@echo Linking...
24-
@$(OCAMLOPT) $(OCAMLFLAGS) -O2 -o ./lib/rescript-editor-support.exe \
26+
@$(OCAMLOPT) $(OCAMLFLAGS) -O2 -o $(OUTPUT) \
2527
-I +compiler-libs unix.cmxa str.cmxa ocamlcommon.cmxa $(INCLUDES) $(SOURCE_FILES)
2628
@echo Done!
2729

28-
build-native: lib/rescript-editor-support.exe depend
30+
build-native: $(OUTPUT) depend
2931

3032
dce: build-native
31-
node_modules/.bin/reanalyze -dce-cmt src -suppress src/vendor
33+
../node_modules/.bin/reanalyze -dce-cmt src -suppress src/vendor
3234

3335
tests/node_modules/.bin/rescript:
3436
@cd tests && npm install

analysis/test.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ function exp {
33
}
44

55
for file in tests/src/*.res; do
6-
lib/rescript-editor-support.exe test $file &> $(exp $file)
6+
../server/analysis_binaries/current-platform.exe test $file &> $(exp $file)
77
done
88

99
warningYellow='\033[0;33m'

package-lock.json

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
"@typescript-eslint/parser": "^2.3.0",
113113
"eslint": "^6.4.0",
114114
"mocha": "^8.0.1",
115+
"reanalyze": "^2.15.0",
115116
"typescript": "^3.9.4"
116117
},
117118
"dependencies": {

server/analysis_binaries/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
We store the analysis binaries here.
2+

server/src/RescriptEditorSupport.ts

Lines changed: 118 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,156 @@
11
import { fileURLToPath } from "url";
22
import { RequestMessage } from "vscode-languageserver";
3-
import { CompletionItem } from "vscode-languageserver-protocol";
3+
import { CompletionItem, Hover, Location } from "vscode-languageserver-protocol";
44
import * as utils from "./utils";
55
import * as path from "path";
66
import { execFileSync } from "child_process";
77
import fs from "fs";
88

9-
let binaryPath = path.join(
9+
let binariesFolder = path.join(
1010
path.dirname(__dirname),
11-
process.platform,
12-
"rescript-editor-support.exe"
11+
"analysis_binaries"
12+
)
13+
14+
// For local development and CI tests
15+
let currentPlatformBinaryPath = path.join(
16+
binariesFolder,
17+
"current-platform.exe"
18+
);
19+
// Platform-specific production binaries manually downloaded from CI
20+
let productionBinaryPath = path.join(
21+
binariesFolder,
22+
process.platform + ".exe"
1323
);
1424

15-
export let binaryExists = fs.existsSync(binaryPath);
25+
let findBinary = () => {
26+
if (fs.existsSync(currentPlatformBinaryPath)) {
27+
return currentPlatformBinaryPath
28+
} else if (fs.existsSync(productionBinaryPath)) {
29+
return productionBinaryPath
30+
} else {
31+
return null
32+
}
33+
}
34+
35+
// export let binaryExists = fs.existsSync(binaryPath);
36+
37+
// let findExecutable = (uri: string) => {
38+
// let filePath = fileURLToPath(uri);
39+
// let projectRootPath = utils.findProjectRootOfFile(filePath);
40+
// if (projectRootPath == null || !binaryExists) {
41+
// return null;
42+
// } else {
43+
// return {
44+
// binaryPath: binaryPath,
45+
// filePath: filePath,
46+
// cwd: projectRootPath,
47+
// };
48+
// }
49+
// };
50+
51+
// type dumpCommandResult = {
52+
// hover?: string;
53+
// definition?: { uri?: string; range: any };
54+
// };
55+
// export function runDumpCommand(msg: RequestMessage): dumpCommandResult | null {
56+
// let executable = findExecutable(msg.params.textDocument.uri);
57+
// if (executable == null) {
58+
// return null;
59+
// }
60+
61+
// let command =
62+
// executable.filePath +
63+
// ":" +
64+
// msg.params.position.line +
65+
// ":" +
66+
// msg.params.position.character;
67+
68+
// try {
69+
// let stdout = execFileSync(executable.binaryPath, ["dump", command], {
70+
// cwd: executable.cwd,
71+
// });
72+
// let parsed = JSON.parse(stdout.toString());
73+
// if (parsed && parsed[0]) {
74+
// return parsed[0];
75+
// } else {
76+
// return null;
77+
// }
78+
// } catch (error) {
79+
// // TODO: @cristianoc any exception possible?
80+
// return null;
81+
// }
82+
// }
1683

17-
let findExecutable = (uri: string) => {
18-
let filePath = fileURLToPath(uri);
84+
export function runCompletionCommand(
85+
msg: RequestMessage,
86+
code: string
87+
): CompletionItem[] | null {
88+
let filePath = fileURLToPath(msg.params.textDocument.uri)
1989
let projectRootPath = utils.findProjectRootOfFile(filePath);
20-
if (projectRootPath == null || !binaryExists) {
90+
let binaryPath = findBinary();
91+
if (binaryPath == null || projectRootPath == null) {
2192
return null;
22-
} else {
23-
return {
24-
binaryPath: binaryPath,
25-
filePath: filePath,
26-
cwd: projectRootPath,
27-
};
2893
}
29-
};
94+
let tmpname = utils.createFileInTempDir();
95+
fs.writeFileSync(tmpname, code, { encoding: "utf-8" });
3096

31-
type dumpCommandResult = {
32-
hover?: string;
33-
definition?: { uri?: string; range: any };
34-
};
35-
export function runDumpCommand(msg: RequestMessage): dumpCommandResult | null {
36-
let executable = findExecutable(msg.params.textDocument.uri);
37-
if (executable == null) {
97+
try {
98+
let stdout = execFileSync(
99+
binaryPath,
100+
["complete", filePath, msg.params.position.line, msg.params.position.character, tmpname],
101+
{ cwd: projectRootPath }
102+
);
103+
return JSON.parse(stdout.toString());
104+
} catch (error) {
105+
// TODO: @cristianoc any exception possible?
38106
return null;
107+
} finally {
108+
fs.unlink(tmpname, () => null);
39109
}
110+
}
40111

41-
let command =
42-
executable.filePath +
43-
":" +
44-
msg.params.position.line +
45-
":" +
46-
msg.params.position.character;
112+
export function runHoverCommand(
113+
msg: RequestMessage,
114+
): Hover | null {
115+
let filePath = fileURLToPath(msg.params.textDocument.uri)
116+
let projectRootPath = utils.findProjectRootOfFile(filePath);
117+
let binaryPath = findBinary();
118+
if (binaryPath == null || projectRootPath == null) {
119+
return null;
120+
}
47121

48122
try {
49-
let stdout = execFileSync(executable.binaryPath, ["dump", command], {
50-
cwd: executable.cwd,
51-
});
52-
let parsed = JSON.parse(stdout.toString());
53-
if (parsed && parsed[0]) {
54-
return parsed[0];
55-
} else {
56-
return null;
57-
}
123+
let stdout = execFileSync(
124+
binaryPath,
125+
["hover", filePath, msg.params.position.line, msg.params.position.character],
126+
{ cwd: projectRootPath }
127+
);
128+
return JSON.parse(stdout.toString());
58129
} catch (error) {
59130
// TODO: @cristianoc any exception possible?
60131
return null;
61132
}
62133
}
63134

64-
// TODO: the result will never be null soon when the updated binary syncs
65-
export function runCompletionCommand(
135+
export function runDefinitionCommand(
66136
msg: RequestMessage,
67-
code: string
68-
): CompletionItem[] | null {
69-
let executable = findExecutable(msg.params.textDocument.uri);
70-
if (executable == null) {
137+
): Location | null {
138+
let filePath = fileURLToPath(msg.params.textDocument.uri)
139+
let projectRootPath = utils.findProjectRootOfFile(filePath);
140+
let binaryPath = findBinary();
141+
if (binaryPath == null || projectRootPath == null) {
71142
return null;
72143
}
73-
let tmpname = utils.createFileInTempDir();
74-
fs.writeFileSync(tmpname, code, { encoding: "utf-8" });
75-
76-
let command =
77-
executable.filePath +
78-
":" +
79-
msg.params.position.line +
80-
":" +
81-
msg.params.position.character;
82144

83145
try {
84146
let stdout = execFileSync(
85-
executable.binaryPath,
86-
["complete", command, tmpname],
87-
{ cwd: executable.cwd }
147+
binaryPath,
148+
["definition", filePath, msg.params.position.line, msg.params.position.character],
149+
{ cwd: projectRootPath }
88150
);
89-
let parsed = JSON.parse(stdout.toString());
90-
if (parsed && parsed[0]) {
91-
return parsed;
92-
} else {
93-
return null;
94-
}
151+
return JSON.parse(stdout.toString());
95152
} catch (error) {
96153
// TODO: @cristianoc any exception possible?
97154
return null;
98-
} finally {
99-
fs.unlink(tmpname, () => null);
100155
}
101156
}

0 commit comments

Comments
 (0)