# GN Language Server Architecture

This document outlines the architecture and key design decisions of the GN Language Server.

## 1. Overview

The primary goal of this language server is to provide a fast and useful IDE experience for the GN build system. It is written in **Rust** and built on top of several key libraries:
-   **`tower-lsp`**: For the core Language Server Protocol framework.
-   **`pest`**: For parsing the GN language based on a formal grammar.
-   **`tokio`**: For asynchronous I/O and concurrency.

## 2. Key Design Decisions

Several core design decisions shape the server's behavior and performance.

### Configuration-Agnostic Analysis (Ignoring `args.gn`)

The most fundamental design choice is that **the server does not read `args.gn` files**. It analyzes the build files in a configuration-agnostic way, without knowing the final values of build arguments for any specific output directory (e.g., `out/Debug`).

This is a deliberate trade-off that prioritizes simplicity and a holistic editing experience over configuration-specific precision.

**Pros:**
-   **Simplicity & Decoupling**: The server does not need to track which of the potentially many build directories is "active," simplifying state management and user configuration. It works out of the box.
-   **Holistic Code View**: By not evaluating conditionals, the server analyzes all possible code paths. This is ideal for developers who need to understand and refactor code that spans multiple configurations (e.g., `if (is_win)` and `if (is_linux)`).
-   **Performance & Stability**: The analysis is stable and depends only on the contents of the `.gn` and `.gni` source files. It avoids the high cost of a full build config evaluation. This means the analysis can be done quickly without costly evaluations like `exec_script()`.

**Cons:**
-   **Inaccurate Semantic Analysis**: The server's understanding is incomplete. It cannot know which code paths are "active" or "dead" for a specific build, nor can it compute the final value of any variable that depends on a build argument.
-   **Ambiguous Results**: LSP features may provide ambiguous results. For example, "Go to Definition" on a variable may navigate to multiple assignments across different conditional blocks.
-   **Diagnostic Mismatches**: The server's error checking may differ from `gn check`. It might produce false positives for code in an inactive block or miss errors in code that is currently disabled.

### Single-Pass Caching & On-Demand Scope Resolution

The analyzer employs a unified caching strategy combined with on-demand scope construction.

-   **Per-File Analysis (`AnalyzedFile`)**: Each file (`.gn` or `.gni`) is parsed and analyzed independently to extract local information:
    -   **Abstract Syntax Tree (AST)**: The structural representation of the code.
    -   **Exports**: Variables, templates, and targets defined at the top level.
    -   **Links**: File paths and target labels referenced in the file.
    -   **Symbols**: A simple index of symbols for document outline.
    This result is wrapped in an `AnalyzedFile` and cached. If a file hasn't changed, this cached result is reused instantly.

-   **On-Demand Scope Building (`analyze_at`)**: When a feature requires a full semantic understanding of a specific location (e.g., "Go to Definition" or "Completion" at a cursor position), the analyzer dynamically constructs an `Environment`.
    -   It starts from the target file and recursively gathers exports from all imported files (transitive imports).
    -   It combines these exports with the local definitions available at that specific position in the code.
    -   This process is fast because it relies on the pre-computed, cached `AnalyzedFile` structures, avoiding the need to re-parse or re-analyze the dependencies.

### Caching and Performance

The server uses a freshness-checking mechanism to avoid re-analyzing unchanged files and their dependencies. The `CacheConfig` struct allows the server to differentiate between interactive requests (which might trigger a shallow update) and background requests.

### Concurrency

The server is built on `tokio` to handle multiple LSP requests concurrently without blocking. Shared state is managed safely across threads. `DocumentStorage` uses `Arc<Mutex<T>>`, while the `Analyzer` uses `RwLock` and fine-grained internal locking to allow concurrent analysis of multiple files.

### Background Indexing

For workspace-wide features like "Find All References," a complete view of the project is necessary. When a `.gn` file is first opened, a background task is spawned to walk the entire workspace directory, analyzing every `.gn` and `.gni` file. This populates the analyzer's cache. The indexer skips build output directories by checking for the presence of an `args.gn` file. Subsequent requests that need this global view can then wait for the indexing task to complete.

### Interaction with `gn` CLI

The server is designed to be mostly standalone but relies on the `gn` command-line tool for specific features where re-implementing the logic would be impractical.
-   **Location**: It has a built-in strategy to find the `gn` binary, looking in common prebuilt directories within a Chromium or Fuchsia checkout, or falling back to the system `PATH`.
-   **Formatting**: Document formatting is implemented by shelling out to `gn format --stdin`, leveraging the canonical formatter directly.

## 3. Core Components

The server is designed with a modular architecture, separating concerns into distinct components.

### Server (`src/server/mod.rs`)

This is the main entry point of the application. It initializes the server, manages the LSP request/response lifecycle, and holds the shared state of the application, including the document storage and the analyzer.

### Document Storage (`src/common/storage.rs`)

This component acts as a cache for file contents. It distinguishes between:
1.  Files currently open and being edited in the client (in-memory).
2.  Files on disk that are part of the workspace but not open for editing.

It uses a combination of LSP document versions (for in-memory files) and file system modification timestamps (for on-disk files) to determine if a file is "fresh" or needs to be re-read.

### Parser (`src/parser/`)

The parser is responsible for turning raw text into a structured representation.
-   **Grammar (`src/parser/gn.pest`)**: A formal grammar defines the syntax of the GN language. This makes the parser predictable and easy to maintain.
-   **AST (`src/parser/mod.rs`, `src/parser/parse.rs`)**: The raw parse tree from `pest` is transformed into a more ergonomic Abstract Syntax Tree (AST). The AST nodes provide methods for easy traversal and inspection, forming the input for the semantic analyzer.

### Semantic Analyzer (`src/analyzer/`)

The analyzer is the brain of the language server. It consumes the AST and builds a rich semantic understanding of the code.

-   **Workspace Context**: The server establishes the workspace context by first finding the root directory, identified by a `.gn` file. This root path is essential for resolving source-absolute paths (e.g., `//path/to/file.cc`). The `WorkspaceAnalyzer` manages the state for a specific workspace, including the build configuration loaded from `build/config/BUILDCONFIG.gn`.

-   **Key Data Structures**:
    -   `AnalyzedFile`: The complete, cached semantic model for a single file, containing its AST, exports, and links.
    -   `Environment`: Represents the fully resolved scope at a specific point in execution, aggregating variables and templates from the current file and all its dependencies.
    -   `FileExports`: Summarizes the public interface of a file (variables, templates, targets) available to importers.
    -   `AnalyzedBlock`, `AnalyzedStatement`: Semantic wrappers around AST nodes, holding resolved scopes and other metadata.

-   **Analysis Flow**:
    -   `analyze_file(path)`: Returns the cached `AnalyzedFile`.
    -   `analyze_at(file, pos)`: Returns an `Environment` representing the state of the program at `pos`, aggregating definitions from the build config and imports.

### Diagnostics (`src/diagnostics/`)

This component handles the generation of diagnostics (errors and warnings) for the user.
-   It aggregates syntax errors produced by the `pest` parser.
-   It includes an "undefined identifier" check (`undefined.rs`) which scans the resolved `Environment` to ensure all used variables are defined.

### LSP Feature Providers (`src/server/providers/`)

Each LSP feature is implemented in its own module. These providers consume the data from the Semantic Analyzer to generate responses for the client. Examples include `completion`, `hover`, `goto_definition`, and `references`.

## 4. Clients

The language server is designed to be client-agnostic, communicating via standard input/output. However, two primary clients are maintained in this repository:

### VS Code Extension (`vscode-gn`)
A standard TypeScript extension that manages the language server process and provides syntax highlighting via TextMate grammar.

### IntelliJ Plugin (`intellij-gn`)
A Kotlin-based plugin for IntelliJ IDEA. It utilizes `lsp4ij` to integrate the language server with the IntelliJ platform, providing a seamless experience for users of JetBrains IDEs.

## 5. Data Flow Example: "Go to Definition"

A typical request flows through the system as follows:

1.  **Request**: The user triggers "Go to Definition" on a variable in the editor. The client sends a `textDocument/definition` request to the server.
2.  **Dispatch**: The `Backend` in `src/server/mod.rs` receives the request and dispatches it to the `goto_definition` provider.
3.  **Analysis (File)**: The provider calls `analyzer.analyze_file()` to get the `AnalyzedFile` for the current document. This returns the cached result of the local analysis (AST, links, exports).
4.  **Link Check**: The provider first checks if the cursor is on a "link" (e.g., a file path in an import or a target label in `deps`). If so, it resolves the destination immediately.
5.  **Analysis (Scope)**: If the cursor is on an identifier, the provider calls `analyzer.analyze_at()`. This triggers the on-demand scope construction, aggregating exports from imported files to build a complete `Environment` for that specific position.
6.  **Resolution**: The provider looks up the identifier in the `Environment` to find all matching variable assignments or template definitions.
7.  **Response**: The provider constructs a `LocationLink` response containing the URIs and ranges of the definitions and returns it to the client.
