Class: Ibex::LSP::DocumentStore
Overview
Owns open buffers, parsed snapshots, include closures, and reverse dependencies.
Instance Attribute Summary collapse
Instance Method Summary
collapse
-
#affected_roots(path) ⇒ Array[String]
-
#change(uri, version, source) ⇒ Array[publication]
-
#close(uri) ⇒ Array[publication]
Clear the open version first, then replace it with a disk snapshot if one exists.
-
#empty_paths ⇒ Array[String]
-
#files_for(path) ⇒ Array[String]
-
#initialize(workspace, loader) ⇒ DocumentStore
constructor
A new instance of DocumentStore.
-
#open(uri, version, source) ⇒ Array[publication]
-
#open_snapshot(path, uri) ⇒ snapshot
-
#publish_paths(paths) ⇒ Array[publication]
-
#rebuild_reverse_dependencies ⇒ void
-
#refresh(path) ⇒ Array[publication]
-
#refresh_dependents(path) ⇒ Array[publication]
-
#refresh_root(root) ⇒ void
-
#remove_path(path) ⇒ void
-
#remove_root_state(path) ⇒ void
-
#resolutions_for(path) ⇒ Array[Frontend::Resolution]
-
#roots_for(path) ⇒ Array[String]
-
#save(uri, source: nil) ⇒ Array[publication]
-
#snapshot(uri, path, version, source, open, document) ⇒ snapshot
-
#snapshot_for(path) ⇒ snapshot?
-
#update_root_membership(path, document) ⇒ void
-
#update_snapshot(path, analyzed, own_diagnostics: true) ⇒ void
-
#uri_for(path) ⇒ String
Preserve the URI spelling used to open a document; closed files use their canonical URI.
#aggregated_diagnostics, #empty_diagnostics, #replace_root_diagnostics
#disk_path_for_close, #parse_candidate, #valid_replacements?, #validate_source, #validate_version
Constructor Details
#initialize(workspace, loader) ⇒ DocumentStore
Returns a new instance of DocumentStore.
29
30
31
32
33
34
35
36
37
38
39
40
|
# File 'lib/ibex/lsp/document_store.rb', line 29
def initialize(workspace, loader)
@workspace = workspace
@loader = loader
@analyzer = WorkspaceAnalyzer.new(workspace, loader)
@snapshots = {} @roots = {} @closures = {} @reverse_dependencies = {} @resolutions = {} @document_diagnostics = {} @root_diagnostics = {} end
|
Instance Attribute Details
25
26
27
|
# File 'lib/ibex/lsp/document_store.rb', line 25
def loader
@loader
end
|
26
27
28
|
# File 'lib/ibex/lsp/document_store.rb', line 26
def workspace
@workspace
end
|
Instance Method Details
#affected_roots(path) ⇒ Array[String]
186
187
188
189
190
|
# File 'lib/ibex/lsp/document_store.rb', line 186
def affected_roots(path)
roots = @reverse_dependencies.fetch(path, empty_paths).dup
roots << path if @roots[path]
roots.uniq
end
|
#change(uri, version, source) ⇒ Array[publication]
55
56
57
58
59
60
61
62
63
64
65
66
67
|
# File 'lib/ibex/lsp/document_store.rb', line 55
def change(uri, version, source)
path = workspace.path(uri)
current = open_snapshot(path, uri)
validate_version(version)
unless current.fetch(:version) && version > current.fetch(:version)
raise ProtocolError.new("document version must increase monotonically", code: -32_602)
end
validate_source(source)
loader.set_overlay(path, source)
@snapshots[path] = snapshot(uri, path, version, source, true, nil)
refresh(path)
end
|
#close(uri) ⇒ Array[publication]
Clear the open version first, then replace it with a disk snapshot if one exists.
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
# File 'lib/ibex/lsp/document_store.rb', line 84
def close(uri)
path = workspace.path(uri)
open_snapshot(path, uri)
clear = { uri: uri, diagnostics: [] } old_files = files_for(path)
was_root = @roots[path]
disk_path = disk_path_for_close(path, uri)
disk_source = loader.disk_source(disk_path) if disk_path && loader.disk_file?(disk_path)
loader.delete_overlay(path)
if disk_source
@snapshots[path] = snapshot(uri, path, nil, disk_source, false, nil)
if was_root
analyzed = @analyzer.analyze(path)
update_snapshot(path, analyzed)
remove_root_state(path)
[clear] + publish_paths((old_files + [path]).uniq)
else
[clear] + refresh(path)
end
else
remove_path(path)
[clear] + refresh_dependents(path)
end
end
|
#empty_paths ⇒ Array[String]
243
244
245
|
# File 'lib/ibex/lsp/document_store.rb', line 243
def empty_paths
[] end
|
#files_for(path) ⇒ Array[String]
124
125
126
127
128
|
# File 'lib/ibex/lsp/document_store.rb', line 124
def files_for(path)
roots = affected_roots(path)
files = roots.flat_map { |root| @closures.fetch(root, [root]) }
(files + [path]).uniq
end
|
#open(uri, version, source) ⇒ Array[publication]
43
44
45
46
47
48
49
50
51
52
|
# File 'lib/ibex/lsp/document_store.rb', line 43
def open(uri, version, source)
path = workspace.path(uri)
raise ProtocolError.new("document is already open: #{uri}", code: -32_602) if @snapshots.dig(path, :open)
validate_version(version)
validate_source(source)
loader.set_overlay(path, source)
@snapshots[path] = snapshot(uri, path, version, source, true, nil)
refresh(path)
end
|
#open_snapshot(path, uri) ⇒ snapshot
235
236
237
238
239
240
|
# File 'lib/ibex/lsp/document_store.rb', line 235
def open_snapshot(path, uri)
entry = @snapshots[path]
return entry if entry&.fetch(:open) && entry.fetch(:uri) == uri
raise ProtocolError.new("document is not open: #{uri}", code: -32_602)
end
|
#publish_paths(paths) ⇒ Array[publication]
214
215
216
217
218
219
220
221
222
223
224
225
226
|
# File 'lib/ibex/lsp/document_store.rb', line 214
def publish_paths(paths)
paths.filter_map do |path|
entry = @snapshots[path]
next unless entry
publication = {
uri: entry.fetch(:uri),
diagnostics: aggregated_diagnostics(path)
} publication[:version] = entry.fetch(:version) if entry.fetch(:open) && entry.fetch(:version)
publication
end
end
|
#rebuild_reverse_dependencies ⇒ void
This method returns an undefined value.
179
180
181
182
183
|
# File 'lib/ibex/lsp/document_store.rb', line 179
def rebuild_reverse_dependencies
reverse = Hash.new { |hash, key| hash[key] = [] } @closures.each { |root, files| files.each { |file| reverse[file] << root } }
@reverse_dependencies = reverse
end
|
#refresh(path) ⇒ Array[publication]
143
144
145
146
147
148
149
150
151
152
153
154
155
|
# File 'lib/ibex/lsp/document_store.rb', line 143
def refresh(path)
old_files = files_for(path)
previous_roots = affected_roots(path)
was_root = @roots[path]
analyzed = @analyzer.analyze(path)
update_snapshot(path, analyzed)
update_root_membership(path, analyzed.fetch(:document))
remove_root_state(path) if was_root && !@roots[path]
roots = (previous_roots + affected_roots(path)).uniq
roots.delete(path) unless @roots[path]
roots.each { |root| refresh_root(root) }
publish_paths((old_files + files_for(path) + [path]).uniq)
end
|
#refresh_dependents(path) ⇒ Array[publication]
158
159
160
161
162
|
# File 'lib/ibex/lsp/document_store.rb', line 158
def refresh_dependents(path)
roots = affected_roots(path)
roots.each { |root| refresh_root(root) }
publish_paths(roots.flat_map { |root| @closures.fetch(root, [root]) }.uniq)
end
|
#refresh_root(root) ⇒ void
This method returns an undefined value.
165
166
167
168
169
170
171
172
173
174
175
176
|
# File 'lib/ibex/lsp/document_store.rb', line 165
def refresh_root(root)
files, analyzed = @analyzer.closure(root)
@closures[root] = files
rebuild_reverse_dependencies
analyzed.each { |path, result| update_snapshot(path, result, own_diagnostics: false) }
parse_failed = analyzed.any? do |path, result|
!result.fetch(:diagnostics).empty? && loader.file?(path)
end
resolution, errors = parse_failed ? [nil, []] : @analyzer.resolve(root)
resolution ? @resolutions[root] = resolution : @resolutions.delete(root)
replace_root_diagnostics(root, files, analyzed, errors)
end
|
#remove_path(path) ⇒ void
This method returns an undefined value.
248
249
250
251
252
|
# File 'lib/ibex/lsp/document_store.rb', line 248
def remove_path(path)
@snapshots.delete(path)
@document_diagnostics.delete(path)
remove_root_state(path)
end
|
#remove_root_state(path) ⇒ void
This method returns an undefined value.
255
256
257
258
259
260
261
|
# File 'lib/ibex/lsp/document_store.rb', line 255
def remove_root_state(path)
@roots.delete(path)
@closures.delete(path)
@resolutions.delete(path)
@root_diagnostics.delete(path)
rebuild_reverse_dependencies
end
|
131
132
133
|
# File 'lib/ibex/lsp/document_store.rb', line 131
def resolutions_for(path)
affected_roots(path).filter_map { |root| @resolutions[root] }
end
|
#roots_for(path) ⇒ Array[String]
136
137
138
|
# File 'lib/ibex/lsp/document_store.rb', line 136
def roots_for(path)
affected_roots(path)
end
|
#save(uri, source: nil) ⇒ Array[publication]
70
71
72
73
74
75
76
77
78
79
80
|
# File 'lib/ibex/lsp/document_store.rb', line 70
def save(uri, source: nil)
path = workspace.path(uri)
current = open_snapshot(path, uri)
if source
validate_source(source)
loader.set_overlay(path, source)
current = snapshot(uri, path, current.fetch(:version), source, true, nil)
@snapshots[path] = current
end
refresh(path)
end
|
#snapshot(uri, path, version, source, open, document) ⇒ snapshot
230
231
232
|
# File 'lib/ibex/lsp/document_store.rb', line 230
def snapshot(uri, path, version, source, open, document)
{ uri: uri, path: path, version: version, source: source, open: open, document: document }
end
|
#snapshot_for(path) ⇒ snapshot?
110
111
112
|
# File 'lib/ibex/lsp/document_store.rb', line 110
def snapshot_for(path)
@snapshots[path]
end
|
#update_root_membership(path, document) ⇒ void
This method returns an undefined value.
205
206
207
208
209
210
211
|
# File 'lib/ibex/lsp/document_store.rb', line 205
def update_root_membership(path, document)
if document&.ast.is_a?(Frontend::AST::Root)
@roots[path] = true
else
@roots.delete(path)
end
end
|
#update_snapshot(path, analyzed, own_diagnostics: true) ⇒ void
This method returns an undefined value.
193
194
195
196
197
198
199
200
201
202
|
# File 'lib/ibex/lsp/document_store.rb', line 193
def update_snapshot(path, analyzed, own_diagnostics: true)
current = @snapshots[path]
uri = current&.fetch(:uri) || workspace.uri(path)
version = current&.fetch(:version)
open = current&.fetch(:open) || false
source = open ? current.fetch(:source) : analyzed.fetch(:source)
document = analyzed.fetch(:document)
@snapshots[path] = snapshot(uri, path, version, source, open, document)
@document_diagnostics[path] = analyzed.fetch(:diagnostics) if own_diagnostics
end
|
#uri_for(path) ⇒ String
Preserve the URI spelling used to open a document; closed files use their canonical URI.
116
117
118
119
120
121
|
# File 'lib/ibex/lsp/document_store.rb', line 116
def uri_for(path)
entry = @snapshots[path]
return entry.fetch(:uri) if entry&.fetch(:open)
workspace.uri(path)
end
|