Skip to content

Enhance diagnostics handling and server communication - #3

Merged
cesp99 merged 13 commits into
mainfrom
dev
Aug 23, 2026
Merged

Enhance diagnostics handling and server communication#3
cesp99 merged 13 commits into
mainfrom
dev

Conversation

@cesp99

Copy link
Copy Markdown
Owner

Summary

This is a large feature branch that brings the editor closer to a real LSP-powered code editor, implements a diagnostics panel following Zed's layout, adds server progress reporting in the status bar, fixes a proot crash on multi-threaded execve(2), and bumps to v0.0.4.

Key changes:

Rust (core/)

  • Editor request bridge: References, code actions (with resolve), rename, and formatting requests on the LSP engine. Actions and workspace edits are held in the engine and applied through a two-step applyPendingEdit flow, so the UI never holds large JSON blobs across JNI.
  • $/progress tracking: Servers' own progress reports ("indexing (45%)") are collected per-token and surfaced in the status bar.
  • File-watcher notifications: The project's file watcher now forwards didChangeWatchedFiles to servers that registered glob watchers, minus temp staging files.
  • Diagnostic rows: A dedicated lspDiagnosticRows endpoint serializes every diagnostic with its message, for a diagnostics panel — separate from the lightweight count the status bar polls.
  • Server startup: Opening a folder now starts servers for every language in the scanned tree, not just for files already open.
  • Project root canonicalization: /data/user/0/… vs /data/data/… symlink mismatch fixed.

Kotlin (app/)

  • Diagnostics panel (DiagnosticsPane.kt, DiagnosticsRows.kt): A full diagnostics view as a dock tab, mirroring Zed's diagnostics editor. Shows files with their diagnostic rows; tapping a row opens the file at the problem. Replaces the status bar's click-through-to-next-diagnostic behavior.
  • LspActions.kt: Quick-fix, references, rename, and formatting wired to the editor via the request bridge. Keyboard and touch access; rename gets a dialog (RenameSymbol.kt).
  • WorkspaceEditActions.kt: Apply a workspace edit (rename, formatting, code action) back into open buffers, with an undo checkpoint.
  • $/progress in StatusBar.kt: The status bar's note slot now shows the first busy server's progress or the first "starting…" server.
  • Server startup on folder open (LanguageServers.kt): lspVersion polling starts servers for the tree's languages without waiting.

proot

  • Thread-execve patch: execve(2) from a non-leader thread (Go's toolchain switch) no longer crashes. The kernel gives the exec'ing thread the leader's tid; the patch adopts the former thread's tracee state at PTRACE_EVENT_EXEC. Rebuilt libproot_exec.so for both ABIs.

Version

  • 0.0.3 → 0.0.4 (build.gradle.kts).

Testing

./gradlew assembleFullDebug assemblePlayDebug
./gradlew :app:testFullDebugUnitTest
cd core && cargo test&& cargo clippy

Verified on a physical device:

  • Folder open starts rust-analyzer / gopls; status bar shows "starting…" → "indexing (45%)".
  • Diagnostics panel populates after servers publish; tapping a row opens the file at the correct position.
  • Quick-fix applies in place; rename dialog produces a workspace edit across files; formatting runs on the whole document.
  • Go workspace with toolchain directive: no SIGSEGV after proot patch.

Checklist

  • Editor logic stays in Rust (core/), UI in Kotlin (app/); the JNI boundary grew together (CoreBridge.ktjni-bridge/src/lib.rslsp.rs)
  • Interactive features work by touch and keyboard and mouse; docs/SHORTCUTS.md — no new chord; the diagnostics tab opens from the status bar summary (same as Zed)
  • Nothing blocking on the main thread, no unrequested network or telemetry, no private info committed
  • Both editions considered: full (Debian userland, proot) and play (no proot changes needed, just the Rust engine)

cesp99and others added 13 commits August 23, 2026 16:40
The root kept the caller's spelling while buffers, publishes and the
watcher were canonicalized — on Android /data/user/0/<pkg> is a symlink
to /data/data/<pkg>, so a server was rooted at a URI none of its
documents were under and treated every file as a lone one.
lspDiagnosticRows is the diagnostics panel's read: the counts stay on
the status bar's lspDiagnostics, the messages live here.
Co-Authored-By: Spettro <spettro@eyed.to>
Zed's project diagnostics, in the dock-panel form search already took:
tapping the error and warning counts deploys it, files fold like search
results, an issue row opens its file with the caret on the problem, and
ToggleWarnings narrows it to errors. The list reads lspDiagnosticRows,
so it is project-wide and outlives tabs.
Co-Authored-By: Spettro <spettro@eyed.to>
client/registerCapability, workspace/configuration and
workDoneProgress/create all came back "method not found", which is how
rust-analyzer's file watching and more than one server's settings load
quietly died. The emptiest legal replies tell a server to proceed with
its defaults.
Co-Authored-By: Spettro <spettro@eyed.to>
A watched-files registration now lands in a per-server table of glob
matchers, and the worktree's subscription forwards matching disk
changes as workspace/didChangeWatchedFiles — how rust-analyzer hears
about a Cargo.toml edited in the terminal. The initial scan and the
save path's .conquest-tmp staging files stay home.
Co-Authored-By: Spettro <spettro@eyed.to>
Four new request kinds on the one polling contract. References answer
with definition's targets plus each line's text. Code actions come back
as a titled list while the actions wait engine-side; picking one
resolves it through codeAction/resolve and readies its edit. Rename and
formatting settle with an edit summary. lspApplyPendingEdit then lands
whatever is waiting: open buffers through the normal edit path — one
undo step, didChange and all — and closed files atomically on disk.
Bare-command actions and file create/rename/delete are refused with a
sentence rather than half-applied.
Co-Authored-By: Spettro <spettro@eyed.to>
Ctrl+. (and the action row's "fix") lists the code actions at the
caret and applies the picked one; Shift+F12 lists references with their
lines, jumping through the definition plumbing; F2 raises a rename
dialog in GoToLine's shape that changes nothing until the whole edit
has landed; Ctrl+Shift+I formats the document. Every applied edit comes
back as a receipt, and the workspace resyncs each editor the engine
edited underneath — the refreshLineCount gap a reload already had.
Co-Authored-By: Spettro <spettro@eyed.to>
Each progress token's begin/report/end lands on the server's slot, and
lspServers now carries one line of it — rust-analyzer's "indexing
(45%)" sits in the note slot while the server works, instead of an
unexplained silence. Progress also feeds the activity clock, so the
idle sweep cannot stop a server mid-reindex.
Co-Authored-By: Spettro <spettro@eyed.to>
The poll's wanted set now includes the languages of the project's own
tree, walked from the mirrored worktree and cached against its version
— a folder of .rs files starts rust-analyzer the moment it opens, no
tab required, and its workspace-wide check fills the diagnostics panel
asynchronously. Tree-started servers are judged by the silence rule
rather than the no-documents one (their working state has no tabs), a
contested budget still prefers a server actually holding a tab, and a
swept tree-want rests until activity brings it back — the same loop
dormancy breaks for documents.
Co-Authored-By: Spettro <spettro@eyed.to>
Installing gopls alone leaves it initialized and useless: it loads the
workspace by running `go list`, and without golang-go every file gets
"No active builds contain <file>". The cargo and pyflakes lesson, a
third time — the table now names the toolchain beside the server, and
the apt sentences name both packages.
Co-Authored-By: Spettro <spettro@eyed.to>
The status bar's note slot now falls through blocked-server notes to
$/progress ("gopls: Setting up workspace…") and then to a plain
"<name> is starting…", so folder-open indexing is visible instead of
silent. window/showMessage and window/logMessage land in the log with
the server's name on them — gopls explains its failures there, and
before this they went nowhere.
Co-Authored-By: Spettro <spettro@eyed.to>
The kernel gives the exec'ing thread the leader's tid before
PTRACE_EVENT_EXEC, so proot's per-tid execve state — the load info,
the saved registers whose ORIGINAL sysnum routes the sysexit stage,
the PTRACE_SYSCALL restart it needs — was stranded on a tracee whose
tid no longer exists. The loader then ran with no load script and the
new program died with SIGSEGV. Go's toolchain switch execs from a
worker thread and hit this every time: a go.mod asking for a newer Go
than Debian's turned every `go` command into "Segmentation fault",
and gopls's `go list` with it ("Error loading workspace folders").
The patch adopts the former thread's state at PTRACE_EVENT_EXEC using
PTRACE_GETEVENTMSG, which has named the old tid since Linux 3.0.
Verified on the Fold: `go version` in a go-1.26 module switches to
the downloaded go1.26.1 and answers, `go list ./...` lists every
package, and gopls loads the workspace it could not before.
Co-Authored-By: Spettro <spettro@eyed.to>
diagnostics::Deploy puts Zed's diagnostics editor into the active pane
as an item, beside the files — the translation the git graph already
made here. The status bar's summary now opens (or re-selects) a
Diagnostics tab; a row still opens its file with the caret on the
problem, now as a sibling tab. The dock panel, its placement default
and its slot in the panel enum are gone.
Co-Authored-By: Spettro <spettro@eyed.to>
Co-Authored-By: Spettro <spettro@eyed.to>
@cesp99
cesp99 merged commit 707e4dc into mainAug 23, 2026
2 checks passed
Sign up for freeto 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.

1 participant

@cesp99