Repository navigation
Experimental ReScript Language Server in OCaml #8425
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
cbf971e
acbfc57
ce6dd17
56d6afe
434c8fe
9767c9f
b1b4b04
d09d328
80e8218
efc77b3
ad0b764
5a36dd1
9276f9e
1c9f4b4
f81dcdb
56563c2
7d0a6e0
f0e8468
104bb77
555bb76
e8e3dc0
c0bdf8b
4e26483
dafb3d9
682137e
ee3f8ad
d26a86a
91f82e4
921ee2c
2d19cb8
b556990
6c1c18d
337066d
9b86e9d
b6566fd
350aaa7
0461d57
7ac8f90
3e1cde6
126f691
2bcd8dc
5127e6a
3f6d138
7a1f9db
f74e2c9
688f5cd
2616cc1
989b85d
1ea5304
c9f7f16
911cf85
967d34e
0853d3c
12d2e75
a4635e3
dc2d30f
d9308a1
5759740
a31d367
fe72544
71829e3
42f097a
aa66d0e
a6645f6
fe3e496
dddcf27
7d693f8
a0a9226
f0c9b00
e547876
7bda550
43869d9
d9dba17
6078f60
691c2fb
5ec4d65
2872ed5
f059445
fa21eec
434d5b8
0036ae7
763f61d
714af2c
9dc1bfc
1518254
5138750
113df9f
2889b5a
632dcec
223c421
def48a0
9ff490c
d633159
78c3e21
1e95aab
5808d26
e340e40
08b6557
c14de44
ee9331e
96505e1
3247c2d
3cb3190
66200a1
5a696e4
0efba12
207a05f
4c1d668
adeef92
eaca209
d2b939a
62aadc8
3d32ad6
e7e4edd
7ecb29e
dcbb246
9e18966
5e44b5a
b1128cd
ab13d92
2124bc0
0880539
b1d3224
c2b3660
eac2a24
7413dc4
0b6206e
983c968
6b53a89
592a731
e9a47cc
6d3d8a5
5e320a4
f2caebc
51be468
977c321
14fcdfd
4f1261e
0a6bc45
24e0e34
0f17da8
74bdab7
11f17cb
59b49ce
17d694e
ba2141e
7153a6e
e612509
a9e7508
cc126b8
3e2a095
d0d935c
97485ad
25c8ea8
7041f86
ba7b4c2
b4367d4
7ae1e3d
a0ea8d0
defa136
ed86dbb
ecd62e7
f010956
ef543ff
5be287b
b499a88
a6edb10
b7147d1
fec7da9
f2e3a7a
2152e00
93bec6c
406f62c
e440b15
2611be3
427f2db
6c444d4
2d50911
8827aee
9c6a69b
ea5c409
4e07c14
4f81def
4209bd4
16bd533
11ba488
e700b6b
2645b50
79fc35b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -64,10 +64,9 @@ jobs: | |
|
|
||
| # Verify that the compiler still builds with the oldest OCaml version we support. | ||
| # The build system's snapshot tests are skipped on this job; the | ||
| # first linux-x64 job runs them. OCaml 5.0 does not build with GCC 15 | ||
| # (C23 by default), so this job stays on Ubuntu 24.04. | ||
| # first linux-x64 job runs them. | ||
| - os: ubuntu-24.04 | ||
| ocaml_compiler: ocaml-variants.5.0.0+options,ocaml-option-static | ||
| ocaml_compiler: ocaml-variants.5.3.0+options,ocaml-option-static | ||
| node-target: linux-x64 | ||
| dune-profile: static | ||
|
|
||
|
|
@@ -95,6 +94,56 @@ jobs: | |
| if: runner.os == 'Linux' | ||
| uses: ./.github/actions/setup-linux-dependencies | ||
|
|
||
| # The static OCaml switch uses musl-gcc. linux-libc-dev installs Linux | ||
| # headers under /usr/include, but musl-gcc searches the musl include dir. | ||
| # Link the Linux headers into musl's include path so packages with C stubs | ||
| # such as uring can include <linux/...> headers. | ||
| - name: Make Linux headers visible to musl-gcc | ||
| if: runner.os == 'Linux' | ||
| run: | | ||
| set -eux | ||
|
|
||
| # Get the GNU multiarch triplet for the current machine. | ||
| # Examples: | ||
| # x86_64-linux-gnu | ||
| # aarch64-linux-gnu | ||
| GNU_MULTIARCH="$(gcc -print-multiarch)" | ||
|
|
||
| # Convert the GNU triplet into the musl include directory name. | ||
| # Examples: | ||
| # x86_64-linux-gnu -> x86_64-linux-musl | ||
| # aarch64-linux-gnu -> aarch64-linux-musl | ||
| MUSL_MULTIARCH="${GNU_MULTIARCH%-gnu}-musl" | ||
|
|
||
| # musl-gcc searches this include directory. | ||
| MUSL_INCLUDE="/usr/include/${MUSL_MULTIARCH}" | ||
|
|
||
| # Linux arch-specific asm headers are installed here by linux-libc-dev. | ||
| GNU_ASM="/usr/include/${GNU_MULTIARCH}/asm" | ||
|
|
||
| # Ensure the musl include directory exists. | ||
| sudo mkdir -p "$MUSL_INCLUDE" | ||
|
|
||
| # Remove old paths first. | ||
| # This avoids silently keeping broken/stale symlinks from previous runs. | ||
| sudo rm -rf "$MUSL_INCLUDE/linux" | ||
| sudo rm -rf "$MUSL_INCLUDE/asm" | ||
| sudo rm -rf "$MUSL_INCLUDE/asm-generic" | ||
|
|
||
| # Expose Linux UAPI headers to musl-gcc. | ||
| # This fixes packages that include headers like <linux/swab.h>. | ||
| sudo ln -s /usr/include/linux "$MUSL_INCLUDE/linux" | ||
|
|
||
| # Expose architecture-specific asm headers to musl-gcc. | ||
| sudo ln -s "$GNU_ASM" "$MUSL_INCLUDE/asm" | ||
|
|
||
| # Expose generic asm headers used by many Linux headers. | ||
| sudo ln -s /usr/include/asm-generic "$MUSL_INCLUDE/asm-generic" | ||
|
|
||
| # Smoke test: fail early if musl-gcc still cannot find Linux headers. | ||
| echo '#include <linux/swab.h>' > /tmp/test.c | ||
| musl-gcc -c /tmp/test.c -o /tmp/test.o | ||
|
|
||
| - name: Setup OCaml ${{ matrix.ocaml_compiler }} | ||
| id: setup_ocaml | ||
| uses: ./.github/actions/setup-ocaml | ||
|
|
@@ -221,7 +270,7 @@ jobs: | |
| shell: bash | ||
|
|
||
| - name: Run rewatch snapshot tests | ||
| if: ${{ !contains(matrix.ocaml_compiler, '5.0.0') }} | ||
| if: ${{ !contains(matrix.ocaml_compiler, '5.3.0') }} | ||
| timeout-minutes: 20 | ||
| run: | | ||
| . rewatch-ocaml/tests/process_watchdog.sh | ||
|
|
@@ -245,7 +294,7 @@ jobs: | |
| shell: bash | ||
|
|
||
| - name: Run rewatch verbose output tests | ||
| if: ${{ !contains(matrix.ocaml_compiler, '5.0.0') }} | ||
| if: ${{ !contains(matrix.ocaml_compiler, '5.3.0') }} | ||
| timeout-minutes: 10 | ||
| run: | | ||
| bash rewatch-ocaml/tests/check_verbose_output.sh \ | ||
|
|
@@ -487,7 +536,7 @@ jobs: | |
| uses: actions/checkout@v7 | ||
| - name: Run make in dev container | ||
| uses: devcontainers/[email protected] | ||
| with: | ||
| with: | ||
| push: never | ||
| runCmd: make | ||
|
|
||
|
|
||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change makes analysis prefer the runtime installed in the project over the compiler-local runtime. Previously, resolving The resolver now searches the project and its ancestor directories first, including the This is not a complete Node/Deno/pnpm module resolver; it extends the existing package-directory lookup. The explicit Module resolution searches each directory and its ancestors for:
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,18 +1,51 @@ | ||
| let ( /+ ) = Filename.concat | ||
|
|
||
| let rec resolve_node_module_path ~start_path name = | ||
| if name = "@rescript/runtime" then | ||
| (* Hack: we need a reliable way to resolve modules in monorepos. *) | ||
| Some (Runtime_package.get_path ()) | ||
| let package_path name = | ||
| let scope = Filename.dirname name in | ||
| let name = Filename.basename name in | ||
| match scope.[0] with | ||
| | '@' -> scope /+ name | ||
| | _ -> name | ||
|
|
||
| let resolve_deno_pnpm ~start_path name = | ||
| let create_path folder = | ||
| start_path /+ "node_modules" /+ folder /+ "node_modules" | ||
| /+ package_path name | ||
| in | ||
| let deno = create_path ".deno" in | ||
| let pnpm = create_path ".pnpm" in | ||
| match (Files.if_exists deno, Files.if_exists pnpm) with | ||
| | Some deno, None -> Some deno | ||
| | None, Some pnpm -> Some pnpm | ||
| | Some deno, Some pnpm -> | ||
| failwith | ||
| (Printf.sprintf | ||
| "Failed to resolve path for %s. Conflict: two directories found. one \ | ||
| for Deno (%s) and one for pnpm (%s)." | ||
| name deno pnpm) | ||
| | _ -> None | ||
|
|
||
| let rec resolve_from_node_modules ~start_path name = | ||
| let path = start_path /+ "node_modules" /+ package_path name in | ||
| if Files.exists path then Some path | ||
| else | ||
| let scope = Filename.dirname name in | ||
| let name = Filename.basename name in | ||
| let name = | ||
| match scope.[0] with | ||
| | '@' -> scope /+ name | ||
| | _ -> name | ||
| in | ||
| let path = start_path /+ "node_modules" /+ name in | ||
| if Files.exists path then Some path | ||
| else if Filename.dirname start_path = start_path then None | ||
| else resolve_node_module_path ~start_path:(Filename.dirname start_path) name | ||
| match resolve_deno_pnpm ~start_path name with | ||
| | Some p -> Some p | ||
| | None -> | ||
| if Filename.dirname start_path = start_path then None | ||
| else | ||
| resolve_from_node_modules ~start_path:(Filename.dirname start_path) name | ||
|
|
||
| let resolve_node_module_path ?(fallback_to_runtime_package = true) ~start_path | ||
| name = | ||
| match resolve_from_node_modules ~start_path name with | ||
| | Some path -> Some path | ||
| | None | ||
| when fallback_to_runtime_package | ||
| && name = Runtime_package.name | ||
| && Files.exists (Runtime_package.get_path ()) -> | ||
| (* Compiler-local fallback for development builds where the runtime package | ||
| is not installed in the target workspace. Real project installs must win | ||
| so LSP definition locations point at the workspace's node_modules. *) | ||
| Some (Runtime_package.get_path ()) | ||
| | None -> None |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| - Add an experimental ReScript language server bundled with the compiler, available | ||
| through `rescript lsp --stdio`. It reuses compiler analysis for hover, | ||
| completion, navigation, rename, diagnostics, formatting, and code actions. |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CI compatibility job now uses OCaml 5.3 instead of 5.0 because the current test dependencies cannot be resolved on 5.0.
The compiler requires
ppxlib >= 0.38.0. The language server’sppx_expectdependency pulls in Jane Street PPXs whose versions compatible with thatppxlibrequire OCaml 5.3 or newer.