# How to Configure Language Server Protocol (LSP) for Various Programming Languages in Flow Control

> Easily configure Language Server Protocol LSP for multiple programming languages in Flow Control. Auto-detects file types and offers JSON overrides for seamless integration.

- Repository: [CJ van den Berg/flow](https://github.com/neurocyte/flow)
- Tags: how-to-guide
- Published: 2026-03-08

---

**Flow Control automatically detects file types and launches the appropriate language server based on mappings defined in `src/file_type_lsp.zig`, while allowing users to override commands via JSON configuration files.**

To configure Language Server Protocol (LSP) for various programming languages in Flow Control, you work with the **neurocyte/flow** repository's built-in file type definitions and optional JSON override files. Flow Control handles LSP integration natively without external plugins, detecting file types automatically and spawning language servers according to predefined commands that you can customize globally or per-project.

## Understanding Flow Control's Built-In LSP Integration

Flow Control implements LSP support directly in its Zig codebase, eliminating the need for third-party extensions. When you open a file, Flow Control executes a four-step process:

1. **File type detection** — The editor identifies the language (e.g., `python`, `rust`, `typescript`) using internal file type tables.
2. **Command lookup** — It retrieves the default LSP command from the `language_server` field in `src/file_type_lsp.zig`.
3. **Process management** — The system calls `Project.get_or_start_language_server` to either reuse an existing server or launch a new process via `LSP.open`.
4. **Initialization** — Flow Control sends the `initialize` request through `Project.send_lsp_init_request`, then forwards all subsequent LSP notifications and requests.

This architecture ensures that language servers start automatically when you open supported files, with each project maintaining its own server instances to prevent cross-contamination between codebases.

## Default LSP Configuration in file_type_lsp.zig

The heart of Flow Control's LSP mapping resides in **`src/file_type_lsp.zig`**, where each language is defined as a public constant containing a `language_server` tuple. For example, the Python definition at line 179 specifies:

```zig
pub const python = .{
    .language_server = .{ "pylsp" },
};

```

The structure follows a consistent pattern across all supported languages:

```zig
pub const <language_id> = .{
    .language_server = .{ "<executable>", "<arg1>", "<arg2>", ... },
};

```

When Flow Control detects a file matching the `<language_id>`, it extracts the executable name and arguments from this tuple to construct the launch command. The defaults cover popular languages like Rust (`rust-analyzer`), TypeScript (`typescript-language-server`), and Go (`gopls`), but you can extend these definitions or override them without modifying the source code.

## Customizing LSP Commands with JSON Overrides

While the built-in defaults work for most users, production environments often require custom flags, specific binary paths, or environment-specific arguments. Flow Control supports **JSON override files** that supersede the default commands without requiring source code changes.

### Override File Locations

Flow Control searches for configuration files in two scopes, as implemented in **`src/lsp_config.zig`**:

- **Global overrides**: `$HOME/.config/flow/lsp/<lsp_name>.json`
- **Project-local overrides**: `<project_root>/.flow/lsp/<lsp_name>.json`

The helper function `get_config_file_path` (lines 32-68) constructs these paths dynamically based on the project context and configuration scope.

### How Overrides Work

When you open a file in Flow Control, the UI entry point in **`src/tui/mainview.zig`** (lines 722-734) retrieves LSP options:

```zig
const language_server = file_type.language_server orelse return no_lsp_error();
const lsp_name = language_server[0];
const language_server_options = lsp_config.get(project, lsp_name) orelse &.{};

```

The `lsp_config.get` function reads the JSON file if present and returns its contents as a raw byte slice. This slice is passed directly to the LSP process as additional arguments, as seen in **`src/project_manager.zig`** at line 215.

### Practical Override Examples

**Global Python configuration with logging:**

```bash
mkdir -p ~/.config/flow/lsp
cat > ~/.config/flow/lsp/python.json <<'EOF'
["pylsp", "--log-file", "/tmp/pylsp.log"]
EOF

```

**Project-specific TypeScript configuration:**

```bash
cd my-project
mkdir -p .flow/lsp
cat > .flow/lsp/typescript.json <<'EOF'
["typescript-language-server", "--stdio", "--tsserver-log-file", ".tsserver.log"]
EOF

```

These configurations take effect immediately when you open a file of the corresponding type, with project-local settings taking precedence over global ones.

## Adding Support for New Languages

If you work with a language not included in Flow Control's default table, you can extend support by modifying **`src/file_type_lsp.zig`**. Each language entry follows a simple structure:

```zig
pub const <language_id> = .{
    .language_server = .{ "<executable>", "<arg1>", "<arg2>", ... },
};

```

For example, to add **Dart** support:

```zig
pub const dart = .{
    .language_server = .{ "dart_language_server", "--protocol=lsp" },
};

```

After adding the constant anywhere in the file (following the existing entries), rebuild Flow Control:

```bash
zig build

```

Verify the new language appears in the supported list:

```bash
flow -l | grep dart

```

Once built, opening any `.dart` file automatically launches your specified language server. You can still provide custom arguments via [`.flow/lsp/dart.json`](https://github.com/neurocyte/flow/blob/main/.flow/lsp/dart.json) or `~/.config/flow/lsp/dart.json` using the override mechanism described earlier.

## Forcing a Specific Language Mode

Flow Control typically detects languages by file extension, but you can override this behavior using the **`-l`** or **`--language`** flag. This is useful when working with files that lack standard extensions or when you need to test a specific LSP configuration.

```bash
flow edit -l python myscript.txt

```

This command forces Flow Control to treat [`myscript.txt`](https://github.com/neurocyte/flow/blob/main/myscript.txt) as Python, applying the Python LSP configuration (including any JSON overrides) regardless of the file extension.

## Summary

- **Flow Control** provides native LSP integration through the `neurocyte/flow` repository, automatically launching language servers based on file type definitions in `src/file_type_lsp.zig`.
- **Default commands** are stored as Zig constants with `language_server` tuples containing executables and arguments.
- **JSON override files** in `~/.config/flow/lsp/` (global) or `.flow/lsp/` (project-local) allow customization of LSP arguments without recompiling.
- **New languages** are supported by adding entries to `src/file_type_lsp.zig` and rebuilding with `zig build`.
- **Manual language selection** is available via the `-l` flag to force specific LSP modes regardless of file extension.

## Frequently Asked Questions

### How does Flow Control determine which language server to start?

Flow Control determines the language server by first detecting the file type from the file extension or content, then looking up the corresponding entry in `src/file_type_lsp.zig`. Each entry contains a `language_server` field specifying the executable name and default arguments. If an override JSON file exists in `~/.config/flow/lsp/` or `.flow/lsp/`, Flow Control merges those arguments with the defaults before launching the process via `Project.get_or_start_language_server`.

### Can I use different language server settings for different projects?

Yes. Flow Control supports project-local LSP configuration through the `.flow/lsp/` directory. When you open a file, the editor checks for JSON files in the current project's `.flow/lsp/` folder before falling back to the global `~/.config/flow/lsp/` directory. This allows you to specify project-specific flags, logging paths, or even different language server binaries for individual repositories without affecting your global settings.

### What should I do if my programming language isn't supported by default?

If your language isn't defined in `src/file_type_lsp.zig`, you can add support by editing that file and adding a new public constant following the existing pattern: `pub const <language_id> = .{ .language_server = .{ "<executable>", "<args>" } };`. After adding the entry, rebuild Flow Control using `zig build`. The new language will appear in `flow -l` and Flow Control will automatically launch your specified server when opening matching files. You can then create JSON override files for the new language just like any built-in one.