Skip to content

Commit 5becb9b

Browse files
committed
feat: add file navigation support
1 parent 6d54190 commit 5becb9b

6 files changed

Lines changed: 218 additions & 19 deletions

File tree

README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
# Expr Language Support
22

3-
VS Code extension for [Expr](https://github.com/expr-lang/expr) language with syntax highlighting, intelligent formatting, and rainbow brackets.
3+
VS Code extension for [Expr](https://github.com/expr-lang/expr) language with syntax highlighting, intelligent formatting, rainbow brackets, and file navigation.
44

55
## Features
66

77
-**Syntax Highlighting** - Full support for Expr language constructs
88
- 🌈 **Rainbow Brackets** - Color-coded parentheses by nesting depth
99
- 🎨 **Smart Formatting** - Auto-format with intelligent spacing and indentation
10+
- 🔗 **File Navigation** - Click `"*.expr"` strings to jump to referenced files
1011

1112
## Installation
1213

13-
```bash
14-
code --install-extension expr-lang-support-0.3.0.vsix
15-
```
14+
**From VS Code Marketplace:**
15+
16+
1. Open VS Code Extensions (`Ctrl+Shift+X` or `Cmd+Shift+X`)
17+
2. Search for "Expr Lang - Syntax & Formatter"
18+
3. Click Install
1619

17-
Or in VS Code: `Extensions``...``Install from VSIX...`
20+
Or visit the [VS Code Marketplace](https://marketplace.visualstudio.com/vscode)
1821

1922
## Usage
2023

@@ -29,7 +32,7 @@ Create a `.expr` file and start coding! Formatting: `Shift+Alt+F` (Windows/Linux
2932
"expr.rainbowBrackets.enabled": true,
3033
"[expr]": {
3134
"editor.formatOnSave": true,
32-
"editor.defaultFormatter": "daangn.expr-lang-support"
35+
"editor.defaultFormatter": "daangn-ml-data-platform.expr-lang-support"
3336
}
3437
}
3538
```

packages/vscode/README.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,23 @@ Complete language support for Expr language - syntax highlighting, intelligent f
3737
- Handles `#`, `//`, and `/* */` style comments
3838
- **Format on save** support (enabled by default)
3939

40-
## Installation
40+
### 🔗 Expr File Navigation
41+
- **Go to Definition**: Cmd+Click (Mac) / Ctrl+Click (Windows) or F12 on `"*.expr"` strings to open referenced files
42+
- **Link Highlighting**: `.expr` file references are automatically highlighted as clickable links
43+
- **Works everywhere**: Supports file references in any file type (Markdown, JSON, YAML, etc.)
44+
- **Relative paths**: Supports relative paths like `"../data/input.expr"` or `"./config.expr"`
45+
- **Tooltip preview**: Hover to see the file path
4146

42-
### Install from code
47+
## Installation
4348

44-
```bash
45-
npm run package:vscod
46-
code --install-extension expr-lang-support-0.3.0.vsix
47-
```
49+
### From VS Code Marketplace
4850

49-
### VS Code Marketplace
51+
1. Open VS Code
52+
2. Press `Ctrl+Shift+X` (Windows/Linux) or `Cmd+Shift+X` (Mac) to open Extensions
53+
3. Search for "Expr Lang - Syntax & Formatter"
54+
4. Click Install
5055

51-
Search the "Expr Language Support" in the Marketplace tab, and install the extension.
56+
Or visit the [VS Code Marketplace](https://marketplace.visualstudio.com/vscode)
5257

5358
## Usage
5459

@@ -237,7 +242,7 @@ npm run watch
237242
```json
238243
{
239244
"[expr]": {
240-
"editor.defaultFormatter": "daangn.expr-lang-support"
245+
"editor.defaultFormatter": "daangn-ml-data-platform.expr-lang-support"
241246
}
242247
}
243248
```

packages/vscode/out/extension.js

Lines changed: 80 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/vscode/out/extension.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/vscode/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "expr-lang-support",
33
"displayName": "Expr Lang - Syntax & Formatter",
44
"description": "Syntax highlighting and formatting for Expr language (.expr files)",
5-
"version": "0.3.0",
5+
"version": "0.4.0",
66
"publisher": "daangn-ml-data-platform",
77
"repository": {
88
"type": "git",

packages/vscode/src/extension.ts

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as vscode from 'vscode';
2+
import * as path from 'path';
23
import { format } from './formatter';
34

45
// Rainbow bracket colors - optimized for readability
@@ -236,6 +237,101 @@ function updateIndentGuides(editor: vscode.TextEditor | undefined) {
236237
}
237238
}
238239

240+
class ExprFileLinkProvider implements vscode.DocumentLinkProvider {
241+
provideDocumentLinks(
242+
document: vscode.TextDocument
243+
): vscode.DocumentLink[] | undefined {
244+
const links: vscode.DocumentLink[] = [];
245+
const text = document.getText();
246+
247+
// Match quoted strings containing .expr files
248+
const regex = /["']([^"']+\.expr)["']/g;
249+
let match;
250+
251+
while ((match = regex.exec(text)) !== null) {
252+
const filePath = match[1];
253+
const startPos = document.positionAt(match.index + 1); // +1 to skip opening quote
254+
const endPos = document.positionAt(match.index + 1 + filePath.length);
255+
const range = new vscode.Range(startPos, endPos);
256+
257+
try {
258+
// Resolve file path relative to current document
259+
const currentDir = path.dirname(document.uri.fsPath);
260+
const fullPath = path.resolve(currentDir, filePath);
261+
const fileUri = vscode.Uri.file(fullPath);
262+
263+
// Create document link
264+
const link = new vscode.DocumentLink(range, fileUri);
265+
link.tooltip = `Open ${filePath}`;
266+
links.push(link);
267+
} catch (error) {
268+
console.error('[ExprLink] Error resolving expr file path:', error);
269+
}
270+
}
271+
272+
return links;
273+
}
274+
}
275+
276+
class ExprFileDefinitionProvider implements vscode.DefinitionProvider {
277+
provideDefinition(
278+
document: vscode.TextDocument,
279+
position: vscode.Position
280+
): vscode.ProviderResult<vscode.Definition | vscode.LocationLink[]> {
281+
console.log('[ExprDef] provideDefinition called at', position.line, position.character);
282+
283+
const line = document.lineAt(position.line);
284+
const lineText = line.text;
285+
console.log('[ExprDef] Line text:', lineText);
286+
287+
// Scan the entire line for .expr files and find the one under cursor
288+
const regex = /["']([^"']+\.expr)["']/g;
289+
let match;
290+
291+
while ((match = regex.exec(lineText)) !== null) {
292+
const filePath = match[1];
293+
const matchStart = match.index + 1; // +1 to skip opening quote
294+
const matchEnd = matchStart + filePath.length;
295+
296+
console.log('[ExprDef] Checking match:', filePath, 'range:', matchStart, '-', matchEnd);
297+
298+
// Check if cursor is within this match (including the filename)
299+
if (position.character >= matchStart && position.character <= matchEnd) {
300+
console.log('[ExprDef] Cursor is within match!');
301+
302+
try {
303+
// Resolve file path relative to current document
304+
const currentDir = path.dirname(document.uri.fsPath);
305+
const fullPath = path.resolve(currentDir, filePath);
306+
const fileUri = vscode.Uri.file(fullPath);
307+
308+
console.log('[ExprDef] Resolved full path:', fullPath);
309+
310+
// Create the range for the entire filename (without quotes)
311+
const originSelectionRange = new vscode.Range(
312+
new vscode.Position(position.line, matchStart),
313+
new vscode.Position(position.line, matchEnd)
314+
);
315+
316+
// Return LocationLink with explicit range for better hover UX
317+
return [{
318+
originSelectionRange: originSelectionRange,
319+
targetUri: fileUri,
320+
targetRange: new vscode.Range(0, 0, 0, 0),
321+
targetSelectionRange: new vscode.Range(0, 0, 0, 0)
322+
}];
323+
} catch (error) {
324+
console.error('[ExprDef] Error resolving expr file path:', error);
325+
return undefined;
326+
}
327+
}
328+
}
329+
330+
console.log('[ExprDef] No match found');
331+
return undefined;
332+
}
333+
}
334+
239335
export function activate(context: vscode.ExtensionContext) {
240336
console.log('Expr language extension activated');
241337

@@ -311,12 +407,28 @@ export function activate(context: vscode.ExtensionContext) {
311407
}
312408
});
313409

410+
// Register document link provider for .expr file highlighting
411+
// Makes .expr files appear as clickable links in all file types
412+
const linkProvider = vscode.languages.registerDocumentLinkProvider(
413+
{ scheme: 'file' },
414+
new ExprFileLinkProvider()
415+
);
416+
417+
// Register definition provider for .expr file navigation
418+
// Works in all file types (markdown, plaintext, etc.)
419+
const definitionProvider = vscode.languages.registerDefinitionProvider(
420+
{ scheme: 'file' },
421+
new ExprFileDefinitionProvider()
422+
);
423+
314424
context.subscriptions.push(
315425
formatterProvider,
316426
formatCommand,
317427
editorChangeListener,
318428
documentChangeListener,
319-
configChangeListener
429+
configChangeListener,
430+
linkProvider,
431+
definitionProvider
320432
);
321433
}
322434

0 commit comments

Comments
 (0)