Repository navigation
VS Code extension: Lineage panel ignores the active editor on Windows (case/separator-sensitive full_path comparison) #6172
Description
Description
On Windows, the lineage panel of the SQLMesh VS Code extension always shows the same model. Switching to another model file does nothing: the graph doesn't update, nothing is logged and no error appears.
It only works in one direction:
- Graph → file: clicking a node opens the right SQL file ✅
- File → graph: opening or focusing a model file doesn't select that model in the lineage panel ❌
The cause is in the webview bundle. It finds the model for the active file with a strict string comparison (===) between model.full_path and the active file path reported by the extension. On Windows the two strings can differ in path separators (\ vs /) and/or in casing (e.g. drive letter c: vs C:), so no model ever matches.
Graph → file still works because VS Code opens full_path no matter how it is cased or separated.
Environment
- OS: Windows 11
- VS Code: 1.144.0
- SQLMesh VS Code extension: (version from the Extensions view)
- sqlmesh: 0.235.4 (
sqlmesh[lsp]) - Python: 3.12.4 (venv)
- Project: single SQLMesh project, workspace folder = project root (containing
config.yaml), ~500 models
Steps to reproduce
- On Windows, open a SQLMesh project folder in VS Code with the SQLMesh extension installed.
- Wait until the language server is ready (
SQLMesh extension activatedin the output channel). - Open model file A and open the lineage panel. The panel shows some model (often the first one in the list, not A).
- Switch the editor to model file B.
Expected: the lineage panel switches to model B.
Actual: the panel stays on the same model. Nothing shows up in the extension output, the LSP output or the webview developer console.
Root cause
The compiled webview bundle has two places that compare paths strictly:
1. Initial model selection (via get_active_file)
const L = await M("get_active_file", {});
if (!L.fileUri) return D[0].name;
const G = L.fileUri,
U = D.find(Z => Z.full_path ? Z.full_path === G : !1);
if (U) return U.name;2. Focus change listener (changeFocusedFile)
const _ = U => {
const Z = Object.values(N).find(Q => Q.full_path === U.fileUri);
Z && h(Z.name);
};
// ...
L = d("changeFocusedFile", _)full_path comes from the Python side (pathlib, e.g. C:\...\models\core\dim_product.sql). fileUri comes from VS Code, which uses a lowercase drive letter on Windows (e.g. c:\...). With ===, these never match. U / Z stay undefined and the selection is silently skipped.
Verified workaround
Normalizing both sides before comparing fixes the problem completely (separators to /, then lowercase). I patched the bundled webview JS locally like this, and the panel now follows the active editor as expected:
- U = D.find(Z => Z.full_path ? Z.full_path === G : !1);
+ const norm = x => String(x).split(String.fromCharCode(92)).join("/").toLowerCase();
+ U = D.find(Z => Z.full_path ? norm(Z.full_path) === norm(G) : !1);- const Z = Object.values(N).find(Q => Q.full_path === U.fileUri);
+ const Z = Object.values(N).find(Q => !!Q.full_path && norm(Q.full_path) === norm(U.fileUri));(String.fromCharCode(92) is just a backslash. It avoids escaping problems when patching the minified file from a shell.)
URI decoding was not needed. Normalizing separators and casing was enough, so fileUri already arrives as a filesystem path and not as a file:///c%3A/... URI.
Activity