mt-lang 0.3.40 → 0.3.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/core/module_loader.rb +41 -6
- data/lib/milk_tea/core/types/registry.rb +14 -2
- data/lib/milk_tea/lsp/server/code_actions.rb +13 -3
- data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +56 -12
- data/lib/milk_tea/lsp/server/text_documents.rb +18 -2
- data/lib/milk_tea/lsp/workspace/caches.rb +28 -1
- data/lib/milk_tea/lsp/workspace/dependency_graph.rb +31 -0
- data/lib/milk_tea/lsp/workspace/store.rb +7 -1
- data/lib/milk_tea/lsp/workspace.rb +6 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 91b5015b218da9925b56895b551063fca825ca776fc336fe898ef17e332aae4e
|
|
4
|
+
data.tar.gz: 46e4a2da80edfb7c64fc847ee10844c9f5d36572df35105ab6ed51e2455d347a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0c1dcedaf98ef374c9dd21cded75f8512c755a63e4a3a155e494d9edf098b2d53da3b258edab5d63066a2a9eaa3c2a3883aa69241608509085caf398c1edecc1
|
|
7
|
+
data.tar.gz: a427c7ad0f2475b7dc5cccadcb6cc143ab195f906b7b9b13407a7e754043fd8550495c7dc750f5f27c92e2eca13477d9f6697650bddd515403526812b1dac06b
|
data/lib/milk_tea/base.rb
CHANGED
|
@@ -158,7 +158,30 @@ module MilkTea
|
|
|
158
158
|
|
|
159
159
|
def load_file(path)
|
|
160
160
|
resolved_path = self.class.resolve_source_path(path, platform: @platform, error_class: ModuleLoadError)
|
|
161
|
-
@ast_cache[resolved_path] ||=
|
|
161
|
+
@ast_cache[resolved_path] ||= cached_or_parse_file(resolved_path)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Parse +resolved_path+, reusing the shared-cache parsed AST when the source
|
|
165
|
+
# is disk-backed and unchanged. ASTs are immutable Data, so sharing them
|
|
166
|
+
# across loaders (and worker threads) is safe; node_ids are assigned at
|
|
167
|
+
# parse time and analyses keep their own per-node result hashes. Source
|
|
168
|
+
# files covered by source_overrides are always re-parsed so live editor
|
|
169
|
+
# buffers win.
|
|
170
|
+
def cached_or_parse_file(resolved_path)
|
|
171
|
+
if use_shared_cache_for?(resolved_path)
|
|
172
|
+
mtime = source_mtime(resolved_path)
|
|
173
|
+
if mtime
|
|
174
|
+
entry = @shared_cache[[:ast, resolved_path]]
|
|
175
|
+
return entry[:ast] if entry && entry[:mtime] == mtime
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
ast = parse_file(resolved_path)
|
|
180
|
+
if use_shared_cache_for?(resolved_path)
|
|
181
|
+
mtime = source_mtime(resolved_path)
|
|
182
|
+
@shared_cache[[:ast, resolved_path]] = { mtime:, ast: } if mtime
|
|
183
|
+
end
|
|
184
|
+
ast
|
|
162
185
|
end
|
|
163
186
|
|
|
164
187
|
def check_file(path)
|
|
@@ -166,7 +189,14 @@ module MilkTea
|
|
|
166
189
|
end
|
|
167
190
|
|
|
168
191
|
def with_check_context(path, &block)
|
|
169
|
-
Types::Registry.reset!
|
|
192
|
+
# NOTE: Types::Registry.reset! is intentionally NOT called here. The LSP
|
|
193
|
+
# runs check_program_collecting concurrently on diagnostics workers and
|
|
194
|
+
# the request thread; a reset would clear the global intern pool while
|
|
195
|
+
# another thread is mid-analysis, causing threads to intern duplicate type
|
|
196
|
+
# instances. Interning is idempotent and the pool stays small (bounded by
|
|
197
|
+
# the type universe), so it is safe to let it grow for the process
|
|
198
|
+
# lifetime. Single-threaded entry points that want a clean slate (Build#build,
|
|
199
|
+
# server re-initialize) reset explicitly.
|
|
170
200
|
requested_path = File.expand_path(path)
|
|
171
201
|
previous_platform = @platform
|
|
172
202
|
@platform ||= self.class.platform_suffix_for_path(requested_path)
|
|
@@ -541,7 +571,7 @@ module MilkTea
|
|
|
541
571
|
return [resolved_path, nil, @analysis_cache[resolved_path]] if @analysis_cache.key?(resolved_path)
|
|
542
572
|
return [resolved_path, nil, extra_cache[resolved_path]] if extra_cache&.key?(resolved_path)
|
|
543
573
|
|
|
544
|
-
if
|
|
574
|
+
if use_shared_cache_for?(resolved_path)
|
|
545
575
|
entry = @shared_cache[resolved_path]
|
|
546
576
|
if entry
|
|
547
577
|
mtime = source_mtime(resolved_path)
|
|
@@ -566,7 +596,7 @@ module MilkTea
|
|
|
566
596
|
end
|
|
567
597
|
|
|
568
598
|
def update_shared_cache(resolved_path, analysis)
|
|
569
|
-
return unless
|
|
599
|
+
return unless use_shared_cache_for?(resolved_path)
|
|
570
600
|
|
|
571
601
|
mtime = source_mtime(resolved_path)
|
|
572
602
|
@shared_cache[resolved_path] = { mtime:, analysis: } if mtime
|
|
@@ -730,8 +760,13 @@ module MilkTea
|
|
|
730
760
|
)
|
|
731
761
|
end
|
|
732
762
|
|
|
733
|
-
|
|
734
|
-
|
|
763
|
+
# The shared cache stores per-module analyses keyed by resolved path. It is
|
|
764
|
+
# consulted only for paths NOT covered by source_overrides: source-overridden
|
|
765
|
+
# files reflect live editor buffers (or in-memory sources) that never match
|
|
766
|
+
# disk, so their entries would be stale by construction. This lets a single
|
|
767
|
+
# open document invalidate only itself while imported modules stay cached.
|
|
768
|
+
def use_shared_cache_for?(resolved_path)
|
|
769
|
+
@shared_cache && !@source_overrides.key?(resolved_path)
|
|
735
770
|
end
|
|
736
771
|
end
|
|
737
772
|
end
|
|
@@ -41,16 +41,28 @@ module MilkTea
|
|
|
41
41
|
_intern([:string_view]) { StringView.new }
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
# Param signature for intern keys. Parameter#eql? is name-insensitive
|
|
45
|
+
# (assignability must not depend on parameter names), so arrays of
|
|
46
|
+
# Parameter objects would conflate fn(value: int) with fn(arg0: int) in
|
|
47
|
+
# the intern pool. Embedding names here keeps distinct signatures
|
|
48
|
+
# distinct across independent programs sharing a long-lived pool (the LSP
|
|
49
|
+
# never resets the registry between checks).
|
|
50
|
+
def self.param_signature(params)
|
|
51
|
+
params.map { |p| [p.name, p.type, p.mutable, p.passing_mode, p.boundary_type] }
|
|
52
|
+
end
|
|
53
|
+
|
|
44
54
|
def self.function(name, params:, return_type:, receiver_type: nil, receiver_editable: false, variadic: false, external: false)
|
|
45
55
|
params_frozen = params.freeze
|
|
46
|
-
|
|
56
|
+
param_key = param_signature(params_frozen)
|
|
57
|
+
_intern([:function, name, param_key, return_type, receiver_type, receiver_editable, variadic, external]) {
|
|
47
58
|
Function.new(name, params: params_frozen, return_type: return_type, receiver_type: receiver_type, receiver_editable: receiver_editable, variadic: variadic, external: external)
|
|
48
59
|
}
|
|
49
60
|
end
|
|
50
61
|
|
|
51
62
|
def self.proc(params:, return_type:)
|
|
52
63
|
params_frozen = params.freeze
|
|
53
|
-
|
|
64
|
+
param_key = param_signature(params_frozen)
|
|
65
|
+
_intern([:proc, param_key, return_type]) { Proc.new(params: params_frozen, return_type: return_type) }
|
|
54
66
|
end
|
|
55
67
|
|
|
56
68
|
def self.parameter(name, type, mutable: false, passing_mode: :plain, boundary_type: nil)
|
|
@@ -360,6 +360,8 @@ module MilkTea
|
|
|
360
360
|
end
|
|
361
361
|
|
|
362
362
|
def handle_document_diagnostic(params)
|
|
363
|
+
return { kind: 'full', items: [] } if request_cancelled?(@current_request_id)
|
|
364
|
+
|
|
363
365
|
uri = params.dig('textDocument', 'uri')
|
|
364
366
|
return { kind: 'full', items: [] } unless uri
|
|
365
367
|
|
|
@@ -404,6 +406,8 @@ module MilkTea
|
|
|
404
406
|
end
|
|
405
407
|
|
|
406
408
|
def handle_workspace_diagnostic(params)
|
|
409
|
+
return { items: [] } if request_cancelled?(@current_request_id)
|
|
410
|
+
|
|
407
411
|
progress = nil
|
|
408
412
|
if (work_done_token = params['workDoneToken'])
|
|
409
413
|
progress = create_progress_handle(@protocol, work_done_token)
|
|
@@ -416,7 +420,13 @@ module MilkTea
|
|
|
416
420
|
end
|
|
417
421
|
|
|
418
422
|
all_uris = @workspace.open_document_uris
|
|
419
|
-
items =
|
|
423
|
+
items = []
|
|
424
|
+
all_uris.each do |uri|
|
|
425
|
+
# Coarse cancellation: workspace/diagnostic can iterate many cold
|
|
426
|
+
# documents (~1s each); bail early when the client cancels so we do
|
|
427
|
+
# not sink CPU into results that will be discarded.
|
|
428
|
+
break if request_cancelled?(@current_request_id)
|
|
429
|
+
|
|
420
430
|
content = @workspace.get_content(uri)
|
|
421
431
|
next if content.empty?
|
|
422
432
|
|
|
@@ -426,10 +436,10 @@ module MilkTea
|
|
|
426
436
|
|
|
427
437
|
cached = @workspace_diagnostic_cache[uri]
|
|
428
438
|
if cached && cached[:result_id] == prev_map[uri] && cached[:fingerprint] == fingerprint
|
|
429
|
-
{ uri: uri, kind: 'unchanged', resultId: result_id, items: [], version: nil }
|
|
439
|
+
items << { uri: uri, kind: 'unchanged', resultId: result_id, items: [], version: nil }
|
|
430
440
|
else
|
|
431
441
|
@workspace_diagnostic_cache[uri] = { result_id: result_id, fingerprint: fingerprint }
|
|
432
|
-
{ uri: uri, kind: 'full', resultId: result_id, items: diagnostics, version: nil }
|
|
442
|
+
items << { uri: uri, kind: 'full', resultId: result_id, items: diagnostics, version: nil }
|
|
433
443
|
end
|
|
434
444
|
end
|
|
435
445
|
|
|
@@ -202,28 +202,72 @@ module MilkTea
|
|
|
202
202
|
end.join("\n")
|
|
203
203
|
end
|
|
204
204
|
|
|
205
|
+
# Declaration-prefix regex. Unlike the old form, it also covers the
|
|
206
|
+
# `const function` compound, async/foreign/external/editable/static
|
|
207
|
+
# modifiers, and `attribute` declarations. `static_assert` is not
|
|
208
|
+
# matched: `static` requires whitespace before the keyword, and a bare
|
|
209
|
+
# module-level statement cannot be a declaration.
|
|
210
|
+
SURFACE_DECL_LINE = %r{\A(?:(?:public|foreign|external|async|editable|static|const)\s+)*(?:function|struct|union|enum|flags|variant|interface|event|type|const|var|extending|opaque|attribute)\b}
|
|
211
|
+
|
|
212
|
+
# A bare `name: Type` line. Only struct/union fields (and continuation
|
|
213
|
+
# parameter lines) take this shape; local declarations use `let`/`var`,
|
|
214
|
+
# named arguments use `=`, and match-arm labels start with a keyword or
|
|
215
|
+
# pattern. Requires a type-like token after the colon so `_:` arm labels
|
|
216
|
+
# are not treated as surface.
|
|
217
|
+
SURFACE_FIELD_LINE = /\A[A-Za-z_][A-Za-z0-9_]*\s*:\s*[A-Za-z_\[\]]/
|
|
218
|
+
|
|
219
|
+
# Over-approximation of the module's externally-observable surface. It
|
|
220
|
+
# must never MISS a surface change (a miss leaves shared-cache analyses
|
|
221
|
+
# of dependents stale); false positives only trigger a harmless
|
|
222
|
+
# re-analysis. In addition to declaration lines it captures:
|
|
223
|
+
# - `@[...]` attributes (packed/align/deprecated change layout/docs)
|
|
224
|
+
# - multi-line declaration headers, so parameter/signature edits on
|
|
225
|
+
# continuation lines are detected
|
|
226
|
+
# - struct/union field lines (`name: Type`)
|
|
205
227
|
def dependency_export_surface_fingerprint(content)
|
|
206
|
-
content.to_s.
|
|
207
|
-
|
|
208
|
-
|
|
228
|
+
lines = content.to_s.lines.map(&:strip)
|
|
229
|
+
surface = []
|
|
230
|
+
i = 0
|
|
231
|
+
while i < lines.length
|
|
232
|
+
line = lines[i]
|
|
233
|
+
if line.empty? || line.start_with?('#')
|
|
234
|
+
i += 1
|
|
235
|
+
next
|
|
236
|
+
end
|
|
209
237
|
|
|
210
|
-
if
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
238
|
+
if line.start_with?('@[') || line.match?(SURFACE_DECL_LINE) || line.match?(SURFACE_FIELD_LINE)
|
|
239
|
+
surface << line
|
|
240
|
+
# Multi-line header: absorb continuation lines until the
|
|
241
|
+
# terminating ':' so edits inside the header are surfaced too.
|
|
242
|
+
unless line.end_with?(':')
|
|
243
|
+
i += 1
|
|
244
|
+
while i < lines.length
|
|
245
|
+
cont = lines[i]
|
|
246
|
+
break if cont.empty?
|
|
247
|
+
surface << cont
|
|
248
|
+
i += 1
|
|
249
|
+
break if cont.end_with?(':')
|
|
250
|
+
end
|
|
251
|
+
next
|
|
252
|
+
end
|
|
216
253
|
end
|
|
217
|
-
|
|
254
|
+
i += 1
|
|
255
|
+
end
|
|
256
|
+
surface.join("\n")
|
|
218
257
|
end
|
|
219
258
|
|
|
220
259
|
def dependency_refresh_required_for_edit?(changed_uri, previous_content, current_content)
|
|
221
260
|
return false if previous_content == current_content
|
|
222
261
|
return true if dependency_import_fingerprint(previous_content) != dependency_import_fingerprint(current_content)
|
|
223
262
|
|
|
224
|
-
|
|
225
|
-
|
|
263
|
+
# Keep the open-document dependency index fresh (related_open_document_uris
|
|
264
|
+
# updates it as a side effect) so dependent tracking stays accurate.
|
|
265
|
+
@workspace.related_open_document_uris(changed_uri)
|
|
226
266
|
|
|
267
|
+
# A surface edit can invalidate shared-cache analyses of NON-open
|
|
268
|
+
# dependents (their cached entries are recomputed against this module
|
|
269
|
+
# on their next pull), so clearing must not be gated on there being
|
|
270
|
+
# open dependents to refresh.
|
|
227
271
|
dependency_export_surface_fingerprint(previous_content) != dependency_export_surface_fingerprint(current_content)
|
|
228
272
|
end
|
|
229
273
|
|
|
@@ -43,7 +43,12 @@ module MilkTea
|
|
|
43
43
|
invalidate_document_caches(uri)
|
|
44
44
|
current_content = @workspace.get_content(uri)
|
|
45
45
|
refresh_open_document_dependency_state(uri, previous_content: previous_content, current_content: current_content)
|
|
46
|
-
|
|
46
|
+
# This server is always pull-based (diagnosticProvider), so the
|
|
47
|
+
# client's textDocument/diagnostic request asks for the full tier.
|
|
48
|
+
# Scheduling a lighter tier here computes in the worker and then
|
|
49
|
+
# duplicates the full lint on the request thread; keep the tiers
|
|
50
|
+
# aligned so the pull can serve the worker's result.
|
|
51
|
+
schedule_diagnostics(uri, lint_tier: :full) unless @workspace.background_document?(uri)
|
|
47
52
|
nil
|
|
48
53
|
end
|
|
49
54
|
|
|
@@ -65,12 +70,23 @@ module MilkTea
|
|
|
65
70
|
|
|
66
71
|
def handle_did_close(params)
|
|
67
72
|
uri = params['textDocument']['uri']
|
|
73
|
+
previous_content = @workspace.get_content(uri)
|
|
68
74
|
cancel_diagnostics(uri)
|
|
69
75
|
@workspace.close_document(uri)
|
|
70
76
|
invalidate_document_caches(uri)
|
|
71
77
|
@diagnostic_report_cache.delete(uri)
|
|
72
78
|
@workspace_diagnostic_cache.delete(uri)
|
|
73
|
-
|
|
79
|
+
# Once closed, the buffer is no longer authoritative. If it differed
|
|
80
|
+
# from disk, module analyses computed against it (for dependents and
|
|
81
|
+
# the file itself) are stale; drop the whole shared cache. Closing is
|
|
82
|
+
# a rare per-file event, so an unconditional clear is cheap and safe.
|
|
83
|
+
disk_content = begin
|
|
84
|
+
path = uri_to_path(uri)
|
|
85
|
+
path && File.file?(path) ? File.read(path) : nil
|
|
86
|
+
rescue StandardError
|
|
87
|
+
nil
|
|
88
|
+
end
|
|
89
|
+
clear_shared_module_cache if previous_content != disk_content
|
|
74
90
|
unless defined?(@pull_diagnostics_active) && @pull_diagnostics_active
|
|
75
91
|
@protocol.write_notification('textDocument/publishDiagnostics', {
|
|
76
92
|
uri: uri,
|
|
@@ -99,14 +99,41 @@ module MilkTea
|
|
|
99
99
|
|
|
100
100
|
lock_wait_start = total_start ? monotonic_time : nil
|
|
101
101
|
if @facts_state_mutex.try_lock
|
|
102
|
+
# No analysis is in flight; computing here is fine (cold paths,
|
|
103
|
+
# tests). It does not block on other work.
|
|
102
104
|
begin
|
|
103
105
|
compute_snapshot.call
|
|
104
106
|
ensure
|
|
105
107
|
@facts_state_mutex.unlock
|
|
106
108
|
end
|
|
107
109
|
elsif allow_last_good_fallback && last_good_snapshot
|
|
108
|
-
|
|
110
|
+
# Facts exist from a prior pass; never block on the in-flight one.
|
|
109
111
|
snapshot = last_good_snapshot
|
|
112
|
+
cache_state = 'last_good'
|
|
113
|
+
elsif allow_last_good_fallback
|
|
114
|
+
# No facts yet and a background analysis is computing this document.
|
|
115
|
+
# Wait briefly (bounded) for it so the request usually returns fresh
|
|
116
|
+
# facts instead of a lexical fallback — without duplicating the work
|
|
117
|
+
# (we never run analysis here) or blocking indefinitely. Beyond the
|
|
118
|
+
# budget, serve nil and let the handler fall back.
|
|
119
|
+
deadline = monotonic_time + (IN_FLIGHT_FACTS_WAIT_MS / 1000.0)
|
|
120
|
+
acquired = false
|
|
121
|
+
while monotonic_time < deadline
|
|
122
|
+
if @facts_state_mutex.try_lock
|
|
123
|
+
acquired = true
|
|
124
|
+
break
|
|
125
|
+
end
|
|
126
|
+
sleep 0.02
|
|
127
|
+
end
|
|
128
|
+
if acquired
|
|
129
|
+
begin
|
|
130
|
+
compute_snapshot.call
|
|
131
|
+
ensure
|
|
132
|
+
@facts_state_mutex.unlock
|
|
133
|
+
end
|
|
134
|
+
else
|
|
135
|
+
cache_state = 'nil'
|
|
136
|
+
end
|
|
110
137
|
else
|
|
111
138
|
@facts_state_mutex.synchronize do
|
|
112
139
|
lock_wait_ms = elapsed_ms(lock_wait_start) if lock_wait_start
|
|
@@ -107,6 +107,37 @@ module MilkTea
|
|
|
107
107
|
@full_reverse_index_built = false
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
+
# Drop all cached module analyses (and the per-uri snapshots derived from
|
|
111
|
+
# them) when an analysis input that was captured in those analyses is no
|
|
112
|
+
# longer authoritative — e.g. a closed document whose buffer differed from
|
|
113
|
+
# disk. Kept rare: closing a file is infrequent, so a wholesale clear is
|
|
114
|
+
# safer than reasoning about which dependents could have observed the
|
|
115
|
+
# closed buffer. Open documents keep their last-known-good snapshots so
|
|
116
|
+
# they keep serving rich features while re-analysis lands.
|
|
117
|
+
def clear_shared_module_cache
|
|
118
|
+
@facts_state_mutex.synchronize do
|
|
119
|
+
@facts_cache_mutex.synchronize do
|
|
120
|
+
all_open = @document_state_mutex.synchronize { @open_documents.keys }
|
|
121
|
+
preserved_facts = all_open.each_with_object({}) do |open_uri, preserved|
|
|
122
|
+
facts = @last_good_facts_cache[open_uri]
|
|
123
|
+
preserved[open_uri] = facts if facts
|
|
124
|
+
end
|
|
125
|
+
preserved_snapshots = all_open.each_with_object({}) do |open_uri, preserved|
|
|
126
|
+
snapshot = @last_good_tooling_snapshot_cache[open_uri]
|
|
127
|
+
preserved[open_uri] = snapshot if snapshot
|
|
128
|
+
end
|
|
129
|
+
@shared_module_cache.clear
|
|
130
|
+
@facts_cache.clear
|
|
131
|
+
@tooling_snapshot_cache.clear
|
|
132
|
+
@diagnostics_cache.clear
|
|
133
|
+
@last_good_facts_cache.clear
|
|
134
|
+
@last_good_tooling_snapshot_cache.clear
|
|
135
|
+
preserved_snapshots.each { |open_uri, snapshot| @last_good_tooling_snapshot_cache[open_uri] = snapshot }
|
|
136
|
+
preserved_facts.each { |open_uri, facts| @last_good_facts_cache[open_uri] = facts }
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
110
141
|
def update_dependency_index(uri, facts)
|
|
111
142
|
imported_module_names = if facts
|
|
112
143
|
facts.imports.each_value.filter_map(&:name).to_set
|
|
@@ -72,7 +72,13 @@ module MilkTea
|
|
|
72
72
|
invalidate_cache(uri)
|
|
73
73
|
enqueue_definition_warmup(uri) unless background_document?(uri)
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
# The shared module cache is intentionally NOT cleared here. Imported
|
|
76
|
+
# module analyses only become stale when this file's dependency surface
|
|
77
|
+
# (imports or exported declarations) changes; a body-only edit leaves
|
|
78
|
+
# them valid. handle_did_change detects surface changes via
|
|
79
|
+
# dependency_refresh_required_for_edit? and clears the cache through
|
|
80
|
+
# refresh_import_dependent_caches. Clearing it on every keystroke forced
|
|
81
|
+
# a full re-analysis of every transitive module per edit.
|
|
76
82
|
dependent_uris = @facts_cache_mutex.synchronize do
|
|
77
83
|
all_open = @document_state_mutex.synchronize { @open_documents.keys }
|
|
78
84
|
dependent_open_document_uris_for(uri, all_open)
|
|
@@ -22,6 +22,12 @@ module MilkTea
|
|
|
22
22
|
DOCUMENT_SOURCES = %w[active-editor visible-editor background-document].freeze
|
|
23
23
|
PERF_LOG_THRESHOLD_MS = 1000
|
|
24
24
|
|
|
25
|
+
# How long a request thread waits (when no facts are available yet) for an
|
|
26
|
+
# in-flight background analysis to finish before falling back to lexical/
|
|
27
|
+
# nil results. Bounds the main-loop stall while usually returning fresh
|
|
28
|
+
# facts; request threads never run the analysis themselves in this window.
|
|
29
|
+
IN_FLIGHT_FACTS_WAIT_MS = Integer(ENV.fetch('MILK_TEA_LSP_FACTS_WAIT_MS', '500'))
|
|
30
|
+
|
|
25
31
|
# Token types that introduce a named definition, in order of precedence.
|
|
26
32
|
#
|
|
27
33
|
# NOTE: this list is intentionally minimal. Multi-keyword prefixes such as
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mt-lang
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.41
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Long (Teefan) Tran
|
|
@@ -625,7 +625,7 @@ metadata:
|
|
|
625
625
|
homepage_uri: https://teefan.github.io/mt-lang/
|
|
626
626
|
source_code_uri: https://github.com/teefan/mt-lang
|
|
627
627
|
post_install_message: |
|
|
628
|
-
Milk Tea 0.3.
|
|
628
|
+
Milk Tea 0.3.41 installed!
|
|
629
629
|
|
|
630
630
|
System requirements:
|
|
631
631
|
- A C compiler (gcc or clang) must be available on PATH
|