Module: MilkTea::LSP::Workspace::WorkspaceModuleIndex
- Included in:
- MilkTea::LSP::Workspace
- Defined in:
- lib/milk_tea/lsp/workspace/module_index.rb
Overview
Persistent module-name index for import-line completion.
import_completions previously walked the entire module-root tree on
every keystroke (stat'ing every directory entry). This index records, per
module root, the importable module names reachable from each directory:
.mt file basenames directly in a directory, plus subdirectory names that
transitively contain a .mt file. It is built once per root and kept in
sync with workspace/didChangeWatchedFiles events, so per-keystroke import
completion becomes an in-memory hash lookup.
Instance Method Summary collapse
-
#apply_module_index_events(changes, skip_open: true) ⇒ Object
Apply workspace/didChangeWatchedFiles events to the index.
-
#ensure_module_index(root) ⇒ Object
Ensure
roothas an index entry, building it on first use. -
#module_importable_names(root, fs_dir, current_path: nil) ⇒ Object
Return importable module names for
fs_dirunderroot, excluding the currently-opencurrent_pathfile. - #module_index_roots ⇒ Object
-
#refresh_module_index_for_workspace ⇒ Object
Rebuild the index for every module root reachable from the workspace root.
- #reset_module_index ⇒ Object
Instance Method Details
#apply_module_index_events(changes, skip_open: true) ⇒ Object
Apply workspace/didChangeWatchedFiles events to the index. Content
changes (type 2) do not affect the name index; creates (1) and deletes
(3) of .mt files rebuild their root once per event batch so a build
producing many events triggers a single rescan. Open documents are
source-of-truth and are ignored (skip_open: true), matching
apply_watched_file_change; rename handling passes skip_open: false so
the index never keeps a stale name for a renamed module.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/milk_tea/lsp/workspace/module_index.rb', line 66 def apply_module_index_events(changes, skip_open: true) open_uris = @document_state_mutex.synchronize { @open_documents.keys } roots_to_rebuild = Set.new changes.each do |change| uri = change.is_a?(Hash) ? change['uri'] : nil change_type = change.is_a?(Hash) ? change['type'] : nil next unless uri && [1, 3].include?(change_type&.to_i) next if skip_open && open_uris.include?(uri) path = uri_to_path(uri) next unless path && path.end_with?('.mt') root = module_index_root_for_path(path) roots_to_rebuild << root if root end roots_to_rebuild.each { |root| build_module_index(root) } roots_to_rebuild.length end |
#ensure_module_index(root) ⇒ Object
Ensure root has an index entry, building it on first use. A race
between two threads simply builds twice and the later write wins.
31 32 33 34 35 36 |
# File 'lib/milk_tea/lsp/workspace/module_index.rb', line 31 def ensure_module_index(root) present = @module_index_mutex.synchronize { @module_index.key?(root) } return if present build_module_index(root) end |
#module_importable_names(root, fs_dir, current_path: nil) ⇒ Object
Return importable module names for fs_dir under root, excluding the
currently-open current_path file. Returns nil when root is unknown.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/milk_tea/lsp/workspace/module_index.rb', line 40 def module_importable_names(root, fs_dir, current_path: nil) ensure_module_index(root) entry = @module_index_mutex.synchronize { @module_index[root] } return nil unless entry result = {} files = entry[:mt_files][fs_dir] if files files.each do |mod_name, file_path| next if current_path && file_path == current_path result[mod_name] = true end end entry[:mt_dirs][fs_dir]&.each { |subdir| result[subdir] = true } result end |
#module_index_roots ⇒ Object
86 87 88 |
# File 'lib/milk_tea/lsp/workspace/module_index.rb', line 86 def module_index_roots @module_index_mutex.synchronize { @module_index.keys } end |
#refresh_module_index_for_workspace ⇒ Object
Rebuild the index for every module root reachable from the workspace root. Called after initialization and after workspace-folder changes.
22 23 24 25 26 27 |
# File 'lib/milk_tea/lsp/workspace/module_index.rb', line 22 def refresh_module_index_for_workspace root_path = @workspace_root_path return unless root_path module_roots_for_path(root_path).each { |root| ensure_module_index(root) } end |
#reset_module_index ⇒ Object
16 17 18 |
# File 'lib/milk_tea/lsp/workspace/module_index.rb', line 16 def reset_module_index @module_index_mutex.synchronize { @module_index.clear } end |