Include used Tags / Markers in LSP Auto-Completion #149
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Use the graph-cache, it needs to be fast!
Implementation Plan
Clarified requirements
@wordthat shows up in the corpus counts, as a marker (before content) or as a tag (after content), whether or not it is declared inRepositoryConfiguration.todo/timesheet.todo,timesheet, …) keep their current cost..streamd.tomlreload, and refreshed on every markdown save or watched.mdchange.@20260101,@0900, R16) are left out of both the list and completion. The existing date/time snippets already cover them.Current state (for reference)
src/cache/projection.rs::project_shardonly internslocalized.tagsas:Tagnodes (TAGGED). Raw marker names never reach the graph. Markers only show up indirectly, as:DimensionValueplacements, and only when they are configured.cache::rebuild()(streamd cache rebuild).cache::load_stream_filessyncs the structural layer but never updates the projection, so the projection is usually stale or missing.src/cli/commands/lsp.rs::completions_for_lineonly suggestsconfig.markers(R25a).1. Graph schema / projection (
src/cache/)schema.rsEDGE_MARKED: &str = "MARKED".PROP_PROJECTION_DIRTY: &str = "projection_dirty".SCHEMA_VERSIONto2, so existing caches are discarded and rebuilt in the new shape.projection.rs::project_shard: also loop overlocalized.markers, intern each one with the existingintern_tagand create anEDGE_MARKEDedge from the shard. A name used both ways therefore shares a single:Tagnode.tags_co_occurring_withonly followsTAGGED, so it keeps its current meaning (add a test for that).Staleness tracking:
sync_structuralalso runs when other commands load the corpus, so its ownSyncStatscan't tell whether the projection is stale.sync.rs::sync_structural: whenadded + updated + removed > 0, setprojection_dirty = trueon:Meta.projection.rs::build_projection: afterstamp_fingerprint, setprojection_dirty = false.projection_is_fresh(session, config, tz) -> bool. It returns true only if the fingerprint matches andprojection_dirtyisfalse(a missing property counts as dirty).query.rs: addused_tag_and_marker_names(session) -> Result<Vec<String>, StreamdError>. It runsMATCH (t:Tag) RETURN t.name, then dedups, drops all-digit names, and sorts alphabetically. Sort with plainstrordering first, for deterministic output.mod.rs: addpub fn load_used_names(base_folder: &Path, tz: Tz) -> Result<Vec<String>, StreamdError>. Steps:store::open_or_rebuildsync::sync_structuralbuild_projection(canonical_configuration(), tz)if!projection_is_freshquery::used_tag_and_marker_namesIt returns
Errwhen the cache is locked or unusable, and callers fall back.2. CLI command
streamd tagssrc/cli/args.rs: addCommands::Tagswith the doc comment "List all tags and markers used in the stream, alphabetically".src/cli/commands/tags.rs(new; register it incommands/mod.rsand dispatch it inmain.rs/cli/mod.rsthe same wayCacheis):run()loadsSettings, then callsrun_in(base_folder).run_intakes the timezone fromload_repository_config(base_folder)?.timezone_or_utc(), same ascache rebuild.collect_used_names(base_folder, tz) -> Result<Vec<String>, StreamdError>:cache::load_used_namesunlesscache::is_disabled().Err, or when the cache is disabled, fall back to a direct recursive scan. Usecache::sync::scan_diskfor the paths, thenparse_markdown_file, and collectmarkers+tagsfrom the parsedShardtree (no localization needed). Apply the same all-digit filter, dedup and sort.normalize_used_names(impl Iterator<Item=String>)) so both paths produce identical output.@, to stdout. Print nothing for an empty corpus.3. LSP completion (
src/cli/commands/lsp.rs)LspState: addused_names: std::sync::RwLock<Vec<String>>.LspState::refresh_used_names(&self):cache::load_used_names(&self.base_folder, self.tz), unless the cache is disabled.markers+tagsfrom every entry currently infile_cache(walk theLocalizedShardtrees), normalized with the same helper. Either way no disk reads happen on this path, and it never fails.used_names.Call sites:
build_state, afterseed_from_cache()(covers start-up and.streamd.tomlreload).did_save.did_change_watched_files.Run the refresh via
tokio::task::spawn_blocking(clone theArc<LspState>) so the graph rebuild never blocks request handling. A completion request that arrives meanwhile just sees the previous set.completions_for_line: add a parameterused_names: &[String], keeping the function pure and unit-testable. After the config markers, add an item for each used name that:config.markers(no duplicate labels).Each item gets
label: "@name",insert_text: name,kind: CompletionItemKind::TEXT,detail: "Used in stream"andsort_text: "1b_{name}". Resulting order: conditional config markers (0_), then config markers (1_), then used names (1b_), then date/time snippets (2_).The
completionhandler passes&state.used_names.read().4. Tests
cache/projection.rs/cache/query.rs:@Project-X, appear inused_tag_and_marker_names.tags_co_occurring_withis unaffected byMARKEDedges.sync_structuralafter editing or adding a file:projection_is_freshmust befalse.load_used_names, the new tag is returned.cli/commands/tags.rs:STREAMD_NO_CACHE=1/ locked cache) paths return identical results on a corpus with nested files, unconfigured markers, content tags and a temporal marker.lsp.rs:completions_for_linesuggests a used tag matching the prefix.&[]).cache/mod.rs:load_used_nameson a fresh cache builds the projection and returns names.5. Docs
REQUIREMENTS.md:streamd tagsto R20.@-prefixed, cache with direct-scan fallback).MARKEDedge,projection_dirty, auto-rebuild when stale for these consumers, schema v2.README.md:streamd tagsto the Commands list.@completions to mention used tags/markers.streamd tags.6. Verification
cargo test,cargo clippy,cargo fmt, thennix flake check.streamd tagson a sample stream. Startstreamd lspin an editor, type@followed by a prefix of a tag used only in another file, and confirm it is suggested. Add a new tag, save, and confirm it becomes suggestible.Implementation notes
Implemented in PR #150 (branch
149_used-tags-markers-completion, released as v0.7.0).Findings during implementation
streamd cache rebuildbuilt it, and ordinary commands synced files without updating it. A dirty flag stored in the cache now tracks that. A flag on one sync's result wouldn't be enough, because another command may already have synced the changed files.STREAMD_CACHE_DIRandSTREAMD_NO_CACHEprocess-wide while the suite ran in parallel. That broketest_cache_lives_outside_the_stream_folderin the Nix build and occasionally a new LSP test. They now pass the value in directly, and no test changes the environment. 20 full runs in a row passed.STREAMD_BASE_FOLDER(R23) isn't implemented.Settings::loadnever reads it. A first smoke test relied on it and read the real stream folder by accident (read-only).@Idea/@Idea:and@TNG/@TNG?, because the tag pattern (R1) includes punctuation. Fixing that belongs in extraction.