Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/_quarto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ project:
- assets/**
- CNAME
- llms.txt
- schema.json
pre-render:
- uv run python generate_llms_txt.py

Expand Down
4 changes: 4 additions & 0 deletions vscode-sidemantic/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
out/
node_modules/
*.vsix
.vscode-test/
7 changes: 7 additions & 0 deletions vscode-sidemantic/.vscodeignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.vscode/**
.vscode-test/**
src/**
.gitignore
tsconfig.json
**/*.map
**/*.ts
56 changes: 56 additions & 0 deletions vscode-sidemantic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Sidemantic VS Code Extension

Language support for [Sidemantic](https://sidemantic.com) semantic layer definitions.

## Features

**For `.sidemantic.sql` files:**
- Syntax highlighting for MODEL, DIMENSION, METRIC, RELATIONSHIP, SEGMENT statements
- Autocompletion for keywords and properties
- Hover documentation
- Validation diagnostics

**For `.sidemantic.yaml` files:**
- JSON Schema validation via [YAML extension](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml)
- Autocompletion for all model/metric/dimension properties

## Requirements

Install the Sidemantic CLI with LSP support:

```bash
uv pip install sidemantic[lsp]
# or
pip install sidemantic[lsp]
```

For YAML support, install the [YAML extension](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml).

## Configuration

| Setting | Default | Description |
|---------|---------|-------------|
| `sidemantic.lsp.enabled` | `true` | Enable the language server |
| `sidemantic.lsp.path` | `sidemantic` | Path to sidemantic CLI |

## File Associations

- `*.sidemantic.sql` - Sidemantic SQL dialect (MODEL, METRIC, etc.)
- `*.sidemantic.yaml`, `*.sidemantic.yml`, `sidemantic.yaml` - YAML definitions

## Development

```bash
cd vscode-sidemantic
bun install
bun run compile
```

To test locally, press F5 in VS Code to launch the Extension Development Host.

## Publishing

```bash
bun run package # Creates .vsix file
vsce publish # Publish to marketplace (requires publisher token)
```
410 changes: 410 additions & 0 deletions vscode-sidemantic/bun.lock

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions vscode-sidemantic/language-configuration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"comments": {
"lineComment": "--",
"blockComment": ["/*", "*/"]
},
"brackets": [
["(", ")"],
["[", "]"]
],
"autoClosingPairs": [
{ "open": "(", "close": ")" },
{ "open": "[", "close": "]" },
{ "open": "'", "close": "'", "notIn": ["string"] },
{ "open": "\"", "close": "\"", "notIn": ["string"] }
],
"surroundingPairs": [
["(", ")"],
["[", "]"],
["'", "'"],
["\"", "\""]
]
}
85 changes: 85 additions & 0 deletions vscode-sidemantic/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"name": "sidemantic",
"displayName": "Sidemantic",
"description": "Language support for Sidemantic semantic layer definitions (SQL dialect and YAML)",
"version": "0.1.0",
"publisher": "sidequery",
"repository": {
"type": "git",
"url": "https://github.com/sidequery/sidemantic"
},
"license": "MIT",
"engines": {
"vscode": "^1.75.0"
},
"categories": [
"Programming Languages",
"Linters"
],
"keywords": [
"sidemantic",
"semantic layer",
"sql",
"yaml",
"metrics"
],
"activationEvents": [
"onLanguage:sidemantic-sql",
"workspaceContains:**/*.sidemantic.yaml",
"workspaceContains:**/*.sidemantic.yml"
],
"main": "./out/extension.js",
"contributes": {
"languages": [
{
"id": "sidemantic-sql",
"aliases": ["Sidemantic SQL", "sidemantic"],
"extensions": [".sidemantic.sql"],
"configuration": "./language-configuration.json"
}
],
"grammars": [
{
"language": "sidemantic-sql",
"scopeName": "source.sidemantic-sql",
"path": "./syntaxes/sidemantic-sql.tmLanguage.json"
}
],
"yamlValidation": [
{
"fileMatch": ["*.sidemantic.yaml", "*.sidemantic.yml", "sidemantic.yaml", "sidemantic.yml"],
"url": "https://sidemantic.com/schema.json"
}
],
"configuration": {
"title": "Sidemantic",
"properties": {
"sidemantic.lsp.enabled": {
"type": "boolean",
"default": true,
"description": "Enable the Sidemantic language server for .sidemantic.sql files"
},
"sidemantic.lsp.path": {
"type": "string",
"default": "sidemantic",
"description": "Path to the sidemantic CLI executable"
}
}
}
},
"scripts": {
"vscode:prepublish": "bun run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"package": "vsce package"
},
"devDependencies": {
"@types/node": "^20.0.0",
"@types/vscode": "^1.75.0",
"typescript": "^5.0.0",
"@vscode/vsce": "^2.0.0"
},
"dependencies": {
"vscode-languageclient": "^9.0.0"
}
}
69 changes: 69 additions & 0 deletions vscode-sidemantic/src/extension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import * as vscode from 'vscode';
import {
LanguageClient,
LanguageClientOptions,
ServerOptions,
TransportKind,
} from 'vscode-languageclient/node';

let client: LanguageClient | undefined;

export async function activate(context: vscode.ExtensionContext) {
const config = vscode.workspace.getConfiguration('sidemantic');

if (!config.get<boolean>('lsp.enabled', true)) {
return;
}

const command = config.get<string>('lsp.path', 'sidemantic');

const serverOptions: ServerOptions = {
command,
args: ['lsp'],
transport: TransportKind.stdio,
};

const clientOptions: LanguageClientOptions = {
documentSelector: [{ scheme: 'file', language: 'sidemantic-sql' }],
synchronize: {
fileEvents: vscode.workspace.createFileSystemWatcher('**/*.sidemantic.sql'),
},
};

client = new LanguageClient(
'sidemantic',
'Sidemantic Language Server',
serverOptions,
clientOptions
);

try {
await client.start();
} catch (error) {
const message =
error instanceof Error ? error.message : 'Unknown error';

if (message.includes('ENOENT') || message.includes('not found')) {
vscode.window
.showErrorMessage(
`Sidemantic CLI not found. Install with: uv pip install sidemantic[lsp]`,
'Copy Install Command'
)
.then((selection) => {
if (selection === 'Copy Install Command') {
vscode.env.clipboard.writeText('uv pip install sidemantic[lsp]');
vscode.window.showInformationMessage('Install command copied to clipboard');
}
});
} else {
vscode.window.showErrorMessage(`Failed to start Sidemantic LSP: ${message}`);
}
}
}

export function deactivate(): Thenable<void> | undefined {
if (!client) {
return undefined;
}
return client.stop();
}
90 changes: 90 additions & 0 deletions vscode-sidemantic/syntaxes/sidemantic-sql.tmLanguage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "Sidemantic SQL",
"scopeName": "source.sidemantic-sql",
"patterns": [
{ "include": "#comments" },
{ "include": "#keywords" },
{ "include": "#properties" },
{ "include": "#strings" },
{ "include": "#numbers" },
{ "include": "#operators" }
],
"repository": {
"comments": {
"patterns": [
{
"name": "comment.line.double-dash.sidemantic-sql",
"match": "--.*$"
},
{
"name": "comment.block.sidemantic-sql",
"begin": "/\\*",
"end": "\\*/"
}
]
},
"keywords": {
"patterns": [
{
"name": "keyword.control.sidemantic-sql",
"match": "\\b(MODEL|DIMENSION|METRIC|RELATIONSHIP|SEGMENT)\\b"
},
{
"name": "keyword.other.sidemantic-sql",
"match": "\\b(AS|FROM|WHERE|AND|OR|NOT|IN|IS|NULL|TRUE|FALSE|JOIN|ON|LEFT|RIGHT|INNER|OUTER|FULL|CROSS|GROUP|BY|ORDER|HAVING|LIMIT|OFFSET|UNION|INTERSECT|EXCEPT|CASE|WHEN|THEN|ELSE|END|DISTINCT|ALL|ANY|EXISTS|BETWEEN|LIKE|ILIKE)\\b"
}
]
},
"properties": {
"patterns": [
{
"name": "variable.other.property.sidemantic-sql",
"match": "\\b(name|table|primary_key|sql|agg|type|description|dimensions|metrics|format|label|hidden|model|from_column|to_column|to_model|filter|base_metric|comparison_type|numerator|denominator|entity|base_event|conversion_event|window|grain|measure|type_params|time_dimension|default_time_dimension|timestamp_column|timestamp_granularity)\\b"
}
]
},
"strings": {
"patterns": [
{
"name": "string.quoted.single.sidemantic-sql",
"begin": "'",
"end": "'",
"patterns": [
{
"name": "constant.character.escape.sidemantic-sql",
"match": "\\\\."
}
]
},
{
"name": "string.quoted.double.sidemantic-sql",
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape.sidemantic-sql",
"match": "\\\\."
}
]
}
]
},
"numbers": {
"patterns": [
{
"name": "constant.numeric.sidemantic-sql",
"match": "\\b\\d+(\\.\\d+)?\\b"
}
]
},
"operators": {
"patterns": [
{
"name": "keyword.operator.sidemantic-sql",
"match": "(=|<>|!=|<|>|<=|>=|\\+|-|\\*|/|%|\\|\\||&&)"
}
]
}
}
}
14 changes: 14 additions & 0 deletions vscode-sidemantic/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "ES2020",
"outDir": "out",
"lib": ["ES2020"],
"sourceMap": true,
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"exclude": ["node_modules", ".vscode-test"]
}