Skip to content

Refactor analysis to decouple I/O from core logic#8426

Open
aspeddro wants to merge 5 commits into
rescript-lang:masterfrom
aspeddro:refactor-analysis-io
Open

Refactor analysis to decouple I/O from core logic#8426
aspeddro wants to merge 5 commits into
rescript-lang:masterfrom
aspeddro:refactor-analysis-io

Conversation

@aspeddro
Copy link
Copy Markdown
Contributor

@aspeddro aspeddro commented May 16, 2026

Splits Commands.ml into a pure layer that returns OCaml values (option, list, typed records like Protocol.hover,
Protocol.signatureHelp, Protocol.completionItem) and a new analysis/src/Cli.ml that does the stringify-and-print step. analysis/bin/main.ml now dispatches to Cli.*, while the LSP server consumes Commands.* directly.

Makes the parsers accept source strings: res_driver gains parse_interface_from_source alongside the existing parse_implementation_from_source

Cherry-pick of #8425

Splits `Commands.ml` into a pure layer that returns OCaml values
(option, list, typed records like Protocol.hover,
Protocol.signatureHelp, Protocol.completionItem) and a new
`analysis/src/Cli.ml` that does the stringify-and-print step.
`analysis/bin/main.ml` now dispatches to `Cli.*`, while the LSP server
consumes `Commands.*` directly.

Makes the parsers accept source strings: `res_driver` gains
`parse_interface_from_source` alongside the existing
`parse_implementation_from_source`
Comment on lines 76 to +83
let emit e =
let sortedTokens =
e.tokens
|> List.sort (fun (l1, c1, _, _) (l2, c2, _, _) ->
if l1 = l2 then compare c1 c2 else compare l1 l2)
in
let buf = Buffer.create 1 in
sortedTokens |> List.iter (fun t -> e |> emitToken buf t);
let arrays = sortedTokens |> List.filter_map (fun t -> e |> emitToken t) in
Array.concat arrays
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread analysis/src/Commands.ml
Comment on lines -293 to -299
let fields =
[("range", Some (Protocol.stringifyRange range))]
@
match placeholderOpt with
| None -> []
| Some s -> [("placeholder", Some (Protocol.wrapInQuotes s))]
in
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this was incorrect. Prepare rename should return Range | { range: Range, placeholder: string } | { defaultBehavior: boolean } | null (https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_prepareRename)

placeholderOpt is an option, so if it's None, the placeholder field doesn't exist; however, { range: Range, placeholder: string } is expected.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 16, 2026

Open in StackBlitz

rescript

npm i https://pkg.pr.new/rescript@8426

@rescript/darwin-arm64

npm i https://pkg.pr.new/@rescript/darwin-arm64@8426

@rescript/darwin-x64

npm i https://pkg.pr.new/@rescript/darwin-x64@8426

@rescript/linux-arm64

npm i https://pkg.pr.new/@rescript/linux-arm64@8426

@rescript/linux-x64

npm i https://pkg.pr.new/@rescript/linux-x64@8426

@rescript/runtime

npm i https://pkg.pr.new/@rescript/runtime@8426

@rescript/win32-x64

npm i https://pkg.pr.new/@rescript/win32-x64@8426

commit: 7ccb7ec

@aspeddro aspeddro marked this pull request as ready for review May 16, 2026 03:58
@fhammerschmidt fhammerschmidt requested a review from cristianoc May 16, 2026 07:58
@fhammerschmidt
Copy link
Copy Markdown
Member

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ccb7ecb9d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread analysis/src/Commands.ml Outdated
Comment on lines +254 to +257
let max = String.length source in
let range =
Protocol.
{start = {line = 0; character = 0}; end_ = {line = max; character = max}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use document line range for formatting edits

Commands.format now returns a TextEdit whose end position is built from String.length source for both line and character, but those fields are line/column coordinates, not byte offsets. For multi-line inputs this produces an out-of-document range, and strict LSP clients can reject or misapply the formatting edit instead of replacing the whole file. Compute the end position from the actual last line and its column (or an explicitly valid full-document range) before returning the edit.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 0c757c6

Comment on lines +145 to +146
Res_driver.print_implementation_from_source =
(fun ~width:_ ~source ~comments:_ _ -> dump_tokens source);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Tokenize source text in from_source debug printer

The new print_implementation_from_source hook forwards source to dump_tokens, but dump_tokens interprets its argument as a filesystem path and calls open_in on it. Any caller that uses the new *_from_source print API with in-memory source will fail by trying to open a file named after the source contents and then exiting. This path should scan the provided source string directly instead of routing through filename-based I/O.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in f97058a

aspeddro added 2 commits May 16, 2026 09:54
The previous implementation used the source byte length as both line and
character values for the end of the format range, which was incorrect.
Replace it with a helper that computes the actual final line index and
character offset by splitting on newlines.

Signed-Off-By: Your Name <email>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants