Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
7e32d1c
V3 answers, persistent compilers, rename, import completion and more
MARCROCK22 Sep 24, 2026
6e4babd
tests: rename asks V3 first, as VLS does
MARCROCK22 Sep 24, 2026
37b1750
rename: refuse interface members and the names they share
MARCROCK22 Sep 24, 2026
98db7ee
V3: ask about a test file as a program of its own
MARCROCK22 Sep 24, 2026
266e29a
rename: ask nothing prepareRename asked, keep the program's server
MARCROCK22 Sep 24, 2026
baef125
V3: write a buffer into the copy only, never through its links
MARCROCK22 Sep 25, 2026
3a98f3a
V3: a copy of its own for each editor and each program
MARCROCK22 Sep 25, 2026
bd4dfb6
V3: take again a module file replaced on disk
MARCROCK22 Sep 26, 2026
1ad2bac
hover: show a sum type declaration written over several lines
MARCROCK22 Sep 26, 2026
23bdba5
hover: a function shows its declaration where it is declared and used
MARCROCK22 Sep 26, 2026
30bb87b
hover: a local is never its statement nor another declaration's docum…
MARCROCK22 Sep 26, 2026
58bfeec
tests: rename a local passed to a method named like an array one
MARCROCK22 Sep 26, 2026
257e15a
hover: show the `Example:` lines of a doc comment as V code
MARCROCK22 Sep 26, 2026
58ae380
diagnostics: a question does not wait for the check of another server
MARCROCK22 Sep 26, 2026
f74e236
diagnostics: a check starts as soon as a change arrives
MARCROCK22 Sep 26, 2026
4e1e276
requests: one that asks no compiler does not wait for one that does
MARCROCK22 Sep 26, 2026
b1d9209
diagnostics: the servers of the diagnostics prepare builtin once
MARCROCK22 Sep 27, 2026
cb63408
questions: the servers of the questions prepare builtin too
MARCROCK22 Sep 27, 2026
d58b41c
diagnostics: a check and the questions about a program share its check
MARCROCK22 Sep 27, 2026
9de562b
diagnostics: publish the errors a check finds before its slow end
MARCROCK22 Sep 27, 2026
69d6713
hover: ask the compiler first about a value that a `$if`, `is` or `ma…
MARCROCK22 Sep 27, 2026
2687a54
index: a sum type written on several lines is a sum type
MARCROCK22 Sep 27, 2026
cb8c0fc
rename: a type parameter with a constraint is a type parameter
MARCROCK22 Sep 27, 2026
16028ba
rename: refuse a new name that changes what the program does
MARCROCK22 Sep 27, 2026
46ad412
diagnostics: show a redefinition on each declaration it names
MARCROCK22 Sep 27, 2026
bae3d3d
all: run v fmt -w
MARCROCK22 Sep 28, 2026
67a85ef
Merge vls#524 (vls-v3 bae3d3d, `v fmt -w`) into the experiment
MARCROCK22 Sep 28, 2026
76e2314
hover: a local whose value the index cannot type asks the compiler
MARCROCK22 Sep 29, 2026
b94866d
builtins: recover, which V added to stop a panic from a defer block
MARCROCK22 Sep 29, 2026
5adb481
hover: a struct literal that a value goes on from is not the type of …
MARCROCK22 Sep 30, 2026
67386d6
builtins: the types of V now: i128 and u128, and no byte
MARCROCK22 Sep 30, 2026
5a88bfc
rename: refuse a new name that changes what the program does
MARCROCK22 Sep 30, 2026
fd484be
rename: rename the variants of the other platforms too
MARCROCK22 Sep 30, 2026
8f26a78
inlay hints: without file watchers, a change on disk renews them
MARCROCK22 Sep 30, 2026
d04712f
diagnostics: a read of a server that keeps writing ends in time
MARCROCK22 Sep 30, 2026
76a071d
Merge vls#524 (vls-v3 d04712f) into the experiment: the fixes of the …
MARCROCK22 Sep 30, 2026
ee6caad
index: the files of a module are the ones V3 builds
MARCROCK22 Oct 1, 2026
cd0d18a
tests: the vlib module offered for JSON is json2
MARCROCK22 Oct 1, 2026
5e66fea
all: run v fmt -w
MARCROCK22 Oct 1, 2026
6b763a3
Refuse unvalidated renames and match platform members by owning type
medvednikov Oct 5, 2026
ce24077
Bound disk traversal when refreshing inlay hints without watchers
medvednikov Oct 5, 2026
5205cee
Merge remote-tracking branch 'origin/master' into codex/fix-pr525
medvednikov Oct 5, 2026
57abb57
Avoid filesystem-root hint scans and bound non-source traversal
medvednikov Oct 5, 2026
74b65e9
Merge remote-tracking branch 'origin/master' into codex/fix-pr525
medvednikov Oct 5, 2026
c709ecd
Probe compiler support before testing constrained generic renames
medvednikov Oct 5, 2026
7d24165
fix: retire compiler servers and join client readers on shutdown
medvednikov Oct 5, 2026
706a863
Report a closed compiler pool as unavailable rename validation
medvednikov Oct 5, 2026
cd50c35
Store the traversal counter in an explicit mutable budget
medvednikov Oct 5, 2026
5f7eabb
Detect same-size disk edits when refreshing cached inlay hints
medvednikov Oct 5, 2026
c1e14a0
Accept compiler builder duplicate-function diagnostics in rename tests
medvednikov Oct 5, 2026
6d45842
Reject capture in unresolved inactive rename uses
medvednikov Oct 5, 2026
bd2a1cf
fix: join compiler workers and reap them safely on exit
medvednikov Oct 5, 2026
880d371
Keep diagnostics reader and cache copies compatible with V1
medvednikov Oct 5, 2026
8c9763a
fix: validate compiler child PIDs before cancellation
medvednikov Oct 5, 2026
5dfbfe1
Mark the joined reader borrow as safe for V1 stack checks
medvednikov Oct 5, 2026
c82996e
Merge remote-tracking branch 'origin/master' into codex/fix-pr525
medvednikov Oct 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 55 additions & 9 deletions diagnostics_scheduler.v
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import os
import sync
import time

// Wait until typing pauses before starting a check. Completion requests can then
// overtake diagnostics instead of sitting behind a compile on every key. A check
// answered by a diagnostics server takes a fraction of a one-shot run, so the
// pause can be short, and the worker looks for ready jobs often.
const diagnostics_debounce_ms = 25
// A check starts as soon as a change arrives: a newer change stops the check
// that runs, whose answer would be stale, and a question goes to a server of
// its own, which a check does not hold (see DiagnosticsServer.busy). The worker
// looks for ready jobs often while one waits for its time.
const diagnostics_debounce_ms = 0
const diagnostics_worker_poll = 5 * time.millisecond

struct DiagnosticsJob {
Expand Down Expand Up @@ -60,8 +60,14 @@ mut:
// The open files the last check of each program answered for, by program
// directory.
program_members map[string][]string
// The diagnostics servers outlive the worker, which exits when idle.
servers &DiagnosticsServerPool = new_diagnostics_server_pool()
// The diagnostics servers outlive the worker, which exits when idle. Each
// one parses and collects builtin once, and they answer the questions about
// the programs they check too, from the same checks (see ProgramCopy).
servers &DiagnosticsServerPool = new_shared_diagnostics_server_pool()
// A paused scheduler starts no worker and keeps its jobs pending: a test
// can look at the queue a change leaves, which a check started at once
// would empty.
paused bool
}

fn new_diagnostics_scheduler() &DiagnosticsScheduler {
Expand Down Expand Up @@ -167,6 +173,9 @@ fn (mut scheduler DiagnosticsScheduler) enqueue(job DiagnosticsJob) bool {
return false
}
scheduler.pending_jobs[job.uri] = job
if scheduler.paused {
return false
}
should_start := !scheduler.worker_running
if should_start {
scheduler.worker_started = true
Expand Down Expand Up @@ -233,7 +242,8 @@ fn (mut scheduler DiagnosticsScheduler) cancel_all() {
scheduler.mutex.unlock()
}

// stop_and_wait cancels the session check and joins its compiler work.
// stop_and_wait cancels the session's last check and waits for its compiler,
// files and transport borrower to be released before the session can return.
fn (mut scheduler DiagnosticsScheduler) stop_and_wait() {
scheduler.mutex.lock()
scheduler.stopped = true
Expand Down Expand Up @@ -383,11 +393,14 @@ fn run_diagnostics_worker(mut scheduler DiagnosticsScheduler) {
done.close()
}
for {
time.sleep(diagnostics_worker_poll)
jobs, should_stop := scheduler.take_ready_jobs(time.now().unix_milli())
if should_stop {
return
}
if jobs.len == 0 {
time.sleep(diagnostics_worker_poll)
continue
}
for job in jobs {
run_diagnostics_job(mut scheduler, job)
scheduler.finish(job)
Expand Down Expand Up @@ -420,11 +433,17 @@ fn run_diagnostics_job(mut scheduler DiagnosticsScheduler, job DiagnosticsJob) {
write_mutex: job.write_mutex
tcp_conn: job.tcp_conn
diagnostics_servers: scheduler.servers
v3_query_servers: scheduler.servers
// A change that arrives while this check runs stops it: its answer would
// be stale, and the newer check can start at once.
diagnostics_cancelled: fn [mut scheduler, job] () bool {
return !scheduler.is_job_current(job)
}
// The errors a check found before its slow end, the instances of generic
// functions above all, are shown at once; its full answer replaces them.
diagnostics_partial: fn [mut scheduler, job] (uri string, found CheckErrors) {
scheduler.publish_partial(job, uri, found)
}
}
notification := worker.build_diagnostics_notification(job.uri, job.content)
if !scheduler.publish_if_current(mut worker, job, notification) {
Expand Down Expand Up @@ -452,6 +471,33 @@ fn run_diagnostics_job(mut scheduler DiagnosticsScheduler, job DiagnosticsJob) {
}
}

// publish_partial publishes the diagnostics a check of `job` found before its
// end, for the file at `uri` and the other open files of its program, while the
// job is current.
fn (mut scheduler DiagnosticsScheduler) publish_partial(job DiagnosticsJob, uri string, found CheckErrors) {
mut versions := map[string]i64{}
if version := job.version {
versions[job.uri] = version
}
mut writer := App{
open_files: job.open_files
open_files_versions: versions
position_encoding: job.position_encoding
write_mutex: job.write_mutex
tcp_conn: job.tcp_conn
diagnostics_enabled: true
}
if uri == job.uri {
scheduler.publish_if_current(mut writer, job, writer.diagnostics_notification_for(uri,
job.content, found.file))
}
for other_uri, other_errors in found.program {
other_content := job.open_files[other_uri] or { continue }
scheduler.publish_if_current(mut writer, job, writer.diagnostics_notification_for(other_uri,
other_content, other_errors))
}
}

// swap_program_members records `members`, the open files a check of the program
// in `program_dir` answered for, and returns those the previous check of that
// program answered for and this one does not.
Expand Down
Loading