Full Code of ndonfris/fish-lsp for AI

master 3a1b117fa5dd cached
316 files
2.8 MB
742.8k tokens
2128 symbols
1 requests
Download .txt
Showing preview only (2,973K chars total). Download the full file or copy to clipboard to get everything.
Repository: ndonfris/fish-lsp
Branch: master
Commit: 3a1b117fa5dd
Files: 316
Total size: 2.8 MB

Directory structure:
gitextract_6mzjd793/

├── .all-contributorsrc
├── .github/
│   ├── CODEOWNERS
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.md
│   │   └── feature_request.md
│   └── workflows/
│       ├── check-npm-release.yml
│       ├── ci.yml
│       └── test-npm-package.yml
├── .gitignore
├── .husky/
│   ├── commit-msg
│   ├── post-checkout
│   ├── post-merge
│   ├── pre-commit
│   └── prepare-commit-msg
├── .nvmrc
├── CODE_OF_CONDUCT.md
├── LICENSE.md
├── README.md
├── SECURITY.md
├── eslint.config.ts
├── fish_files/
│   ├── exec.fish
│   ├── expand_cartesian.fish
│   ├── get-autoloaded-filepath.fish
│   ├── get-command-options.fish
│   ├── get-completion.fish
│   ├── get-dependency.fish
│   ├── get-docs.fish
│   ├── get-documentation.fish
│   ├── get-fish-autoloaded-paths.fish
│   ├── get-type-verbose.fish
│   └── get-type.fish
├── man/
│   └── fish-lsp.1
├── package.json
├── renovate.json
├── scripts/
│   ├── build-assets.fish
│   ├── build-completions.fish
│   ├── build-time
│   ├── dev-complete.fish
│   ├── esbuild/
│   │   ├── cli.ts
│   │   ├── colors.ts
│   │   ├── configs.ts
│   │   ├── file-watcher.ts
│   │   ├── index.ts
│   │   ├── pipeline.ts
│   │   ├── plugins.ts
│   │   ├── types.ts
│   │   └── utils.ts
│   ├── fish/
│   │   ├── continue-or-exit.fish
│   │   ├── pretty-print.fish
│   │   └── utils.fish
│   ├── fish-commands-scrapper.ts
│   ├── publish-nightly.fish
│   ├── relink-locally.fish
│   ├── update-changelog.fish
│   ├── update-codeblocks-in-docs.ts
│   └── workspace-cli.ts
├── src/
│   ├── analyze.ts
│   ├── cli.ts
│   ├── code-actions/
│   │   ├── action-kinds.ts
│   │   ├── alias-wrapper.ts
│   │   ├── argparse-completions.ts
│   │   ├── code-action-handler.ts
│   │   ├── combiner.ts
│   │   ├── disable-actions.ts
│   │   ├── quick-fixes.ts
│   │   ├── redirect-actions.ts
│   │   └── refactors.ts
│   ├── code-lens.ts
│   ├── command.ts
│   ├── config.ts
│   ├── diagnostics/
│   │   ├── buffered-async-cache.ts
│   │   ├── comments-handler.ts
│   │   ├── diagnostic-ranges.ts
│   │   ├── error-codes.ts
│   │   ├── invalid-error-code.ts
│   │   ├── missing-completions.ts
│   │   ├── no-execute-diagnostic.ts
│   │   ├── node-types.ts
│   │   ├── types.ts
│   │   └── validate.ts
│   ├── document-highlight.ts
│   ├── document.ts
│   ├── documentation.ts
│   ├── execute-handler.ts
│   ├── formatting.ts
│   ├── hover.ts
│   ├── inlay-hints.ts
│   ├── linked-editing.ts
│   ├── logger.ts
│   ├── main.ts
│   ├── parser.ts
│   ├── parsing/
│   │   ├── alias.ts
│   │   ├── argparse.ts
│   │   ├── barrel.ts
│   │   ├── bind.ts
│   │   ├── comments.ts
│   │   ├── complete.ts
│   │   ├── emit.ts
│   │   ├── equality-utils.ts
│   │   ├── export.ts
│   │   ├── for.ts
│   │   ├── function.ts
│   │   ├── inline-variable.ts
│   │   ├── nested-strings.ts
│   │   ├── options.ts
│   │   ├── read.ts
│   │   ├── reference-comparator.ts
│   │   ├── set.ts
│   │   ├── source.ts
│   │   ├── string.ts
│   │   ├── symbol-converters.ts
│   │   ├── symbol-detail.ts
│   │   ├── symbol-kinds.ts
│   │   ├── symbol-modifiers.ts
│   │   ├── symbol.ts
│   │   ├── unreachable.ts
│   │   └── values.ts
│   ├── references.ts
│   ├── renames.ts
│   ├── selection-range.ts
│   ├── semantic-tokens.ts
│   ├── server.ts
│   ├── signature.ts
│   ├── snippets/
│   │   ├── envVariables.json
│   │   ├── fishlspEnvVariables.json
│   │   ├── functions.json
│   │   ├── helperCommands.json
│   │   ├── localeVariables.json
│   │   ├── pipesAndRedirects.json
│   │   ├── specialFishVariables.json
│   │   ├── statusNumbers.json
│   │   └── syntaxHighlightingVariables.json
│   ├── utils/
│   │   ├── builtins.ts
│   │   ├── cli-dump-tree.ts
│   │   ├── commander-cli-subcommands.ts
│   │   ├── completion/
│   │   │   ├── comment-completions.ts
│   │   │   ├── documentation.ts
│   │   │   ├── inline-parser.ts
│   │   │   ├── list.ts
│   │   │   ├── pager.ts
│   │   │   ├── shell.ts
│   │   │   ├── startup-cache.ts
│   │   │   ├── startup-config.ts
│   │   │   ├── static-items.ts
│   │   │   └── types.ts
│   │   ├── definition-scope.ts
│   │   ├── documentation-cache.ts
│   │   ├── env-manager.ts
│   │   ├── exec.ts
│   │   ├── file-operations.ts
│   │   ├── flag-documentation.ts
│   │   ├── flatten.ts
│   │   ├── get-lsp-completions.ts
│   │   ├── health-check.ts
│   │   ├── locations.ts
│   │   ├── markdown-builder.ts
│   │   ├── maybe.ts
│   │   ├── node-types.ts
│   │   ├── path-resolution.ts
│   │   ├── polyfills.ts
│   │   ├── process-env.ts
│   │   ├── progress-notification.ts
│   │   ├── semantics.ts
│   │   ├── snippets.ts
│   │   ├── startup.ts
│   │   ├── symbol-documentation-builder.ts
│   │   ├── translation.ts
│   │   ├── tree-sitter.ts
│   │   ├── workspace-manager.ts
│   │   └── workspace.ts
│   ├── virtual-fs.ts
│   └── web.ts
├── tests/
│   ├── alias-conversion.test.ts
│   ├── analyze-functions.test.ts
│   ├── analyzer.test.ts
│   ├── cli.test.ts
│   ├── code-action.test.ts
│   ├── comments-handler.test.ts
│   ├── complete-symbol.test.ts
│   ├── completion-shell.test.ts
│   ├── completion-startup-config.test.ts
│   ├── completion-variable-expansion.test.ts
│   ├── conditional-execution-diagnostics.test.ts
│   ├── definition-location.test.ts
│   ├── diagnostics-with-missing-completions.test.ts
│   ├── diagnostics.test.ts
│   ├── document-highlights.test.ts
│   ├── document-test-helpers.ts
│   ├── document.test.ts
│   ├── embedded-functions-resolution.test.ts
│   ├── example-test-workspace-usage.test.ts
│   ├── exec.test.ts
│   ├── execute-handler.test.ts
│   ├── file-operations.test.ts
│   ├── fish-symbol-fast-check.test.ts
│   ├── fish-symbol.test.ts
│   ├── fish-syntax-node.test.ts
│   ├── fish_files/
│   │   ├── __fish_complete_docutils.fish
│   │   ├── __fish_complete_gpg.fish
│   │   ├── __fish_config_interactive.fish
│   │   ├── __fish_shared_key_bindings.fish
│   │   ├── advanced/
│   │   │   ├── better_variable_scopes.fish
│   │   │   ├── inner_functions.fish
│   │   │   ├── lots_of_globals.fish
│   │   │   ├── multiple_functions.fish
│   │   │   ├── variable_scope.fish
│   │   │   └── variable_scope_2.fish
│   │   ├── errors/
│   │   │   ├── extra_end.fish
│   │   │   ├── invalid_pipes.fish
│   │   │   ├── missing_end.fish
│   │   │   └── variable_expansion_missing_name.fish
│   │   ├── fish_config.fish
│   │   ├── fish_git_prompt.fish
│   │   ├── fish_vi_key_bindings.fish
│   │   ├── help.fish
│   │   ├── history.fish
│   │   ├── huge_file.fish
│   │   ├── simple/
│   │   │   ├── all_variable_def_types.fish
│   │   │   ├── for_var.fish
│   │   │   ├── func_a.fish
│   │   │   ├── func_abc.fish
│   │   │   ├── function_variable_def.fish
│   │   │   ├── global_vs_local.fish
│   │   │   ├── inner_function.fish
│   │   │   ├── is_chained_return.fish
│   │   │   ├── multiple_broken_scopes.fish
│   │   │   ├── set_var.fish
│   │   │   ├── simple_function.fish
│   │   │   └── symbols.fish
│   │   ├── small_file.fish
│   │   ├── switch_case_test_1.fish
│   │   └── umask.fish
│   ├── format-aligned-columns.test.ts
│   ├── formatting.test.ts
│   ├── helpers.ts
│   ├── inline-variable.test.ts
│   ├── install_scripts/
│   │   └── generate_largest_fish_files.fish
│   ├── interactive-buffers.test.ts
│   ├── issue-140-complete-command-quoting.test.ts
│   ├── logger.test.ts
│   ├── main.test.ts
│   ├── markdown-builder.test.ts
│   ├── node-types.test.ts
│   ├── parser.test.ts
│   ├── parsing-defintions.test.ts
│   ├── parsing-env-values.test.ts
│   ├── parsing-export-defintions.test.ts
│   ├── parsing-function-with-event.test.ts
│   ├── parsing-indent-comments.test.ts
│   ├── parsing-string-value.test.ts
│   ├── process-env.test.ts
│   ├── read-workspace.test.ts
│   ├── reference-locations.test.ts
│   ├── selection-range.test.ts
│   ├── semantic-tokens-helpers.ts
│   ├── semantic-tokens.test.ts
│   ├── setup-mocks.ts
│   ├── snippets.test.ts
│   ├── sourced-function-export.test.ts
│   ├── startup-workspace.test.ts
│   ├── symbol-root-level.test.ts
│   ├── temp.ts
│   ├── test-comprehensive-utility.test.ts
│   ├── test-setup.test.ts
│   ├── test-snapshot-functionality.test.ts
│   ├── test-workspace-utils.ts
│   ├── tree-sitter-fast-check.test.ts
│   ├── tree-sitter.test.ts
│   ├── unreachable.test.ts
│   ├── virtual-file-handling.test.ts
│   ├── workspace-manager.test.ts
│   ├── workspace-util.ts
│   └── workspaces/
│       ├── embedded-functions-resolution/
│       │   ├── functions/
│       │   │   ├── my_test.fish
│       │   │   └── other_test.fish
│       │   └── test_script.fish
│       ├── example_test_src/
│       │   ├── completions/
│       │   │   ├── abbr.fish
│       │   │   ├── alias.fish
│       │   │   ├── cd.fish
│       │   │   ├── cdh.fish
│       │   │   ├── diff.fish
│       │   │   └── fish_add_path.fish
│       │   ├── config.fish
│       │   └── functions/
│       │       ├── abbr.fish
│       │       ├── alias.fish
│       │       ├── cd.fish
│       │       ├── cdh.fish
│       │       ├── contains_seq.fish
│       │       ├── diff.fish
│       │       ├── dirh.fish
│       │       ├── dirs.fish
│       │       ├── down-or-search.fish
│       │       ├── edit_command_buffer.fish
│       │       ├── export.fish
│       │       └── fish_add_path.fish
│       ├── incorrect-permissions-indexing/
│       │   └── file.fish
│       ├── semantic-tokens-simple-workspace/
│       │   ├── basic.fish
│       │   ├── commands.fish
│       │   ├── completions/
│       │   │   ├── deployctl.fish
│       │   │   └── source_fish.fish
│       │   ├── diagnostics.fish
│       │   ├── functions.fish
│       │   ├── keywords.fish
│       │   ├── mixed.fish
│       │   ├── operators.fish
│       │   └── variables.fish
│       ├── workspace_1/
│       │   └── fish/
│       │       ├── completions/
│       │       │   └── exa.fish
│       │       ├── config.fish
│       │       └── functions/
│       │           ├── func-inner.fish
│       │           ├── test-func.fish
│       │           ├── test-rename-1.fish
│       │           ├── test-rename-2.fish
│       │           └── test-variable-renames.fish
│       └── workspace_semantic-tokens/
│           └── test-operator-tokens.fish
├── tsconfig.eslint.json
├── tsconfig.json
└── vitest.config.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .all-contributorsrc
================================================
{
  "projectName": "fish-lsp",
  "projectOwner": "ndonfris",
  "repoType": "github",
  "repoHost": "https://github.com",
  "files": [
    "README.md"
  ],
  "imageSize": 50,
  "commit": false,
  "commitConvention": "eslint",
  "contributors": [
    {
      "login": "ndonfris",
      "name": "nick",
      "avatar_url": "https://avatars.githubusercontent.com/u/49458459?v=4",
      "profile": "https://github.com/ndonfris",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "mimikun",
      "name": "mimikun",
      "avatar_url": "https://avatars.githubusercontent.com/u/13450321?v=4",
      "profile": "https://github.com/mimikun",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "jpaju",
      "name": "Jaakko Paju",
      "avatar_url": "https://avatars.githubusercontent.com/u/36770267?v=4",
      "profile": "https://github.com/jpaju",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "shaleh",
      "name": "Sean Perry",
      "avatar_url": "https://avatars.githubusercontent.com/u/1377996?v=4",
      "profile": "https://github.com/shaleh",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "cova-fe",
      "name": "Fabio Coatti",
      "avatar_url": "https://avatars.githubusercontent.com/u/385249?v=4",
      "profile": "https://mastodon.online/@cova",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "PeterCardenas",
      "name": "Peter Cardenas",
      "avatar_url": "https://avatars.githubusercontent.com/u/16930781?v=4",
      "profile": "https://github.com/PeterCardenas",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "petertriho",
      "name": "Peter Tri Ho",
      "avatar_url": "https://avatars.githubusercontent.com/u/7420227?v=4",
      "profile": "https://github.com/petertriho",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "bnwa",
      "name": "bnwa",
      "avatar_url": "https://avatars.githubusercontent.com/u/74591246?v=4",
      "profile": "https://github.com/bnwa",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "branchvincent",
      "name": "Branch Vincent",
      "avatar_url": "https://avatars.githubusercontent.com/u/19800529?v=4",
      "profile": "https://github.com/branchvincent",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "devsunb",
      "name": "Jaeseok Lee",
      "avatar_url": "https://avatars.githubusercontent.com/u/23169202?v=4",
      "profile": "https://github.com/devsunb",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "ClanEver",
      "name": "ClanEver",
      "avatar_url": "https://avatars.githubusercontent.com/u/73160783?v=4",
      "profile": "https://github.com/ClanEver",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "ndegruchy",
      "name": "Nathan DeGruchy",
      "avatar_url": "https://avatars.githubusercontent.com/u/52262673?v=4",
      "profile": "https://degruchy.org/",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "TeddyHuang-00",
      "name": "Nan Huang",
      "avatar_url": "https://avatars.githubusercontent.com/u/64199650?v=4",
      "profile": "https://teddyhuang-00.github.io/",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "unlimitedsola",
      "name": "Sola",
      "avatar_url": "https://avatars.githubusercontent.com/u/3632663?v=4",
      "profile": "https://github.com/unlimitedsola",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "jose-elias-alvarez",
      "name": "Jose Alvarez",
      "avatar_url": "https://avatars.githubusercontent.com/u/54108223?v=4",
      "profile": "https://github.com/jose-elias-alvarez",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "gaborbernat",
      "name": "Bernát Gábor",
      "avatar_url": "https://avatars.githubusercontent.com/u/690238?v=4",
      "profile": "https://www.bernat.tech/",
      "contributions": [
        "code"
      ]
    }
  ],
  "contributorsPerLine": 7,
  "linkToUsage": false
}


================================================
FILE: .github/CODEOWNERS
================================================
* @ndonfris


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: ndonfris # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
# patreon: # Replace with a single Patreon username
# open_collective: # Replace with a single Open Collective username
# ko_fi: # Replace with a single Ko-fi username
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
# liberapay: # Replace with a single Liberapay username
# issuehunt: # Replace with a single IssueHunt username
# lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
# polar: # Replace with a single Polar username
buy_me_a_coffee: ndonfris # Replace with a single Buy Me a Coffee username
# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']


================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.md
================================================
---
name: Bug Report
about: Report a bug you're experiencing
title: BUG
labels: bug
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior.

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Please complete the following information:**
 - OS: [e.g. Ubuntu, macOS, etc...] `uname -o`
 - yarn version: [e.g. yarn@1.22.22] `yarn --version`
 - node version: [e.g., node@20.0.0] `node --version` 
 - fish version [e.g., fish@3.7.1] `fish --version`
 - fish-lsp version [e.g, fish-lsp@1.0.4] `fish-lsp --version`
> You can run the following in your shell: 
```fish
echo "OS NAME: $(uname -o)"
echo "YARN VERSION: $(yarn --version)"
echo "NODE VERSION: $(node --version)"
echo "FISH VERSION: $(fish --version)"
echo "FISH-LSP VERSION: $(fish-lsp --version)"
```

**Additional context**
Any other context about the problem here.
  - fish-lsp configuration (Include if relevant to the issue)
 - relevant `logs.txt` output: `cat (fish-lsp info --logs-file)`


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .github/workflows/check-npm-release.yml
================================================
# Daily check that fish-lsp NPM package installation
# and basic commands are working
name: Check NPM Release

on:
  schedule:
    - cron: '20 2 * * *'
  workflow_dispatch: # Allow manual triggering

jobs:
  verify-npm-package:
    name: Verify fish-lsp NPM Package
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
    permissions: 
      contents: read
      security-events: write
      actions: read

    steps:
      - name: Install Fish Shell
        uses: fish-actions/install-fish@v1.2.0

      - name: Check which fish version
        run: fish --version
        # shell: fish {0}
        # to use fish shell for a step 

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22.14.0

      - name: Install npm package
        run: npm install -g fish-lsp@latest

      - name: Check fish-lsp exists `which fish-lsp`
        run: which fish-lsp

      - name: Check binary `fish-lsp --help`
        run: fish-lsp --help

      - name: Check version `fish-lsp --version`
        run: fish-lsp --version

      - name: Check completions `fish-lsp complete`
        run: fish-lsp complete

      - name: Check info `fish-lsp info`
        run: fish-lsp info

      - name: Check env `fish-lsp env --show`
        run: fish-lsp env --show

      - name: Check startup time `fish-lsp info --time-startup`
        run: fish-lsp info --time-startup


================================================
FILE: .github/workflows/ci.yml
================================================
## INSTALL, BUILD and LINT a local clone of the repository, with the recommended dependencies.
## Will run on every push to master, every PR to master, and once a day at 2:20 UTC.
## Also allow manual triggering.
name: CI Pipeline

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  schedule:
    - cron: '20 2 * * *'
      # every day at 2:20 UTC
  workflow_dispatch: # Allow manual triggering

jobs:
  ci:
    name: (master) CI Pipeline - install, build & lint
    runs-on: ubuntu-latest
    permissions: 
      contents: read
      security-events: write
      actions: read

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Install Fish Shell
        uses: fish-actions/install-fish@v1.2.0

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          # node-version: 22.14.0
          node-version-file: .nvmrc

      - name: Install Yarn
        shell: fish {0}
        run: npm install -g yarn@1.22.22

      - name: Install Dependencies
        shell: fish {0}
        run: yarn install

      - name: Build Development
        shell: fish {0}
        run: yarn build

      - name: Check Binary
        shell: fish {0}
        run: fish-lsp --help

      - name: Run Lint
        shell: fish {0}
        run: yarn lint:fix


================================================
FILE: .github/workflows/test-npm-package.yml
================================================
## Test that the built npm package can be successfully installed and works correctly
## This workflow builds the package, packs it, installs it globally, and runs verification commands
name: Test NPM Package Installation

on:
  push:
    branches:
      - master
  workflow_dispatch:
    inputs:
      timestamp:
        description: 'Build timestamp (for reproducible builds)'
        required: false
        default: ''
  pull_request:
    paths:
      - 'src/**'
      - 'package.json'
      - 'scripts/build.ts'
      - '.github/workflows/test-npm-package.yml'

jobs:
  test-npm-package:
    name: Test NPM Package (Node ${{ matrix.node-version }}, ${{ matrix.os }})
    runs-on: ${{ matrix.os }}
    permissions:
      contents: read

    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu-latest
          - macos-latest
        node-version:
          - '20'      # Minimum supported version
          - '22'      # Current LTS
          - '24'  # Latest stable

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}

      - name: Install Fish Shell (v4.x)
        uses: fish-actions/install-fish@v1.2.0

      - name: Generate Timestamp if Not Provided
        id: timestamp
        run: |
          if [ -z "${{ github.event.inputs.timestamp }}" ]; then
            echo "SOURCE_DATE_EPOCH=$(date +%s)" >> $GITHUB_ENV
          else
            echo "SOURCE_DATE_EPOCH=${{ github.event.inputs.timestamp }}" >> $GITHUB_ENV
          fi

      - name: Install Yarn
        shell: fish {0}
        run: npm install -g yarn@1.22.22

      - name: Display Build Timestamp
        shell: fish {0}
        run: |
          echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH"
          echo "Human-readable: "(date -d @$SOURCE_DATE_EPOCH 2>/dev/null || date -r $SOURCE_DATE_EPOCH 2>/dev/null || echo "N/A")

      - name: Install Dependencies
        shell: fish {0}
        run: yarn install

      - name: Build for NPM
        shell: fish {0}
        run: yarn build:npm

      - name: Pack the Package
        shell: fish {0}
        run: yarn package

      - name: Upload Package Artifact
        if: github.event_name != 'workflow_dispatch' || !env.ACT
        uses: actions/upload-artifact@v4
        with:
          name: fish-lsp-package-node${{ matrix.node-version }}-${{ matrix.os }}
          path: fish-lsp.tgz
          retention-days: 7
          if-no-files-found: error

      - name: Install Package Globally
        shell: fish {0}
        run: |
          set -l package_file (ls fish-lsp.tgz | head -n 1)
          echo "Installing package: $package_file"
          npm install -g $package_file

      - name: Verify fish-lsp binary exists
        run: which fish-lsp

      - name: Test - fish-lsp --help
        run: fish-lsp --help

      - name: Test - fish-lsp --version
        run: fish-lsp --version

      - name: Test - fish-lsp info
        run: fish-lsp info

      - name: Test - fish-lsp info --build-time
        run: fish-lsp info --build-time

      - name: Test - fish-lsp info --path
        run: fish-lsp info --path

      - name: Test - fish-lsp env
        run: fish-lsp env

      - name: Test - fish-lsp info --time-startup
        run: fish-lsp info --time-startup

      - name: Test - fish-lsp complete
        run: fish-lsp complete

      - name: Test - fish-lsp complete | fish --no-execute
        run: fish-lsp complete | fish --no-execute

      - name: Test - fish-lsp env --show-default | fish --no-execute
        run: fish-lsp env --show-default | fish --no-execute

      - name: Test - fish-lsp start --dump
        run: fish-lsp start --dump

      - name: Cleanup - Uninstall Package
        if: always()
        run: npm uninstall -g fish-lsp


================================================
FILE: .gitignore
================================================
.DS_Store
.vim
*.log
*.tsbuildinfo
logs.txt
wikis
tests/staging
*.tgz
*.tsbuildinfo
.editorconfig
.gitattributes
coverage
.bun
dist
build
*.cast
*.gif
*.txt

# ignore all build artifacts
out
node_modules
bin
lib
dist

!bin/fish-lsp

scripts/build-with-bun.sh
scripts/build-binary.ts
scripts/debug.fish
scripts/build-release.fish

release-assets
tsconfig.types.json

*.d.ts
temp-types
tests/workspaces/*.snapshot
temp-embedded-assets
tests/workspaces/example_test_src_1

!docs/CHANGELOG.md   
!docs/CONTRIBUTING.md
!docs/ROADMAP.md     
!docs/MAN_FILE.md    
docs/*


================================================
FILE: .husky/commit-msg
================================================
## .husky/commit-msg
# yarn commitlint --extends '@commitlint/config-conventional' --edit $1
yarn commitlint --extends '@commitlint/config-conventional' --edit $1 --git-log-args='first-parent cherry-pick'

================================================
FILE: .husky/post-checkout
================================================
# Only run yarn install if this was a branch checkout (not file checkout)
# $3 is 1 for branch checkout, 0 for file checkout
if [ "$3" = "1" ]; then
  yarn install
fi


================================================
FILE: .husky/post-merge
================================================
yarn

================================================
FILE: .husky/pre-commit
================================================
##.husky/pre-commit
yarn run lint-staged


================================================
FILE: .husky/prepare-commit-msg
================================================
#!/usr/bin/env sh
# . "$(dirname -- "$0")/_/husky.sh"

cp "$1" "/tmp/fish-lsp-last-commit-msg-$(date +%Y%m%d-%H%M%S).msg"


================================================
FILE: .nvmrc
================================================
v22.14.0


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
  overall community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or
  advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
  address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
donfris.nick@gmail.com.
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series
of actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior,  harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within
the community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.

Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.


================================================
FILE: LICENSE.md
================================================
Copyright (c) 2022-2025 Nick Donfris and others

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

================================================
FILE: README.md
================================================
<h1 align="center">
    <div align="center">
        <a href="https://fish-lsp.dev">
            <image src="https://raw.githubusercontent.com/ndonfris/fish-lsp.dev/31d3d587ebd00f76ababcc98ed21b5109637e318/public/favicon-centered-bluee.svg" alt="fish-lsp" style="position: flex; text-align: center;" height="23rem"> fish-lsp
        </a>
        <div align="center">
            <a href="https://github.com/ndonfris/fish-lsp"><img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/ndonfris/fish-lsp/ci.yml?branch=master&labelColor=%23181939"></a>
            <a href="https://github.com/ndonfris/fish-lsp/blob/master/LICENSE.md"><img alt="License" src="https://img.shields.io/github/license/ndonfris/fish-lsp?&labelColor=%23181939&color=b88af3"></a>
            <a href="https://github.com/ndonfris/fish-lsp/commits/master/"><img alt="Github Created At" src="https://img.shields.io/github/created-at/ndonfris/fish-lsp?logo=%234e6cfa&label=created&labelColor=%23181939&color=%236198f5"></a>
            <a href="https://npmjs.org/fish-lsp"><img alt="NPM Downloads" src="https://img.shields.io/npm/dw/fish-lsp?logoColor=%235f5fd7&labelColor=%23181939&color=%235f5fd7"></a>
        </div>
    </div>
</h1>

![demo.gif](https://github.com/ndonfris/fish-lsp.dev/blob/ndonfris-patch-1/new_output.gif?raw=true)

Introducing the [fish-lsp](https://fish-lsp.dev), a [Language Server Protocol (LSP)](https://lsif.dev/) implementation for the [fish shell language](https://fishshell.com).

## Quick Start

Please choose a [method to install](#installation) the language server and [configure a client](#client-configuration-required) to use `fish-lsp` in your editor.

A detailed explanation of how a language server connection works is described on the following [wiki](https://github.com/ndonfris/fish-lsp/wiki/How-does-it-work%3F) page.

## Why? 🐟

- 🦈 __Efficiency__: enhances the shell scripting experience with an extensive suite of intelligent text-editing [features](#features)

- 🐡 __Flexibility__: allows for a highly customizable [configuration](#server-configuration-optional)

- 🐚 __Guidance__: [friendly hints](https://github.com/ndonfris/fish-lsp/?tab=readme-ov-file#) and [documentation](#installation) to comfortably explore command line tooling

- 🐬 __Community__: improved by a [vibrant user base](#contributors), with [supportive and insightful feedback](https://github.com/ndonfris/fish-lsp/discussions)

- 🐙 __Compatibility__: integrates with a wide variety of [tooling and language clients](#client-configuration-required)

- 🌊 __Reliability__: produces an [editor agnostic developer environment](https://en.wikipedia.org/wiki/Language_Server_Protocol),
     ensuring __all__ fish user's have access to a consistent set of features

## Features

| Feature | Description | Status |
| --- | --- | --- |
| __Completion__ | Provides completions for commands, variables, and functions | ✅ |
| __Hover__ | Shows documentation for commands, variables, and functions. Has special handlers for --flag, commands, functions, and variables | ✅ |
| __Signature Help__ | Shows the signature of a command or function | ✅  |
| __Goto Definition__ | Jumps to the definition of a command, variable, function or --flag | ✅ |
| __Goto Implementation__ | Jumps between symbol definitions and completion definitions | ✅ |
| __Find References__ | Shows all references to a command, variable, function, or --flag | ✅ |
| __Rename__ | Rename within _matching_ __global__ && __local__ scope | ✅ |
| __Document Symbols__ | Shows all commands, variables, and functions in a document | ✅ |
| __Workspace Symbols__ | Shows all commands, variables, and functions in a workspace | ✅ |
| __Document Formatting__ | Formats a document, _full_ & _selection_ | ✅ |
| __On Type Formatting__ | Formats a document while typing | ✅ |
| __Document Highlight__ | Highlights all references to a command, variable, or function.  | ✅  |
| __Command Execution__ | Executes a server command from the client | ✅ |
| __Code Action__ | Automate code generation | ✅  |
| __Quick fix__ | Auto fix lint issues | ✅  |
| __Inlay Hint__ | Shows Virtual Text/Inlay Hints | ✅  |
| __Code Lens__ | Shows all available code lenses | ✖ |
| __Logger__ | Logs all server activity | ✅ |
| __Diagnostic__ | Shows all diagnostics | ✅ |
| __Folding Range__ | Toggle ranges to fold text  | ✅ |
| __Selection Range__ | Expand ranges when selecting text  | ✅ |
| __Semantic Tokens__ | Server provides extra syntax highlighting | ✅ |
| __CLI Interactivity__ | Provides a CLI for server interaction. <br/>Built by `fish-lsp complete` | ✅ |
| __Client Tree__ | Shows the defined scope as a Tree | ✅ |
| __Indexing__ | Indexes all commands, variables, functions, and source files | ✅ |

## Installation

Some language clients might support downloading the fish-lsp directly from within the client, but for the most part, you'll typically be required to install the language server manually.

Below are a few methods to install the language server, and how to verify that it's working.

### Use a Package Manager

Stability across package managers can vary. Consider using another installation method if issues arise.

```bash
npm install -g fish-lsp

yarn global add fish-lsp

pnpm install -g fish-lsp

nix-shell -p fish-lsp

brew install fish-lsp

conda install fish-lsp

mamba install fish-lsp
```

You can install the completions by running the following command:

```fish
fish-lsp complete > ~/.config/fish/completions/fish-lsp.fish
```

### Download Standalone Binary

Install the standalone binary directly from GitHub releases (no dependencies required):

```bash
# Download the latest standalone binary
curl -L https://github.com/ndonfris/fish-lsp/releases/latest/download/fish-lsp.standalone \
  -o ~/.local/bin/fish-lsp

# Make it executable
chmod +x ~/.local/bin/fish-lsp

# Install completions
fish-lsp complete > ~/.config/fish/completions/fish-lsp.fish
```

> __Note:__
> Ensure `~/.local/bin` is in your `$PATH`.

### Build from Source

Recommended Dependencies: `yarn@1.22.22` `node@22.14.0` `fish@4.0.8`

```bash
git clone https://github.com/ndonfris/fish-lsp 
cd fish-lsp/

yarn install 
yarn build # links `./dist/fish-lsp` to `yarn global bin` $PATH
```

Building the project from source is the most portable method for installing the language server.

### Verifying Installation

After installation, verify that `fish-lsp` is working correctly:

```bash
fish-lsp --help
```

![fish-lsp --help](https://github.com/ndonfris/fish-lsp.dev/blob/master/public/help-msg-new.png?raw=true)

## Setup

To properly configure [fish-lsp](https://fish-lsp.dev), you need to define a client configuration after installing the language server.

Configuring a client should be relatively straightforward. Typically, you're only required to translate the shell command `fish-lsp start` for `fish` files, in the [client's configuration](#client-configuration-required). However, further configuration can be specified as a [server configuration](#server-configuration-optional).

Some clients may also allow specifying the server configuration directly in the client configuration.

### Client Configuration <ins><i>(Required)</i></ins><a href="client-configuration" />

Theoretically, the language-server should generally be compatible with almost any text-editor or IDE you prefer using.  Feel free to setup the project in any [fish-lsp-client](https://github.com/ndonfris/fish-lsp/wiki/Client-Configurations) of your choice, or [submit a PR](https://github.com/ndonfris/fish-lsp-language-clients/pulls) for new configurations.

<details>
  <summary><span><a id="nvim"></a><b>neovim</b> (minimum version <code>>= v0.8.x</code>)</span></summary>

  Full table of options available in the [neovim documentation](https://neovim.io/doc/user/lsp.html)

  ```lua
  vim.api.nvim_create_autocmd('FileType', {
    pattern = 'fish',
    callback = function()
      vim.lsp.start({
        name = 'fish-lsp',
        cmd = { 'fish-lsp', 'start' },
      })
    end,
  })
  ```

  Alternatively, you can also see official documentation for [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig/blob/master/doc/configs.md#fish_lsp), or use your client of choice below.

  > There is also a useful configuration for testing out the language server in `nvim@v0.11.1` included in the [fish-lsp-language-clients](https://github.com/ndonfris/fish-lsp-language-clients/tree/packer) repository.

</details>
<details>
  <summary><span><a id="mason.nvim"></a><b>mason.nvim</b></span></summary>

  Install the `fish-lsp` using [mason.nvim](https://github.com/mason-org/mason-registry/pull/8609#event-18154473712)

  ```vimscript
  :MasonInstall fish-lsp
  ```

</details>
<details>
  <summary><span><a id="coc.nvim"></a><b>coc.nvim</b></span></summary>

  [Neovim](https://neovim.io) client using [coc.nvim](https://github.com/neoclide/coc.nvim) configuration, located inside [coc-settings.json](https://github.com/neoclide/coc.nvim/wiki/Language-servers#register-custom-language-servers) `"languageserver"` key

  ```json
  {
    "fish-lsp": {
      "command": "fish-lsp",
      "filetypes": ["fish"],
      "args": ["start"]
    }
  }
  ```

</details>
<details>
  <summary><span><a id="YouCompleteMe"></a><b>YouCompleteMe</b></span></summary>

  [YouCompleteMe](https://github.com/ycm-core/YouCompleteMe) configuration for vim/neovim

  ```vim
  let g:ycm_language_server =
            \ [
            \   {
            \       'name': 'fish',
            \       'cmdline': [ 'fish-lsp', 'start' ],
            \       'filetypes': [ 'fish' ],
            \   }
            \ ]
  ```

</details>
<details>
  <summary><span><a id="vim-lsp"></a><b>vim-lsp</b></span></summary>

  Configuration of [prabirshrestha/vim-lsp](https://github.com/prabirshrestha/vim-lsp) in your `init.vim` or `init.lua` file

  ```vim
  if executable('fish-lsp')
    au User lsp_setup call lsp#register_server({
        \ 'name': 'fish-lsp',
        \ 'cmd': {server_info->['fish-lsp', 'start']},
        \ 'allowlist': ['fish'],
        \ })
  endif
  ```

</details>
<details>
  <summary><span><a id="helix"></a><b>helix</b></span></summary>

  In config file `~/.config/helix/languages.toml`

  ```toml
  [[language]]
  name = "fish"
  language-servers = [ "fish-lsp" ]
  
  [language-server.fish-lsp]
  command = "fish-lsp"
  args= ["start"]
  environment = { "fish_lsp_show_client_popups" = "false" }
  ```

</details>
<details>
  <summary><span><a id="kakoune"></a><b>kakoune</b></span></summary>

  Configuration for [kakoune-lsp](https://github.com/kakoune-lsp/kakoune-lsp), located in `~/.config/kak-lsp/kak-lsp.toml`

  ```toml
  [language.fish]
  filetypes = ["fish"]
  command = "fish-lsp"
  args = ["start"]

  ```

  Or in your `~/.config/kak/lsp.kak` file

  ```kak
  hook -group lsp-filetype-fish global BufSetOption filetype=fish %{
      set-option buffer lsp_servers %{
          [fish-lsp]
          root_globs = [ "*.fish", "config.fish", ".git", ".hg" ]
          args = [ "start" ]
      }
  }
  ```

</details>
<details>
  <summary><span><a id="kate"></a><b>kate</b></span></summary>

  Configuration for [kate](https://kate-editor.org/)

  ```json
  {
    "servers": {
      "fish": {
        "command": ["fish-lsp", "start"],
        "url": "https://github.com/ndonfris/fish-lsp",
        "highlightingModeRegex": "^fish$"
      }
    }
  }
  ```

</details>
<details>
  <summary><span><a id="emacs"></a><b>emacs</b></span></summary>

  Configuration using [eglot](https://github.com/joaotavora/eglot) (Built into Emacs 29+)

  ```elisp
  ;; Add to your init.el or .emacs
  (require 'eglot)

  (add-to-list 'eglot-server-programs
    '(fish-mode . ("fish-lsp" "start")))

  ;; Optional: auto-start eglot for fish files
  (add-hook 'fish-mode-hook 'eglot-ensure)
  ```

  or place in your `languages/fish.el` file

  ```elisp
  (use-package fish-mode)

  (with-eval-after-load 'eglot
    (add-to-list 'eglot-server-programs
                 '(fish-mode . ("fish-lsp" "start"))))
  ```

  <!-- https://github.com/girlkissers/gkmacs/blob/main/lisp/languages/fish.el -->

  Configuration using [lsp-mode](https://github.com/emacs-lsp/lsp-mode)

  ```elisp
  ;; Add to your init.el or .emacs
  (require 'lsp-mode)

  (lsp-register-client
   (make-lsp-client
    :new-connection (lsp-stdio-connection '("fish-lsp" "start"))
    :activation-fn (lsp-activate-on "fish")
    :server-id 'fish-lsp))

  ;; Optional: auto-start lsp for fish files
  (add-hook 'fish-mode-hook #'lsp)
  ```

  Full example configuration using [doom-emacs](https://github.com/doomemacs/doomemacs/tree/master) can be found in the [fish-lsp language clients repo](https://github.com/ndonfris/fish-lsp-language-clients/).

</details>
<details>
  <summary><span><a id="vscode"></a><b>VSCode/VSCodium</b> <emph><a href='https://github.com/ndonfris/vscode-fish-lsp'>(Source Code Repo)</a></emph></span></summary>

  > For VSCode, visit the extension on the [VSCode Marketplace](https://marketplace.visualstudio.com/items?itemName=ndonfris.fish-lsp).
  > For VSCodium, visit the extension on the [OpenVSX Marketplace](https://open-vsx.org/extension/ndonfris/fish-lsp).
  >
  > Using either of these editors/extensions, should allow the `fish-lsp` to work out-of-the-box with minimal configuration (no client configuration is required).
  >
  > A server configuration can still be specified to control the server's behavior. ([see below](#server-configuration-optional))

</details>
<details>
  <summary><span><a id="bbedit"></a><b>BBEdit</b></span></summary>

  > To install the fish-lsp in [BBEdit](https://www.barebones.com/products/bbedit/), please follow the instructions in the repository [fish-lsp-language-clients](https://github.com/ndonfris/fish-lsp-language-clients/blob/bbedit/BBEdit%20Install.md).
  >
  > This configuration includes a [Fish.plist](https://github.com/ndonfris/fish-lsp-language-clients/blob/bbedit/Lanugage%20Modules/Fish.plist) file that provides syntax highlighting and other features for the fish shell.

</details>
<details>
  <summary><span><a id="Intellij"></a><b>IntelliJ</b></span></summary>

  > To install the fish-lsp in [IntelliJ](https://www.jetbrains.com/idea/), please follow the instructions in the repository [jetbrains-fish](https://github.com/tox-dev/jetbrains-fish?tab=readme-ov-file#installation).

</details>



### Server Configuration <ins><i>(Optional)</i></ins>

Specific functionality for the server can be set independently from the client. The server allows for both [environment variables](#environment-variables) and [command flags](#command-flags) to customize how specific server processes are started.

#### Environment variables

Environment variables provide a way to globally configure the server across all sessions, but can be overridden interactively<sup>[\[1\]](https://fishshell.com/docs/current/language.html#variable-scope)</sup> by the current shell session as well. They can easily be auto-generated<sup>[\[1\]](#environment-variables-default)</sup><sup>[\[2\]](#environment-variables-template)</sup><sup>[\[3\]](#environment-variables-json)</sup><sup>[\[4\]](#environment-variables-confd)</sup> for multiple different use cases using the `fish-lsp env` command.

You can store them directly in your `config.fish` to be autoloaded for every fish session. Or if you prefer a more modular approach, checkout the [`--confd`](#environment-variables-confd) flag which will structure the autoloaded environment variables to only be sourced when the `fish-lsp` command exists.

<blockquote>
<details>
<summary>

###### <a id="environment-variables-default">:package:</a> <b> Default Values: <code> fish-lsp env --show-default </code></b>

</summary>

<!-- FISH_LSP_UPDATE_CODEBLOCK: fish-lsp env --show-default -->
```fish
# $fish_lsp_enabled_handlers <ARRAY>
# Enables the fish-lsp handlers. By default, all stable handlers are enabled.
# (Options: 'complete', 'hover', 'rename', 'definition', 'implementation', 
#           'reference', 'logger', 'formatting', 'formatRange', 
#           'typeFormatting', 'codeAction', 'codeLens', 'folding', 
#           'selectionRange', 'signature', 'executeCommand', 'inlayHint', 
#           'highlight', 'diagnostic', 'popups', 'semanticTokens')
# (Default: [])
set -gx fish_lsp_enabled_handlers 

# $fish_lsp_disabled_handlers <ARRAY>
# Disables the fish-lsp handlers. By default, non-stable handlers are disabled.
# (Options: 'complete', 'hover', 'rename', 'definition', 'implementation', 
#           'reference', 'logger', 'formatting', 'formatRange', 
#           'typeFormatting', 'codeAction', 'codeLens', 'folding', 
#           'selectionRange', 'signature', 'executeCommand', 'inlayHint', 
#           'highlight', 'diagnostic', 'popups', 'semanticTokens')
# (Default: [])
set -gx fish_lsp_disabled_handlers 

# $fish_lsp_commit_characters <ARRAY>
# Array of the completion expansion characters.
# Single letter values only.
# Commit characters are used to select completion items, as shortcuts.
# (Example Options: '.', ',', ';', ':', '(', ')', '[', ']', '{', '}', '<', 
#                   '>', ''', '"', '=', '+', '-', '/', '\', '|', '&', '%', 
#                   '$', '#', '@', '!', '?', '*', '^', '`', '~', '\t', ' ')
# (Default: ['\t', ';', ' '])
set -gx fish_lsp_commit_characters '\t' ';' ' '

# $fish_lsp_log_file <STRING>
# A path to the fish-lsp's logging file. Empty string disables logging.
# (Example Options: '/tmp/fish_lsp.log', '~/path/to/fish_lsp/logs.txt')
# (Default: '')
set -gx fish_lsp_log_file ''

# $fish_lsp_log_level <STRING>
# The logging severity level for displaying messages in the log file.
# (Options: 'debug', 'info', 'warning', 'error', 'log')
# (Default: '')
set -gx fish_lsp_log_level ''

# $fish_lsp_all_indexed_paths <ARRAY>
# The fish file paths to include in the fish-lsp's startup indexing, as workspaces.
# Order matters (usually place `$__fish_config_dir` before `$__fish_data_dir`).
# (Example Options: '$HOME/.config/fish', '/usr/share/fish', 
#                   '$__fish_config_dir', '$__fish_data_dir')
# (Default: ['$__fish_config_dir', '$__fish_data_dir'])
set -gx fish_lsp_all_indexed_paths "$__fish_config_dir" "$__fish_data_dir"

# $fish_lsp_modifiable_paths <ARRAY>
# The fish file paths, for workspaces where global symbols can be renamed by the user.
# (Example Options: '/usr/share/fish', '$HOME/.config/fish', 
#                   '$__fish_data_dir', '$__fish_config_dir')
# (Default: ['$__fish_config_dir'])
set -gx fish_lsp_modifiable_paths "$__fish_config_dir"

# $fish_lsp_diagnostic_disable_error_codes <ARRAY>
# The diagnostics error codes to disable from the fish-lsp's diagnostics.
# (Options: 1001, 1002, 1003, 1004, 1005, 2001, 2002, 2003, 2004, 3001, 3002, 
#           3003, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 5001, 5555, 
#           6001, 7001, 8001, 9999)
# (Default: [])
set -gx fish_lsp_diagnostic_disable_error_codes 

# $fish_lsp_max_diagnostics <NUMBER>
# The maximum number of diagnostics to return per file.
# Using value `0` means unlimited diagnostics.
# To entirely disable diagnostics use `fish_lsp_disabled_handlers`
# (Example Options: 0, 10, 25, 50, 100, 250)
# (Default: 0)
set -gx fish_lsp_max_diagnostics 0

# $fish_lsp_enable_experimental_diagnostics <BOOLEAN>
# Enables the experimental diagnostics feature, using `fish --no-execute`.
# This feature will enable the diagnostic error code 9999 (disabled by default).
# (Options: 'true', 'false')
# (Default: 'false')
set -gx fish_lsp_enable_experimental_diagnostics false

# $fish_lsp_strict_conditional_command_warnings <BOOLEAN>
# Diagnostic `3002` includes/excludes conditionally chained commands to explicitly check existence.
# ENABLED EXAMPLE: `command -q ls && command ls || echo 'no ls'`
# DISABLED EXAMPLE: `command ls || echo 'no ls'`
# (Options: 'true', 'false')
# (Default: 'false')
set -gx fish_lsp_strict_conditional_command_warnings false

# $fish_lsp_prefer_builtin_fish_commands <BOOLEAN>
# Show diagnostic `2004` which warns the user when they are using a recognized external command that can be replaced by an equivalent fish builtin command.
# (Options: 'true', 'false')
# (Default: 'false')
set -gx fish_lsp_prefer_builtin_fish_commands false

# $fish_lsp_allow_fish_wrapper_functions <BOOLEAN>
# Show warnings when `alias`, `export`, etc... are used instead of their equivalent fish builtin commands.
# Some commands will provide quick-fixes to convert this diagnostic to its equivalent fish command.
# Diagnostic `2002` is shown when this setting is false, and hidden when true.
# (Options: 'true', 'false')
# (Default: 'true')
set -gx fish_lsp_allow_fish_wrapper_functions true

# $fish_lsp_require_autoloaded_functions_to_have_description <BOOLEAN>
# Show warning diagnostic `4008` when an autoloaded function definition does not have a description `function -d/--description '...'; end;`
# (Options: 'true', 'false')
# (Default: 'true')
set -gx fish_lsp_require_autoloaded_functions_to_have_description true

# $fish_lsp_max_background_files <NUMBER>
# The maximum number of background files to read into buffer on startup.
# (Example Options: 100, 250, 500, 1000, 5000, 10000)
# (Default: 10000)
set -gx fish_lsp_max_background_files 10000

# $fish_lsp_show_client_popups <BOOLEAN>
# Should the client receive pop-up window notification requests from the fish-lsp server?
# (Options: 'true', 'false')
# (Default: 'false')
set -gx fish_lsp_show_client_popups true

# $fish_lsp_single_workspace_support <BOOLEAN>
# Try to limit the fish-lsp's workspace searching to only the current workspace open.
# (Options: 'true', 'false')
# (Default: 'false')
set -gx fish_lsp_single_workspace_support false

# $fish_lsp_ignore_paths <ARRAY>
# Glob paths to never search when indexing their parent folder
# (Example Options: '**/.git/**', '**/node_modules/**', '**/vendor/**', 
#                   '**/__pycache__/**', '**/docker/**', 
#                   '**/containerized/**', '**/*.log', '**/tmp/**')
# (Default: ['**/.git/**', '**/node_modules/**', '**/containerized/**', 
#           '**/docker/**'])
set -gx fish_lsp_ignore_paths '**/.git/**' '**/node_modules/**' '**/containerized/**' '**/docker/**'

# $fish_lsp_max_workspace_depth <NUMBER>
# The maximum depth for the lsp to search when starting up.
# (Example Options: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20)
# (Default: 5)
set -gx fish_lsp_max_workspace_depth 3

# $fish_lsp_fish_path <STRING>
# A path to the fish executable to use exposing fish binary to use in server's spawned child_processes.
# Typically, this is used in the language-client's `FishServer.initialize(connection, InitializeParams.initializationOptions)`, NOT as an environment variable
# (Example Options: 'fish', '/usr/bin/fish', '/usr/.local/bin/fish', 
#                   '~/.local/bin/fish')
# (Default: '')
set -gx fish_lsp_fish_path 'fish'
```

</details>
</blockquote>

<blockquote>
<details>
<summary>

###### <a id="environment-variables-template">:gear:</a> <b>Complete Configuration Template: <code> fish-lsp env --create </code></b>

</summary>

<!-- FISH_LSP_UPDATE_CODEBLOCK: fish-lsp env --create -->
```fish
# $fish_lsp_enabled_handlers <ARRAY>
# Enables the fish-lsp handlers. By default, all stable handlers are enabled.
# (Options: 'complete', 'hover', 'rename', 'definition', 'implementation', 
#           'reference', 'logger', 'formatting', 'formatRange', 
#           'typeFormatting', 'codeAction', 'codeLens', 'folding', 
#           'selectionRange', 'signature', 'executeCommand', 'inlayHint', 
#           'highlight', 'diagnostic', 'popups', 'semanticTokens')
# (Default: [])
set -gx fish_lsp_enabled_handlers 

# $fish_lsp_disabled_handlers <ARRAY>
# Disables the fish-lsp handlers. By default, non-stable handlers are disabled.
# (Options: 'complete', 'hover', 'rename', 'definition', 'implementation', 
#           'reference', 'logger', 'formatting', 'formatRange', 
#           'typeFormatting', 'codeAction', 'codeLens', 'folding', 
#           'selectionRange', 'signature', 'executeCommand', 'inlayHint', 
#           'highlight', 'diagnostic', 'popups', 'semanticTokens')
# (Default: [])
set -gx fish_lsp_disabled_handlers 

# $fish_lsp_commit_characters <ARRAY>
# Array of the completion expansion characters.
# Single letter values only.
# Commit characters are used to select completion items, as shortcuts.
# (Example Options: '.', ',', ';', ':', '(', ')', '[', ']', '{', '}', '<', 
#                   '>', ''', '"', '=', '+', '-', '/', '\', '|', '&', '%', 
#                   '$', '#', '@', '!', '?', '*', '^', '`', '~', '\t', ' ')
# (Default: ['\t', ';', ' '])
set -gx fish_lsp_commit_characters 

# $fish_lsp_log_file <STRING>
# A path to the fish-lsp's logging file. Empty string disables logging.
# (Example Options: '/tmp/fish_lsp.log', '~/path/to/fish_lsp/logs.txt')
# (Default: '')
set -gx fish_lsp_log_file 

# $fish_lsp_log_level <STRING>
# The logging severity level for displaying messages in the log file.
# (Options: 'debug', 'info', 'warning', 'error', 'log')
# (Default: '')
set -gx fish_lsp_log_level 

# $fish_lsp_all_indexed_paths <ARRAY>
# The fish file paths to include in the fish-lsp's startup indexing, as workspaces.
# Order matters (usually place `$__fish_config_dir` before `$__fish_data_dir`).
# (Example Options: '$HOME/.config/fish', '/usr/share/fish', 
#                   '$__fish_config_dir', '$__fish_data_dir')
# (Default: ['$__fish_config_dir', '$__fish_data_dir'])
set -gx fish_lsp_all_indexed_paths 

# $fish_lsp_modifiable_paths <ARRAY>
# The fish file paths, for workspaces where global symbols can be renamed by the user.
# (Example Options: '/usr/share/fish', '$HOME/.config/fish', 
#                   '$__fish_data_dir', '$__fish_config_dir')
# (Default: ['$__fish_config_dir'])
set -gx fish_lsp_modifiable_paths 

# $fish_lsp_diagnostic_disable_error_codes <ARRAY>
# The diagnostics error codes to disable from the fish-lsp's diagnostics.
# (Options: 1001, 1002, 1003, 1004, 1005, 2001, 2002, 2003, 2004, 3001, 3002, 
#           3003, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 5001, 5555, 
#           6001, 7001, 8001, 9999)
# (Default: [])
set -gx fish_lsp_diagnostic_disable_error_codes 

# $fish_lsp_max_diagnostics <NUMBER>
# The maximum number of diagnostics to return per file.
# Using value `0` means unlimited diagnostics.
# To entirely disable diagnostics use `fish_lsp_disabled_handlers`
# (Example Options: 0, 10, 25, 50, 100, 250)
# (Default: 0)
set -gx fish_lsp_max_diagnostics 

# $fish_lsp_enable_experimental_diagnostics <BOOLEAN>
# Enables the experimental diagnostics feature, using `fish --no-execute`.
# This feature will enable the diagnostic error code 9999 (disabled by default).
# (Options: 'true', 'false')
# (Default: 'false')
set -gx fish_lsp_enable_experimental_diagnostics 

# $fish_lsp_strict_conditional_command_warnings <BOOLEAN>
# Diagnostic `3002` includes/excludes conditionally chained commands to explicitly check existence.
# ENABLED EXAMPLE: `command -q ls && command ls || echo 'no ls'`
# DISABLED EXAMPLE: `command ls || echo 'no ls'`
# (Options: 'true', 'false')
# (Default: 'false')
set -gx fish_lsp_strict_conditional_command_warnings 

# $fish_lsp_prefer_builtin_fish_commands <BOOLEAN>
# Show diagnostic `2004` which warns the user when they are using a recognized external command that can be replaced by an equivalent fish builtin command.
# (Options: 'true', 'false')
# (Default: 'false')
set -gx fish_lsp_prefer_builtin_fish_commands 

# $fish_lsp_allow_fish_wrapper_functions <BOOLEAN>
# Show warnings when `alias`, `export`, etc... are used instead of their equivalent fish builtin commands.
# Some commands will provide quick-fixes to convert this diagnostic to its equivalent fish command.
# Diagnostic `2002` is shown when this setting is false, and hidden when true.
# (Options: 'true', 'false')
# (Default: 'true')
set -gx fish_lsp_allow_fish_wrapper_functions 

# $fish_lsp_require_autoloaded_functions_to_have_description <BOOLEAN>
# Show warning diagnostic `4008` when an autoloaded function definition does not have a description `function -d/--description '...'; end;`
# (Options: 'true', 'false')
# (Default: 'true')
set -gx fish_lsp_require_autoloaded_functions_to_have_description 

# $fish_lsp_max_background_files <NUMBER>
# The maximum number of background files to read into buffer on startup.
# (Example Options: 100, 250, 500, 1000, 5000, 10000)
# (Default: 10000)
set -gx fish_lsp_max_background_files 

# $fish_lsp_show_client_popups <BOOLEAN>
# Should the client receive pop-up window notification requests from the fish-lsp server?
# (Options: 'true', 'false')
# (Default: 'false')
set -gx fish_lsp_show_client_popups 

# $fish_lsp_single_workspace_support <BOOLEAN>
# Try to limit the fish-lsp's workspace searching to only the current workspace open.
# (Options: 'true', 'false')
# (Default: 'false')
set -gx fish_lsp_single_workspace_support 

# $fish_lsp_ignore_paths <ARRAY>
# Glob paths to never search when indexing their parent folder
# (Example Options: '**/.git/**', '**/node_modules/**', '**/vendor/**', 
#                   '**/__pycache__/**', '**/docker/**', 
#                   '**/containerized/**', '**/*.log', '**/tmp/**')
# (Default: ['**/.git/**', '**/node_modules/**', '**/containerized/**', 
#           '**/docker/**'])
set -gx fish_lsp_ignore_paths 

# $fish_lsp_max_workspace_depth <NUMBER>
# The maximum depth for the lsp to search when starting up.
# (Example Options: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20)
# (Default: 5)
set -gx fish_lsp_max_workspace_depth 

# $fish_lsp_fish_path <STRING>
# A path to the fish executable to use exposing fish binary to use in server's spawned child_processes.
# Typically, this is used in the language-client's `FishServer.initialize(connection, InitializeParams.initializationOptions)`, NOT as an environment variable
# (Example Options: 'fish', '/usr/bin/fish', '/usr/.local/bin/fish', 
#                   '~/.local/bin/fish')
# (Default: '')
set -gx fish_lsp_fish_path
```

</details>
</blockquote>

<blockquote>
<details>
<summary>

###### <a id="environment-variables-json">:floppy_disk:</a> <b> Formatting as JSON:</b> <code> fish-lsp env --show-default --json </code>

</summary>

<!-- FISH_LSP_UPDATE_CODEBLOCK: fish-lsp env --show-default --json -->
```json
{
  "fish_lsp_enabled_handlers": [],
  "fish_lsp_disabled_handlers": [],
  "fish_lsp_commit_characters": [
    "\t",
    ";",
    " "
  ],
  "fish_lsp_log_file": "",
  "fish_lsp_log_level": "",
  "fish_lsp_all_indexed_paths": [
    "$__fish_config_dir",
    "$__fish_data_dir"
  ],
  "fish_lsp_modifiable_paths": [
    "$__fish_config_dir"
  ],
  "fish_lsp_diagnostic_disable_error_codes": [],
  "fish_lsp_max_diagnostics": 0,
  "fish_lsp_enable_experimental_diagnostics": false,
  "fish_lsp_strict_conditional_command_warnings": false,
  "fish_lsp_prefer_builtin_fish_commands": false,
  "fish_lsp_allow_fish_wrapper_functions": true,
  "fish_lsp_require_autoloaded_functions_to_have_description": true,
  "fish_lsp_max_background_files": 10000,
  "fish_lsp_show_client_popups": true,
  "fish_lsp_single_workspace_support": false,
  "fish_lsp_ignore_paths": [
    "**/.git/**",
    "**/node_modules/**",
    "**/containerized/**",
    "**/docker/**"
  ],
  "fish_lsp_max_workspace_depth": 3,
  "fish_lsp_fish_path": "fish"
}
```

</details></blockquote>

<blockquote>
<details>
<summary>

###### <a id="environment-variables-writing"> :jigsaw: </a> <b> Writing current values to <code> ~/.config/fish/conf.d/fish-lsp.fish </code></b>

</summary>

```fish
## clear the current fish-lsp configuration
## >_ fish-lsp env --names-only | string split \n | read -e $name;

## grab only specific variables
fish-lsp env --show-default --only fish_lsp_all_indexed_paths fish_lsp_diagnostic_disable_error_codes | source

## Write the current fish-lsp configuration to ~/.config/fish/conf.d/fish-lsp.fish
fish-lsp env --show --confd > ~/.config/fish/conf.d/fish-lsp.fish
```

</details>
</blockquote>

For language clients that import the source code directly and manually connect with the server (e.g., [VSCode](https://github.com/ndonfris/vscode-fish-lsp/blob/4aa63803a0d0a65ceabf164eaeb5a3e360662ef9/package.json#L136)), passing the environment configuration through the [`initializeParams.initializationOptions`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initializeParams) is also possible.

#### Command Flags

Both the flags `--enable` and `--disable` are provided on the `fish-lsp start` subcommand. __Default configuration enables all stable server handlers__.

```fish
# displays what handlers are enabled. Removing the dump flag will run the server.
fish-lsp start --disable complete signature --dump 
```

#### Further Server Configuration

Any [flags](#command-flags) will overwrite their corresponding [environment variables](#environment-variables), if both are seen for the `fish-lsp` process. For this reason, it is encouraged to wrap any non-standard behavior of the `fish-lsp` in [functions](https://fishshell.com/docs/current/language.html#functions) or [aliases](https://fishshell.com/docs/current/language.html#defining-aliases).

Due to the vast possibilities this project aims to support in the fish shell, [sharing useful configurations is highly encouraged](https://github.com/ndonfris/fish-lsp/discussions).

##### Project Specific configuration via dot-env

If you are using the environment variables, or an alias to start the server from a shell instance, you can also use a `.env` file to set project specific overrides.

This is not directly supported by the server, but can be achieved using the variety of dotenv tools available.<sup>[\[1\]](https://github.com/berk-karaal/loadenv.fish)</sup><sup>[\[2\]](https://direnv.net)</sup><sup>[\[3\]](https://github.com/jdx/mise)</sup><sup>[\[4\]](https://github.com/hyperupcall/autoenv)</sup>

<!-- [1]: https://github.com/berk-karaal/loadenv.fish] -->
<!-- [2]: https://direnv.net] -->
<!-- [3]: https://github.com/jdx/mise] -->
<!-- [4]: https://github.com/hyperupcall/autoenv] -->
<!-- ![](https://github.com/ndonfris/fish-lsp.dev/blob/master/public/comment.png?raw=true) -->

##### Configuration via Disable Comments

<div align="center">

![`# @fish-lsp-disable`](https://github.com/ndonfris/fish-lsp.dev/blob/master/public/comment.svg?raw=true)

</div>

Single document configurations can be set using fish-shell comments to disable diagnostics or formatting from applying to specific lines or sections of a file. These comments are parsed by the server when a file is opened, and can be placed anywhere in the file.
<!-- These comments generally follow the format: `# fish_*` -->

If you're interested in disabling specific diagnostic messages, the [wiki](https://github.com/ndonfris/fish-lsp/wiki) includes a table of [error codes](https://github.com/ndonfris/fish-lsp/wiki/Diagnostic-Error-Codes) that should be helpful. Diagnostics are a newer feature so [PRs](https://github.com/ndonfris/fish-lsp/blob/master/docs/CONTRIBUTING.md#getting-started-rocket) are welcome to improve their support.

Any diagnostic can be disabled by providing its error code to the environment variable `fish_lsp_diagnostic_disable_error_codes` (see the [template above](#environment-variables) for an example).

<!-- <details> -->
<!--   <summary><b>Example</b> <code>edit_command_buffer</code> wrapper to conditionally disable specific <code>fish-lsp</code> features</summary> -->
<!---->
<!--   > ```fish -->
<!--   > function edit_command_buffer_wrapper --description 'edit command buffer with custom server configurations' -->
<!--   >   # place any CUSTOM server configurations here -->
<!--   >   set -lx fish_lsp_diagnostic_disable_error_codes 1001 1002 1003 1004 2001 2002 2003 3001 3002 3003  -->
<!--   >   set -lx fish_lsp_show_client_popups false -->
<!--   >  -->
<!--   >   # open the command buffer with the custom server configuration, without -->
<!--   >   # overwriting the default server settings -->
<!--   >   edit_command_buffer -->
<!--   > end -->
<!--   > bind \ee edit_command_buffer_wrapper -->
<!--   > # now pressing alt+e in an interactive command prompt will open fish-lsp with the -->
<!--   > # options set above, but opening the `$EDITOR` normally will still behave as expected -->
<!--   > ``` -->
<!--   > -->
<!--   > This allows normal editing of fish files to keep their default behaviour, while disabling unwanted server features for _"interactive"_ buffers. -->
<!---->
<!-- </details> -->

## Trouble Shooting

If you encounter any issues with the server, the following commands may be useful to help diagnose the problem:

- Show every available <a id="#subcommand">sub-command</a> and flag for the `fish-lsp`

  ```fish
  fish-lsp --help-all
  ```

- <a id="info"></a>Ensure that the `fish-lsp` command is available in your system's `$PATH` by running `which fish-lsp` or `fish-lsp info --bin`.

  ```fish
  fish-lsp info
  ```

- <a id="startup"></a>Confirm that the language server is able to startup correctly by indexing the `$fish_lsp_all_indexed_paths` directories.

  ```fish
  fish-lsp info --time-startup
  ```

  > <ins><b>Note:</b></ins>
  > There is also, `fish-lsp info --time-only` which will show a less verbose summary of the startup timings. To limit either of these flags to a specific folder, use `--use-workspace ~/path/to/fish`.

- <a id="health"></a>Check the <b>health</b> of the server.

  ```fish
  fish-lsp info --check-health
  ```

- <a id="logs"></a>Check the <b>server logs</b>, while a server is running.

  ```fish
  set -gx fish_lsp_log_file /tmp/fish_lsp.log
  tail -f (fish-lsp info --log-file)
  # open the server somewhere else
  ```

- <a id="source-maps"></a>Enable [source maps](https://www.typescriptlang.org/tsconfig/#sourceMap) to debug the bundled server code.

  ```fish
  set -gx NODE_OPTIONS '--enable-source-maps --inspect' 
  $EDITOR ~/.config/fish/config.fish
  ```

- <a id="tree-sitter"></a>Show the [tree-sitter](https://github.com/esdmr/tree-sitter-fish) parse tree for a specific file:

  ```fish
  fish-lsp info --dump-parse-tree path/to/file.fish
  ```

##### Abbreviations to shorten the amount of characters typed for many of the above commands are available on the [wiki](https://github.com/ndonfris/fish-lsp/wiki/Abbreviations)

## Additional Resources

- [Contributing](./docs/CONTRIBUTING.md) - documentation describing how to contribute to the fish-lsp project.
- [Roadmap](./docs/ROADMAP.md) - goals for future project releases.
- [Wiki](https://github.com/ndonfris/fish-lsp/wiki) - further documentation and knowledge relevant to the project
- [Discussions](https://github.com/ndonfris/fish-lsp/discussions) - interact with maintainers
- [Site](https://fish-lsp.dev/) - website homepage
- [Client Examples](https://github.com/ndonfris/fish-lsp/wiki/Client-Configurations) - testable language client configurations
- [Sources](https://github.com/ndonfris/fish-lsp/wiki/Sources) - major influences for the project

## Contributors

Contributions of any kind are welcome! Special thanks to anyone who contributed to the project! :pray:

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
  <tbody>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/ndonfris"><img src="https://avatars.githubusercontent.com/u/49458459?v=4?s=50" width="50px;" alt="nick"/><br /><sub><b>nick</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=ndonfris" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/mimikun"><img src="https://avatars.githubusercontent.com/u/13450321?v=4?s=50" width="50px;" alt="mimikun"/><br /><sub><b>mimikun</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=mimikun" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/jpaju"><img src="https://avatars.githubusercontent.com/u/36770267?v=4?s=50" width="50px;" alt="Jaakko Paju"/><br /><sub><b>Jaakko Paju</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=jpaju" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/shaleh"><img src="https://avatars.githubusercontent.com/u/1377996?v=4?s=50" width="50px;" alt="Sean Perry"/><br /><sub><b>Sean Perry</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=shaleh" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://mastodon.online/@cova"><img src="https://avatars.githubusercontent.com/u/385249?v=4?s=50" width="50px;" alt="Fabio Coatti"/><br /><sub><b>Fabio Coatti</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=cova-fe" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/PeterCardenas"><img src="https://avatars.githubusercontent.com/u/16930781?v=4?s=50" width="50px;" alt="Peter Cardenas"/><br /><sub><b>Peter Cardenas</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=PeterCardenas" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/petertriho"><img src="https://avatars.githubusercontent.com/u/7420227?v=4?s=50" width="50px;" alt="Peter Tri Ho"/><br /><sub><b>Peter Tri Ho</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=petertriho" title="Code">💻</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/bnwa"><img src="https://avatars.githubusercontent.com/u/74591246?v=4?s=50" width="50px;" alt="bnwa"/><br /><sub><b>bnwa</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=bnwa" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/branchvincent"><img src="https://avatars.githubusercontent.com/u/19800529?v=4?s=50" width="50px;" alt="Branch Vincent"/><br /><sub><b>Branch Vincent</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=branchvincent" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/devsunb"><img src="https://avatars.githubusercontent.com/u/23169202?v=4?s=50" width="50px;" alt="Jaeseok Lee"/><br /><sub><b>Jaeseok Lee</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=devsunb" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/ClanEver"><img src="https://avatars.githubusercontent.com/u/73160783?v=4?s=50" width="50px;" alt="ClanEver"/><br /><sub><b>ClanEver</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=ClanEver" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://degruchy.org/"><img src="https://avatars.githubusercontent.com/u/52262673?v=4?s=50" width="50px;" alt="Nathan DeGruchy"/><br /><sub><b>Nathan DeGruchy</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=ndegruchy" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://teddyhuang-00.github.io/"><img src="https://avatars.githubusercontent.com/u/64199650?v=4?s=50" width="50px;" alt="Nan Huang"/><br /><sub><b>Nan Huang</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=TeddyHuang-00" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/unlimitedsola"><img src="https://avatars.githubusercontent.com/u/3632663?v=4?s=50" width="50px;" alt="Sola"/><br /><sub><b>Sola</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=unlimitedsola" title="Code">💻</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/jose-elias-alvarez"><img src="https://avatars.githubusercontent.com/u/54108223?v=4?s=50" width="50px;" alt="Jose Alvarez"/><br /><sub><b>Jose Alvarez</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=jose-elias-alvarez" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://www.bernat.tech/"><img src="https://avatars.githubusercontent.com/u/690238?v=4?s=50" width="50px;" alt="Bernát Gábor"/><br /><sub><b>Bernát Gábor</b></sub></a><br /><a href="https://github.com/ndonfris/fish-lsp/commits?author=gaborbernat" title="Code">💻</a></td>
    </tr>
  </tbody>
</table>

<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://allcontributors.org) specification.

## License

[MIT](https://github.com/ndonfris/fish-lsp/blob/master/LICENSE.md)


================================================
FILE: SECURITY.md
================================================
# Security Policy

## Supported Versions

| Version   | Supported          |
| --------- | ------------------ |
| >= 1.1.x  | :white_check_mark: |
| < 1.1.0   | :x:                |

## Reporting a Vulnerability

If you discover a security vulnerability in fish-lsp, please report it responsibly.

**Do not open a public GitHub issue for security vulnerabilities.**

Instead, please report vulnerabilities by emailing the maintainer directly or by using
[GitHub's private vulnerability reporting](https://github.com/ndonfris/fish-lsp/security/advisories/new).

### What to include

- A description of the vulnerability
- Steps to reproduce the issue
- The potential impact
- Any suggested fixes (if applicable)

### Response timeline

- **Acknowledgment**: Within 48 hours of receiving your report
- **Assessment**: Within 7 days, we will assess the severity and provide an initial response
- **Fix**: Critical vulnerabilities will be prioritized and patched as soon as possible

## Scope

fish-lsp is a language server that runs locally and communicates with editors over stdio/TCP.
The primary security considerations include:

- **Code execution**: fish-lsp parses and analyzes fish shell scripts but does not execute them
- **File system access**: The server reads files within your workspace to provide language features
- **Dependencies**: Third-party npm packages are used and kept up to date

## Best Practices for Users

- Keep fish-lsp updated to the latest version
- Review workspace trust settings in your editor before opening untrusted projects
- Report any unexpected behavior that could indicate a security issue


================================================
FILE: eslint.config.ts
================================================
// @ts-check

import eslint from '@eslint/js';
import tseslint, { type ConfigArray } from 'typescript-eslint';
import stylistic from '@stylistic/eslint-plugin';
import globals from 'globals';

export default tseslint.config(
  {
    ignores: [
      'scripts/',
      'dist/',
      '.bun/',
      'out/',
      'build/',
      'lib/src/',
      'lib/*.d.ts',
      'release-assets/',
      'vitest.config.ts',
      'eslint.config.ts',
    ],
  },
  {
    files: ['**/*.ts'],
    extends: [
      eslint.configs.recommended,
      ...tseslint.configs.recommended,
    ],
    plugins: {
      '@stylistic': stylistic,
    },
    languageOptions: {
      globals: {
        ...globals.node,
        ...globals.es2022,
      },
      parserOptions: {
        projectService: true,
        tsconfigRootDir: __dirname,
      },
    },
    rules: {
      // --- Core rules ---
      'no-control-regex': 'off',
      'no-useless-assignment': 'off',
      curly: ['error', 'multi-line'],
      'dot-notation': 'error',
      eqeqeq: 'error',
      'no-console': ['warn', { allow: ['assert', 'warn', 'error'] }],
      'no-constant-binary-expression': 'error',
      'no-constructor-return': 'error',
      'no-template-curly-in-string': 'off',
      'no-fallthrough': 'off',
      'no-whitespace-before-property': 'error',
      'one-var-declaration-per-line': ['error', 'always'],
      'no-useless-escape': 'off',
      'no-extra-parens': 'off',
      'no-extra-semi': 'off',

      // --- @stylistic rules (replaces deprecated formatting rules) ---
      '@stylistic/array-bracket-spacing': 'error',
      '@stylistic/brace-style': 'error',
      '@stylistic/comma-dangle': ['error', 'always-multiline'],
      '@stylistic/comma-spacing': 'error',
      '@stylistic/computed-property-spacing': 'error',
      '@stylistic/eol-last': 'error',
      '@stylistic/func-call-spacing': 'error',
      '@stylistic/indent': ['error', 2, { SwitchCase: 1 }],
      '@stylistic/keyword-spacing': 'error',
      '@stylistic/linebreak-style': 'error',
      '@stylistic/no-extra-parens': 'error',
      '@stylistic/no-extra-semi': 'error',
      '@stylistic/no-multi-spaces': ['error', { ignoreEOLComments: true }],
      '@stylistic/no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }],
      '@stylistic/no-tabs': 'error',
      '@stylistic/no-trailing-spaces': 'error',
      '@stylistic/nonblock-statement-body-position': ['warn', 'beside', { overrides: { while: 'below' } }],
      '@stylistic/object-curly-spacing': ['error', 'always'],
      '@stylistic/padded-blocks': ['error', 'never'],
      '@stylistic/quote-props': ['error', 'as-needed'],
      '@stylistic/space-before-blocks': 'error',
      '@stylistic/space-before-function-paren': ['error', { anonymous: 'never', named: 'never' }],
      '@stylistic/space-in-parens': 'error',
      '@stylistic/space-infix-ops': 'error',
      '@stylistic/member-delimiter-style': ['warn', {
        singleline: {
          delimiter: 'semi',
          requireLast: true,
        },
      }],
      '@stylistic/quotes': ['error', 'single', { avoidEscape: true, allowTemplateLiterals: false }],
      '@stylistic/semi': ['warn', 'always'],

      // --- @typescript-eslint rules ---
      '@typescript-eslint/explicit-function-return-type': ['off', { allowExpressions: true }],
      '@typescript-eslint/explicit-module-boundary-types': ['off', { allowArgumentsExplicitlyTypedAsAny: false }],
      '@typescript-eslint/no-explicit-any': 'off',
      '@typescript-eslint/no-namespace': 'off',
      '@typescript-eslint/no-require-imports': 'error',
      '@typescript-eslint/no-unnecessary-qualifier': 'error',
      '@typescript-eslint/no-unused-vars': ['error', {
        argsIgnorePattern: '^_',
        varsIgnorePattern: '^_',
        caughtErrors: 'none',
      }],
      '@typescript-eslint/no-useless-constructor': 'error',
      '@typescript-eslint/ban-ts-comment': 'off',
      '@typescript-eslint/no-non-null-assertion': 'off',
      '@typescript-eslint/restrict-plus-operands': 'error',
      '@typescript-eslint/no-unsafe-declaration-merging': 'off',
    },
  },
  {
    files: ['tests/**/*.ts'],
    rules: {
      '@typescript-eslint/no-unused-vars': 'off',
      '@typescript-eslint/no-require-imports': 'off',
      'no-console': 'off',
      'no-control-regex': 'off',
      '@typescript-eslint/no-explicit-any': 'off',
    },
  },
) satisfies ConfigArray;


================================================
FILE: fish_files/exec.fish
================================================
#!/usr/bin/env fish

string collect -- $argv | read --tokenize --local cmd
fish --command "$cmd" 2>/dev/null
# begin
#   string collect -- $argv | read --local --tokenize cmd
#   fish --command "$cmd"
# end 2>/dev/null


================================================
FILE: fish_files/expand_cartesian.fish
================================================
#!/usr/bin/env fish

# Example usage:
#
# >_ ./expand_cartisian.fish {a,b,c}/foo/{1,2,3}
#   1  |a/foo/1|
#   2  |a/foo/2|

function expand_cartesian
    set idx 1
    for item in (fish -c "printf %s\n $(string split0 -- (string collect -- $argv | string unescape | string join0))")
        printf ' %s  |`%s`|\n' (string pad -c ' ' -w 3 -- "$idx") $item
        set idx (math $idx+1)
    end
end

expand_cartesian $argv


================================================
FILE: fish_files/get-autoloaded-filepath.fish
================================================
#!/usr/bin/env fish

argparse --stop-nonopt f/function c/completion m/max=+ -- $argv
or return 

set cmd_name (string split ' ' --max 1 --fields 1 --no-empty -- $argv)
if test -z "$cmd_name"
    return 0
end

set -ql _flag_max
and set max_results $_flag_max
or set max_results 100

if set -ql _flag_function
    path filter -f -- $fish_function_path/$cmd_name.fish 2>/dev/null | head -n $max_results
    return 0
end

if set -ql _flag_completion
    path filter -f -- $fish_complete_path/$cmd_name.fish 2>/dev/null | head -n $max_results
    return 0
end



================================================
FILE: fish_files/get-command-options.fish
================================================
#!/usr/bin/env fish

function backup_input 
    set -a -l _fish_lsp_file_cmps (fish -c "complete --do-complete '$argv -' | uniq") (fish -c "complete --do-complete '$argv ' | uniq") 

    for _fish_lsp_cmp in $_fish_lsp_file_cmps
        echo "$_fish_lsp_cmp"
    end
    return 0;
    and exit
end



# file is just used to get command options
# not used for tokens other than one needing a commandline completion

if test (count $argv) -ge 2
    fish -c "complete --do-complete '$argv' | uniq"
else 
    backup_input $argv
end



================================================
FILE: fish_files/get-completion.fish
================================================
#!/usr/bin/env fish

##
# File takes two arguments:
#       $argv[1] = '1' | '2' | '3'
#       $argv[2] =  string to be completed from the shell
#
##



function build_cmd --argument-names input
    set --local input_arr (string split --right --max 1 ' ' -- "$input")
    #switch "$input_arr[2]"
        ##case '-*'
            ##printf "complete --escape --do-complete '$input' | uniq | string match --regex --entire '^\-'"
        ##case ''
            ##string match -req '^\s?\$' -- "$input_arr[1]";
            ##printf "complete --escape --do-complete '$input' | uniq ";
            ##or printf "complete --escape --do-complete '$input -' | uniq | string match --regex --entire '^\-' && complete --escape --do-complete '$input ' | uniq";
        #case '*'
    #end
    printf "complete --escape --do-complete '$argv' | uniq"
end

# taken from my fish_config
function get-completions
    set --local cmd (build_cmd "$argv")
    eval $cmd
end

function get-subcommand-completions 
    set --local cmd (printf "complete --escape --do-complete '$argv ' | uniq")
    eval $cmd
end

function get-variable-completions
    if contains $argv (set -n)
        set --show $argv
    end
end

switch "$argv[1]"
    case '1'
        get-completions "$argv[2..]"
    case '2'
        get-subcommand-completions "$argv[2..]"
    case '3'
        get-variable-completions "$argv[2..]"
    case '*'
        get-completions "$argv"
end




================================================
FILE: fish_files/get-dependency.fish
================================================
#!/usr/local/bin/fish



set -l filepath (functions --all -D "$argv" 2>> /dev/null)

switch $filepath
    case 'n/a'
        echo ""
        return 0
    case \*
        echo "$filepath"
        return 0
end


================================================
FILE: fish_files/get-docs.fish
================================================
#!/usr/bin/env fish

# ┌───────┐
# │ utils │
# └───────┘
function __handle_builtin -d 'Retrieve documentation for a fish builtin'
    man $argv 2>/dev/null | sed -r 's/^ {7}/ /' | col -bx
    # Alt Approach:
    #   >_ `__fish_print_help $argv 2>/dev/null | command cat`
end
function __handle_function -d 'Retrieve documentation for a fish function'
    set output (functions -av $argv 2>/dev/null | col -bx)
    if test -n "$output"
        printf %s\n $output
        return 0
    else
        echo "ERROR(builtin): $argv doesn't have help documentation" >&2
        return 1
    end
end
function __handle_command -d 'Retrieve documentation for a system command'
    set output (man -a $argv 2>/dev/null | sed -r 's/^ {7}/ /' | col -bx)
    if test -n "$output"
        printf %s\n $output
        return 0
    else
        echo "ERROR(man $argv): $argv doesn't have man page" >&2
        return 1
    end
end

# git worktree --help -> git worktree
# git commit -m "msg" -> git commit
# git --help -> git
function validate_args -d 'Validate input by stopping on first non-option argument'
    for arg in $argv
        switch $arg
            case '-*'
                break
            case '*'
                printf "%s\n" $arg
        end
    end
end

# ┌────────────────────┐
# │ special processing │
# └────────────────────┘
# argparse --strict-longopts --move-unknown --unknown-arguments=none --stop-nonopt \
#     'function=&' 'builtin=&' 'command=&' 'use-help=&' 'h/help=&' -- $argv &>/dev/null 
# or 
argparse --ignore-unknown --stop-nonopt \
    'function=&' \
    'builtin=&' \
    'command=&' \
    'use-help' \
    'with-col' \
    'h/help=&' \
    -- $argv &>/dev/null
or return 0

# ┌──────────────┐
# │ help message │
# └──────────────┘
if set -ql _flag_h or set -ql _flag_help
    echo "Usage: get-docs.fish [OPTIONS] COMMAND

Retrieve documentation for fish builtins, functions, or commands.

Options:
  --function         Retrieve documentation for a fish function
  --builtin          Retrieve documentation for a fish builtin
  --command          Retrieve documentation for a system command
  --use-help         Use help documentation if available
  --with-col         Make sure pager is not used (pipes output through 'col -bx')
  -h, --help         Show this help message and exit

Examples:
  >_ get-docs.fish cd
  >_ get-docs.fish complete
  >_ get-docs.fish --function my_custom_function
  >_ get-docs.fish --builtin set
  >_ get-docs.fish --use-help --with-col set
"
    return 0
end

# ┌────────────┐
# │ core logic │
# └────────────┘

if set -ql _flag_use_help
    set cmd $argv --help
    if set -ql _flag_with_col
        set -a cmd \| col -bx
    end
    eval $cmd 2>/dev/null 
    return $status
end

if set -ql _flag_builtin || builtin -q $argv[1] 2>/dev/null
    __handle_builtin (string join '-' --no-empty -- (validate_args $argv))
    return $status
end

if set -ql _flag_function || functions -aq $argv[1] 2>/dev/null
    __handle_function $argv
    return $status
end

if set -ql _flag_command || command -aq $argv[1] 2>/dev/null
    __handle_command (string join '-' --no-empty -- (validate_args $argv))
    return $status
end

echo "ERROR: '$argv' is not a valid fish builtin, command or function" >&2
return 1


================================================
FILE: fish_files/get-documentation.fish
================================================
#!/usr/bin/env fish

## commands like mkdir or touch should reach this point 
function _flsp_get_command_without_manpage -d 'fallback for a command passed in without a manpage'
    set -l completions_docs (complete --do-complete="$argv -")
    if test -n "$completions_docs"
        echo -e "\t$argv Completions"
        echo $completions_docs[..10]
    else if test -n "$($argv --help 2>> /dev/null)"
        echo -e "\t$argv --help output"
        $argv --help 2>> /dev/null
    else
        echo ''
    end
end

function _flsp_get_manpage -d 'for a command with a manpage'
    man $argv | command col
end

set -l type_result (type -at "$argv[1]" 2> /dev/null)

switch "$type_result"
case "function"
    if type -f -q $argv 2>/dev/null
        _flsp_get_manpage $argv
    else
        functions --all $argv | tr -d '\b'
    end

case "builtin"
    __fish_print_help $argv 2>/dev/null | command cat
    return 0

case "file"
    set -l bad_manpage ( man -a $argv 2> /dev/null )
    
    if test -z "$bad_manpage" 
        echo ''
        return

    else if string match -rq "No manual entry for $argv" -- $bad_manpage
        _flsp_get_command_without_manpage $argv

    else 
        _flsp_get_manpage $argv
    end
case \*
    set -l bad_manpage ( man -a $argv 2> /dev/null )
    if test -z "$bad_manpage" 
        echo ''
        return 0
    else 
        _flsp_get_manpage $argv
        return 0
    end
end


================================================
FILE: fish_files/get-fish-autoloaded-paths.fish
================================================
#!/usr/bin/env fish

echo -e "__fish_bin_dir\t$(string join ':' -- $__fish_bin_dir)"

echo -e "__fish_config_dir\t$(string join ':' -- $__fish_config_dir)"
echo -e "__fish_data_dir\t$(string join ':' -- $__fish_data_dir)"
echo -e "__fish_help_dir\t$(string join ':' -- $__fish_help_dir)"

# docs unclear: https://fishshell.com/docs/current/language.html#syntax-function-autoloading
# includes __fish_sysconfdir but __fish_sysconf_dir is defined on local system 
echo -e "__fish_sysconfdir\t$(string join ':' -- $__fish_sysconfdir)"
echo -e "__fish_sysconf_dir\t$(string join ':' -- $__fish_sysconf_dir)"

echo -e "__fish_user_data_dir\t$(string join ':' -- $__fish_user_data_dir)"
echo -e "__fish_added_user_paths\t$(string join ':' -- $__fish_added_user_paths)"

echo -e "__fish_vendor_completionsdirs\t$(string join ':' -- $__fish_vendor_completionsdirs)"
echo -e "__fish_vendor_confdirs\t$(string join ':' -- $__fish_vendor_confdirs)"
echo -e "__fish_vendor_functionsdirs\t$(string join ':' -- $__fish_vendor_functionsdirs)"

echo -e "fish_function_path\t$(string join ':' -- $fish_function_path)"
echo -e "fish_complete_path\t$(string join ':' -- $fish_complete_path)"
echo -e "fish_user_paths\t$(string join ':' -- $fish_user_paths)"


================================================
FILE: fish_files/get-type-verbose.fish
================================================
#!/usr/bin/env fish

# takes a single argument and returns a string/token 
# without throwing an error

# possible return values are:
#      'builtin'
#      'variable'
#      'abbr'
#      'command'
#      'function'
#      'alias' ?

# meant to be used on a token. Below outlines the inclusion and exclusion of behavior
# expected by this shell script.
#    includes: some_builtin | some_function | some_variable | some_abbr | some_command
#    excludes: options | flags | subcommands | $variable | $$variables


function get_type_verbose --argument-names str
  # EDITING THIS SCRIPT? 
  # ORDER OF OPERATIONS MATTERS!
  if builtin --query -- "$str"
    echo "builitn"
  else if abbr -q -- "$str"
    echo 'abbr'
  else if functions --all --query -- "$str"
    # could be alias or function
    echo 'function'
  else if command -q -- "$str"
    echo 'command'
  else if set --query -- "$str"
    echo 'variable'
  else
    echo ''
  end
end

function get_first_token
  string match -req '^(\w+)-(\w+)$' -- "$argv"
  and string split -m 1 -f 1 '-' -- "$argv"
  or echo "$argv[1]"
end


set -l first "$(get_first_token $argv)"

get_type_verbose $first

================================================
FILE: fish_files/get-type.fish
================================================
#!/usr/bin/env fish

function get_type --argument-names str
    set -l type_result (type -t "$str" 2> /dev/null)
    switch "$type_result"
    case "function"
        if type -f -q $str 2>/dev/null || contains -- $str export
            echo 'command'
        else
            echo 'file'
        end
    case "builtin"
        echo 'command'
    case "file"
        echo 'command'
    case \*
        echo ''
    end
end

# command - shown using man
# file - shown using functions query

set -l first (string split -f 1 '-' -- "$argv")

set -l normal_output (get_type "$argv")
set -l fallback_output (get_type "$first")

if test -n "$normal_output"
    echo "$normal_output"
else if test -n "$fallback_output"
    echo "$fallback_output"
else
    echo ''
end


================================================
FILE: man/fish-lsp.1
================================================
.TH "FISH\-LSP" "1" "April 2026" "1.1.4-pre.0" "fish-lsp"
.SH "NAME"
\fBfish-lsp\fR \- A language server for the fish shell
.SH SYNOPSIS
.P
\fBfish\-lsp [OPTIONS]\fP
.br
\fBfish\-lsp [SUBCOMMAND] [OPTIONS]\fP
.SH DESCRIPTION
.P
\fBfish\-lsp\fP is a language server for the fish shell\. It provides IDE\-like features for fish shell scripts, such as syntax checking, linting, and auto\-completion\.
.P
It requires a language client that supports the Language Server Protocol (LSP)\.
.P
Some common language clients include: the builtin API for \fBnvim\fP (v0\.9+), lsp\-mode for \fBemacs\fP, or the fish\-lsp extension for \fBVSCode\fP\|\.
.P
Documentation below shows usage of the \fBfish\-lsp\fP command, including its subcommands and options\.
.SH OPTIONS
.P
\fB\-v\fP or \fB\-\-version\fP                Show version information and exit\.
.br
\fB\-h\fP or \fB\-\-help\fP                   Show help message and exit\.
.br
\fB\-\-help\-all\fP                     Show all the help information
.br
\fB\-\-help\-short\fP                   Show shortened help message
.br
\fB\-\-help\-man\fP                     Show manpage output
.SH SUBCOMMANDS
.SS \fBstart\fP
.P
Start the language server\.
.P
\fB\-\-enable\fP                       enable the language server features
.br
\fB\-\-disable\fP                      disable the language server features
.br
\fB\-\-dump\fP                         dump the json output of the language server features enabled after startup
.br
\fB\-\-stdio\fP                        use stdin/stdout for communication (default)
.br
\fB\-\-node\-ipc\fP                     use node IPC for communication
.br
\fB\-\-socket <port>\fP                use TCP socket for communication
.br
\fB\-\-memory\-limit <mb>\fP            set memory usage limit in MB
.br
\fB\-\-max\-files <number>\fP           override the maximum number of files to analyze
.br
\fB\-\-web\fP                          start server in web mode used for https://fish-lsp.dev/playground
.SS \fBenv\fP
.P
show the environment variables available to the lsp
.P
\fB\-c\fP or \fB\-\-create\fP                 create the environment variable
.br
\fB\-s\fP or \fB\-\-show\fP                   show the environment variables
.br
\fB\-\-show\-default\fP                 show the default values for fish\-lsp env variables
.br
\fB\-\-only <VAR>\fP                   only include the specified environment variables in the output
.br
\fB\-\-no\-global\fP                    don't use global scope when generating environment variables
.br
\fB\-\-no\-local\fP                     don't use local scope when generating environment variables
.br
\fB\-\-no\-export\fP                    don't use export flag when generating environment variables
.br
\fB\-\-no\-comments\fP                  skip outputting comments
.br
\fB\-\-confd\fP                        output for redirecting to conf\.d/fish\-lsp\.fish
.br
\fB\-\-json\fP                         output \fBfish_lsp_*\fP initialization variables as JSON object (for vscode \fBsettings\.json\fP)
.SS \fBinfo\fP
.P
show the build info of fish\-lsp
.P
\fB\-\-bin\fP                          show the path of the fish\-lsp executable
.br
\fB\-\-path\fP                         show the path of the entire fish\-lsp installation
.br
\fB\-\-build\-time\fP                   show the path of the entire fish\-lsp repo
.br
\fB\-\-build\-type\fP                   show the build type of the command
.br
\fB\-v\fP or \fB\-\-version\fP                show the lsp version
.br
\fB\-\-lsp\-version\fP                  show the vscode\-languageserver version
.br
\fB\-\-capabilities\fP                 show the lsp capabilities
.br
\fB\-\-man\-file\fP                     show the man file path
.br
\fB\-\-log\-file\fP                     show the log file path
.br
\fB\-\-show\fP                         show the man/log file contents (needs to be paired with \fB\-\-log\-file\fP or \fB\-\-man\-file\fP)
.br
\fB\-\-extra\fP                        show debugging server info (capabilities, paths, version, etc\.)
.br
\fB\-\-verbose\fP                      show debugging server info (capabilities, paths, version, etc\.)
.br
\fB\-\-check\-health\fP                 run diagnostics and report health status
.br
\fB\-\-health\-check\fP                 run diagnostics and report health status
.br
\fB\-\-time\-startup\fP                 time the startup of the fish\-lsp executable
.br
\fB\-\-time\-only\fP                    show brief summary of the startup timing
.br
\fB\-\-use\-workspace <PATH>\fP         use the workspace at the specified directory path when \fBfish\-lsp info \-\-time\-startup\fP is used
.br
\fB\-\-no\-warning\fP                   disable message in the \fBfish\-lsp info \-\-time\-startup\fP output
.br
\fB\-\-show\-files\fP                   show the files that were indexed during startup when \fBfish\-lsp info \-\-time\-startup\fP is used
.br
\fB\-\-dump\-symbol\-tree <FILE>\fP      show the fish\-lsp definition symbol tree for the specified file
.br
\fB\-\-dump\-parse\-tree <FILE>\fP       show the tree\-sitter AST for the specified file
.br
\fB\-\-dump\-semantic\-tokens <FILE>\fP  show the semantic\-tokens for the specified file
.br
\fB\-\-no\-color\fP                     disable color output from \fB\-\-dump\-*\fP output
.br
\fB\-\-no\-icons\fP                     disable icon usage in output from \fBfish\-lsp info \-\-dump\-symbol\-tree\fP
.br
\fB\-\-source\-maps\fP                  show the source\-maps
.br
\fB\-\-check\fP                        used in combination with \fB\-\-source\-maps\fP, verifies source\-maps are working by throwing an error
.br
\fB\-\-status\fP                       used in combination with \fB\-\-source\-maps\fP, shows status of source\-maps loading
.SS \fBurl\fP
.P
show a helpful url related to the fish\-lsp
.P
\fB\-\-repo\fP or \fB\-\-git\fP                show the github repo
.br
\fB\-\-npm\fP                          show the npm package url
.br
\fB\-\-homepage\fP                     show the homepage
.br
\fB\-\-contributions\fP                show the contributions url
.br
\fB\-\-wiki\fP                         show the github wiki
.br
\fB\-\-issues\fP or \fB\-\-report\fP           show the issues page
.br
\fB\-\-discussions\fP                  show the discussions page
.br
\fB\-\-clients\-repo\fP                 show the clients configuration repo
.br
\fB\-\-sources\fP                      show a list of helpful sources
.SS \fBcomplete\fP
.P
Provide completions for the \fBfish\-lsp\fP
.P
\fB\-\-names\fP                        show the feature names of the completions
.br
\fB\-\-toggles\fP                      show the feature names of the completions
.br
\fB\-\-fish\fP                         show fish script
.br
\fB\-\-features\fP                     show features
.br
\fB\-\-env\-variables\fP                show env variable completions
.br
\fB\-\-env\-variable\-names\fP           show env variable names
.br
\fB\-\-names\-with\-summary\fP           show the names with the summary for the completions
.br
\fB\-\-abbreviations\fP                show the 'fish\-lsp' subcommand abbreviations
.SH EXAMPLES

.RS 1
.IP \(bu 2
Start the \fBfish\-lsp\fP language server, with the default configuration:
.RS 2
.nf
>_ fish\-lsp start
.fi
.RE
.IP \(bu 2
Generate the completions for the \fBfish\-lsp\fP language server binary:
.RS 2
.nf
>_ fish\-lsp complete > ~/\.config/fish/completions/fish\-lsp\.fish
.fi
.RE
.IP \(bu 2
Debug the \fBfish\-lsp\fP language server by dumping the enabled features after startup:
.RS 2
.nf
>_ fish\-lsp start \-\-dump
.fi
.RE
.IP \(bu 2
Show information about the \fBfish\-lsp\fP language server:
.RS 2
.nf
>_ fish\-lsp info 
.fi
.RE
.IP \(bu 2
Show all the available information about the \fBfish\-lsp\fP language server:
.RS 2
.nf
>_ fish\-lsp info \-\-verbose
.fi
.RE
.IP \(bu 2
Show startup timing information for the \fBfish\-lsp\fP language server:
.RS 2
.nf
>_ fish\-lsp info \-\-time\-startup
.fi
.RE
.IP \(bu 2
Show startup timing information for the \fBfish\-lsp\fP language server for a specific workspace:
.RS 2
.nf
>_ fish\-lsp info \-\-time\-startup \-\-use\-workspace ~/\.config/fish \-\-no\-warning
.fi
.RE
.IP \(bu 2
Preform a health check on the \fBfish\-lsp\fP language server:
.RS 2
.nf
>_ fish\-lsp info \-\-check\-health
.fi
.RE
.IP \(bu 2
Show the definition symbol tree for a specific file:
.RS 2
.nf
>_ fish\-lsp info \-\-dump\-symbol\-tree ~/\.config/fish/config\.fish
.fi
.RE
.IP \(bu 2
Show the semantic tokens for a specific file (read from \fBstdin\fP):
.RS 2
.nf
>_ cat $__fish_data_dir/config\.fish | fish\-lsp info \-\-dump\-semantic\-tokens
.fi
.RE
.IP \(bu 2
Show the environment variables available to the \fBfish\-lsp\fP language server:
.RS 2
.nf
>_ fish\-lsp env \-\-show
.fi
.RE
.IP \(bu 2
Show the default values for specific environment variables used by the \fBfish\-lsp\fP language server:
.RS 2
.nf
>_ fish\-lsp env \-\-show\-default \-\-only fish_lsp_all_indexed_paths,fish_lsp_max_background_files \-\-no\-comments
.fi
.RE
.IP \(bu 2
Get sources related to the \fBfish\-lsp\fP language server's development:
.RS 2
.nf
>_ fish\-lsp url \-\-sources
.fi
.RE

.RE
.SH SEE ALSO

.RS 1
.IP \(bu 2
\fBwebsite:\fR \fIhttps://fish-lsp.dev/\fR
.IP \(bu 2
\fBrepo:\fR \fIhttps://github.com/ndonfris/fish-lsp\fR
.IP \(bu 2
\fBfish website:\fR \fIhttps://fishshell.com/\fR

.RE
.SH AUTHOR

.RS 1
.IP \(bu 2
Nick Donfris

.RE


================================================
FILE: package.json
================================================
{
  "$schema": "https://json.schemastore.org/package",
  "author": "ndonfris",
  "license": "MIT",
  "name": "fish-lsp",
  "version": "1.1.4-pre.0",
  "description": "LSP implementation for fish/fish-shell",
  "keywords": [
    "lsp",
    "fish",
    "fish-shell",
    "language-server-protocol",
    "language-server"
  ],
  "type": "commonjs",
  "homepage": "https://fish-lsp.dev",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/ndonfris/fish-lsp.git"
  },
  "bugs": {
    "url": "https://github.com/ndonfris/fish-lsp/issues"
  },
  "funding": {
    "url": "https://github.com/ndonfris",
    "type": "github"
  },
  "engines": {
    "node": ">=20.0.0"
  },
  "files": [
    "dist/fish-lsp",
    "dist/fish-lsp.d.ts",
    "package.json",
    "man/fish-lsp.1",
    "README.md",
    "LICENSE.md"
  ],
  "main": "./dist/fish-lsp",
  "typings": "./dist/fish-lsp.d.ts",
  "browser": "./dist/fish-lsp",
  "exports": {
    ".": {
      "types": "./dist/fish-lsp.d.ts",
      "import": "./dist/fish-lsp",
      "require": "./dist/fish-lsp"
    },
    "./server": {
      "types": "./dist/fish-lsp.d.ts",
      "import": "./dist/fish-lsp",
      "require": "./dist/fish-lsp"
    },
    "./web": {
      "types": "./dist/fish-lsp.d.ts",
      "import": "./dist/fish-lsp",
      "require": "./dist/fish-lsp"
    }
  },
  "bin": {
    "fish-lsp": "dist/fish-lsp"
  },
  "man": "man/fish-lsp.1",
  "scripts": {
    "prepare": "husky",
    "prepack:pack": "run-s --continue-on-error clean:build lint:check update-changelog generate:man generate:commands build:npm build:types sh:build-completions",
    "package": "yarn pack --filename fish-lsp.tgz",
    "build": "run-s -sn build:all sh:relink sh:build-completions",
    "build:watch": "run-s watch",
    "build:npm": "tsx scripts/esbuild/index.ts --npm",
    "build:npm:nosourcemaps": "tsx scripts/esbuild/index.ts --npm --sourcemaps=none",
    "build:types": "tsx scripts/esbuild/index.ts --types",
    "build:all": "tsx scripts/esbuild/index.ts --all",
    "dev": "tsx scripts/esbuild/index.ts",
    "watch": "tsx scripts/esbuild/index.ts --watch-all",
    "sh:build-completions": "fish ./scripts/build-completions.fish",
    "sh:build-time": "node ./scripts/build-time",
    "sh:relink": "fish ./scripts/relink-locally.fish",
    "sh:build-assets": "fish ./scripts/build-assets.fish",
    "sh:dev:complete:install": "fish ./scripts/dev-complete.fish --install",
    "sh:dev:complete:uninstall": "fish ./scripts/dev-complete.fish --uninstall",
    "sh:workspace-cli": "tsx ./scripts/workspace-cli.ts",
    "rm": "rimraf",
    "clean": "rimraf out dist lib man bin node_modules *.tgz .tsbuildinfo coverage .bun",
    "clean:all": "rimraf out lib dist bin .tsbuildinfo node_modules tree-sitter-fish.wasm logs.txt coverage .bun",
    "clean:build": "rimraf out lib dist bin .tsbuildinfo",
    "clean:packs": "rimraf *.tgz .tsbuildinfo",
    "clean:dev-completions": "fish ./scripts/dev-complete.fish --uninstall",
    "test": "env -i HOME=$HOME PATH=$PATH NODE_ENV=test USER=test_user vitest",
    "test:run": "env -i HOME=$HOME PATH=$PATH NODE_ENV=test USER=test_user vitest --run",
    "test:coverage": "env -i HOME=$HOME PATH=$PATH NODE_ENV=test USER=test_user vitest --coverage",
    "test:coverage:ui": "env -i HOME=$HOME PATH=$PATH NODE_ENV=test  USER=test_user vitest --ui --open --coverage",
    "test:coverage:run": "env -i HOME=$HOME PATH=$PATH NODE_ENV=test USER=test_user vitest --coverage --run",
    "publish-nightly": "fish ./scripts/publish-nightly.fish",
    "refactor": "knip",
    "lint:check": "eslint .",
    "lint:fix": "eslint . --fix",
    "lint:check-fix": "eslint . --fix-dry-run",
    "update:prerelease": "run-s lint:fix update-changelog generate:man update-codeblocks-in-docs",
    "update-codeblocks-in-docs": "tsx scripts/update-codeblocks-in-docs.ts",
    "update-changelog": "fish scripts/update-changelog.fish",
    "util:update-changelog": "conventional-changelog -i docs/CHANGELOG.md --same-file",
    "util:update-changelog:dry": "conventional-changelog -i docs/CHANGELOG.md --stdout",
    "util:update-changelog:dry:diff": "conventional-changelog -i docs/CHANGELOG.md --stdout | diff --color=always --unified docs/CHANGELOG.md -",
    "all-contributors": "npx -s -y all-contributors-cli -c .all-contributorsrc",
    "generate:commands": "tsx ./scripts/fish-commands-scrapper.ts --write-to-snippets || true",
    "generate:commands:check": "tsx ./scripts/fish-commands-scrapper.ts",
    "generate:snippets": "tsx ./scripts/fish-commands-scrapper.ts",
    "create:man:dir": "mkdir -p ./man",
    "generate:man": "run-s create:man:dir generate:man:actual",
    "generate:man:cat": "npx marked-man --date \"$(date)\"  --manual fish-lsp --section 1 -i ./docs/MAN_FILE.md -o ./man/fish-lsp.1 2>/dev/null",
    "generate:man:actual": "yarn run --silent generate:man:cat > ./man/fish-lsp.1",
    "generate:man:diff": "yarn run --silent generate:man:cat | diff --color=always --unified ./man/fish-lsp.1 - && echo 'NO CHANGES TO man/fish-lsp.1' || echo 'CHANGES IN man/fish-lsp.1'",
    "generate:man:cp": "cp ./man/fish-lsp.1 ~/.local/share/man/man1/fish-lsp.1",
    "generate:man:write-global": "run-s generate:man generate:man:cp"
  },
  "lint-staged": {
    "**/*.ts": [
      "eslint --fix"
    ]
  },
  "contributes": {
    "commands": [
      {
        "command": "fish-lsp.executeRange",
        "title": "execute the range"
      },
      {
        "command": "fish-lsp.executeLine",
        "title": "execute the line"
      },
      {
        "command": "fish-lsp.executeBuffer",
        "title": "execute the buffer"
      },
      {
        "command": "fish-lsp.execute",
        "title": "execute the buffer"
      },
      {
        "command": "fish-lsp.createTheme",
        "title": "create a new theme"
      },
      {
        "command": "fish-lsp.showStatusDocs",
        "title": "show the status documentation"
      },
      {
        "command": "fish-lsp.showWorkspaceMessage",
        "title": "show the workspace message"
      },
      {
        "command": "fish-lsp.updateWorkspace",
        "title": "update the workspace"
      },
      {
        "command": "fish-lsp.fixAll",
        "title": "execute all quick-fixes in file"
      },
      {
        "command": "fish-lsp.toggleSingleWorkspaceSupport",
        "title": "enable/disable single workspace support"
      },
      {
        "command": "fish-lsp.generateEnvVariables",
        "title": "output the $fish_lsp_* environment variables"
      },
      {
        "command": "fish-lsp.showReferences",
        "title": "show references"
      },
      {
        "command": "fish-lsp.showInfo",
        "title": "show server info"
      }
    ]
  },
  "dependencies": {
    "@esdmr/tree-sitter-fish": "^3.7.0",
    "chalk": "^5.6.2",
    "commander": "^12.1.0",
    "fast-glob": "^3.3.3",
    "fs-extra": "^11.3.4",
    "husky": "^9.1.7",
    "memfs": "4.38.1",
    "npm-run-all": "^4.1.5",
    "source-map-support": "^0.5.21",
    "vscode-languageserver": "^9.0.1",
    "vscode-languageserver-protocol": "^3.17.5",
    "vscode-languageserver-textdocument": "^1.0.12",
    "vscode-uri": "^3.1.0",
    "web-tree-sitter": "^0.23.0",
    "zod": "^3.25.76"
  },
  "devDependencies": {
    "@commitlint/cli": "^19.8.1",
    "@commitlint/config-conventional": "^20.5.0",
    "@esbuild-plugins/node-globals-polyfill": "^0.2.3",
    "@eslint/js": "^10.0.1",
    "@stylistic/eslint-plugin": "^4.4.1",
    "@tsconfig/node-ts": "^23.6.4",
    "@tsconfig/node22": "^22.0.5",
    "@types/chokidar": "^2.1.7",
    "@types/eslint": "^9.6.1",
    "@types/fs-extra": "^11.0.4",
    "@types/jsdom": "^21.1.7",
    "@types/node": "^24.12.2",
    "@types/node-fetch": "^2.6.13",
    "@vitest/coverage-v8": "3.2.4",
    "@vitest/ui": "^3.2.4",
    "chokidar": "^4.0.3",
    "conventional-changelog": "^7.2.0",
    "dts-bundle-generator": "^9.5.1",
    "esbuild": "^0.28.0",
    "esbuild-plugin-polyfill-node": "^0.3.0",
    "esbuild-plugins-node-modules-polyfill": "^1.8.1",
    "eslint": "^9.39.4",
    "fast-check": "^4.7.0",
    "globals": "^16.5.0",
    "hono": "^4.12.14",
    "jsdom": "^26.1.0",
    "knip": "^5.88.1",
    "lint-staged": "^15.5.2",
    "marked-man": "^1.3.6",
    "node-fetch": "^3.3.2",
    "rimraf": "^6.1.3",
    "tsx": "^4.21.0",
    "typescript": "^5.9.3",
    "typescript-eslint": "^8.59.0",
    "vite": "^7.3.2",
    "vite-plugin-wasm": "^3.6.0",
    "vite-tsconfig-paths": "^5.1.4",
    "vitest": "^3.2.4"
  },
  "resolutions": {
    "glob": "^12.0.0",
    "minimatch": "^10.2.0"
  }
}


================================================
FILE: renovate.json
================================================
{
  "extends": [
    "config:base",
    ":prHourlyLimit4",
    ":semanticCommitTypeAll(chore)"
  ],
  "schedule": [
    "after 10am every monday"
  ],
  "meteor": {
    "enabled": false
  },
  "rangeStrategy": "bump",
  "npm": {
    "commitMessageTopic": "{{prettyDepType}} {{depName}}"
  },
  "packageRules": [
    {
      "matchPackageNames": [
        "node"
      ],
      "enabled": false
    },
    {
      "groupName": "all non-major dependencies",
      "groupSlug": "all-minor-patch",
      "matchFiles": ["package.json"],
      "matchUpdateTypes": [
        "minor",
        "patch"
      ],
      "lockFileMaintenance": {
        "enabled": true,
        "extends": [
          "schedule:weekly"
        ]
      }
    }
  ]
}


================================================
FILE: scripts/build-assets.fish
================================================
#!/usr/bin/env fish

# Automation script to build all assets for releasing fish-lsp. The files
# outputted by this script are intended to be located in the release-assets/
# folder. 
#
# These files are included in the release-assets/ folder:
#   - fish-lsp.standalone                                  (standalone binary -- bundled dependencies into a single executable, npm package will be smaller)
#   - fish-lsp.standalone.extra-assets.tar                 (standalone w/ sourcemaps, manpage, completions, and TypeScript declarations)
#   - fish-lsp.tgz                                         (npm packaged tarball)
#   - fish-lsp.no-sourcemaps.tgz                           (npm packaged tarball, no sourcemaps)
#   - fish-lsp.1                                           (man page)
#   - fish-lsp.fish                                        (shell completions)
#
# Usage:
#
#   Build assets, and upload them to a GitHub release
#   >_ yarn sh:build-assets [--clean] [--fresh-install]
#   >_ gh release upload <tag> ./release-assets/*
#
#   >_ fish ./scripts/build-assets.fish # Build assets without using yarn
#

source ./scripts/fish/continue-or-exit.fish
source ./scripts/fish/pretty-print.fish

argparse clean fresh-install h/help -- "$argv"
or fail 'Failed to parse arguments.'

if set -q _flag_help
    echo 'Usage:'
    echo '  yarn sh:build-assets [--clean] [--fresh-install] [--help]'
    echo '  fish ./scripts/build-assets.fish [--clean] [--fresh-install] [--help]'
    echo ''
    echo 'Synopsis:'
    echo '  Script to build all assets for releasing fish-lsp. Assets are outputted'
    echo '  in the ./release-assets/ directory.'
    echo ''
    echo 'Options:'
    echo '  --clean            Remove the release-assets/ directory and exit.'
    echo '  --fresh-install    Install dependencies from scratch before building.'
    echo '  -h, --help         Show this help message and exit.'
    exit 0
end

if set -q _flag_clean
    not test -d release-assets &&
    and log_warning '' '[WARNING]' 'release-assets/ directory does not exist. Nothing to clean.'
    and exit 0

    rm -rf release-assets
    and success ' Cleaned up release-assets/ directory. '
    exit 0
end

if test -d release-assets
    log_warning '' '[WARNING]' 'Directory release-assets/ already exists and will be removed.'
    rm -rf release-assets
end

if not test -d release-assets
    log_info '' '[INFO]' 'Creating release-assets/ directory...'
    mkdir -p release-assets
    or fail 'Failed to create release-assets/ directory.'
    log_info '' '[INFO]' 'Directory release-assets/ created successfully!'
end

log_info '' '[INFO]' 'Building project...'
yarn install &>/dev/null
if set -q _flag_fresh_install
    yarn run clean:packs &>/dev/null
    and log_info '' '[INFO]' 'Dependencies installed successfully!'
    or fail 'Failed to install dependencies.'
end
yarn build &>/dev/null

log_info '' '[INFO]' 'Project built successfully!'

log_info '' '[INFO]' 'Creating npm package tarball...'
yarn pack --filename release-assets/fish-lsp.tgz --silent
or fail 'Failed to create npm package tarball.'

log_info '' '[INFO]' 'Creating npm package tarball (no sourcemaps)...'
yarn build:npm:nosourcemaps &>/dev/null
or fail 'Failed to build npm package without sourcemaps.'
yarn pack --filename release-assets/fish-lsp.no-sourcemaps.tgz --silent
or fail 'Failed to create npm package tarball (no sourcemaps).'

log_info '' '[INFO]' 'Creating standalone binary...'
yarn build:all &>/dev/null

log_info '' '[INFO]' 'Creating release-assets extra files...'
yarn run -s generate:man &>/dev/null && command cp man/fish-lsp.1 release-assets/fish-lsp.1
./dist/fish-lsp complete >release-assets/fish-lsp.fish

log_info '' '[INFO]' 'Creating tarball for extra files...'
tar -cf release-assets/fish-lsp.standalone.with-all-assets.tar bin man dist/fish-lsp.d.ts &>/dev/null
or log_warning '' '[WARNING]' 'failed to create `release-assets/fish-lsp.standalone.with-all-assets.tar` archive.'

log_info '' '[INFO]' 'Copying standalone binary to release-assets/ directory...'
command cp bin/fish-lsp release-assets/fish-lsp.standalone
or log_warning '' '[WARNING]' 'failed to copy `bin/fish-lsp` to `release-assets/fish-lsp.standalone`!'

print_separator
echo ''

set_color --bold green
yarn exec -- npx -s -y tree-cli --base ./release-assets/
or true
set_color normal

print_separator

success " All assets built successfully! 📦 "


================================================
FILE: scripts/build-completions.fish
================================================
#!/usr/bin/env fish

source ./scripts/fish/pretty-print.fish

# The below if statement is only included because of possible CI/CD edge-cases.
# For almost all users, this should not do anything.
if not test -d $HOME/.config/fish/completions
    mkdir -p $HOME/.config/fish/completions
    if not contains -- $HOME/.config/fish/completions $fish_complete_path
        set --append --global --export fish_complete_path $HOME/.config/fish/completions $fish_complete_path
    end
end

argparse h/help s/source -- $argv
or return

if set -q _flag_help
    echo 'NAME:'
    echo '   build-completions.fish'
    echo ''
    echo 'DESCRIPTION:'
    echo '   Generate completions for fish-lsp.'
    echo ''
    echo 'OPTIONS:'
    echo -e '   -s,--source\terase shell\'s completions and source current fish-lsp completions'
    echo -e '   -h,--help\tshow this message'
    echo ''
    echo 'EXAMPLES:'
    echo -e '  >_ ./build-completions.fish '
    echo -e '  no args will overwrite the $fish_complete_path[1]/fish-lsp.fish file with the current completions'
    echo -e ''
    echo -e '  >_ ./build-completions.fish -s'
    echo -e '  erase the current completions and source the new completions from the current fish-lsp'
    echo -e '  this will not overwrite the $fish_complete_path[1]/fish-lsp.fish file'
    return 0
end

if set -q _flag_source
    complete -c fish-lsp -e
    complete -e fish-lsp
    ./dist/fish-lsp complete | source
    # ./bin/fish-lsp complete | source
    and print_success "Generated completions for fish-lsp in $BLUE'$fish_complete_path[1]/fish-lsp.fish'"
    or print_failure "Failed to generate completions for fish-lsp in $BLUE'$fish_complete_path[1]/fish-lsp.fish'"
    return 0
end

# ./bin/fish-lsp complete > $fish_complete_path[1]/fish-lsp.fish
./dist/fish-lsp complete >$fish_complete_path[1]/fish-lsp.fish
and print_success "Generated completions for fish-lsp in $BLUE'$fish_complete_path[1]/fish-lsp.fish'"
or print_failure "Failed to generate completions for fish-lsp in $BLUE'$fish_complete_path[1]/fish-lsp.fish'"


================================================
FILE: scripts/build-time
================================================
#!/usr/bin/env node

const fs = require('fs');
const path = require('path');

// Parse flags
const args = process.argv.slice(1).filter(arg => arg.startsWith('-'));
const flags = {
    quiet: args.includes('-q') || args.includes('--quiet'),
    verbose: args.includes('-v') || args.includes('--verbose'),
    help: args.includes('-h') || args.includes('--help'),
    noColor: args.includes('-n') || args.includes('--no-color'),
    color: args.includes('--color'),
    complete: args.includes('-c') || args.includes('--complete'),
    forceSuccess: args.includes('-f') || args.includes('--force-success')
};

// Setup colors
const colors = {
    reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m', italic: '\x1b[3m', underline: '\x1b[4m', inverse: '\x1b[7m',
    black: '\x1b[30m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', magenta: '\x1b[35m', cyan: '\x1b[36m', white: '\x1b[37m', gray: '\x1b[90m',
    bgBlack: '\x1b[40m', bgRed: '\x1b[41m', bgGreen: '\x1b[42m', bgYellow: '\x1b[43m', bgBlue: '\x1b[44m', bgMagenta: '\x1b[45m', bgCyan: '\x1b[46m', bgWhite: '\x1b[47m',
};

Object.keys(colors).forEach(color => {
    String.prototype[color] = flags.noColor || color === 'reset'
        ? function () {return this.toString();}
        : function () {return `${colors[color]}${this}${colors.reset}`;};
});


// Handle conflicting flags
if (flags.color && flags.noColor) flags.help = true;

if (flags.help) {
    console.log(`Usage:`.reset().bold(), `yarn sh:build-time  [OPTIONS]
      ./scripts/build-time [OPTIONS]

${'Description:'.reset().bold()}
  This script creates a file in the 'out' directory with the current
  date and time for the most recent \`fish-lsp\` package's build.

${'Options:'.reset().bold()}
  -h, --help                 Show this help message
  -q, --quiet                Suppress output
  -v, --verbose              Enable verbose output
      --color                Enable colored output
  -n, --no-color             Disable colored output
  -f, --force-success        Force success exit code
`);
    process.exit(0);
}

if (flags.complete) {
    const file = path.resolve(__filename);
    const logStr = `
complete --path ${file} -f
complete --path ${file} -s c -l complete -d "generate shell completions"
complete --path ${file}      -l color -d "Enable colored output"
complete --path ${file} -s n -l no-color -d "Disable colored output"
complete --path ${file} -s h -l help -d "show help message"
complete --path ${file} -s q -l quiet -d "suppress output"
complete --path ${file} -s v -l verbose -d "enable verbose output"
complete --path ${file} -s f -l force-success -d "force success exit"
# yarn sh:build-time
complete -c yarn -n '__fish_seen_subcommand_from sh:build-time' -f
complete -c yarn -n '__fish_seen_subcommand_from sh:build-time' -s c -l complete -d "generate shell completions"
complete -c yarn -n '__fish_seen_subcommand_from sh:build-time'      -l color -d "Enable colored output"
complete -c yarn -n '__fish_seen_subcommand_from sh:build-time' -s n -l no-color -d "Disable colored output"
complete -c yarn -n '__fish_seen_subcommand_from sh:build-time' -s h -l help -d "show help message"
complete -c yarn -n '__fish_seen_subcommand_from sh:build-time' -s q -l quiet -d "suppress output"
complete -c yarn -n '__fish_seen_subcommand_from sh:build-time' -s v -l verbose -d "enable verbose output"
complete -c yarn -n '__fish_seen_subcommand_from sh:build-time' -s f -l force-success -d "force success exit"
`
    process.stdout.write(logStr)
    process.exit(0)
}



const log = (...args) => !flags.quiet && console.log(...args);
const error = (...args) => !flags.quiet && console.error(...args);
const verbose = (...args) => flags.verbose && console.log(...args);
const exit = (code = 0) => process.exit(flags.forceSuccess ? 0 : code);

try {
    // Use SOURCE_DATE_EPOCH for reproducible builds (standard for Nix/nixpkgs)
    // Falls back to current time if not set
    const now = process.env.SOURCE_DATE_EPOCH
        ? new Date(parseInt(process.env.SOURCE_DATE_EPOCH) * 1000)
        : new Date();
    const timestamp = now.toLocaleString(undefined, {dateStyle: 'short', timeStyle: 'medium'});
    const buildTimeData = {
        date: now.toDateString(),
        timestamp,
        isoTimestamp: now.toISOString(),
        unix: Math.floor(now.getTime() / 1000),
        version: process.env.npm_package_version || 'unknown',
        nodeVersion: process.version,
        reproducible: !!process.env.SOURCE_DATE_EPOCH
    };

    const scriptDir = path.dirname(path.resolve(__filename));
    const outDir = scriptDir.endsWith('scripts') ? path.join(path.dirname(scriptDir), 'out') : path.join(scriptDir, 'out');
    const jsonFilePath = path.join(outDir, 'build-time.json');

    verbose();
    verbose('>>> begin executing verbose build-time script <<<'.white().dim().italic());
    verbose('\n', ' --verbose '.bgGreen().black().bold(), 'enabled!'.green().bold(), '\n');
    verbose(' filePath: '.green().bold(), path.resolve(__filename).blue().bold());

    // Create directory and files
    fs.mkdirSync(outDir, {recursive: true});
    if (!fs.existsSync(outDir)) {
        error("ERROR:".bgRed().white().bold(), "Failed to access 'out' directory.".red());
        exit(1);
    }

    // Write JSON file
    fs.writeFileSync(jsonFilePath, JSON.stringify(buildTimeData, null, 2));

    if (!fs.existsSync(jsonFilePath)) {
        error("ERROR:".bgRed().white().bold(), "Failed to write build time file.".red());
        exit(1);
    }

    if (flags.verbose) {
        verbose(' ✓ build-time script executed successfully!'.green().bold());
        verbose(' ✓ created JSON file:'.green().bold(), jsonFilePath.cyan());
        verbose(' ✓ relative filepath:'.green().bold(), path.relative(process.cwd(), jsonFilePath).cyan());
        verbose(' content:'.green().black().bold(), JSON.stringify(buildTimeData, null, 2).blue().bold());
        verbose(' last modified:'.green().black().bold(), fs.statSync(jsonFilePath).mtime.toLocaleString().blue().dim());
        verbose();
        verbose('>>> end executing verbose build-time script <<<'.white().dim().italic());
        verbose();
    }

    log('✓  created JSON at:'.bgGreen().black().bold(), path.basename(jsonFilePath).cyan().dim());
    log('✓  with timestamp: '.bgGreen().black().bold(), timestamp.blue().dim());

} catch (error) {
    error("ERROR:".bgRed().white().bold(), "Script execution failed.".red());
    flags.verbose && console.error('Details:'.bgRed().white().bold(), error.message.red());
    exit(1);
}


================================================
FILE: scripts/dev-complete.fish
================================================
#!/usr/bin/env fish 

set -l DIR (status current-filename | path resolve | path dirname)
source "$DIR/fish/pretty-print.fish"

argparse install uninstall -- $argv
or return 

set -l cached_file ~/.config/fish/conf.d/tmp-fish-lsp.fish
set -l workspace_root (path dirname (path dirname -- (status current-filename)) | path resolve)

if set -ql _flag_uninstall
    if test -f $cached_file
        echo "Uninstalling completions for fish-lsp..."
        rm -f $cached_file
        echo "Completions uninstalled."
    else
        echo "No completions found to uninstall."
    end
    exit 0
end

if set -q INSTALL_DEV_COMPLETIONS && test "$INSTALL_DEV_COMPLETIONS" = "true" || set -q _flag_install
    echo "Installing completions for fish-lsp..."
else
    echo "Skipping completions installation for fish-lsp."
    exit 0
end



echo "
if not string match -rq -- '^$workspace_root' \"\$PWD\"
    exit
end
" > $cached_file

# Append each completion to the cached file
yarn -s run dev -c >> $cached_file
# yarn -s run tag-and-publish -c >>$cached_file
# yarn -s run publish-and-release -c >>$cached_file
yarn -s run publish-nightly -c >>$cached_file
node ./scripts/build-time -c >>$cached_file
yarn -s run sh:workspace-cli -c >>$cached_file
yarn -s run generate:snippets -c >>$cached_file
# fish ./scripts/build-assets.fish --complete >>$cached_file

print_success "Generated fish-lsp development completions in $BLUE$cached_file$NORMAL"


source ~/.config/fish/config.fish

# Alternative approach using psub (sources completions dynamically without creating intermediate file)
# Uncomment to use psub instead of cached file:
# source (yarn -s run dev -c | psub)
# source (yarn -s run publish-and-release -c | psub)
# source (yarn -s run publish-nightly -c | psub)
# source (node ./scripts/build-time -c | psub)
# source (yarn -s run sh:workspace-cli -c | psub)
# source (yarn -s run generate:snippets -c | psub)

source $cached_file
exec fish


================================================
FILE: scripts/esbuild/cli.ts
================================================
// Improved CLI argument parsing
import { Command } from 'commander';
import { BuildTarget, WatchMode, SourcemapMode, VALID_WATCH_MODES, VALID_SOURCEMAP_MODES } from './types';

export interface BuildArgs {
  target: BuildTarget;
  watch: boolean;
  watchAll: boolean;
  watchMode: WatchMode;
  production: boolean;
  minify: boolean;
  enhanced: boolean;
  fishWasm: boolean;
  typesOnly: boolean;
  sourcemaps: SourcemapMode;
  specialSourceMaps: boolean;
}

export function parseArgs(): BuildArgs {
  const program = new Command();
  
  program
    .name('dev-esbuild')
    .description('Fish LSP development build system using esbuild')
    .option('-w, --watch', 'Watch for changes to all relevant files and run full build', false)
    .option('--watch-all', 'Watch for changes to all relevant files and run full build (same as --watch)', false)
    .option('--mode <type>', 'Watch mode type: dev (default), lint, npm, types, binary, all, test', 'dev')
    .option('-p, --production', 'Production build (minified, optimized sourcemaps)', false)
    .option('-c, --completions', 'Show shell completions for this command', false)
    .option('-m, --minify', 'Minify output', true)
    .option('--sourcemaps <type>', 'Sourcemap type: optimized (default), extended (full debug), none, special (src-only)', 'optimized')
    .option('--special-source-maps', 'Enable special sourcemap processing (src files only with content)', false)
    .option('--all', 'Build all targets: development, binary, npm, and web', false)
    .option('--binary, --bin', 'Create bundled binary in build/', false)
    .option('--npm', 'Create NPM package build with external dependencies', false)
    .option('--web', 'Create web bundle with Node.js polyfills for browser usage', false)
    .option('--fish-wasm', 'Create web bundle with full Fish shell via WASM', false)
    .option('--enhanced', 'Use enhanced web build with Fish WASM', false)
    .option('--types', 'Generate TypeScript declaration files only', false)
    .option('--ci', 'Run CI/CD test on fresh install', false)
    .option('--fresh', 'fresh install', false)
    .option('--setup', 'setup & install dependencies without building', false)
    .option('-h, --help', 'Show help message');

  program.parse();
  const options = program.opts();

  // Check if any target flag was explicitly provided
  const hasTargetFlag = options.types || options.all || 
                        options.binary || options.bin || options.npm || options.library || 
                        options.test || options.web || options.fishWasm;

  // Determine target based on flags
  // Default to 'all' if no target flags are provided for backwards compatibility
  let target: BuildTarget = hasTargetFlag ? 'development' : 'all';
  if (options.types) target = 'types';
  else if (options.all) target = 'all';
  else if (options.binary || options.bin) target = 'binary';
  else if (options.npm) target = 'npm';
  else if (options.library) target = 'library';
  else if (options.test) target = 'test';
  else if (options.ci) target = 'ci';
  else if (options.fresh) target = 'fresh';
  else if (options.setup) target = 'setup';
  // else if (options.web || options.fishWasm) target = 'web';

  // Validate sourcemaps option
  let sourcemaps: SourcemapMode = (VALID_SOURCEMAP_MODES as readonly string[]).includes(options.sourcemaps)
    ? options.sourcemaps
    : 'optimized';
  
  // Override sourcemaps if special flag is used
  if (options.specialSourceMaps) {
    sourcemaps = 'special';
  }

  // Validate watchMode
  if (!(VALID_WATCH_MODES as readonly string[]).includes(options.mode)) {
    throw new Error(`Invalid watch mode: ${options.mode}. Must be one of: ${VALID_WATCH_MODES.join(', ')}`);
  }

  return {
    target,
    watch: options.watch,
    watchAll: options.watchAll,
    watchMode: options.mode as WatchMode,
    production: options.production,
    minify: options.minify,
    enhanced: options.enhanced,
    fishWasm: options.fishWasm,
    typesOnly: options.types,
    sourcemaps,
    specialSourceMaps: options.specialSourceMaps,
  };
}

export function showHelp(): void {
  console.log(`
Usage: tsx scripts/build.ts [options]

Options:
  --watch, -w         Watch for changes to all relevant files and run full build
  --watch-all         Watch for changes to all relevant files and run full build (same as --watch)
  --mode <type>       Watch mode type: dev (default), lint, npm, types, binary, all, test
  --binary, --bin     Create bundled binary in bin/fish-lsp (used for GitHub releases)
  --npm               Create NPM package build with external dependencies (used for npm publishing)
  --web               Create web bundle with Node.js polyfills for browser usage
  --fish-wasm         Create web bundle with full Fish shell via WASM (large bundle, not yet supported)
  --enhanced          Use enhanced web build with Fish WASM
  --types             Generate TypeScript declaration files only
  --ci                Run CI/CD test on fresh install (installs from npm and runs test build)
  --fresh             Fresh install (installs from npm and runs test build, same as --ci)
  --setup             Setup & install dependencies without building (installs from npm and exits)
  --all               Build all targets: development, binary, npm
  --production, -p    Production build (minified, optimized sourcemaps)
  --minify, -m        Minify output
  --sourcemaps <type> Sourcemap type: optimized (default), extended (full debug), none, special (src-only)
  --special-source-maps Enable special sourcemap processing (src files only with content)
  --help, -h          Show this help message

Examples:
  tsx scripts/build.ts                       # Build all targets (default)
  tsx scripts/build.ts --watch               # Watch all files and run full build on changes
  tsx scripts/build.ts --watch-all           # Watch all files and run full build on changes (same as --watch)
  tsx scripts/build.ts --watch-all --mode=npm # Watch files and run npm build on changes
  tsx scripts/build.ts --watch-all --mode=types # Watch files and run types build on changes
  tsx scripts/build.ts --binary              # Create bundled binary
  tsx scripts/build.ts --bin                 # Create bundled binary (alias for --binary)
  tsx scripts/build.ts --npm                 # Create NPM package build
  tsx scripts/build.ts --types               # Generate TypeScript declaration files only
  tsx scripts/build.ts --all                 # Build all targets
  tsx scripts/build.ts --production          # Production build with optimized sourcemaps
  tsx scripts/build.ts --sourcemaps=extended # Development build with full debug sourcemaps
  tsx scripts/build.ts --sourcemaps=none     # Build without sourcemaps
  tsx scripts/build.ts --special-source-maps # Build with special sourcemaps (src files only)
  
  # Or use yarn scripts:
  yarn dev --binary                          # Create bundled binary
  yarn dev --npm                             # Create NPM package build
  yarn dev --types                           # Generate TypeScript declarations
  yarn dev --all                             # Build all targets
  yarn build:watch                           # Watch all files (equivalent to --watch-all)
  yarn build:watch --mode=npm                # Watch files and run npm build on changes
  yarn build:watch --mode=test               # Watch files and test build on changes
`);
}

export function showCompletions(): void {
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -f`)
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -s w -l watch -d "Watch for changes and rebuild (esbuild only)"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l watch-all -d "Watch for changes to all relevant files and run full build"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l mode -d "Watch mode type" -x -a "dev lint npm types binary all test"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l all -d "Build all targets: development, binary, npm"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l binary -d "Create bundled binary in bin/fish-lsp"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l bin -d "Create bundled binary in bin/fish-lsp (alias for --binary)"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l npm -d "Create NPM package build with external dependencies"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l web -d "Create web bundle with Node.js polyfills for browser usage"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l fish-wasm -d "Create web bundle with full Fish shell via WASM"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l enhanced -d "Use enhanced web build with Fish WASM"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l types -d "Generate TypeScript declaration files only"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l ci -d "Run CI/CD tests on fresh install"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l fresh -d "Reinstall with fresh dependencies"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l setup -d "Reinstall with fresh dependencies && build required dependencies (no build targets)"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l production -d "Production build (minified, optimized sourcemaps)"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l minify -d "Minify output"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -l special-source-maps -d "Enable special sourcemap processing (src files only with content)"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -s h -l help -d "Show help message"`);
  console.log(`complete -c yarn -n "__fish_seen_subcommand_from dev" -s c -l completions -d "Show shell completions for this command"`);
}


================================================
FILE: scripts/esbuild/colors.ts
================================================
// ANSI color utilities for terminal output
import path from 'path';
import process from 'process';

// Helper to convert absolute paths to relative paths from project root
export function toRelativePath(filePath: string): string {
  return path.relative(path.resolve(process.cwd()), filePath);
}

export const colors = {
  // Basic colors
  reset: '\x1b[0m',
  bright: '\x1b[1m',
  bold: '\x1b[1m',
  b: '\x1b[1m',
  dim: '\x1b[2m',
  underline: '\x1b[4m',

  // Text colors
  black: '\x1b[30m',
  red: '\x1b[31m',
  green: '\x1b[32m',
  yellow: '\x1b[33m',
  blue: '\x1b[34m',
  magenta: '\x1b[35m',
  cyan: '\x1b[36m',
  white: '\x1b[37m',
  gray: '\x1b[90m',

  // Background colors
  bgBlack: '\x1b[40m',
  bgRed: '\x1b[41m',
  bgGreen: '\x1b[42m',
  bgYellow: '\x1b[43m',
  bgBlue: '\x1b[44m',
  bgMagenta: '\x1b[45m',
  bgCyan: '\x1b[46m',
  bgWhite: '\x1b[47m',
};

// Check if we should use colors (respects NO_COLOR env var and TTY detection)
const shouldUseColors = !process.env.NO_COLOR && process.stdout.isTTY;

export function colorize(text: string, color: string): string {
  if (!shouldUseColors) return text;
  return `${color}${text}${colors.reset}`;
}

// Utility functions for common color patterns
export const logger = {
  success: (text: string) => colorize(text, colors.green),
  error: (text: string) => colorize(text, colors.red),
  warning: (text: string) => colorize(text, colors.yellow),
  info: (text: string) => colorize(text, colors.blue),
  debug: (text: string) => colorize(text, colors.gray),
  highlight: (text: string) => colorize(text, colors.cyan),
  bold: (text: string) => colorize(text, colors.bright),
  dim: (text: string) => colorize(text, colors.dim),

  // Status indicators
  building: (target: string) => `${colorize('⚡', colors.yellow)} Building ${colorize(target, colors.cyan)}...`,
  watching: (target: string) => `${colorize(' ', colors.blue)} Watching ${colorize(target, colors.cyan)} for changes...`,
  complete: (target: string) => `${colorize(' ', colors.green)} ${colorize(target, colors.cyan)} build complete!`,
  failed: (target: string) => `${colorize(' ', colors.red)} ${colorize(target, colors.cyan)} build failed!`,

  // File operations
  copied: (from: string, to?: string) => `${colorize(' ', colors.cyan)} Copied ${colorize(toRelativePath(from), colors.dim)}${to ? ` → ${colorize(toRelativePath(to), colors.dim)}` : ''}`,
  generated: (file: string) => `${colorize(' ', colors.cyan)} Generated ${colorize(toRelativePath(file), colors.dim)}`,
  executable: (file: string) => `${colorize(' ', colors.green)} Made executable: ${colorize(toRelativePath(file), colors.dim)}`,

  // Statistics
  size: (label: string, size: string, path?: string) => {
    const sizeColored = colorize(size, colors.yellow);
    const labelColored = colorize(label, colors.cyan);
    const pathColored = path ? colorize(path, colors.dim) : '';
    return `${colorize(' ', colors.blue)} ${labelColored} size: ${sizeColored}${path ? ` (${pathColored})` : ''}`;
  },

  // Progress indicators
  step: (current: number, total: number, description: string) => {
    const progress = colorize(`[${current}/${total}]`, colors.white);
    const desc = colorize(description, colors.cyan);
    return `${progress} ${desc}`;
  },

  time: (text: string) => {
    // alt icon: 
    return `${logger.success(' ')} ${colorize(text, colors.dim)}`;
  },

  // Headers and sections
  header: (text: string) => colorize(`${text}`, colors.bright + colors.cyan),
  section: (text: string) => colorize(text, colors.bright),

  // Raw logging with color support
  log: (message: string, color?: keyof typeof colors) => {
    const colored = color ? colorize(message, colors[color]) : message;
    console.log(colored);
  },

  // Error handling
  warn: (message: string) => console.warn(colorize(`  ${message}`, colors.yellow)),
  logError: (message: string, error?: Error) => {
    console.error(colorize(`  ${message}`, colors.red));
    if (error && process.env.DEBUG) {
      console.error(colorize(error.stack || error.message, colors.red + colors.dim));
    }
  }
};

// Setup colors
export function enableColors() {
  return String.prototype;
}

Object.keys(colors).forEach(color => {
  String.prototype[color] = () => { return `${colors[color]}${this}${colors.reset}` };
  Object.defineProperty(String.prototype, color, {
    get: function() {
      return colors[color] + this + colors.reset;
    },
    configurable: true // Allows redefinition or deletion
  });
})

declare global {
  interface String {
    red: string;
    green: string;
    yellow: string;
    blue: string;
    magenta: string;
    cyan: string;
    white: string;
    gray: string;
    black: string;
    // @ts-ignore
    bold: string;
    b: string;
    dim: string;
    bright: string;
    underline: string;
    bgRed: string;
    bgGreen: string;
    bgYellow: string;
    bgBlue: string;
    bgMagenta: string;
    bgCyan: string;
    bgWhite: string;
    bgBlack: string;
  }
}



================================================
FILE: scripts/esbuild/configs.ts
================================================
// Centrfalized build configurations
import esbuild from 'esbuild';
import { resolve } from 'path';
import { createPlugins, createDefines, PluginOptions, createSourceMapOptimizationPlugin, createSpecialSourceMapPlugin } from './plugins';
import { BuildConfigTarget, SourcemapMode } from "./types";

export interface BuildConfig extends esbuild.BuildOptions {
  name: string;
  entryPoint: string;
  outfile?: string;
  outdir?: string;
  target: string;
  format: 'cjs' | 'esm';
  platform: 'node' | 'browser';
  bundle: boolean;
  minify: boolean;
  sourcemap: boolean | 'inline' | 'external';
  external?: string[];
  plugins?: esbuild.Plugin[];
  internalPlugins: PluginOptions;
  onBuildEnd?: () => void;
}

export const buildConfigs: Record<BuildConfigTarget, BuildConfig> = {
  binary: {
    name: 'Universal Binary',
    entryPoint: 'src/main.ts',
    outfile: resolve('bin', 'fish-lsp'),
    target: 'node',
    format: 'cjs',
    platform: 'node',
    bundle: true,
    treeShaking: true,
    minify: true,
    assetNames: 'assets/[name]-[hash]', // Include hash in asset names for cache busting
    loader: {
      '.wasm': 'file',
      '.node': 'file',
      '.fish': 'text',
    },
    sourcemap: true, // Generate external source maps for debugging
    preserveSymlinks: true,
    // Bundle @ndonfris/tree-sitter-fish for binary builds
    external: [],
    internalPlugins: {
      target: 'node',
      typescript: false, // Use native esbuild TS support
      polyfills: 'minimal', // Include minimal polyfills for browser compatibility when needed
      embedAssets: true, // Enable embedded assets for binary builds
    },
    onBuildEnd: () => { }
  },

  development: {
    name: 'Development',
    entryPoint: 'src/**/*.ts',
    outdir: 'out',
    target: 'node',
    format: 'cjs',
    platform: 'node',
    bundle: false,
    minify: false,
    sourcemap: true,
    internalPlugins: {
      target: 'node',
      typescript: false, // Use tsc separately
      polyfills: 'none',
    },
  },

  npm: {
    name: 'NPM Package',
    entryPoint: 'src/main.ts',
    outfile: resolve('dist', 'fish-lsp'),
    target: 'node20',
    format: 'cjs',
    platform: 'node',
    bundle: true,
    treeShaking: true,
    minify: true,
    assetNames: 'assets/[name]-[hash]',
    loader: {
      '.wasm': 'file',
      '.node': 'file',
      '.fish': 'text',
    },
    sourcemap: true,
    preserveSymlinks: true,
    // External dependencies - don't bundle these, npm will provide them
    external: [
      '@esdmr/tree-sitter-fish',
      'chalk',
      'commander',
      'fast-glob',
      'fs-extra',
      'vscode-languageserver',
      'vscode-languageserver-protocol',
      'vscode-languageserver-textdocument',
      'vscode-uri',
      'web-tree-sitter',
      'zod'
    ],
    internalPlugins: {
      target: 'node',
      typescript: false,
      polyfills: 'minimal',
      embedAssets: true, // Keep WASM files embedded
    },
  },
};

export function createBuildOptions(config: BuildConfig, production = false, sourcemapsMode: SourcemapMode | 'inline' | 'inline-optimized' = 'inline-optimized'): esbuild.BuildOptions {
  // Configure sourcemaps based on mode
  const shouldGenerateSourceMaps = config.sourcemap !== false && sourcemapsMode !== 'none';
  const isInlineMode = sourcemapsMode === 'inline' || sourcemapsMode === 'inline-optimized';
  const sourcemapSetting: esbuild.BuildOptions['sourcemap'] = shouldGenerateSourceMaps
    ? (isInlineMode ? 'inline' : 'external')
    : false;

  return {
    entryPoints: config.bundle ? [config.entryPoint] : [config.entryPoint],
    bundle: config.bundle,
    platform: config.platform,
    target: config.target === 'node' ? 'node18' : 'es2020',
    format: config.format,
    loader: config.loader,
    assetNames: config.assetNames,
    preserveSymlinks: config.preserveSymlinks,
    ...(config.outfile ? { outfile: config.outfile } : { outdir: config.outdir }),
    minify: config.minify && production,
    sourcemap: sourcemapSetting,
    sourcesContent: sourcemapsMode !== 'inline-optimized', // Exclude sources for optimized inline mode
    keepNames: !production,
    treeShaking: config.bundle ? true : production,
    external: config.external,
    define: createDefines(config.target, production),
    // Performance optimizations for startup speed
    splitting: false, // Disable code splitting for faster startup
    metafile: false, // Disable metadata generation
    legalComments: 'none', // Remove legal comments for smaller bundles
    ignoreAnnotations: false, // Keep function annotations for V8 optimization
    // mangleProps: false, // Don't mangle properties to avoid runtime overhead
    plugins: [
      ...createPlugins(config.internalPlugins),
      // Always use the special sourcemap plugin for bundled builds (but skip for inline sourcemaps)
      config.bundle && !isInlineMode
        ? createSpecialSourceMapPlugin({ preserveOnlySrcContent: true })
        : !isInlineMode
          ? createSourceMapOptimizationPlugin(sourcemapsMode === 'extended')
          : { name: 'no-sourcemap-plugin', setup() { } }, // Inline sourcemaps don't need post-processing
      ...(config.onBuildEnd ? [{
        name: 'build-end-hook',
        setup(build: esbuild.PluginBuild) {
          build.onEnd(config.onBuildEnd!);
        },
      }] : []),
    ],
  };
}



================================================
FILE: scripts/esbuild/file-watcher.ts
================================================
import { spawn, ChildProcess } from 'child_process';
import { colorize, colors, logger } from './colors';
import { WatchMode, TargetInfo, getTarget, findTarget, keyboardTargets } from './types';
import chokidar from 'chokidar';
import fastGlob from 'fast-glob';

// Utility to kill process tree (handles child processes)
function killProcessTree(pid: number, signal: string = 'SIGTERM'): void {
  try {
    // On Unix systems, kill the process group
    if (process.platform !== 'win32') {
      // Kill the process group (negative PID targets the process group)
      process.kill(-pid, signal as any);
      // Also kill the main process directly as a fallback
      try {
        process.kill(pid, signal as any);
      } catch (e) {
        // Process may already be dead
      }
    } else {
      // On Windows, use taskkill to terminate the process tree
      const taskKillOptions = signal === 'SIGKILL' ? ['/pid', pid.toString(), '/T', '/F'] : ['/pid', pid.toString(), '/T'];
      spawn('taskkill', taskKillOptions, { stdio: 'ignore' });
    }
  } catch (error) {
    // Process may already be dead, ignore errors but try direct kill as fallback
    try {
      process.kill(pid, signal as any);
    } catch (e) {
      // Really dead now, ignore
    }
  }
}

// ============================================================================
// UI Helpers
// ============================================================================

const separator = () => {
  console.log(colorize('━'.repeat(Math.max(90, Number.parseInt(process.env['COLUMNS'] || '89', 10))), colors.blue));
};

const showHelp = (currentMode?: WatchMode) => {
  separator();
  console.log(logger.info(' Available Commands:'));
  console.log(` * ${'[H]'.green}          - Show this help`);
  console.log(` * ${'[M]'.blue}          - Switch watch mode`);
  console.log(` * ${'[W]'.magenta}          - Show watched file paths`);
  console.log(` * ${'[Enter|A|R]'.white}  - Run current mode build`);
  for (const t of keyboardTargets) {
    const entry = TargetInfo.helpEntry(t);
    if (entry) {
      console.log(` * ${entry.key.padEnd(13)[entry.color]}- ${entry.text}`);
    }
  }
  console.log(` * ${'[Q|Ctrl+C]'.red}   - Quit watch mode`);
  console.log('');
  if (currentMode) {
    console.log(` Current Mode: ${getTarget(currentMode).description.bgBlue.black.underline.dim}`);
  }
  separator();
};

const log = (...args: string[]) => {
  console.log(args.join(' '));
}

const showKeysReminder = (currentMode?: WatchMode) => {
  const modeText = currentMode ? `[${getTarget(currentMode).description}]` : '';
  console.log(`Press ${"[H]".bgGreen.black.dim} for help, ${"[M]".bgCyan.black.dim} for mode switch, ${"[Enter]".bgBlue.black.dim} to rebuild ${modeText.bgBlue.black.dim}`);
};

// ============================================================================
// Build Manager - Handles all build operations consistently
// ============================================================================

type BuildTrigger = 'file-change' | 'manual' | 'mode-switch';

class BuildManager {
  private currentProcess: ChildProcess | null = null;
  private isBuilding = false;
  private buildCount = 0;
  private currentMode: WatchMode = 'dev';

  async runBuild(type: WatchMode, trigger: BuildTrigger): Promise<void> {
    if (this.isBuilding) {
      console.log(logger.dim('⏳ Build already in progress, please wait...'));
      return;
    }

    this.isBuilding = true;
    this.buildCount++;

    const info = getTarget(type);
    const command = [...info.command];
    const buildName = info.label;

    this.currentMode = type;

    separator();
    console.log(logger.info(`🔄 ${buildName} rebuild triggered (${trigger})...`));
    separator();

    try {
      await this.executeCommand(['yarn', ...command]);
      this.showCompletionMessage(type, trigger, true);
    } catch (error) {
      this.showCompletionMessage(type, trigger, false, error as Error);
    } finally {
      this.isBuilding = false;
    }
  }

  private executeCommand(args: string[]): Promise<void> {
    return new Promise((resolve, reject) => {
      // Join the command and arguments into a single command string for shell execution
      const command = args.join(' ');
      this.currentProcess = spawn(command, [], {
        stdio: 'inherit',
        cwd: process.cwd(),
        shell: true,
        detached: process.platform !== 'win32', // Use process groups on Unix
        killSignal: 'SIGTERM'
      });

      // On Unix, create a new process group
      if (process.platform !== 'win32' && this.currentProcess.pid) {
        try {
          process.kill(this.currentProcess.pid, 0); // Check if process exists
        } catch (error) {
          // Process creation failed
          reject(error);
          return;
        }
      }

      this.currentProcess.on('close', (code: number) => {
        this.currentProcess = null;
        if (code === 0) {
          resolve();
        } else {
          reject(new Error(`Process exited with code ${code}`));
        }
      });

      this.currentProcess.on('error', (error: Error) => {
        this.currentProcess = null;
        reject(error);
      });
    });
  }

  private showCompletionMessage(type: WatchMode, trigger: BuildTrigger, success: boolean, error?: Error): void {
    separator();
    const buildName = getTarget(type).label;
    this.currentMode = type;

    if (success) {
      console.log(`${buildName} Rebuild Completed`.bright);
    } else {
      console.log(`${buildName} Rebuild Failed`.red);
    }

    separator();

    if (success) {
      console.log(`  ${buildName} rebuild completed successfully!`.white);
    } else if (error) {
      console.log(`  Rebuild failed:`.red, error.message.dim);
    }

    console.log(`  Build timestamp:`.white, new Date().toLocaleTimeString().yellow);
    console.log(`  Total rebuilds:`.white, `${this.buildCount}`.blue);
    console.log(`  Trigger:`.white, trigger.magenta);
    console.log(`  Current mode:`.white, getTarget(this.currentMode).description.cyan);

    separator();
    showKeysReminder(this.currentMode);
  }

  cancel(): boolean {
    if (this.currentProcess && this.currentProcess.pid) {
      console.log(logger.warning(' Cancelling current build...'));

      const pid = this.currentProcess.pid;

      // Kill the entire process tree (including child processes)
      killProcessTree(pid, 'SIGTERM');

      // Force kill after timeout if process doesn't exit
      const forceKillTimeout = setTimeout(() => {
        if (this.currentProcess && !this.currentProcess.killed) {
          console.log(logger.warning('🔥 Force killing build process tree...'));
          killProcessTree(pid, 'SIGKILL');
        }
      }, 2000); // 2 second timeout

      // Clear timeout if process exits normally
      this.currentProcess.on('exit', () => {
        clearTimeout(forceKillTimeout);
      });

      this.currentProcess = null;
      this.isBuilding = false;
      return true;
    }
    return false;
  }

  get building(): boolean {
    return this.isBuilding;
  }

  get mode(): WatchMode {
    return this.currentMode;
  }

  setMode(mode: WatchMode): void {
    this.currentMode = mode;
  }

}

// ============================================================================
// File Watcher - Simplified using chokidar
// ============================================================================

interface WatchConfig {
  watchPaths: string[];
  ignorePatterns: string[];
  debounceMs: number;
}

class FileWatcher {
  // @ts-ignore
  private watcher: chokidar.FSWatcher | null = null;
  private debounceTimer: NodeJS.Timeout | null = null;
  private readonly config: WatchConfig;
  private readonly buildManager: BuildManager;

  constructor(config: WatchConfig, buildManager: BuildManager) {
    this.config = config;
    this.buildManager = buildManager;
  }

  start(): void {
    console.log(logger.info('Starting file watcher...'));
    console.log(logger.dim(`Current working directory: ${process.cwd()}`));
    console.log(logger.dim(`Watching: ${this.config.watchPaths.join(', ')}`));
    console.log(logger.dim(`Debounce: ${this.config.debounceMs}ms`));

    const toAdd: string[] = []

    // Debug: test if patterns match any files
    console.log(logger.dim('Testing glob patterns:'));

    // Resolve globs to actual file paths
    this.config.watchPaths.forEach(pattern => {
      try {
        const matches = fastGlob.sync(pattern, { ignore: this.config.ignorePatterns });
        console.log(logger.dim(`  ${pattern} -> ${matches.length} files`));
        matches.forEach((m: string) => {
          if (!toAdd.includes(m)) {
            toAdd.push(m);
          }
        })
      } catch (e) {
        console.log(logger.dim(`  ${pattern} -> ERROR: ${e.message}`));
      }
    });

    // Create chokidar watcher with globbing enabled
    this.watcher = chokidar.watch(toAdd, {
      ignored: this.config.ignorePatterns,
      ignoreInitial: true,
      persistent: false,
      // @ts-ignore
      disableGlobbing: true, // We already resolved globs with fast-glob
      usePolling: false,
      useFsEvents: true, // Use native filesystem events for better case sensitivity
      interval: 1000,
      alwaysStat: true,
    });

    // Run initial build in current mode
    this.buildManager.runBuild(this.buildManager.mode, 'file-change');

    // Set up event handlers
    this.watcher
      .on('ready', () => {
        console.log(logger.success('File watcher ready and monitoring for changes'));
        // Debug: show what files are being watched
        const watchedPaths = this.watcher?.getWatched();
        if (watchedPaths) {
          const totalFiles = Object.values(watchedPaths).reduce((sum: number, files) => Array.isArray(files) ? sum + files.length : sum, 0);
          console.log(logger.dim(`Watching ${totalFiles} files across ${Object.keys(watchedPaths).length} directories`));
        }
      })
      .on('change', (path: string) => {
        log(colorize(logger.dim(`  File changed:`), colors.green), colorize(logger.bold(path), colors.yellow));
        this.handleFileChange('change', path);
      })
      .on('add', (path: string) => {
        log(colorize(logger.dim(`➕ File added:`), colors.green), logger.bold(path));
        this.handleFileChange('add', path);
      })
      .on('unlink', (path: string) => {
        log(colorize(logger.dim(`➖ File removed:`), colors.red), (logger.highlight(`${path}`)));
        this.handleFileChange('unlink', path);
      })
      .on('addDir', (path: string) => {
        log(colorize(logger.dim(`➕ Directory added`), colors.green), logger.bold(path));
        this.handleFileChange('addDir', path);
      })
      .on('unlinkDir', (path: string) => {
        log(colorize(logger.dim(`➖ Directory removed`), colors.red), logger.bold(path));
        this.handleFileChange('unlinkDir', path);
      })
      .on('error', (error: Error) => {
        console.error(logger.error('File watcher error:'), error);
      });
  }

  private handleFileChange(event: string, filePath: string): void {
    // Extract filename for display
    const filename = filePath.split('/').pop() || filePath;

    log(colorize(`   ${event}:`, colors.white), colorize(filename, colors.yellow));

    // Debounce rebuilds - clear existing timer and set new one
    if (this.debounceTimer) {
      clearTimeout(this.debounceTimer);
    }

    this.debounceTimer = setTimeout(async () => {
      console.log(logger.building('Rebuilding due to file changes...'));
      await this.buildManager.runBuild(this.buildManager.mode, 'file-change');
    }, this.config.debounceMs);
  }

  showWatchedPaths(): void {
    if (!this.watcher) {
      console.log(logger.warning('File watcher is not active'));
      return;
    }

    const watchedPaths: { [regexStr: string]: string[] } = this.watcher.getWatched();
    if (!watchedPaths) {
      console.log(logger.warning('No watched paths available'));
      return;
    }

    separator();
    console.log(logger.info('Currently Watched Files:'));
    separator();

    const totalFiles = Object.values(watchedPaths).reduce((sum: number, files) => Array.isArray(files) ? sum + files.length : sum, 0);
    //                 ^?
    const totalDirs = Object.keys(watchedPaths).length;

    console.log(`Total: ${totalFiles.toString().b.green} files across ${totalDirs.toString().b.cyan} directories\n`);

    // Group and display by directory
    Object.keys(watchedPaths).sort().forEach(dir => {
      const files = watchedPaths[dir];
      if (files.length > 0) {
        console.log(colorize(dir, colors.blue));
        files.forEach(file => {
          console.log(logger.dim(`  ${file}`));
        });
        console.log('');
      }
    });

    separator();
  }

  stop(): void {
    console.log(''.red.b + '  ' + logger.warning('Stopping file watcher...'));

    // Cancel any running build
    this.buildManager.cancel();

    // Clear debounce timer
    if (this.debounceTimer) {
      clearTimeout(this.debounceTimer);
      this.debounceTimer = null;
    }

    // Close chokidar watcher
    if (this.watcher) {
      this.watcher.close();
      this.watcher = null;
    }
  }
}

// ============================================================================
// Keyboard Handler - Simplified input handling
// ============================================================================

class KeyboardHandler {
  private readonly buildManager: BuildManager;
  private readonly fileWatcher: FileWatcher;
  private _activePanel: 'help' | 'mode' | null = null;

  constructor(buildManager: BuildManager, fileWatcher: FileWatcher) {
    this.buildManager = buildManager;
    this.fileWatcher = fileWatcher;
  }

  setup(): void {
    process.stdin.setRawMode(true);
    process.stdin.resume();
    process.stdin.setEncoding('utf8');

    process.stdin.on('data', this.handleKeyPress.bind(this));
    process.stdin.on('error', (err) => {
      console.error('Error reading stdin:', err);
    });
  }

  private async handleKeyPress(key: string): Promise<void> {
    const keyCode = key.toLowerCase();

    // Mode selection has its own once() handler — ignore main handler input
    if (this._activePanel === 'mode') return;

    // Any non-help key clears the help panel state
    if (this._activePanel === 'help' && keyCode !== 'h') {
      this._activePanel = null;
    }

    switch (keyCode) {
      case '\u0003': // Ctrl+C
      case 'q':
        this.exit();
        break;

      case 'h':
        if (this._activePanel === 'help') {
          this._activePanel = null;
          showKeysReminder(this.buildManager.mode);
        } else {
          this._activePanel = 'help';
          showHelp(this.buildManager.mode);
        }
        break;

      case 'm':
        this._activePanel = 'mode';
        await this.showModeSelection();
        break;

      case 'w':
        this.fileWatcher.showWatchedPaths();
        break;

      case '\r': // Enter
      case '\n':
      case 'a':
      case 'r':
        await this.buildManager.runBuild(this.buildManager.mode, 'manual');
        break;

      default: {
        const target = findTarget(keyCode);
        if (target) {
          await this.buildManager.runBuild(target.name as WatchMode, 'mode-switch');
        }
        break;
      }
    }
  }

  private async showModeSelection(): Promise<void> {
    console.log('\n' + 'Select Watch Mode:'.bright.underline.magenta + '\n');
    for (const t of keyboardTargets) {
      const entry = TargetInfo.helpEntry(t);
      if (entry) {
        console.log(`\t${entry.key.padEnd(10)[entry.color]} ${t.description}`);
      }
    }
    console.log('\n\t' + logger.dim('Current: ') + getTarget(this.buildManager.mode).description.bgBlue.black.b + '\n');
    console.log(logger.highlight(`Enter number (1-${keyboardTargets.length}) or key to switch, any other key to cancel:`));

    // Set up temporary key listener for mode selection
    const modeSelectionHandler = (key: string) => {
      process.stdin.removeListener('data', modeSelectionHandler);
      this._activePanel = null;

      const choice = key.trim().toLowerCase();

      // 'm' toggles the menu closed
      if (choice === 'm') {
        showKeysReminder(this.buildManager.mode);
        return;
      }

      const target = findTarget(choice);

      if (!target) {
        console.log(logger.dim('Mode selection cancelled.'));
        showKeysReminder(this.buildManager.mode);
        return;
      }

      const newMode = target.name as WatchMode;
      if (newMode !== this.buildManager.mode) {
        this.buildManager.setMode(newMode);
        console.log(logger.success(`Switched to: ${getTarget(newMode).description}`));
        console.log(logger.info('File changes will now trigger: ' + getTarget(newMode).description));
      } else {
        console.log(logger.dim('Already in that mode.'));
      }

      separator();
      showKeysReminder(this.buildManager.mode);
    };

    process.stdin.once('data', modeSelectionHandler);
  }

  private exit(): void {
    console.log('\n' + ''.red.b + '  ' + logger.warning('Exiting watch mode...'));

    // Restore stdin
    if (process.stdin.setRawMode) {
      process.stdin.setRawMode(false);
    }
    process.stdin.pause();

    // Stop file watcher
    this.fileWatcher.stop();

    process.exit(0);
  }
}

// ============================================================================
// Main Export - Simple interface
// ============================================================================

export async function startFileWatcher(initialMode: WatchMode = 'dev'): Promise<void> {
  // Create managers
  const buildManager = new BuildManager();
  buildManager.setMode(initialMode);

  const fileWatcher = new FileWatcher({
    watchPaths: [
      'src/*.ts',
      'src/**/*.ts',
      'src/**/*.json',
      'fish_files/**/*',
      'scripts/**/*.ts',
      'scripts/**/*',
      'scripts/*.fish',
      'fish_files/*.fish',
      'package.json',
      'tsconfig.json',
      'vitest.config.ts'
    ],
    ignorePatterns: [
      '**/node_modules/**',
      '**/temp-embedded-assets/**',
      '**/out/**',
      '**/dist/**',
      '**/lib/**',
      '**/.git/**',
      '**/coverage/**',
      '**/*.tgz',
      '**/.tsbuildinfo',
      '**/logs.txt',
      '**/*.map',
      '**/.bun/**',
      // Additional common ignores
      '**/.DS_Store',
      '**/Thumbs.db',
      '**/*.tmp',
      '**/*.temp'
    ],
    debounceMs: 1000,
  }, buildManager);

  const keyboardHandler = new KeyboardHandler(buildManager, fileWatcher);

  // Setup comprehensive signal handling
  const cleanup = (signal: string) => {
    console.log(`\n${logger.info(`Received ${signal}, cleaning up...`)}`);

    // Cancel any running builds first
    buildManager.cancel();

    // Stop file watcher
    fileWatcher.stop();

    // Force exit to ensure we don't hang
    setTimeout(() => {
      process.exit(1);
    }, 1000);

    // Exit cleanly
    process.exit(0);
  };

  // Handle various termination signals
  process.on('SIGTERM', () => cleanup('SIGTERM'));
  process.on('SIGINT', () => cleanup('SIGINT'));
  process.on('SIGHUP', () => cleanup('SIGHUP'));

  // Handle uncaught exceptions to prevent zombie processes
  process.on('uncaughtException', (error) => {
    console.error(logger.error('Uncaught exception:'), error);
    cleanup('uncaughtException');
  });

  process.on('unhandledRejection', (reason, promise) => {
    console.error(logger.error('Unhandled rejection at:'), promise, 'reason:', reason);
    cleanup('unhandledRejection');
  });

  // Start everything
  fileWatcher.start();
  keyboardHandler.setup();

  console.log(logger.success('File watcher started!'));
  console.log([`Current mode:`.underline.green, `${getTarget(buildManager.mode).description.bgBlue.black.underline.b}`].join(' '));
  separator();
  showKeysReminder(buildManager.mode);
  separator();

  // Keep process running
  return new Promise(() => { }); // Never resolves
}


================================================
FILE: scripts/esbuild/index.ts
================================================
#!/usr/bin/env tsx

import { parseArgs, showCompletions, showHelp } from "./cli";
import { pipeline } from './pipeline';
import { startFileWatcher } from './file-watcher';
import { logger } from './colors';

export async function build(_customArgs?: string[]): Promise<void> {
  const args = parseArgs();

  // Handle help and completions                                               
  if (process.argv.includes('--help') || process.argv.includes('-h')) {
    showHelp();
    process.exit(0);
  }
  if (process.argv.includes('--completions') || process.argv.includes('-c')) {
    showCompletions();
    process.exit(0);
  }

  // Handle comprehensive file watching                                        
  if (args.watchAll || args.watch) {
    console.log(logger.header('`fish-lsp` comprehensive file watcher'));
    console.log(logger.info('Starting comprehensive file watcher...'));
    await startFileWatcher(args.watchMode);
    return;
  }

  try {
    // Execute the build pipeline for the target                               
    await pipeline.execute(args.target, args);
  } catch (error) {
    logger.logError('Build failed', error as Error);
    process.exit(1);
  }
}

build(); 


================================================
FILE: scripts/esbuild/pipeline.ts
================================================
import { execSync } from 'child_process';
import esbuild from 'esbuild';
import { BuildArgs } from './cli';
import { logger } from './colors';
import { buildConfigs, createBuildOptions } from './configs';
import { copyDevelopmentAssets, ensureDirectoryExists, generateTypeDeclarations, isFileEmpty, makeExecutable, showBuildStats, showDirectorySize } from './utils';


interface BuildStep {
  name: string;
  priority: number;
  tags: string[]; // What meta-targets include this step
  condition?: (args: BuildArgs) => boolean;
  runner: (args: BuildArgs) => Promise<void> | void;
  timing?: boolean;
  postBuild?: (args: BuildArgs) => Promise<void> | void;
}

class BuildPipeline {
  private steps: BuildStep[] = [];

  register(step: BuildStep): this {
    this.steps.push(step);
    return this;
  }

  async execute(target: string, args: BuildArgs): Promise<void> {
    const applicableSteps = this.getStepsForTarget(target, args);

    if (applicableSteps.length === 0) {
      throw new Error(`No build steps found for target: ${target}`);
    }

    // Show header once at the beginning
    console.log(logger.header('`fish-lsp` esbuild (BUILD SYSTEM)'));
    console.log(logger.info(`Building ${applicableSteps.length} targets...`));

    // Execute all steps with correct numbering
    for (let i = 0; i < applicableSteps.length; i++) {
      const step = applicableSteps[i];
      console.log(`\n${logger.step(i + 1, applicableSteps.length, logger.building(step.name))}`);

      const startTime = Date.now();
      try {
        await step.runner(args);
        if (step.postBuild) {
          await step.postBuild(args);
        }
      } catch (error) {
        console.log(logger.failed(step.name));
        console.error('Error details:', error);
        throw error;
      }

      if (step.timing) {
        const buildTime = Date.now() - startTime;
        console.log(logger.time(`${step.name} built in ${buildTime} ms`));
      }
    }

    console.log(`\n${logger.success('All builds completed successfully!')}`);
  }

  // Get steps for a specific target - useful for other scripts
  getStepsForTarget(target: string, args: BuildArgs): BuildStep[] {
    return this.steps.filter(step => {
      // Direct target match
      if (step.tags.includes(target)) return true;

      // Custom condition
      if (step.condition && step.condition(args)) return true;

      return false;
    }).sort((a, b) => a.priority - b.priority);
  }

  // Get all registered steps - useful for introspection
  getAllSteps(): ReadonlyArray<BuildStep> {
    return [...this.steps];
  }

  // Check if a target exists
  hasTarget(target: string): boolean {
    return this.steps.some(step => step.tags.includes(target));
  }
}

// Build step definitions
const pipeline = new BuildPipeline()
  .register({
    name: "Fresh Install",
    priority: 3,
    tags: ['fresh', 'ci', 'setup'],
    runner: async () => {
      console.log(logger.info('Performing fresh install...'));
      execSync('yarn install --frozen-lockfile', { stdio: 'inherit' });
    },
  })
  .register({
    name: 'Build Time',
    priority: 5,
    tags: ['all', 'dev', 'binary', 'npm', 'types', 'lint', "fresh", 'ci', 'setup'],
    timing: true,
    runner: async () => {
      execSync('node ./scripts/build-time', { stdio: 'inherit' });
    },
  })
  .register({
    name: 'Required Files',
    priority: 10,
    tags: ['all', 'dev', 'binary', 'npm', "fresh", "ci", 'setup'],
    runner: async () => {
      ensureDirectoryExists('man');
      ensureDirectoryExists('src/snippets');
      if (isFileEmpty(`man/fish-lsp.1`) || isFileEmpty('src/snippets/helperCommands.json')) {
        execSync('yarn generate:man && yarn generate:snippets --write', { stdio: 'inherit' });
        showBuildStats('man/fish-lsp.1', 'Man file');
        showBuildStats('src/snippets/helperCommands.json', 'Helper Commands Snippets');
      }
      console.log(logger.success('  Required files are up to date'));
    }
  })
  .register({
    name: 'Development',
    priority: 20,
    tags: ['all', 'dev', 'development', 'npm', "ci"],
    timing: true,
    runner: async (args) => {
      const config = buildConfigs.development;
      const buildOptions = createBuildOptions(config, args.production || args.minify, args.sourcemaps);
      await esbuild.build(buildOptions);
    },
    postBuild: async () => {
      copyDevelopmentAssets();
    },
  })
  .register({
    name: 'TypeScript Declarations',
    priority: 25,
    tags: ['all', 'types', 'dev', 'npm', 'fresh', "ci"],
    timing: true,
    runner: async () => {
      generateTypeDeclarations();
    },
    postBuild: async () => {
      showBuildStats('dist/fish-lsp.d.ts', 'Type Declarations');
    },
  })
  .register({
    name: 'NPM Package',
    priority: 30,
    tags: ['all', 'npm', 'dev', 'fresh', "ci"],
    timing: true,
    runner: async (args) => {
      const config = buildConfigs.npm;
      ensureDirectoryExists('dist');
      // Only override sourcemaps when explicitly changed from the CLI default
      const sourcemaps = args.sourcemaps !== 'optimized' ? args.sourcemaps : undefined;
      const buildOptions = createBuildOptions(config, args.production || args.minify, sourcemaps);
      await esbuild.build(buildOptions);
    },
    postBuild: async () => {
      const config = buildConfigs.npm;
      if (config.outfile) {
        makeExecutable(config.outfile);
        showBuildStats(config.outfile, 'NPM Package Binary');
        showDirectorySize('dist', 'dist/*');
      }
    },
  })
  .register({
    name: 'Universal Binary',
    priority: 40,
    tags: ['all', 'binary', 'dev'],
    timing: true,
    runner: async (args) => {
      const config = buildConfigs.binary;
      ensureDirectoryExists('bin');
      const sourcemaps = args.sourcemaps !== 'optimized' ? args.sourcemaps : undefined;
      const buildOptions = createBuildOptions(config, args.production || args.minify, sourcemaps);
      await esbuild.build(buildOptions);
    },
    postBuild: async () => {
      const config = buildConfigs.binary;
      if (config.outfile) {
        makeExecutable(config.outfile);
        showBuildStats(config.outfile, 'Universal Binary');
        showDirectorySize('bin', 'bin/*');
      }
    },
  })
  .register({
    name: 'Lint Check',
    priority: 60,
    tags: ['lint', "ci"],
    timing: true,
    runner: async () => {
      try {
        execSync('yarn lint:fix', { stdio: 'inherit' });
      } catch (error) {
        console.log(logger.warning('Lint check failed. Attempting to fix issues...'));
        execSync('yarn lint:check', { stdio: 'inherit' });
      }
    },
  })
  .register({
    name: 'Test Suite',
    priority: 70,
    tags: ['test', "ci"],
    timing: true,
    runner: async () => {
      execSync('yarn test:run', { stdio: 'inherit' });
    },
  });

// Export both the pipeline instance and the BuildPipeline class for extensibility
export { BuildPipeline, pipeline, type BuildStep };



================================================
FILE: scripts/esbuild/plugins.ts
================================================
// Build plugin factory for consistent configuration

// ESBuild plugins - these packages don't provide TypeScript definitions

import esbuild from 'esbuild';
import type { Plugin } from 'esbuild';
import { polyfillNode } from 'esbuild-plugin-polyfill-node';
import { nodeModulesPolyfillPlugin } from 'esbuild-plugins-node-modules-polyfill';
import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill';
import { colorize, colors, toRelativePath } from './colors';
import { writeFileSync, existsSync, readFileSync } from 'fs';
import path, { resolve } from 'path';

export interface PluginOptions {
  target: 'node' | 'browser';
  typescript: boolean;
  polyfills: 'minimal' | 'full' | 'none';
  embedAssets?: boolean;
}

export function createPlugins(options: PluginOptions): esbuild.Plugin[] {
  const plugins: esbuild.Plugin[] = [];

  // Handle generic .wasm imports
  plugins.push(createWasmPlugin());

  // Simple embedded assets handler for wasm/package/man/build-time
  if (options.embedAssets) {
    plugins.push({
      name: 'embedded-assets',
      setup(build) {
        const projectRoot = process.cwd();
        const wasmFile = resolve(projectRoot, 'node_modules/@esdmr/tree-sitter-fish/tree-sitter-fish.wasm');
        const coreWasmFile = resolve(projectRoot, 'node_modules/web-tree-sitter/tree-sitter.wasm');
        const manFile = resolve(projectRoot, 'man', 'fish-lsp.1');
        const buildTimeFile = resolve(projectRoot, 'out', 'build-time.json');
        const pkgJsonFile = resolve(projectRoot, 'package.json');

        build.onResolve({ filter: /^@embedded_assets\// }, (args) => ({
          path: args.path.replace('@embedded_assets/', ''),
          namespace: 'embedded-asset',
        }));

        build.onResolve({ filter: /^web-tree-sitter\/tree-sitter\.wasm$/ }, () => ({
          path: coreWasmFile,
          namespace: 'wasm-embedded',
        }));

        build.onResolve({ filter: /^@esdmr\/tree-sitter-fish\/tree-sitter-fish\.wasm$/ }, () => ({
          path: wasmFile,
          namespace: 'wasm-embedded',
        }));

        const loadWasm = (filePath: string) => {
          if (!existsSync(filePath)) throw new Error(`Missing WASM asset: ${filePath}`);
          const content = readFileSync(filePath);
          return `export default "data:application/wasm;base64,${content.toString('base64')}"`;
        };

        build.onLoad({ filter: /\.wasm$/, namespace: 'wasm-embedded' }, (args) => ({
          contents: loadWasm(args.path),
          loader: 'js',
        }));

        build.onLoad({ filter: /.*/, namespace: 'embedded-asset' }, (args) => {
          const asset = args.path;

          if (asset === 'tree-sitter-fish.wasm') {
            return { contents: loadWasm(wasmFile), loader: 'js' };
          }
          if (asset === 'tree-sitter.wasm') {
            return { contents: loadWasm(coreWasmFile), loader: 'js' };
          }
          if (asset === 'package.json') {
            if (!existsSync(pkgJsonFile)) throw new Error('package.json not found for embedding');
            const json = JSON.parse(readFileSync(pkgJsonFile, 'utf8'));
            return { contents: `export default ${JSON.stringify(json)};`, loader: 'js' };
          }
          if (asset.startsWith('man/')) {
            const manPath = resolve(projectRoot, asset);
            if (!existsSync(manPath)) throw new Error(`Missing man asset: ${asset}`);
            const content = readFileSync(manPath, 'utf8');
            return { contents: `export default ${JSON.stringify(content)};`, loader: 'js' };
          }
          if (asset === 'out/build-time.json') {
            if (existsSync(buildTimeFile)) {
              const json = JSON.parse(readFileSync(buildTimeFile, 'utf8'));
              return { contents: `export default ${JSON.stringify(json)};`, loader: 'js' };
            }
            const now = process.env.SOURCE_DATE_EPOCH
              ? new Date(parseInt(process.env.SOURCE_DATE_EPOCH) * 1000)
              : new Date();
            const fallback = {
              date: now.toDateString(),
              timestamp: now.toLocaleString(undefined, { dateStyle: 'short', timeStyle: 'medium' }),
              isoTimestamp: now.toISOString(),
              unix: Math.floor(now.getTime() / 1000),
              version: process.env.npm_package_version || 'unknown',
              nodeVersion: process.version,
              reproducible: !!process.env.SOURCE_DATE_EPOCH,
            };
            return { contents: `export default ${JSON.stringify(fallback)};`, loader: 'js' };
          }

          return { contents: 'export default "";', loader: 'js' };
        });
      },
    });
  }

  // Note: Using native esbuild TypeScript support instead of external plugin for better performance

  // Polyfills based on target and level - only load when actually needed
  if (options.target === 'browser' && options.polyfills === 'full') {
    plugins.push(
      polyfillNode({
        globals: {
          navigator: false,
          global: true,
          process: true,
        },
        polyfills: {
          fs: true,
          path: true,
          stream: true,
          crypto: true,
          os: true,
          util: true,
          events: true,
          buffer: true,
          process: true,
          child_process: false,
          cluster: false,
          dgram: false,
          dns: false,
          http: false,
          https: false,
          net: false,
          tls: false,
          worker_threads: false,
        },
      }),
      nodeModulesPolyfillPlugin()
    );
  } else if (options.target === 'node' && options.polyfills === 'minimal') {
    plugins.push(
      NodeGlobalsPolyfillPlugin({
        buffer: true,
        process: false,
      })
    );
  }

  return plugins;
}

export function createDefines(target: 'node' | 'browser' | string, production = false): Record<string, string> {
  const defines: Record<string, string> = {
    'process.env.NODE_ENV': production ? '"production"' : '"development"',
  };

  // Embed build-time for bundled versions
  try {
    const buildTimePath = resolve('out', 'build-time.json');
    const buildTimeData = JSON.parse(readFileSync(buildTimePath, 'utf8'));
    defines['process.env.FISH_LSP_BUILD_TIME'] = `'${JSON.stringify(buildTimeData)}'`;
  } catch (error) {
    // If build-time.json doesn't exist, use current time as fallback
    const now = process.env.SOURCE_DATE_EPOCH
      ? new Date(parseInt(process.env.SOURCE_DATE_EPOCH) * 1000)
      : new Date();
    const timestamp = now.toLocaleString(undefined, { dateStyle: 'short', timeStyle: 'medium' });
    const fallbackBuildTime = {
      date: now.toDateString(),
      timestamp,
      isoTimestamp: now.toISOString(),
      unix: Math.floor(now.getTime() / 1000),
      version: process.env.npm_package_version || 'unknown',
      nodeVersion: process.version,
      reproducible: !!process.env.SOURCE_DATE_EPOCH
    };
    defines['process.env.FISH_LSP_BUILD_TIME'] = `'${JSON.stringify(fallbackBuildTime)}'`;
  }

  // Mark as bundled for Node target (used by virtual filesystem)
  if (target === 'node') {
    defines['process.env.FISH_LSP_BUNDLED'] = '"true"';
  }

  if (target === 'browser') {
    defines['global'] = 'globalThis';
    defines['navigator'] = '{"language":"en-US"}';
  } else {
    defines['global'] = 'globalThis';
    defines['navigator'] = '{"language":"en-US"}';
  }

  return defines;
}

/**
 * Plugin to optimize source maps by removing embedded source content
 * This reduces file size significantly while keeping source file references
 * @param preserveSourceContent - Keep source content for debugging (default: false for production, true for development)
 */
export function createSourceMapOptimizationPlugin(preserveSourceContent?: boolean): esbuild.Plugin {
  return {
    name: 'sourcemap-optimization',
    setup(build) {
      build.onEnd((result) => {
        if (!result.outputFiles && build.initialOptions.outfile && build.initialOptions.sourcemap) {
          const outfile = build.initialOptions.outfile;
          const sourcemapFile = outfile + '.map';
          
          try {
            const sourcemapContent = readFileSync(sourcemapFile, 'utf8');
            const originalSize = sourcemapContent.length;
            const sourcemap = JSON.parse(sourcemapContent);
            
            // Ensure the bundle has a sourcemap reference
            const bundleContent = readFileSync(outfile, 'utf8');
            const sourcemapRef = `\n//# sourceMappingURL=${resolve(sourcemapFile).split('/').pop()}`;
            
            if (!bundleContent.includes('//# sourceMappingURL=')) {
              writeFileSync(outfile, bundleContent + sourcemapRef);
            }
            
            // Remove embedded source content to reduce file size
            // This keeps file references but removes the full source code
            if (preserveSourceContent) {
              console.log(`  Source map: ${colorize(toRelativePath(sourcemapFile), colors.white)}`);
              console.log(`  Size: ${colorize((originalSize/1024/1024).toFixed(1) + 'MB', colors.white)} (with source content for debugging)`);
              console.log(`  Sources: ${colorize(sourcemap.sources.length + ' files', colors.white)}`);
            } else if (sourcemap.sourcesContent) {
              delete sourcemap.sourcesContent;
              
              const optimizedContent = JSON.stringify(sourcemap);
              writeFileSync(sourcemapFile, optimizedContent);
              
              const newSize = optimizedContent.length;
              const reduction = ((originalSize - newSize) / originalSize * 100).toFixed(1);
              
              console.log(`  Optimized source map: ${colorize(toRelativePath(sourcemapFile), colors.white)}`);
              const reductionSize = colorize(`${reduction}% (${(originalSize/1024/1024).toFixed(1)}MB → ${(newSize/1024/1024).toFixed(1)}MB)`, colors.white);
              console.log(`  Size reduction: ${reductionSize}`);
              console.log(`  Sources: ${colorize(sourcemap.sources.length + ' files', colors.white)}`);
            }
          } catch (error) {
            // Silently ignore if source map doesn't exist or can't be processed
          }
        }
      });
    },
  };
}

/**
 * Enhanced sourcemap plugin that filters sources to only include src/ files
 * and validates mappings bounds while preserving sourcesContent for debugging
 * @param options Configuration for the special sourcemap processing
 */
export function createSpecialSourceMapPlugin(options: { preserveOnlySrcContent?: boolean } = {}): esbuild.Plugin {
  return {
    name: 'special-sourcemap-optimization',
    setup(build) {
      build.onEnd((result) => {
        if (!result.outputFiles && build.initialOptions.outfile && build.initialOptions.sourcemap) {
          const outfile = build.initialOptions.outfile;
          const sourcemapFile = outfile + '.map';
          
          try {
            const sourcemapContent = readFileSync(sourcemapFile, 'utf8');
            const originalSize = sourcemapContent.length;
            const sourcemap = JSON.parse(sourcemapContent);
            
            // Ensure the bundle has a sourcemap reference
            const bundleContent = readFileSync(outfile, 'utf8');
            const sourcemapRef = `\n//# sourceMappingURL=${resolve(sourcemapFile).split('/').pop()}`;
            
            if (!bundleContent.includes('//# sourceMappingURL=')) {
              writeFileSync(outfile, bundleContent + sourcemapRef);
            }
            
            if (options.preserveOnlySrcContent && sourcemap.sources && sourcemap.sourcesContent) {
              // Instead of filtering and breaking mappings, we'll selectively remove sourcesContent
              // for non-src files while keeping all sources for valid mappings
              const optimizedSourcesContent: (string | null)[] = [];
              let srcFileCount = 0;
              let removedSourcesSize = 0;
              
              sourcemap.sources.forEach((source: string, index: number) => {
                // Only preserve sourcesContent for TypeScript files from src/ directory
                // Remove content for node_modules, embedded assets, and other non-src files
                if (
                  source.includes('../src/') && 
                  source.endsWith('.ts') &&
                  !source.includes('node_modules') &&
                  !source.startsWith('embedded-asset:') &&
                  !source.includes('webpack://')
                ) {
                  // Keep the source content for src files
                  optimizedSourcesContent.push(sourcemap.sourcesContent[index] || null);
                  srcFileCount++;
                } else {
                  // Remove source content but keep the entry to maintain mapping indices
                  const originalContent = sourcemap.sourcesContent[index] || '';
                  removedSourcesSize += originalContent.length;
                  optimizedSourcesContent.push(null);
                }
              });
              
              // Create optimized sourcemap with selective sourcesContent
              const optimizedSourcemap = {
                ...sourcemap,
                sourcesContent: optimizedSourcesContent
              };
              
              console.log(`  Special source map: ${colorize(toRelativePath(sourcemapFile), colors.white)}`);
              console.log(`  Total sources: ${colorize(sourcemap.sources.length + ' files', colors.white)}`);
              console.log(`  src/ files with content: ${colorize(srcFileCount + ' files', colors.white)}`);
              console.log(`  Other sources (content removed): ${colorize((sourcemap.sources.length - srcFileCount) + ' files', colors.white)}`);
              
              if (srcFileCount > 0) {
                const optimizedContent = JSON.stringify(optimizedSourcemap);
                writeFileSync(sourcemapFile, optimizedContent);
                
                const newSize = optimizedContent.length;
                const reduction = originalSize > newSize 
                  ? ((originalSize - newSize) / originalSize * 100).toFixed(1)
                  : '0';
                
                console.log(`  Size reduction: ${colorize(`${reduction}% (${(originalSize/1024/1024).toFixed(1)}MB → ${(newSize/1024/1024).toFixed(1)}MB)`, colors.white)}`);
                console.log(`  Mappings preserved: ${colorize('All mappings intact', colors.white)}`);
                
                // Note: Shebang modification removed - use NODE_OPTIONS="--enable-source-maps" instead
                // to avoid process.argv parsing issues
              } else {
                console.log(`  ${colorize('Warning: No src/ TypeScript files found in sourcemap', colors.white)}`);
              }
            } else {
              // Fallback to regular sourcemap optimization
              console.log(`  Source map: ${colorize(toRelativePath(sourcemapFile), colors.white)}`);
              console.log(`  Size: ${colorize((originalSize/1024/1024).toFixed(1) + 'MB', colors.white)} (preserved for debugging)`);
              // console.log(`  Sources: ${colorize(sourcemap.sources.length + ' files', colors.white)}`);
              console.log(`  Sources: ${colorize(sourcemap.sources.length + ' files', colors.white)}`);
            }
          } catch (error) {
            console.log(`  ${colorize('Warning: Could not process sourcemap - ' + (error as Error).message, colors.white)}`);
          }
        }
      });
    },
  };
}

/**
 * Loads .wasm files as base64 data URLs so they can be imported directly in bundles.
 */
export function createWasmPlugin(): Plugin {
  return {
    name: 'wasm-loader',
    setup(build) {
      build.onResolve({ filter: /\.wasm$/ }, (args) => {
        const isEmbedded = args.path.startsWith('@embedded_assets/');
        const isRelative = args.path.startsWith('./') || args.path.startsWith('../');
        const isAbsolute = path.isAbsolute(args.path);

        // Let other plugins handle embedded or bare module .wasm specifiers
        if (isEmbedded || (!isRelative && !isAbsolute)) {
          return;
        }
        return {
          path: resolve(args.resolveDir, args.path),
          namespace: 'wasm-inline',
        };
      });

      build.onLoad({ filter: /\.wasm$/, namespace: 'wasm-inline' }, (args) => {
        try {
          const content = readFileSync(args.path);
          const base64 = content.toString('base64');
          return {
            contents: `export default "data:application/wasm;base64,${base64}";`,
            loader: 'js',
          };
        } catch {
          return {
            contents: 'export default "";',
            loader: 'js',
          };
        }
      });
    },
  };
}


================================================
FILE: scripts/esbuild/types.ts
================================================
// Build target type definitions for fish-lsp esbuild system

/**
 * Individual build configuration targets that map to actual build configs
 */
export type BuildConfigTarget = 'binary' | 'development' | 'npm';

/**
 * Meta targets that control the build process behavior
 */
export type MetaTarget = 'all' | 'types' | 'library' | 'test' | 'ci' | 'fresh' | 'setup';

/**
 * All possible build targets that can be passed to the build system
 */
export type BuildTarget = BuildConfigTarget | MetaTarget;

/**
 * Watch/build mode used by file-watcher and CLI --mode flag
 */
export type WatchMode = 'dev' | 'binary' | 'npm' | 'types' | 'all' | 'lint' | 'test' | 'ci' | 'fresh' | 'setup';

/**
 * Sourcemap generation modes
 */
export type SourcemapMode = 'optimized' | 'extended' | 'none' | 'special';

// ============================================================================
// TargetInfo — single source of truth for all target metadata
// ============================================================================

export interface TargetInfo {
  readonly index: number;
  readonly name: string;
  readonly altNames: readonly string[];
  readonly label: string;
  readonly description: string;
  readonly keys: readonly string[];
  readonly type: 'meta' | 'build';
  readonly command: readonly string[];
  /** Color name used in help/mode menus (maps to String prototype color) */
  readonly helpColor: string;
}

export namespace TargetInfo {
  let _idx = 0;

  export function create(
    name: string,
    label: string,
    description: string,
    command: string[],
    helpColor?: string,
    keys?: string[],
    altNames?: string[],
  ): TargetInfo {
    _idx++;
    const buildNames: string[] = ['binary', 'development', 'npm'];
    const isBuild = buildNames.includes(name) || (altNames?.some(a => buildNames.includes(a)) ?? false);
    return {
      index: _idx,
      name,
      altNames: altNames ?? [],
      label,
      description,
      keys: [String(_idx), ...(keys ?? [])],
      type: isBuild ? 'build' : 'meta',
      command,
      helpColor: helpColor ?? 'dim',
    };
  }

  /** Get the single-letter keyboard shortcut (e.g. 'd', 'n', 'b') */
  export function letterKey(info: TargetInfo): string | undefined {
    return info.keys.find(k => /^[a-z]$/i.test(k));
  }

  /** Quick mode summary string: "1:full, 2:npm, 3:lint, ..." */
  export function quickModeSummary(items: readonly TargetInfo[]): string {
    return items.map(t => `${t.index}:${t.label.toLowerCase()}`).join(', ');
  }

  /** Format a help entry with combined index+key: "[4|B]", color name, and description */
  export function helpEntry(info: TargetInfo): { key: string; color: string; text: string } | undefined {
    const letter = letterKey(info);
    if (!letter) return undefined;
    return { key: `[${info.index}|${letter.toUpperCase()}]`, color: info.helpColor, text: info.description };
  }
}

/**
 * All targets with their metadata. Order determines the 1-based index
 * and the numeric keyboard shortcut in watch mode.
 */
export const targets: readonly TargetInfo[] = [
  TargetInfo.create('dev',    'Full',        'Full Project (yarn build)',           ['dev'],             'cyan',      ['d'], ['development']),
  TargetInfo.create('npm',    'NPM',         'NPM Build (yarn dev --npm)',          ['dev', '--npm'],    'yellow',    ['n']),
  TargetInfo.create('lint',   'Lint',         'Lint Fix (yarn lint:fix)',            ['lint:fix'],        'magenta',  ['l']),
  TargetInfo.create('binary', 'Binary',       'Binary Build (yarn dev --binary)',    ['dev', '--binary'], 'blue',     ['b'], ['bin']),
  TargetInfo.create('test',   'Test',         'Test Run (yarn test)',                ['test:run'],        'green',    ['t']),
  TargetInfo.create('types',  'Types',        'Types Build (yarn dev --types)',      ['dev', '--types'],  'white',    ['y']),
  TargetInfo.create('ci',     'CI/CD',        'CI/CD Test (yarn dev --ci)',          ['dev', '--ci'],     'magenta',  ['c']),
  TargetInfo.create('all',    'All Targets',  'All Targets (yarn dev --all)',        ['dev', '--all']),
  TargetInfo.create('fresh',  'Fresh',        'Fresh Install (yarn dev --fresh)',    ['dev', '--fresh']),
  TargetInfo.create('setup',  'Setup',        'Setup (yarn dev --setup)',            ['dev', '--setup']),
];

/** Targets that have keyboard shortcuts in watch mode (index 1-7) */
export const keyboardTargets: readonly TargetInfo[] = targets.filter(t => t.keys.length > 1);

// ============================================================================
// Derived constants
// ============================================================================

export const VALID_WATCH_MODES: readonly string[] = targets.map(t => t.name);
export const VALID_SOURCEMAP_MODES: readonly SourcemapMode[] = ['optimized', 'extended', 'none', 'special'];

// ============================================================================
// Lookup helpers
// ============================================================================

/** Find a target by name, alt name, or keyboard key */
export function findTarget(nameOrKey: string): TargetInfo | undefined {
  return targets.find(t =>
    t.name === nameOrKey ||
    t.altNames.includes(nameOrKey) ||
    t.keys.includes(nameOrKey)
  );
}

/** Get target by its primary name (throws if not found) */
export function getTarget(name: string): TargetInfo {
  const target = targets.find(t => t.name === name);
  if (!target) throw new Error(`Unknown target: ${name}`);
  return target;
}


================================================
FILE: scripts/esbuild/utils.ts
================================================
// Build utility functions
import fs from 'fs-extra';
import { existsSync, statSync, unlinkSync } from 'fs';
import { execSync, spawnSync } from 'child_process';
import { logger, toRelativePath } from './colors';




export function copyDevelopmentAssets(): void {
  if (existsSync('src/snippets')) {
    fs.copySync('src/snippets', 'out/snippets');
    console.log(logger.copied('src/snippets', 'out/snippets'));
  }
}

export function ensureDirectoryExists(dirPath: string): void {
  if (existsSync(dirPath)) return;
  fs.mkdirSync(dirPath, { recursive: true });
}

export function formatBytes(bytes: number): string {
  return (bytes / 1024 / 1024).toFixed(2) + ' MB';
}

export function makeExecutable(filePath: string): void {
  try {
    execSync(`chmod +x "${filePath}"`);
    console.log(logger.executable(filePath));
  } catch (error) {
    logger.warn(`Could not make executable: ${filePath}`);
  }
}

export function showBuildStats(filePath: string, label = 'Bundle'): void {
  if (existsSync(filePath)) {
    const size = statSync(filePath).size;
    console.log(logger.complete(label));
    console.log(logger.info(`  ${label}: ${logger.dim(toRelativePath(filePath))}`));
    console.log(logger.size(label, formatBytes(size)));
  }
}

export function showDirectorySize(dirPath: string, label?: string): void {
  if (!existsSync(dirPath)) {
    return;
  }

  const files = fs.readdirSync(dirPath);
  let totalSize = 0;

  for (const file of files) {
    const filePath = `${dirPath}/${file}`;
    const stats = statSync(filePath);

    if (stats.isFile()) {
      totalSize += stats.size;
    }
  }

  const displayLabel = label || dirPath;
  console.log(logger.size(`${displayLabel} total`, formatBytes(totalSize)));
}

export function isFileEmpty(filePath: string): boolean {
  if (!existsSync(filePath)) {
    return true;
  }
  
  const stats = statSync(filePath);
  return stats.size === 0;
}

export function generateTypeDeclarations(): void {
  console.log(logger.info('  Generating TypeScript declarations...'));

  try {
    execSync('mkdir -p dist');

    // Step 1: Create tsconfig used for declaration emit
    const tsconfigContent = JSON.stringify({
      "extends": ["@tsconfig/node22/tsconfig.json"],
      "compilerOptions": {
        "declaration": true,
        "emitDeclarationOnly": true,
        "outDir": "temp-types",
        // Remove rootDir to avoid conflicts with path mapping
        "target": "es2018",
        "lib": ["es2018", "es2019", "es2020", "es2021", "es2022", "es2023", "dom"],
        "module": "commonjs",
        "moduleResolution": "node",
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "strict": false,
        "skipLibCheck": true,
        "skipDefaultLibCheck": true,
        "resolveJsonModule": true,
        "allowJs": false,
        "types": ["node", "vscode-languageserver"],
        "baseUrl": ".",
        // Suppress some strict checks for cleaner output
        "noImplicitAny": false,
        "noImplicitReturns": false,
        "noImplicitThis": false
      },
      "include": [
        "src/**/*.ts",
        "src/types/embedded-assets.d.ts"
      ],
      "exclude": [
        "node_modules/**/*",
        "tests/**/*",
        "**/*.test.ts",
        "**/vitest/**/*",
        "node_modules/vitest/**/*"
      ]
    });

    fs.writeFileSync('tsconfig.types.json', tsconfigContent);

    // Step 2.5: Create debug tsconfig for dts-bundle-generator
    const debugTsconfigContent = JSON.stringify({
      "extends": ["@tsconfig/node22/tsconfig.json"],
      "compilerOptions": {
        "declaration": true,
        "emitDeclarationOnly": true,
        "outDir": "temp-types",
        "target": "es2018",
        "lib": ["es2018", "es2019", "es2020", "es2021", "es2022", "es2023", "dom"],
        "module": "commonjs",
        "moduleResolution": "node",
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "strict": false,
        "skipLibCheck": true,
        "skipDefaultLibCheck": true,
        "resolveJsonModule": true,
        "allowJs": false,
        "types": ["node", "vscode-languageserver"],
        "baseUrl": ".",
        "noImplicitAny": false,
        "noImplicitReturns": false,
        "noImplicitThis": false
      },
      "include": [
        "src/**/*.ts",
        "src/types/embedded-assets.d.ts"
      ],
      "exclude": [
        "node_modules/**/*",
        "tests/**/*",
        "**/*.test.ts",
        "**/vitest/**/*",
        "node_modules/vitest/**/*"
      ]
    });

    fs.writeFileSync('tsconfig.debug.json', debugTsconfigContent);

    // Step 3: Generate .d.ts files with TypeScript compiler
    console.log(logger.info('  Compiling TypeScript declarations...'));
    execSync('node_modules/typescript/bin/tsc -p tsconfig.types.json', { stdio: 'inherit' });

    // Step 4: Bundle all declarations with dts-bundle-generator
    console.log(logger.info('  Bundling type declarations...'));

    const dtsConfig = {
      "compilationOptions": {
        "preferredConfigPath": "./tsconfig.debug.json",
        "followSymlinks": false
      },
      "entries": [
        {
          "filePath": "./temp-types/src/main.d.ts",
          "outFile": "./dist/fish-lsp.d.ts",
          "noCheck": true,
          "output": {
            "inlineDeclareExternals": true,
            "sortNodes": true,
            "exportReferencedTypes": false,
            "respectPreserveConstEnum": true,
          },
          "libraries": {
            "allowedTypesLibraries": ["web-tree-sitter", "vscode-languageserver", "vscode-languageserver-textdocument", "node"],
            "importe
Download .txt
gitextract_6mzjd793/

├── .all-contributorsrc
├── .github/
│   ├── CODEOWNERS
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.md
│   │   └── feature_request.md
│   └── workflows/
│       ├── check-npm-release.yml
│       ├── ci.yml
│       └── test-npm-package.yml
├── .gitignore
├── .husky/
│   ├── commit-msg
│   ├── post-checkout
│   ├── post-merge
│   ├── pre-commit
│   └── prepare-commit-msg
├── .nvmrc
├── CODE_OF_CONDUCT.md
├── LICENSE.md
├── README.md
├── SECURITY.md
├── eslint.config.ts
├── fish_files/
│   ├── exec.fish
│   ├── expand_cartesian.fish
│   ├── get-autoloaded-filepath.fish
│   ├── get-command-options.fish
│   ├── get-completion.fish
│   ├── get-dependency.fish
│   ├── get-docs.fish
│   ├── get-documentation.fish
│   ├── get-fish-autoloaded-paths.fish
│   ├── get-type-verbose.fish
│   └── get-type.fish
├── man/
│   └── fish-lsp.1
├── package.json
├── renovate.json
├── scripts/
│   ├── build-assets.fish
│   ├── build-completions.fish
│   ├── build-time
│   ├── dev-complete.fish
│   ├── esbuild/
│   │   ├── cli.ts
│   │   ├── colors.ts
│   │   ├── configs.ts
│   │   ├── file-watcher.ts
│   │   ├── index.ts
│   │   ├── pipeline.ts
│   │   ├── plugins.ts
│   │   ├── types.ts
│   │   └── utils.ts
│   ├── fish/
│   │   ├── continue-or-exit.fish
│   │   ├── pretty-print.fish
│   │   └── utils.fish
│   ├── fish-commands-scrapper.ts
│   ├── publish-nightly.fish
│   ├── relink-locally.fish
│   ├── update-changelog.fish
│   ├── update-codeblocks-in-docs.ts
│   └── workspace-cli.ts
├── src/
│   ├── analyze.ts
│   ├── cli.ts
│   ├── code-actions/
│   │   ├── action-kinds.ts
│   │   ├── alias-wrapper.ts
│   │   ├── argparse-completions.ts
│   │   ├── code-action-handler.ts
│   │   ├── combiner.ts
│   │   ├── disable-actions.ts
│   │   ├── quick-fixes.ts
│   │   ├── redirect-actions.ts
│   │   └── refactors.ts
│   ├── code-lens.ts
│   ├── command.ts
│   ├── config.ts
│   ├── diagnostics/
│   │   ├── buffered-async-cache.ts
│   │   ├── comments-handler.ts
│   │   ├── diagnostic-ranges.ts
│   │   ├── error-codes.ts
│   │   ├── invalid-error-code.ts
│   │   ├── missing-completions.ts
│   │   ├── no-execute-diagnostic.ts
│   │   ├── node-types.ts
│   │   ├── types.ts
│   │   └── validate.ts
│   ├── document-highlight.ts
│   ├── document.ts
│   ├── documentation.ts
│   ├── execute-handler.ts
│   ├── formatting.ts
│   ├── hover.ts
│   ├── inlay-hints.ts
│   ├── linked-editing.ts
│   ├── logger.ts
│   ├── main.ts
│   ├── parser.ts
│   ├── parsing/
│   │   ├── alias.ts
│   │   ├── argparse.ts
│   │   ├── barrel.ts
│   │   ├── bind.ts
│   │   ├── comments.ts
│   │   ├── complete.ts
│   │   ├── emit.ts
│   │   ├── equality-utils.ts
│   │   ├── export.ts
│   │   ├── for.ts
│   │   ├── function.ts
│   │   ├── inline-variable.ts
│   │   ├── nested-strings.ts
│   │   ├── options.ts
│   │   ├── read.ts
│   │   ├── reference-comparator.ts
│   │   ├── set.ts
│   │   ├── source.ts
│   │   ├── string.ts
│   │   ├── symbol-converters.ts
│   │   ├── symbol-detail.ts
│   │   ├── symbol-kinds.ts
│   │   ├── symbol-modifiers.ts
│   │   ├── symbol.ts
│   │   ├── unreachable.ts
│   │   └── values.ts
│   ├── references.ts
│   ├── renames.ts
│   ├── selection-range.ts
│   ├── semantic-tokens.ts
│   ├── server.ts
│   ├── signature.ts
│   ├── snippets/
│   │   ├── envVariables.json
│   │   ├── fishlspEnvVariables.json
│   │   ├── functions.json
│   │   ├── helperCommands.json
│   │   ├── localeVariables.json
│   │   ├── pipesAndRedirects.json
│   │   ├── specialFishVariables.json
│   │   ├── statusNumbers.json
│   │   └── syntaxHighlightingVariables.json
│   ├── utils/
│   │   ├── builtins.ts
│   │   ├── cli-dump-tree.ts
│   │   ├── commander-cli-subcommands.ts
│   │   ├── completion/
│   │   │   ├── comment-completions.ts
│   │   │   ├── documentation.ts
│   │   │   ├── inline-parser.ts
│   │   │   ├── list.ts
│   │   │   ├── pager.ts
│   │   │   ├── shell.ts
│   │   │   ├── startup-cache.ts
│   │   │   ├── startup-config.ts
│   │   │   ├── static-items.ts
│   │   │   └── types.ts
│   │   ├── definition-scope.ts
│   │   ├── documentation-cache.ts
│   │   ├── env-manager.ts
│   │   ├── exec.ts
│   │   ├── file-operations.ts
│   │   ├── flag-documentation.ts
│   │   ├── flatten.ts
│   │   ├── get-lsp-completions.ts
│   │   ├── health-check.ts
│   │   ├── locations.ts
│   │   ├── markdown-builder.ts
│   │   ├── maybe.ts
│   │   ├── node-types.ts
│   │   ├── path-resolution.ts
│   │   ├── polyfills.ts
│   │   ├── process-env.ts
│   │   ├── progress-notification.ts
│   │   ├── semantics.ts
│   │   ├── snippets.ts
│   │   ├── startup.ts
│   │   ├── symbol-documentation-builder.ts
│   │   ├── translation.ts
│   │   ├── tree-sitter.ts
│   │   ├── workspace-manager.ts
│   │   └── workspace.ts
│   ├── virtual-fs.ts
│   └── web.ts
├── tests/
│   ├── alias-conversion.test.ts
│   ├── analyze-functions.test.ts
│   ├── analyzer.test.ts
│   ├── cli.test.ts
│   ├── code-action.test.ts
│   ├── comments-handler.test.ts
│   ├── complete-symbol.test.ts
│   ├── completion-shell.test.ts
│   ├── completion-startup-config.test.ts
│   ├── completion-variable-expansion.test.ts
│   ├── conditional-execution-diagnostics.test.ts
│   ├── definition-location.test.ts
│   ├── diagnostics-with-missing-completions.test.ts
│   ├── diagnostics.test.ts
│   ├── document-highlights.test.ts
│   ├── document-test-helpers.ts
│   ├── document.test.ts
│   ├── embedded-functions-resolution.test.ts
│   ├── example-test-workspace-usage.test.ts
│   ├── exec.test.ts
│   ├── execute-handler.test.ts
│   ├── file-operations.test.ts
│   ├── fish-symbol-fast-check.test.ts
│   ├── fish-symbol.test.ts
│   ├── fish-syntax-node.test.ts
│   ├── fish_files/
│   │   ├── __fish_complete_docutils.fish
│   │   ├── __fish_complete_gpg.fish
│   │   ├── __fish_config_interactive.fish
│   │   ├── __fish_shared_key_bindings.fish
│   │   ├── advanced/
│   │   │   ├── better_variable_scopes.fish
│   │   │   ├── inner_functions.fish
│   │   │   ├── lots_of_globals.fish
│   │   │   ├── multiple_functions.fish
│   │   │   ├── variable_scope.fish
│   │   │   └── variable_scope_2.fish
│   │   ├── errors/
│   │   │   ├── extra_end.fish
│   │   │   ├── invalid_pipes.fish
│   │   │   ├── missing_end.fish
│   │   │   └── variable_expansion_missing_name.fish
│   │   ├── fish_config.fish
│   │   ├── fish_git_prompt.fish
│   │   ├── fish_vi_key_bindings.fish
│   │   ├── help.fish
│   │   ├── history.fish
│   │   ├── huge_file.fish
│   │   ├── simple/
│   │   │   ├── all_variable_def_types.fish
│   │   │   ├── for_var.fish
│   │   │   ├── func_a.fish
│   │   │   ├── func_abc.fish
│   │   │   ├── function_variable_def.fish
│   │   │   ├── global_vs_local.fish
│   │   │   ├── inner_function.fish
│   │   │   ├── is_chained_return.fish
│   │   │   ├── multiple_broken_scopes.fish
│   │   │   ├── set_var.fish
│   │   │   ├── simple_function.fish
│   │   │   └── symbols.fish
│   │   ├── small_file.fish
│   │   ├── switch_case_test_1.fish
│   │   └── umask.fish
│   ├── format-aligned-columns.test.ts
│   ├── formatting.test.ts
│   ├── helpers.ts
│   ├── inline-variable.test.ts
│   ├── install_scripts/
│   │   └── generate_largest_fish_files.fish
│   ├── interactive-buffers.test.ts
│   ├── issue-140-complete-command-quoting.test.ts
│   ├── logger.test.ts
│   ├── main.test.ts
│   ├── markdown-builder.test.ts
│   ├── node-types.test.ts
│   ├── parser.test.ts
│   ├── parsing-defintions.test.ts
│   ├── parsing-env-values.test.ts
│   ├── parsing-export-defintions.test.ts
│   ├── parsing-function-with-event.test.ts
│   ├── parsing-indent-comments.test.ts
│   ├── parsing-string-value.test.ts
│   ├── process-env.test.ts
│   ├── read-workspace.test.ts
│   ├── reference-locations.test.ts
│   ├── selection-range.test.ts
│   ├── semantic-tokens-helpers.ts
│   ├── semantic-tokens.test.ts
│   ├── setup-mocks.ts
│   ├── snippets.test.ts
│   ├── sourced-function-export.test.ts
│   ├── startup-workspace.test.ts
│   ├── symbol-root-level.test.ts
│   ├── temp.ts
│   ├── test-comprehensive-utility.test.ts
│   ├── test-setup.test.ts
│   ├── test-snapshot-functionality.test.ts
│   ├── test-workspace-utils.ts
│   ├── tree-sitter-fast-check.test.ts
│   ├── tree-sitter.test.ts
│   ├── unreachable.test.ts
│   ├── virtual-file-handling.test.ts
│   ├── workspace-manager.test.ts
│   ├── workspace-util.ts
│   └── workspaces/
│       ├── embedded-functions-resolution/
│       │   ├── functions/
│       │   │   ├── my_test.fish
│       │   │   └── other_test.fish
│       │   └── test_script.fish
│       ├── example_test_src/
│       │   ├── completions/
│       │   │   ├── abbr.fish
│       │   │   ├── alias.fish
│       │   │   ├── cd.fish
│       │   │   ├── cdh.fish
│       │   │   ├── diff.fish
│       │   │   └── fish_add_path.fish
│       │   ├── config.fish
│       │   └── functions/
│       │       ├── abbr.fish
│       │       ├── alias.fish
│       │       ├── cd.fish
│       │       ├── cdh.fish
│       │       ├── contains_seq.fish
│       │       ├── diff.fish
│       │       ├── dirh.fish
│       │       ├── dirs.fish
│       │       ├── down-or-search.fish
│       │       ├── edit_command_buffer.fish
│       │       ├── export.fish
│       │       └── fish_add_path.fish
│       ├── incorrect-permissions-indexing/
│       │   └── file.fish
│       ├── semantic-tokens-simple-workspace/
│       │   ├── basic.fish
│       │   ├── commands.fish
│       │   ├── completions/
│       │   │   ├── deployctl.fish
│       │   │   └── source_fish.fish
│       │   ├── diagnostics.fish
│       │   ├── functions.fish
│       │   ├── keywords.fish
│       │   ├── mixed.fish
│       │   ├── operators.fish
│       │   └── variables.fish
│       ├── workspace_1/
│       │   └── fish/
│       │       ├── completions/
│       │       │   └── exa.fish
│       │       ├── config.fish
│       │       └── functions/
│       │           ├── func-inner.fish
│       │           ├── test-func.fish
│       │           ├── test-rename-1.fish
│       │           ├── test-rename-2.fish
│       │           └── test-variable-renames.fish
│       └── workspace_semantic-tokens/
│           └── test-operator-tokens.fish
├── tsconfig.eslint.json
├── tsconfig.json
└── vitest.config.ts
Download .txt
SYMBOL INDEX (2128 symbols across 143 files)

FILE: scripts/esbuild/cli.ts
  type BuildArgs (line 5) | interface BuildArgs {
  function parseArgs (line 19) | function parseArgs(): BuildArgs {
  function showHelp (line 97) | function showHelp(): void {
  function showCompletions (line 148) | function showCompletions(): void {

FILE: scripts/esbuild/colors.ts
  function toRelativePath (line 6) | function toRelativePath(filePath: string): string {
  function colorize (line 44) | function colorize(text: string, color: string): string {
  function enableColors (line 112) | function enableColors() {
  type String (line 127) | interface String {

FILE: scripts/esbuild/configs.ts
  type BuildConfig (line 7) | interface BuildConfig extends esbuild.BuildOptions {
  function createBuildOptions (line 112) | function createBuildOptions(config: BuildConfig, production = false, sou...

FILE: scripts/esbuild/file-watcher.ts
  function killProcessTree (line 8) | function killProcessTree(pid: number, signal: string = 'SIGTERM'): void {
  type BuildTrigger (line 77) | type BuildTrigger = 'file-change' | 'manual' | 'mode-switch';
  class BuildManager (line 79) | class BuildManager {
    method runBuild (line 85) | async runBuild(type: WatchMode, trigger: BuildTrigger): Promise<void> {
    method executeCommand (line 114) | private executeCommand(args: string[]): Promise<void> {
    method showCompletionMessage (line 153) | private showCompletionMessage(type: WatchMode, trigger: BuildTrigger, ...
    method cancel (line 181) | cancel(): boolean {
    method building (line 210) | get building(): boolean {
    method mode (line 214) | get mode(): WatchMode {
    method setMode (line 218) | setMode(mode: WatchMode): void {
  type WatchConfig (line 228) | interface WatchConfig {
  class FileWatcher (line 234) | class FileWatcher {
    method constructor (line 241) | constructor(config: WatchConfig, buildManager: BuildManager) {
    method start (line 246) | start(): void {
    method handleFileChange (line 324) | private handleFileChange(event: string, filePath: string): void {
    method showWatchedPaths (line 341) | showWatchedPaths(): void {
    method stop (line 378) | stop(): void {
  class KeyboardHandler (line 402) | class KeyboardHandler {
    method constructor (line 407) | constructor(buildManager: BuildManager, fileWatcher: FileWatcher) {
    method setup (line 412) | setup(): void {
    method handleKeyPress (line 423) | private async handleKeyPress(key: string): Promise<void> {
    method showModeSelection (line 476) | private async showModeSelection(): Promise<void> {
    method exit (line 524) | private exit(): void {
  function startFileWatcher (line 544) | async function startFileWatcher(initialMode: WatchMode = 'dev'): Promise...

FILE: scripts/esbuild/index.ts
  function build (line 8) | async function build(_customArgs?: string[]): Promise<void> {

FILE: scripts/esbuild/pipeline.ts
  type BuildStep (line 9) | interface BuildStep {
  class BuildPipeline (line 19) | class BuildPipeline {
    method register (line 22) | register(step: BuildStep): this {
    method execute (line 27) | async execute(target: string, args: BuildArgs): Promise<void> {
    method getStepsForTarget (line 65) | getStepsForTarget(target: string, args: BuildArgs): BuildStep[] {
    method getAllSteps (line 78) | getAllSteps(): ReadonlyArray<BuildStep> {
    method hasTarget (line 83) | hasTarget(target: string): boolean {

FILE: scripts/esbuild/plugins.ts
  type PluginOptions (line 14) | interface PluginOptions {
  function createPlugins (line 21) | function createPlugins(options: PluginOptions): esbuild.Plugin[] {
  function createDefines (line 157) | function createDefines(target: 'node' | 'browser' | string, production =...
  function createSourceMapOptimizationPlugin (line 206) | function createSourceMapOptimizationPlugin(preserveSourceContent?: boole...
  function createSpecialSourceMapPlugin (line 262) | function createSpecialSourceMapPlugin(options: { preserveOnlySrcContent?...
  function createWasmPlugin (line 359) | function createWasmPlugin(): Plugin {

FILE: scripts/esbuild/types.ts
  type BuildConfigTarget (line 6) | type BuildConfigTarget = 'binary' | 'development' | 'npm';
  type MetaTarget (line 11) | type MetaTarget = 'all' | 'types' | 'library' | 'test' | 'ci' | 'fresh' ...
  type BuildTarget (line 16) | type BuildTarget = BuildConfigTarget | MetaTarget;
  type WatchMode (line 21) | type WatchMode = 'dev' | 'binary' | 'npm' | 'types' | 'all' | 'lint' | '...
  type SourcemapMode (line 26) | type SourcemapMode = 'optimized' | 'extended' | 'none' | 'special';
  type TargetInfo (line 32) | interface TargetInfo {
  function create (line 48) | function create(
  function letterKey (line 74) | function letterKey(info: TargetInfo): string | undefined {
  function quickModeSummary (line 79) | function quickModeSummary(items: readonly TargetInfo[]): string {
  function helpEntry (line 84) | function helpEntry(info: TargetInfo): { key: string; color: string; text...
  constant VALID_WATCH_MODES (line 115) | const VALID_WATCH_MODES: readonly string[] = targets.map(t => t.name);
  constant VALID_SOURCEMAP_MODES (line 116) | const VALID_SOURCEMAP_MODES: readonly SourcemapMode[] = ['optimized', 'e...
  function findTarget (line 123) | function findTarget(nameOrKey: string): TargetInfo | undefined {
  function getTarget (line 132) | function getTarget(name: string): TargetInfo {

FILE: scripts/esbuild/utils.ts
  function copyDevelopmentAssets (line 10) | function copyDevelopmentAssets(): void {
  function ensureDirectoryExists (line 17) | function ensureDirectoryExists(dirPath: string): void {
  function formatBytes (line 22) | function formatBytes(bytes: number): string {
  function makeExecutable (line 26) | function makeExecutable(filePath: string): void {
  function showBuildStats (line 35) | function showBuildStats(filePath: string, label = 'Bundle'): void {
  function showDirectorySize (line 44) | function showDirectorySize(dirPath: string, label?: string): void {
  function isFileEmpty (line 65) | function isFileEmpty(filePath: string): boolean {
  function generateTypeDeclarations (line 74) | function generateTypeDeclarations(): void {

FILE: scripts/fish-commands-scrapper.ts
  type FishCommand (line 9) | interface FishCommand {
  type FishFunctionDefinition (line 14) | interface FishFunctionDefinition {
  type DatasetType (line 51) | type DatasetType = keyof typeof datasetConfig;
  function printHelp (line 79) | function printHelp() {
  function printCompletions (line 121) | function printCompletions() {
  function fetchFishCommands (line 308) | async function fetchFishCommands(): Promise<FishCommand[]> {
  function fetchSpecialVariables (line 346) | async function fetchSpecialVariables(...keys: ('special-variables' | 'en...
  function stripQuotes (line 441) | function stripQuotes(value: string): string {
  function tokenizeDefinition (line 449) | function tokenizeDefinition(line: string): string[] {
  function parseFunctionLine (line 491) | function parseFunctionLine(line: string): { name: string; flags: string[...
  function resolveFishDataDir (line 516) | function resolveFishDataDir(): string | null {
  function fetchFishFunctions (line 541) | async function fetchFishFunctions(): Promise<FishFunctionDefinition[]> {
  function fetchDataset (line 572) | async function fetchDataset(target: DatasetType): Promise<FishCommand[] ...
  function main (line 587) | async function main() {

FILE: scripts/update-codeblocks-in-docs.ts
  constant WORKSPACE_ROOT (line 35) | const WORKSPACE_ROOT = resolve(__dirname, '..');
  constant DRY_RUN (line 36) | const DRY_RUN = process.argv.includes('--dry-run');
  type UpdateDirective (line 42) | interface UpdateDirective {
  function extractUpdateDirectives (line 47) | function extractUpdateDirectives(content: string): UpdateDirective[] {
  function executeCommand (line 65) | function executeCommand(command: string): { output: string; status: numb...
  function processReadme (line 81) | function processReadme(content: string, filePath: string): { newContent:...
  function getMarkdownFiles (line 175) | function getMarkdownFiles(targetPath?: string): string[] {
  function processFile (line 210) | function processFile(filePath: string): { updated: boolean; updatesCount...
  function main (line 230) | function main() {

FILE: scripts/workspace-cli.ts
  type TestFileSpec (line 11) | interface TestFileSpec {
  type WorkspaceSnapshot (line 16) | interface WorkspaceSnapshot {
  class WorkspaceCLI (line 22) | class WorkspaceCLI {
    method fromSnapshot (line 23) | static fromSnapshot(snapshotPath: string): { name: string; files: Test...
    method convertSnapshotToWorkspace (line 34) | static convertSnapshotToWorkspace(snapshotPath: string, outputDir?: st...
    method readWorkspace (line 63) | static readWorkspace(folderPath: string): { path: string; files: strin...
    method convertWorkspaceToSnapshot (line 84) | static convertWorkspaceToSnapshot(folderPath: string, outputPath?: str...
    method showFileTree (line 112) | static showFileTree(dirPath: string): string {
    method showTreeSitterAST (line 137) | static async showTreeSitterAST(folderPath: string, useColors: boolean ...
  function generateFishCompletions (line 177) | function generateFishCompletions(): void {

FILE: src/analyze.ts
  type AnalyzedDocumentType (line 45) | type AnalyzedDocumentType = 'partial' | 'full';
  type EnsuredAnalyzeDocument (line 56) | type EnsuredAnalyzeDocument = Required<AnalyzedDocument> & { root: Synta...
  class AnalyzedDocument (line 72) | class AnalyzedDocument {
    method constructor (line 89) | private constructor(
    method create (line 144) | private static create(
    method createFull (line 177) | public static createFull(
    method createPartial (line 216) | public static createPartial(document: LspDocument): AnalyzedDocument {
    method isPartial (line 225) | public isPartial(): boolean {
    method isFull (line 233) | public isFull(): boolean {
    method ensureParsed (line 237) | public ensureParsed(): EnsuredAnalyzeDocument {
  class Analyzer (line 280) | class Analyzer {
    method constructor (line 301) | constructor(public parser: Parser) { }
    method initialize (line 347) | public static async initialize(): Promise<Analyzer> {
    method analyze (line 362) | public analyze(document: LspDocument): AnalyzedDocument {
    method removeDocumentSymbols (line 379) | public removeDocumentSymbols(uri: string): void {
    method analyzeUri (line 388) | public analyzeUri(uri: DocumentUri): AnalyzedDocument | undefined {
    method analyzePath (line 406) | public analyzePath(rawFilePath: string): AnalyzedDocument | undefined {
    method analyzePartial (line 436) | public analyzePartial(document: LspDocument): AnalyzedDocument {
    method getAnalyzedDocument (line 456) | private getAnalyzedDocument(document: LspDocument): AnalyzedDocument {
    method analyzeWorkspace (line 472) | public async analyzeWorkspace(
    method getSymbolAtLocation (line 543) | public getSymbolAtLocation(location: Location): FishSymbol | undefined {
    method findDocumentSymbol (line 551) | public findDocumentSymbol(
    method findDocumentSymbols (line 564) | public findDocumentSymbols(
    method findSymbol (line 578) | public findSymbol(
    method findSymbols (line 595) | public findSymbols(
    method findNode (line 613) | public findNode(
    method findNodes (line 632) | public findNodes(
    method findDocumentsGen (line 655) | public * findDocumentsGen(): Generator<LspDocument> {
    method findSymbolsGen (line 668) | public * findSymbolsGen(): Generator<{ document: LspDocument; symbols:...
    method findNodesGen (line 682) | public * findNodesGen(): Generator<{ document: LspDocument; nodes: Gen...
    method allSymbolsAccessibleAtPosition (line 703) | public allSymbolsAccessibleAtPosition(document: LspDocument, position:...
    method getWorkspaceSymbols (line 745) | public getWorkspaceSymbols(query: string = ''): WorkspaceSymbol[] {
    method getDefinitionHelper (line 759) | private getDefinitionHelper(document: LspDocument, position: Position)...
    method getDefinition (line 807) | public getDefinition(document: LspDocument, position: Position): FishS...
    method getDefinitionLocation (line 849) | public getDefinitionLocation(document: LspDocument, position: Position...
    method getImplementation (line 895) | public getImplementation(document: LspDocument, position: Position): L...
    method getSourceDefinitionLocation (line 905) | private getSourceDefinitionLocation(node: SyntaxNode, document: LspDoc...
    method getHover (line 931) | public getHover(document: LspDocument, position: Position): Hover | nu...
    method getTree (line 962) | getTree(documentUri: string): Tree | undefined {
    method getRootNode (line 980) | getRootNode(documentUri: string): SyntaxNode | undefined {
    method getDocument (line 994) | getDocument(documentUri: string): LspDocument | undefined {
    method getDocumentFromPath (line 1001) | getDocumentFromPath(path: string): LspDocument | undefined {
    method getDocumentSymbols (line 1010) | getDocumentSymbols(documentUri: string): FishSymbol[] {
    method getFlatDocumentSymbols (line 1018) | getFlatDocumentSymbols(documentUri: string): FishSymbol[] {
    method getFlatCompletionSymbols (line 1032) | getFlatCompletionSymbols(documentUri: string): CompletionSymbol[] {
    method nodesGen (line 1049) | public nodesGen(documentUri: string): {
    method getNodes (line 1070) | public getNodes(documentUri: string): SyntaxNode[] {
    method getNamedNodes (line 1081) | public getNamedNodes(documentUri: string): SyntaxNode[] {
    method collectSources (line 1096) | public collectSources(
    method collectReachableSources (line 1125) | public collectReachableSources(documentUri: string, position: Position...
    method collectAllSources (line 1160) | public collectAllSources(documentUri: string): Set<string> {
    method collectSourcedSymbols (line 1177) | public collectSourcedSymbols(documentUri: string): FishSymbol[] {
    method allReachableSymbols (line 1220) | public allReachableSymbols(documentUri: string): FishSymbol[] {
    method parseCurrentLine (line 1248) | public parseCurrentLine(
    method wordAtPoint (line 1273) | public wordAtPoint(
    method nodeAtPoint (line 1296) | public nodeAtPoint(
    method commandNameAtPoint (line 1312) | public commandNameAtPoint(
    method commandAtPoint (line 1331) | public commandAtPoint(
    method getTextAtLocation (line 1347) | public getTextAtLocation(location: LSP.Location): string {
    method ensureCachedDocument (line 1356) | public ensureCachedDocument(doc: LspDocument): AnalyzedDocument {
    method getIterableUris (line 1366) | private getIterableUris(): DocumentUri[] {
  class GlobalDefinitionCache (line 1388) | class GlobalDefinitionCache {
    method constructor (line 1389) | constructor(private _definitions: Map<string, FishSymbol[]> = new Map(...
    method add (line 1390) | add(symbol: FishSymbol): void {
    method removeSymbolsByUri (line 1397) | removeSymbolsByUri(uri: string): void {
    method find (line 1407) | find(name: string): FishSymbol[] {
    method findFirst (line 1410) | findFirst(name: string): FishSymbol | undefined {
    method has (line 1417) | has(name: string): boolean {
    method uniqueSymbols (line 1420) | uniqueSymbols(): FishSymbol[] {
    method allSymbols (line 1430) | get allSymbols(): FishSymbol[] {
    method allNames (line 1437) | get allNames(): string[] {
    method map (line 1440) | get map(): Map<string, FishSymbol[]> {
  class AnalyzedDocumentCache (line 1461) | class AnalyzedDocumentCache {
    method constructor (line 1462) | constructor(private _documents: Map<URI, AnalyzedDocument> = new Map()...
    method uris (line 1463) | uris(): string[] {
    method setDocument (line 1466) | setDocument(uri: URI, analyzedDocument: AnalyzedDocument): void {
    method getDocument (line 1469) | getDocument(uri: URI): AnalyzedDocument | undefined {
    method hasUri (line 1475) | hasUri(uri: URI): boolean {
    method updateUri (line 1478) | updateUri(oldUri: URI, newUri: URI): void {
    method getDocumentSymbols (line 1485) | getDocumentSymbols(uri: URI): FishSymbol[] {
    method getFlatDocumentSymbols (line 1493) | getFlatDocumentSymbols(uri: URI): FishSymbol[] {
    method getCommands (line 1496) | getCommands(uri: URI): SyntaxNode[] {
    method getRootNode (line 1504) | getRootNode(uri: URI): Parser.SyntaxNode | undefined {
    method getParsedTree (line 1507) | getParsedTree(uri: URI): Parser.Tree | undefined {
    method getSymbolTree (line 1515) | getSymbolTree(uri: URI): FishSymbol[] {
    method getSources (line 1523) | getSources(uri: URI): Set<string> {
    method getSourceNodes (line 1542) | getSourceNodes(uri: URI): SyntaxNode[] {
    method clear (line 1550) | clear(uri: URI) {
  function findCommandLocations (line 1555) | function findCommandLocations(cmd: string) {

FILE: src/cli.ts
  function execCLI (line 452) | function execCLI() {

FILE: src/code-actions/action-kinds.ts
  type SupportedCodeActionKinds (line 14) | type SupportedCodeActionKinds = typeof SupportedCodeActionKinds[keyof ty...

FILE: src/code-actions/alias-wrapper.ts
  function extractFunctionName (line 25) | function extractFunctionName(node: SyntaxNode): string {
  function createAliasInlineAction (line 41) | async function createAliasInlineAction(
  function createVersionedDocument (line 70) | function createVersionedDocument(uri: string) {
  function createFunctionFileEdit (line 74) | function createFunctionFileEdit(functionUri: string, content: string) {
  function createRemoveAliasEdit (line 81) | function createRemoveAliasEdit(document: LspDocument, node: SyntaxNode) {
  function createAliasSaveActionNewFile (line 91) | async function createAliasSaveActionNewFile(

FILE: src/code-actions/argparse-completions.ts
  type CompleteFlag (line 11) | type CompleteFlag = {
  function parseArgparseFlag (line 17) | function parseArgparseFlag(node: SyntaxNode): CompleteFlag {
  function findFlagsToComplete (line 39) | function findFlagsToComplete(node: SyntaxNode): CompleteFlag[] {
  function buildCompleteString (line 48) | function buildCompleteString(commandName: string, flags: CompleteFlag[])...
  function buildConfdCompletions (line 82) | function buildConfdCompletions(
  function getNodesForArgparse (line 134) | function getNodesForArgparse(selectedNode: SyntaxNode) {
  function createArgparseCompletionsCodeAction (line 166) | function createArgparseCompletionsCodeAction(

FILE: src/code-actions/code-action-handler.ts
  function sortCodeActionsByKind (line 18) | function sortCodeActionsByKind(actions: CodeAction[]): CodeAction[] {
  function isSelection (line 38) | function isSelection(range: Range): boolean {
  function getParentCommandNodeForCodeAction (line 43) | function getParentCommandNodeForCodeAction(node: SyntaxNode | null): Syn...
  function createCodeActionHandler (line 48) | function createCodeActionHandler() {
  function equalDiagnostics (line 309) | function equalDiagnostics(d1: Diagnostic, d2: Diagnostic) {
  function createOnCodeActionResolveHandler (line 319) | function createOnCodeActionResolveHandler() {
  function codeActionHandlers (line 325) | function codeActionHandlers() {

FILE: src/code-actions/combiner.ts
  function convertIfToCombinersString (line 28) | function convertIfToCombinersString(node: SyntaxNode) {
  function skipChildren (line 55) | function skipChildren(node: SyntaxNode, queue: SyntaxNode[]) {
  type BlockKeywordType (line 65) | type BlockKeywordType = 'if_statement' | 'else_if_clause' | 'else_clause';
  type ConditionalBlock (line 89) | interface ConditionalBlock {
  function create (line 104) | function create(keyword: BlockKeywordType, body: SyntaxNode[] = []) {
  class StatementCombiner (line 117) | class StatementCombiner {
    method currentBlock (line 120) | get currentBlock(): undefined | ConditionalBlock {
    method newBlock (line 130) | newBlock(keywordType: 'if_statement' | 'else_if_clause' | 'else_clause...
    method appendCommand (line 147) | appendCommand(node: SyntaxNode) {
    method getCombinerFromKeyword (line 165) | private getCombinerFromKeyword(block: ConditionalBlock) {
    method buildBlockString (line 180) | private buildBlockString(block: ConditionalBlock) {
    method build (line 201) | build() {

FILE: src/code-actions/disable-actions.ts
  type DiagnosticGroup (line 8) | interface DiagnosticGroup {
  function createDisableAction (line 14) | function createDisableAction(
  function handleDisableSingleLine (line 34) | function handleDisableSingleLine(
  function handleDisableBlock (line 55) | function handleDisableBlock(
  function groupDiagnostics (line 86) | function groupDiagnostics(diagnostics: Diagnostic[], maxGap: number = 1)...
  function handleDisableEntireFile (line 126) | function handleDisableEntireFile(
  function getDisableDiagnosticActions (line 192) | function getDisableDiagnosticActions(

FILE: src/code-actions/quick-fixes.ts
  function createQuickFix (line 26) | function createQuickFix(
  function createFixAllAction (line 43) | function createFixAllAction(
  function getErrorNodeToken (line 110) | function getErrorNodeToken(node: SyntaxNode): string | undefined {
  function handleMissingEndFix (line 177) | function handleMissingEndFix(
  function findErrorCauseFromNode (line 219) | function findErrorCauseFromNode(errorNode: SyntaxNode): SyntaxNode | null {
  function getTokenInsertionData (line 242) | function getTokenInsertionData(errNode: SyntaxNode, closingToken: string...
  function handleExtraEndFix (line 282) | function handleExtraEndFix(
  function handleMissingQuietError (line 299) | function handleMissingQuietError(
  function handleZeroIndexedArray (line 323) | function handleZeroIndexedArray(
  function handleDotSourceCommand (line 343) | function handleDotSourceCommand(
  function handleUniversalVariable (line 363) | function handleUniversalVariable(
  function handleExternalShellCommandInsteadOfBuiltin (line 393) | function handleExternalShellCommandInsteadOfBuiltin(
  function handleSingleQuoteVarFix (line 431) | function handleSingleQuoteVarFix(
  function handleTestCommandVariableExpansionWithoutString (line 457) | function handleTestCommandVariableExpansionWithoutString(
  function handleMissingDefinition (line 473) | function handleMissingDefinition(diagnostic: Diagnostic, node: SyntaxNod...
  function handleFilenameMismatch (line 497) | function handleFilenameMismatch(diagnostic: Diagnostic, node: SyntaxNode...
  function handleCompletionFilenameMismatch (line 531) | function handleCompletionFilenameMismatch(diagnostic: Diagnostic, node: ...
  function handleReservedKeyword (line 564) | function handleReservedKeyword(diagnostic: Diagnostic, node: SyntaxNode,...
  function handleUnusedSymbol (line 608) | function handleUnusedSymbol(diagnostic: Diagnostic, node: SyntaxNode, do...
  function handleAddEndStdinToArgparse (line 695) | function handleAddEndStdinToArgparse(diagnostic: Diagnostic, document: L...
  function handleConvertDeprecatedFishLsp (line 711) | function handleConvertDeprecatedFishLsp(diagnostic: Diagnostic, node: Sy...
  function getQuickFixes (line 731) | async function getQuickFixes(

FILE: src/code-actions/redirect-actions.ts
  function selectCommandNode (line 9) | function selectCommandNode(node: SyntaxNode): SyntaxNode | null {
  function silenceCommandAction (line 18) | function silenceCommandAction(
  function silenceStderrCommandAction (line 41) | function silenceStderrCommandAction(
  function silenceStdoutCommandAction (line 64) | function silenceStdoutCommandAction(
  function redirectStoutToStder (line 87) | function redirectStoutToStder(
  function handleRedirectActions (line 110) | function handleRedirectActions(

FILE: src/code-actions/refactors.ts
  function createRefactorAction (line 26) | function createRefactorAction(
  function extractFunctionWithArgparseToCompletionsFile (line 40) | function extractFunctionWithArgparseToCompletionsFile(
  function extractFunctionToFile (line 98) | function extractFunctionToFile(
  function extractToFunction (line 151) | function extractToFunction(
  function extractCommandToFunction (line 214) | function extractCommandToFunction(
  function extractToVariable (line 285) | function extractToVariable(
  function convertIfToCombiners (line 315) | function convertIfToCombiners(
  function isPathModifyingCommand (line 352) | function isPathModifyingCommand(node: SyntaxNode): boolean {
  function replaceAbsolutePathWithVariable (line 374) | function replaceAbsolutePathWithVariable(
  function simplifySetAppendPrepend (line 519) | function simplifySetAppendPrepend(

FILE: src/code-lens.ts
  function getReferenceCountCodeLenses (line 7) | function getReferenceCountCodeLenses(analyzer: Analyzer, document: LspDo...

FILE: src/command.ts
  type CommandName (line 41) | type CommandName = typeof CommandNames[keyof typeof CommandNames];
  type CommandArgs (line 44) | type CommandArgs = {
  function formatCommandHelp (line 131) | function formatCommandHelp(commandName: CommandName, reason?: string): s...
  type ParsedNumber (line 151) | type ParsedNumber =
  function parseNumberArg (line 155) | function parseNumberArg(value: string | number, argName: string = 'argum...
  function toZeroIndexed (line 183) | function toZeroIndexed(line: number): number {
  type ParsedPath (line 205) | type ParsedPath =
  function parsePathArg (line 209) | function parsePathArg(args: string[], argIndex: number = 0): ParsedPath {
  type ParsedNumberPair (line 242) | type ParsedNumberPair =
  function parseNumberPair (line 246) | function parseNumberPair(
  function createExecuteCommandHandler (line 305) | function createExecuteCommandHandler(

FILE: src/config.ts
  function updateHandlers (line 74) | function updateHandlers(keys: string[], value: boolean): void {
  type Config (line 156) | type Config = z.infer<typeof ConfigSchema>;
  function getConfigFromEnvironmentVariables (line 158) | function getConfigFromEnvironmentVariables(): {
  function getDefaultConfiguration (line 204) | function getDefaultConfiguration(): Config {
  function buildOutput (line 220) | function buildOutput(confd: boolean, result: string[]) {
  function convertValueToShellOutput (line 252) | function convertValueToShellOutput(value: Config.ConfigValueType) {
  function getDefaultValueAsShellOutput (line 260) | function getDefaultValueAsShellOutput(
  function getEnvVariableJsonObject (line 271) | function getEnvVariableJsonObject(
  function handleEnvOutput (line 284) | function handleEnvOutput(
  function escapeValue (line 406) | function escapeValue(value: string | number | boolean): string {
  type EnvVariableCommand (line 419) | type EnvVariableCommand = 'set -g' | 'set -l' | 'set -gx' | 'set -lx' | ...
  function getEnvVariableCommand (line 435) | function getEnvVariableCommand(useGlobal: boolean, useLocal: boolean, us...
  function fixPopups (line 468) | function fixPopups(enabled: string[], disabled: string[]): void {
  type ConfigValueType (line 524) | type ConfigValueType = string | number | boolean | string[] | number[];
  type ConfigKeyType (line 525) | type ConfigKeyType = keyof Config;
  function getDefaultValue (line 527) | function getDefaultValue(key: keyof Config): Config[keyof Config] {
  function getDocsForKey (line 532) | function getDocsForKey(key: keyof Config): string {
  function isDeprecatedKey (line 569) | function isDeprecatedKey(key: string): boolean {
  function getEnvVariableKey (line 585) | function getEnvVariableKey(key: string): keyof Config | undefined {
  function updateFromInitializationOptions (line 601) | function updateFromInitializationOptions(initializationOptions: Config |...
  function fixEnabledDisabledHandlers (line 621) | function fixEnabledDisabledHandlers(): void {
  function getResultCapabilities (line 639) | function getResultCapabilities(): InitializeResult {
  function initialize (line 715) | function initialize(params: InitializeParams, connection: Connection) {

FILE: src/diagnostics/buffered-async-cache.ts
  class BufferedAsyncDiagnosticCache (line 20) | class BufferedAsyncDiagnosticCache {
    method requestUpdate (line 37) | requestUpdate(uri: DocumentUri, immediate = false, changedSpan?: LineS...
    method update (line 109) | private async update(uri: DocumentUri): Promise<void> {
    method delete (line 189) | delete(uri: DocumentUri): void {
    method clear (line 217) | clear(): void {
    method get (line 240) | get(uri: DocumentUri): Diagnostic[] | undefined {
    method has (line 250) | has(uri: DocumentUri): boolean {
    method pendingCount (line 260) | get pendingCount(): number {
    method isPending (line 270) | isPending(uri: DocumentUri): boolean {
    method setForTesting (line 274) | public setForTesting(uri: DocumentUri, diagnostics: Diagnostic[]) {

FILE: src/diagnostics/comments-handler.ts
  type DiagnosticAction (line 7) | type DiagnosticAction = 'enable' | 'disable';
  type DiagnosticTarget (line 8) | type DiagnosticTarget = 'line' | 'next-line';
  type DiagnosticComment (line 10) | interface DiagnosticComment {
  type DiagnosticState (line 18) | interface DiagnosticState {
  constant DIAGNOSTIC_COMMENT_REGEX (line 34) | const DIAGNOSTIC_COMMENT_REGEX = /^#\s*@fish-lsp-(disable|enable)(?:-(ne...
  function isDiagnosticComment (line 41) | function isDiagnosticComment(node: SyntaxNode): boolean {
  function isValidErrorCode (line 46) | function isValidErrorCode(code: number): code is ErrorCodes.CodeTypes {
  function parseDiagnosticComment (line 55) | function parseDiagnosticComment(node: SyntaxNode): DiagnosticComment | n...
  type DiagnosticControlPoint (line 94) | interface DiagnosticControlPoint {
  type LineState (line 104) | interface LineState {
  class DiagnosticCommentsHandler (line 108) | class DiagnosticCommentsHandler {
    method constructor (line 124) | constructor() {
    method initialState (line 130) | private get initialState(): DiagnosticState {
    method rootState (line 142) | private get rootState(): DiagnosticState {
    method currentState (line 146) | private get currentState(): DiagnosticState {
    method globalEnabledCodes (line 150) | private globalEnabledCodes(): ErrorCodes.CodeTypes[] {
    method pushState (line 162) | private pushState(state: DiagnosticState) {
    method popState (line 166) | private popState() {
    method handleNode (line 177) | public handleNode(node: SyntaxNode): void {
    method processComment (line 198) | private processComment(comment: DiagnosticComment) {
    method cleanupNextLineComments (line 240) | private cleanupNextLineComments(currentLine: number) {
    method finalizeStateMap (line 254) | public finalizeStateMap(maxLine: number): void {
    method applyControlPointToState (line 306) | private applyControlPointToState(state: LineState, point: DiagnosticCo...
    method isCodeEnabledAtNode (line 320) | public isCodeEnabledAtNode(code: ErrorCodes.CodeTypes, node: SyntaxNod...
    method isCodeEnabledAtPosition (line 329) | public isCodeEnabledAtPosition(code: ErrorCodes.CodeTypes, position: P...
    method computeStateAtPosition (line 343) | private computeStateAtPosition(position: Position): LineState {
    method isCodeEnabled (line 372) | public isCodeEnabled(code: ErrorCodes.CodeTypes): boolean {
    method isRootEnabled (line 376) | public isRootEnabled(code: ErrorCodes.CodeTypes): boolean {
    method getStackDepth (line 380) | public getStackDepth(): number {
    method getCurrentState (line 384) | public getCurrentState(): DiagnosticState {
    method stateIterator (line 388) | public * stateIterator(): IterableIterator<DiagnosticState> {
    method getCurrentStateVerbose (line 397) | public getCurrentStateVerbose() {

FILE: src/diagnostics/diagnostic-ranges.ts
  type DisabledRange (line 10) | interface DisabledRange {
  type DiagnosticRangesResult (line 19) | interface DiagnosticRangesResult {
  constant DIAGNOSTIC_COMMENT_REGEX (line 33) | const DIAGNOSTIC_COMMENT_REGEX = /^#\s*@fish-lsp-(disable|enable)(?:-(ne...
  function isValidErrorCode (line 38) | function isValidErrorCode(code: number): code is ErrorCodes.CodeTypes {
  function getGlobalEnabledCodes (line 45) | function getGlobalEnabledCodes(): Set<ErrorCodes.CodeTypes> {
  type ParsedComment (line 59) | interface ParsedComment {
  function parseDiagnosticComment (line 71) | function parseDiagnosticComment(node: SyntaxNode): ParsedComment | null {
  function computeDiagnosticRanges (line 120) | function computeDiagnosticRanges(root: SyntaxNode, maxLine: number): Dia...
  class DiagnosticRangeChecker (line 217) | class DiagnosticRangeChecker {
    method constructor (line 225) | constructor(ranges: DiagnosticRangesResult, maxLine?: number) {
    method precomputeLineLookup (line 238) | private precomputeLineLookup(maxLine: number): void {
    method isCodeEnabledAtLine (line 261) | isCodeEnabledAtLine(code: ErrorCodes.CodeTypes, line: number): boolean {
    method isCodeEnabledAtNode (line 287) | isCodeEnabledAtNode(code: ErrorCodes.CodeTypes, node: SyntaxNode): boo...
    method getDisabledCodesAtLine (line 294) | getDisabledCodesAtLine(line: number): ErrorCodes.CodeTypes[] {
    method getSummary (line 314) | getSummary(): {
    method getLineState (line 329) | getLineState(line: number): {
  function createDiagnosticChecker (line 349) | function createDiagnosticChecker(root: SyntaxNode, maxLine: number): {

FILE: src/diagnostics/error-codes.ts
  type CodeTypes (line 40) | type CodeTypes =
  type CodeValueType (line 51) | type CodeValueType = {
  type DiagnosticCode (line 60) | type DiagnosticCode = {
  function getSeverityString (line 258) | function getSeverityString(severity: DiagnosticSeverity | undefined): st...
  function codeTypeGuard (line 274) | function codeTypeGuard(code: CodeTypes | number | string | undefined): c...
  function getDiagnostic (line 278) | function getDiagnostic(code: CodeTypes | number): CodeValueType {

FILE: src/diagnostics/invalid-error-code.ts
  constant DIAGNOSTIC_COMMENT_REGEX (line 9) | const DIAGNOSTIC_COMMENT_REGEX = /^#\s*@fish-lsp-(disable|enable)(?:-(ne...
  function isPossibleDiagnosticComment (line 11) | function isPossibleDiagnosticComment(node: SyntaxNode): boolean {
  function findCodes (line 17) | function findCodes(text: string): { code: string; startIndex: number; }[] {
  function detectInvalidDiagnosticCodes (line 42) | function detectInvalidDiagnosticCodes(node: SyntaxNode): Diagnostic[] {
  function checkForInvalidDiagnosticCodes (line 78) | function checkForInvalidDiagnosticCodes(node: SyntaxNode): Diagnostic[] {

FILE: src/diagnostics/missing-completions.ts
  function findAllMissingArgparseFlags (line 15) | function findAllMissingArgparseFlags(
  function findMissingArgparseFlagsWithExistingCompletions (line 61) | function findMissingArgparseFlagsWithExistingCompletions(
  function findMissingCompletionsWithExistingArgparse (line 101) | function findMissingCompletionsWithExistingArgparse(
  function createCompletionDiagnostic (line 139) | function createCompletionDiagnostic(completionGroup: CompletionSymbol[],...
  function createArgparseDiagnostic (line 192) | function createArgparseDiagnostic(

FILE: src/diagnostics/no-execute-diagnostic.ts
  function runNoExecuteDiagnostic (line 19) | function runNoExecuteDiagnostic(document: LspDocument): Diagnostic[] {
  function getNoExecuteDiagnostics (line 49) | function getNoExecuteDiagnostics(document: LspDocument): Diagnostic[] {

FILE: src/diagnostics/node-types.ts
  type startTokenType (line 18) | type startTokenType = 'function' | 'while' | 'if' | 'for' | 'begin' | 's...
  type endTokenType (line 19) | type endTokenType = 'end' | "'" | '"' | ']' | '}' | ')';
  function isStartTokenType (line 35) | function isStartTokenType(str: string): str is startTokenType {
  function findErrorCause (line 39) | function findErrorCause(children: Parser.SyntaxNode[]): Parser.SyntaxNod...
  function hasContentAfterQuote (line 77) | function hasContentAfterQuote(nodes: Parser.SyntaxNode[]): boolean {
  function isExtraEnd (line 90) | function isExtraEnd(node: SyntaxNode) {
  function isZeroIndex (line 94) | function isZeroIndex(node: SyntaxNode) {
  function isSingleQuoteVariableExpansion (line 98) | function isSingleQuoteVariableExpansion(node: Parser.SyntaxNode): boolean {
  function isAlias (line 110) | function isAlias(node: SyntaxNode): boolean {
  function isExport (line 114) | function isExport(node: SyntaxNode): boolean {
  function isWrapperFunction (line 118) | function isWrapperFunction(node: SyntaxNode, handler: DiagnosticComments...
  function isUniversalDefinition (line 125) | function isUniversalDefinition(node: SyntaxNode): boolean {
  function isSourceFilename (line 150) | function isSourceFilename(node: SyntaxNode): boolean {
  function isDotSourceCommand (line 182) | function isDotSourceCommand(node: SyntaxNode): boolean {
  function isTestCommandVariableExpansionWithoutString (line 189) | function isTestCommandVariableExpansionWithoutString(node: SyntaxNode): ...
  function isInsideStatementCondition (line 203) | function isInsideStatementCondition(statement: SyntaxNode, node: SyntaxN...
  function isConditionalStatement (line 218) | function isConditionalStatement(node: SyntaxNode) {
  function hasCommandSubstitution (line 246) | function hasCommandSubstitution(node: SyntaxNode) {
  class CommandAnalyzer (line 266) | class CommandAnalyzer {
    method findFirstCommand (line 270) | static findFirstCommand(node: SyntaxNode): Maybe<SyntaxNode> {
    method hasQuietFlags (line 277) | static hasQuietFlags(command: SyntaxNode): boolean {
    method isConditionalCommand (line 288) | static isConditionalCommand(command: SyntaxNode): boolean {
  class ConditionalContext (line 297) | class ConditionalContext {
    method isTopLevel (line 301) | static isTopLevel(node: SyntaxNode): boolean {
    method isUsedAsCondition (line 310) | static isUsedAsCondition(node: SyntaxNode): boolean {
    method hasConditionalOperators (line 320) | static hasConditionalOperators(node: SyntaxNode): boolean {
    method isConditionalChainNode (line 327) | static isConditionalChainNode(node: SyntaxNode): boolean {
  function isConditionalWithoutQuietCommand (line 347) | function isConditionalWithoutQuietCommand(node: SyntaxNode): boolean {
  function isCommandInConditionalContext (line 369) | function isCommandInConditionalContext(command: SyntaxNode): boolean {
  function isFirstCommandInConditionalChain (line 388) | function isFirstCommandInConditionalChain(command: SyntaxNode): boolean {
  function isFirstCommandInAnyIfCondition (line 402) | function isFirstCommandInAnyIfCondition(command: SyntaxNode): boolean {
  function isFirstCommandInSpecificCondition (line 414) | function isFirstCommandInSpecificCondition(command: SyntaxNode, conditio...
  function isVariableDefinitionWithExpansionCharacter (line 425) | function isVariableDefinitionWithExpansionCharacter(node: SyntaxNode, de...
  type LocalFunctionCallType (line 442) | type LocalFunctionCallType = {
  function isMatchingCompleteOptionIsCommand (line 447) | function isMatchingCompleteOptionIsCommand(node: SyntaxNode) {
  function isMatchingAbbrFunction (line 453) | function isMatchingAbbrFunction(node: SyntaxNode) {
  function isAbbrDefinitionName (line 457) | function isAbbrDefinitionName(node: SyntaxNode) {
  function isArgparseWithoutEndStdin (line 468) | function isArgparseWithoutEndStdin(node: SyntaxNode) {
  function isPosixCommandInsteadOfFishCommand (line 475) | function isPosixCommandInsteadOfFishCommand(node: SyntaxNode): boolean {
  function getFishBuiltinEquivalentCommandName (line 501) | function getFishBuiltinEquivalentCommandName(node: SyntaxNode): string |...
  function getAutoloadedFunctionsWithoutDescription (line 533) | function getAutoloadedFunctionsWithoutDescription(doc: LspDocument, hand...
  function isFunctionWithEventHookCallback (line 544) | function isFunctionWithEventHookCallback(doc: LspDocument, handler: Diag...
  function isFishLspDeprecatedVariableName (line 564) | function isFishLspDeprecatedVariableName(node: SyntaxNode): boolean {
  function getDeprecatedFishLspMessage (line 573) | function getDeprecatedFishLspMessage(node: SyntaxNode): string {
  function isKnownCommand (line 588) | function isKnownCommand(commandName: string, doc: LspDocument): boolean {

FILE: src/diagnostics/types.ts
  type FishDiagnostic (line 11) | interface FishDiagnostic extends Diagnostic {
  function create (line 21) | function create(
  function fromDiagnostic (line 43) | function fromDiagnostic(diagnostic: Diagnostic): FishDiagnostic {
  function fromSymbol (line 53) | function fromSymbol(code: ErrorCodes.CodeTypes, symbol: FishSymbol): Fis...

FILE: src/diagnostics/validate.ts
  constant CHUNK_SIZE (line 26) | const CHUNK_SIZE = 100;
  function getDiagnosticsAsync (line 41) | async function getDiagnosticsAsync(

FILE: src/document-highlight.ts
  function getDocumentHighlights (line 13) | function getDocumentHighlights(analyzer: Analyzer) {

FILE: src/document.ts
  class LspDocument (line 16) | class LspDocument implements TextDocument {
    method constructor (line 20) | constructor(doc: TextDocumentItem) {
    method createTextDocumentItem (line 25) | static createTextDocumentItem(uri: string, text: string): LspDocument {
    method fromTextDocument (line 34) | static fromTextDocument(doc: TextDocument): LspDocument {
    method createFromUri (line 39) | static createFromUri(uri: DocumentUri): LspDocument {
    method createFromPath (line 44) | static createFromPath(path: PathLike): LspDocument {
    method testUri (line 49) | static testUri(uri: DocumentUri): string {
    method testUtil (line 57) | static testUtil(uri: DocumentUri) {
    method create (line 73) | static create(
    method update (line 83) | static update(
    method createFrom (line 104) | static createFrom(param: PathLike | DocumentUri | TextDocument | TextD...
    method createFromUriAsync (line 115) | static async createFromUriAsync(uri: DocumentUri): Promise<LspDocument> {
    method asTextDocumentItem (line 120) | asTextDocumentItem(): TextDocumentItem {
    method asTextDocumentIdentifier (line 129) | asTextDocumentIdentifier(): TextDocumentIdentifier {
    method uri (line 135) | get uri(): DocumentUri {
    method languageId (line 139) | get languageId(): string {
    method version (line 143) | get version(): number {
    method path (line 147) | get path(): string {
    method fullSpan (line 154) | get fullSpan() {
    method getText (line 161) | getText(range?: Range): string {
    method positionAt (line 165) | positionAt(offset: number): Position {
    method offsetAt (line 169) | offsetAt(position: Position): number {
    method lineCount (line 173) | get lineCount(): number {
    method create (line 177) | create(uri: string, languageId: string, version: number, text: string)...
    method getLine (line 189) | getLine(line: number | Position | Range | FishSymbol): string {
    method getLineBeforeCursor (line 201) | getLineBeforeCursor(position: Position): string {
    method getLineRange (line 208) | getLineRange(line: number): Range {
    method getLineEnd (line 214) | getLineEnd(line: number): Position {
    method getLineOffset (line 219) | getLineOffset(line: number): number {
    method getLineStart (line 224) | getLineStart(line: number): Position {
    method getIndentAtLine (line 228) | getIndentAtLine(line: number): string {
    method update (line 240) | update(changes: TextDocumentContentChangeEvent[], version?: number): v...
    method asVersionedIdentifier (line 245) | asVersionedIdentifier() {
    method rename (line 249) | rename(newUri: string): void {
    method getFilePath (line 253) | getFilePath(): string {
    method getFilename (line 257) | getFilename(): string {
    method getRelativeFilenameToWorkspace (line 261) | getRelativeFilenameToWorkspace(): string {
    method isFunction (line 281) | isFunction(): boolean {
    method isAutoloadedFunction (line 293) | isAutoloadedFunction(): boolean {
    method isAutoloadedCompletion (line 297) | isAutoloadedCompletion(): boolean {
    method isAutoloadedConfd (line 301) | isAutoloadedConfd(): boolean {
    method shouldAnalyzeInBackground (line 305) | shouldAnalyzeInBackground(): boolean {
    method getWorkspace (line 312) | public getWorkspace(): Workspace | undefined {
    method getFolderType (line 316) | private getFolderType(): AutoloadType | null {
    method isAutoloaded (line 343) | isAutoloaded(): boolean {
    method isFunced (line 350) | isFunced(): boolean {
    method isCommandlineBuffer (line 354) | isCommandlineBuffer(): boolean {
    method isFuncedPath (line 358) | static isFuncedPath(path: string): boolean {
    method isCommandlineBufferPath (line 362) | static isCommandlineBufferPath(path: string): boolean {
    method isAutoloadedUri (line 375) | isAutoloadedUri(): boolean {
    method isAutoloadedWithPotentialCompletions (line 385) | isAutoloadedWithPotentialCompletions(): boolean {
    method getAutoloadType (line 394) | getAutoloadType(): AutoloadType {
    method getAutoLoadName (line 402) | getAutoLoadName(): string {
    method getFileName (line 411) | getFileName(): string {
    method getLines (line 417) | getLines(): number {
    method showTree (line 422) | showTree(): void {
    method getTree (line 426) | getTree(): string {
    method updateVersion (line 430) | updateVersion(version: number) {
    method is (line 441) | static is(value: unknown): value is LspDocument {
    method fileRange (line 467) | get fileRange(): Range {
    method hasShebang (line 473) | hasShebang(): boolean {
  type LineSpan (line 494) | type LineSpan = { start: number; end: number; isFullDocument?: boolean; };
  function computeChangedLineSpan (line 499) | function computeChangedLineSpan(
  function rangeOverlapsLineSpan (line 526) | function rangeOverlapsLineSpan(
  type Documents (line 563) | type Documents = typeof documents;

FILE: src/documentation.ts
  type markdownFiletypes (line 13) | type markdownFiletypes = 'fish' | 'man';
  function enrichToMarkdown (line 15) | function enrichToMarkdown(doc: string): MarkupContent {
  function enrichToCodeBlockMarkdown (line 24) | function enrichToCodeBlockMarkdown(doc: string, filetype: markdownFilety...
  function enrichWildcard (line 35) | function enrichWildcard(label: string, documentation: string, examples: ...
  function enrichCommandArg (line 50) | function enrichCommandArg(doc: string): MarkupContent {
  function enrichCommandWithFlags (line 64) | function enrichCommandWithFlags(command: string, description: string, fl...
  function handleSourceArgumentHover (line 79) | function handleSourceArgumentHover(analyzer: Analyzer, current: SyntaxNo...
  function handleBraceExpansionHover (line 103) | async function handleBraceExpansionHover(current: SyntaxNode): Promise<H...
  function handleEndStdinHover (line 129) | function handleEndStdinHover(current: SyntaxNode): Hover {
  function enrichToPlainText (line 170) | function enrichToPlainText(doc: string): MarkupContent {
  function documentationHoverProvider (line 177) | async function documentationHoverProvider(cmd: string): Promise<Hover | ...
  function documentationHoverProviderForBuiltIns (line 192) | async function documentationHoverProviderForBuiltIns(cmd: string): Promi...
  function commandStringHelper (line 213) | function commandStringHelper(cmd: string) {
  function documentationHoverCommandArg (line 220) | function documentationHoverCommandArg(root: SyntaxNode, cmp: CompletionA...
  function forwardSubCommandCollect (line 242) | function forwardSubCommandCollect(rootNode: SyntaxNode): string[] {
  function forwardArgCommandCollect (line 254) | function forwardArgCommandCollect(rootNode: SyntaxNode): string[] {
  function getFlagString (line 266) | function getFlagString(arr: string[]): string {
  class HoverFromCompletion (line 270) | class HoverFromCompletion {
    method constructor (line 280) | constructor(commandNode: SyntaxNode, currentNode: SyntaxNode) {
    method checkForSubCommands (line 296) | private async checkForSubCommands() {
    method isSubCommand (line 315) | private isSubCommand() {
    method hasOldStyleFlags (line 341) | private hasOldStyleFlags() {
    method reparseFlags (line 357) | private reparseFlags() {
    method buildCompletions (line 370) | public async buildCompletions() {
    method findCompletion (line 379) | public findCompletion(flag: string) {
    method checkForHoverDoc (line 388) | private async checkForHoverDoc() {
    method generateForFlags (line 397) | public async generateForFlags(): Promise<Hover> {
    method generateForSubcommand (line 420) | public async generateForSubcommand() {
    method generate (line 424) | public async generate(): Promise<Hover | void> {

FILE: src/execute-handler.ts
  type ExecResultKind (line 8) | type ExecResultKind = 'error' | 'info';
  type ExecResultWrapper (line 10) | type ExecResultWrapper = {
  function execLineInBuffer (line 15) | async function execLineInBuffer(line: string): Promise<ExecResultWrapper> {
  function buildOutput (line 36) | function buildOutput(line: string, outputMessage: 'error:' | 'stderr:' |...
  function buildExecuteNotificationResponse (line 59) | function buildExecuteNotificationResponse(
  function execEntireBuffer (line 72) | async function execEntireBuffer(bufferName: string): Promise<ExecResultW...
  function sourceFishBuffer (line 101) | async function sourceFishBuffer(bufferName: string) {
  function FishThemeDump (line 124) | async function FishThemeDump() {
  function showCurrentTheme (line 128) | async function showCurrentTheme(buffName: string) {
  type ThemeOptions (line 140) | type ThemeOptions = {
  function executeThemeDump (line 148) | async function executeThemeDump(buffName: string, options: ThemeOptions ...
  function findLongestLine (line 172) | function findLongestLine(...inputs: string[]): string {
  function useMessageKind (line 192) | function useMessageKind(connection: Connection, result: ExecResultWrappe...

FILE: src/formatting.ts
  function formatDocumentContent (line 6) | async function formatDocumentContent(content: string): Promise<string> {
  function formatDocumentRangeContent (line 23) | async function formatDocumentRangeContent(content: string): Promise<stri...
  type OriginalRange (line 40) | interface OriginalRange {
  function formatDocumentWithIndentComments (line 48) | async function formatDocumentWithIndentComments(doc: LspDocument): Promi...
  function formatDocumentRangeWithIndentComments (line 209) | async function formatDocumentRangeWithIndentComments(

FILE: src/hover.ts
  function handleHover (line 17) | async function handleHover(
  function getHoverForFlag (line 62) | async function getHoverForFlag(current: Parser.SyntaxNode): Promise<Hove...
  function hasOldUnixStyleFlags (line 97) | function hasOldUnixStyleFlags(allFlags: string[]) {
  function spiltShortFlags (line 109) | function spiltShortFlags(flags: string[], shouldSplit: boolean): string[] {
  function appendToCommand (line 124) | async function appendToCommand(commands: string[], subCommand: string): ...
  function collectCommandString (line 134) | async function collectCommandString(current: Parser.SyntaxNode): Promise...
  function isPrebuiltVariableExpansion (line 153) | function isPrebuiltVariableExpansion(node: Parser.SyntaxNode): boolean {
  function getPrebuiltVariableExpansionDocs (line 161) | function getPrebuiltVariableExpansionDocs(node: Parser.SyntaxNode): LSP....
  function getVariableExpansionDocs (line 181) | function getVariableExpansionDocs(analyzer: Analyzer, doc: LspDocument, ...

FILE: src/inlay-hints.ts
  function getStatusInlayHints (line 11) | function getStatusInlayHints(root: SyntaxNode): InlayHint[] {
  function findReturnNodes (line 57) | function findReturnNodes(root: SyntaxNode): SyntaxNode[] {
  function getStatusDescription (line 72) | function getStatusDescription(status: string): string {
  function getReturnStatusValue (line 85) | function getReturnStatusValue(returnNode: SyntaxNode): {
  function getExitStatusValue (line 109) | function getExitStatusValue(exitNode: SyntaxNode): {
  type InlayHintsCache (line 134) | type InlayHintsCache = {
  constant INLAY_HINTS_TTL (line 141) | const INLAY_HINTS_TTL = 1500;
  function getCachedInlayHints (line 143) | function getCachedInlayHints(
  function setCachedInlayHints (line 160) | function setCachedInlayHints(
  function getGlobalReferencesInlayHints (line 172) | function getGlobalReferencesInlayHints(
  function invalidateInlayHintsCache (line 209) | function invalidateInlayHintsCache(uri: string) {
  function getAllInlayHints (line 213) | function getAllInlayHints(analyzer: Analyzer, document: LspDocument): In...

FILE: src/linked-editing.ts
  function getLinkedEditingRanges (line 17) | function getLinkedEditingRanges(

FILE: src/logger.ts
  type IConsole (line 5) | interface IConsole {
  constant LOG_LEVELS (line 13) | const LOG_LEVELS = ['error', 'warning', 'info', 'debug', 'log', ''] as c...
  constant DEFAULT_LOG_LEVEL (line 14) | const DEFAULT_LOG_LEVEL: LogLevel = 'log';
  type LogLevel (line 16) | type LogLevel = typeof LOG_LEVELS[number];
  function getLogLevel (line 26) | function getLogLevel(level: string): LogLevel {
  class Logger (line 33) | class Logger {
    method constructor (line 61) | constructor(logFilePath: string = '') {
    method setLogFilePath (line 80) | setLogFilePath(logFilePath: string): this {
    method setConnectionConsole (line 88) | setConnectionConsole(_console: IConsole | undefined): this {
    method setConsole (line 100) | setConsole(_console: IConsole | undefined): this {
    method setClear (line 107) | setClear(clear: boolean = true): this {
    method setSilent (line 116) | setSilent(silence: boolean = true): this {
    method setLogLevel (line 124) | setLogLevel(level: string): this {
    method allowDefaultConsole (line 135) | allowDefaultConsole(): this {
    method isConnectionConsole (line 140) | isConnectionConsole(): boolean {
    method isStarted (line 144) | isStarted(): boolean {
    method isSilent (line 148) | isSilent(): boolean {
    method isClearing (line 152) | isClearing(): boolean {
    method isConnected (line 156) | isConnected(): boolean {
    method hasLogLevel (line 160) | hasLogLevel(): boolean {
    method hasConsole (line 164) | hasConsole(): boolean {
    method start (line 171) | start(): this {
    method hasLogFile (line 180) | hasLogFile(): boolean {
    method clearLogFile (line 187) | private clearLogFile(): void {
    method convertArgsToString (line 204) | convertArgsToString(...args: any[]): string {
    method formatArgument (line 224) | private formatArgument(arg: any): string {
    method _log (line 293) | private _log(...args: any[]): void {
    method logAsJson (line 304) | public logAsJson(...args: any[]) {
    method _logWithSeverity (line 313) | private _logWithSeverity(severity: LogLevel, ...args: string[]): void {
    method logPropertiesForEachObject (line 321) | logPropertiesForEachObject<T extends Record<string, any>>(objs: T[], ....
    method logTime (line 335) | public logTime(...args: any[]): void {
    method log (line 341) | public log(...args: any[]): void {
    method debug (line 351) | public debug(...args: any[]): void {
    method info (line 355) | public info(...args: any[]): void {
    method warning (line 359) | public warning(...args: any[]): void {
    method error (line 363) | public error(...args: any[]): void {
    method logToStdout (line 373) | public logToStdout(message: string, newline = true): void {
    method logToStdoutJoined (line 383) | public logToStdoutJoined(...message: string[]): void {
    method logToStderr (line 388) | public logToStderr(message: string, newline = true): void {
    method logFallbackToStdout (line 401) | public logFallbackToStdout(...args: any[]): void {
  function now (line 410) | function now(): string {
  function createServerLogger (line 426) | function createServerLogger(logFilePath: string, connectionConsole?: ICo...

FILE: src/main.ts
  function isBrowserEnvironment (line 19) | function isBrowserEnvironment(): boolean {
  function isRunningAsCLI (line 23) | function isRunningAsCLI(): boolean {
  function runCLI (line 28) | async function runCLI() {

FILE: src/parser.ts
  function initializeParser (line 8) | async function initializeParser(): Promise<Parser> {
  function bufferToUint8Array (line 45) | function bufferToUint8Array(buffer: ArrayBuffer | Buffer | string): Uint...

FILE: src/parsing/alias.ts
  type FishAliasInfoType (line 11) | type FishAliasInfoType = {
  function isAlias (line 24) | function isAlias(node: SyntaxNode): boolean {
  function getInfo (line 34) | function getInfo(node: SyntaxNode): {
  function toFunction (line 103) | function toFunction(node: SyntaxNode): string | null {
  function getNameRange (line 137) | function getNameRange(node: SyntaxNode) {
  function buildDetail (line 158) | function buildDetail(node: SyntaxNode) {
  function toFishDocumentSymbol (line 176) | function toFishDocumentSymbol(
  function getAliasScopeModifier (line 211) | function getAliasScopeModifier(document: LspDocument, node: SyntaxNode) {
  function getScopeNode (line 224) | function getScopeNode(node: SyntaxNode) {
  function isAliasDefinitionName (line 239) | function isAliasDefinitionName(node: SyntaxNode) {
  function isAliasDefinitionValue (line 263) | function isAliasDefinitionValue(node: SyntaxNode) {
  function processAliasCommand (line 287) | function processAliasCommand(document: LspDocument, node: SyntaxNode, ch...

FILE: src/parsing/argparse.ts
  function findArgparseOptions (line 38) | function findArgparseOptions(node: SyntaxNode) {
  function isArgparseOptionSpecifier (line 68) | function isArgparseOptionSpecifier(node: SyntaxNode) {
  function isInvalidArgparseName (line 94) | function isInvalidArgparseName(node: SyntaxNode) {
  function findArgparseDefinitionNames (line 121) | function findArgparseDefinitionNames(node: SyntaxNode): SyntaxNode[] {
  function isArgparseVariableDefinitionName (line 149) | function isArgparseVariableDefinitionName(node: SyntaxNode) {
  function convertNodeRangeWithPrecedingFlag (line 155) | function convertNodeRangeWithPrecedingFlag(node: SyntaxNode) {
  function isGlobalArgparseDefinition (line 166) | function isGlobalArgparseDefinition(document: LspDocument, symbol: FishS...
  function getGlobalArgparseLocations (line 199) | function getGlobalArgparseLocations(document: LspDocument, symbol: FishS...
  function getArgparseScopeModifier (line 241) | function getArgparseScopeModifier(document: LspDocument, _node: SyntaxNo...
  function getArgparseDefinitionName (line 254) | function getArgparseDefinitionName(node: SyntaxNode): string {
  function isCompletionArgparseFlagWithCommandName (line 280) | function isCompletionArgparseFlagWithCommandName(node: SyntaxNode, comma...
  function createSelectionRange (line 331) | function createSelectionRange(node: SyntaxNode, flags: string[], flag: s...
  function splitSlash (line 384) | function splitSlash(str: string): string[] {
  function getNames (line 393) | function getNames(flags: string[]) {
  function processArgparseCommand (line 406) | function processArgparseCommand(document: LspDocument, node: SyntaxNode,...

FILE: src/parsing/barrel.ts
  function isVariableDefinitionName (line 56) | function isVariableDefinitionName(node: SyntaxNode) {
  function isFunctionDefinitionName (line 71) | function isFunctionDefinitionName(node: SyntaxNode) {
  function isAliasDefinitionName (line 81) | function isAliasDefinitionName(node: SyntaxNode) {
  function isEmittedEventDefinitionName (line 90) | function isEmittedEventDefinitionName(node: SyntaxNode) {
  function isExportVariableDefinitionName (line 100) | function isExportVariableDefinitionName(node: SyntaxNode) {
  function isArgparseVariableDefinitionName (line 118) | function isArgparseVariableDefinitionName(node: SyntaxNode) {
  function isDefinitionName (line 127) | function isDefinitionName(node: SyntaxNode) {
  type DefinitionNodeNameTypes (line 162) | type DefinitionNodeNameTypes = 'isDefinitionName' | 'isVariableDefinitio...
  type DefinitionNodeChecker (line 163) | type DefinitionNodeChecker = (n: SyntaxNode) => boolean;

FILE: src/parsing/bind.ts
  function isBindCommand (line 21) | function isBindCommand(node: SyntaxNode) {
  function isBindKeySequence (line 29) | function isBindKeySequence(node: SyntaxNode) {
  function isBindFunctionCall (line 45) | function isBindFunctionCall(node: SyntaxNode) {

FILE: src/parsing/comments.ts
  constant INDENT_COMMENT_REGEX (line 7) | const INDENT_COMMENT_REGEX = /^#\s*@fish_indent(?::\s*(off|on)?)?$/;
  function isIndentComment (line 9) | function isIndentComment(node: SyntaxNode): boolean {
  type IndentComment (line 14) | interface IndentComment {
  function parseIndentComment (line 20) | function parseIndentComment(node: SyntaxNode): IndentComment | null {
  function processIndentComments (line 31) | function processIndentComments(root: SyntaxNode): IndentComment[] {
  type FormatRange (line 44) | interface FormatRange {
  type FormatRanges (line 49) | interface FormatRanges {
  function getEnabledIndentRanges (line 54) | function getEnabledIndentRanges(doc: LspDocument, rootNode?: SyntaxNode)...

FILE: src/parsing/complete.ts
  function isCompletionCommandDefinition (line 33) | function isCompletionCommandDefinition(node: SyntaxNode) {
  function isMatchingCompletionFlagNodeWithFishSymbol (line 37) | function isMatchingCompletionFlagNodeWithFishSymbol(symbol: FishSymbol, ...
  function isCompletionDefinitionWithName (line 76) | function isCompletionDefinitionWithName(node: SyntaxNode, name: string, ...
  function isCompletionSymbolShort (line 84) | function isCompletionSymbolShort(node: SyntaxNode) {
  function isCompletionSymbolLong (line 91) | function isCompletionSymbolLong(node: SyntaxNode) {
  function isCompletionSymbolOld (line 98) | function isCompletionSymbolOld(node: SyntaxNode) {
  function isCompletionSymbol (line 105) | function isCompletionSymbol(node: SyntaxNode) {
  type OptionType (line 111) | type OptionType = '' | 'short' | 'long' | 'old';
  class CompletionSymbol (line 112) | class CompletionSymbol {
    method constructor (line 113) | constructor(
    method createEmpty (line 128) | static createEmpty() {
    method create (line 135) | static create({
    method isEmpty (line 160) | isEmpty() {
    method isNonEmpty (line 168) | isNonEmpty(): this is CompletionSymbol & { node: SyntaxNode; parent: S...
    method parent (line 176) | get parent() {
    method text (line 187) | get text(): string {
    method isShort (line 197) | isShort() {
    method isLong (line 204) | isLong() {
    method isOld (line 211) | isOld() {
    method isCorrespondingOption (line 221) | isCorrespondingOption(other: CompletionSymbol) {
    method toFlag (line 233) | toFlag() {
    method toUsage (line 249) | toUsage() {
    method toUsageVerbose (line 259) | toUsageVerbose() {
    method equalsArgparse (line 270) | equalsArgparse(symbol: FishSymbol) {
    method equalsCommand (line 280) | equalsCommand(symbol: FishSymbol) {
    method equalsNode (line 291) | equalsNode(n: SyntaxNode) {
    method hasCommandName (line 298) | hasCommandName(name: string) {
    method isMatchingRawOption (line 305) | isMatchingRawOption(...opts: Flag[]) {
    method getRange (line 318) | getRange(): Range {
    method toLocation (line 328) | toLocation(): Location {
    method toPosition (line 332) | toPosition(): { line: number; character: number; } | null {
    method toArgparseOpt (line 354) | toArgparseOpt(): string {
    method toArgparseVariableName (line 365) | toArgparseVariableName(): string {
    method is (line 374) | static is(obj: unknown): obj is CompletionSymbol {
  function isCompletionSymbolVerbose (line 388) | function isCompletionSymbolVerbose(node: SyntaxNode, doc?: LspDocument):...
  function getCompletionSymbol (line 405) | function getCompletionSymbol(node: SyntaxNode, doc?: LspDocument): Compl...
  function groupCompletionSymbolsTogether (line 453) | function groupCompletionSymbolsTogether(
  function getGroupedCompletionSymbolsAsArgparse (line 473) | function getGroupedCompletionSymbolsAsArgparse(groupedCompletionSymbols:...
  function processCompletion (line 489) | function processCompletion(document: LspDocument, node: SyntaxNode) {

FILE: src/parsing/emit.ts
  function isEmittedEventDefinitionName (line 20) | function isEmittedEventDefinitionName(node: SyntaxNode): boolean {
  function findEmittedEventDefinitionName (line 38) | function findEmittedEventDefinitionName(node: SyntaxNode): SyntaxNode | ...
  function isGenericFunctionEventHandlerDefinitionName (line 56) | function isGenericFunctionEventHandlerDefinitionName(node: SyntaxNode): ...
  function processEmitEventCommandName (line 78) | function processEmitEventCommandName(document: LspDocument, node: Syntax...

FILE: src/parsing/equality-utils.ts
  type SymbolPair (line 9) | type SymbolPair = {
  type EqualityCheck (line 14) | type EqualityCheck = (pair: SymbolPair) => boolean;
  type ScopeCheck (line 15) | type ScopeCheck = (pair: SymbolPair) => boolean;

FILE: src/parsing/export.ts
  function isExportDefinition (line 15) | function isExportDefinition(node: SyntaxNode): boolean {
  function isExportVariableDefinitionName (line 21) | function isExportVariableDefinitionName(node: SyntaxNode): boolean {
  type ExtractedExportVariable (line 45) | type ExtractedExportVariable = {
  function findVariableDefinitionNameNode (line 51) | function findVariableDefinitionNameNode(node: SyntaxNode): {
  function extractExportVariable (line 113) | function extractExportVariable(node: SyntaxNode): ExtractedExportVariabl...
  function buildExportDetail (line 137) | function buildExportDetail(doc: LspDocument, commandNode: SyntaxNode, va...
  function processExportCommand (line 160) | function processExportCommand(document: LspDocument, node: SyntaxNode, c...

FILE: src/parsing/for.ts
  function isForVariableDefinitionName (line 18) | function isForVariableDefinitionName(node: SyntaxNode): boolean {
  function processForDefinition (line 38) | function processForDefinition(document: LspDocument, node: SyntaxNode, c...

FILE: src/parsing/function.ts
  function isFunctionDefinition (line 36) | function isFunctionDefinition(node: SyntaxNode) {
  function findFunctionDefinitionChildren (line 49) | function findFunctionDefinitionChildren(node: SyntaxNode) {
  function processArgvDefinition (line 56) | function processArgvDefinition(document: LspDocument, node: SyntaxNode) {
  function isFunctionDefinitionName (line 86) | function isFunctionDefinitionName(node: SyntaxNode) {
  function isFunctionVariableDefinitionName (line 100) | function isFunctionVariableDefinitionName(node: SyntaxNode) {
  function findFunctionOptionNamedArguments (line 116) | function findFunctionOptionNamedArguments(node: SyntaxNode): {
  function processFunctionDefinition (line 152) | function processFunctionDefinition(document: LspDocument, node: SyntaxNo...

FILE: src/parsing/inline-variable.ts
  function hasInlineVariables (line 24) | function hasInlineVariables(commandNode: SyntaxNode): boolean {
  function isInlineVariableAssignment (line 41) | function isInlineVariableAssignment(node: SyntaxNode): boolean {
  function parseInlineVariableAssignment (line 54) | function parseInlineVariableAssignment(node: SyntaxNode): { name: string...
  function processInlineVariables (line 71) | function processInlineVariables(document: LspDocument, commandNode: Synt...
  function findAllInlineVariables (line 136) | function findAllInlineVariables(document: LspDocument, tree: SyntaxNode)...
  function getInlineVariableCompletions (line 160) | function getInlineVariableCompletions(): string[] {

FILE: src/parsing/nested-strings.ts
  type ExtractConfig (line 8) | interface ExtractConfig {
  type CommandReference (line 20) | interface CommandReference {
  constant DEFAULT_CONFIG (line 27) | const DEFAULT_CONFIG: ExtractConfig = {
  constant FISH_KEYWORDS (line 36) | const FISH_KEYWORDS = new Set([
  constant FISH_OPERATORS (line 42) | const FISH_OPERATORS = new Set([
  function extractCommands (line 50) | function extractCommands(
  function extractCommandLocations (line 89) | function extractCommandLocations(
  function extractMatchingCommandLocations (line 127) | function extractMatchingCommandLocations(
  function cleanQuotes (line 141) | function cleanQuotes(input: string): string {
  function getQuoteOffset (line 153) | function getQuoteOffset(input: string): number {
  function findCommandsWithOffsets (line 165) | function findCommandsWithOffsets(
  function findCommandSubstitutionOffsets (line 190) | function findCommandSubstitutionOffsets(text: string): Array<{ command: ...
  function findParenthesizedCommandOffsets (line 216) | function findParenthesizedCommandOffsets(text: string): Array<{ command:...
  function findDirectCommandOffsets (line 255) | function findDirectCommandOffsets(
  function getFirstCommand (line 298) | function getFirstCommand(text: string): string | null {
  function extractCommandsFromText (line 306) | function extractCommandsFromText(input: string, cleanKeywords = true): s...
  function parseCommandSubstitutions (line 335) | function parseCommandSubstitutions(input: string): string[] {
  function parseParenthesizedExpressions (line 353) | function parseParenthesizedExpressions(input: string): string[] {
  function parseOptionArgument (line 381) | function parseOptionArgument(text: string): string | null {
  function parseDirectCommands (line 400) | function parseDirectCommands(input: string, config: ExtractConfig): stri...
  function tokenizeStatement (line 407) | function tokenizeStatement(statement: string): string[] {
  function createPreciseRange (line 445) | function createPreciseRange(command: string, offset: number, nodeRange: ...
  function isNumeric (line 463) | function isNumeric(str: string): boolean {

FILE: src/parsing/options.ts
  type AlphaLowercaseChar (line 9) | type AlphaLowercaseChar = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' ...
  type AlphaUppercaseChar (line 10) | type AlphaUppercaseChar = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' ...
  type AlphaChar (line 11) | type AlphaChar = AlphaLowercaseChar | AlphaUppercaseChar;
  type DigitChar (line 12) | type DigitChar = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
  type ExtraChar (line 13) | type ExtraChar = '?' | '!' | '@' | '$' | '%' | '^' | '&' | '*' | '(' | '...
  type Character (line 14) | type Character = AlphaChar | DigitChar | ExtraChar;
  type ShortFlag (line 22) | type ShortFlag = `-${Character}`;
  type UnixFlag (line 23) | type UnixFlag = `-${string}`;
  type LongFlag (line 24) | type LongFlag = `--${string}`;
  type Flag (line 25) | type Flag = ShortFlag | UnixFlag | LongFlag;
  class Option (line 34) | class Option {
    method create (line 42) | static create(shortOption: ShortFlag | '', longOption: LongFlag | ''):...
    method long (line 53) | static long(longOption: LongFlag): Option {
    method short (line 59) | static short(shortOption: ShortFlag): Option {
    method unix (line 65) | static unix(unixOption: UnixFlag): Option {
    method fromRaw (line 71) | static fromRaw(...str: string[]) {
    method addUnixFlag (line 85) | addUnixFlag(...options: UnixFlag[]): Option {
    method withAliases (line 93) | withAliases(...optionAlias: ShortFlag[] | LongFlag[] | string[]): Opti...
    method isOption (line 107) | isOption(shortOption: ShortFlag | '', longOption: LongFlag | ''): bool...
    method withValue (line 119) | withValue(): Option {
    method withOptionalValue (line 129) | withOptionalValue(): Option {
    method withMultipleValues (line 139) | withMultipleValues(): Option {
    method isSwitch (line 158) | isSwitch(): boolean {
    method matchesValue (line 162) | matchesValue(node: SyntaxNode): boolean {
    method matches (line 192) | matches(node: SyntaxNode, checkWithEquals: boolean = true): boolean {
    method matchesLongFlag (line 214) | private matchesLongFlag(text: string): boolean {
    method matchesUnixFlag (line 222) | private matchesUnixFlag(text: string): boolean {
    method matchesShortFlag (line 229) | private matchesShortFlag(text: string): boolean {
    method equals (line 237) | equals(node: SyntaxNode, allowEquals = false): boolean {
    method equalsRawOption (line 249) | equalsRawOption(...rawOption: Flag[]): boolean {
    method equalsRawShortOption (line 261) | equalsRawShortOption(...rawOption: ShortFlag[]): boolean {
    method equalsRawLongOption (line 265) | equalsRawLongOption(...rawOption: LongFlag[]): boolean {
    method equalsOption (line 269) | equalsOption(other: Option): boolean {
    method findValueRangeAfterEquals (line 274) | findValueRangeAfterEquals(node: SyntaxNode): LSP.Range | null {
    method isSet (line 293) | isSet(node: SyntaxNode): boolean {
    method getAllFlags (line 300) | getAllFlags(): Array<string> {
    method toString (line 308) | toString(): string {
    method toName (line 312) | toName(): string {
  type OptionValueMatch (line 326) | type OptionValueMatch = {
  function findOptionsSet (line 331) | function findOptionsSet(nodes: SyntaxNode[], options: Option[]): OptionV...
  function findOptions (line 343) | function findOptions(nodes: SyntaxNode[], options: Option[]): { remainin...
  function isMatchingOption (line 371) | function isMatchingOption(node: SyntaxNode, ...option: Option[]): boolean {
  function findMatchingOptions (line 382) | function findMatchingOptions(node: SyntaxNode, ...options: Option[]): Op...
  function isMatchingOptionOrOptionValue (line 387) | function isMatchingOptionOrOptionValue(node: SyntaxNode, option: Option)...
  function isMatchingOptionValue (line 420) | function isMatchingOptionValue(node: SyntaxNode, ...options: Option[]): ...

FILE: src/parsing/read.ts
  function isReadVariableDefinitionName (line 53) | function isReadVariableDefinitionName(node: SyntaxNode) {
  function isReadDefinition (line 59) | function isReadDefinition(node: SyntaxNode) {
  function getFallbackModifierScope (line 63) | function getFallbackModifierScope(document: LspDocument, node: SyntaxNod...
  function findReadChildren (line 84) | function findReadChildren(node: SyntaxNode): { definitionNodes: SyntaxNo...
  function findReadParent (line 143) | function findReadParent(node: SyntaxNode, scopeModifier: ModifierScopeTa...
  function processReadCommand (line 159) | function processReadCommand(document: LspDocument, node: SyntaxNode, chi...

FILE: src/parsing/reference-comparator.ts
  type ReferenceContext (line 17) | type ReferenceContext = {
  type ReferenceCheck (line 24) | type ReferenceCheck = (ctx: ReferenceContext) => boolean;

FILE: src/parsing/set.ts
  function isSetDefinition (line 36) | function isSetDefinition(node: SyntaxNode) {
  function isSetQueryDefinition (line 40) | function isSetQueryDefinition(node: SyntaxNode) {
  function isSetVariableDefinitionName (line 49) | function isSetVariableDefinitionName(node: SyntaxNode, excludeQuery = tr...
  function getFallbackModifierScope (line 57) | function getFallbackModifierScope(document: LspDocument, node: SyntaxNod...
  function findSetChildren (line 73) | function findSetChildren(node: SyntaxNode) {
  function setModifierDetailDescriptor (line 79) | function setModifierDetailDescriptor(node: SyntaxNode) {
  function findParentScopeNode (line 104) | function findParentScopeNode(commandNode: SyntaxNode, modifier: Modifier...
  function processSetCommand (line 117) | function processSetCommand(document: LspDocument, node: SyntaxNode, chil...

FILE: src/parsing/source.ts
  function isSourceCommandName (line 17) | function isSourceCommandName(node: SyntaxNode) {
  function isSourceCommandWithArgument (line 21) | function isSourceCommandWithArgument(node: SyntaxNode) {
  function isSourceCommandArgumentName (line 25) | function isSourceCommandArgumentName(node: SyntaxNode) {
  function isSourcedFilename (line 32) | function isSourcedFilename(node: SyntaxNode) {
  function isExistingSourceFilenameNode (line 39) | function isExistingSourceFilenameNode(node: SyntaxNode, baseDir?: string) {
  function getExpandedSourcedFilenameNode (line 45) | function getExpandedSourcedFilenameNode(node: SyntaxNode, baseDir?: stri...
  function resolveSourcePath (line 61) | function resolveSourcePath(sourcePath: string, baseDir?: string): string {
  type SourceResource (line 82) | interface SourceResource {
    method constructor (line 93) | constructor(
    method create (line 103) | static create(
    method scopeReachableFromNode (line 121) | scopeReachableFromNode(node: SyntaxNode) {
  class SourceResource (line 92) | class SourceResource {
    method constructor (line 93) | constructor(
    method create (line 103) | static create(
    method scopeReachableFromNode (line 121) | scopeReachableFromNode(node: SyntaxNode) {
  function createSourceResources (line 129) | function createSourceResources(analyzer: Analyzer, from: LspDocument): S...
  function reachableSources (line 153) | function reachableSources(resources: SourceResource[], uniqueUris: Set<s...
  function symbolsFromResource (line 179) | function symbolsFromResource(analyzer: Analyzer, resources: SourceResour...

FILE: src/parsing/string.ts
  function unescapeSequence (line 13) | function unescapeSequence(seq: string): string {
  function fromNode (line 73) | function fromNode(node: SyntaxNode): string {
  function fromText (line 96) | function fromText(text: string): string {
  function parse (line 114) | function parse(input: SyntaxNode | string): string {

FILE: src/parsing/symbol-detail.ts
  function unindentNestedSyntaxNode (line 29) | function unindentNestedSyntaxNode(node: SyntaxNode) {
  function getSymbolKind (line 41) | function getSymbolKind(symbol: FishSymbol) {
  function isAutoloadedPath (line 60) | function isAutoloadedPath(uriOrPath: string, type?: string): boolean {
  function getAutoloadType (line 91) | function getAutoloadType(uriOrPath: string): string {
  function buildFunctionDetail (line 118) | function buildFunctionDetail(symbol: FishSymbol) {
  function isVariableArgumentNamed (line 167) | function isVariableArgumentNamed(node: SyntaxNode, name: string) {
  function getArgumentNamesIndexString (line 178) | function getArgumentNamesIndexString(node: SyntaxNode, name: string) {
  function buildVariableDetail (line 189) | function buildVariableDetail(symbol: FishSymbol) {
  function createDetail (line 258) | function createDetail(symbol: FishSymbol) {

FILE: src/parsing/symbol-kinds.ts
  type FishSymbolKind (line 8) | type FishSymbolKind = 'ARGPARSE' | 'FUNCTION' | 'ALIAS' | 'COMPLETE' | '...
  type kindGroups (line 105) | type kindGroups = 'VARIABLES' | 'FUNCTIONS' | 'EVENTS' | 'ARGPARSE' | 'O...
  type FishSymbolInput (line 118) | type FishSymbolInput = Pick<FishSymbol,

FILE: src/parsing/symbol-modifiers.ts
  function getSetReadModifiers (line 27) | function getSetReadModifiers(symbol: FishSymbol): SemanticTokenModifier[] {
  function getSymbolModifiers (line 65) | function getSymbolModifiers(symbol: FishSymbol): SemanticTokenModifier[] {

FILE: src/parsing/symbol.ts
  constant SKIPPABLE_VARIABLE_REFERENCE_NAMES (line 30) | const SKIPPABLE_VARIABLE_REFERENCE_NAMES = [
  type FishSymbol (line 35) | interface FishSymbol extends DocumentSymbol {
    method constructor (line 54) | constructor(obj: FishSymbolInput) {
    method setupDetail (line 74) | setupDetail() {
    method create (line 78) | static create(
    method fromObject (line 104) | static fromObject(obj: FishSymbolInput) {
    method copy (line 108) | public copy(): FishSymbol {
    method is (line 112) | static is(obj: unknown): obj is FishSymbol {
    method addChildren (line 116) | addChildren(...children: FishSymbol[]) {
    method addAliasedNames (line 124) | addAliasedNames(...names: string[]) {
    method nameEqualsNodeText (line 129) | private nameEqualsNodeText(node: SyntaxNode) {
    method isBefore (line 133) | public isBefore(other: FishSymbol, urisMustMatch = true) {
    method isAfter (line 138) | public isAfter(other: FishSymbol, urisMustMatch = true) {
    method argparseFlagName (line 146) | public get argparseFlagName() {
    method argparseFlagFromName (line 153) | public static argparseFlagFromName(name: string) {
    method argparseFlag (line 160) | public get argparseFlag(): Flag | string {
    method isArgparseCompletionFlag (line 187) | private isArgparseCompletionFlag(node: SyntaxNode): boolean {
    method isCommandCompletionFlag (line 203) | private isCommandCompletionFlag(node: SyntaxNode) {
    method isExported (line 213) | isExported(): boolean {
    method isEqualLocation (line 235) | isEqualLocation(node: SyntaxNode) {
    method needsLocalReferences (line 281) | needsLocalReferences(): boolean {
    method skippableVariableName (line 310) | skippableVariableName(): boolean {
    method path (line 315) | get path() {
    method workspacePath (line 319) | get workspacePath() {
    method scopeTag (line 333) | get scopeTag() {
    method scopeNode (line 343) | get scopeNode() {
    method toString (line 348) | toString() {
    method toWorkspaceSymbol (line 352) | toWorkspaceSymbol(): WorkspaceSymbol {
    method toDocumentSymbol (line 356) | toDocumentSymbol(): DocumentSymbol | undefined {
    method toLocation (line 360) | toLocation(): Location {
    method toPosition (line 364) | toPosition(): Position {
    method toFoldingRange (line 368) | toFoldingRange(): FoldingRange {
    method toMarkupContent (line 372) | toMarkupContent(): MarkupContent {
    method toHover (line 380) | toHover(currentUri: DocumentUri = ''): Hover {
    method isLocal (line 385) | isLocal() {
    method isGlobal (line 389) | isGlobal() {
    method isAutoloaded (line 393) | isAutoloaded() {
    method isRootLevel (line 399) | isRootLevel() {
    method isEventHook (line 407) | isEventHook(): boolean {
    method isEmittedEvent (line 411) | isEmittedEvent(): boolean {
    method isEvent (line 415) | isEvent(): boolean {
    method isFunction (line 419) | isFunction(): boolean {
    method isVariable (line 423) | isVariable(): boolean {
    method isArgparse (line 427) | isArgparse(): boolean {
    method isSymbolImmutable (line 431) | isSymbolImmutable() {
    method isConfigDefinition (line 446) | isConfigDefinition() {
    method isConfigDefinitionWithErase (line 456) | isConfigDefinitionWithErase() {
    method findValueNodes (line 468) | findValueNodes(): SyntaxNode[] {
    method valuesAsShellValues (line 482) | valuesAsShellValues() {
    method equalArgparse (line 492) | equalArgparse(other: FishSymbol | CompletionSymbol) {
    method hasEventHook (line 520) | hasEventHook() {
    method equalsEvent (line 549) | equalsEvent(other: FishSymbol | CompletionSymbol): boolean {
    method isReference (line 578) | isReference(document: LspDocument, node: SyntaxNode, excludeEqualNode ...
    method equals (line 585) | equals(other: FishSymbol): boolean {
    method equalsLocation (line 592) | equalsLocation(location: Location): boolean {
    method equalDefinition (line 599) | equalDefinition(other: FishSymbol): boolean {
    method equalsNode (line 610) | equalsNode(node: SyntaxNode, opts: { strict?: boolean; } = { strict: f...
    method containsScope (line 619) | containsScope(other: FishSymbol): boolean {
    method equalScopes (line 626) | equalScopes(other: FishSymbol): boolean {
    method scopeContainsNode (line 633) | scopeContainsNode(node: SyntaxNode): boolean {
    method containsNode (line 640) | containsNode(node: SyntaxNode): boolean {
    method containsPosition (line 649) | containsPosition(position: { line: number; character: number; }): bool...
  class FishSymbol (line 48) | class FishSymbol {
    method constructor (line 54) | constructor(obj: FishSymbolInput) {
    method setupDetail (line 74) | setupDetail() {
    method create (line 78) | static create(
    method fromObject (line 104) | static fromObject(obj: FishSymbolInput) {
    method copy (line 108) | public copy(): FishSymbol {
    method is (line 112) | static is(obj: unknown): obj is FishSymbol {
    method addChildren (line 116) | addChildren(...children: FishSymbol[]) {
    method addAliasedNames (line 124) | addAliasedNames(...names: string[]) {
    method nameEqualsNodeText (line 129) | private nameEqualsNodeText(node: SyntaxNode) {
    method isBefore (line 133) | public isBefore(other: FishSymbol, urisMustMatch = true) {
    method isAfter (line 138) | public isAfter(other: FishSymbol, urisMustMatch = true) {
    method argparseFlagName (line 146) | public get argparseFlagName() {
    method argparseFlagFromName (line 153) | public static argparseFlagFromName(name: string) {
    method argparseFlag (line 160) | public get argparseFlag(): Flag | string {
    method isArgparseCompletionFlag (line 187) | private isArgparseCompletionFlag(node: SyntaxNode): boolean {
    method isCommandCompletionFlag (line 203) | private isCommandCompletionFlag(node: SyntaxNode) {
    method isExported (line 213) | isExported(): boolean {
    method isEqualLocation (line 235) | isEqualLocation(node: SyntaxNode) {
    method needsLocalReferences (line 281) | needsLocalReferences(): boolean {
    method skippableVariableName (line 310) | skippableVariableName(): boolean {
    method path (line 315) | get path() {
    method workspacePath (line 319) | get workspacePath() {
    method scopeTag (line 333) | get scopeTag() {
    method scopeNode (line 343) | get scopeNode() {
    method toString (line 348) | toString() {
    method toWorkspaceSymbol (line 352) | toWorkspaceSymbol(): WorkspaceSymbol {
    method toDocumentSymbol (line 356) | toDocumentSymbol(): DocumentSymbol | undefined {
    method toLocation (line 360) | toLocation(): Location {
    method toPosition (line 364) | toPosition(): Position {
    method toFoldingRange (line 368) | toFoldingRange(): FoldingRange {
    method toMarkupContent (line 372) | toMarkupContent(): MarkupContent {
    method toHover (line 380) | toHover(currentUri: DocumentUri = ''): Hover {
    method isLocal (line 385) | isLocal() {
    method isGlobal (line 389) | isGlobal() {
    method isAutoloaded (line 393) | isAutoloaded() {
    method isRootLevel (line 399) | isRootLevel() {
    method isEventHook (line 407) | isEventHook(): boolean {
    method isEmittedEvent (line 411) | isEmittedEvent(): boolean {
    method isEvent (line 415) | isEvent(): boolean {
    method isFunction (line 419) | isFunction(): boolean {
    method isVariable (line 423) | isVariable(): boolean {
    method isArgparse (line 427) | isArgparse(): boolean {
    method isSymbolImmutable (line 431) | isSymbolImmutable() {
    method isConfigDefinition (line 446) | isConfigDefinition() {
    method isConfigDefinitionWithErase (line 456) | isConfigDefinitionWithErase() {
    method findValueNodes (line 468) | findValueNodes(): SyntaxNode[] {
    method valuesAsShellValues (line 482) | valuesAsShellValues() {
    method equalArgparse (line 492) | equalArgparse(other: FishSymbol | CompletionSymbol) {
    method hasEventHook (line 520) | hasEventHook() {
    method equalsEvent (line 549) | equalsEvent(other: FishSymbol | CompletionSymbol): boolean {
    method isReference (line 578) | isReference(document: LspDocument, node: SyntaxNode, excludeEqualNode ...
    method equals (line 585) | equals(other: FishSymbol): boolean {
    method equalsLocation (line 592) | equalsLocation(location: Location): boolean {
    method equalDefinition (line 599) | equalDefinition(other: FishSymbol): boolean {
    method equalsNode (line 610) | equalsNode(node: SyntaxNode, opts: { strict?: boolean; } = { strict: f...
    method containsScope (line 619) | containsScope(other: FishSymbol): boolean {
    method equalScopes (line 626) | equalScopes(other: FishSymbol): boolean {
    method scopeContainsNode (line 633) | scopeContainsNode(node: SyntaxNode): boolean {
    method containsNode (line 640) | containsNode(node: SyntaxNode): boolean {
    method containsPosition (line 649) | containsPosition(position: { line: number; character: number; }): bool...
  type ModifierScopeTag (line 654) | type ModifierScopeTag = 'universal' | 'global' | 'function' | 'local' | ...
  function filterLastPerScopeSymbol (line 678) | function filterLastPerScopeSymbol(symbols: FishSymbol[]) {
  function filterFirstPerScopeSymbol (line 693) | function filterFirstPerScopeSymbol(document: LspDocument | DocumentUri):...
  function filterFirstUniqueSymbolperScope (line 708) | function filterFirstUniqueSymbolperScope(document: LspDocument | Documen...
  function findLocalLocations (line 725) | function findLocalLocations(symbol: FishSymbol, allSymbols: FishSymbol[]...
  function formatFishSymbolTree (line 754) | function formatFishSymbolTree(symbols: FishSymbol[], indentLevel: number...
  function buildNested (line 772) | function buildNested(document: LspDocument, node: SyntaxNode, ...childre...
  type NestedFishSymbolTree (line 817) | type NestedFishSymbolTree = FishSymbol[];
  type FlatFishSymbolTree (line 818) | type FlatFishSymbolTree = FishSymbol[];
  function processNestedTree (line 820) | function processNestedTree(document: LspDocument, ...nodes: SyntaxNode[]...

FILE: src/parsing/unreachable.ts
  function isTerminalStatement (line 7) | function isTerminalStatement(node: SyntaxNode): boolean {
  function conditionalExecutionTerminates (line 26) | function conditionalExecutionTerminates(conditionalNode: SyntaxNode): bo...
  function getConditionalType (line 41) | function getConditionalType(node: SyntaxNode): 'and' | 'or' | null {
  function sequenceFormsTerminatingAndOrChain (line 70) | function sequenceFormsTerminatingAndOrChain(nodes: SyntaxNode[], startIn...
  function caseContainsTerminalStatement (line 108) | function caseContainsTerminalStatement(caseNode: SyntaxNode): boolean {
  function sequenceTerminatesAllPaths (line 129) | function sequenceTerminatesAllPaths(nodes: SyntaxNode[]): boolean {
  function allPathsTerminate (line 157) | function allPathsTerminate(ifNode: SyntaxNode): boolean {
  function allSwitchPathsTerminate (line 199) | function allSwitchPathsTerminate(switchNode: SyntaxNode): boolean {
  function getUnreachableStatementsInSequence (line 224) | function getUnreachableStatementsInSequence(nodes: SyntaxNode[]): Syntax...
  function findUnreachableInFunction (line 273) | function findUnreachableInFunction(functionNode: SyntaxNode): SyntaxNode...
  function findUnreachableInBlock (line 310) | function findUnreachableInBlock(blockNode: SyntaxNode): SyntaxNode[] {
  function findUnreachableRecursive (line 369) | function findUnreachableRecursive(node: SyntaxNode, unreachable: SyntaxN...
  function findUnreachableCode (line 392) | function findUnreachableCode(root: SyntaxNode): SyntaxNode[] {

FILE: src/parsing/values.ts
  function isConfigVariableDefinition (line 24) | function isConfigVariableDefinition(symbol: FishSymbol): boolean {
  function isConfigVariableDefinitionWithErase (line 31) | function isConfigVariableDefinitionWithErase(
  function findValueNodes (line 40) | function findValueNodes(symbol: FishSymbol) {
  function nodeToShellValue (line 51) | function nodeToShellValue(node: SyntaxNode): string {
  function hasEraseFlag (line 57) | function hasEraseFlag(symbol: FishSymbol): boolean {
  function isEmptyString (line 69) | function isEmptyString(node: SyntaxNode) {
  function configDefinitionParser (line 73) | function configDefinitionParser(

FILE: src/references.ts
  type ReferenceOptions (line 29) | type ReferenceOptions = {
  function getReferences (line 56) | function getReferences(
  function allUnusedLocalReferences (line 201) | function allUnusedLocalReferences(document: LspDocument): FishSymbol[] {
  function getImplementation (line 284) | function getImplementation(
  function getLocationWrapper (line 343) | function getLocationWrapper(symbol: FishSymbol, node: SyntaxNode, uri: D...
  function getLeadingDashCount (line 392) | function getLeadingDashCount(node: SyntaxNode): number {
  function isAliasValueNode (line 416) | function isAliasValueNode(definitionSymbol: FishSymbol, node: SyntaxNode...
  function isBindCall (line 426) | function isBindCall(definitionSymbol: FishSymbol, node: SyntaxNode): boo...
  function isCompleteConditionCall (line 436) | function isCompleteConditionCall(definitionSymbol: FishSymbol, node: Syn...
  function isWrappedCall (line 445) | function isWrappedCall(definitionSymbol: FishSymbol, node: SyntaxNode): ...
  function isAnyNestedCommand (line 461) | function isAnyNestedCommand(definitionSymbol: FishSymbol, node: SyntaxNo...
  function isSymbolLocalToDocument (line 477) | function isSymbolLocalToDocument(symbol: FishSymbol): boolean {
  function extractCommandRangeFromAliasValue (line 504) | function extractCommandRangeFromAliasValue(node: SyntaxNode, commandName...
  function findCommandPositions (line 547) | function findCommandPositions(shellCode: string, commandName: string): A...
  function getDocumentsToSearch (line 657) | function getDocumentsToSearch(
  function logWrapper (line 704) | function logWrapper(

FILE: src/renames.ts
  type FishRenameLocationType (line 8) | type FishRenameLocationType = 'variable' | 'function' | 'command' | 'arg...
  type FishRenameLocation (line 10) | interface FishRenameLocation {
  function getRenames (line 17) | function getRenames(
  function fixNewText (line 68) | function fixNewText(symbol: FishSymbol, position: Position, newText: str...
  function canRenameWithNewText (line 84) | function canRenameWithNewText(analyzer: Analyzer, doc: LspDocument, posi...

FILE: src/selection-range.ts
  function findSmallestNode (line 19) | function findSmallestNode(node: SyntaxNode, position: Position): SyntaxN...
  function shouldIncludeInHierarchy (line 43) | function shouldIncludeInHierarchy(node: SyntaxNode): boolean {
  function buildSelectionHierarchy (line 52) | function buildSelectionHierarchy(node: SyntaxNode): SelectionRange {
  function getSelectionRanges (line 86) | function getSelectionRanges(

FILE: src/semantic-tokens.ts
  function modifiersToBitmask (line 42) | function modifiersToBitmask(modifiers: SemanticTokenModifier[]): number {
  function symbolToSemanticToken (line 49) | function symbolToSemanticToken(symbol: FishSymbol): SemanticToken | null {
  constant STRUCTURAL_KEYWORDS (line 92) | const STRUCTURAL_KEYWORDS = [
  type isNodeMatch (line 153) | type isNodeMatch = (node: SyntaxNode) => boolean;
  type nodeToTokenFunc (line 154) | type nodeToTokenFunc = (node: SyntaxNode, ctx: SemanticTokenContext) => ...
  type NodeToToken (line 155) | type NodeToToken = [isNodeMatch, nodeToTokenFunc];
  function getSemanticTokensSimplest (line 304) | function getSemanticTokensSimplest(analyzedDoc: EnsuredAnalyzeDocument, ...
  class SemanticTokenContext (line 352) | class SemanticTokenContext {
    method constructor (line 353) | private constructor(
    method create (line 359) | public static create({ document, tokens = [] }: {
    method has (line 366) | public has(token: SemanticToken): boolean {
    method hasNode (line 369) | public hasNode(node: SyntaxNode): boolean {
    method add (line 374) | public add(...tokens: SemanticToken[]): void {
    method size (line 383) | public get size(): number {
    method getTokens (line 387) | public getTokens(): SemanticToken[] {
    method clear (line 391) | public clear(): void {
    method show (line 397) | public show(): void {
    method build (line 406) | public build() {
  type SemanticTokensParams (line 447) | type SemanticTokensParams = LSP.SemanticTokensParams | LSP.SemanticToken...
  method isFull (line 453) | isFull(params: SemanticTokensParams): params is LSP.SemanticTokensParams {
  method isRange (line 459) | isRange(params: SemanticTokensParams): params is LSP.SemanticTokensRange...
  function semanticTokenHandler (line 471) | function semanticTokenHandler(params: SemanticTokensParams): LSP.Semanti...

FILE: src/server.ts
  type SupportedFeatures (line 48) | type SupportedFeatures = {
  class FishServer (line 73) | class FishServer {
    method create (line 108) | public static async create(
    method constructor (line 165) | constructor(
    method register (line 191) | register(connection: Connection): void {
    method didSaveTextDocument (line 290) | async didSaveTextDocument(params: LSP.DidSaveTextDocumentParams): Prom...
    method onShutdown (line 306) | async onShutdown() {
    method onInitialized (line 323) | async onInitialized(params: any): Promise<{
    method handleWorkspaceFolderChanges (line 403) | private async handleWorkspaceFolderChanges(event: WorkspaceFoldersChan...
    method onCommand (line 413) | onCommand(params: LSP.ExecuteCommandParams): Promise<any> {
    method onCompletion (line 430) | async onCompletion(params: CompletionParams): Promise<CompletionList> {
    method onCompletionResolve (line 487) | async onCompletionResolve(item: CompletionItem): Promise<CompletionIte...
    method onDocumentSymbols (line 514) | onDocumentSymbols(params: DocumentSymbolParams): DocumentSymbol[] {
    method supportHierarchicalDocumentSymbol (line 539) | public get supportHierarchicalDocumentSymbol(): boolean {
    method onWorkspaceSymbol (line 548) | async onWorkspaceSymbol(params: WorkspaceSymbolParams): Promise<Worksp...
    method onWorkspaceSymbolResolve (line 571) | async onWorkspaceSymbolResolve(symbol: WorkspaceSymbol): Promise<Works...
    method onDefinition (line 588) | async onDefinition(params: DefinitionParams): Promise<Location[]> {
    method onReferences (line 605) | async onReferences(params: ReferenceParams): Promise<Location[]> {
    method onImplementation (line 641) | async onImplementation(params: ImplementationParams): Promise<Location...
    method onHover (line 656) | async onHover(params: HoverParams): Promise<Hover | null> {
    method onRename (line 812) | async onRename(params: RenameParams): Promise<WorkspaceEdit | null> {
    method onDocumentFormatting (line 834) | async onDocumentFormatting(params: DocumentFormattingParams): Promise<...
    method onDocumentTypeFormatting (line 856) | async onDocumentTypeFormatting(params: DocumentFormattingParams): Prom...
    method onDocumentRangeFormatting (line 881) | async onDocumentRangeFormatting(params: DocumentRangeFormattingParams)...
    method onFoldingRanges (line 928) | async onFoldingRanges(params: FoldingRangeParams): Promise<FoldingRang...
    method onSelectionRanges (line 955) | async onSelectionRanges(params: SelectionRangeParams): Promise<Selecti...
    method onInlayHints (line 966) | async onInlayHints(params: InlayHintParams) {
    method onCodeLens (line 976) | async onCodeLens(params: CodeLensParams): Promise<CodeLens[]> {
    method onShowSignatureHelp (line 987) | public onShowSignatureHelp(params: SignatureHelpParams): SignatureHelp...
    method analyzeDocument (line 1046) | public analyzeDocument(document: LspDocument) {
    method info (line 1073) | public get info() {
    method completions (line 1080) | public get completions(): CompletionItemMap {
    method instance (line 1084) | public static get instance(): FishServer {
    method throwError (line 1089) | public static throwError(message: string) {
    method logParams (line 1103) | private logParams(methodName: string, ...params: any[]) {
    method getDefaults (line 1109) | private getDefaults(params: TextDocumentPositionParams): {
    method getDefaultsForPartialParams (line 1128) | private getDefaultsForPartialParams(params: {
    method logDocument (line 1141) | private logDocument(request: string, document: LspDocument | undefined...
    method setupForTestUtilities (line 1183) | static async setupForTestUtilities() {

FILE: src/signature.ts
  function buildSignature (line 21) | function buildSignature(label: string, value: string): SignatureInformat...
  function getCurrentNodeType (line 31) | function getCurrentNodeType(input: string) {
  function lineSignatureBuilder (line 45) | function lineSignatureBuilder(lineRootNode: SyntaxNode, lineCurrentNode:...
  function getPipes (line 72) | function getPipes(rootNode: SyntaxNode): ExtendedBaseJson[] {
  function getVariableNode (line 81) | function getVariableNode(rootNode: SyntaxNode): SyntaxNode | undefined {
  function getAllCommands (line 85) | function getAllCommands(rootNode: SyntaxNode): SyntaxNode[] {
  function getRegexOption (line 89) | function getRegexOption(rootNode: SyntaxNode): SyntaxNode | undefined {
  function isStringWithRegex (line 93) | function isStringWithRegex(line: string, regexOption: SyntaxNode | undef...
  function isSetOrReadWithVarNode (line 97) | function isSetOrReadWithVarNode(line: string, varNode: SyntaxNode | unde...
  function getSignatureForVariable (line 101) | function getSignatureForVariable(varNode: SyntaxNode): SignatureHelp | n...
  function getReturnStatusSignature (line 111) | function getReturnStatusSignature(): SignatureHelp {
  function getPipesSignature (line 120) | function getPipesSignature(pipes: ExtendedBaseJson[]): SignatureHelp {
  function getCommandSignature (line 128) | function getCommandSignature(firstCmd: SyntaxNode): SignatureHelp {
  function getAliasedCompletionItemSignature (line 137) | function getAliasedCompletionItemSignature(item: FishAliasCompletionItem...
  function regexStringSignature (line 150) | function regexStringSignature(): SignatureInformation {
  function regexStringCharacterSets (line 165) | function regexStringCharacterSets(): SignatureInformation {
  function isMatchingOption (line 194) | function isMatchingOption(
  function getActiveParameterIndex (line 226) | function getActiveParameterIndex(line: string, commandName: string, need...
  function isRegexStringSignature (line 279) | function isRegexStringSignature(line: string): boolean {
  function findActiveParameterStringRegex (line 295) | function findActiveParameterStringRegex(
  type signatureType (line 315) | type signatureType = 'stringRegexPatterns' | 'stringRegexCharacterSets';
  function getDefaultSignatures (line 322) | function getDefaultSignatures(): SignatureHelp {
  function getFunctionSignatureHelp (line 342) | function getFunctionSignatureHelp(
  function calculateActiveParameter (line 440) | function calculateActiveParameter(line: string, position: Position): num...

FILE: src/utils/builtins.ts
  function isBuiltin (line 80) | function isBuiltin(word: string): boolean {
  function isReservedKeyword (line 121) | function isReservedKeyword(word: string): boolean {
  function findShell (line 128) | function findShell() {
  function execFishCommand (line 144) | function execFishCommand(command: string): string[] {
  function createFunctionNamesList (line 149) | function createFunctionNamesList() {
  function isFunction (line 153) | function isFunction(word: string): boolean {
  function createFunctionEventsList (line 156) | function createFunctionEventsList() {
  function isEvent (line 164) | function isEvent(word: string): boolean {
  function createAbbrList (line 168) | function createAbbrList() {
  function createGlobalVariableList (line 173) | function createGlobalVariableList() {

FILE: src/utils/cli-dump-tree.ts
  function isDumpFlagStdin (line 19) | function isDumpFlagStdin(value: string | boolean | undefined): boolean {
  type ParseTreeOutput (line 28) | interface ParseTreeOutput {
  type SemanticTokensOutput (line 33) | interface SemanticTokensOutput {
  function readFromStdin (line 43) | async function readFromStdin(): Promise<string> {
  function debugWorkspaceDocument (line 63) | function debugWorkspaceDocument(document: LspDocument, useColors: boolea...
  function getNodeTypeColor (line 144) | function getNodeTypeColor(nodeType: string): (text: string) => string {
  function getParenthesesColor (line 151) | function getParenthesesColor(depth: number): (text: string) => string {
  function formatSyntaxTree (line 159) | function formatSyntaxTree(node: any, depth: number = 0, useColors: boole...
  function escapeWhitespace (line 206) | function escapeWhitespace(text: string): string {
  function logTreeSitterDocumentDebug (line 217) | function logTreeSitterDocumentDebug(document: LspDocument): void {
  function returnParseTreeString (line 239) | function returnParseTreeString(document: LspDocument, useColors: boolean...
  function expandParseCliTreeFile (line 244) | function expandParseCliTreeFile(input: string | undefined): string {
  function cliDumpParseTree (line 256) | async function cliDumpParseTree(document: LspDocument, useColors: boolea...
  function handleCLiDumpParseTree (line 271) | async function handleCLiDumpParseTree(args: CommanderSubcommand.info.sch...
  function getTokenTypeColor (line 324) | function getTokenTypeColor(tokenType: string, useColors: boolean): (text...
  function decodeModifiers (line 332) | function decodeModifiers(modifiersMask: number): string[] {
  function formatSemanticTokens (line 349) | function formatSemanticTokens(data: number[], source: string, useColors:...
  function debugSemanticTokens (line 419) | function debugSemanticTokens(document: LspDocument, useColors: boolean =...
  function cliDumpSemanticTokens (line 439) | async function cliDumpSemanticTokens(document: LspDocument, useColors: b...
  function formatSymbolLine (line 523) | function formatSymbolLine(symbol: FishSymbol, useIcons: boolean): string {
  function formatColoredSymbolNodes (line 538) | function formatColoredSymbolNodes(symbols: FishSymbol[], prefix: string,...
  function formatColoredSymbolTree (line 560) | function formatColoredSymbolTree(symbols: FishSymbol[], rootLabel: strin...
  function cliDumpSymbolTree (line 567) | async function cliDumpSymbolTree(document: LspDocument, useColors: boole...
  function handleCLiDumpSymbolTree (line 603) | async function handleCLiDumpSymbolTree(args: CommanderSubcommand.info.sc...
  function handleCLiDumpSemanticTokens (line 639) | async function handleCLiDumpSemanticTokens(args: CommanderSubcommand.inf...

FILE: src/utils/commander-cli-subcommands.ts
  function accumulateStartupOptions (line 23) | function accumulateStartupOptions(args: string[]): {
  type ArgsType (line 65) | type ArgsType = {
  type HandlerOptionsType (line 80) | type HandlerOptionsType = {
  function getOutputType (line 108) | function getOutputType(args: ArgsType): 'show' | 'create' | 'showDefault' {
  function getOnly (line 112) | function getOnly(args: ArgsType): string[] | undefined {
  function toEnvOutputOptions (line 123) | function toEnvOutputOptions(args: ArgsType): HandlerOptionsType {
  function getEnvOnlyArgs (line 137) | function getEnvOnlyArgs(cliEnvOnly: string | string[] | undefined): stri...
  function filterStartCommandArgs (line 157) | function filterStartCommandArgs(args: string[]): string[] {
  type VersionTuple (line 203) | type VersionTuple = {
  function minimumNodeVersion (line 215) | function minimumNodeVersion(): VersionTuple {
  function extract (line 224) | function extract(versionString: string): VersionTuple | null {
  function compareVersions (line 240) | function compareVersions(a: VersionTuple, b: VersionTuple): number {
  function satisfies (line 252) | function satisfies(current: VersionTuple, required: VersionTuple): boole...
  type BuildTimeJsonObj (line 292) | type BuildTimeJsonObj = {
  function FishLspHelp (line 470) | function FishLspHelp() {
  function FishLspManPage (line 509) | function FishLspManPage() {
  function fishLspLogFile (line 552) | function fishLspLogFile() {
  type schemaType (line 586) | type schemaType = z.infer<typeof schema>;
  function parse (line 587) | function parse(args: unknown): schemaType {
  type schemaType (line 627) | type schemaType = z.infer<typeof schema>;
  function parse (line 628) | function parse(args: unknown): schemaType {
  type skippableType (line 643) | type skippableType = z.infer<typeof skippable>;
  type skippableArgs (line 644) | type skippableArgs = keyof skippableType;
  function handleBadArgs (line 662) | function handleBadArgs(args: schemaType) {
  function handleFileArgs (line 686) | function handleFileArgs(args: schemaType) {
  function handleSourceMaps (line 725) | function handleSourceMaps(args: schemaType) {
  function sourcemaps (line 813) | function sourcemaps() {
  function log (line 827) | function log(argsCount: number, title: string, message: string, alwaysSh...
  type schemaType (line 852) | type schemaType = z.infer<typeof schema>;
  function parse (line 853) | function parse(args: unknown): schemaType {
  type schemaType (line 873) | type schemaType = z.infer<typeof schema>;
  function parse (line 874) | function parse(args: unknown): schemaType {
  type schemaType (line 897) | type schemaType = z.infer<typeof schema>;
  function parse (line 898) | function parse(args: unknown): schemaType {
  type SubcommandType (line 912) | type SubcommandType = (typeof subcommands)[number];
  type schemas (line 914) | type schemas = typeof start.schema
  function parseSubcommand (line 928) | function parseSubcommand(command: SubcommandType, args: unknown): z.infe...
  function hasSkippable (line 950) | function hasSkippable(command: SubcommandType) {
  function getSubcommand (line 965) | function getSubcommand(command: SubcommandType): schemas {
  function countArgsWithValues (line 982) | function countArgsWithValues(subcommand: SubcommandType, args: Record<st...
  function removeArgs (line 1006) | function removeArgs(args: { [k: string]: unknown; }, ...keysToRemove: st...
  function entries (line 1021) | function entries(args: any) {
  function noArgs (line 1027) | function noArgs(args: any): boolean {
  function argsToString (line 1031) | function argsToString(args: { [k: string]: unknown; } | string[]): string {
  function buildErrorMessage (line 1038) | function buildErrorMessage(...stdin: string[]) {
  type CommandlineOpts (line 1052) | type CommandlineOpts = {
  function buildColoredCommandlineString (line 1067) | function buildColoredCommandlineString(opts: CommandlineOpts): string {
  function BuildCapabilityString (line 1103) | function BuildCapabilityString() {

FILE: src/utils/completion/comment-completions.ts
  function buildCommentCompletions (line 10) | function buildCommentCompletions(
  function getCommentDiagnostics (line 85) | function getCommentDiagnostics(line: string, lineNumber: number) {

FILE: src/utils/completion/documentation.ts
  function getDocumentationResolver (line 6) | async function getDocumentationResolver(item: FishCompletionItem): Promi...
  function getFunctionDocString (line 69) | async function getFunctionDocString(name: string): Promise<string | unde...
  function getStaticDocString (line 95) | async function getStaticDocString(item: FishCompletionItem): Promise<str...
  function buildArgumentDocString (line 113) | async function buildArgumentDocString(item: FishCompletionItem): Promise...
  function getAbbrDocString (line 124) | async function getAbbrDocString(name: string): Promise<string | undefine...
  function getBuiltinDocString (line 147) | async function getBuiltinDocString(name: string): Promise<string | undef...
  function getAliasDocString (line 163) | async function getAliasDocString(label: string, line: string): Promise<s...
  function getEventHandlerDocString (line 176) | async function getEventHandlerDocString(documentation: string): Promise<...
  function getVariableDocString (line 197) | async function getVariableDocString(name: string): Promise<string | unde...
  function getCommandDocString (line 219) | async function getCommandDocString(name: string): Promise<string | undef...
  function ensureMinLength (line 233) | function ensureMinLength<T>(arr: T[], minLength: number, fillValue?: T):...

FILE: src/utils/completion/inline-parser.ts
  class InlineParser (line 7) | class InlineParser {
    method create (line 10) | static async create() {
    method constructor (line 15) | constructor(private parser: Parser) {
    method parseWord (line 30) | parseWord(line: string): {
    method parseCommand (line 63) | parseCommand(line: string) : {
    method parse (line 85) | parse(line: string): SyntaxNode {
    method getNodeContext (line 90) | getNodeContext(line: string) {
    method lastItemIsOption (line 108) | lastItemIsOption(line: string): boolean {
    method getLastNode (line 122) | getLastNode(line: string): SyntaxNode | null {
    method hasOption (line 131) | hasOption(command: SyntaxNode, options: string[]) {
    method getIndex (line 135) | getIndex(line: string): number {
    method createCompletionList (line 148) | async createCompletionList(line: string): Promise<FishCompletionItem[]> {
  function wordPrecedesCommand (line 164) | function wordPrecedesCommand(word: string | null) {
  function isEmpty (line 186) | function isEmpty(line: string): boolean {
  function isComment (line 189) | function isComment(line: string): boolean {
  function hasMultipleLastSpaces (line 192) | function hasMultipleLastSpaces(line: string): boolean {
  function removeAllButLastSpace (line 195) | function removeAllButLastSpace(line: string): string {
  function appendEndSequence (line 201) | function appendEndSequence(

FILE: src/utils/completion/list.ts
  class FishCompletionListBuilder (line 6) | class FishCompletionListBuilder {
    method constructor (line 9) | constructor(
    method addItem (line 15) | addItem(item: FishCompletionItem) {
    method addItems (line 19) | addItems(items: FishCompletionItem[], priority?: number) {
    method addSymbols (line 26) | addSymbols(symbols: FishSymbol[], insertDollarSign: boolean = false) {
    method addData (line 39) | addData(data: FishCompletionData) {
    method reset (line 53) | reset() {
    method sortByPriority (line 57) | sortByPriority(items: FishCompletionItem[]): FishCompletionItem[] {
    method build (line 92) | build(isIncomplete: boolean = false): FishCompletionList {
    method log (line 100) | log() {
    method _logger (line 105) | get _logger() {
  function itemLoggingInfo (line 110) | function itemLoggingInfo(item: FishCompletionItem, index: number) {
  type FishCompletionList (line 122) | type FishCompletionList = CompletionList;
  function empty (line 125) | function empty() {
  function create (line 132) | function create(

FILE: src/utils/completion/pager.ts
  type SetupData (line 20) | type SetupData = {
  class CompletionPager (line 26) | class CompletionPager {
    method constructor (line 29) | constructor(
    method empty (line 37) | empty(): CompletionList {
    method create (line 44) | create(
    method completeEmpty (line 54) | async completeEmpty(
    method completeVariables (line 75) | async completeVariables(
    method isInVariableDefinitionContext (line 161) | private isInVariableDefinitionContext(lineBeforeCursor: string, positi...
    method complete (line 246) | async complete(
    method getData (line 334) | getData(uri: string, position: Position, line: string, word: string) {
    method getSubshellStdoutCompletions (line 343) | private async getSubshellStdoutCompletions(
  function initializeCompletionPager (line 360) | async function initializeCompletionPager(logger: Logger, items: Completi...
  function addFirstIndexedItems (line 365) | function addFirstIndexedItems(command: string, items: CompletionItemMap) {
  function addSpecialItems (line 383) | function addSpecialItems(
  function wordsFirstChar (line 423) | function wordsFirstChar(word: string | null) {
  function includesFlag (line 427) | function includesFlag(
  function sortSymbols (line 451) | function sortSymbols(symbols: FishSymbol[]) {
  function isInVariableExpansionContext (line 474) | function isInVariableExpansionContext(doc: LspDocument, position: Positi...

FILE: src/utils/completion/shell.ts
  function escapeCmd (line 3) | function escapeCmd(cmd: string): string {
  function shellComplete (line 12) | async function shellComplete(cmd: string): Promise<[string, string][]> {

FILE: src/utils/completion/startup-cache.ts
  type ItemMapRecord (line 6) | type ItemMapRecord = Record<FishCompletionItemKind, FishCompletionItem[]>;
  class CompletionItemMap (line 8) | class CompletionItemMap {
    method constructor (line 9) | constructor(private _items: ItemMapRecord = {} as ItemMapRecord) { }
    method initialize (line 11) | static async initialize(): Promise<CompletionItemMap> {
    method get (line 71) | get(kind: FishCompletionItemKind): FishCompletionItem[] {
    method allKinds (line 75) | get allKinds(): FishCompletionItemKind[] {
    method allOfKinds (line 79) | allOfKinds(...kinds: FishCompletionItemKind[]): FishCompletionItem[] {
    method entries (line 83) | entries(): [FishCompletionItemKind, FishCompletionItem[]][] {
    method forEach (line 87) | forEach(callbackfn: (key: FishCompletionItemKind, value: FishCompletio...
    method allCompletionsWithoutCommand (line 91) | allCompletionsWithoutCommand() {
    method findLabel (line 102) | findLabel(label: string, ...searchKinds: FishCompletionItemKind[]): Fi...
    method blockedCommands (line 113) | get blockedCommands() {
  function splitLine (line 123) | function splitLine(line: string): { label: string; value?: string; } {
  function getCommandsDetail (line 134) | function getCommandsDetail(value: string) {

FILE: src/utils/completion/startup-config.ts
  type SetupItem (line 4) | type SetupItem = {
  type SetupResult (line 63) | type SetupResult = SetupItem & { results: string[]; };
  function runSetupItems (line 65) | async function runSetupItems(

FILE: src/utils/completion/types.ts
  type FishCompletionItemKind (line 34) | type FishCompletionItemKind = typeof FishCompletionItemKind[keyof typeof...
  type FishCompletionData (line 59) | type FishCompletionData = {
  type FishCompletionItem (line 68) | interface FishCompletionItem extends CompletionItem {
    method constructor (line 84) | constructor(
    method setKinds (line 97) | setKinds(kind: FishCompletionItemKind) {
    method setLocal (line 103) | setLocal() {
    method setUseDocAsDetail (line 108) | setUseDocAsDetail() {
    method setData (line 113) | setData(data: FishCompletionData) {
    method setPriority (line 123) | setPriority(priority: number) {
  class FishCompletionItem (line 83) | class FishCompletionItem implements FishCompletionItem {
    method constructor (line 84) | constructor(
    method setKinds (line 97) | setKinds(kind: FishCompletionItemKind) {
    method setLocal (line 103) | setLocal() {
    method setUseDocAsDetail (line 108) | setUseDocAsDetail() {
    method setData (line 113) | setData(data: FishCompletionData) {
    method setPriority (line 123) | setPriority(priority: number) {
  class FishCommandCompletionItem (line 129) | class FishCommandCompletionItem extends FishCompletionItem {
  class FishAbbrCompletionItem (line 135) | class FishAbbrCompletionItem extends FishCommandCompletionItem {
    method constructor (line 136) | constructor(label: string, detail: string, documentation: string) {
  class FishAliasCompletionItem (line 144) | class FishAliasCompletionItem extends FishCommandCompletionItem {
    method constructor (line 145) | constructor(label: string, detail: string, documentation: string) {
  function create (line 152) | function create(label: string, kind: FishCompletionItemKind, detail: str...
  function fromSymbol (line 168) | function fromSymbol(symbol: FishSymbol) {
  function createData (line 179) | function createData(
  type CompletionExample (line 191) | interface CompletionExample {
  function create (line 197) | function create(title: string, ...shellText: string[]): CompletionExample {
  function toMarkedString (line 205) | function toMarkedString(example: CompletionExample): string {

FILE: src/utils/definition-scope.ts
  type ScopeTag (line 8) | type ScopeTag = 'global' | 'universal' | 'local' | 'function' | 'inherit';
  type DefinitionScope (line 9) | interface DefinitionScope {
    method constructor (line 16) | constructor(
    method create (line 20) | static create(
    method containsPosition (line 30) | containsPosition(position: Position) {
    method isBeforePosition (line 39) | isBeforePosition(position: Position) {
    method isAfterPosition (line 44) | isAfterPosition(position: Position) {
    method isBeforeNode (line 49) | isBeforeNode(node: SyntaxNode) {
    method isAfterNode (line 55) | isAfterNode(node: SyntaxNode) {
    method containsNode (line 61) | containsNode(node: SyntaxNode) {
    method tag (line 66) | get tag() {
    method ScopeTags (line 71) | static get ScopeTags() {
  class DefinitionScope (line 15) | class DefinitionScope {
    method constructor (line 16) | constructor(
    method create (line 20) | static create(
    method containsPosition (line 30) | containsPosition(position: Position) {
    method isBeforePosition (line 39) | isBeforePosition(position: Position) {
    method isAfterPosition (line 44) | isAfterPosition(position: Position) {
    method isBeforeNode (line 49) | isBeforeNode(node: SyntaxNode) {
    method isAfterNode (line 55) | isAfterNode(node: SyntaxNode) {
    method containsNode (line 61) | containsNode(node: SyntaxNode) {
    method tag (line 66) | get tag() {
    method ScopeTags (line 71) | static get ScopeTags() {
  class VariableDefinitionFlag (line 83) | class VariableDefinitionFlag {
    method constructor (line 87) | constructor(short: string, long: string) {
    method isMatch (line 92) | isMatch(node: SyntaxNode) {
    method kind (line 105) | get kind() {
  function getMatchingFlags (line 123) | function getMatchingFlags(focusedNode: SyntaxNode, nodes: SyntaxNode[]) {
  function findScopeFromFlag (line 135) | function findScopeFromFlag(node: SyntaxNode, flag: VariableDefinitionFla...
  function getVariableScope (line 177) | function getVariableScope(node: SyntaxNode) {
  function getScope (line 199) | function getScope(document: LspDocument, node: SyntaxNode) {
  function expandEntireVariableLine (line 243) | function expandEntireVariableLine(node: SyntaxNode): SyntaxNode[] {
  function setQuery (line 267) | function setQuery(searchNodes: SyntaxNode[]) {

FILE: src/utils/documentation-cache.ts
  type CachedGlobalItem (line 31) | interface CachedGlobalItem {
  function createCachedItem (line 40) | function createCachedItem(type: SymbolKind, uri?: string): CachedGlobalI...
  function getNewDocString (line 52) | async function getNewDocString(name: string, item: CachedGlobalItem): Pr...
  function resolveItem (line 65) | async function resolveItem(name: string, item: CachedGlobalItem, uri?: s...
  function getFunctionUri (line 87) | async function getFunctionUri(name: string): Promise<string | undefined> {
  function _escapePathStr (line 101) | function _escapePathStr(functionTitleLine: string): string {
  function _ensureMinLength (line 112) | function _ensureMinLength<T>(arr: T[], minLength: number, fillValue?: T)...
  function getFunctionDocString (line 122) | async function getFunctionDocString(name: string): Promise<string | unde...
  function getStaticDocString (line 135) | async function getStaticDocString(item: FishCompletionItem): Promise<str...
  function getAbbrDocString (line 153) | async function getAbbrDocString(name: string): Promise<string | undefine...
  function getBuiltinDocString (line 176) | async function getBuiltinDocString(name: string): Promise<string | undef...
  function getAliasDocString (line 197) | async function getAliasDocString(label: string, line: string): Promise<s...
  function getEventHandlerDocString (line 210) | async function getEventHandlerDocString(documentation: string): Promise<...
  function getVariableDocString (line 231) | async function getVariableDocString(name: string): Promise<string | unde...
  function getCommandDocString (line 253) | async function getCommandDocString(name: string): Promise<string | undef...
  function initializeMap (line 267) | function initializeMap(collection: string[], type: SymbolKind, _uri?: st...
  class DocumentationCache (line 285) | class DocumentationCache {
    method items (line 291) | get items(): string[] {
    method parse (line 300) | async parse(uri?: string) {
    method find (line 318) | find(name: string, type?: SymbolKind): CachedGlobalItem | undefined {
    method findType (line 331) | findType(name: string): SymbolKind {
    method resolve (line 349) | async resolve(name: string, uri?: string, type?: SymbolKind) {
    method setItem (line 376) | setItem(name: string, item: CachedGlobalItem) {
    method getItem (line 396) | getItem(name: string) {
  function initializeDocumentationCache (line 409) | async function initializeDocumentationCache() {

FILE: src/utils/env-manager.ts
  function allPossibleAutoloadedFunctionPaths (line 6) | function allPossibleAutoloadedFunctionPaths(functionName: string): strin...
  class FishVariableParser (line 40) | class FishVariableParser {
    method parse (line 44) | static parse(value: string): string[] {
    method parsePathVariable (line 60) | static parsePathVariable(value: string): string[] {
    method parseSpaceSeparatedWithQuotes (line 68) | static parseSpaceSeparatedWithQuotes(value: string): string[] {
    method getAtIndex (line 120) | static getAtIndex(array: string[], index: number): string | undefined {
    method tokenSeparator (line 126) | static tokenSeparator(value: string): ':' | ' ' {
  class EnvManager (line 134) | class EnvManager {
    method constructor (line 147) | private constructor() {
    method setAllKeys (line 154) | private setAllKeys(): void {
    method getInstance (line 161) | public static getInstance(): EnvManager {
    method has (line 168) | public has(key: string): boolean {
    method set (line 172) | public set(key: string, value: undefined | string): void {
    method get (line 177) | public get(key: string): string | undefined {
    method getAsArray (line 181) | public getAsArray(key: string): string[] {
    method getFirstValueInArray (line 186) | public getFirstValueInArray(key: string): string | undefined {
    method getAsTypedArray (line 190) | public getAsTypedArray(key: string): Config.ConfigValueType | undefined {
    method isArrayValue (line 208) | public static isArrayValue(value: string): boolean {
    method isArray (line 212) | public isArray(key: string): boolean {
    method isAutoloaded (line 216) | public isAutoloaded(key: string): boolean {
    method isProcessEnv (line 220) | public isProcessEnv(key: string): boolean {
    method append (line 224) | public append(key: string, value: string): void {
    method prepend (line 236) | public prepend(key: string, value: string) {
    method processEnv (line 248) | public get processEnv(): NodeJS.ProcessEnv {
    method autoloadedFishVariables (line 252) | public get autoloadedFishVariables(): Record<string, string[]> {
    method keys (line 260) | get keys(): string[] {
    method getAutoloadedKeys (line 264) | public getAutoloadedKeys(): string[] {
    method getProcessEnvKeys (line 268) | public getProcessEnvKeys(): string[] {
    method findAutolaodedKey (line 272) | public findAutolaodedKey(key: string): string | undefined {
    method values (line 279) | get values() {
    method entries (line 287) | get entries(): [string, string][] {
    method parser (line 294) | public parser() {
    method findAutoloadedFunctionPath (line 298) | public findAutoloadedFunctionPath(functionName: string): string[] {
    method clear (line 313) | public clear(): void {

FILE: src/utils/exec.ts
  type EmbeddedFishResult (line 18) | type EmbeddedFishResult = {
  function runEmbeddedFish (line 24) | function runEmbeddedFish(script: string, args: string[] = []): Promise<E...
  function getCommandOptions (line 60) | function getCommandOptions(...args: string[]): Promise<EmbeddedFishResul...
  function getDocs (line 64) | function getDocs(...args: string[]): Promise<EmbeddedFishResult> {
  function getType (line 68) | function getType(...args: string[]): Promise<EmbeddedFishResult> {
  function getTypeVerbose (line 72) | function getTypeVerbose(...args: string[]): Promise<EmbeddedFishResult> {
  function getCartisianExpansion (line 76) | function getCartisianExpansion(...args: string[]): Promise<EmbeddedFishR...
  function getAutoloadedFilepath (line 80) | function getAutoloadedFilepath(...args: string[]): Promise<EmbeddedFishR...
  function getFishAutoloadedPaths (line 84) | function getFishAutoloadedPaths(...args: string[]): Promise<EmbeddedFish...
  function getDependency (line 88) | function getDependency(...args: string[]): Promise<EmbeddedFishResult> {
  function getDocumentation (line 92) | function getDocumentation(...args: string[]): Promise<EmbeddedFishResult> {
  function execFish (line 96) | function execFish(cmd: string): Promise<EmbeddedFishResult> {
  function getCompletion (line 100) | function getCompletion(...args: string[]): Promise<EmbeddedFishResult> {
  function execEscapedCommand (line 117) | async function execEscapedCommand(cmd: string): Promise<string[]> {
  function execCmd (line 126) | async function execCmd(cmd: string, options?: {
  function execAsyncF (line 147) | async function execAsyncF(cmd: string) {
  function execAsyncFish (line 161) | async function execAsyncFish(cmd: string) {
  function execFishNoExecute (line 165) | function execFishNoExecute(filepath: string) {
  function execCompletions (line 180) | async function execCompletions(...cmd: string[]): Promise<string[]> {
  function execSubCommandCompletions (line 187) | async function execSubCommandCompletions(...cmd: string[]): Promise<stri...
  function execCompleteLine (line 193) | async function execCompleteLine(cmd: string): Promise<string[]> {
  function execCompleteSpace (line 206) | async function execCompleteSpace(cmd: string): Promise<string[]> {
  function execCompleteCmdArgs (line 219) | async function execCompleteCmdArgs(cmd: string): Promise<string[]> {
  function execCommandDocs (line 240) | async function execCommandDocs(cmd: string): Promise<string> {
  function execCommandType (line 255) | async function execCommandType(cmd: string): Promise<string> {
  type CompletionArguments (line 263) | interface CompletionArguments {
  function documentCommandDescription (line 268) | async function documentCommandDescription(cmd: string): Promise<string> {
  function execFindDependency (line 273) | async function execFindDependency(cmd: string): Promise<string> {
  function execExpandBraceExpansion (line 278) | async function execExpandBraceExpansion(input: string): Promise<string> {
  function execCommandLocations (line 283) | function execCommandLocations(cmd: string): { uri: string; path: string;...

FILE: src/utils/file-operations.ts
  class SyncFileHelper (line 13) | class SyncFileHelper {
    method open (line 14) | static open(filePath: PathLike, flags: string): number {
    method close (line 19) | static close(fd: number): void {
    method read (line 23) | static read(filePath: PathLike, encoding: BufferEncoding = 'utf8'): st...
    method loadDocumentSync (line 36) | static loadDocumentSync(filePath: PathLike): LspDocument | undefined {
    method write (line 65) | static write(filePath: PathLike, data: string, encoding: BufferEncodin...
    method writeRecursive (line 71) | static writeRecursive(filePath: PathLike, data: string, encoding: Buff...
    method append (line 83) | static append(filePath: PathLike, data: string, encoding: BufferEncodi...
    method expandEnvVars (line 88) | static expandEnvVars(filePath: PathLike): string {
    method expandNormalize (line 107) | static expandNormalize(filePath: PathLike): string {
    method isExpandable (line 112) | static isExpandable(filePath: PathLike): boolean {
    method exists (line 117) | static exists(filePath: PathLike): boolean {
    method delete (line 122) | static delete(filePath: PathLike): void {
    method create (line 126) | static create(filePath: PathLike) {
    method getPathTokens (line 136) | static getPathTokens(filePath: PathLike) {
    method convertTextToFishFunction (line 148) | static convertTextToFishFunction(filePath: PathLike, data: string, _en...
    method toTextDocumentItem (line 166) | static toTextDocumentItem(filePath: PathLike, languageId: string, vers...
    method toLspDocument (line 173) | static toLspDocument(filePath: PathLike, languageId: string = 'fish', ...
    method isDirectory (line 184) | static isDirectory(filePath: PathLike): boolean {
    method isFile (line 194) | static isFile(filePath: PathLike): boolean {
    method isWriteableDirectory (line 209) | static isWriteableDirectory(workspacePath: string): boolean {
    method isWriteableFile (line 217) | static isWriteableFile(filePath: string): boolean {
    method isWriteable (line 225) | static isWriteable(filePath: string): boolean {
    method isWriteablePath (line 230) | private static isWriteablePath(path: string): boolean {
    method isAbsolutePath (line 239) | static isAbsolutePath(filePath: string): boolean {
    method isRelativePath (line 244) | static isRelativePath(filePath: string): boolean {
  function isReadable (line 251) | async function isReadable(filePath: string): Promise<boolean> {
  function isDir (line 261) | async function isDir(filePath: string): Promise<boolean> {
  function isFile (line 271) | async function isFile(filePath: string): Promise<boolean> {
  function readFile (line 281) | async function readFile(filePath: string, encoding: BufferEncoding = 'ut...

FILE: src/utils/flag-documentation.ts
  function getFlagDocumentationStrings (line 106) | async function getFlagDocumentationStrings(input: string) : Promise<stri...
  function getFlagCommand (line 118) | function getFlagCommand(input: string) : string {
  function getFlagDocumentationAsMarkup (line 128) | async function getFlagDocumentationAsMarkup(input: string) : Promise<Mar...
  function getFlagDocumentationString (line 136) | async function getFlagDocumentationString(input: string): Promise<string> {

FILE: src/utils/flatten.ts
  function flattenNested (line 26) | function flattenNested<T extends { children?: T[]; }>(...roots: T[]): T[] {

FILE: src/utils/get-lsp-completions.ts
  function getAutoGeneratedHeader (line 6) | function getAutoGeneratedHeader(): string {
  function getHelperFunctions (line 53) | function getHelperFunctions(): string {
  function getAutoGeneratedFooter (line 475) | function getAutoGeneratedFooter(): string {
  function buildFishLspCompletions (line 496) | function buildFishLspCompletions(commandBin: Command) {
  function buildFishLspAbbreviations (line 532) | function buildFishLspAbbreviations() {

FILE: src/utils/health-check.ts
  function performHealthCheck (line 11) | async function performHealthCheck() {
  function logFishLspConfig (line 197) | async function logFishLspConfig() {
  function isNodeVersionGreaterThanMinimumRequiredVersion (line 239) | function isNodeVersionGreaterThanMinimumRequiredVersion() {

FILE: src/utils/locations.ts
  type Location (line 7) | interface Location {
  type TextSpan (line 12) | type TextSpan = {
  function intersection (line 34) | function intersection(one: LSP.Range, other: LSP.Range): LSP.Range | und...
  function isAfter (line 46) | function isAfter(one: LSP.Range, other: LSP.Range): boolean {
  function Min (line 72) | function Min(...positions: LSP.Position[]): LSP.Position | undefined {
  function isBefore (line 84) | function isBefore(one: LSP.Position, other: LSP.Position): boolean {
  function Max (line 95) | function Max(...positions: LSP.Position[]): LSP.Position | undefined {
  function isAfter (line 107) | function isAfter(one: LSP.Position, other: LSP.Position): boolean {
  function isBeforeOrEqual (line 110) | function isBeforeOrEqual(one: LSP.Position, other: LSP.Position): boolean {
  function fromSyntaxNode (line 120) | function fromSyntaxNode(node: TS.SyntaxNode): { start: LSP.Position; end...
  function equals (line 134) | function equals(one: LSP.Location, other: LSP.Location): boolean {

FILE: src/utils/markdown-builder.ts
  function h (line 9) | function h(text: string, value: number = 1) {
  function italic (line 13) | function italic(value: string) {
  function bold (line 17) | function bold(value: string) {
  function boldItalic (line 21) | function boldItalic(value: string) {
  function separator (line 25) | function separator() {
  function space (line 29) | function space() {
  function newline (line 33) | function newline() {
  function blockQuote (line 40) | function blockQuote(value: string) {
  function inlineCode (line 44) | function inlineCode(value: string) {
  function codeBlock (line 48) | function codeBlock(language: string, value: string): string {
  function li (line 56) | function li(value: string) {
  function ol (line 60) | function ol(value: string) {
  function link (line 64) | function link(name: string, href: string) {
  function filepathString (line 68) | function filepathString(value: string) {
  function p (line 72) | function p(...strs: string[]) {
  type MarkdownStringTextNewlineStyle (line 79) | const enum MarkdownStringTextNewlineStyle {
  class MarkdownBuilder (line 84) | class MarkdownBuilder {
    method constructor (line 85) | constructor(public value = '') { }
    method appendText (line 87) | appendText(value: string, newlineStyle: MarkdownStringTextNewlineStyle...
    method appendNewline (line 96) | appendNewline(): MarkdownBuilder {
    method fromMarkdown (line 106) | fromMarkdown(...values: (string | string[])[]): MarkdownBuilder {
    method appendMarkdown (line 113) | appendMarkdown(value: string): MarkdownBuilder {
    method appendCodeblock (line 118) | appendCodeblock(langId: string, code: string): MarkdownBuilder {
    method toMarkupContent (line 127) | toMarkupContent(): MarkupContent {
    method toString (line 134) | toString() {
  function escapeMarkdownSyntaxTokens (line 139) | function escapeMarkdownSyntaxTokens(text: string): string {

FILE: src/utils/maybe.ts
  class Maybe (line 21) | class Maybe<T> {
    method constructor (line 22) | constructor(private value: T | null | undefined) {}
    method of (line 27) | static of<T>(value: T | null | undefined): Maybe<T> {
    method none (line 34) | static none<T>(): Maybe<T> {
    method map (line 41) | map<U>(fn: (value: T) => U | null | undefined): Maybe<U> {
    method flatMap (line 48) | flatMap<U>(fn: (value: T) => Maybe<U>): Maybe<U> {
    method filter (line 55) | filter(predicate: (value: T) => boolean): Maybe<T> {
    method getOrElse (line 64) | getOrElse<U>(defaultValue: T | U): T | U {
    method exists (line 71) | exists(): boolean {
    method equals (line 78) | equals(other: T): boolean {
    method ifPresent (line 89) | ifPresent(action: (value: T) => void): Maybe<T> {
    method get (line 99) | get(): T | null | undefined {

FILE: src/utils/node-types.ts
  function isVariableDefinition (line 28) | function isVariableDefinition(node: SyntaxNode): boolean {
  function isComment (line 35) | function isComment(node: SyntaxNode): boolean {
  function isShebang (line 39) | function isShebang(node: SyntaxNode) {
  function isFunctionDefinition (line 67) | function isFunctionDefinition(node: SyntaxNode): boolean {
  function isCommand (line 75) | function isCommand(node: SyntaxNode): boolean {
  function isFishShippedFunctionName (line 83) | function isFishShippedFunctionName(node: SyntaxNode): boolean {
  function isTopLevelFunctionDefinition (line 116) | function isTopLevelFunctionDefinition(node: SyntaxNode): boolean {
  function isTopLevelDefinition (line 126) | function isTopLevelDefinition(node: SyntaxNode): boolean {
  function isDefinition (line 144) | function isDefinition(node: SyntaxNode): boolean {
  function isCommandName (line 151) | function isCommandName(node: SyntaxNode): boolean {
  function isProgram (line 166) | function isProgram(node: SyntaxNode): boolean {
  function isError (line 170) | function isError(node: SyntaxNode | null = null): boolean {
  function isForLoop (line 177) | function isForLoop(node: SyntaxNode): boolean {
  function isIfStatement (line 181) | function isIfStatement(node: SyntaxNode): boolean {
  function isElseStatement (line 185) | function isElseStatement(node: SyntaxNode): boolean {
  function isConditional (line 190) | function isConditional(node: SyntaxNode): boolean {
  function isIfOrElseIfConditional (line 194) | function isIfOrElseIfConditional(node: SyntaxNode): boolean {
  function isPossibleUnreachableStatement (line 198) | function isPossibleUnreachableStatement(node: SyntaxNode): boolean {
  function isClause (line 209) | function isClause(node: SyntaxNode): boolean {
  function isStatement (line 220) | function isStatement(node: SyntaxNode): boolean {
  function isBlock (line 237) | function isBlock(node: SyntaxNode): boolean {
  function isEnd (line 241) | function isEnd(node: SyntaxNode): boolean {
  function isScope (line 249) | function isScope(node: SyntaxNode): boolean {
  function isSemicolon (line 253) | function isSemicolon(node: SyntaxNode): boolean {
  function isNewline (line 257) | function isNewline(node: SyntaxNode): boolean {
  function isBlockBreak (line 261) | function isBlockBreak(node: SyntaxNode): boolean {
  function isString (line 265) | function isString(node: SyntaxNode) {
  function isStringCharacter (line 272) | function isStringCharacter(node: SyntaxNode) {
  function isEmptyString (line 279) | function isEmptyString(node: SyntaxNode) {
  function isEndStdinCharacter (line 289) | function isEndStdinCharacter(node: SyntaxNode) {
  function isEscapeSequence (line 297) | function isEscapeSequence(node: SyntaxNode) {
  function isLongOption (line 301) | function isLongOption(node: SyntaxNode): boolean {
  function isShortOption (line 311) | function isShortOption(node: SyntaxNode): boolean {
  function isOption (line 323) | function isOption(node: SyntaxNode): boolean {
  function isOptionValue (line 328) | function isOptionValue(node: SyntaxNode): boolean {
  function isJoinedShortOption (line 345) | function isJoinedShortOption(node: SyntaxNode) {
  function hasShortOptionCharacter (line 351) | function hasShortOptionCharacter(node: SyntaxNode, findChar: string) {
  function isPipe (line 358) | function isPipe(node: SyntaxNode): boolean {
  function isInvalidVariableName (line 364) | function isInvalidVariableName(node: SyntaxNode): boolean {
  function gatherSiblingsTillEol (line 378) | function gatherSiblingsTillEol(node: SyntaxNode): SyntaxNode[] {
  function isBeforeCommand (line 392) | function isBeforeCommand(node: SyntaxNode) {
  function isVariableExpansion (line 403) | function isVariableExpansion(node: SyntaxNode) {
  function isVariableExpansionWithName (line 412) | function isVariableExpansionWithName(node: SyntaxNode, variableName: str...
  function isVariable (line 416) | function isVariable(node: SyntaxNode) {
  function isCompleteFlagCommandName (line 424) | function isCompleteFlagCommandName(node: SyntaxNode) {
  function findPreviousSibling (line 440) | function findPreviousSibling(node?: SyntaxNode): SyntaxNode | null {
  function findParentCommand (line 459) | function findParentCommand(node?: SyntaxNode): SyntaxNode | null {
  function isConcatenation (line 473) | function isConcatenation(node: SyntaxNode) {
  function isAliasWithName (line 477) | function isAliasWithName(node: SyntaxNode, aliasName: string) {
  function findParentFunction (line 490) | function findParentFunction(node?: SyntaxNode): SyntaxNode | null {
  function findParentVariableDefinitionKeyword (line 504) | function findParentVariableDefinitionKeyword(node?: SyntaxNode): SyntaxN...
  function findForLoopVariable (line 521) | function findForLoopVariable(node: SyntaxNode): SyntaxNode | null {
  function findSetDefinedVariable (line 537) | function findSetDefinedVariable(node: SyntaxNode): SyntaxNode | null {
  function hasParent (line 561) | function hasParent(node: SyntaxNode, callbackfn: (n: SyntaxNode) => bool...
  function findParent (line 572) | function findParent(node: SyntaxNode, callbackfn: (n: SyntaxNode) => boo...
  function findParentWithFallback (line 586) | function findParentWithFallback(node: SyntaxNode, callbackfn: (n: Syntax...
  function hasParentFunction (line 597) | function hasParentFunction(node: SyntaxNode) {
  function findFunctionScope (line 611) | function findFunctionScope(node: SyntaxNode) {
  function scopeCheck (line 622) | function scopeCheck(node1: SyntaxNode, node2: SyntaxNode): boolean {
  function wordNodeIsCommand (line 631) | function wordNodeIsCommand(node: SyntaxNode) {
  function isSwitchStatement (line 638) | function isSwitchStatement(node: SyntaxNode) {
  function isCaseClause (line 642) | function isCaseClause(node: SyntaxNode) {
  function isReturn (line 646) | function isReturn(node: SyntaxNode) {
  function isExit (line 650) | function isExit(node: SyntaxNode) {
  function isConditionalCommand (line 654) | function isConditionalCommand(node: SyntaxNode) {
  function isCommandFlag (line 658) | function isCommandFlag(node: SyntaxNode) {
  function isRegexArgument (line 666) | function isRegexArgument(n: SyntaxNode): boolean {
  function isUnmatchedStringCharacter (line 670) | function isUnmatchedStringCharacter(node: SyntaxNode) {
  function isPartialForLoop (line 680) | function isPartialForLoop(node: SyntaxNode) {
  function isInlineComment (line 702) | function isInlineComment(node: SyntaxNode) {
  function isCommandWithName (line 709) | function isCommandWithName(node: SyntaxNode, ...commandNames: string[]) {
  function isArgumentThatCanContainCommandCalls (line 714) | function isArgumentThatCanContainCommandCalls(node: SyntaxNode) {
  function isStringWithCommandCall (line 748) | function isStringWithCommandCall(node: SyntaxNode) {
  function isReturnStatusNumber (line 783) | function isReturnStatusNumber(node: SyntaxNode) {
  function isConcatenatedValue (line 790) | function isConcatenatedValue(node: SyntaxNode) {
  function isBraceExpansion (line 798) | function isBraceExpansion(node: SyntaxNode) {
  function isFilepath (line 810) | function isFilepath(node: SyntaxNode): boolean {
  function isDirectoryPath (line 848) | function isDirectoryPath(node: SyntaxNode): boolean {
  function isPathNode (line 881) | function isPathNode(node: SyntaxNode): boolean {
  function isBuiltin (line 885) | function isBuiltin(node: SyntaxNode) {
  function isCompleteCommandName (line 889) | function isCompleteCommandName(node: SyntaxNode) {
  function isBuiltinCommand (line 903) | function isBuiltinCommand(node: SyntaxNode): boolean {
  function isRedirect (line 915) | function isRedirect(n: SyntaxNode): boolean {
  function getRedirectOperatorNode (line 927) | function getRedirectOperatorNode(n: SyntaxNode): SyntaxNode | null {

FILE: src/utils/path-resolution.ts
  function findFirstExistingFile (line 16) | function findFirstExistingFile(...possiblePaths: string[]): string | und...
  function isExistingFile (line 30) | function isExistingFile(path: string): boolean {
  function isBundledEnvironment (line 41) | function isBundledEnvironment(): boolean {
  function getCurrentExecutablePath (line 49) | function getCurrentExecutablePath(): string {
  function getProjectRootPath (line 66) | function getProjectRootPath(): string {
  function getFishBuildTimeFilePath (line 98) | function getFishBuildTimeFilePath(): string {
  function getManFilePath (line 121) | function getManFilePath(): string {

FILE: src/utils/polyfills.ts
  type String (line 43) | interface String {

FILE: src/utils/process-env.ts
  type AutoloadedFishVariableName (line 28) | type AutoloadedFishVariableName = typeof autoloadedFishVariableNames[num...
  function setupProcessEnvExecFile (line 32) | async function setupProcessEnvExecFile() {
  function setupFallbackProcessEnv (line 59) | function setupFallbackProcessEnv() {
  function includes (line 82) | function includes(name: string): name is AutoloadedFishVariableName {
  function get (line 90) | function get(variable: AutoloadedFishVariableName): string[] {
  function asShowDocumentation (line 100) | function asShowDocumentation(variable: AutoloadedFishVariableName): stri...
  function update (line 114) | function update(variable: AutoloadedFishVariableName, ...newValues: stri...
  function read (line 124) | function read(variable: AutoloadedFishVariableName): string {
  function all (line 131) | function all(): AutoloadedFishVariableName[] {
  function find (line 138) | function find(key: string): string[] {
  function has (line 148) | function has(key: string): boolean {
  function getHoverDocumentation (line 152) | function getHoverDocumentation(variable: string): string {
  function findAutoloadedFunctionPath (line 177) | function findAutoloadedFunctionPath(functionName: string): string | null {

FILE: src/utils/progress-notification.ts
  type ProgressAction (line 6) | type ProgressAction =
  class ProgressNotification (line 16) | class ProgressNotification implements WorkDoneProgressReporter {
    method constructor (line 24) | private constructor(token: string) {
    method isSupported (line 29) | public static isSupported(): boolean {
    method create (line 36) | public static async create(caller?: string): Promise<ProgressNotificat...
    method sendNotification (line 63) | private sendNotification(value: ProgressAction): void {
    method flushQueue (line 70) | private flushQueue(): void {
    method enqueue (line 87) | private enqueue(action: ProgressAction): void {
    method begin (line 98) | public begin(title: string = '[fish-lsp] analysis', percentage?: numbe...
    method report (line 106) | public report(arg0: string | number, message?: string): void {
    method done (line 120) | public done(): void {

FILE: src/utils/semantics.ts
  type SemanticToken (line 15) | interface SemanticToken {
  function create (line 24) | function create(
  function fromNode (line 46) | function fromNode(
  function fromPosition (line 60) | function fromPosition(
  function fromRange (line 78) | function fromRange(params: {
  type SemanticTokenType (line 108) | type SemanticTokenType = (typeof SemanticTokenTypes)[keyof typeof Semant...
  type SemanticTokenModifier (line 119) | type SemanticTokenModifier = (typeof SemanticTokenModifiers)[keyof typeo...
  function modMaskToStringArray (line 138) | function modMaskToStringArray(mask: number): string[] {
  function getTokenTypeIndex (line 150) | function getTokenTypeIndex(tokenType: string): number {
  function getModifierIndex (line 154) | function getModifierIndex(modifier: string): number {
  function calculateModifiersMask (line 158) | function calculateModifiersMask(...modifiers: string[]): number {
  function getModifiersFromMask (line 169) | function getModifiersFromMask(mask: number): string[] {
  function nodeIntersectsRange (line 180) | function nodeIntersectsRange(node: SyntaxNode, range: Range): boolean {
  function getPositionFromOffset (line 192) | function getPositionFromOffset(content: string, offset: number): { line:...
  function getTokenTypePriority (line 208) | function getTokenTypePriority(tokenTypeIndex: number, modifiersMask: num...
  function analyzeValueType (line 256) | function analyzeValueType(text: string): { tokenType: string; modifiers?...
  function getVariableModifiers (line 307) | function getVariableModifiers(variableName: string, documentUri?: string...
  type CommandModifierInfo (line 357) | type CommandModifierInfo = {
  function getCommandModifierInfo (line 368) | function getCommandModifierInfo(commandNode: SyntaxNode, documentUri?: s...
  function getCommandModifiers (line 445) | function getCommandModifiers(commandNode: SyntaxNode, documentUri?: stri...
  type TextMatchPosition (line 452) | type TextMatchPosition = {
  function getTextMatchPositions (line 467) | function getTextMatchPositions(node: SyntaxNode, filter: string | RegExp...
  function calculatePositionFromOffset (line 540) | function calculatePositionFromOffset(
  function createTokensFromMatches (line 572) | function createTokensFromMatches(
  function isNodeCoveredByTokens (line 594) | function isNodeCoveredByTokens(node: SyntaxNode, tokens: SemanticToken[]...

FILE: src/utils/snippets.ts
  type BaseJson (line 12) | interface BaseJson {
  type JsonType (line 19) | type JsonType = 'command' | 'function' | 'pipe' | 'status' | 'variable';
  type SpecialType (line 20) | type SpecialType = 'fishlsp' | 'env' | 'locale' | 'special' | 'theme';
  type AllTypes (line 21) | type AllTypes = JsonType | SpecialType;
  type ExtendedBaseJson (line 23) | interface ExtendedBaseJson extends BaseJson {
  function create (line 29) | function create(o: BaseJson, type: JsonType, specialType?: SpecialType):...
  function is (line 37) | function is(o: any): o is ExtendedBaseJson {
  type ValueType (line 42) | type ValueType = boolean | boolean[] | number | number[] | string | stri...
  type CliObject (line 44) | type CliObject = {
  type EnvVariableJson (line 54) | interface EnvVariableJson extends BaseJson {
  function create (line 66) | function create(o: BaseJson | any, exactMatchOptions: boolean, options: ...
  function is (line 77) | function is(o: any): o is EnvVariableJson {
  function asCliObject (line 119) | function asCliObject(o: EnvVariableJson): CliObject {
  function toCliOutput (line 133) | function toCliOutput(o: EnvVariableJson, opts: CliToStringOpts = {
  function toMarkdownString (line 143) | function toMarkdownString(o: EnvVariableJson, opts: CliToStringOpts = {
  function buildBodySection (line 154) | function buildBodySection(subtitle: string, body: string, shouldWrap: bo...
  type CliToStringOpts (line 193) | type CliToStringOpts = {
  function fromCliOutputToString (line 200) | function fromCliOutputToString(cli: CliObject, opts: CliToStringOpts = {
  function fromCliToMarkdownString (line 223) | function fromCliToMarkdownString(cli: CliObject, opts: CliToStringOpts = {
  type ExtendedJson (line 248) | type ExtendedJson = ExtendedBaseJson | EnvVariableJson;
  class DocumentationMap (line 250) | class DocumentationMap {
    method constructor (line 254) | constructor(data: ExtendedJson[]) {
    method getByName (line 265) | getByName(name: string): ExtendedJson[] {
    method getByType (line 271) | getByType(type: JsonType, specialType?: SpecialType): ExtendedJson[] {
    method add (line 278) | add(item: ExtendedBaseJson): void {
    method findMatchingNames (line 286) | findMatchingNames(query: string, ...types: AllTypes[]): ExtendedJson[] {
    method getSpecialVariableAsHoverDoc (line 296) | getSpecialVariableAsHoverDoc(name: `$${string}` | string): string {
  function getPrebuiltDocUrlByName (line 333) | function getPrebuiltDocUrlByName(name: string): string {
  function getPrebuiltDocUrl (line 343) | function getPrebuiltDocUrl(obj: ExtendedBaseJson): string {

FILE: src/utils/startup.ts
  type ConnectionType (line 19) | type ConnectionType = 'stdio' | 'node-ipc' | 'socket' | 'pipe';
  type ConnectionOptions (line 21) | interface ConnectionOptions {
  function createConnectionType (line 24) | function createConnectionType(opts: {
  function setExternalConnection (line 49) | function setExternalConnection(externalConnection: Connection): void {
  function createLspConnection (line 59) | function createLspConnection(connectionType: ConnectionType = 'stdio', o...
  function createBrowserConnection (line 105) | function createBrowserConnection(): Connection {
  function isPortTaken (line 127) | function isPortTaken(port: number): Promise<boolean> {
  function setupServerWithConnection (line 157) | function setupServerWithConnection(connection: Connection): void {
  function startServer (line 178) | function startServer(connectionType: ConnectionType = 'stdio', options: ...
  function timeOperation (line 192) | async function timeOperation<T>(
  function fixupStartPath (line 216) | function fixupStartPath(startPath: string | undefined): string | undefin...
  type TimeServerOpts (line 228) | type TimeServerOpts = {
  function timeServerStartup (line 247) | async function timeServerStartup(
  type AlignedItem (line 469) | type AlignedItem = string | {
  function processAlignedItem (line 494) | function processAlignedItem(item: AlignedItem, availableWidth: number, d...
  function maxWidthForOutput (line 633) | function maxWidthForOutput(): number {
  function formatAlignedColumns (line 679) | function formatAlignedColumns(items: AlignedItem[], maxWidth?: number): ...
  function stdoutSeparator (line 773) | function stdoutSeparator(): void {

FILE: src/utils/symbol-documentation-builder.ts
  class DocumentationStringBuilder (line 18) | class DocumentationStringBuilder {
    method constructor (line 19) | constructor(
    method outer (line 27) | private get outer() {
    method precedingComments (line 39) | private get precedingComments(): string {
    method text (line 52) | get text(): string {
    method shortenedUri (line 65) | get shortenedUri(): string {
    method toString (line 71) | toString() {
  function create (line 97) | function create(name: string, uri: string, kind: SymbolKind, inner: Synt...
  function getPrecedingCommentString (line 102) | function getPrecedingCommentString(node: SyntaxNode): string {
  function hasPrecedingFunctionDefinition (line 112) | function hasPrecedingFunctionDefinition(node: SyntaxNode): boolean {

FILE: src/utils/translation.ts
  constant RE_PATHSEP_WINDOWS (line 15) | const RE_PATHSEP_WINDOWS = /\\/g;
  function isUri (line 17) | function isUri(stringOrUri: unknown): stringOrUri is DocumentUri {
  type PathLike (line 26) | type PathLike = string;
  function isPath (line 27) | function isPath(pathOrUri: unknown): pathOrUri is PathLike {
  function isTextDocument (line 37) | function isTextDocument(value: unknown): value is TextDocument {
  function isTextDocumentItem (line 61) | function isTextDocumentItem(value: unknown): value is TextDocumentItem {
  function uriToPath (line 78) | function uriToPath(stringUri: DocumentUri): PathLike {
  function pathToUri (line 83) | function pathToUri(filepath: PathLike, documents?: Documents | undefined...
  function normalizePath (line 103) | function normalizePath(filePath: PathLike): PathLike {
  function normalizeFsPath (line 111) | function normalizeFsPath(fsPath: string): string {
  function pathToRelativeFunctionName (line 115) | function pathToRelativeFunctionName(filepath: PathLike): string {
  function uriInUserFunctions (line 120) | function uriInUserFunctions(uri: DocumentUri) {
  function nodeToSymbolInformation (line 125) | function nodeToSymbolInformation(node: SyntaxNode, uri: string): SymbolI...
  function nodeToDocumentSymbol (line 144) | function nodeToDocumentSymbol(node: SyntaxNode): DocumentSymbol {
  function createRange (line 172) | function createRange(startLine: number, startCharacter: number, endLine:...
  function toSelectionRange (line 185) | function toSelectionRange(range: SelectionRange): SelectionRange {
  function toLspDocument (line 193) | function toLspDocument(filename: string, content: string): LspDocument {
  function toSymbolKind (line 198) | function toSymbolKind(node: SyntaxNode): SymbolKind {
  function symbolKindToString (line 216) | function symbolKindToString(kind: SymbolKind) {
  function uriToReadablePath (line 242) | function uriToReadablePath(uri: DocumentUri | WorkspaceUri): string {
  function symbolKindsFromNode (line 276) | function symbolKindsFromNode(node: SyntaxNode): { kindType: SymbolKind; ...
  type AutoloadType (line 285) | type AutoloadType = 'conf.d' | 'functions' | 'completions' | 'config' | '';
  type AutoloadFunctionCallback (line 286) | type AutoloadFunctionCallback = (n: SyntaxNode) => boolean;
  function isAutoloadedUriLoadsFunction (line 295) | function isAutoloadedUriLoadsFunction(document: LspDocument): (n: Syntax...
  function isAutoloadedUriLoadsFunctionName (line 323) | function isAutoloadedUriLoadsFunctionName(document: LspDocument): (n: Sy...
  function isAutoloadedUriLoadsAliasName (line 339) | function isAutoloadedUriLoadsAliasName(document: LspDocument): (n: Synta...
  function shouldHaveAutoloadedFunction (line 350) | function shouldHaveAutoloadedFunction(document: LspDocument): boolean {
  function formatTextWithIndents (line 354) | function formatTextWithIndents(doc: LspDocument, line: number, text: str...

FILE: src/utils/tree-sitter.ts
  function isSyntaxNode (line 8) | function isSyntaxNode(obj: unknown): obj is SyntaxNode {
  function getChildNodes (line 40) | function getChildNodes(root: SyntaxNode): SyntaxNode[] {
  function getNamedChildNodes (line 55) | function getNamedChildNodes(root: SyntaxNode): SyntaxNode[] {
  function findChildNodes (line 70) | function findChildNodes(root: SyntaxNode, predicate: (node: SyntaxNode) ...
  function collectNodesByTypes (line 91) | function collectNodesByTypes(root: SyntaxNode, types: string[]): SyntaxN...
  function getParentNodes (line 115) | function getParentNodes(child: SyntaxNode): SyntaxNode[] {
  function findFirstParent (line 185) | function findFirstParent(node: SyntaxNode, predicate: (node: SyntaxNode)...
  function getSiblingNodes (line 204) | function getSiblingNodes(
  function findFirstNamedSibling (line 225) | function findFirstNamedSibling(
  function findFirstSibling (line 242) | function findFirstSibling(
  function findEnclosingScope (line 267) | function findEnclosingScope(node: SyntaxNode): SyntaxNode {
  function getNodeText (line 290) | function getNodeText(node: SyntaxNode | null): string {
  function getNodesTextAsSingleLine (line 304) | function getNodesTextAsSingleLine(nodes: SyntaxNode[]): string {
  function firstAncestorMatch (line 315) | function firstAncestorMatch(
  function ancestorMatch (line 339) | function ancestorMatch(
  function descendantMatch (line 362) | function descendantMatch(
  function hasNode (line 373) | function hasNode(allNodes: SyntaxNode[], matchNode: SyntaxNode) {
  function getNamedNeighbors (line 382) | function getNamedNeighbors(node: SyntaxNode): SyntaxNode[] {
  function getRange (line 386) | function getRange(node: SyntaxNode): Range {
  function nodeLogFormatter (line 406) | function nodeLogFormatter(node: SyntaxNode | null) {
  function findNodeAt (line 424) | function findNodeAt(tree: Tree, line: number, column: number): SyntaxNod...
  function equalRanges (line 442) | function equalRanges(a: Range, b: Range): boolean {
  function containsRange (line 457) | function containsRange(outer: Range, inner: Range): boolean {
  function precedesRange (line 478) | function precedesRange(before: Range, after: Range): boolean {
  function getNodeAt (line 491) | function getNodeAt(tree: Tree, line: number, column: number): SyntaxNode...
  function containsNode (line 505) | function containsNode(outer: SyntaxNode, inner: SyntaxNode): boolean {
  function getNodeAtRange (line 509) | function getNodeAtRange(root: SyntaxNode, range: Range): SyntaxNode | nu...
  function positionToPoint (line 516) | function positionToPoint(pos: Position): Point {
  function pointToPosition (line 523) | function pointToPosition(point: Point): Position {
  function rangeToPoint (line 530) | function rangeToPoint(range: Range): Point {
  function getRangeWithPrecedingComments (line 537) | function getRangeWithPrecedingComments(node: SyntaxNode): Range {
  function getPrecedingComments (line 550) | function getPrecedingComments(node: SyntaxNode | null): string {
  function commentsHelper (line 564) | function commentsHelper(node: SyntaxNode | null): string {
  function isFishExtension (line 581) | function isFishExtension(path: URI | string): boolean {
  function isPositionWithinRange (line 586) | function isPositionWithinRange(position: Position, range: Range): boolean {
  function isPositionAfter (line 598) | function isPositionAfter(first: Position, second: Position): boolean {
  function isNodeWithinRange (line 604) | function isNodeWithinRange(node: SyntaxNode, range: Range): boolean {
  function isNodeWithinOtherNode (line 618) | function isNodeWithinOtherNode(node: SyntaxNode, otherNode: SyntaxNode):...
  function isPositionInNode (line 625) | function isPositionInNode(position: Position, node: SyntaxNode): boolean {
  function getLeafNodes (line 640) | function getLeafNodes(node: SyntaxNode): SyntaxNode[] {
  function getLastLeafNode (line 654) | function getLastLeafNode(node: SyntaxNode, maxIndex: number = Infinity):...
  function getNodeAtPosition (line 659) | function getNodeAtPosition(tree: Tree, position: { line: number; charact...
  class TreeWalker (line 685) | class TreeWalker {
    method walkUp (line 689) | static walkUp(node: SyntaxNode, predicate: (n: SyntaxNode) => boolean)...
    method walkUpAll (line 703) | static walkUpAll(node: SyntaxNode, predicate: (n: SyntaxNode) => boole...
    method findFirstChild (line 718) | static findFirstChild(node: SyntaxNode, predicate: (n: SyntaxNode) => ...
    method findHighest (line 726) | static findHighest(node: SyntaxNode, predicate: (n: SyntaxNode) => boo...
    method walkDown (line 734) | static walkDown(node: SyntaxNode, predicate: (n: SyntaxNode) => boolea...
    method walkDownAll (line 749) | static walkDownAll(node: SyntaxNode, predicate: (n: SyntaxNode) => boo...

FILE: src/utils/workspace-manager.ts
  type WorkspaceUpdateOptions (line 10) | type WorkspaceUpdateOptions = {
  class WorkspaceManager (line 19) | class WorkspaceManager {
    method copy (line 26) | public copy(workspaceManager: WorkspaceManager) {
    method setCurrent (line 38) | public setCurrent(workspace: Workspace) {
    method current (line 47) | public get current(): Workspace | undefined {
    method add (line 53) | public add(...workspaces: Workspace[]): void {
    method remove (line 63) | public remove(...workspaces: Workspace[]): void {
    method findContainingWorkspace (line 76) | public findContainingWorkspace(doc: DocumentUri | LspDocument): Worksp...
    method hasContainingWorkspace (line 85) | public hasContainingWorkspace(doc: DocumentUri | LspDocument): boolean {
    method clear (line 93) | public clear(): this {
    method all (line 104) | public get all() {
    method allUrisInAllWorkspaces (line 123) | public get allUrisInAllWorkspaces(): DocumentUri[] {
    method workspacesToAnalyze (line 134) | public workspacesToAnalyze(): Workspace[] {
    method needsAnalysis (line 141) | public needsAnalysis(): boolean {
    method allWorkspacesWithDocument (line 148) | public allWorkspacesWithDocument(doc: LspDocument): Workspace[] {
    method allAnalysisDocuments (line 157) | public allAnalysisDocuments(): LspDocument[] {
    method isLargeAnalysis (line 172) | public get isLargeAnalysis(): boolean {
    method findDocumentInAnyWorkspace (line 176) | public findDocumentInAnyWorkspace(uri: DocumentUri): LspDocument | null {
    method getWorkspaceContainingUri (line 187) | private getWorkspaceContainingUri(uri: DocumentUri): Workspace | null {
    method getExistingWorkspaceOrCreateNew (line 212) | private getExistingWorkspaceOrCreateNew(uri: DocumentUri): Workspace |...
    method getDocumentUriFromParams (line 230) | private getDocumentUriFromParams(param: DocumentUri | LspDocument | Pa...
    method handleOpenDocument (line 246) | public handleOpenDocument(doc: DocumentUri | LspDocument): Workspace |...
    method handleCloseDocument (line 287) | public handleCloseDocument(doc: DocumentUri | LspDocument): Workspace ...
    method handleUpdateDocument (line 331) | public handleUpdateDocument(doc: DocumentUri | LspDocument, options: W...
    method handleWorkspaceChangeEvent (line 379) | public handleWorkspaceChangeEvent(event: WorkspaceFoldersChangeEvent, ...
    method analyzePendingDocuments (line 429) | public async analyzePendingDocuments(
  class WorkspaceStack (line 536) | class WorkspaceStack {
    method copy (line 539) | public copy(workspaceStack: WorkspaceStack) {
    method push (line 544) | public push(workspace: Workspace): void {
    method pop (line 549) | public pop(): Workspace | undefined {
    method current (line 553) | public get current(): Workspace | undefined {
    method allOpened (line 557) | public get allOpened(): Workspace[] {
    method findIndex (line 561) | public findIndex(workspace: Workspace): number {
    method has (line 565) | public has(workspace: Workspace): boolean {
    method isEmpty (line 569) | public isEmpty(): boolean {
    method clear (line 573) | public clear(): void {
    method length (line 577) | public get length(): number {
    method remove (line 581) | public remove(...workspaces: Workspace[]): void {

FILE: src/utils/workspace.ts
  type AnalyzedWorkspace (line 16) | type AnalyzedWorkspace = {
  type AnalyzeWorkspacePromise (line 23) | type AnalyzeWorkspacePromise = Promise<{
  function getWorkspacePathsFromInitializationParams (line 35) | function getWorkspacePathsFromInitializationParams(params: LSP.Initializ...
  function getFileUriSet (line 56) | async function getFileUriSet(path: string) {
  function syncGetFileUriSet (line 82) | function syncGetFileUriSet(path: string) {
  function initializeDefaultFishWorkspaces (line 116) | async function initializeDefaultFishWorkspaces(...uris: string[]): Promi...
  type WorkspaceUri (line 165) | type WorkspaceUri = string;
  type FishWorkspace (line 167) | interface FishWorkspace extends LSP.WorkspaceFolder {
  class Workspace (line 177) | class Workspace implements FishWorkspace {
    method create (line 184) | public static async create(name: string, uri: DocumentUri | WorkspaceU...
    method syncCreateFromUri (line 197) | public static syncCreateFromUri(uri: string) {
    method constructor (line 218) | public constructor(name: string, uri: WorkspaceUri, path: string, file...
    method allUris (line 225) | public get allUris(): Set<DocumentUri> {
    method contains (line 229) | contains(...checkUris: DocumentUri[]): boolean {
    method shouldContain (line 243) | shouldContain(uri: DocumentUri) {
    method addUri (line 247) | addUri(uri: DocumentUri) {
    method add (line 251) | add(...newUris: DocumentUri[]) {
    method addDocument (line 255) | addDocument(...newDocs: LspDocument[]) {
    method addPending (line 260) | addPending(...newUris: DocumentUri[]) {
    method findMatchingFishIdentifiers (line 264) | findMatchingFishIdentifiers(fishIdentifier: string) {
    method findDocument (line 275) | findDocument(callbackfn: (doc: LspDocument) => boolean): LspDocument |...
    method isMutable (line 291) | isMutable() {
    method isLoadable (line 295) | isLoadable() {
    method isAnalyzed (line 299) | isAnalyzed() {
    method hasCompletionUri (line 303) | hasCompletionUri(fishIdentifier: string) {
    method hasFunctionUri (line 308) | hasFunctionUri(fishIdentifier: string) {
    method hasCompletionAndFunction (line 313) | hasCompletionAndFunction(fishIdentifier: string) {
    method getCompletionUri (line 317) | getCompletionUri(fishIdentifier: string) {
    method pendingDocuments (line 322) | pendingDocuments(): LspDocument[] {
    method allDocuments (line 336) | allDocuments(): LspDocument[] {
    method paths (line 355) | get paths(): string[] {
    method getUris (line 359) | getUris(): DocumentUri[] {
    method equals (line 363) | equals(other: FishWorkspace | null) {
    method needsAnalysis (line 368) | public needsAnalysis() {
    method setAllPending (line 372) | setAllPending() {
    method toTreeString (line 378) | toTreeString() {
    method showAllTreeSitterParseTrees (line 399) | showAllTreeSitterParseTrees() {
  type FishUriWorkspace (line 411) | interface FishUriWorkspace {
  function isTmpWorkspace (line 423) | function isTmpWorkspace(uri: string) {
  function getFuncedOrCommandlineWorkspaceRoot (line 436) | function getFuncedOrCommandlineWorkspaceRoot(): string | undefined {
  function trimFishFilePath (line 444) | function trimFishFilePath(uri: string): string | undefined {
  function getWorkspaceRootFromUri (line 456) | function getWorkspaceRootFromUri(uri: string): string | undefined {
  function getWorkspaceName (line 515) | function getWorkspaceName(uri: string): string {
  function isFishWorkspacePath (line 543) | function isFishWorkspacePath(path: string): boolean {
  function isInFishWorkspace (line 561) | function isInFishWorkspace(uri: string): boolean {
  function initializeEnvWorkspaces (line 565) | function initializeEnvWorkspaces(): FishUriWorkspace[] {
  function create (line 577) | function create(uri: string): FishUriWorkspace | null {
  class UriTracker (line 628) | class UriTracker {
    method create (line 632) | static create(...uris: string[]) {
    method add (line 643) | add(...uris: string[]) {
    method addPending (line 655) | addPending(uris: string[]) {
    method markIndexed (line 667) | markIndexed(uri: string): void {
    method markPending (line 675) | markPending(uri: string): void {
    method all (line 683) | get all(): string[] {
    method allAsSet (line 687) | allAsSet(): Set<string> {
    method indexed (line 694) | get indexed(): string[] {
    method pending (line 701) | get pending(): string[] {
    method pendingCount (line 708) | get pendingCount(): number {
    method indexedCount (line 715) | get indexedCount(): number {
    method isIndexed (line 722) | isIndexed(uri: string): boolean {
    method has (line 726) | has(uri: string): boolean {

FILE: src/virtual-fs.ts
  type FindMatchPredicateFunction (line 24) | type FindMatchPredicateFunction = (vf: VirtualFile) => boolean;
  type FindMatchPredicate (line 25) | type FindMatchPredicate = string | FindMatchPredicateFunction;
  class VirtualFile (line 27) | class VirtualFile {
    method constructor (line 30) | private constructor(
    method create (line 55) | static create(
    method getContent (line 62) | async getContent(): Promise<string | Buffer> {
    method type (line 70) | get type() {
    method exists (line 74) | exists(): boolean {
    method getParentDirectory (line 78) | getParentDirectory(): string {
    method depth (line 89) | depth(): number {
    method basename (line 95) | basename(): string {
    method insideDirectory (line 99) | insideDirectory(dir: string): boolean {
  class VirtualFileSystem (line 114) | class VirtualFileSystem {
    method constructor (line 121) | constructor() {
    method setupVirtualFS (line 128) | private async setupVirtualFS() {
    method initialize (line 150) | async initialize(): Promise<void> {
    method getVirtualPath (line 214) | getVirtualPath(relativePath: string): string {
    method getMountPoint (line 225) | getMountPoint(): string {
    method isReady (line 232) | isReady(): boolean {
    method displayTree (line 239) | displayTree(): string {
    method cleanup (line 294) | async cleanup(): Promise<void> {
    method find (line 303) | find(predicate: FindMatchPredicate): VirtualFile | undefined {
    method fishFiles (line 310) | get fishFiles() {
    method getPathOrFallback (line 347) | getPathOrFallback(vfsRelativePath: string, ...fallbackPaths: string[])...

FILE: src/web.ts
  class FishLspWeb (line 9) | class FishLspWeb {
    method constructor (line 12) | constructor() {
    method setupHandlers (line 18) | private setupHandlers() {
    method listen (line 73) | public listen() {
    method dispose (line 77) | public dispose() {

FILE: tests/alias-conversion.test.ts
  function createTestDocument (line 22) | function createTestDocument(content: string): LspDocument {
  function createDiagnostic (line 31) | function createDiagnostic(line: number, character: number, length: numbe...

FILE: tests/code-action.test.ts
  type LocalFunctionCallType (line 639) | type LocalFunctionCallType = {
  function isMatchingCompletionOption (line 644) | function isMatchingCompletionOption(node: SyntaxNode) {

FILE: tests/completion-startup-config.test.ts
  type AllowedEmptyCommandResult (line 20) | type AllowedEmptyCommandResult = { kind: FishCompletionItemKind; command...
  function setup (line 23) | async function setup(): Promise<AllowedEmptyCommandResult[]> {
  function hasKind (line 33) | function hasKind(kind: FishCompletionItemKind): boolean {
  function getCountForKind (line 38) | function getCountForKind(kind: FishCompletionItemKind): number {
  type SetupResult (line 46) | type SetupResult = SetupItem & {
  function simpleParrallelTestSetupItemsInitializer (line 50) | async function simpleParrallelTestSetupItemsInitializer(
  type TestItemInput (line 180) | type TestItemInput = { label: string; kinds: FishCompletionItemKind[]; };
  type TestItemExpectedOutput (line 181) | type TestItemExpectedOutput = { found: boolean; };

FILE: tests/diagnostics.test.ts
  function fishTextDocumentItem (line 58) | function fishTextDocumentItem(uri: string, text: string): LspDocument {
  function severityStr (line 67) | function severityStr(severity: DiagnosticSeverity | undefined) {
  function logDiagnostics (line 77) | function logDiagnostics(diagnostic: Diagnostic, root: SyntaxNode) {
  function mapDiagnostics (line 88) | function mapDiagnostics(diagnostics: Diagnostic) {
  function extractDiagnostics (line 95) | function extractDiagnostics(tree: Tree) {
  type ConditionalOutput (line 380) | type ConditionalOutput = {

FILE: tests/document-highlights.test.ts
  function createHighlightRequest (line 32) | function createHighlightRequest(doc: LspDocument, position: Position) {

FILE: tests/document-test-helpers.ts
  function testOpenDocument (line 20) | function testOpenDocument(doc: LspDocument): void {
  function testCloseDocument (line 54) | function testCloseDocument(uri: string): void {
  function testClearDocuments (line 73) | function testClearDocuments(): void {
  function testChangeDocument (line 96) | function testChangeDocument(uri: string, newText: string, version?: numb...
  function testGetDocumentCount (line 119) | function testGetDocumentCount(): number {
  function testHasDocument (line 130) | function testHasDocument(uri: string): boolean {

FILE: tests/exec.test.ts
  type PrintDocsParams (line 75) | type PrintDocsParams = EmbeddedFishResult & {
  function printDocsStdout (line 79) | function printDocsStdout(input: PrintDocsParams) {

FILE: tests/fish-symbol.test.ts
  function getGlobalSymbols (line 18) | function getGlobalSymbols(symbols: FishSymbol[]): FishSymbol[] {
  function getLocalSymbols (line 22) | function getLocalSymbols(symbols: FishSymbol[]): FishSymbol[] {
  function clientTree (line 172) | function clientTree(symbol: FishSymbol[]) {
  type NestedStringArray (line 185) | type NestedStringArray = Array<string | NestedStringArray>;
  function expectedClientTree (line 186) | function expectedClientTree(names: NestedStringArray[]): string {

FILE: tests/fish-syntax-node.test.ts
  constant SHOULD_LOG (line 47) | let SHOULD_LOG = false;

FILE: tests/formatting.test.ts
  function helperOutputFormattedString (line 13) | function helperOutputFormattedString(input: string) {

FILE: tests/helpers.ts
  function setupStartupMock (line 41) | function setupStartupMock() {
  function setLogger (line 264) | function setLogger(
  function createMockConnection (line 285) | function createMockConnection(): LSP.Connection {
  function getMockedInitializationFunctions (line 410) | async function getMockedInitializationFunctions() {
  function resolveLspDocumentForHelperTestFile (line 432) | function resolveLspDocumentForHelperTestFile(fname: string, inAutoloadPa...
  function resolveAbsPath (line 441) | async function resolveAbsPath(fname: string): Promise<string[]> {
  function positionStr (line 446) | function positionStr(pos: Point) {
  function parseFile (line 450) | async function parseFile(fname: string): Promise<Tree> {
  function createFakeUriPath (line 457) | function createFakeUriPath(path: string): string {
  type TestLspDocument (line 464) | type TestLspDocument = {
  function createTestWorkspace (line 469) | function createTestWorkspace(
  type FakeLspDocumentType (line 482) | type FakeLspDocumentType = {
  class FakeLspDocument (line 489) | class FakeLspDocument extends LspDocument {
    method constructor (line 490) | constructor(input: FakeLspDocumentType = { languageId: 'fish', version...
    method from (line 494) | static from(uri: string, ...text: string[]): FakeLspDocument {
  function createFakeLspDocument (line 499) | function createFakeLspDocument(name: string, ...text: string[]): LspDocu...
  function setupTestCallback (line 520) | function setupTestCallback(parser: Parser) {
  function getAllTypesOfNestedArrays (line 535) | function getAllTypesOfNestedArrays(doc: LspDocument, root: SyntaxNode) {
  type PrintClientTreeOpts (line 553) | type PrintClientTreeOpts = { log: boolean; };
  function printClientTree (line 558) | function printClientTree(
  function locationAsString (line 589) | function locationAsString(loc: Location): string[] {
  function rangeAsString (line 596) | function rangeAsString(range: Range): string {
  function fakeDocumentTrimUri (line 603) | function fakeDocumentTrimUri(doc: LspDocument): string {
  function printLocations (line 613) | function printLocations(locations: Location[], opts: {
  function fishLocations (line 665) | async function fishLocations(): Promise<FishLocations> {
  type FishLocations (line 714) | type FishLocations = {
  type FishTestWorkspaceLocation (line 807) | type FishTestWorkspaceLocation = {
  function getAllFilesInDir (line 813) | function getAllFilesInDir(dir: string): {
  function truncatedUri (line 880) | function truncatedUri(doc: LspDocument, opts: {

FILE: tests/issue-140-complete-command-quoting.test.ts
  constant COMMAND_NAME (line 39) | const COMMAND_NAME = 'mas';
  constant MAS_REPRESENTATIONS (line 53) | const MAS_REPRESENTATIONS: { input: string; description: string; nodeTyp...

FILE: tests/node-types.test.ts
  function parseStringForNodeType (line 21) | function parseStringForNodeType(str: string, predicate: (n: SyntaxNode) ...
  function skipSetQuery (line 27) | function skipSetQuery(node: SyntaxNode) {
  function walkUpSiblings (line 41) | function walkUpSiblings(n: SyntaxNode) {
  function walkUpAndGather (line 49) | function walkUpAndGather(n: SyntaxNode, predicate: (_: SyntaxNode) => bo...

FILE: tests/parsing-defintions.test.ts
  type PrintClientTreeOpts (line 31) | type PrintClientTreeOpts = { log: boolean; };
  function printClientTree (line 32) | function printClientTree(
  function getCompletionsForCommand (line 62) | async function getCompletionsForCommand(command: string) {
  function getFlagsFromCompletion (line 69) | function getFlagsFromCompletion(completions: string[][]): string[] {
  function getAllOptionFlags (line 73) | function getAllOptionFlags(flags: Option[]): string[] {

FILE: tests/parsing-env-values.test.ts
  type PrintClientTreeOpts (line 26) | type PrintClientTreeOpts = { log: boolean; };

FILE: tests/parsing-export-defintions.test.ts
  type PrintClientTreeOpts (line 32) | type PrintClientTreeOpts = { log: boolean; };
  function printClientTree (line 33) | function printClientTree(

FILE: tests/parsing-string-value.test.ts
  function getCommandArgNode (line 32) | function getCommandArgNode(input: string): Parser.SyntaxNode {

FILE: tests/reference-locations.test.ts
  function setup (line 37) | function setup() {

FILE: tests/semantic-tokens-helpers.ts
  type DecodedToken (line 7) | interface DecodedToken {
  function decodeSemanticTokens (line 24) | function decodeSemanticTokens(
  function findTokensByText (line 71) | function findTokensByText(tokens: DecodedToken[], text: string): Decoded...
  function findTokensByType (line 78) | function findTokensByType(tokens: DecodedToken[], tokenType: string): De...
  function findTokensByModifier (line 85) | function findTokensByModifier(tokens: DecodedToken[], modifier: string):...
  function findTokensWithModifiers (line 92) | function findTokensWithModifiers(tokens: DecodedToken[], ...modifiers: s...
  function expectTokenExists (line 99) | function expectTokenExists(
  function countTokensByType (line 131) | function countTokensByType(tokens: DecodedToken[], tokenType: string): n...
  function getUniqueTokenTypes (line 138) | function getUniqueTokenTypes(tokens: DecodedToken[]): string[] {
  function getUniqueModifiers (line 145) | function getUniqueModifiers(tokens: DecodedToken[]): string[] {
  function printTokens (line 153) | function printTokens(tokens: DecodedToken[], title?: string): void {

FILE: tests/temp.ts
  type TempFileResult (line 9) | interface TempFileResult {
  function createFakeLspDocument (line 15) | function createFakeLspDocument(document: TextDocumentItem) {
  function createTempFishFile (line 32) | function createTempFishFile(content: string): TempFileResult {
  function withTempFishFile (line 72) | async function withTempFishFile(

FILE: tests/test-workspace-utils.ts
  class Query (line 72) | class Query {
    method constructor (line 76) | private constructor() { }
    method create (line 81) | static create(): Query {
    method functions (line 88) | static functions(): Query {
    method completions (line 95) | static completions(): Query {
    method config (line 102) | static config(): Query {
    method confd (line 109) | static confd(): Query {
    method scripts (line 116) | static scripts(): Query {
    method autoloaded (line 123) | static autoloaded(): Query {
    method withName (line 130) | static withName(name: string): Query {
    method withPath (line 137) | static withPath(...patterns: string[]): Query {
    method firstMatch (line 144) | static firstMatch(): Query {
    method functions (line 153) | functions(): Query {
    method completions (line 164) | completions(): Query {
    method config (line 175) | config(): Query {
    method confd (line 186) | confd(): Query {
    method scripts (line 197) | scripts(): Query {
    method autoloaded (line 214) | autoloaded(): Query {
    method withName (line 230) | withName(name: string): Query {
    method withPath (line 243) | withPath(...patterns: string[]): Query {
    method firstMatch (line 254) | firstMatch(): Query {
    method execute (line 262) | execute(documents: LspDocument[]): LspDocument[] {
  type TestFileSpec (line 282) | interface TestFileSpec {
  function is (line 290) | function is(item: any): item is TestFileSpec {
  type TestFileSpecLegacy (line 295) | interface TestFileSpecLegacy {
  function is (line 301) | function is(item: any): item is TestFileSpecLegacy {
  function toNewFormat (line 305) | function toNewFormat(item: TestFileSpecLegacy): TestFileSpec {
  function is (line 321) | function is(item: any): item is TestFileSpecInput {
  type TestFileSpecInput (line 326) | type TestFileSpecInput = TestFileSpec | TestFileSpecLegacy;
  type TestWorkspaceConfig (line 331) | interface TestWorkspaceConfig {
  type ReadWorkspaceConfig (line 359) | interface ReadWorkspaceConfig {
  function is (line 365) | function is(item: any): item is ReadWorkspaceConfig {
  function fromInput (line 369) | function fromInput(input: string | ReadWorkspaceConfig): ReadWorkspaceCo...
  type WorkspaceSnapshot (line 384) | interface WorkspaceSnapshot {
  class TestFile (line 393) | class TestFile {
    method constructor (line 394) | private constructor(
    method function (line 402) | static function(name: string, content: string | string[]) {
    method completion (line 410) | static completion(name: string, content: string | string[]) {
    method config (line 418) | static config(content: string | string[]) {
    method confd (line 425) | static confd(name: string, content: string | string[]) {
    method script (line 433) | static script(name: string, content: string | string[]) {
    method custom (line 441) | static custom(relativePath: string, content: string | string[]) {
    method withShebang (line 445) | withShebang(shebang: string = '#!/usr/bin/env fish'): TestFile {
    method fromInput (line 454) | static fromInput(relativePath: string, content: string | string[]): Te...
  class TestWorkspace (line 480) | class TestWorkspace {
    method constructor (line 494) | private constructor(config: TestWorkspaceConfig = {}) {
    method createBaseWorkspace (line 525) | static createBaseWorkspace() {
    method reset (line 529) | reset() {
    method read (line 588) | static read(input: ReadWorkspaceConfig | string): TestWorkspace {
    method create (line 647) | static create(config?: TestWorkspaceConfig): TestWorkspace {
    method createSingle (line 667) | static createSingle(
    method createSingleFileReady (line 712) | static createSingleFileReady(
    method fromSnapshot (line 738) | static fromSnapshot(snapshotPath: string): TestWorkspace {
    method addFiles (line 750) | addFiles(...files: TestFileSpecInput[]): TestWorkspace {
    method addFile (line 770) | addFile(file: TestFileSpecInput): TestWorkspace {
    method inheritFilesFromExistingAutoloadedWorkspace (line 786) | inheritFilesFromExistingAutoloadedWorkspace(sourcePath: string): TestW...
    method editFile (line 844) | editFile(searchPath: string, newContent: string | string[]): void {
    method addDocuments (line 879) | addDocuments(...item: (LspDocument | TestFileSpec)[]): TestWorkspace {
    method addDocument (line 886) | addDocument(item: LspDocument | TestFileSpec): TestWorkspace {
    method initialize (line 953) | initialize() {
    method setup (line 961) | get setup() {
    method focus (line 1010) | focus(documentPath?: string | number): TestWorkspace {
    method setupWithFocus (line 1030) | get setupWithFocus() {
    method documents (line 1040) | get documents(): LspDocument[] {
    method focusedDocument (line 1047) | get focusedDocument(): LspDocument | null {
    method document (line 1052) | get document(): LspDocument | null {
    method workspace (line 1056) | get workspace(): Workspace | null {
    method name (line 1063) | get name(): string {
    method path (line 1070) | get path(): string {
    method uri (line 1077) | get uri(): string {
    method getDocument (line 1084) | getDocument(searchPath: string): LspDocument | undefined {
    method getDocuments (line 1105) | getDocuments(...queries: Query[]): LspDocument[] {
    method find (line 1139) | find(...query: (Query | string | number)[]) {
    method getWorkspace (line 1177) | getWorkspace(): Workspace | null {
    method asResult (line 1184) | asResult() {
    method inspect (line 1201) | inspect(): TestWorkspace {
    method dumpFileTree (line 1209) | dumpFileTree(): string {
    method writeSnapshot (line 1237) | writeSnapshot(outputPath?: string): string {
    method _generateUniqueName (line 1253) | private _generateUniqueName(): string {
    method _generateRandomName (line 1259) | private static _generateRandomName(): string {
    method _createWorkspaceFiles (line 1265) | private async _createWorkspaceFiles(): Promise<void> {
    method _setupWorkspace (line 1320) | private async _setupWorkspace(): Promise<void> {
    method analyzeAllFiles (line 1369) | async analyzeAllFiles() {
    method _resetAnalysisState (line 1408) | private async _resetAnalysisState(): Promise<void> {
    method _cleanup (line 1425) | private async _cleanup(): Promise<void> {
  class TestLogger (line 1459) | class TestLogger {
    method setSilent (line 1465) | static setSilent(silent: boolean): void {
    method enableTestWorkspaceLogging (line 1487) | static enableTestWorkspaceLogging(): void {
  class DefaultTestWorkspaces (line 1496) | class DefaultTestWorkspaces {
    method emptyWorkspace (line 1497) | static emptyWorkspace(): TestWorkspace {
    method basicFunctions (line 1504) | static basicFunctions(): TestWorkspace {
    method complexFunctions (line 1524) | static complexFunctions(): TestWorkspace {
    method configAndEvents (line 1553) | static configAndEvents(): TestWorkspace {
    method projectWorkspace (line 1576) | static projectWorkspace(): TestWorkspace {
  function cliModule (line 1646) | function cliModule() {

FILE: tests/tree-sitter-fast-check.test.ts
  function shellVals (line 149) | function shellVals() {

FILE: tests/tree-sitter.test.ts
  function parseString (line 36) | function parseString(str: string): Parser.Tree {
  function parseStringForNode (line 41) | function parseStringForNode(str: string, predicate: (n: SyntaxNode) => b...

FILE: tests/unreachable.test.ts
  function logNode (line 381) | function logNode(node: any, indent = 0) {

FILE: tests/workspace-util.ts
  function generateRandomWorkspaceName (line 14) | function generateRandomWorkspaceName(): string {
  type QueryPathType (line 22) | type QueryPathType = 'functions' | 'completions' | 'conf.d' | 'config.fi...
  class QueryConfig (line 23) | class QueryConfig {
    method is (line 29) | static is(config: any): config is QueryConfig {
    method to (line 42) | static to(config: QueryConfig): Query {
  class Query (line 98) | class Query {
    method constructor (line 102) | private constructor() { }
    method is (line 104) | public static is(query: unknown): query is Query {
    method fromConfig (line 111) | public static fromConfig(config: QueryConfig | string | unknown): Query {
    method create (line 126) | static create(): Query {
    method functions (line 133) | static functions(): Query {
    method completions (line 140) | static completions(): Query {
    method config (line 147) | static config(): Query {
    method confd (line 154) | static confd(): Query {
    method scripts (line 161) | static scripts(): Query {
    method autoloaded (line 168) | static autoloaded(): Query {
    method withName (line 175) | static withName(name: string): Query {
    method withPath (line 182) | static withPath(...patterns: string[]): Query {
    method firstMatch (line 189) | static firstMatch(): Query {
    method functions (line 198) | functions(): Query {
    method completions (line 209) | completions(): Query {
    method config (line 220) | config(): Query {
    method confd (line 231) | confd(): Query {
    method scripts (line 242) | scripts(): Query {
    method autoloaded (line 259) | autoloaded(): Query {
    method withName (line 275) | withName(name: string): Query {
    method withPath (line 287) | withPath(...patterns: string[]): Query {
    method firstMatch (line 298) | firstMatch(): Query {
    method execute (line 306) | execute(documents: LspDocument[]): LspDocument[] {
  type QueryPropsType (line 323) | type QueryPropsType = Query | QueryConfig | string;
  class TestFile (line 326) | class TestFile {
    method constructor (line 330) | private constructor(
    method absPath (line 336) | get absPath(): string {
    method toDocument (line 340) | toDocument(): LspDocument {
    method getType (line 347) | getType() {
    method withShebang (line 351) | withShebang(shebang: string = '#!/usr/bin/env fish'): TestFile {
    method writeFile (line 364) | writeFile() {
    method create (line 374) | static create(
    method relativeUri (line 382) | get relativeUri() {
    method uri (line 386) | get uri() {
    method function (line 399) | static function(name: string, content: string | string[]) {
    method completion (line 407) | static completion(name: string, content: string | string[]) {
    method config (line 415) | static config(content: string | string[]) {
    method confd (line 422) | static confd(name: string, content: string | string[]) {
    method script (line 430) | static script(name: string, content: string | string[]) {
    method custom (line 438) | static custom(relativePath: string, content: string | string[]) {
    method fromDoc (line 442) | static fromDoc(doc: LspDocument): TestFile {
  type TestWorkspaceForceUtil (line 465) | type TestWorkspaceForceUtil = {
  class TestWorkspace (line 475) | class TestWorkspace {
    method constructor (line 487) | constructor(
    method absPath (line 505) | get absPath() {
    method workspaceUri (line 512) | get workspaceUri() {
    method isCurrent (line 516) | isCurrent() {
    method add (line 524) | add(...files: TestFile[]) {
    method inspect (line 568) | inspect() {
    method _isValidFishDir (line 572) | private _isValidFishDir(relativePath: string): boolean {
    method copyFromAutoloadedEnvVariable (line 579) | copyFromAutoloadedEnvVariable(sourcePath: string) {
    method initialize (line 676) | initialize() {
    method getHooks (line 800) | getHooks(): {
    method initializeLazy (line 883) | initializeLazy(): TestWorkspace {
    method forceInitializeSync (line 905) | forceInitializeSync(): TestWorkspace {
    method forceInitializeAsync (line 943) | async forceInitializeAsync(): Promise<TestWorkspace> {
    method forceInitialize (line 980) | async forceInitialize(): Promise<TestWorkspace> {
    method workspace (line 1014) | get workspace(): Workspace {
    method documents (line 1027) | get documents(): LspDocument[] {
    method get (line 1041) | public get(
    method findDocumentByPath (line 1047) | findDocumentByPath(searchPath: string): LspDocument | undefined {
    method findDocumentsByName (line 1051) | findDocumentsByName(name: string): LspDocument[] {
    method writeSnapshot (line 1055) | writeSnapshot(outputPath?: string): string {
    method findSnapshotPath (line 1067) | static findSnapshotPath(searchWorkspace: string | TestWorkspace) {
    method fromSnapshot (line 1081) | static fromSnapshot(path: string): TestWorkspace {
    method readSnapshot (line 1105) | readSnapshot(path: string) {
    method dumpFileTree (line 1132) | dumpFileTree(): string {
    method dumpParseTrees (line 1161) | dumpParseTrees(): string {
    method dumpParseTree (line 1188) | dumpParseTree(pathOrQuery: string): string {
    method formatParseTree (line 1209) | private formatParseTree(node: any, indent = ''): string {
    method filter (line 1241) | filter(...queryProps: QueryPropsType[]) {
    method filterHelper (line 1257) | private filterHelper(
    method find (line 1282) | find(...queryProps: QueryPropsType[]) {
    method force (line 1296) | get force(): TestWorkspaceForceUtil {
    method edit (line 1350) | edit(
    method create (line 1388) | static create(name: string | { name: string; } = generateRandomWorkspa...
    method createSingleFile (line 1403) | static createSingleFile(
    method forceDelete (line 1417) | forceDelete() {
  class DefaultTestWorkspaces (line 1428) | class DefaultTestWorkspaces {
    method basicFunctions (line 1432) | static basicFunctions(): TestWorkspace {
    method complexFunctions (line 1452) | static complexFunctions(): TestWorkspace {
    method configAndEvents (line 1481) | static configAndEvents(): TestWorkspace {
    method projectWorkspace (line 1504) | static projectWorkspace(): TestWorkspace {

FILE: vitest.config.ts
  function fishLoader (line 8) | function fishLoader(): Plugin {
Condensed preview — 316 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,035K chars).
[
  {
    "path": ".all-contributorsrc",
    "chars": 4172,
    "preview": "{\n  \"projectName\": \"fish-lsp\",\n  \"projectOwner\": \"ndonfris\",\n  \"repoType\": \"github\",\n  \"repoHost\": \"https://github.com\","
  },
  {
    "path": ".github/CODEOWNERS",
    "chars": 12,
    "preview": "* @ndonfris\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 903,
    "preview": "# These are supported funding model platforms\n\ngithub: ndonfris # Replace with up to 4 GitHub Sponsors-enabled usernames"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.md",
    "chars": 1153,
    "preview": "---\nname: Bug Report\nabout: Report a bug you're experiencing\ntitle: BUG\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the b"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 595,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
  },
  {
    "path": ".github/workflows/check-npm-release.yml",
    "chars": 1450,
    "preview": "# Daily check that fish-lsp NPM package installation\n# and basic commands are working\nname: Check NPM Release\n\non:\n  sch"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1336,
    "preview": "## INSTALL, BUILD and LINT a local clone of the repository, with the recommended dependencies.\n## Will run on every push"
  },
  {
    "path": ".github/workflows/test-npm-package.yml",
    "chars": 3879,
    "preview": "## Test that the built npm package can be successfully installed and works correctly\n## This workflow builds the package"
  },
  {
    "path": ".gitignore",
    "chars": 565,
    "preview": ".DS_Store\n.vim\n*.log\n*.tsbuildinfo\nlogs.txt\nwikis\ntests/staging\n*.tgz\n*.tsbuildinfo\n.editorconfig\n.gitattributes\ncoverag"
  },
  {
    "path": ".husky/commit-msg",
    "chars": 204,
    "preview": "## .husky/commit-msg\n# yarn commitlint --extends '@commitlint/config-conventional' --edit $1\nyarn commitlint --extends '"
  },
  {
    "path": ".husky/post-checkout",
    "chars": 167,
    "preview": "# Only run yarn install if this was a branch checkout (not file checkout)\n# $3 is 1 for branch checkout, 0 for file chec"
  },
  {
    "path": ".husky/post-merge",
    "chars": 4,
    "preview": "yarn"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 41,
    "preview": "##.husky/pre-commit\nyarn run lint-staged\n"
  },
  {
    "path": ".husky/prepare-commit-msg",
    "chars": 122,
    "preview": "#!/usr/bin/env sh\n# . \"$(dirname -- \"$0\")/_/husky.sh\"\n\ncp \"$1\" \"/tmp/fish-lsp-last-commit-msg-$(date +%Y%m%d-%H%M%S).msg"
  },
  {
    "path": ".nvmrc",
    "chars": 9,
    "preview": "v22.14.0\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 5224,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
  },
  {
    "path": "LICENSE.md",
    "chars": 1071,
    "preview": "Copyright (c) 2022-2025 Nick Donfris and others\n\nPermission is hereby granted, free of charge, to any person obtaining\na"
  },
  {
    "path": "README.md",
    "chars": 45191,
    "preview": "<h1 align=\"center\">\n    <div align=\"center\">\n        <a href=\"https://fish-lsp.dev\">\n            <image src=\"https://raw"
  },
  {
    "path": "SECURITY.md",
    "chars": 1629,
    "preview": "# Security Policy\n\n## Supported Versions\n\n| Version   | Supported          |\n| --------- | ------------------ |\n| >= 1.1"
  },
  {
    "path": "eslint.config.ts",
    "chars": 4414,
    "preview": "// @ts-check\n\nimport eslint from '@eslint/js';\nimport tseslint, { type ConfigArray } from 'typescript-eslint';\nimport st"
  },
  {
    "path": "fish_files/exec.fish",
    "chars": 219,
    "preview": "#!/usr/bin/env fish\n\nstring collect -- $argv | read --tokenize --local cmd\nfish --command \"$cmd\" 2>/dev/null\n# begin\n#  "
  },
  {
    "path": "fish_files/expand_cartesian.fish",
    "chars": 421,
    "preview": "#!/usr/bin/env fish\n\n# Example usage:\n#\n# >_ ./expand_cartisian.fish {a,b,c}/foo/{1,2,3}\n#   1  |a/foo/1|\n#   2  |a/foo/"
  },
  {
    "path": "fish_files/get-autoloaded-filepath.fish",
    "chars": 556,
    "preview": "#!/usr/bin/env fish\n\nargparse --stop-nonopt f/function c/completion m/max=+ -- $argv\nor return \n\nset cmd_name (string sp"
  },
  {
    "path": "fish_files/get-command-options.fish",
    "chars": 529,
    "preview": "#!/usr/bin/env fish\n\nfunction backup_input \n    set -a -l _fish_lsp_file_cmps (fish -c \"complete --do-complete '$argv -'"
  },
  {
    "path": "fish_files/get-completion.fish",
    "chars": 1425,
    "preview": "#!/usr/bin/env fish\n\n##\n# File takes two arguments:\n#       $argv[1] = '1' | '2' | '3'\n#       $argv[2] =  string to be "
  },
  {
    "path": "fish_files/get-dependency.fish",
    "chars": 208,
    "preview": "#!/usr/local/bin/fish\n\n\n\nset -l filepath (functions --all -D \"$argv\" 2>> /dev/null)\n\nswitch $filepath\n    case 'n/a'\n   "
  },
  {
    "path": "fish_files/get-docs.fish",
    "chars": 3255,
    "preview": "#!/usr/bin/env fish\n\n# ┌───────┐\n# │ utils │\n# └───────┘\nfunction __handle_builtin -d 'Retrieve documentation for a fish"
  },
  {
    "path": "fish_files/get-documentation.fish",
    "chars": 1415,
    "preview": "#!/usr/bin/env fish\n\n## commands like mkdir or touch should reach this point \nfunction _flsp_get_command_without_manpage"
  },
  {
    "path": "fish_files/get-fish-autoloaded-paths.fish",
    "chars": 1239,
    "preview": "#!/usr/bin/env fish\n\necho -e \"__fish_bin_dir\\t$(string join ':' -- $__fish_bin_dir)\"\n\necho -e \"__fish_config_dir\\t$(stri"
  },
  {
    "path": "fish_files/get-type-verbose.fish",
    "chars": 1151,
    "preview": "#!/usr/bin/env fish\n\n# takes a single argument and returns a string/token \n# without throwing an error\n\n# possible retur"
  },
  {
    "path": "fish_files/get-type.fish",
    "chars": 760,
    "preview": "#!/usr/bin/env fish\n\nfunction get_type --argument-names str\n    set -l type_result (type -t \"$str\" 2> /dev/null)\n    swi"
  },
  {
    "path": "man/fish-lsp.1",
    "chars": 9412,
    "preview": ".TH \"FISH\\-LSP\" \"1\" \"April 2026\" \"1.1.4-pre.0\" \"fish-lsp\"\n.SH \"NAME\"\n\\fBfish-lsp\\fR \\- A language server for the fish sh"
  },
  {
    "path": "package.json",
    "chars": 8574,
    "preview": "{\n  \"$schema\": \"https://json.schemastore.org/package\",\n  \"author\": \"ndonfris\",\n  \"license\": \"MIT\",\n  \"name\": \"fish-lsp\","
  },
  {
    "path": "renovate.json",
    "chars": 737,
    "preview": "{\n  \"extends\": [\n    \"config:base\",\n    \":prHourlyLimit4\",\n    \":semanticCommitTypeAll(chore)\"\n  ],\n  \"schedule\": [\n    "
  },
  {
    "path": "scripts/build-assets.fish",
    "chars": 4421,
    "preview": "#!/usr/bin/env fish\n\n# Automation script to build all assets for releasing fish-lsp. The files\n# outputted by this scrip"
  },
  {
    "path": "scripts/build-completions.fish",
    "chars": 2053,
    "preview": "#!/usr/bin/env fish\n\nsource ./scripts/fish/pretty-print.fish\n\n# The below if statement is only included because of possi"
  },
  {
    "path": "scripts/build-time",
    "chars": 6561,
    "preview": "#!/usr/bin/env node\n\nconst fs = require('fs');\nconst path = require('path');\n\n// Parse flags\nconst args = process.argv.s"
  },
  {
    "path": "scripts/dev-complete.fish",
    "chars": 1939,
    "preview": "#!/usr/bin/env fish \n\nset -l DIR (status current-filename | path resolve | path dirname)\nsource \"$DIR/fish/pretty-print."
  },
  {
    "path": "scripts/esbuild/cli.ts",
    "chars": 10113,
    "preview": "// Improved CLI argument parsing\nimport { Command } from 'commander';\nimport { BuildTarget, WatchMode, SourcemapMode, VA"
  },
  {
    "path": "scripts/esbuild/colors.ts",
    "chars": 5002,
    "preview": "// ANSI color utilities for terminal output\nimport path from 'path';\nimport process from 'process';\n\n// Helper to conver"
  },
  {
    "path": "scripts/esbuild/configs.ts",
    "chars": 5361,
    "preview": "// Centrfalized build configurations\nimport esbuild from 'esbuild';\nimport { resolve } from 'path';\nimport { createPlugi"
  },
  {
    "path": "scripts/esbuild/file-watcher.ts",
    "chars": 20060,
    "preview": "import { spawn, ChildProcess } from 'child_process';\nimport { colorize, colors, logger } from './colors';\nimport { Watch"
  },
  {
    "path": "scripts/esbuild/index.ts",
    "chars": 1196,
    "preview": "#!/usr/bin/env tsx\n\nimport { parseArgs, showCompletions, showHelp } from \"./cli\";\nimport { pipeline } from './pipeline';"
  },
  {
    "path": "scripts/esbuild/pipeline.ts",
    "chars": 6966,
    "preview": "import { execSync } from 'child_process';\nimport esbuild from 'esbuild';\nimport { BuildArgs } from './cli';\nimport { log"
  },
  {
    "path": "scripts/esbuild/plugins.ts",
    "chars": 16947,
    "preview": "// Build plugin factory for consistent configuration\n\n// ESBuild plugins - these packages don't provide TypeScript defin"
  },
  {
    "path": "scripts/esbuild/types.ts",
    "chars": 5538,
    "preview": "// Build target type definitions for fish-lsp esbuild system\n\n/**\n * Individual build configuration targets that map to "
  },
  {
    "path": "scripts/esbuild/utils.ts",
    "chars": 6687,
    "preview": "// Build utility functions\nimport fs from 'fs-extra';\nimport { existsSync, statSync, unlinkSync } from 'fs';\nimport { ex"
  },
  {
    "path": "scripts/fish/continue-or-exit.fish",
    "chars": 6315,
    "preview": "#!/usr/bin/env fish\n\nset -l DIR (status current-filename | path resolve | path dirname)\nsource \"$DIR/pretty-print.fish\"\n"
  },
  {
    "path": "scripts/fish/pretty-print.fish",
    "chars": 10249,
    "preview": "function reset_color\n    set_color normal\nend\n\nset -gx NORMAL (set_color normal)\nset -gx GREEN (reset_color && set_color"
  },
  {
    "path": "scripts/fish/utils.fish",
    "chars": 4446,
    "preview": "#!/usr/bin/env fish\n\nset -l DIR (status current-filename | path resolve | path dirname)\nsource \"$DIR/continue-or-exit.fi"
  },
  {
    "path": "scripts/fish-commands-scrapper.ts",
    "chars": 22020,
    "preview": "/* eslint-disable no-console  */\nimport { JSDOM } from 'jsdom';\nimport fetch from 'node-fetch';\nimport * as fs from 'fs/"
  },
  {
    "path": "scripts/publish-nightly.fish",
    "chars": 6259,
    "preview": "#!/usr/bin/env fish\n\n# ┌──────────────────────────────┐\n# │ Imported variables/functions │\n# └──────────────────────────"
  },
  {
    "path": "scripts/relink-locally.fish",
    "chars": 2612,
    "preview": "#!/usr/bin/env fish\n\n\n# Relink a globally installed package to the local package\n# that was called by this script. If th"
  },
  {
    "path": "scripts/update-changelog.fish",
    "chars": 874,
    "preview": "#!/usr/bin/env fish\n\nsource ./scripts/fish/pretty-print.fish\nsource ./scripts/fish/continue-or-exit.fish\n\nlog_info '  ' "
  },
  {
    "path": "scripts/update-codeblocks-in-docs.ts",
    "chars": 8124,
    "preview": "#!/usr/bin/env tsx\n\n/**\n * Script to update markdown code blocks based on special HTML comments\n *\n * This script search"
  },
  {
    "path": "scripts/workspace-cli.ts",
    "chars": 14624,
    "preview": "#!/usr/bin/env tsx\n\nimport { Command } from 'commander';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport "
  },
  {
    "path": "src/analyze.ts",
    "chars": 58875,
    "preview": "import * as LSP from 'vscode-languageserver';\nimport { DocumentUri, Hover, Location, Position, SymbolKind, URI, WorkDone"
  },
  {
    "path": "src/cli.ts",
    "chars": 20713,
    "preview": "import './utils/polyfills';\nimport { BuildCapabilityString, PathObj, PackageLspVersion, PackageVersion, accumulateStartu"
  },
  {
    "path": "src/code-actions/action-kinds.ts",
    "chars": 709,
    "preview": "import { CodeActionKind } from 'vscode-languageserver';\n\n// Define our supported code action kinds\nexport const Supporte"
  },
  {
    "path": "src/code-actions/alias-wrapper.ts",
    "chars": 3846,
    "preview": "import * as os from 'os';\nimport { CodeAction, CreateFile, TextDocumentEdit, TextEdit, VersionedTextDocumentIdentifier, "
  },
  {
    "path": "src/code-actions/argparse-completions.ts",
    "chars": 6249,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { findParentFunction, isCommandWithName, isFunctionDefinition, isSt"
  },
  {
    "path": "src/code-actions/code-action-handler.ts",
    "chars": 13445,
    "preview": "import { CodeAction, CodeActionParams, Diagnostic, Range } from 'vscode-languageserver';\nimport { getDisableDiagnosticAc"
  },
  {
    "path": "src/code-actions/combiner.ts",
    "chars": 6189,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { getNamedChildNodes } from '../utils/tree-sitter';\nimport { isCond"
  },
  {
    "path": "src/code-actions/disable-actions.ts",
    "chars": 6627,
    "preview": "// src/code-actions/disable-diagnostics.ts\nimport { CodeAction, Diagnostic, DiagnosticSeverity, TextEdit } from 'vscode-"
  },
  {
    "path": "src/code-actions/quick-fixes.ts",
    "chars": 26441,
    "preview": "import { ChangeAnnotation, CodeAction, Diagnostic, RenameFile, TextEdit, WorkspaceEdit } from 'vscode-languageserver';\ni"
  },
  {
    "path": "src/code-actions/redirect-actions.ts",
    "chars": 4011,
    "preview": "import { TextEdit } from 'vscode-languageserver';\nimport { SyntaxNode } from 'web-tree-sitter';\nimport { LspDocument } f"
  },
  {
    "path": "src/code-actions/refactors.ts",
    "chars": 21689,
    "preview": "import os from 'os';\nimport { ChangeAnnotation, CodeAction, CodeActionKind, CreateFile, Range, TextDocumentEdit, TextEdi"
  },
  {
    "path": "src/code-lens.ts",
    "chars": 1056,
    "preview": "import { CodeLens } from 'vscode-languageserver';\nimport { Analyzer } from './analyze';\nimport { LspDocument } from './d"
  },
  {
    "path": "src/command.ts",
    "chars": 42375,
    "preview": "import { Connection, ExecuteCommandParams, MessageType, /** Position, */ Range, Location, TextEdit, WorkspaceEdit, /** P"
  },
  {
    "path": "src/config.ts",
    "chars": 28052,
    "preview": "import { z } from 'zod';\nimport { Connection, FormattingOptions, InitializeParams, InitializeResult, TextDocumentSyncKin"
  },
  {
    "path": "src/diagnostics/buffered-async-cache.ts",
    "chars": 9094,
    "preview": "import { Diagnostic, DocumentUri } from 'vscode-languageserver';\nimport { analyzer } from '../analyze';\nimport { documen"
  },
  {
    "path": "src/diagnostics/comments-handler.ts",
    "chars": 13595,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { isComment } from '../utils/node-types';\nimport { ErrorCodes } fro"
  },
  {
    "path": "src/diagnostics/diagnostic-ranges.ts",
    "chars": 10824,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { ErrorCodes } from './error-codes';\nimport { config } from '../con"
  },
  {
    "path": "src/diagnostics/error-codes.ts",
    "chars": 11230,
    "preview": "import { CodeDescription, DiagnosticSeverity } from 'vscode-languageserver';\n\nexport namespace ErrorCodes {\n\n  export co"
  },
  {
    "path": "src/diagnostics/invalid-error-code.ts",
    "chars": 2940,
    "preview": "import { Diagnostic } from 'vscode-languageserver';\nimport { SyntaxNode } from 'web-tree-sitter';\nimport { ErrorCodes } "
  },
  {
    "path": "src/diagnostics/missing-completions.ts",
    "chars": 7994,
    "preview": "import { Diagnostic, Location } from 'vscode-languageserver';\nimport { analyzer } from '../analyze';\nimport { LspDocumen"
  },
  {
    "path": "src/diagnostics/no-execute-diagnostic.ts",
    "chars": 3298,
    "preview": "// import { spawnSync } from 'child_process';\nimport { LspDocument } from '../document';\nimport { Diagnostic, Diagnostic"
  },
  {
    "path": "src/diagnostics/node-types.ts",
    "chars": 22539,
    "preview": "import Parser, { SyntaxNode } from 'web-tree-sitter';\nimport { findParentCommand, hasParent, isCommand, isCommandName, i"
  },
  {
    "path": "src/diagnostics/types.ts",
    "chars": 1829,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { Diagnostic } from 'vscode-languageserver-protocol';\nimport { Erro"
  },
  {
    "path": "src/diagnostics/validate.ts",
    "chars": 25073,
    "preview": "import { Diagnostic, DiagnosticRelatedInformation, Range } from 'vscode-languageserver';\nimport { SyntaxNode } from 'web"
  },
  {
    "path": "src/document-highlight.ts",
    "chars": 2351,
    "preview": "import { Analyzer } from './analyze';\nimport { getRange } from './utils/tree-sitter';\nimport { DocumentHighlight, Docume"
  },
  {
    "path": "src/document.ts",
    "chars": 18585,
    "preview": "import * as path from 'path';\nimport { homedir } from 'os';\nimport { promises } from 'fs';\nimport { TextDocument } from "
  },
  {
    "path": "src/documentation.ts",
    "chars": 14201,
    "preview": "import { dirname } from 'path';\nimport { SyntaxNode } from 'web-tree-sitter';\nimport { Hover, MarkupContent, MarkupKind "
  },
  {
    "path": "src/execute-handler.ts",
    "chars": 6270,
    "preview": "import { Connection } from 'vscode-languageserver';\nimport { exec } from 'child_process';\nimport { execAsyncFish } from "
  },
  {
    "path": "src/formatting.ts",
    "chars": 9817,
    "preview": "import { exec } from 'child_process';\nimport { logger } from './logger';\nimport { LspDocument } from './document';\nimpor"
  },
  {
    "path": "src/hover.ts",
    "chars": 10435,
    "preview": "import * as LSP from 'vscode-languageserver';\nimport { Hover, MarkupKind } from 'vscode-languageserver-protocol/node';\ni"
  },
  {
    "path": "src/inlay-hints.ts",
    "chars": 6376,
    "preview": "import { InlayHint, InlayHintKind } from 'vscode-languageserver';\nimport { SyntaxNode } from 'web-tree-sitter';\nimport {"
  },
  {
    "path": "src/linked-editing.ts",
    "chars": 2007,
    "preview": "import { LinkedEditingRanges, Position, Range } from 'vscode-languageserver';\nimport { LspDocument } from './document';\n"
  },
  {
    "path": "src/logger.ts",
    "chars": 12159,
    "preview": "import * as console from 'node:console';\nimport fs from 'fs';\nimport { config } from './config';\n\nexport interface ICons"
  },
  {
    "path": "src/main.ts",
    "chars": 1796,
    "preview": "#!/usr/bin/env node\n\n// Enable source map support for better stack traces\nimport 'source-map-support/register';\n\n// Univ"
  },
  {
    "path": "src/parser.ts",
    "chars": 1708,
    "preview": "import Parser from 'web-tree-sitter';\nimport treeSitterWasmPath from 'web-tree-sitter/tree-sitter.wasm';\nimport fishLang"
  },
  {
    "path": "src/parsing/alias.ts",
    "chars": 9654,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { FishSymbol } from './symbol';\nimport { DefinitionScope, getScope "
  },
  {
    "path": "src/parsing/argparse.ts",
    "chars": 17466,
    "preview": "import path, { dirname } from 'path';\nimport { SyntaxNode } from 'web-tree-sitter';\nimport { FishSymbol } from './symbol"
  },
  {
    "path": "src/parsing/barrel.ts",
    "chars": 6355,
    "preview": "import * as SetParser from './set';\nimport * as ReadParser from './read';\nimport * as ForParser from './for';\nimport * a"
  },
  {
    "path": "src/parsing/bind.ts",
    "chars": 1882,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { findOptions, Option } from './options';\nimport { findParentComman"
  },
  {
    "path": "src/parsing/comments.ts",
    "chars": 2875,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { isComment } from '../utils/node-types';\nimport { analyzer } from "
  },
  {
    "path": "src/parsing/complete.ts",
    "chars": 14707,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { isCommand, isCommandWithName, isOption, isString } from '../utils"
  },
  {
    "path": "src/parsing/emit.ts",
    "chars": 4206,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { isCommandWithName, isFunctionDefinition } from '../utils/node-typ"
  },
  {
    "path": "src/parsing/equality-utils.ts",
    "chars": 8301,
    "preview": "import { Location, Position, Range } from 'vscode-languageserver';\nimport { SyntaxNode } from 'web-tree-sitter';\nimport "
  },
  {
    "path": "src/parsing/export.ts",
    "chars": 6616,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { Range } from 'vscode-languageserver';\nimport { isCommandWithName,"
  },
  {
    "path": "src/parsing/for.ts",
    "chars": 1841,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { FishSymbol } from './symbol';\nimport { DefinitionScope } from '.."
  },
  {
    "path": "src/parsing/function.ts",
    "chars": 9405,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { findOptionsSet, Option, OptionValueMatch } from './options';\nimpo"
  },
  {
    "path": "src/parsing/inline-variable.ts",
    "chars": 5241,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { isCommand, isCommandName } from '../utils/node-types';\nimport { F"
  },
  {
    "path": "src/parsing/nested-strings.ts",
    "chars": 12498,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { DocumentUri, Range, Location } from 'vscode-languageserver';\nimpo"
  },
  {
    "path": "src/parsing/options.ts",
    "chars": 13534,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { isLongOption, isOption, isShortOption } from '../utils/node-types"
  },
  {
    "path": "src/parsing/read.ts",
    "chars": 7106,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { Option, isMatchingOption, findMatchingOptions, findOptionsSet } f"
  },
  {
    "path": "src/parsing/reference-comparator.ts",
    "chars": 10092,
    "preview": "import * as Locations from '../utils/locations';\nimport { SyntaxNode } from 'web-tree-sitter';\nimport { FishSymbol } fro"
  },
  {
    "path": "src/parsing/set.ts",
    "chars": 6855,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { isOption, isCommandWithName, isTopLevelDefinition, findParentComm"
  },
  {
    "path": "src/parsing/source.ts",
    "chars": 6928,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { findParentFunction, isCommandWithName, isFunctionDefinition, isPr"
  },
  {
    "path": "src/parsing/string.ts",
    "chars": 4096,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\n\n/**\n * Resolves a single fish shell escape sequence token to its characte"
  },
  {
    "path": "src/parsing/symbol-converters.ts",
    "chars": 4304,
    "preview": "import { DocumentSymbol, WorkspaceSymbol, Location, FoldingRange, FoldingRangeKind, MarkupContent, MarkupKind, Hover, Do"
  },
  {
    "path": "src/parsing/symbol-detail.ts",
    "chars": 9969,
    "preview": "import { SymbolKind } from 'vscode-languageserver';\nimport { FishSymbol, fishSymbolKindToSymbolKind } from './symbol';\ni"
  },
  {
    "path": "src/parsing/symbol-kinds.ts",
    "chars": 4221,
    "preview": "import { SymbolKind, Range } from 'vscode-languageserver';\nimport { FishSymbol } from './symbol';\nimport { Option } from"
  },
  {
    "path": "src/parsing/symbol-modifiers.ts",
    "chars": 4271,
    "preview": "import { SetOptions } from './set';\nimport { ReadOptions } from './read';\nimport { ArgparseOptions } from './argparse';\n"
  },
  {
    "path": "src/parsing/symbol.ts",
    "chars": 28386,
    "preview": "import { DocumentSymbol, SymbolKind, WorkspaceSymbol, Location, FoldingRange, MarkupContent, Hover, DocumentUri, Positio"
  },
  {
    "path": "src/parsing/unreachable.ts",
    "chars": 13221,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { isCommand, isReturn, isSwitchStatement, isCaseClause, isIfStateme"
  },
  {
    "path": "src/parsing/values.ts",
    "chars": 2990,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { FishSymbol } from './symbol';\nimport { isMatchingOption, isString"
  },
  {
    "path": "src/references.ts",
    "chars": 29424,
    "preview": "import { DocumentUri, Location, Position, Range, WorkDoneProgressReporter } from 'vscode-languageserver';\nimport { analy"
  },
  {
    "path": "src/renames.ts",
    "chars": 3944,
    "preview": "import { getReferences } from './references';\nimport { analyzer, Analyzer } from './analyze';\nimport { Position, Range }"
  },
  {
    "path": "src/selection-range.ts",
    "chars": 2957,
    "preview": "import { SelectionRange, Position } from 'vscode-languageserver';\nimport { SyntaxNode } from 'web-tree-sitter';\nimport {"
  },
  {
    "path": "src/semantic-tokens.ts",
    "chars": 16694,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { analyzer, EnsuredAnalyzeDocument } from './analyze';\nimport * as "
  },
  {
    "path": "src/server.ts",
    "chars": 46785,
    "preview": "// Import polyfills for Node.js 18 compatibility\nimport './utils/polyfills';\n// Initialize virtual filesystem (must be b"
  },
  {
    "path": "src/signature.ts",
    "chars": 16930,
    "preview": "import {\n  MarkupContent,\n  MarkupKind,\n  ParameterInformation,\n  Position,\n  SignatureHelp,\n  SignatureInformation,\n  S"
  },
  {
    "path": "src/snippets/envVariables.json",
    "chars": 4139,
    "preview": "[\n  {\n    \"name\": \"_\",\n    \"description\": \"the name of the currently running command (though this is deprecated, and the"
  },
  {
    "path": "src/snippets/fishlspEnvVariables.json",
    "chars": 10860,
    "preview": "[\n  {\n    \"name\": \"fish_lsp_enabled_handlers\",\n    \"description\": \"Enables the fish-lsp handlers. By default, all stable"
  },
  {
    "path": "src/snippets/functions.json",
    "chars": 49383,
    "preview": "[\n  {\n    \"name\": \"__fish_any_arg_in\",\n    \"file\": \"$__fish_data_dir/functions/__fish_any_arg_in.fish\",\n    \"flags\": []\n"
  },
  {
    "path": "src/snippets/helperCommands.json",
    "chars": 10971,
    "preview": "[\n  {\n    \"name\": \"_\",\n    \"description\": \"call fish’s translations\"\n  },\n  {\n    \"name\": \"abbr\",\n    \"description\": \"ma"
  },
  {
    "path": "src/snippets/localeVariables.json",
    "chars": 1918,
    "preview": "[\n{\n\t\"name\": \"LANG\",\n\t\"description\": \"This is the typical environment variable for specifying a locale. A user may set t"
  },
  {
    "path": "src/snippets/pipesAndRedirects.json",
    "chars": 2287,
    "preview": "[ \n  {\n    \"name\": \">\",\n    \"description\" : \"To write standard output to a file, use >DESTINATION\"\n  }, \n  {\n    \"name\":"
  },
  {
    "path": "src/snippets/specialFishVariables.json",
    "chars": 5162,
    "preview": "[\n  {\n    \"name\": \"PATH\",\n    \"description\": \"A list of directories in which to search for commands. This is a common un"
  },
  {
    "path": "src/snippets/statusNumbers.json",
    "chars": 1312,
    "preview": "[\n  {\n    \"name\": \"0\",\n    \"description\": \"0 is generally the exit status of commands if they successfully performed the"
  },
  {
    "path": "src/snippets/syntaxHighlightingVariables.json",
    "chars": 4134,
    "preview": "[\n  {\n    \"name\": \"fish_color_normal\",\n    \"description\": \"default color\"\n  },\n  {\n    \"name\": \"fish_color_command\",\n   "
  },
  {
    "path": "src/utils/builtins.ts",
    "chars": 4041,
    "preview": "import { spawnSync, SpawnSyncOptionsWithStringEncoding } from 'child_process';\n\nexport const BuiltInList = [\n  '!',\n  '."
  },
  {
    "path": "src/utils/cli-dump-tree.ts",
    "chars": 21229,
    "preview": "import { LspDocument } from '../document';\nimport { Analyzer, analyzer } from '../analyze';\nimport { logger } from '../l"
  },
  {
    "path": "src/utils/commander-cli-subcommands.ts",
    "chars": 41971,
    "preview": "import chalk from 'chalk';\nimport fs, { readFileSync, existsSync } from 'fs';\nimport { homedir } from 'os';\nimport path,"
  },
  {
    "path": "src/utils/completion/comment-completions.ts",
    "chars": 3393,
    "preview": "import { Command, Position, Range, TextEdit } from 'vscode-languageserver';\nimport { FishCommandCompletionItem, FishComp"
  },
  {
    "path": "src/utils/completion/documentation.ts",
    "chars": 7195,
    "preview": "import { MarkupContent } from 'vscode-languageserver';\nimport { FishCompletionItem, FishCompletionItemKind, CompletionEx"
  },
  {
    "path": "src/utils/completion/inline-parser.ts",
    "chars": 7953,
    "preview": "import Parser, { SyntaxNode } from 'web-tree-sitter';\nimport { initializeParser } from '../../parser';\nimport { getChild"
  },
  {
    "path": "src/utils/completion/list.ts",
    "chars": 4145,
    "preview": "import { FishCompletionData, FishCompletionItem, toCompletionItemKind } from './types';\nimport { FishSymbol } from '../."
  },
  {
    "path": "src/utils/completion/pager.ts",
    "chars": 17739,
    "preview": "import { FishSymbol } from '../../parsing/symbol';\nimport { FishCompletionItem } from './types';\nimport { execCompleteLi"
  },
  {
    "path": "src/utils/completion/shell.ts",
    "chars": 1436,
    "preview": "import { execAsync } from '../exec';\n\nexport function escapeCmd(cmd: string): string {\n  return cmd\n    .replace(/\\\\/g, "
  },
  {
    "path": "src/utils/completion/startup-cache.ts",
    "chars": 4699,
    "preview": "import { FishCompletionItem, FishCompletionItemKind } from './types';\nimport { StaticItems } from './static-items';\nimpo"
  },
  {
    "path": "src/utils/completion/startup-config.ts",
    "chars": 3189,
    "preview": "import { config } from '../../config';\nimport { FishCompletionItemKind } from './types';\n\nexport type SetupItem = {\n  co"
  },
  {
    "path": "src/utils/completion/static-items.ts",
    "chars": 26432,
    "preview": "import { CompletionItemKind } from 'vscode-languageserver';\nimport { ErrorCodes } from '../../diagnostics/error-codes';\n"
  },
  {
    "path": "src/utils/completion/types.ts",
    "chars": 7142,
    "preview": "import {\n  CompletionContext,\n  CompletionItem,\n  CompletionItemKind, MarkupContent,\n  Position, Range,\n  SymbolKind,\n  "
  },
  {
    "path": "src/utils/definition-scope.ts",
    "chars": 8691,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport * as NodeTypes from './node-types';\nimport { isAutoloadedUriLoadsAl"
  },
  {
    "path": "src/utils/documentation-cache.ts",
    "chars": 13353,
    "preview": "import { SymbolKind, MarkupContent } from 'vscode-languageserver';\nimport { execCmd, execCommandDocs, execEscapedCommand"
  },
  {
    "path": "src/utils/env-manager.ts",
    "chars": 9024,
    "preview": "import path from 'path';\nimport { Config } from '../config';\nimport { AutoloadedPathVariables } from './process-env';\nim"
  },
  {
    "path": "src/utils/exec.ts",
    "chars": 9792,
    "preview": "import { spawn, exec, execFile, execFileSync } from 'child_process';\nimport { promisify } from 'util';\nimport { logger }"
  },
  {
    "path": "src/utils/file-operations.ts",
    "chars": 9427,
    "preview": "import { PathLike, accessSync, appendFileSync, closeSync, constants, existsSync, mkdirSync, openSync, readFileSync, stat"
  },
  {
    "path": "src/utils/flag-documentation.ts",
    "chars": 4592,
    "preview": "import { MarkupContent, MarkupKind } from 'vscode-languageserver-protocol/node';\nimport { execCommandDocs, execCompleteL"
  },
  {
    "path": "src/utils/flatten.ts",
    "chars": 1769,
    "preview": "/**\n * ___Example types for flattening include:___ \\`SyntaxNode\\`, \\`FishDocumentSymbol\\`, and \\`DocumentSymbol\\`\n *\n * "
  },
  {
    "path": "src/utils/get-lsp-completions.ts",
    "chars": 36569,
    "preview": "import { Command } from 'commander';\nimport os from 'os';\nimport { Config, validHandlers } from '../config';\nimport { Pk"
  },
  {
    "path": "src/utils/health-check.ts",
    "chars": 9467,
    "preview": "import * as fs from 'fs';\nimport * as path from 'path';\nimport { config } from '../config';\nimport { logger } from '../l"
  },
  {
    "path": "src/utils/locations.ts",
    "chars": 4714,
    "preview": "// https://github.com/typescript-language-server/typescript-language-server/blob/5a39c1f801ab0cad725a2b8711c0e0d46606a08"
  },
  {
    "path": "src/utils/markdown-builder.ts",
    "chars": 3650,
    "preview": "import { MarkupContent, MarkupKind } from 'vscode-languageserver';\n\n/**\n * Utility function namespace\n */\n\nexport namesp"
  },
  {
    "path": "src/utils/maybe.ts",
    "chars": 2457,
    "preview": "/**\n * Optional/Maybe monad for null-safe operations and functional composition\n *\n * Provides a way to safely chain ope"
  },
  {
    "path": "src/utils/node-types.ts",
    "chars": 28641,
    "preview": "import { SyntaxNode } from 'web-tree-sitter';\nimport { getLeafNodes } from './tree-sitter';\nimport { isDefinitionName, i"
  },
  {
    "path": "src/utils/path-resolution.ts",
    "chars": 5082,
    "preview": "import path, { resolve, dirname } from 'path';\nimport { realpathSync } from 'fs';\nimport { vfs } from '../virtual-fs';\ni"
  },
  {
    "path": "src/utils/polyfills.ts",
    "chars": 1944,
    "preview": "// Polyfills for array methods missing in Node.js 18\n// These methods were added in later versions of Node.js/JavaScript"
  },
  {
    "path": "src/utils/process-env.ts",
    "chars": 6340,
    "preview": "import { join } from 'path';\nimport { existsSync } from 'fs';\nimport { PrebuiltDocumentationMap } from './snippets';\nimp"
  },
  {
    "path": "src/utils/progress-notification.ts",
    "chars": 4769,
    "preview": "import { connection } from './startup';\nimport { config } from '../config';\nimport { WorkDoneProgressReporter } from 'vs"
  },
  {
    "path": "src/utils/semantics.ts",
    "chars": 18541,
    "preview": "import {\n  SemanticTokensLegend,\n  Range,\n  Position,\n} from 'vscode-languageserver';\nimport { SyntaxNode } from 'web-tr"
  },
  {
    "path": "src/utils/snippets.ts",
    "chars": 13237,
    "preview": "import helperCommandsJson from '../snippets/helperCommands.json';\nimport themeVariablesJson from '../snippets/syntaxHigh"
  },
  {
    "path": "src/utils/startup.ts",
    "chars": 26448,
    "preview": "import * as path from 'path';\nimport * as os from 'os';\nimport * as net from 'net';\nimport { execSync } from 'child_proc"
  },
  {
    "path": "src/utils/symbol-documentation-builder.ts",
    "chars": 4057,
    "preview": "import os from 'os';\nimport { SymbolKind } from 'vscode-languageserver';\nimport { SyntaxNode } from 'web-tree-sitter';\ni"
  },
  {
    "path": "src/utils/translation.ts",
    "chars": 12806,
    "preview": "import { DocumentSymbol, DocumentUri, SelectionRange, SymbolInformation, SymbolKind, TextDocumentItem } from 'vscode-lan"
  },
  {
    "path": "src/utils/tree-sitter.ts",
    "chars": 22730,
    "preview": "import { extname } from 'path';\nimport { Position, Range, URI } from 'vscode-languageserver';\nimport { Point, SyntaxNode"
  },
  {
    "path": "src/utils/workspace-manager.ts",
    "chars": 22234,
    "preview": "import { DocumentUri, WorkDoneProgressServerReporter, WorkspaceFoldersChangeEvent } from 'vscode-languageserver';\nimport"
  },
  {
    "path": "src/utils/workspace.ts",
    "chars": 21512,
    "preview": "import * as fastGlob from 'fast-glob';\nimport fs from 'fs';\nimport path, { basename, dirname, join } from 'path';\nimport"
  },
  {
    "path": "src/virtual-fs.ts",
    "chars": 12798,
    "preview": "import * as fs from 'fs';\nimport path, { resolve, join } from 'path';\nimport { existsSync, writeFileSync, unlinkSync } f"
  },
  {
    "path": "src/web.ts",
    "chars": 2313,
    "preview": "// Import polyfills for browser/Node.js compatibility\nimport './utils/polyfills';\nimport { createConnection, BrowserMess"
  },
  {
    "path": "tests/alias-conversion.test.ts",
    "chars": 4749,
    "preview": "import { Diagnostic } from 'vscode-languageserver';\nimport { initializeParser } from '../src/parser';\nimport { createAli"
  },
  {
    "path": "tests/analyze-functions.test.ts",
    "chars": 3063,
    "preview": "import * as Parser from 'web-tree-sitter';\nimport { getChildNodes, getRange } from '../src/utils/tree-sitter';\nimport { "
  },
  {
    "path": "tests/analyzer.test.ts",
    "chars": 8871,
    "preview": "import { setLogger, createFakeLspDocument } from './helpers';\nimport { initializeParser } from '../src/parser';\n/* @ts-i"
  },
  {
    "path": "tests/cli.test.ts",
    "chars": 17280,
    "preview": "import { accumulateStartupOptions } from '../src/utils/commander-cli-subcommands';\nimport { validHandlers } from '../src"
  },
  {
    "path": "tests/code-action.test.ts",
    "chars": 22009,
    "preview": "import * as os from 'os';\nimport * as Parser from 'web-tree-sitter';\nimport { containsRange, findEnclosingScope, getChil"
  },
  {
    "path": "tests/comments-handler.test.ts",
    "chars": 8887,
    "preview": "import { DiagnosticCommentsHandler, isDiagnosticComment, parseDiagnosticComment } from '../src/diagnostics/comments-hand"
  },
  {
    "path": "tests/complete-symbol.test.ts",
    "chars": 11445,
    "preview": "import { initializeParser } from '../src/parser';\nimport { createTestWorkspace, setLogger, locationAsString, fakeDocumen"
  },
  {
    "path": "tests/completion-shell.test.ts",
    "chars": 12418,
    "preview": "import { setLogger } from './helpers';\nimport { escapeCmd, shellComplete } from '../src/utils/completion/shell';\n\ndescri"
  },
  {
    "path": "tests/completion-startup-config.test.ts",
    "chars": 11565,
    "preview": "import { runSetupItems, SetupItem, SetupItemsFromCommandConfig } from '../src/utils/completion/startup-config';\nimport {"
  },
  {
    "path": "tests/completion-variable-expansion.test.ts",
    "chars": 8536,
    "preview": "import { CompletionParams, InsertReplaceEdit, TextEdit, Range, CompletionItem } from 'vscode-languageserver';\nimport { c"
  },
  {
    "path": "tests/conditional-execution-diagnostics.test.ts",
    "chars": 14399,
    "preview": "import { analyzer, Analyzer } from '../src/analyze';\nimport { initializeParser } from '../src/parser';\nimport * as Parse"
  },
  {
    "path": "tests/definition-location.test.ts",
    "chars": 13363,
    "preview": "import * as os from 'os';\nimport * as Parser from 'web-tree-sitter';\nimport { analyzer, Analyzer } from '../src/analyze'"
  },
  {
    "path": "tests/diagnostics-with-missing-completions.test.ts",
    "chars": 5340,
    "preview": "import * as os from 'os';\nimport * as fs from 'fs';\nimport { findAllMissingArgparseFlags } from '../src/diagnostics/miss"
  },
  {
    "path": "tests/diagnostics.test.ts",
    "chars": 40217,
    "preview": "import * as os from 'os';\nimport { homedir } from 'os';\nimport * as Parser from 'web-tree-sitter';\nimport { SyntaxNode, "
  },
  {
    "path": "tests/document-highlights.test.ts",
    "chars": 6138,
    "preview": "import { createFakeLspDocument, setLogger } from './helpers';\nimport { analyzer, Analyzer } from '../src/analyze';\nimpor"
  },
  {
    "path": "tests/document-test-helpers.ts",
    "chars": 4167,
    "preview": "/**\n * Test helpers for working with the TextDocuments singleton in tests.\n *\n * The new TextDocuments implementation fr"
  },
  {
    "path": "tests/document.test.ts",
    "chars": 11273,
    "preview": "import { documents, LspDocument } from '../src/document';\nimport { resolveLspDocumentForHelperTestFile } from './helpers"
  },
  {
    "path": "tests/embedded-functions-resolution.test.ts",
    "chars": 7748,
    "preview": "import { Analyzer, analyzer } from '../src/analyze';\nimport { LspDocument } from '../src/document';\nimport { nodesGen, p"
  },
  {
    "path": "tests/example-test-workspace-usage.test.ts",
    "chars": 10163,
    "preview": "import { workspaceManager } from '../src/utils/workspace-manager';\nimport { setLogger } from './helpers';\nimport { TestW"
  },
  {
    "path": "tests/exec.test.ts",
    "chars": 10464,
    "preview": "\nimport { setLogger } from './helpers';\n\nimport * as path from 'path';\nimport {\n  execEscapedCommand,\n  execCmd,\n  execC"
  },
  {
    "path": "tests/execute-handler.test.ts",
    "chars": 3542,
    "preview": "\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { buildOutput, execEntireBuffer, sourceF"
  },
  {
    "path": "tests/file-operations.test.ts",
    "chars": 22638,
    "preview": "import { SyncFileHelper, AsyncFileHelper } from '../src/utils/file-operations';\nimport { homedir } from 'os';\nimport { j"
  },
  {
    "path": "tests/fish-symbol-fast-check.test.ts",
    "chars": 36940,
    "preview": "import { describe, it, expect, beforeAll } from 'vitest';\nimport * as fc from 'fast-check';\nimport { SyntaxNode, Tree } "
  },
  {
    "path": "tests/fish-symbol.test.ts",
    "chars": 49122,
    "preview": "import * as os from 'os';\nimport { filterLastPerScopeSymbol, findLocalLocations, FishSymbol, processNestedTree } from '."
  },
  {
    "path": "tests/fish-syntax-node.test.ts",
    "chars": 6939,
    "preview": "import * as Parser from 'web-tree-sitter';\nimport { SyntaxNode } from 'web-tree-sitter';\n// import {getReturnSiblings} f"
  },
  {
    "path": "tests/fish_files/__fish_complete_docutils.fish",
    "chars": 10154,
    "preview": "function __fish_complete_docutils -d \"Completions for Docutils common options\" -a cmd\n    complete -x -c $cmd -k -a \"\n  "
  },
  {
    "path": "tests/fish_files/__fish_complete_gpg.fish",
    "chars": 38074,
    "preview": "#\n# Completions for the gpg program.\n#\n# This program accepts an rather large number of switches. It allows\n# you to do "
  },
  {
    "path": "tests/fish_files/__fish_config_interactive.fish",
    "chars": 12878,
    "preview": "#\n# Initializations that should only be performed when entering interactive mode.\n#\n# This function is called by the __f"
  }
]

// ... and 116 more files (download for full content)

About this extraction

This page contains the full source code of the ndonfris/fish-lsp GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 316 files (2.8 MB), approximately 742.8k tokens, and a symbol index with 2128 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!