docs/plugins/development/language-packs.md
Language packs add syntax highlighting, language configuration, and LSP support for new languages in Fresh.
Use the CLI to scaffold a new language pack:
fresh --init language
This creates a directory with the basic structure:
my-language/
├── package.json # Package manifest
├── grammars/
│ └── syntax.sublime-syntax # Sublime syntax grammar (YAML)
├── validate.sh # Validation script
└── README.md
The manifest configures the language pack:
{
"$schema": "https://raw.githubusercontent.com/sinelaw/fresh/main/crates/fresh-editor/plugins/schemas/package.schema.json",
"name": "my-language",
"version": "0.1.0",
"description": "Language support for MyLang",
"type": "language",
"author": "Your Name",
"license": "MIT",
"fresh": {
"grammar": {
"file": "grammars/syntax.sublime-syntax",
"extensions": ["mylang", "ml"]
},
"language": {
"commentPrefix": "//",
"blockCommentStart": "/*",
"blockCommentEnd": "*/",
"tabSize": 4,
"autoIndent": true
},
"lsp": {
"command": "my-language-server",
"args": ["--stdio"],
"autoStart": true
}
}
}
| Field | Description |
|---|---|
file | Path to the grammar file (relative to package root) |
extensions | File extensions this grammar handles (without dots) |
firstLine | Optional regex for shebang detection |
| Field | Description |
|---|---|
commentPrefix | Line comment prefix (e.g., //, #, --) |
blockCommentStart | Block comment opening (e.g., /*, <!--) |
blockCommentEnd | Block comment closing (e.g., */, -->) |
tabSize | Default indentation width |
useTabs | Use tabs instead of spaces |
autoIndent | Enable automatic indentation |
formatter.command | Formatter command (e.g., prettier, rustfmt) |
formatter.args | Arguments for the formatter (file path is passed automatically) |
Formatter Examples:
// Prettier (JavaScript/TypeScript/etc.)
"formatter": {
"command": "prettier",
"args": ["--write"]
}
// Prettier with plugin (Svelte, Vue, etc.)
"formatter": {
"command": "prettier",
"args": ["--write", "--plugin", "prettier-plugin-svelte"]
}
// Black (Python)
"formatter": {
"command": "black",
"args": ["-"]
}
// rustfmt (Rust)
"formatter": {
"command": "rustfmt",
"args": []
}
// gofmt (Go)
"formatter": {
"command": "gofmt",
"args": ["-w"]
}
Note: The file path is automatically appended to the args by Fresh. Some formatters expect stdin (use "-" as arg), others expect file path.
| Field | Description |
|---|---|
command | LSP server executable (e.g., rust-analyzer, typescript-language-server) |
args | Arguments to pass to the server (e.g., ["--stdio"]) |
autoStart | Start server when opening matching files |
initializationOptions | Custom LSP initialization options (language-specific JSON) |
Finding LSP Servers:
Common LSP Servers:
| Language | Server | Command | Installation |
|---|---|---|---|
| Rust | rust-analyzer | rust-analyzer | rustup component add rust-analyzer |
| TypeScript/JavaScript | typescript-language-server | typescript-language-server | npm install -g typescript-language-server |
| Python | pyright | pyright-langserver | npm install -g pyright |
| Go | gopls | gopls | go install golang.org/x/tools/gopls@latest |
| C/C++ | clangd | clangd | System package manager |
Example with initialization options:
"lsp": {
"command": "rust-analyzer",
"args": [],
"autoStart": true,
"initializationOptions": {
"cargo": {
"buildScripts": {
"enable": true
}
}
}
}
Before writing a grammar from scratch, search online for existing Sublime Text or TextMate grammars:
<language> sublime-syntax or <language> tmLanguageImportant: Fresh supports a subset of sublime-syntax features. Before using a grammar, check that it:
Will NOT work:
extends: Packages/... directive (grammar inheritance)Will work:
include for internal contextsExamples of compatible grammars:
extendsTo test compatibility:
Try installing your language pack locally (see Testing section below) and check the logs for parse errors.
If you find a grammar that uses extends, you'll need to either:
When using an existing grammar:
grammars/ directory (e.g., grammars/LICENSE)Example attribution in README:
## Grammar Attribution
The syntax grammar is derived from [original-package](https://github.com/user/repo)
by Original Author, licensed under MIT. See `grammars/LICENSE` for details.
Fresh uses Sublime Text's .sublime-syntax format (YAML-based).
Recommendation: Start with an existing grammar from fresh-plugins/languages and adapt it for your language, rather than writing from scratch.
%YAML 1.2
---
name: My Language
scope: source.mylang
file_extensions: [mylang, ml]
contexts:
main:
# Line comments
- match: //.*$
scope: comment.line
# Strings
- match: '"'
scope: string.quoted.double
push:
- match: '"'
pop: true
- match: \\.
scope: constant.character.escape
# Keywords
- match: \b(if|else|while|for|return)\b
scope: keyword.control
Official documentation:
Browse complete, tested grammars in the fresh-plugins repository:
See the Solidity language pack:
languages/solidity/
├── package.json
├── grammars/
│ ├── solidity.sublime-syntax
│ └── LICENSE
├── validate.sh
└── README.md
See the Templ language pack for a complete, self-contained grammar example:
%YAML 1.2
---
name: Templ
scope: source.templ
version: 2
file_extensions:
- templ
variables:
ident: '[a-zA-Z_][a-zA-Z0-9_]*'
contexts:
main:
# All grammar rules defined inline
# No external dependencies
The fastest way to test your language pack during development:
Ctrl+P then type >package and select "Package: Install from URL"/path/to/your-language-pack~/.config/fresh/grammars/<package-name>/./validate.sh in your package directoryAlways validate your package before publishing:
# Validate package.json schema
./validate.sh
# Test by installing locally and checking logs
# (see Troubleshooting section for log commands)
# Show log locations
fresh --show-paths
# View Fresh logs (check for grammar parse errors)
tail -f ~/.local/state/fresh/logs/fresh-*.log
# Check LSP logs
tail -f ~/.local/state/fresh/logs/lsp/<language>-*.log
# Validate package.json
./validate.sh
Syntax highlighting not working:
Failed to parse grammar - most often caused by extends directive (see compatibility warning)["py"] not [".py"]LSP server not starting:
which <server-command>Formatter not working:
which <formatter><formatter> <args> <file>languages.jsonAfter approval, users can install via the command palette:
Ctrl+P then type >package and select "Package: Install from URL"Users can also install directly from your git repository:
# In Fresh command palette
Package: Install from URL
# Then enter: https://github.com/username/your-language-pack