> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/sinelaw/fresh/llms.txt
> Use this file to discover all available pages before exploring further.

# Language Pack Development

> Create syntax highlighting, LSP support, and language configuration for new languages in Fresh

Language packs extend Fresh with support for new programming languages. They provide syntax highlighting, language-specific configuration, and LSP integration.

## Quick Start

Scaffold a new language pack using the Fresh CLI:

```bash theme={null}
fresh --init language
```

This creates a complete package structure:

```
my-language/
├── package.json          # Package manifest
├── grammars/
│   └── syntax.sublime-syntax  # Sublime syntax grammar (YAML)
├── validate.sh           # Validation script
└── README.md
```

## Package Structure

### Package Manifest

The `package.json` configures all aspects of your language pack:

```json theme={null}
{
  "$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
    }
  }
}
```

<Note>
  The `$schema` field enables validation and autocomplete in editors that support JSON Schema.
</Note>

### Grammar Configuration

The `grammar` section tells Fresh how to syntax-highlight your language:

| Field        | Type      | Description                                                  |
| ------------ | --------- | ------------------------------------------------------------ |
| `file`       | string    | Path to grammar file (relative to package root)              |
| `extensions` | string\[] | File extensions without dots (e.g., `["py", "pyw"]`)         |
| `firstLine`  | string    | Optional regex for shebang detection (e.g., `"^#!.*python"`) |

<Warning>
  Use `["py"]` not `[".py"]` - extensions should NOT include the dot.
</Warning>

### Language Configuration

The `language` section configures editor behavior for your language:

| Field               | Type      | Description                                             |
| ------------------- | --------- | ------------------------------------------------------- |
| `commentPrefix`     | string    | Line comment prefix (e.g., `//`, `#`, `--`)             |
| `blockCommentStart` | string    | Block comment opening (e.g., `/*`, `<!--`)              |
| `blockCommentEnd`   | string    | Block comment closing (e.g., `*/`, `-->`)               |
| `tabSize`           | number    | Default indentation width (e.g., `4`, `2`)              |
| `useTabs`           | boolean   | Use tabs instead of spaces for indentation              |
| `autoIndent`        | boolean   | Enable automatic indentation                            |
| `formatter.command` | string    | Formatter executable (e.g., `prettier`, `rustfmt`)      |
| `formatter.args`    | string\[] | Arguments for formatter (file path added automatically) |

### Formatter Examples

<CodeGroup>
  ```json JavaScript/TypeScript (Prettier) theme={null}
  "formatter": {
    "command": "prettier",
    "args": ["--write"]
  }
  ```

  ```json Svelte/Vue (Prettier with plugin) theme={null}
  "formatter": {
    "command": "prettier",
    "args": ["--write", "--plugin", "prettier-plugin-svelte"]
  }
  ```

  ```json Python (Black) theme={null}
  "formatter": {
    "command": "black",
    "args": ["-"]
  }
  ```

  ```json Rust (rustfmt) theme={null}
  "formatter": {
    "command": "rustfmt",
    "args": []
  }
  ```

  ```json Go (gofmt) theme={null}
  "formatter": {
    "command": "gofmt",
    "args": ["-w"]
  }
  ```
</CodeGroup>

<Note>
  The file path is automatically appended to args. Some formatters expect stdin (use `"-"` as arg), others expect a file path.
</Note>

## LSP Integration

The `lsp` section configures Language Server Protocol support:

| Field                   | Type      | Description                                            |
| ----------------------- | --------- | ------------------------------------------------------ |
| `command`               | string    | LSP server executable name or path                     |
| `args`                  | string\[] | Command-line arguments (e.g., `["--stdio"]`)           |
| `autoStart`             | boolean   | Start server automatically when opening matching files |
| `initializationOptions` | object    | Custom LSP initialization options (language-specific)  |

### Finding LSP Servers

<CardGroup cols={2}>
  <Card title="Official LSP Registry" icon="book" href="https://microsoft.github.io/language-server-protocol/implementors/servers/">
    Microsoft's official list of LSP implementations
  </Card>

  <Card title="langserver.org" icon="globe" href="https://langserver.org/">
    Community-maintained directory of language servers
  </Card>
</CardGroup>

### 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                                      |
| Ruby                  | solargraph                 | `solargraph`                 | `gem install solargraph`                                    |
| Java                  | jdtls                      | `jdtls`                      | [Eclipse JDT LS](https://github.com/eclipse/eclipse.jdt.ls) |

### Advanced LSP Configuration

Some language servers accept custom initialization options:

```json theme={null}
"lsp": {
  "command": "rust-analyzer",
  "args": [],
  "autoStart": true,
  "initializationOptions": {
    "cargo": {
      "buildScripts": {
        "enable": true
      }
    },
    "procMacro": {
      "enable": true
    }
  }
}
```

<Tip>
  Check your language server's documentation for available initialization options. These vary by server.
</Tip>

## Grammar Development

Fresh uses Sublime Text's `.sublime-syntax` format (YAML-based) for syntax highlighting.

### Finding Existing Grammars

Before writing a grammar from scratch, search for existing ones:

<Steps>
  <Step title="Search GitHub">
    Look for `<language> sublime-syntax` or `<language> tmLanguage`
  </Step>

  <Step title="Check VS Code Extensions">
    Many VS Code extensions use TextMate or Sublime grammars that you can adapt
  </Step>

  <Step title="Browse Package Control">
    Visit [packagecontrol.io](https://packagecontrol.io/) for Sublime Text packages
  </Step>
</Steps>

### Grammar Compatibility

<Warning>
  Fresh supports a **subset** of sublime-syntax features. Not all grammars will work.
</Warning>

**Will NOT work:**

* Grammars using `extends: Packages/...` directive (grammar inheritance)
* References to external grammars or packages
* Dependencies on other grammar files

**Will work:**

* Standalone, self-contained grammars
* Grammars using only `include` for internal contexts
* No external dependencies

**Compatible examples:**

* See [fresh-plugins/languages](https://github.com/sinelaw/fresh-plugins/tree/main/languages) for working examples (templ, hare, solidity)
* Standalone grammars from Package Control that don't use `extends`

### Testing Compatibility

Install your language pack locally (see [Testing](#testing-and-local-development)) and check logs:

```bash theme={null}
tail -f ~/.local/state/fresh/logs/fresh-*.log
```

Look for `Failed to parse grammar` errors.

### Attribution Requirements

When using an existing grammar:

<Steps>
  <Step title="Check the License">
    Ensure it allows redistribution (MIT, Apache, BSD are common)
  </Step>

  <Step title="Include License File">
    Copy the license to `grammars/LICENSE`
  </Step>

  <Step title="Credit Original Author">
    Add attribution to your README and package description
  </Step>
</Steps>

**Example attribution:**

```markdown theme={null}
## 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.
```

### Writing Grammars from Scratch

<Note>
  **Recommendation:** Start with an existing grammar from [fresh-plugins/languages](https://github.com/sinelaw/fresh-plugins/tree/main/languages) and adapt it, rather than writing from scratch.
</Note>

#### Minimal Example

```yaml theme={null}
%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
```

#### Documentation Resources

<CardGroup cols={2}>
  <Card title="Sublime Syntax Reference" icon="book" href="https://www.sublimetext.com/docs/syntax.html">
    Complete format specification
  </Card>

  <Card title="Scope Naming Guide" icon="tag" href="https://www.sublimetext.com/docs/scope_naming.html">
    Standard scope names for syntax elements
  </Card>

  <Card title="TextMate Grammars" icon="scroll" href="https://macromates.com/manual/en/language_grammars">
    Additional background information
  </Card>

  <Card title="Working Examples" icon="code" href="https://github.com/sinelaw/fresh-plugins/tree/main/languages">
    Real grammars from fresh-plugins
  </Card>
</CardGroup>

### Complete Working Example

From the [Templ language pack](https://github.com/sinelaw/fresh-plugins/tree/main/languages/templ):

```yaml theme={null}
%YAML 1.2
---
name: Templ
scope: source.templ
version: 2

file_extensions:
  - templ

variables:
  ident: '[a-zA-Z_][a-zA-Z0-9_]*'

contexts:
  main:
    # Templ component declaration
    - match: '\b(templ)\s+({{ident}})'
      captures:
        1: keyword.declaration.templ
        2: entity.name.function.templ
      push: component_params

    # Go code blocks
    - match: '\{%'
      scope: punctuation.section.embedded.begin.templ
      push: go_code

  component_params:
    - match: '\('
      scope: punctuation.section.parens.begin
      set: param_list

  param_list:
    - match: '\)'
      scope: punctuation.section.parens.end
      pop: true
    - match: '{{ident}}'
      scope: variable.parameter.templ

  go_code:
    - match: '%\}'
      scope: punctuation.section.embedded.end.templ
      pop: true
    # Include Go syntax rules here...
```

## Testing and Local Development

### Testing with Local Path (Recommended)

The fastest way to test during development:

<Steps>
  <Step title="Open Fresh">
    Open Fresh with a test file for your language
  </Step>

  <Step title="Open Command Palette">
    Press `Ctrl+P` then type `>`
  </Step>

  <Step title="Install from Local Path">
    Type `package` and select "Package: Install from URL"

    Enter the full path to your language pack directory:

    ```
    /path/to/your-language-pack
    ```
  </Step>

  <Step title="Check for Errors">
    Open command palette and run "Show Warnings"

    Look for grammar parse errors or missing files
  </Step>

  <Step title="Iterate">
    Edit your grammar, then reinstall from the same local path to reload
  </Step>
</Steps>

### Alternative: Manual Installation

<Steps>
  <Step title="Copy Package">
    ```bash theme={null}
    cp -r your-language-pack ~/.config/fresh/grammars/my-language/
    ```
  </Step>

  <Step title="Validate Manifest">
    ```bash theme={null}
    cd your-language-pack
    ./validate.sh
    ```
  </Step>

  <Step title="Restart Fresh">
    Restart Fresh to load the new grammar
  </Step>
</Steps>

### Validation

Always validate before publishing:

```bash theme={null}
# Validate package.json schema
./validate.sh

# Test by installing locally
fresh  # Open Fresh and install from local path

# Check logs for errors
tail -f ~/.local/state/fresh/logs/fresh-*.log
```

## Troubleshooting

### Debugging Commands

```bash theme={null}
# 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
```

### Common Issues

<AccordionGroup>
  <Accordion title="Syntax highlighting not working">
    **Possible causes:**

    1. **Grammar uses `extends` directive** - Most common issue. Fresh doesn't support grammar inheritance.
       * Check logs for `Failed to parse grammar`
       * Find a standalone grammar or manually merge the base grammar

    2. **Wrong file extension format** - Use `["py"]` not `[".py"]`
       ```json theme={null}
       "extensions": ["py", "pyw"]  // ✓ Correct
       "extensions": [".py", ".pyw"]  // ✗ Wrong
       ```

    3. **Incorrect grammar file path** - Check that the path in `package.json` matches the actual file location
       ```json theme={null}
       "file": "grammars/syntax.sublime-syntax"  // Must match actual path
       ```
  </Accordion>

  <Accordion title="LSP server not starting">
    **Debugging steps:**

    1. **Verify server is installed:**
       ```bash theme={null}
       which rust-analyzer  # or your server command
       ```

    2. **Check LSP logs:**
       ```bash theme={null}
       tail -f ~/.local/state/fresh/logs/lsp/<language>-*.log
       ```

    3. **Test server manually:**
       ```bash theme={null}
       rust-analyzer --version
       ```

    4. **Check LSP registry** - Verify correct command and args at [microsoft.github.io/language-server-protocol](https://microsoft.github.io/language-server-protocol/implementors/servers/)
  </Accordion>

  <Accordion title="Formatter not working">
    **Debugging steps:**

    1. **Verify formatter is installed:**
       ```bash theme={null}
       which prettier  # or your formatter
       ```

    2. **Test formatter manually:**
       ```bash theme={null}
       prettier --write test.js
       ```

    3. **Check formatter documentation** - Ensure you're using correct arguments
       * Some formatters need stdin: `["-"]`
       * Others need file path: `["--write"]` (path added automatically)

    4. **Check Fresh logs** for formatter errors
  </Accordion>

  <Accordion title="Package validation fails">
    **Common validation errors:**

    1. **Invalid JSON** - Use a JSON validator or editor with schema support

    2. **Missing required fields:**
       ```json theme={null}
       {
         "name": "required",
         "version": "required",
         "type": "language"  // must be "language" for language packs
       }
       ```

    3. **Invalid schema URL** - Copy the exact URL from working examples
  </Accordion>
</AccordionGroup>

## Publishing

Once your language pack is tested and working:

<Steps>
  <Step title="Push to Git Repository">
    Create a public Git repository (GitHub, GitLab, etc.) and push your package
  </Step>

  <Step title="Submit to Registry">
    Submit a PR to [fresh-plugins-registry](https://github.com/sinelaw/fresh-plugins-registry)

    Add your package to `languages.json`:

    ```json theme={null}
    {
      "name": "my-language",
      "description": "Language support for MyLang",
      "repository": "https://github.com/username/fresh-mylang",
      "version": "0.1.0"
    }
    ```
  </Step>

  <Step title="Wait for Approval">
    Maintainers will review your submission. Once merged, users can install via the command palette.
  </Step>
</Steps>

### User Installation

After your package is in the registry, users can install it:

<Steps>
  <Step title="Open Command Palette">
    Press `Ctrl+P` then type `>`
  </Step>

  <Step title="Select Install Command">
    Type `package` and select "Package: Install from URL"
  </Step>

  <Step title="Enter Package Name">
    Type your package name or Git URL:

    ```
    my-language
    ```

    or

    ```
    https://github.com/username/fresh-mylang
    ```
  </Step>
</Steps>

## Examples

<CardGroup cols={2}>
  <Card title="Solidity" icon="code" href="https://github.com/sinelaw/fresh-plugins/tree/main/languages/solidity">
    Minimal example - just grammar and basic config
  </Card>

  <Card title="Templ" icon="file-code" href="https://github.com/sinelaw/fresh-plugins/tree/main/languages/templ">
    Complete self-contained grammar with no external dependencies
  </Card>

  <Card title="Hare" icon="language" href="https://github.com/sinelaw/fresh-plugins/tree/main/languages/hare">
    Systems language with LSP integration
  </Card>

  <Card title="Fresh Plugins Registry" icon="book-open" href="https://github.com/sinelaw/fresh-plugins-registry">
    Browse all published language packs
  </Card>
</CardGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Plugin Development" icon="puzzle-piece" href="/plugins">
    Learn how to build plugins with custom functionality
  </Card>

  <Card title="Sublime Syntax Docs" icon="book" href="https://www.sublimetext.com/docs/syntax.html">
    Master the grammar format
  </Card>

  <Card title="LSP Specification" icon="server" href="https://microsoft.github.io/language-server-protocol/">
    Understand the Language Server Protocol
  </Card>

  <Card title="Example Grammars" icon="github" href="https://github.com/sinelaw/fresh-plugins/tree/main/languages">
    Study working language packs
  </Card>
</CardGroup>
