index EE files in wm-ts-nav code navigator (#8400)

EE files (*_ee.rs, *_ee.ts, *_ee.svelte) are symlinks from
windmill-ee-private that are gitignored. The walker skipped them
because it respects .gitignore. This adds a separate recursive scan
for _ee files and merges them into the index. Also fixes outline
resolving symlinks via canonicalize, causing path mismatches.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hugocasa
2026-03-16 17:57:38 +01:00
committed by GitHub
parent 9554876d8b
commit 0b65c3d8fa
3 changed files with 48 additions and 3 deletions

View File

@@ -58,6 +58,8 @@ let { my_prop = $bindable(default_value) }: { my_prop?: string } = $props()
- `refs "X" --caller` instead of reading files to find which function contains each reference
- `callers "X"` / `callees "X"` for call-graph questions
EE files (`*_ee.rs`, `*_ee.ts`, `*_ee.svelte`) are indexed — you can `outline`, `def`, `body`, `refs` etc. on them just like regular files.
```bash
NAV="sh wm-ts-nav/nav"
# Use --root backend for Rust, --root frontend/src for TS/Svelte

View File

@@ -2,7 +2,7 @@ use anyhow::Result;
use ignore::WalkBuilder;
use rayon::prelude::*;
use std::collections::HashSet;
use std::path::Path;
use std::path::{Path, PathBuf};
use crate::db::{self, Db};
use crate::parser::{self, Lang};
@@ -14,14 +14,40 @@ pub struct IndexStats {
pub files_unchanged: usize,
}
/// Find gitignored *_ee files (EE symlinks from windmill-ee-private).
fn find_ee_files(dir: &Path, out: &mut Vec<PathBuf>) {
let Ok(entries) = std::fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
let name = entry.file_name();
let name_str = name.to_str().unwrap_or("");
// path.is_dir() follows symlinks
if path.is_dir() {
if !matches!(name_str, "target" | "node_modules" | ".git") {
find_ee_files(&path, out);
}
} else if Lang::from_path(&path).is_some()
&& (name_str.ends_with("_ee.rs")
|| name_str.ends_with("_ee.ts")
|| name_str.ends_with("_ee.svelte"))
&& path.exists() // follows symlink, checks target exists
{
out.push(path);
}
}
}
/// Incrementally update the index for the given root directory.
/// Only re-parses files whose mtime has changed since last index.
pub fn update_index(db: &Db, root: &Path) -> Result<IndexStats> {
// Collect all supported files using `ignore` crate (respects .gitignore)
let files: Vec<_> = WalkBuilder::new(root)
let mut files: Vec<_> = WalkBuilder::new(root)
.hidden(true)
.git_ignore(true)
.git_global(false)
.follow_links(true)
.build()
.filter_map(|e| e.ok())
.filter(|e| e.file_type().map(|t| t.is_file()).unwrap_or(false))
@@ -29,6 +55,16 @@ pub fn update_index(db: &Db, root: &Path) -> Result<IndexStats> {
.map(|e| e.into_path())
.collect();
// Also include gitignored *_ee files (EE symlinks from windmill-ee-private)
let file_set: HashSet<_> = files.iter().cloned().collect();
let mut ee_files = Vec::new();
find_ee_files(root, &mut ee_files);
for f in ee_files {
if !file_set.contains(&f) {
files.push(f);
}
}
let disk_paths: HashSet<String> = files
.iter()
.map(|p| p.to_string_lossy().to_string())

View File

@@ -94,6 +94,13 @@ enum Command {
},
}
/// Get absolute path without resolving symlinks (canonicalize the parent, keep the filename).
fn absolute_no_symlink(p: &std::path::Path) -> Result<PathBuf> {
let parent = p.parent().unwrap_or(std::path::Path::new("."));
let parent = std::fs::canonicalize(parent)?;
Ok(parent.join(p.file_name().unwrap_or_default()))
}
fn main() -> Result<()> {
let cli = Cli::parse();
let root = cli
@@ -114,7 +121,7 @@ fn main() -> Result<()> {
);
}
Command::Outline { file } => {
let file = std::fs::canonicalize(&file)?;
let file = absolute_no_symlink(&file)?;
let symbols = db.file_symbols(&file.to_string_lossy())?;
if symbols.is_empty() {
println!("No symbols found");