Merge remote-tracking branch 'origin/master' into goto_next_reference

pull/6465/head
Anthony Templeton 1 year ago
commit 45af0e9b76

@ -55,6 +55,16 @@ body:
placeholder: wezterm 20220101-133340-7edc5b5a
validations:
required: true
- type: input
id: installation-method
attributes:
label: Installation Method
description: >
How you installed Helix - from a package manager like Homebrew or the
AUR, built from source, downloaded a binary from the releases page, etc.
placeholder: "source / brew / nixpkgs / flake / releases page"
validations:
required: true
- type: input
id: helix-version
attributes:

@ -22,6 +22,8 @@ jobs:
override: true
- uses: Swatinem/rust-cache@v2
with:
shared-key: "build"
- name: Run cargo check
run: cargo check
@ -40,6 +42,8 @@ jobs:
uses: dtolnay/rust-toolchain@1.65
- uses: Swatinem/rust-cache@v2
with:
shared-key: "build"
- name: Cache test tree-sitter grammar
uses: actions/cache@v3
@ -71,6 +75,8 @@ jobs:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
with:
shared-key: "build"
- name: Run cargo fmt
run: cargo fmt --all --check
@ -94,6 +100,8 @@ jobs:
uses: dtolnay/rust-toolchain@1.65
- uses: Swatinem/rust-cache@v2
with:
shared-key: "build"
- name: Validate queries
run: cargo xtask query-check

@ -26,16 +26,16 @@ jobs:
OUTDIR=$(basename ${{ github.ref }})
echo "OUTDIR=$OUTDIR" >> $GITHUB_ENV
- name: Deploy
- name: Deploy stable
uses: peaceiris/actions-gh-pages@v3
if: startswith(github.ref, 'refs/tags/')
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./book/book
destination_dir: ./${{ env.OUTDIR }}
- name: Deploy stable
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
if: startswith(github.ref, 'refs/tags/')
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./book/book
destination_dir: ./${{ env.OUTDIR }}

@ -70,11 +70,11 @@ jobs:
rust: stable
target: aarch64-unknown-linux-gnu
cross: true
- build: riscv64-linux
os: ubuntu-latest
rust: stable
target: riscv64gc-unknown-linux-gnu
cross: true
# - build: riscv64-linux
# os: ubuntu-latest
# rust: stable
# target: riscv64gc-unknown-linux-gnu
# cross: true
- build: x86_64-macos
os: macos-latest
rust: stable

@ -1,3 +1,263 @@
# 23.10 (2023-10-24)
A big shout out to all the contributors! We had 118 contributors in this release.
Breaking changes:
- Support multiple language servers per language ([#2507](https://github.com/helix-editor/helix/pull/2507))
- This is a breaking change to language configuration
Features:
- Support multiple language servers per language ([#2507](https://github.com/helix-editor/helix/pull/2507), [#7082](https://github.com/helix-editor/helix/pull/7082), [#7286](https://github.com/helix-editor/helix/pull/7286), [#8374](https://github.com/helix-editor/helix/pull/8374))
- Add a statusline element for the selected register ([#7222](https://github.com/helix-editor/helix/pull/7222))
- Add `%`, `#`, `.`, `*` and `+` special registers ([#6985](https://github.com/helix-editor/helix/pull/6985))
- Add initial support for LSP DidChangeWatchedFiles notifications ([#7665](https://github.com/helix-editor/helix/pull/7665))
- Search buffer contents in `global_search` ([#5652](https://github.com/helix-editor/helix/pull/5652))
- Add a "smart tab" command that intelligently jumps the cursor on tab ([#4443](https://github.com/helix-editor/helix/pull/4443))
- Add a statusline element for whether a file is read-only ([#7222](https://github.com/helix-editor/helix/pull/7222), [#7875](https://github.com/helix-editor/helix/pull/7875))
- Syntax highlight regex prompts ([#7738](https://github.com/helix-editor/helix/pull/7738))
- Allow defining alignment in indent queries ([#5355](https://github.com/helix-editor/helix/pull/5355))
- Show visual feedback in `surround_replace` ([#7588](https://github.com/helix-editor/helix/pull/7588))
- Switch to Nucleo for fuzzy matching ([#7814](https://github.com/helix-editor/helix/pull/7814), [#8148](https://github.com/helix-editor/helix/pull/8148), [#8192](https://github.com/helix-editor/helix/pull/8192), [#8194](https://github.com/helix-editor/helix/pull/8194))
- Insert a trailing newline on write ([#8157](https://github.com/helix-editor/helix/pull/8157))
- Add a `-w`/`--working-dir` CLI flag for specifying a working directory on startup ([#8223](https://github.com/helix-editor/helix/pull/8223), [#8498](https://github.com/helix-editor/helix/pull/8498), [#8520](https://github.com/helix-editor/helix/pull/8520))
- Accept a `+N` CLI argument to set the first file's line number ([#8521](https://github.com/helix-editor/helix/pull/8521))
- Accept Helix-specific ignore files in `.helix/ignore` and `~/.config/helix/ignore` ([#8099](https://github.com/helix-editor/helix/pull/8099))
Commands:
- `merge_selections` (`A-minus`) - merge all selections into one selection that covers all ranges ([#7053](https://github.com/helix-editor/helix/pull/7053))
- `move_prev_long_word_end` and `extend_prev_long_word_end` - move/extend to the end of the previous WORD ([#6905](https://github.com/helix-editor/helix/pull/6905))
- `reverse_selection_contents` - swaps the values of each selection so they are reversed ([#7329](https://github.com/helix-editor/helix/pull/7329))
- Add `:rl` and `:rla` aliases for `:reload` and `:reload-all` ([#7158](https://github.com/helix-editor/helix/pull/7158))
- `yank_joined` - join the selections and yank to the selected register ([#7195](https://github.com/helix-editor/helix/pull/7195))
- `:write-all!` (`:wa!`) - forcibly write all buffers to disk and create any necessary subdirectories ([#7577](https://github.com/helix-editor/helix/pull/7577))
- `:redraw` - clear re-render the UI ([#6949](https://github.com/helix-editor/helix/pull/6949))
- `:tree-sitter-highlight-name` - show the theme scope name of the highlight under the cursor ([#8170](https://github.com/helix-editor/helix/pull/8170))
Usability improvements:
- Allow cycling option values at runtime ([#4411](https://github.com/helix-editor/helix/pull/4411), [#7240](https://github.com/helix-editor/helix/pull/7240), [#7877](https://github.com/helix-editor/helix/pull/7877))
- Exit gracefully on termination signals ([#7236](https://github.com/helix-editor/helix/pull/7236))
- Add plaintext matching fallback to tree-sitter pair matching ([#4288](https://github.com/helix-editor/helix/pull/4288))
- Persist register selection in pending keymaps ([0e08349](https://github.com/helix-editor/helix/commit/0e08349))
- Propagate the count and register to command palette commands ([b394997](https://github.com/helix-editor/helix/commit/b394997))
- Auto indent on `insert_at_line_start` ([#5837](https://github.com/helix-editor/helix/pull/5837))
- Add a config option to control whether LSP completions are automatically inserted on preview ([#7189](https://github.com/helix-editor/helix/pull/7189))
- Add a config option for default line endings ([#5621](https://github.com/helix-editor/helix/pull/5621), [#7357](https://github.com/helix-editor/helix/pull/7357))
- Allow ANSI colors in themes ([#5119](https://github.com/helix-editor/helix/pull/5119))
- Match pairs that don't form a standalone tree-sitter node ([#7242](https://github.com/helix-editor/helix/pull/7242))
- Allow indent sizes of up to 16 columns ([#7429](https://github.com/helix-editor/helix/pull/7429))
- Improve performance of mapping positions through changes ([#7408](https://github.com/helix-editor/helix/pull/7408), [8d39a81](https://github.com/helix-editor/helix/commit/8d39a81), [#7471](https://github.com/helix-editor/helix/pull/7471))
- Mark buffers created from stdin as modified ([#7431](https://github.com/helix-editor/helix/pull/7431))
- Forcibly shut down uninitialized language servers ([#7449](https://github.com/helix-editor/helix/pull/7449))
- Add filename completer for shell prompts ([#7569](https://github.com/helix-editor/helix/pull/7569))
- Allow binding F13-F24 ([#7672](https://github.com/helix-editor/helix/pull/7672))
- Resolve LSP code actions ([#7677](https://github.com/helix-editor/helix/pull/7677), [#8421](https://github.com/helix-editor/helix/pull/8421))
- Save an undo checkpoint before accepting completions ([#7747](https://github.com/helix-editor/helix/pull/7747))
- Include gitignored files in debugger completions ([#7936](https://github.com/helix-editor/helix/pull/7936))
- Make editor remember the last search register ([#5244](https://github.com/helix-editor/helix/pull/5244))
- Open directories with `goto_file` ([#7909](https://github.com/helix-editor/helix/pull/7909))
- Use relative path to open buffer in `goto_file` (`gf`) ([#7965](https://github.com/helix-editor/helix/pull/7965))
- Support `default` color in themes ([#8083](https://github.com/helix-editor/helix/pull/8083), [#8114](https://github.com/helix-editor/helix/pull/8114))
- Toggle between relative and absolute line numbers when the terminal loses focus ([#7955](https://github.com/helix-editor/helix/pull/7955))
- Lower default idle-timeout to 250ms ([060e73a](https://github.com/helix-editor/helix/commit/060e73a))
- Allow theming diff gutters separately from other diff colors ([#8343](https://github.com/helix-editor/helix/pull/8343))
- Style bold/italic/strikethrough in markdown doc popups ([#8385](https://github.com/helix-editor/helix/pull/8385))
- Maintain the cursor position and view when splitting with `:hsplit`/`:vsplit` ([#8109](https://github.com/helix-editor/helix/pull/8109))
- Accept `-` in macros outside of `<`/`>` ([#8475](https://github.com/helix-editor/helix/pull/8475))
- Show all language servers for each language in `--health` ([#7315](https://github.com/helix-editor/helix/pull/7315))
- Don't break on hyphens in `:reflow` ([#8569](https://github.com/helix-editor/helix/pull/8569))
Fixes:
- Update diagnostics correctly on language server exit ([#7111](https://github.com/helix-editor/helix/pull/7111))
- Fix off-by-one in `select_references_to_symbol_under_cursor` ([#7132](https://github.com/helix-editor/helix/pull/7132))
- Extend selection with repeat-last-motion only if the original motion extended the selection ([#7159](https://github.com/helix-editor/helix/pull/7159))
- Fix undefined behavior in the diff gutter ([#7227](https://github.com/helix-editor/helix/pull/7227))
- Check that tab width is non-zero ([#7178](https://github.com/helix-editor/helix/pull/7178))
- Fix styles being overwritten in table rows with multiple cells ([#7281](https://github.com/helix-editor/helix/pull/7281))
- Add file for `--log` CLI arg in help text ([#7307](https://github.com/helix-editor/helix/pull/7307))
- Fix underflow when repeating a completion that has a negative shift position ([#7322](https://github.com/helix-editor/helix/pull/7322))
- Prefer longer matches in `select_next_sibling` and `select_prev_sibling` ([#7332](https://github.com/helix-editor/helix/pull/7332))
- Preview scratch buffers in the jumplist picker ([#7331](https://github.com/helix-editor/helix/pull/7331))
- Fix chunking by bytes in tree-sitter parsing ([#7417](https://github.com/helix-editor/helix/pull/7417))
- Discard LSP publishDiagnostic from uninitialized servers ([#7467](https://github.com/helix-editor/helix/pull/7467))
- Use negotiated position encoding for LSP workspace edits ([#7469](https://github.com/helix-editor/helix/pull/7469))
- Fix error message for unknown gutter types in config ([#7534](https://github.com/helix-editor/helix/pull/7534))
- Fix `:log-open` when `--log` CLI arg is specified ([#7573](https://github.com/helix-editor/helix/pull/7573), [#7585](https://github.com/helix-editor/helix/pull/7585))
- Fix debouncing of LSP messages to fix the last message sticking around ([#7538](https://github.com/helix-editor/helix/pull/7538), [#8023](https://github.com/helix-editor/helix/pull/8023))
- Fix crash when the current working directory is deleted ([#7185](https://github.com/helix-editor/helix/pull/7185))
- Fix piping to Helix on macOS ([#5468](https://github.com/helix-editor/helix/pull/5468))
- Fix crash when parsing overlapping injections ([#7621](https://github.com/helix-editor/helix/pull/7621))
- Clear the statusline when the prompt is visible ([#7646](https://github.com/helix-editor/helix/pull/7646))
- Fix range formatting error message typo ([#7823](https://github.com/helix-editor/helix/pull/7823))
- Skip rendering gutters when gutter width exceeds view width ([#7821](https://github.com/helix-editor/helix/pull/7821))
- Center the picker preview using visual lines ([#7837](https://github.com/helix-editor/helix/pull/7837))
- Align view correctly for background buffers opened with `A-ret` ([#7691](https://github.com/helix-editor/helix/pull/7691))
- Fix cursor resetting to block when quitting via a keybind ([#7931](https://github.com/helix-editor/helix/pull/7931))
- Remove path completions for the `:new` command ([#8010](https://github.com/helix-editor/helix/pull/8010))
- Use binary path resolved by `which` for formatter commands ([#8064](https://github.com/helix-editor/helix/pull/8064))
- Handle crossterm's `hidden` modifier ([#8120](https://github.com/helix-editor/helix/pull/8120))
- Clear completion when switching between windows with the mouse ([#8118](https://github.com/helix-editor/helix/pull/8118))
- Eagerly remove the last picker (`<space>'`) when the picker has many items ([#8127](https://github.com/helix-editor/helix/pull/8127))
- Fix find commands for buffers with non-LF line-endings ([#8111](https://github.com/helix-editor/helix/pull/8111))
- Detect the tmux clipboard provider on macOS ([#8182](https://github.com/helix-editor/helix/pull/8182))
- Fix syntax highlighting in dynamic picker preview pane ([#8206](https://github.com/helix-editor/helix/pull/8206))
- Recognize HTML code tags with attributes as code in markdown previews ([#8397](https://github.com/helix-editor/helix/pull/8397))
- Fix multicursor snippet placeholder directions ([#8423](https://github.com/helix-editor/helix/pull/8423))
- Only show diagnostic highlights when diagnostics are enabled for a language server ([#8551](https://github.com/helix-editor/helix/pull/8551))
Themes:
- Improve the selection color in `ferra` ([#7138](https://github.com/helix-editor/helix/pull/7138))
- Add `variable.other.member` theming to `spacebones_light` ([#7125](https://github.com/helix-editor/helix/pull/7125))
- Update `autumn` and theme the soft-wrap indicator ([#7229](https://github.com/helix-editor/helix/pull/7229))
- Add `gruvbox_dark_soft` ([#7139](https://github.com/helix-editor/helix/pull/7139))
- Add `merionette` ([#7186](https://github.com/helix-editor/helix/pull/7186))
- Add `zed_onedark` and `zed_onelight` ([#7250](https://github.com/helix-editor/helix/pull/7250))
- Use light-gray for `onedarker` inlay hint theming ([#7433](https://github.com/helix-editor/helix/pull/7433))
- Update the Nord theme to follow the style guidelines ([#7490](https://github.com/helix-editor/helix/pull/7490))
- Tune `dark_plus` inlay hint colors ([#7611](https://github.com/helix-editor/helix/pull/7611))
- Add `naysayer` ([#7570](https://github.com/helix-editor/helix/pull/7570))
- Add `kaolin-dark`, `kaolin-light` and `kaolin-valley-dark` ([#7151](https://github.com/helix-editor/helix/pull/7151))
- Fix selection highlighting in gruvbox variants ([#7717](https://github.com/helix-editor/helix/pull/7717))
- Add soft-wrap indicator to `gruvbox` ([#7736](https://github.com/helix-editor/helix/pull/7736))
- Add missing palette definitions in `everforest_dark` ([#7739](https://github.com/helix-editor/helix/pull/7739))
- Increase diagnostics clarity in `pop-dark` ([#7702](https://github.com/helix-editor/helix/pull/7702))
- Add `vim_dark_high_contrast` ([#7785](https://github.com/helix-editor/helix/pull/7785))
- Add `new_moon` ([#7834](https://github.com/helix-editor/helix/pull/7834))
- Add `yellowed` ([#7849](https://github.com/helix-editor/helix/pull/7849))
- Improve comment readability for `autumn` ([#7939](https://github.com/helix-editor/helix/pull/7939))
- Distinguish active bufferline buffer in `monokai` ([#7983](https://github.com/helix-editor/helix/pull/7983))
- Update ruler colors in `nord` ([#7995](https://github.com/helix-editor/helix/pull/7995))
- Update Catppuccin themes ([#8102](https://github.com/helix-editor/helix/pull/8102))
- Add text focus scope and diagnostics undercurls for `nord` ([#8165](https://github.com/helix-editor/helix/pull/8165))
- Add material theme collection ([#8211](https://github.com/helix-editor/helix/pull/8211))
- Improve indent line color in `dracula` ([#8266](https://github.com/helix-editor/helix/pull/8266))
- Clean up and refactor `papercolor` to use inheritance ([#8276](https://github.com/helix-editor/helix/pull/8276))
- Fix `zenburn` inlay hint color ([#8278](https://github.com/helix-editor/helix/pull/8278)a)
- Fix picker crash when previewing an invalid range ([e9d0bd7](https://github.com/helix-editor/helix/commit/e9d0bd7))
- Correctly center items in the picker preview ([13d4463](https://github.com/helix-editor/helix/commit/13d4463))
- Add `cyan_light` ([#8293](https://github.com/helix-editor/helix/pull/8293), [#8587](https://github.com/helix-editor/helix/pull/8587))
- Theme HTML tags in `onedark` ([#8409](https://github.com/helix-editor/helix/pull/8409))
- Refine `darcula` and `darcula-solid` themes ([#8412](https://github.com/helix-editor/helix/pull/8412))
- Improve `nord` highlights ([#8414](https://github.com/helix-editor/helix/pull/8414))
- Add `nord-night` ([#8549](https://github.com/helix-editor/helix/pull/8549))
New languages:
- Blueprint ([#7213](https://github.com/helix-editor/helix/pull/7213), [#8161](https://github.com/helix-editor/helix/pull/8161))
- Forth ([#7256](https://github.com/helix-editor/helix/pull/7256), [#7334](https://github.com/helix-editor/helix/pull/7334))
- t32 ([#7140](https://github.com/helix-editor/helix/pull/7140), [#7811](https://github.com/helix-editor/helix/pull/7811))
- WebC ([#7290](https://github.com/helix-editor/helix/pull/7290))
- Persistent DSL for Haskell ([#7261](https://github.com/helix-editor/helix/pull/7261))
- F# ([#7619](https://github.com/helix-editor/helix/pull/7619), [#8024](https://github.com/helix-editor/helix/pull/8024))
- Wren ([#7765](https://github.com/helix-editor/helix/pull/7765), [#7819](https://github.com/helix-editor/helix/pull/7819))
- Unison ([#7724](https://github.com/helix-editor/helix/pull/7724))
- Todo.txt ([#7835](https://github.com/helix-editor/helix/pull/7835))
- Jinja and Handlebars ([#7233](https://github.com/helix-editor/helix/pull/7233))
- Pod ([#7907](https://github.com/helix-editor/helix/pull/7907))
- Strace ([#7928](https://github.com/helix-editor/helix/pull/7928))
- Gemini ([#8070](https://github.com/helix-editor/helix/pull/8070))
- GNU Assembler (GAS) ([#8291](https://github.com/helix-editor/helix/pull/8291))
- JSON5 ([#8473](https://github.com/helix-editor/helix/pull/8473))
- TEMPL ([#8540](https://github.com/helix-editor/helix/pull/8540))
Updated languages and queries:
- Add one to the ruler numbers for git-commit ([#7072](https://github.com/helix-editor/helix/pull/7072))
- Recognize XAML files as XML ([#7083](https://github.com/helix-editor/helix/pull/7083))
- Recognize `Cargo.lock` as TOML ([#7095](https://github.com/helix-editor/helix/pull/7095))
- Use Rust grammar for Cairo ([c6d1430](https://github.com/helix-editor/helix/commit/c6d1430))
- Update tree-sitter-nickel ([#7059](https://github.com/helix-editor/helix/pull/7059), [#7551](https://github.com/helix-editor/helix/pull/7551))
- Tune auto-pair characters for Nickel ([#7059](https://github.com/helix-editor/helix/pull/7059))
- Recognize `Vagrantfile` as Ruby ([#7112](https://github.com/helix-editor/helix/pull/7112))
- Recognize hidden justfiles as Just ([#7088](https://github.com/helix-editor/helix/pull/7088))
- Update Java and TypeScript highlight queries ([#7145](https://github.com/helix-editor/helix/pull/7145))
- Recognize `.zimrc` as Bash ([#7146](https://github.com/helix-editor/helix/pull/7146))
- Recognize `.gir` as XML ([#7152](https://github.com/helix-editor/helix/pull/7152))
- Update tree-sitter-scala ([#7147](https://github.com/helix-editor/helix/pull/7147))
- Recognize make file-type as Makefile ([#7212](https://github.com/helix-editor/helix/pull/7212))
- Update tree-sitter-verilog ([#7262](https://github.com/helix-editor/helix/pull/7262))
- Update tree-sitter-cpp ([#7285](https://github.com/helix-editor/helix/pull/7285))
- Support core mode for delve debugger ([#7300](https://github.com/helix-editor/helix/pull/7300))
- Add Fortran comment injections ([#7305](https://github.com/helix-editor/helix/pull/7305))
- Switch Vue language server to `vue-language-server` ([#7312](https://github.com/helix-editor/helix/pull/7312))
- Update tree-sitter-sql ([#7387](https://github.com/helix-editor/helix/pull/7387), [#8464](https://github.com/helix-editor/helix/pull/8464))
- Replace the MATLAB tre-sitter grammar ([#7388](https://github.com/helix-editor/helix/pull/7388), [#7442](https://github.com/helix-editor/helix/pull/7442), [#7491](https://github.com/helix-editor/helix/pull/7491), [#7493](https://github.com/helix-editor/helix/pull/7493), [#7511](https://github.com/helix-editor/helix/pull/7511), [#7532](https://github.com/helix-editor/helix/pull/7532), [#8040](https://github.com/helix-editor/helix/pull/8040))
- Highlight TOML table headers ([#7441](https://github.com/helix-editor/helix/pull/7441))
- Recognize `cppm` file-type as C++ ([#7492](https://github.com/helix-editor/helix/pull/7492))
- Refactor ecma language queries into private and public queries ([#7207](https://github.com/helix-editor/helix/pull/7207))
- Update tree-sitter-dart ([#7576](https://github.com/helix-editor/helix/pull/7576))
- Add shebang for nushell files ([#7606](https://github.com/helix-editor/helix/pull/7606))
- Recognize systemd files as INI ([#7592](https://github.com/helix-editor/helix/pull/7592))
- Update TypeScript, TSX and Svelte grammars ([#6874](https://github.com/helix-editor/helix/pull/6874))
- Enable inlay hints in the Svelte language server ([#7622](https://github.com/helix-editor/helix/pull/7622))
- Recognize `Brewfile`s as Ruby ([#7629](https://github.com/helix-editor/helix/pull/7629))
- Add more file-types for R ([#7633](https://github.com/helix-editor/helix/pull/7633))
- Switch tree-sitter-perl to official upstream parser ([#7644](https://github.com/helix-editor/helix/pull/7644), [#7947](https://github.com/helix-editor/helix/pull/7947))
- Fix predicate typo in comment highlights ([#7732](https://github.com/helix-editor/helix/pull/7732))
- Update tree-sitter-prql ([#7771](https://github.com/helix-editor/helix/pull/7771))
- Recognize `.gitf` as JSON ([#7781](https://github.com/helix-editor/helix/pull/7781))
- Switch V language server to `v-analyzer` ([#7760](https://github.com/helix-editor/helix/pull/7760))
- Add protobuf language servers ([#7796](https://github.com/helix-editor/helix/pull/7796))
- Update tree-sitter-zig ([#7803](https://github.com/helix-editor/helix/pull/7803))
- Update tree-sitter-hare ([#7784](https://github.com/helix-editor/helix/pull/7784))
- Add Java indent queries ([#7844](https://github.com/helix-editor/helix/pull/7844))
- Update tree-sitter-scheme ([979933b](https://github.com/helix-editor/helix/commit/979933b))
- Recognize `scm` as Scheme instead of TSQ ([5707151](https://github.com/helix-editor/helix/commit/5707151))
- Update tree-sitter-git-commit ([#7831](https://github.com/helix-editor/helix/pull/7831))
- Update JavaScript, TypeScript and TSX grammars ([#7852](https://github.com/helix-editor/helix/pull/7852))
- Update tree-sitter-nu ([#7873](https://github.com/helix-editor/helix/pull/7873))
- Fix YAML indentation ([#6768](https://github.com/helix-editor/helix/pull/6768))
- Add `csharp-ls`, Pyright, Pylyzer and add roots for Python ([#7897](https://github.com/helix-editor/helix/pull/7897), [#8032](https://github.com/helix-editor/helix/pull/8032))
- Update tree-sitter-slint ([#7893](https://github.com/helix-editor/helix/pull/7893))
- Recognize more ZSH file-types as Bash ([#7930](https://github.com/helix-editor/helix/pull/7930))
- Recognize `star` extension as Starlark ([#7922](https://github.com/helix-editor/helix/pull/7922))
- Fix inline HTML tag highlighting in markdown ([#7960](https://github.com/helix-editor/helix/pull/7960))
- Update tree-sitter-robot ([#7970](https://github.com/helix-editor/helix/pull/7970))
- Highlight Dart 3 `sealed` and `base` keywords ([#7974](https://github.com/helix-editor/helix/pull/7974))
- Add configuration for `ltex-ls` to the default `languages.toml` ([#7838](https://github.com/helix-editor/helix/pull/7838))
- Update tree-sitter-strace ([#8087](https://github.com/helix-editor/helix/pull/8087))
- Update tree-sitter-gleam, enable auto-format ([#8085](https://github.com/helix-editor/helix/pull/8085))
- Update tree-sitter-esdl ([#8222](https://github.com/helix-editor/helix/pull/8222))
- Expand ignore file-types ([#8220](https://github.com/helix-editor/helix/pull/8220))
- Recognize feed related formats as XML ([#8232](https://github.com/helix-editor/helix/pull/8232))
- Improve YAML injections ([#8217](https://github.com/helix-editor/helix/pull/8217))
- Add shebangs for TypeScript, Julia, Java and OCaml ([95e994a](https://github.com/helix-editor/helix/commit/95e994a))
- Highlight abbreviations in Scheme ([ef23847](https://github.com/helix-editor/helix/commit/ef23847))
- Remove backtic auto-pair in OCaml ([#8260](https://github.com/helix-editor/helix/pull/8260))
- Recognize `flake.lock` as JSON ([#8304](https://github.com/helix-editor/helix/pull/8304))
- Add Python test script injection for Nix ([b4494e1](https://github.com/helix-editor/helix/commit/b4494e1))
- Fix Nix comment injection precedence ([37e48f4](https://github.com/helix-editor/helix/commit/37e48f4))
- Recognize editorconfig files as INI ([#8308](https://github.com/helix-editor/helix/pull/8308))
- Recognize `.babelrc` as JSON ([#8309](https://github.com/helix-editor/helix/pull/8309))
- Switch Purescript to its own tree-sitter parser ([#8306](https://github.com/helix-editor/helix/pull/8306), [#8338](https://github.com/helix-editor/helix/pull/8338), [#8527](https://github.com/helix-editor/helix/pull/8527))
- Update Unison highlights ([#8315](https://github.com/helix-editor/helix/pull/8315))
- Recognize `.webmanifest` as JSON ([#8342](https://github.com/helix-editor/helix/pull/8342))
- Recognize polkit policy files as XML ([#8369](https://github.com/helix-editor/helix/pull/8369))
- Recognize polkit rules files as JavaScript ([#8370](https://github.com/helix-editor/helix/pull/8370))
- Update Go highlight queries ([#8399](https://github.com/helix-editor/helix/pull/8399))
- Add shebangs for Makefiles ([#8410](https://github.com/helix-editor/helix/pull/8410))
- Add file-type associations from VSCode ([#8388](https://github.com/helix-editor/helix/pull/8388))
- Add validation to JSON/CSS language server configs ([#8433](https://github.com/helix-editor/helix/pull/8433))
- Add a configuration for the tailwind language server ([#8442](https://github.com/helix-editor/helix/pull/8442))
- Add a configuration for the ansible language server ([#7973](https://github.com/helix-editor/helix/pull/7973))
- Add a configuration for the GraphQL language server ([#8492](https://github.com/helix-editor/helix/pull/8492))
- Indent while statements in Bash ([#8528](https://github.com/helix-editor/helix/pull/8528))
- Update tree-sitter-haskell and queries ([#8558](https://github.com/helix-editor/helix/pull/8558))
Packaging:
- Add an overlay to the Nix flake ([#7078](https://github.com/helix-editor/helix/pull/7078))
- Check for `git` before fetching or building grammars ([#7320](https://github.com/helix-editor/helix/pull/7320))
- Refactor Nix flake to use Crane ([#7763](https://github.com/helix-editor/helix/pull/7763))
- Remove the aarch64 appimage from the release CI ([#7832](https://github.com/helix-editor/helix/pull/7832))
- Add desktop and icon files to Nix flake output ([#7979](https://github.com/helix-editor/helix/pull/7979))
- Build flake packages with the latest stable Rust ([#8133](https://github.com/helix-editor/helix/pull/8133))
# 23.05 (2023-05-18)
23.05 is a smaller release focusing on fixes. There were 88 contributors in this release. Thank you all!

626
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -1 +1 @@
23.05
23.10

@ -51,7 +51,7 @@ Its settings will be merged with the configuration directory `config.toml` and t
| `auto-completion` | Enable automatic pop up of auto-completion | `true` |
| `auto-format` | Enable automatic formatting on save | `true` |
| `auto-save` | Enable automatic saving on the focus moving away from Helix. Requires [focus event support](https://github.com/helix-editor/helix/wiki/Terminal-Support) from your terminal | `false` |
| `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant | `400` |
| `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant | `250` |
| `preview-completion-insert` | Whether to apply completion item instantly when selected | `true` |
| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
| `completion-replace` | Set to `true` to make completions always replace the entire word and not just the part before the cursor | `false` |

@ -16,7 +16,7 @@
| clojure | ✓ | | | `clojure-lsp` |
| cmake | ✓ | ✓ | ✓ | `cmake-language-server` |
| comment | ✓ | | | |
| common-lisp | ✓ | | | `cl-lsp` |
| common-lisp | ✓ | | | `cl-lsp` |
| cpon | ✓ | | ✓ | |
| cpp | ✓ | ✓ | ✓ | `clangd` |
| crystal | ✓ | ✓ | | `crystalline` |
@ -44,6 +44,7 @@
| forth | ✓ | | | `forth-lsp` |
| fortran | ✓ | | ✓ | `fortls` |
| fsharp | ✓ | | | `fsautocomplete` |
| gas | ✓ | ✓ | | |
| gdscript | ✓ | ✓ | ✓ | |
| gemini | ✓ | | | |
| git-attributes | ✓ | | | |
@ -53,12 +54,12 @@
| git-rebase | ✓ | | | |
| gleam | ✓ | ✓ | | `gleam` |
| glsl | ✓ | ✓ | ✓ | |
| go | ✓ | ✓ | ✓ | `gopls` |
| go | ✓ | ✓ | ✓ | `gopls`, `golangci-lint-langserver` |
| godot-resource | ✓ | | | |
| gomod | ✓ | | | `gopls` |
| gotmpl | ✓ | | | `gopls` |
| gowork | ✓ | | | `gopls` |
| graphql | ✓ | | | |
| graphql | ✓ | | | `graphql-lsp` |
| hare | ✓ | | | |
| haskell | ✓ | ✓ | | `haskell-language-server-wrapper` |
| haskell-persistent | ✓ | | | |
@ -75,11 +76,12 @@
| jinja | ✓ | | | |
| jsdoc | ✓ | | | |
| json | ✓ | | ✓ | `vscode-json-language-server` |
| json5 | ✓ | | | |
| jsonnet | ✓ | | | `jsonnet-language-server` |
| jsx | ✓ | ✓ | ✓ | `typescript-language-server` |
| julia | ✓ | ✓ | ✓ | `julia` |
| just | ✓ | ✓ | ✓ | |
| kdl | ✓ | | | |
| kdl | ✓ | | | |
| kotlin | ✓ | | | `kotlin-language-server` |
| latex | ✓ | ✓ | | `texlab` |
| lean | ✓ | | | `lean` |
@ -87,6 +89,7 @@
| llvm | ✓ | ✓ | ✓ | |
| llvm-mir | ✓ | ✓ | ✓ | |
| llvm-mir-yaml | ✓ | | ✓ | |
| lpf | ✓ | | | |
| lua | ✓ | ✓ | ✓ | `lua-language-server` |
| make | ✓ | | | |
| markdoc | ✓ | | | `markdoc-ls` |
@ -121,11 +124,11 @@
| prolog | | | | `swipl` |
| protobuf | ✓ | | ✓ | `bufls`, `pb` |
| prql | ✓ | | | |
| purescript | ✓ | | | `purescript-language-server` |
| purescript | ✓ | | | `purescript-language-server` |
| python | ✓ | ✓ | ✓ | `pylsp` |
| qml | ✓ | | ✓ | `qmlls` |
| r | ✓ | | | `R` |
| racket | ✓ | | | `racket` |
| racket | ✓ | | | `racket` |
| regex | ✓ | | | |
| rego | ✓ | | | `regols` |
| rescript | ✓ | ✓ | | `rescript-language-server` |
@ -137,7 +140,7 @@
| rust | ✓ | ✓ | ✓ | `rust-analyzer` |
| sage | ✓ | ✓ | | |
| scala | ✓ | | ✓ | `metals` |
| scheme | ✓ | | | |
| scheme | ✓ | | | |
| scss | ✓ | | | `vscode-css-language-server` |
| slint | ✓ | | ✓ | `slint-lsp` |
| smithy | ✓ | | | `cs` |
@ -153,6 +156,7 @@
| t32 | ✓ | | | |
| tablegen | ✓ | ✓ | ✓ | |
| task | ✓ | | | |
| templ | ✓ | | | `templ` |
| tfvars | ✓ | | ✓ | `terraform-ls` |
| todotxt | ✓ | | | |
| toml | ✓ | | | `taplo` |
@ -160,6 +164,7 @@
| tsx | ✓ | ✓ | ✓ | `typescript-language-server` |
| twig | ✓ | | | |
| typescript | ✓ | ✓ | ✓ | `typescript-language-server` |
| typst | ✓ | | | `typst-lsp` |
| ungrammar | ✓ | | | |
| unison | ✓ | | | |
| uxntal | ✓ | | | |
@ -177,6 +182,6 @@
| wren | ✓ | ✓ | ✓ | |
| xit | ✓ | | | |
| xml | ✓ | | ✓ | |
| yaml | ✓ | | ✓ | `yaml-language-server` |
| yaml | ✓ | | ✓ | `yaml-language-server`, `ansible-language-server` |
| yuck | ✓ | | | |
| zig | ✓ | ✓ | ✓ | `zls` |

@ -85,3 +85,4 @@
| `:reset-diff-change`, `:diffget`, `:diffg` | Reset the diff change at the cursor position. |
| `:clear-register` | Clear given register. If no argument is provided, clear all registers. |
| `:redraw` | Clear and re-render the whole UI |
| `:move` | Move the current buffer and its corresponding file to a different path |

@ -1,7 +1,7 @@
# Adding Injection Queries
Writing language injection queries allows one to highlight a specific node as a different language.
In addition to the [standard](upstream-docs) language injection options used by tree-sitter, there
In addition to the [standard][upstream-docs] language injection options used by tree-sitter, there
are a few Helix specific extensions that allow for more control.
And example of a simple query that would highlight all strings as bash in Nix:

@ -13,6 +13,7 @@
- [AppImage](#appimage)
- [macOS](#macos)
- [Homebrew Core](#homebrew-core)
- [MacPorts](#macports)
- [Windows](#windows)
- [Winget](#winget)
- [Scoop](#scoop)
@ -133,6 +134,12 @@ chmod +x helix-*.AppImage # change permission for executable mode
brew install helix
```
### MacPorts
```sh
port install helix
```
## Windows
Install on Windows using [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/), [Scoop](https://scoop.sh/), [Chocolatey](https://chocolatey.org/)
@ -257,12 +264,32 @@ following order:
1. `runtime/` sibling directory to `$CARGO_MANIFEST_DIR` directory (this is intended for
developing and testing helix only).
2. `runtime/` subdirectory of OS-dependent helix user config directory.
3. `$HELIX_RUNTIME`.
4. `runtime/` subdirectory of path to Helix executable.
3. `$HELIX_RUNTIME`
4. Distribution-specific fallback directory (set at compile time—not run time—
with the `HELIX_DEFAULT_RUNTIME` environment variable)
5. `runtime/` subdirectory of path to Helix executable.
This order also sets the priority for selecting which file will be used if multiple runtime
directories have files with the same name.
#### Note to packagers
If you are making a package of Helix for end users, to provide a good out of
the box experience, you should set the `HELIX_DEFAULT_RUNTIME` environment
variable at build time (before invoking `cargo build`) to a directory which
will store the final runtime files after installation. For example, say you want
to package the runtime into `/usr/lib/helix/runtime`. The rough steps a build
script could follow are:
1. `export HELIX_DEFAULT_RUNTIME=/usr/lib/helix/runtime`
1. `cargo build --profile opt --locked --path helix-term`
1. `cp -r runtime $BUILD_DIR/usr/lib/helix/`
1. `cp target/opt/hx $BUILD_DIR/usr/bin/hx`
This way the resulting `hx` binary will always look for its runtime directory in
`/usr/lib/helix/runtime` if the user has no custom runtime in `~/.config/helix`
or `HELIX_RUNTIME`.
### Validating the installation
To make sure everything is set up as expected you should run the Helix health

@ -155,6 +155,7 @@ We use a similar set of scopes as
- `type` - Types
- `builtin` - Primitive types provided by the language (`int`, `usize`)
- `parameter` - Generic type parameters (`T`)
- `enum`
- `variant`
- `constructor`
@ -245,9 +246,12 @@ We use a similar set of scopes as
- `diff` - version control changes
- `plus` - additions
- `gutter` - gutter indicator
- `minus` - deletions
- `gutter` - gutter indicator
- `delta` - modifications
- `moved` - renamed or moved files/changes
- `gutter` - gutter indicator
#### Interface

@ -59,8 +59,8 @@ Some registers have special behavior when read from and written to.
| `#` | Selection indices (first selection is `1`, second is `2`, etc.) | This register is not writable |
| `.` | Contents of the current selections | This register is not writable |
| `%` | Name of the current file | This register is not writable |
| `*` | Reads from the system clipboard | Joins and yanks to the system clipboard |
| `+` | Reads from the primary clipboard | Joins and yanks to the primary clipboard |
| `+` | Reads from the system clipboard | Joins and yanks to the system clipboard |
| `*` | Reads from the primary clipboard | Joins and yanks to the primary clipboard |
When yanking multiple selections to the clipboard registers, the selections
are joined with newlines. Pasting from these registers will paste multiple

@ -1,11 +1,11 @@
<!DOCTYPE HTML>
<html lang="{{ language }}" class="sidebar-visible no-js {{ default_theme }}">
<html lang="{{ language }}" class="{{ default_theme }}" dir="{{ text_direction }}">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>{{ title }}</title>
{{#if is_print }}
<meta name="robots" content="noindex" />
<meta name="robots" content="noindex">
{{/if}}
{{#if base_url}}
<base href="{{ base_url }}">
@ -17,7 +17,7 @@
<meta name="description" content="{{ description }}">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<meta name="theme-color" content="#ffffff">
{{#if favicon_svg}}
<link rel="icon" href="{{ path_to_root }}favicon.svg">
@ -34,8 +34,6 @@
<!-- Fonts -->
<link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@200;400;500;700&display=swap" rel="stylesheet">
{{#if copy_fonts}}
<link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css">
{{/if}}
@ -55,7 +53,7 @@
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
{{/if}}
</head>
<body>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
@ -85,24 +83,29 @@
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('{{ default_theme }}')
html.classList.add(theme);
html.classList.add('js');
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var html = document.querySelector('html');
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
@ -141,9 +144,9 @@
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
@ -220,7 +223,7 @@
{{/previous}}
{{#next}}
<a rel="next" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
{{/next}}
@ -238,7 +241,7 @@
{{/previous}}
{{#next}}
<a rel="next" href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
{{/next}}

@ -5,6 +5,7 @@
<project_license>MPL-2.0</project_license>
<name>Helix</name>
<summary>A post-modern text editor</summary>
<summary xml:lang="ar">مُحَرِّرُ نُصُوصٍ سَابِقٌ لِعَهدِه</summary>
<description>
<p>
@ -17,6 +18,17 @@
<li>Smart, incremental syntax highlighting and code editing via tree-sitter</li>
</ul>
</description>
<description xml:lang="ar">
<p>
مُحَرِّرُ نُصُوصٍ يَعمَلُ فِي الطَّرَفِيَّة، مُستَلهَمٌ مِن Kakoune وَ Neovim وَمَكتُوبٌ بِلُغَةِ رَست البَرمَجِيَّة.
</p>
<ul>
<li>تَحرِيرٌ وَضعِيٌّ شَبيهٌ بِـVim</li>
<li>تَحدِيدَاتٌ لِلنَّصِ مُتَعَدِّدَة</li>
<li>دَعْمٌ مُدمَجٌ لِخَوادِمِ اللُّغَات</li>
<li>تَحرِيرُ التَّعلِيمَاتِ البَّرمَجِيَّةِ مَعَ تَمييزٍ لِلتَّركِيبِ النَّحُويِّ بِواسِطَةِ tree-sitter</li>
</ul>
</description>
<launchable type="desktop-id">Helix.desktop</launchable>
@ -36,6 +48,9 @@
<content_rating type="oars-1.1" />
<releases>
<release version="23.10" date="2023-10-24">
<url>https://helix-editor.com/news/release-23-10-highlights/</url>
</release>
<release version="23.05" date="2023-05-18">
<url>https://github.com/helix-editor/helix/releases/tag/23.05</url>
</release>

@ -1,6 +1,7 @@
[Desktop Entry]
Name=Helix
GenericName=Text Editor
GenericName[ar]=مُحَرِّرُ نُصُوص
GenericName[de]=Texteditor
GenericName[fr]=Éditeur de texte
GenericName[ru]=Текстовый редактор
@ -9,7 +10,7 @@ GenericName[tr]=Metin Düzenleyici
Comment=Edit text files
Comment[af]=Redigeer tekslêers
Comment[am]=የጽሑፍ ፋይሎች ያስተካክሉ
Comment[ar]=حرّر ملفات نصية
Comment[ar]=مُحَرِّرُ مِلَفَّاتٍ نَصِّيَّة
Comment[az]=Mətn fayllarını redaktə edin
Comment[be]=Рэдагаваньне тэкставых файлаў
Comment[bg]=Редактиране на текстови файлове
@ -79,6 +80,7 @@ Exec=hx %F
Terminal=true
Type=Application
Keywords=Text;editor;
Keywords[ar]=نص;نصوص;محرر;
Keywords[fr]=Texte;éditeur;
Keywords[ru]=текст;текстовый редактор;
Keywords[sr]=Текст;едитор;

@ -5,6 +5,7 @@
runCommand,
yj,
includeGrammarIf ? _: true,
grammarOverlays ? [],
...
}: let
# HACK: nix < 2.6 has a bug in the toml parser, so we convert to JSON
@ -48,22 +49,22 @@
then sourceGitHub
else sourceGit;
in
stdenv.mkDerivation rec {
stdenv.mkDerivation {
# see https://github.com/NixOS/nixpkgs/blob/fbdd1a7c0bc29af5325e0d7dd70e804a972eb465/pkgs/development/tools/parsing/tree-sitter/grammar.nix
pname = "helix-tree-sitter-${grammar.name}";
version = grammar.source.rev;
src =
if builtins.hasAttr "subpath" grammar.source
then "${source}/${grammar.source.subpath}"
else source;
src = source;
sourceRoot = if builtins.hasAttr "subpath" grammar.source then
"source/${grammar.source.subpath}"
else
"source";
dontUnpack = true;
dontConfigure = true;
FLAGS = [
"-I${src}/src"
"-Isrc"
"-g"
"-O3"
"-fPIC"
@ -76,13 +77,13 @@
buildPhase = ''
runHook preBuild
if [[ -e "$src/src/scanner.cc" ]]; then
$CXX -c "$src/src/scanner.cc" -o scanner.o $FLAGS
elif [[ -e "$src/src/scanner.c" ]]; then
$CC -c "$src/src/scanner.c" -o scanner.o $FLAGS
if [[ -e src/scanner.cc ]]; then
$CXX -c src/scanner.cc -o scanner.o $FLAGS
elif [[ -e src/scanner.c ]]; then
$CC -c src/scanner.c -o scanner.o $FLAGS
fi
$CC -c "$src/src/parser.c" -o parser.o $FLAGS
$CC -c src/parser.c -o parser.o $FLAGS
$CXX -shared -o $NAME.so *.o
ls -al
@ -105,15 +106,17 @@
'';
};
grammarsToBuild = builtins.filter includeGrammarIf gitGrammars;
builtGrammars =
builtins.map (grammar: {
builtGrammars = builtins.map (grammar: {
inherit (grammar) name;
artifact = buildGrammar grammar;
})
grammarsToBuild;
grammarLinks =
builtins.map (grammar: "ln -s ${grammar.artifact}/${grammar.name}.so $out/${grammar.name}.so")
builtGrammars;
value = buildGrammar grammar;
}) grammarsToBuild;
extensibleGrammars =
lib.makeExtensible (self: builtins.listToAttrs builtGrammars);
overlayedGrammars = lib.pipe extensibleGrammars
(builtins.map (overlay: grammar: grammar.extend overlay) grammarOverlays);
grammarLinks = lib.mapAttrsToList
(name: artifact: "ln -s ${artifact}/${name}.so $out/${name}.so")
(lib.filterAttrs (n: v: lib.isDerivation v) overlayedGrammars);
in
runCommand "consolidated-helix-grammars" {} ''
mkdir -p $out

@ -17,7 +17,7 @@ integration = []
[dependencies]
helix-loader = { version = "0.6", path = "../helix-loader" }
ropey = { version = "1.6.0", default-features = false, features = ["simd"] }
ropey = { version = "1.6.1", default-features = false, features = ["simd"] }
smallvec = "1.11"
smartstring = "1.0.1"
unicode-segmentation = "1.10"
@ -30,8 +30,8 @@ once_cell = "1.18"
arc-swap = "1"
regex = "1"
bitflags = "2.4"
ahash = "0.8.3"
hashbrown = { version = "0.14.0", features = ["raw"] }
ahash = "0.8.6"
hashbrown = { version = "0.14.2", features = ["raw"] }
dunce = "1.0"
log = "0.4"
@ -53,4 +53,4 @@ parking_lot = "0.12"
[dev-dependencies]
quickcheck = { version = "1", default-features = false }
indoc = "2.0.3"
indoc = "2.0.4"

@ -271,7 +271,9 @@ impl Indentation {
}
/// Add an indent capture to this indent.
/// All the captures that are added in this way should be on the same line.
/// Only captures that apply to the same line should be added together in this way (otherwise use `add_line`)
/// and the captures should be added starting from the innermost tree-sitter node (currently this only matters
/// if multiple `@align` patterns occur on the same line).
fn add_capture(&mut self, added: IndentCaptureType) {
match added {
IndentCaptureType::Indent => {
@ -295,10 +297,12 @@ impl Indentation {
self.outdent = 0;
}
IndentCaptureType::Align(align) => {
if self.align.is_none() {
self.align = Some(align);
}
}
}
}
fn into_string(self, indent_style: &IndentStyle) -> String {
let indent = self.indent_always + self.indent;
let outdent = self.outdent_always + self.outdent;

@ -1,7 +1,9 @@
use smartstring::{LazyCompact, SmartString};
use textwrap::{Options, WordSplitter::NoHyphenation};
/// Given a slice of text, return the text re-wrapped to fit it
/// within the given width.
pub fn reflow_hard_wrap(text: &str, text_width: usize) -> SmartString<LazyCompact> {
textwrap::refill(text, text_width).into()
let options = Options::new(text_width).word_splitter(NoHyphenation);
textwrap::refill(text, options).into()
}

@ -28,7 +28,7 @@ which = "4.4"
# cloning/compiling tree-sitter grammars
cc = { version = "1" }
threadpool = { version = "1.0" }
tempfile = "3.8.0"
tempfile = "3.8.1"
dunce = "1.0.4"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]

@ -33,9 +33,9 @@ pub fn current_working_dir() -> PathBuf {
path
}
pub fn set_current_working_dir(path: PathBuf) -> std::io::Result<()> {
pub fn set_current_working_dir(path: impl AsRef<Path>) -> std::io::Result<()> {
let path = dunce::canonicalize(path)?;
std::env::set_current_dir(path.clone())?;
std::env::set_current_dir(&path)?;
let mut cwd = CWD.write().unwrap();
*cwd = Some(path);
Ok(())
@ -60,7 +60,8 @@ pub fn initialize_log_file(specified_file: Option<PathBuf>) {
/// 1. sibling directory to `CARGO_MANIFEST_DIR` (if environment variable is set)
/// 2. subdirectory of user config directory (always included)
/// 3. `HELIX_RUNTIME` (if environment variable is set)
/// 4. subdirectory of path to helix executable (always included)
/// 4. `HELIX_DEFAULT_RUNTIME` (if environment variable is set *at build time*)
/// 5. subdirectory of path to helix executable (always included)
///
/// Postcondition: returns at least two paths (they might not exist).
fn prioritize_runtime_dirs() -> Vec<PathBuf> {
@ -81,6 +82,14 @@ fn prioritize_runtime_dirs() -> Vec<PathBuf> {
rt_dirs.push(dir.into());
}
// If this variable is set during build time, it will always be included
// in the lookup list. This allows downstream packagers to set a fallback
// directory to a location that is conventional on their distro so that they
// need not resort to a wrapper script or a global environment variable.
if let Some(dir) = std::option_env!("HELIX_DEFAULT_RUNTIME") {
rt_dirs.push(dir.into());
}
// fallback to location of the executable being run
// canonicalize the path in case the executable is symlinked
let exe_rt_dir = std::env::current_exe()
@ -280,7 +289,7 @@ mod merge_toml_tests {
let cwd = current_working_dir();
assert_ne!(cwd, new_path);
set_current_working_dir(new_path.clone()).expect("Couldn't set new path");
set_current_working_dir(&new_path).expect("Couldn't set new path");
let cwd = current_working_dir();
assert_eq!(cwd, new_path);

@ -25,7 +25,7 @@ lsp-types = { version = "0.94" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
tokio = { version = "1.32", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
tokio = { version = "1.33", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
tokio-stream = "0.1.14"
which = "4.4"
parking_lot = "0.12.1"

@ -401,12 +401,22 @@ impl Client {
&self,
params: R::Params,
) -> impl Future<Output = Result<Value>>
where
R::Params: serde::Serialize,
{
self.call_with_timeout::<R>(params, self.req_timeout)
}
fn call_with_timeout<R: lsp::request::Request>(
&self,
params: R::Params,
timeout_secs: u64,
) -> impl Future<Output = Result<Value>>
where
R::Params: serde::Serialize,
{
let server_tx = self.server_tx.clone();
let id = self.next_request_id();
let timeout_secs = self.req_timeout;
async move {
use std::time::Duration;
@ -548,6 +558,11 @@ impl Client {
dynamic_registration: Some(true),
relative_pattern_support: Some(false),
}),
file_operations: Some(lsp::WorkspaceFileOperationsClientCapabilities {
will_rename: Some(true),
did_rename: Some(true),
..Default::default()
}),
..Default::default()
}),
text_document: Some(lsp::TextDocumentClientCapabilities {
@ -700,6 +715,65 @@ impl Client {
})
}
pub fn prepare_file_rename(
&self,
old_uri: &lsp::Url,
new_uri: &lsp::Url,
) -> Option<impl Future<Output = Result<lsp::WorkspaceEdit>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support willRename feature
match &capabilities.workspace {
Some(workspace) => match &workspace.file_operations {
Some(op) => {
op.will_rename.as_ref()?;
}
_ => return None,
},
_ => return None,
}
let files = vec![lsp::FileRename {
old_uri: old_uri.to_string(),
new_uri: new_uri.to_string(),
}];
let request = self.call_with_timeout::<lsp::request::WillRenameFiles>(
lsp::RenameFilesParams { files },
5,
);
Some(async move {
let json = request.await?;
let response: Option<lsp::WorkspaceEdit> = serde_json::from_value(json)?;
Ok(response.unwrap_or_default())
})
}
pub fn did_file_rename(
&self,
old_uri: &lsp::Url,
new_uri: &lsp::Url,
) -> Option<impl Future<Output = std::result::Result<(), Error>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support DidRename feature
match &capabilities.workspace {
Some(workspace) => match &workspace.file_operations {
Some(op) => {
op.did_rename.as_ref()?;
}
_ => return None,
},
_ => return None,
}
let files = vec![lsp::FileRename {
old_uri: old_uri.to_string(),
new_uri: new_uri.to_string(),
}];
Some(self.notify::<lsp::notification::DidRenameFiles>(lsp::RenameFilesParams { files }))
}
// -------------------------------------------------------------------------------------------
// Text document
// -------------------------------------------------------------------------------------------
@ -971,12 +1045,12 @@ impl Client {
) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support resolving code action.
match capabilities.completion_provider {
Some(lsp::CompletionOptions {
// Return early if the server does not support resolving code actions.
match capabilities.code_action_provider {
Some(lsp::CodeActionProviderCapability::Options(lsp::CodeActionOptions {
resolve_provider: Some(true),
..
}) => (),
})) => (),
_ => return None,
}

@ -445,36 +445,36 @@ pub mod util {
// the tabstop closest to the range simply replaces `head` while anchor remains in place
// the remaining tabstops receive their own single-width cursor
if range.head < range.anchor {
let first_tabstop = tabstop_anchor + tabstops[0].1;
let last_idx = tabstops.len() - 1;
let last_tabstop = tabstop_anchor + tabstops[last_idx].0;
// if selection is forward but was moved to the right it is
// contained entirely in the replacement text, just do a point
// selection (fallback below)
if range.anchor >= first_tabstop {
let range = Range::new(range.anchor, first_tabstop);
if range.anchor > last_tabstop {
let range = Range::new(range.anchor, last_tabstop);
mapped_selection.push(range);
let rem_tabstops = tabstops[1..]
let rem_tabstops = tabstops[..last_idx]
.iter()
.map(|tabstop| Range::point(tabstop_anchor + tabstop.1));
.map(|tabstop| Range::point(tabstop_anchor + tabstop.0));
mapped_selection.extend(rem_tabstops);
continue;
}
} else {
let last_idx = tabstops.len() - 1;
let last_tabstop = tabstop_anchor + tabstops[last_idx].1;
let first_tabstop = tabstop_anchor + tabstops[0].0;
// if selection is forward but was moved to the right it is
// contained entirely in the replacement text, just do a point
// selection (fallback below)
if range.anchor <= last_tabstop {
if range.anchor < first_tabstop {
// we can't properly compute the the next grapheme
// here because the transaction hasn't been applied yet
// that is not a problem because the range gets grapheme aligned anyway
// tough so just adding one will always cause head to be grapheme
// aligned correctly when applied to the document
let range = Range::new(range.anchor, last_tabstop + 1);
let range = Range::new(range.anchor, first_tabstop + 1);
mapped_selection.push(range);
let rem_tabstops = tabstops[..last_idx]
let rem_tabstops = tabstops[1..]
.iter()
.map(|tabstop| Range::point(tabstop_anchor + tabstop.0));
mapped_selection.extend(rem_tabstops);
@ -749,36 +749,40 @@ impl Registry {
}
}
pub fn get(
&mut self,
language_config: &LanguageConfiguration,
doc_path: Option<&std::path::PathBuf>,
root_dirs: &[PathBuf],
pub fn get<'a>(
&'a mut self,
language_config: &'a LanguageConfiguration,
doc_path: Option<&'a std::path::PathBuf>,
root_dirs: &'a [PathBuf],
enable_snippets: bool,
) -> Result<HashMap<LanguageServerName, Arc<Client>>> {
language_config
.language_servers
.iter()
.map(|LanguageServerFeatures { name, .. }| {
) -> impl Iterator<Item = (LanguageServerName, Result<Arc<Client>>)> + 'a {
language_config.language_servers.iter().map(
move |LanguageServerFeatures { name, .. }| {
if let Some(clients) = self.inner.get(name) {
if let Some((_, client)) = clients.iter().enumerate().find(|(i, client)| {
client.try_add_doc(&language_config.roots, root_dirs, doc_path, *i == 0)
}) {
return Ok((name.to_owned(), client.clone()));
return (name.to_owned(), Ok(client.clone()));
}
}
let client = self.start_client(
match self.start_client(
name.clone(),
language_config,
doc_path,
root_dirs,
enable_snippets,
)?;
let clients = self.inner.entry(name.clone()).or_default();
clients.push(client.clone());
Ok((name.clone(), client))
})
.collect()
) {
Ok(client) => {
self.inner
.entry(name.to_owned())
.or_default()
.push(client.clone());
(name.clone(), Ok(client))
}
Err(err) => (name.to_owned(), Err(err)),
}
},
)
}
pub fn iter_clients(&self) -> impl Iterator<Item = &Arc<Client>> {

@ -69,7 +69,7 @@ grep-searcher = "0.1.11"
[target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
libc = "0.2.147"
libc = "0.2.150"
[target.'cfg(target_os = "macos")'.dependencies]
crossterm = { version = "0.27", features = ["event-stream", "use-dev-tty"] }
@ -79,5 +79,5 @@ helix-loader = { version = "0.6", path = "../helix-loader" }
[dev-dependencies]
smallvec = "1.11"
indoc = "2.0.3"
tempfile = "3.8.0"
indoc = "2.0.4"
tempfile = "3.8.1"

@ -162,9 +162,8 @@ impl Application {
// Unset path to prevent accidentally saving to the original tutor file.
doc_mut!(editor).set_path(None);
} else if !args.files.is_empty() {
let first = &args.files[0].0; // we know it's not empty
if first.is_dir() {
helix_loader::set_current_working_dir(first.clone())?;
if args.open_cwd {
// NOTE: The working directory is already set to args.files[0] in main()
editor.new_file(Action::VerticalSplit);
let picker = ui::file_picker(".".into(), &config.load().editor);
compositor.push(Box::new(overlaid(picker)));

@ -17,12 +17,15 @@ pub struct Args {
pub log_file: Option<PathBuf>,
pub config_file: Option<PathBuf>,
pub files: Vec<(PathBuf, Position)>,
pub open_cwd: bool,
pub working_directory: Option<PathBuf>,
}
impl Args {
pub fn parse_args() -> Result<Args> {
let mut args = Args::default();
let mut argv = std::env::args().peekable();
let mut line_number = 0;
argv.next(); // skip the program, we don't care about that
@ -59,6 +62,20 @@ impl Args {
Some(path) => args.log_file = Some(path.into()),
None => anyhow::bail!("--log must specify a path to write"),
},
"-w" | "--working-dir" => match argv.next().as_deref() {
Some(path) => {
args.working_directory = if Path::new(path).is_dir() {
Some(PathBuf::from(path))
} else {
anyhow::bail!(
"--working-dir specified does not exist or is not a directory"
)
}
}
None => {
anyhow::bail!("--working-dir must specify an initial working directory")
}
},
arg if arg.starts_with("--") => {
anyhow::bail!("unexpected double dash argument: {}", arg)
}
@ -73,6 +90,13 @@ impl Args {
}
}
}
arg if arg.starts_with('+') => {
let arg = &arg[1..];
line_number = match arg.parse::<usize>() {
Ok(n) => n.saturating_sub(1),
_ => anyhow::bail!("bad line number after +"),
};
}
arg => args.files.push(parse_file(arg)),
}
}
@ -82,6 +106,12 @@ impl Args {
args.files.push(parse_file(&arg));
}
if let Some(file) = args.files.first_mut() {
if line_number != 0 {
file.1.row = line_number;
}
}
Ok(args)
}
}

@ -2186,7 +2186,10 @@ fn global_search(cx: &mut Context) {
let searcher = SearcherBuilder::new()
.binary_detection(BinaryDetection::quit(b'\x00'))
.build();
WalkBuilder::new(search_root)
let mut walk_builder = WalkBuilder::new(search_root);
walk_builder
.hidden(file_picker_config.hidden)
.parents(file_picker_config.parents)
.ignore(file_picker_config.ignore)
@ -2197,9 +2200,13 @@ fn global_search(cx: &mut Context) {
.max_depth(file_picker_config.max_depth)
.filter_entry(move |entry| {
filter_picker_entry(entry, &absolute_root, dedup_symlinks)
})
.build_parallel()
.run(|| {
});
walk_builder
.add_custom_ignore_filename(helix_loader::config_dir().join("ignore"));
walk_builder.add_custom_ignore_filename(".helix/ignore");
walk_builder.build_parallel().run(|| {
let mut searcher = searcher.clone();
let matcher = matcher.clone();
let injector = injector_.clone();
@ -3892,12 +3899,12 @@ fn yank(cx: &mut Context) {
}
fn yank_to_clipboard(cx: &mut Context) {
yank_impl(cx.editor, '*');
yank_impl(cx.editor, '+');
exit_select_mode(cx);
}
fn yank_to_primary_clipboard(cx: &mut Context) {
yank_impl(cx.editor, '+');
yank_impl(cx.editor, '*');
exit_select_mode(cx);
}
@ -3954,13 +3961,13 @@ fn yank_joined(cx: &mut Context) {
fn yank_joined_to_clipboard(cx: &mut Context) {
let line_ending = doc!(cx.editor).line_ending;
yank_joined_impl(cx.editor, line_ending.as_str(), '*');
yank_joined_impl(cx.editor, line_ending.as_str(), '+');
exit_select_mode(cx);
}
fn yank_joined_to_primary_clipboard(cx: &mut Context) {
let line_ending = doc!(cx.editor).line_ending;
yank_joined_impl(cx.editor, line_ending.as_str(), '+');
yank_joined_impl(cx.editor, line_ending.as_str(), '*');
exit_select_mode(cx);
}
@ -3977,12 +3984,12 @@ fn yank_primary_selection_impl(editor: &mut Editor, register: char) {
}
fn yank_main_selection_to_clipboard(cx: &mut Context) {
yank_primary_selection_impl(cx.editor, '*');
yank_primary_selection_impl(cx.editor, '+');
exit_select_mode(cx);
}
fn yank_main_selection_to_primary_clipboard(cx: &mut Context) {
yank_primary_selection_impl(cx.editor, '+');
yank_primary_selection_impl(cx.editor, '*');
exit_select_mode(cx);
}
@ -4083,19 +4090,19 @@ pub(crate) fn paste_bracketed_value(cx: &mut Context, contents: String) {
}
fn paste_clipboard_after(cx: &mut Context) {
paste(cx.editor, '*', Paste::After, cx.count());
paste(cx.editor, '+', Paste::After, cx.count());
}
fn paste_clipboard_before(cx: &mut Context) {
paste(cx.editor, '*', Paste::Before, cx.count());
paste(cx.editor, '+', Paste::Before, cx.count());
}
fn paste_primary_clipboard_after(cx: &mut Context) {
paste(cx.editor, '+', Paste::After, cx.count());
paste(cx.editor, '*', Paste::After, cx.count());
}
fn paste_primary_clipboard_before(cx: &mut Context) {
paste(cx.editor, '+', Paste::Before, cx.count());
paste(cx.editor, '*', Paste::Before, cx.count());
}
fn replace_with_yanked(cx: &mut Context) {
@ -4133,11 +4140,11 @@ fn replace_with_yanked_impl(editor: &mut Editor, register: char, count: usize) {
}
fn replace_selections_with_clipboard(cx: &mut Context) {
replace_with_yanked_impl(cx.editor, '*', cx.count());
replace_with_yanked_impl(cx.editor, '+', cx.count());
}
fn replace_selections_with_primary_clipboard(cx: &mut Context) {
replace_with_yanked_impl(cx.editor, '+', cx.count());
replace_with_yanked_impl(cx.editor, '*', cx.count());
}
fn paste(editor: &mut Editor, register: char, pos: Paste, count: usize) {

@ -6,7 +6,8 @@ use crate::job::Job;
use super::*;
use helix_core::fuzzy::fuzzy_match;
use helix_core::{encoding, line_ending, shellwords::Shellwords};
use helix_core::{encoding, line_ending, path::get_canonicalized_path, shellwords::Shellwords};
use helix_lsp::{OffsetEncoding, Url};
use helix_view::document::DEFAULT_LANGUAGE_NAME;
use helix_view::editor::{Action, CloseError, ConfigEvent};
use serde_json::Value;
@ -921,7 +922,7 @@ fn yank_main_selection_to_clipboard(
return Ok(());
}
yank_primary_selection_impl(cx.editor, '*');
yank_primary_selection_impl(cx.editor, '+');
Ok(())
}
@ -956,7 +957,7 @@ fn yank_joined_to_clipboard(
let doc = doc!(cx.editor);
let default_sep = Cow::Borrowed(doc.line_ending.as_str());
let separator = args.first().unwrap_or(&default_sep);
yank_joined_impl(cx.editor, separator, '*');
yank_joined_impl(cx.editor, separator, '+');
Ok(())
}
@ -969,7 +970,7 @@ fn yank_main_selection_to_primary_clipboard(
return Ok(());
}
yank_primary_selection_impl(cx.editor, '+');
yank_primary_selection_impl(cx.editor, '*');
Ok(())
}
@ -985,7 +986,7 @@ fn yank_joined_to_primary_clipboard(
let doc = doc!(cx.editor);
let default_sep = Cow::Borrowed(doc.line_ending.as_str());
let separator = args.first().unwrap_or(&default_sep);
yank_joined_impl(cx.editor, separator, '+');
yank_joined_impl(cx.editor, separator, '*');
Ok(())
}
@ -998,7 +999,7 @@ fn paste_clipboard_after(
return Ok(());
}
paste(cx.editor, '*', Paste::After, 1);
paste(cx.editor, '+', Paste::After, 1);
Ok(())
}
@ -1011,7 +1012,7 @@ fn paste_clipboard_before(
return Ok(());
}
paste(cx.editor, '*', Paste::Before, 1);
paste(cx.editor, '+', Paste::Before, 1);
Ok(())
}
@ -1024,7 +1025,7 @@ fn paste_primary_clipboard_after(
return Ok(());
}
paste(cx.editor, '+', Paste::After, 1);
paste(cx.editor, '*', Paste::After, 1);
Ok(())
}
@ -1037,7 +1038,7 @@ fn paste_primary_clipboard_before(
return Ok(());
}
paste(cx.editor, '+', Paste::Before, 1);
paste(cx.editor, '*', Paste::Before, 1);
Ok(())
}
@ -1050,7 +1051,7 @@ fn replace_selections_with_clipboard(
return Ok(());
}
replace_with_yanked_impl(cx.editor, '*', 1);
replace_with_yanked_impl(cx.editor, '+', 1);
Ok(())
}
@ -1063,7 +1064,7 @@ fn replace_selections_with_primary_clipboard(
return Ok(());
}
replace_with_yanked_impl(cx.editor, '+', 1);
replace_with_yanked_impl(cx.editor, '*', 1);
Ok(())
}
@ -2408,6 +2409,80 @@ fn redraw(
Ok(())
}
fn move_buffer(
cx: &mut compositor::Context,
args: &[Cow<str>],
event: PromptEvent,
) -> anyhow::Result<()> {
if event != PromptEvent::Validate {
return Ok(());
}
ensure!(args.len() == 1, format!(":move takes one argument"));
let doc = doc!(cx.editor);
let new_path = get_canonicalized_path(&PathBuf::from(args.first().unwrap().to_string()));
let old_path = doc
.path()
.ok_or_else(|| anyhow!("Scratch buffer cannot be moved. Use :write instead"))?
.clone();
let old_path_as_url = doc.url().unwrap();
let new_path_as_url = Url::from_file_path(&new_path).unwrap();
let edits: Vec<(
helix_lsp::Result<helix_lsp::lsp::WorkspaceEdit>,
OffsetEncoding,
String,
)> = doc
.language_servers()
.map(|lsp| {
(
lsp.prepare_file_rename(&old_path_as_url, &new_path_as_url),
lsp.offset_encoding(),
lsp.name().to_owned(),
)
})
.filter(|(f, _, _)| f.is_some())
.map(|(f, encoding, name)| (helix_lsp::block_on(f.unwrap()), encoding, name))
.collect();
for (lsp_reply, encoding, name) in edits {
match lsp_reply {
Ok(edit) => {
if let Err(e) = apply_workspace_edit(cx.editor, encoding, &edit) {
log::error!(
":move command failed to apply edits from lsp {}: {:?}",
name,
e
);
};
}
Err(e) => {
log::error!("LSP {} failed to treat willRename request: {:?}", name, e);
}
};
}
let doc = doc_mut!(cx.editor);
doc.set_path(Some(new_path.as_path()));
if let Err(e) = std::fs::rename(&old_path, &new_path) {
doc.set_path(Some(old_path.as_path()));
bail!("Could not move file: {}", e);
};
doc.language_servers().for_each(|lsp| {
lsp.did_file_rename(&old_path_as_url, &new_path_as_url);
});
cx.editor
.language_servers
.file_event_handler
.file_changed(new_path);
Ok(())
}
pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
TypableCommand {
name: "quit",
@ -3008,6 +3083,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
fun: redraw,
signature: CommandSignature::none(),
},
TypableCommand {
name: "move",
aliases: &[],
doc: "Move the current buffer and its corresponding file to a different path",
fun: move_buffer,
signature: CommandSignature::positional(&[completers::filename]),
},
];
pub static TYPABLE_COMMAND_MAP: Lazy<HashMap<&'static str, &'static TypableCommand>> =

@ -181,8 +181,8 @@ pub fn languages_all() -> std::io::Result<()> {
.language
.sort_unstable_by_key(|l| l.language_id.clone());
let check_binary = |cmd: Option<String>| match cmd {
Some(cmd) => match which::which(&cmd) {
let check_binary = |cmd: Option<&str>| match cmd {
Some(cmd) => match which::which(cmd) {
Ok(_) => column(&format!("✓ {}", cmd), Color::Green),
Err(_) => column(&format!("✘ {}", cmd), Color::Red),
},
@ -192,17 +192,15 @@ pub fn languages_all() -> std::io::Result<()> {
for lang in &syn_loader_conf.language {
column(&lang.language_id, Color::Reset);
// TODO multiple language servers (check binary for each supported language server, not just the first)
let lsp = lang.language_servers.first().and_then(|ls| {
let mut cmds = lang.language_servers.iter().filter_map(|ls| {
syn_loader_conf
.language_server
.get(&ls.name)
.map(|config| config.command.clone())
.map(|config| config.command.as_str())
});
check_binary(lsp);
check_binary(cmds.next());
let dap = lang.debugger.as_ref().map(|dap| dap.command.to_string());
let dap = lang.debugger.as_ref().map(|dap| dap.command.as_str());
check_binary(dap);
for ts_feat in TsFeature::all() {
@ -213,6 +211,12 @@ pub fn languages_all() -> std::io::Result<()> {
}
writeln!(stdout)?;
for cmd in cmds {
column("", Color::Reset);
check_binary(Some(cmd));
writeln!(stdout)?;
}
}
Ok(())
@ -268,15 +272,12 @@ pub fn language(lang_str: String) -> std::io::Result<()> {
}
};
// TODO multiple language servers
probe_protocol(
probe_protocols(
"language server",
lang.language_servers.first().and_then(|ls| {
syn_loader_conf
.language_server
.get(&ls.name)
.map(|config| config.command.clone())
}),
lang.language_servers
.iter()
.filter_map(|ls| syn_loader_conf.language_server.get(&ls.name))
.map(|config| config.command.as_str()),
)?;
probe_protocol(
@ -291,6 +292,33 @@ pub fn language(lang_str: String) -> std::io::Result<()> {
Ok(())
}
/// Display diagnostics about multiple LSPs and DAPs.
fn probe_protocols<'a, I: Iterator<Item = &'a str> + 'a>(
protocol_name: &str,
server_cmds: I,
) -> std::io::Result<()> {
let stdout = std::io::stdout();
let mut stdout = stdout.lock();
let mut server_cmds = server_cmds.peekable();
write!(stdout, "Configured {}s:", protocol_name)?;
if server_cmds.peek().is_none() {
writeln!(stdout, "{}", " None".yellow())?;
return Ok(());
}
writeln!(stdout)?;
for cmd in server_cmds {
let (path, icon) = match which::which(cmd) {
Ok(path) => (path.display().to_string().green(), "✓".green()),
Err(_) => (format!("'{}' not found in $PATH", cmd).red(), "✘".red()),
};
writeln!(stdout, " {} {}: {}", icon, cmd, path)?;
}
Ok(())
}
/// Display diagnostics about LSP and DAP.
fn probe_protocol(protocol_name: &str, server_cmd: Option<String>) -> std::io::Result<()> {
let stdout = std::io::stdout();

@ -66,6 +66,8 @@ FLAGS:
-V, --version Prints version information
--vsplit Splits all given files vertically into different windows
--hsplit Splits all given files horizontally into different windows
-w, --working-dir <path> Specify an initial working directory
+N Open the first given file at line number N
",
env!("CARGO_PKG_NAME"),
VERSION_AND_GIT_HASH,
@ -74,7 +76,7 @@ FLAGS:
helix_loader::default_log_file().display(),
);
let args = Args::parse_args().context("could not parse arguments")?;
let mut args = Args::parse_args().context("could not parse arguments")?;
helix_loader::initialize_config_file(args.config_file.clone());
helix_loader::initialize_log_file(args.log_file.clone());
@ -114,6 +116,18 @@ FLAGS:
setup_logging(args.verbosity).context("failed to initialize logging")?;
// NOTE: Set the working directory early so the correct configuration is loaded. Be aware that
// Application::new() depends on this logic so it must be updated if this changes.
if let Some(path) = &args.working_directory {
helix_loader::set_current_working_dir(path)?;
}
// If the first file is a directory, it will be the working directory and a file picker will be opened
if let Some((path, _)) = args.files.first().filter(|p| p.0.is_dir()) {
helix_loader::set_current_working_dir(path)?;
args.open_cwd = true; // Signal Application that we want to open the picker on "."
}
let config = match Config::load_default() {
Ok(config) => config,
Err(ConfigLoadError::Error(err)) if err.kind() == std::io::ErrorKind::NotFound => {

@ -365,7 +365,7 @@ impl EditorView {
let mut warning_vec = Vec::new();
let mut error_vec = Vec::new();
for diagnostic in doc.diagnostics() {
for diagnostic in doc.shown_diagnostics() {
// Separate diagnostics into different Vecs by severity.
let (vec, scope) = match diagnostic.severity {
Some(Severity::Info) => (&mut info_vec, info),

@ -14,6 +14,7 @@ use helix_core::{
};
use helix_view::{
graphics::{Margin, Rect, Style},
theme::Modifier,
Theme,
};
@ -183,7 +184,9 @@ impl Markdown {
// Transform text in `<code>` blocks into `Event::Code`
let mut in_code = false;
let parser = parser.filter_map(|event| match event {
Event::Html(tag) if *tag == *"<code>" => {
Event::Html(tag)
if tag.starts_with("<code") && matches!(tag.chars().nth(5), Some(' ' | '>')) =>
{
in_code = true;
None
}
@ -275,17 +278,21 @@ impl Markdown {
);
lines.extend(tui_text.lines.into_iter());
} else {
let style = if let Some(Tag::Heading(level, ..)) = tags.last() {
match level {
let style = match tags.last() {
Some(Tag::Heading(level, ..)) => match level {
HeadingLevel::H1 => heading_styles[0],
HeadingLevel::H2 => heading_styles[1],
HeadingLevel::H3 => heading_styles[2],
HeadingLevel::H4 => heading_styles[3],
HeadingLevel::H5 => heading_styles[4],
HeadingLevel::H6 => heading_styles[5],
},
Some(Tag::Emphasis) => text_style.add_modifier(Modifier::ITALIC),
Some(Tag::Strong) => text_style.add_modifier(Modifier::BOLD),
Some(Tag::Strikethrough) => {
text_style.add_modifier(Modifier::CROSSED_OUT)
}
} else {
text_style
_ => text_style,
};
spans.push(Span::styled(text, style));
}

@ -177,6 +177,9 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> Picker
.max_depth(config.file_picker.max_depth)
.filter_entry(move |entry| filter_picker_entry(entry, &absolute_root, dedup_symlinks));
walk_builder.add_custom_ignore_filename(helix_loader::config_dir().join("ignore"));
walk_builder.add_custom_ignore_filename(".helix/ignore");
// We want to exclude files that the editor can't handle yet
let mut type_builder = TypesBuilder::new();
type_builder

@ -795,7 +795,8 @@ impl<T: Item + 'static + Send + Sync> Component for Picker<T> {
// | | | |
// +---------+ +---------+
let render_preview = self.show_preview && area.width > MIN_AREA_WIDTH_FOR_PREVIEW;
let render_preview =
self.show_preview && self.file_fn.is_some() && area.width > MIN_AREA_WIDTH_FOR_PREVIEW;
let picker_width = if render_preview {
area.width / 2

@ -320,6 +320,14 @@ impl AppBuilder {
}
pub fn build(self) -> anyhow::Result<Application> {
if let Some(path) = &self.args.working_directory {
bail!("Changing the working directory to {path:?} is not yet supported for integration tests");
}
if let Some((path, _)) = self.args.files.first().filter(|p| p.0.is_dir()) {
bail!("Having the directory {path:?} in args.files[0] is not yet supported for integration tests");
}
let mut app = Application::new(self.args, self.config, self.syn_conf)?;
if let Some((text, selection)) = self.input {

@ -32,10 +32,21 @@ fn vte_version() -> Option<usize> {
}
/// Describes terminal capabilities like extended underline, truecolor, etc.
#[derive(Copy, Clone, Debug, Default)]
#[derive(Clone, Debug)]
struct Capabilities {
/// Support for undercurled, underdashed, etc.
has_extended_underlines: bool,
/// Support for resetting the cursor style back to normal.
reset_cursor_command: String,
}
impl Default for Capabilities {
fn default() -> Self {
Self {
has_extended_underlines: false,
reset_cursor_command: "\x1B[0 q".to_string(),
}
}
}
impl Capabilities {
@ -54,6 +65,10 @@ impl Capabilities {
|| t.extended_cap("Su").is_some()
|| vte_version() >= Some(5102)
|| matches!(term_program().as_deref(), Some("WezTerm")),
reset_cursor_command: t
.utf8_string_cap(termini::StringCapability::CursorNormal)
.unwrap_or("\x1B[0 q")
.to_string(),
},
}
}
@ -154,7 +169,8 @@ where
fn restore(&mut self, config: Config) -> io::Result<()> {
// reset cursor shape
write!(self.buffer, "\x1B[0 q")?;
self.buffer
.write_all(self.capabilities.reset_cursor_command.as_bytes())?;
if config.enable_mouse_capture {
execute!(self.buffer, DisableMouseCapture)?;
}

@ -18,7 +18,7 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p
parking_lot = "0.12"
arc-swap = { version = "1.6.0" }
gix = { version = "0.48.0", default-features = false , optional = true }
gix = { version = "0.55.0", default-features = false , optional = true }
imara-diff = "0.1.5"
anyhow = "1"

@ -126,7 +126,7 @@ fn find_file_in_commit(repo: &Repository, commit: &Commit, file: &Path) -> Resul
let rel_path = file.strip_prefix(repo_dir)?;
let tree = commit.tree()?;
let tree_entry = tree
.lookup_entry_by_path(rel_path)?
.lookup_entry_by_path(rel_path, &mut Vec::new())?
.context("file is untracked")?;
match tree_entry.mode() {
// not a file, everything is new, do not show diff

@ -1188,41 +1188,52 @@ impl Editor {
}
/// Refreshes the language server for a given document
pub fn refresh_language_servers(&mut self, doc_id: DocumentId) -> Option<()> {
pub fn refresh_language_servers(&mut self, doc_id: DocumentId) {
self.launch_language_servers(doc_id)
}
/// Launch a language server for a given document
fn launch_language_servers(&mut self, doc_id: DocumentId) -> Option<()> {
fn launch_language_servers(&mut self, doc_id: DocumentId) {
if !self.config().lsp.enable {
return None;
return;
}
// if doc doesn't have a URL it's a scratch buffer, ignore it
let doc = self.documents.get_mut(&doc_id)?;
let doc_url = doc.url()?;
let Some(doc) = self.documents.get_mut(&doc_id) else {
return;
};
let Some(doc_url) = doc.url() else {
return;
};
let (lang, path) = (doc.language.clone(), doc.path().cloned());
let config = doc.config.load();
let root_dirs = &config.workspace_lsp_roots;
// try to find language servers based on the language name
let language_servers = lang.as_ref().and_then(|language| {
// store only successfully started language servers
let language_servers = lang.as_ref().map_or_else(HashMap::default, |language| {
self.language_servers
.get(language, path.as_ref(), root_dirs, config.lsp.snippets)
.map_err(|e| {
.filter_map(|(lang, client)| match client {
Ok(client) => Some((lang, client)),
Err(err) => {
log::error!(
"Failed to initialize the language servers for `{}` {{ {} }}",
"Failed to initialize the language servers for `{}` - `{}` {{ {} }}",
language.scope(),
e
)
lang,
err
);
None
}
})
.ok()
.collect::<HashMap<_, _>>()
});
if let Some(language_servers) = language_servers {
if language_servers.is_empty() {
return;
}
let language_id = doc.language_id().map(ToOwned::to_owned).unwrap_or_default();
// only spawn new language servers if the servers aren't the same
let doc_language_servers_not_in_registry =
doc.language_servers.iter().filter(|(name, doc_ls)| {
language_servers
@ -1252,8 +1263,6 @@ impl Editor {
doc.language_servers = language_servers;
}
Some(())
}
fn _refresh(&mut self) {
let config = self.config();
@ -1454,7 +1463,7 @@ impl Editor {
doc.set_version_control_head(self.diff_providers.get_current_head_name(&path));
let id = self.new_document(doc);
let _ = self.launch_language_servers(id);
self.launch_language_servers(id);
id
};

@ -94,9 +94,9 @@ pub fn diff<'doc>(
theme: &Theme,
_is_focused: bool,
) -> GutterFn<'doc> {
let added = theme.get("diff.plus");
let deleted = theme.get("diff.minus");
let modified = theme.get("diff.delta");
let added = theme.get("diff.plus.gutter");
let deleted = theme.get("diff.minus.gutter");
let modified = theme.get("diff.delta.gutter");
if let Some(diff_handle) = doc.diff_handle() {
let hunks = diff_handle.load();
let mut hunk_i = 0;

@ -549,7 +549,7 @@ pub fn parse_macro(keys_str: &str) -> anyhow::Result<Vec<KeyEvent>> {
if c == ">" {
keys_res = Err(anyhow!("Unmatched '>'"));
} else if c != "<" {
keys.push(c);
keys.push(if c == "-" { keys::MINUS } else { c });
i += end_i;
} else {
match s.find('>').context("'>' expected") {
@ -813,6 +813,64 @@ mod test {
},
])
);
assert_eq!(
parse_macro(":w aa-bb.txt<ret>").ok(),
Some(vec![
KeyEvent {
code: KeyCode::Char(':'),
modifiers: KeyModifiers::NONE,
},
KeyEvent {
code: KeyCode::Char('w'),
modifiers: KeyModifiers::NONE,
},
KeyEvent {
code: KeyCode::Char(' '),
modifiers: KeyModifiers::NONE,
},
KeyEvent {
code: KeyCode::Char('a'),
modifiers: KeyModifiers::NONE,
},
KeyEvent {
code: KeyCode::Char('a'),
modifiers: KeyModifiers::NONE,
},
KeyEvent {
code: KeyCode::Char('-'),
modifiers: KeyModifiers::NONE,
},
KeyEvent {
code: KeyCode::Char('b'),
modifiers: KeyModifiers::NONE,
},
KeyEvent {
code: KeyCode::Char('b'),
modifiers: KeyModifiers::NONE,
},
KeyEvent {
code: KeyCode::Char('.'),
modifiers: KeyModifiers::NONE,
},
KeyEvent {
code: KeyCode::Char('t'),
modifiers: KeyModifiers::NONE,
},
KeyEvent {
code: KeyCode::Char('x'),
modifiers: KeyModifiers::NONE,
},
KeyEvent {
code: KeyCode::Char('t'),
modifiers: KeyModifiers::NONE,
},
KeyEvent {
code: KeyCode::Enter,
modifiers: KeyModifiers::NONE,
},
])
);
}
#[test]

@ -75,8 +75,8 @@ impl Registers {
self.clipboard_provider.as_ref(),
self.inner.get(&name),
match name {
'*' => ClipboardType::Clipboard,
'+' => ClipboardType::Selection,
'+' => ClipboardType::Clipboard,
'*' => ClipboardType::Selection,
_ => unreachable!(),
},
)),
@ -95,8 +95,8 @@ impl Registers {
self.clipboard_provider.set_contents(
values.join(NATIVE_LINE_ENDING.as_str()),
match name {
'*' => ClipboardType::Clipboard,
'+' => ClipboardType::Selection,
'+' => ClipboardType::Clipboard,
'*' => ClipboardType::Selection,
_ => unreachable!(),
},
)?;
@ -118,8 +118,8 @@ impl Registers {
'#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support pushing")),
'*' | '+' => {
let clipboard_type = match name {
'*' => ClipboardType::Clipboard,
'+' => ClipboardType::Selection,
'+' => ClipboardType::Clipboard,
'*' => ClipboardType::Selection,
_ => unreachable!(),
};
let contents = self.clipboard_provider.get_contents(clipboard_type)?;
@ -172,8 +172,8 @@ impl Registers {
('#', "<selection indices>"),
('.', "<selection contents>"),
('%', "<document path>"),
('*', "<system clipboard>"),
('+', "<primary clipboard>"),
('+', "<system clipboard>"),
('*', "<primary clipboard>"),
]
.iter()
.copied(),
@ -190,8 +190,8 @@ impl Registers {
match name {
'*' | '+' => {
self.clear_clipboard(match name {
'*' => ClipboardType::Clipboard,
'+' => ClipboardType::Selection,
'+' => ClipboardType::Clipboard,
'*' => ClipboardType::Selection,
_ => unreachable!(),
});
self.inner.remove(&name);

@ -30,6 +30,7 @@ forth-lsp = { command = "forth-lsp" }
fortls = { command = "fortls", args = ["--lowercase_intrinsics"] }
fsharp-ls = { command = "fsautocomplete", config = { AutomaticWorkspaceInit = true } }
gleam = { command = "gleam", args = ["lsp"] }
graphql-language-service = { command = "graphql-lsp", args = ["server", "-m", "stream"] }
haskell-language-server = { command = "haskell-language-server-wrapper", args = ["--lsp"] }
idris2-lsp = { command = "idris2-lsp" }
intelephense = { command = "intelephense", args = ["--stdio"] }
@ -71,21 +72,27 @@ solc = { command = "solc", args = ["--lsp"] }
sourcekit-lsp = { command = "sourcekit-lsp" }
svlangserver = { command = "svlangserver", args = [] }
swipl = { command = "swipl", args = [ "-g", "use_module(library(lsp_server))", "-g", "lsp_server:main", "-t", "halt", "--", "stdio" ] }
tailwindcss-ls = { command = "tailwindcss-language-server", args = ["--stdio"] }
taplo = { command = "taplo", args = ["lsp", "stdio"] }
templ = { command = "templ", args = ["lsp"] }
terraform-ls = { command = "terraform-ls", args = ["serve"] }
texlab = { command = "texlab" }
vala-language-server = { command = "vala-language-server" }
vhdl_ls = { command = "vhdl_ls", args = [] }
vlang-language-server = { command = "v-analyzer" }
vscode-css-language-server = { command = "vscode-css-language-server", args = ["--stdio"], config = { "provideFormatter" = true }}
vscode-css-language-server = { command = "vscode-css-language-server", args = ["--stdio"], config = { provideFormatter = true, css = { validate = { enable = true } } } }
vscode-html-language-server = { command = "vscode-html-language-server", args = ["--stdio"], config = { provideFormatter = true } }
vscode-json-language-server = { command = "vscode-json-language-server", args = ["--stdio"], config = { provideFormatter = true } }
vscode-json-language-server = { command = "vscode-json-language-server", args = ["--stdio"], config = { provideFormatter = true, json = { validate = { enable = true } } } }
vuels = { command = "vue-language-server", args = ["--stdio"], config = { typescript = { tsdk = "node_modules/typescript/lib/" } } }
wgsl_analyzer = { command = "wgsl_analyzer" }
yaml-language-server = { command = "yaml-language-server", args = ["--stdio"] }
zls = { command = "zls" }
blueprint-compiler = { command = "blueprint-compiler", args = ["lsp"] }
typst-lsp = { command = "typst-lsp" }
[language-server.ansible-language-server]
command = "ansible-language-server"
args = ["--stdio"]
[language-server.lua-language-server]
command = "lua-language-server"
@ -110,6 +117,12 @@ functionTypeParameters = true
parameterNames = true
rangeVariableTypes = true
[language-server.golangci-lint-lsp]
command = "golangci-lint-langserver"
[language-server.golangci-lint-lsp.config]
command = ["golangci-lint", "run", "--out-format", "json", "--issues-exit-code=1"]
[language-server.rust-analyzer]
command = "rust-analyzer"
@ -317,7 +330,27 @@ indent = { tab-width = 2, unit = " " }
name = "json"
scope = "source.json"
injection-regex = "json"
file-types = ["json", "jsonc", "arb", "ipynb", "geojson", "gltf"]
file-types = [
"json",
"jsonc",
"arb",
"ipynb",
"geojson",
"gltf",
"webmanifest",
"flake.lock",
".babelrc",
".bowerrc",
".jscrc",
"js.map",
"ts.map",
"css.map",
".jslintrc",
"jsonld",
".vuerc",
"composer.lock",
".watchmanconfig"
]
roots = []
language-servers = [ "vscode-json-language-server" ]
auto-format = true
@ -327,6 +360,22 @@ indent = { tab-width = 2, unit = " " }
name = "json"
source = { git = "https://github.com/tree-sitter/tree-sitter-json", rev = "73076754005a460947cafe8e03a8cf5fa4fa2938" }
[[language]]
name = "json5"
scope = "source.json5"
injection-regex = "json5"
file-types = ["json5"]
roots = []
language-servers = []
comment-token = "//"
indent = { tab-width = 4, unit = " " }
# https://json5.org
[[grammar]]
name = "json5"
source = { git = "https://github.com/Joakker/tree-sitter-json5", rev = "c23f7a9b1ee7d45f516496b1e0e4be067264fa0d" }
[[language]]
name = "c"
scope = "source.c"
@ -368,7 +417,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-c", rev = "7175a6dd
name = "cpp"
scope = "source.cpp"
injection-regex = "cpp"
file-types = ["cc", "hh", "c++", "cpp", "hpp", "h", "ipp", "tpp", "cxx", "hxx", "ixx", "txx", "ino", "C", "H", "cu", "cuh", "cppm"]
file-types = ["cc", "hh", "c++", "cpp", "hpp", "h", "ipp", "tpp", "cxx", "hxx", "ixx", "txx", "ino", "C", "H", "cu", "cuh", "cppm", "h++", "ii", "inl", { suffix = ".hpp.in" }, { suffix = ".h.in" }]
roots = []
comment-token = "//"
language-servers = [ "clangd" ]
@ -415,7 +464,7 @@ language-servers = [ "crystalline" ]
name = "c-sharp"
scope = "source.csharp"
injection-regex = "c-?sharp"
file-types = ["cs"]
file-types = ["cs", "csx", "cake"]
roots = ["sln", "csproj"]
comment-token = "//"
indent = { tab-width = 4, unit = "\t" }
@ -452,7 +501,7 @@ file-types = ["go"]
roots = ["go.work", "go.mod"]
auto-format = true
comment-token = "//"
language-servers = [ "gopls" ]
language-servers = [ "gopls", "golangci-lint-lsp" ]
# TODO: gopls needs utf-8 offsets?
indent = { tab-width = 4, unit = "\t" }
@ -546,7 +595,7 @@ name = "javascript"
scope = "source.js"
injection-regex = "(js|javascript)"
language-id = "javascript"
file-types = ["js", "mjs", "cjs"]
file-types = ["js", "mjs", "cjs", "rules", "es6", "pac", "jakefile"]
shebangs = ["node"]
roots = []
comment-token = "//"
@ -642,7 +691,7 @@ source = { git = "https://github.com/serenadeai/tree-sitter-scss", rev = "c478c6
name = "html"
scope = "text.html.basic"
injection-regex = "html"
file-types = ["html"]
file-types = ["html", "htm", "shtml", "xhtml", "xht", "jsp", "asp", "aspx", "jshtm", "volt", "rhtml"]
roots = []
language-servers = [ "vscode-html-language-server" ]
auto-format = true
@ -656,7 +705,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-html", rev = "29f53
name = "python"
scope = "source.python"
injection-regex = "python"
file-types = ["py","pyi","py3","pyw","ptl",".pythonstartup",".pythonrc","SConstruct"]
file-types = ["py","pyi","py3","pyw","ptl",".pythonstartup",".pythonrc","SConstruct", "rpy", "cpy", "ipy", "pyt", "SConscript"]
shebangs = ["python"]
roots = ["pyproject.toml", "setup.py", "poetry.lock", "pyrightconfig.json"]
comment-token = "#"
@ -708,7 +757,42 @@ source = { git = "https://github.com/nix-community/tree-sitter-nix", rev = "1b69
name = "ruby"
scope = "source.ruby"
injection-regex = "ruby"
file-types = ["rb", "rake", "rakefile", "irb", "gemfile", "gemspec", "Rakefile", "Gemfile", "rabl", "jbuilder", "jb", "Podfile", "podspec", "Vagrantfile", "Brewfile"]
file-types = [
"rb",
"rake",
"rakefile",
"irb",
"gemfile",
"gemspec",
"Rakefile",
"Gemfile",
"rabl",
"jbuilder",
"jb",
"Podfile",
"podspec",
"Vagrantfile",
"Brewfile",
"rjs",
"rbi",
"Guardfile",
"Capfile",
"Cheffile",
"Hobofile",
"Appraisals",
"Rantfile",
"Berksfile",
"Berksfile.lock",
"Thorfile",
"Puppetfile",
"Fastfile",
"Appfile",
"Deliverfile",
"Matchfile",
"Scanfile",
"Snapfile",
"Gymfile"
]
shebangs = ["ruby"]
roots = []
comment-token = "#"
@ -723,7 +807,47 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-ruby", rev = "206c7
name = "bash"
scope = "source.bash"
injection-regex = "(shell|bash|zsh|sh)"
file-types = ["sh", "bash", "zsh", ".bash_login", ".bash_logout", ".bash_profile", ".bashrc", ".profile", ".zshenv", "zshenv", ".zlogin", "zlogin", ".zlogout", "zlogout", ".zprofile", "zprofile", ".zshrc", "zshrc", ".zimrc", "APKBUILD", "PKGBUILD", "eclass", "ebuild", "bazelrc", ".bash_aliases", "Renviron", ".Renviron"]
file-types = [
"sh",
"bash",
"zsh",
".bash_login",
".bash_logout",
".bash_profile",
".bashrc",
".profile",
".zshenv",
"zshenv",
".zlogin",
"zlogin",
".zlogout",
"zlogout",
".zprofile",
"zprofile",
".zshrc",
"zshrc",
".zimrc",
"APKBUILD",
"PKGBUILD",
"eclass",
"ebuild",
"bazelrc",
".bash_aliases",
"Renviron",
".Renviron",
".xprofile",
".xsession",
".xsessionrc",
"zsh-theme",
"ksh",
"cshrc",
"tcshrc",
".yashrc",
".yash_profile",
".hushlogin",
"bashrc_Apple_Terminal",
"zshrc_Apple_Terminal"
]
shebangs = ["sh", "bash", "dash", "zsh"]
roots = []
comment-token = "#"
@ -738,7 +862,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-bash", rev = "275ef
name = "php"
scope = "source.php"
injection-regex = "php"
file-types = ["php", "inc"]
file-types = ["php", "inc", "php4", "php5", "phtml", "ctp"]
shebangs = ["php"]
roots = ["composer.json", "index.php"]
language-servers = [ "intelephense" ]
@ -764,7 +888,7 @@ source = { git = "https://github.com/gbprod/tree-sitter-twig", rev = "807b293fec
name = "latex"
scope = "source.tex"
injection-regex = "tex"
file-types = ["tex", "sty", "cls", "Rd"]
file-types = ["tex", "sty", "cls", "Rd", "bbx", "cbx"]
roots = []
comment-token = "%"
language-servers = [ "texlab" ]
@ -816,6 +940,18 @@ indent = { tab-width = 2, unit = " " }
name = "lean"
source = { git = "https://github.com/Julian/tree-sitter-lean", rev = "d98426109258b266e1e92358c5f11716d2e8f638" }
[[language]]
name = "lpf"
comment-token = "#"
scope = "source.lpf"
file-types = ["lpf"]
roots = []
[[grammar]]
name = "lpf"
source = { git = "https://gitlab.com/TheZoq2/tree-sitter-lpf", rev = "db7372e60c722ca7f12ab359e57e6bf7611ab126" }
[[language]]
name = "julia"
scope = "source.julia"
@ -959,7 +1095,7 @@ file-types = ["yml", "yaml"]
roots = []
comment-token = "#"
indent = { tab-width = 2, unit = " " }
language-servers = [ "yaml-language-server" ]
language-servers = [ "yaml-language-server", "ansible-language-server" ]
injection-regex = "yml|yaml"
[[grammar]]
@ -978,7 +1114,7 @@ indent = { tab-width = 2, unit = " " }
[[grammar]]
name = "haskell"
source = { git = "https://github.com/tree-sitter/tree-sitter-haskell", rev = "98fc7f59049aeb713ab9b72a8ff25dcaaef81087" }
source = { git = "https://github.com/tree-sitter/tree-sitter-haskell", rev = "d7ac98f49e3ed7e17541256fe3881a967d7ffdd3" }
[[language]]
name = "haskell-persistent"
@ -1003,7 +1139,10 @@ language-servers = [ "purescript-language-server" ]
indent = { tab-width = 2, unit = " " }
auto-format = true
formatter = { command = "purs-tidy", args = ["format"] }
grammar = "haskell"
[[grammar]]
name = "purescript"
source = { git = "https://github.com/postsolar/tree-sitter-purescript", rev = "593193b9bf0f46d5eee708a4e53044d2a9054897" }
[[language]]
name = "zig"
@ -1083,7 +1222,8 @@ source = { git = "https://github.com/uyha/tree-sitter-cmake", rev = "6e51463ef30
[[language]]
name = "make"
scope = "source.make"
file-types = ["Makefile", "makefile", "make", "mk"]
file-types = ["Makefile", "makefile", "make", "mk", "mak", "GNUmakefile", "OCamlMakefile"]
shebangs = ["make", "gmake"]
injection-regex = "(make|makefile|Makefile|mk)"
roots = []
comment-token = "#"
@ -1109,7 +1249,7 @@ source = { git = "https://github.com/theHamsta/tree-sitter-glsl", rev = "88408ff
[[language]]
name = "perl"
scope = "source.perl"
file-types = ["pl", "pm", "t"]
file-types = ["pl", "pm", "t", "psgi", "raku", "rakumod", "rakutest", "rakudoc", "nqp", "p6", "pl6", "pm6"]
shebangs = ["perl"]
roots = []
comment-token = "#"
@ -1138,6 +1278,7 @@ roots = []
file-types = ["rkt", "rktd", "rktl", "scrbl"]
shebangs = ["racket"]
comment-token = ";"
indent = { tab-width = 2, unit = " " }
language-servers = [ "racket" ]
grammar = "scheme"
@ -1236,14 +1377,14 @@ source = { git = "https://github.com/Flakebi/tree-sitter-tablegen", rev = "568dd
name = "markdown"
scope = "source.md"
injection-regex = "md|markdown"
file-types = ["md", "markdown", "PULLREQ_EDITMSG"]
file-types = ["md", "markdown", "PULLREQ_EDITMSG", "mkd", "mdwn", "mdown", "markdn", "mdtxt", "mdtext", "workbook"]
roots = [".marksman.toml"]
language-servers = [ "marksman" ]
indent = { tab-width = 2, unit = " " }
[[grammar]]
name = "markdown"
source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "fa6bfd51727e4bef99f7eec5f43947f73d64ea7d", subpath = "tree-sitter-markdown" }
source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "aaf76797aa8ecd9a5e78e0ec3681941de6c945ee", subpath = "tree-sitter-markdown" }
[[language]]
name = "markdown.inline"
@ -1255,7 +1396,7 @@ grammar = "markdown_inline"
[[grammar]]
name = "markdown_inline"
source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "fa6bfd51727e4bef99f7eec5f43947f73d64ea7d", subpath = "tree-sitter-markdown-inline" }
source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "aaf76797aa8ecd9a5e78e0ec3681941de6c945ee", subpath = "tree-sitter-markdown-inline" }
[[language]]
name = "dart"
@ -1316,7 +1457,7 @@ source = { git = "https://github.com/the-mikedavis/tree-sitter-git-commit", rev
name = "diff"
scope = "source.diff"
roots = []
file-types = ["diff", "patch"]
file-types = ["diff", "patch", "rej"]
injection-regex = "diff"
comment-token = "#"
indent = { tab-width = 2, unit = " " }
@ -1394,6 +1535,7 @@ scope = "source.graphql"
injection-regex = "graphql"
file-types = ["gql", "graphql", "graphqls"]
roots = []
language-servers = [ "graphql-language-service" ]
indent = { tab-width = 2, unit = " " }
[[grammar]]
@ -1554,7 +1696,10 @@ file-types = ["ron"]
roots = []
comment-token = "//"
indent = { tab-width = 4, unit = " " }
grammar = "rust"
[[grammar]]
name = "ron"
source = { git = "https://github.com/zee-editor/tree-sitter-ron", rev = "7762d709a0f7c1f9e269d0125a2e8a7a69006146" }
[[language]]
name = "robot"
@ -1574,7 +1719,7 @@ source = { git = "https://github.com/Hubro/tree-sitter-robot", rev = "322e4cc657
name = "r"
scope = "source.r"
injection-regex = "(r|R)"
file-types = ["r", "R", ".Rprofile", "Rprofile.site"]
file-types = ["r", "R", ".Rprofile", "Rprofile.site", ".RHistory"]
shebangs = ["r", "R"]
roots = []
comment-token = "#"
@ -1659,7 +1804,7 @@ source = { git = "https://github.com/phoenixframework/tree-sitter-heex", rev = "
[[language]]
name = "sql"
scope = "source.sql"
file-types = ["sql"]
file-types = ["sql", "dsql"]
roots = []
comment-token = "--"
indent = { tab-width = 4, unit = " " }
@ -1667,7 +1812,7 @@ injection-regex = "sql"
[[grammar]]
name = "sql"
source = { git = "https://github.com/DerekStride/tree-sitter-sql", rev = "7cbac0472e5b8f8486ce64ffbcf1982d5cd5fc8d" }
source = { git = "https://github.com/DerekStride/tree-sitter-sql", rev = "eeab7240a11098724e6f95bc57cc3ceaf5487d5f" }
[[language]]
name = "gdscript"
@ -2196,13 +2341,68 @@ injection-regex = "kdl"
[[grammar]]
name = "kdl"
source = { git = "https://github.com/Unoqwy/tree-sitter-kdl", rev = "e1cd292c6d15df6610484e1d4b5c987ecad52373" }
source = { git = "https://github.com/amaanq/tree-sitter-kdl", rev = "3ca569b9f9af43593c24f9e7a21f02f43a13bb88" }
[[language]]
name = "xml"
scope = "source.xml"
injection-regex = "xml"
file-types = ["xml", "mobileconfig", "plist", "xib", "storyboard", "svg", "xsd", "gml", "xaml", "gir", "rss", "atom", "opml"]
file-types = [
"xml",
"mobileconfig",
"plist",
"xib",
"storyboard",
"svg",
"xsd",
"gml",
"xaml",
"gir",
"rss",
"atom",
"opml",
"policy",
"ascx",
"axml",
"axaml",
"bpmn",
"cpt",
"csl",
"csproj.user",
"dita",
"ditamap",
"dtml",
"fxml",
"iml",
"isml",
"jmx",
"launch",
"menu",
"mxml",
"nuspec",
"pt",
"publishsettings",
"pubxml",
"pubxml.user",
"rbxlx",
"rbxmx",
"rng",
"shproj",
"tld",
"tmx",
"vbproj.user",
"vcxproj",
"vcxproj.filters",
"wsdl",
"wxi",
"wxs",
"xbl",
"xlf",
"xliff",
"xpdl",
"xul",
"xoml"
]
indent = { tab-width = 2, unit = " " }
roots = []
@ -2290,7 +2490,11 @@ file-types = [
"container",
"volume",
"kube",
"network"
"network",
".editorconfig",
"properties",
"cfg",
"directory"
]
injection-regex = "ini"
comment-token = "#"
@ -2495,7 +2699,7 @@ source = { git = "https://github.com/erasin/tree-sitter-po", rev = "417cee9abb20
[[language]]
name = "nasm"
scope = "source.nasm"
file-types = ["asm", "s", "S", "nasm"]
file-types = ["asm", "S", "nasm"]
injection-regex = "n?asm"
roots = []
comment-token = ";"
@ -2505,6 +2709,19 @@ indent = { tab-width = 8, unit = " " }
name = "nasm"
source = { git = "https://github.com/naclsn/tree-sitter-nasm", rev = "a0db15db6fcfb1bf2cc8702500e55e558825c48b" }
[[language]]
name = "gas"
scope = "source.gas"
file-types = ["s"]
injection-regex = "gas"
roots = []
comment-token = "#"
indent = { tab-width = 8, unit = " " }
[[grammar]]
name = "gas"
source = { git = "https://github.com/sirius94/tree-sitter-gas", rev = "60f443646b20edee3b7bf18f3a4fb91dc214259a" }
[[language]]
name = "rst"
scope = "source.rst"
@ -2686,7 +2903,7 @@ name = "fsharp"
scope = "source.fs"
roots = ["sln", "fsproj"]
injection-regex = "fsharp"
file-types = ["fs", "fsx"]
file-types = ["fs", "fsx", "fsi", "fsscript"]
comment-token = "//"
indent = { tab-width = 4, unit = " " }
auto-format = true
@ -2718,6 +2935,27 @@ roots = []
indent = { tab-width = 2, unit = " " }
grammar = "html"
[[language]]
name = "typst"
scope = "source.typst"
injection-regex = "typst"
file-types = ["typst", "typ"]
roots = []
comment-token = "//"
language-servers = ["typst-lsp"]
indent = { tab-width = 2, unit = " " }
[language.auto-pairs]
'(' = ')'
'{' = '}'
'[' = ']'
'$' = '$'
'"' = '"'
[[grammar]]
name = "typst"
source = { git = "https://github.com/uben0/tree-sitter-typst", rev = "e35aa22395fdde82bbc4b5700c324ce346dfc9e5" }
[[language]]
name = "nunjucks"
scope = "text.html.nunjucks"
@ -2805,3 +3043,16 @@ roots = []
[[grammar]]
name = "gemini"
source = { git = "https://git.sr.ht/~sfr/tree-sitter-gemini", rev = "3cc5e4bdf572d5df4277fc2e54d6299bd59a54b3" }
[[language]]
name = "templ"
scope = "source.templ"
file-types = ["templ"]
roots = ["go.work", "go.mod"]
comment-token = "//"
indent = { tab-width = 2, unit = " " }
language-servers = [ "templ" ]
[[grammar]]
name = "templ"
source = { git = "https://github.com/vrischmann/tree-sitter-templ", rev = "ea56ac0655243490a4929a988f4eaa91dfccc995" }

@ -107,6 +107,8 @@
; Types
; -----
(type_parameter
name: (type_identifier) @type.parameter)
(type_identifier) @type
(predefined_type) @type.builtin

@ -1,6 +1,18 @@
; Scopes
;-------
[
(type_alias_declaration)
(class_declaration)
(interface_declaration)
] @local.scope
; Definitions
;------------
(type_parameter
name: (type_identifier) @local.definition)
; Javascript and Typescript Treesitter grammars deviate when defining the
; tree structure for parameters, so we need to address them in each specific
; language instead of ecma.
@ -14,3 +26,8 @@
; (i?: t = 1) // Invalid but still posible to hihglight.
(optional_parameter
(identifier) @local.definition)
; References
;-----------
(type_identifier) @local.reference

@ -2,6 +2,7 @@
(function_definition)
(if_statement)
(for_statement)
(while_statement)
(case_statement)
(pipeline)
] @indent

@ -7,31 +7,31 @@
; Hint level tags
((tag (name) @hint)
(#match? @hint "^(HINT|MARK)$"))
(#match? @hint "^(HINT|MARK|PASSED|STUB|MOCK)$"))
("text" @hint
(#match? @hint "^(HINT|MARK)$"))
(#match? @hint "^(HINT|MARK|PASSED|STUB|MOCK)$"))
; Info level tags
((tag (name) @info)
(#match? @info "^(INFO|NOTE|TODO)$"))
(#match? @info "^(INFO|NOTE|TODO|PERF|OPTIMIZE|PERFORMANCE|QUESTION|ASK)$"))
("text" @info
(#match? @info "^(INFO|NOTE|TODO)$"))
(#match? @info "^(INFO|NOTE|TODO|PERF|OPTIMIZE|PERFORMANCE|QUESTION|ASK)$"))
; Warning level tags
((tag (name) @warning)
(#match? @warning "^(HACK|WARN|WARNING)$"))
(#match? @warning "^(HACK|WARN|WARNING|TEST|TEMP)$"))
("text" @warning
(#match? @warning "^(HACK|WARN|WARNING)$"))
(#match? @warning "^(HACK|WARN|WARNING|TEST|TEMP)$"))
; Error level tags
((tag (name) @error)
(#match? @error "^(BUG|FIXME|ISSUE|XXX)$"))
(#match? @error "^(BUG|FIXME|ISSUE|XXX|FIX|SAFETY|FIXIT|FAILED|DEBUG)$"))
("text" @error
(#match? @error "^(BUG|FIXME|ISSUE|XXX)$"))
(#match? @error "^(BUG|FIXME|ISSUE|XXX|FIX|SAFETY|FIXIT|FAILED|DEBUG)$"))
(tag
(name) @ui.text

@ -0,0 +1,21 @@
(comment) @comment
(number) @constant.numeric
(directive_name) @keyword.directive
(symbol) @variable
(label) @function
(label)
(instruction_prefix) @keyword
(instruction_name) @function.special
(register) @constant.builtin
(string) @string
(char) @constant.character
(type) @type
(constant "$" @constant)
(operand_modifier) @attribute
(expression
["-" "+" "*" "/" "="] @operator)
["(" ")"] @punctuation.bracket
["," ":"] @punctuation.delimiter

@ -0,0 +1,2 @@
((comment) @injection.content
(#set! injection.language "comment"))

@ -0,0 +1,2 @@
(comment) @comment.inside
(comment)+ @comment.around

@ -11,6 +11,18 @@
function: (selector_expression
field: (field_identifier) @function.method))
; Types
(type_parameter_list
(parameter_declaration
name: (identifier) @type.parameter))
((type_identifier) @type.builtin
(match? @type.builtin "^(any|bool|byte|comparable|complex128|complex64|error|float32|float64|int|int16|int32|int64|int8|rune|string|uint|uint16|uint32|uint64|uint8|uintptr)$"))
(type_identifier) @type
; Function definitions
(function_declaration
@ -24,20 +36,16 @@
; Identifiers
((identifier) @constant (match? @constant "^[A-Z][A-Z\\d_]+$"))
(const_spec
name: (identifier) @constant)
(parameter_declaration (identifier) @variable.parameter)
(variadic_parameter_declaration (identifier) @variable.parameter)
((type_identifier) @type.builtin
(match? @type.builtin "^(any|bool|byte|comparable|complex128|complex64|error|float32|float64|int|int16|int32|int64|int8|rune|string|uint|uint16|uint32|uint64|uint8|uintptr)$"))
(type_identifier) @type
(type_spec
name: (type_identifier) @constructor)
(field_identifier) @variable.other.member
(keyed_element (literal_element (identifier) @variable.other.member))
(identifier) @variable
(package_identifier) @namespace

@ -1,9 +1,17 @@
; Scopes
(block) @local.scope
[
(function_declaration)
(type_declaration)
(block)
] @local.scope
; Definitions
(type_parameter_list
(parameter_declaration
name: (identifier) @local.definition))
(parameter_declaration (identifier) @local.definition)
(variadic_parameter_declaration (identifier) @local.definition)
@ -27,4 +35,4 @@
(identifier) @local.reference
(field_identifier) @local.reference
(type_identifier) @local.reference

@ -33,6 +33,11 @@
;; ----------------------------------------------------------------------------
;; Keywords, operators, includes
[
"forall"
"∀"
] @keyword.control.repeat
(pragma) @constant.macro
[
@ -68,10 +73,7 @@
"@"
] @operator
(qualified_module (module) @constructor)
(qualified_type (module) @namespace)
(qualified_variable (module) @namespace)
(import (module) @namespace)
(module) @namespace
[
(where)
@ -92,8 +94,6 @@
"do"
"mdo"
"rec"
"forall"
"∀"
"infix"
"infixl"
"infixr"
@ -104,22 +104,35 @@
;; Functions and variables
(signature name: (variable) @type)
(function name: (variable) @function)
(variable) @variable
"_" @variable.builtin
(function
name: (variable) @function
patterns: (patterns))
((signature (fun)) . (function (variable) @function))
((signature (context (fun))) . (function (variable) @function))
((signature (forall (context (fun)))) . (function (variable) @function))
(exp_infix (variable) @operator) ; consider infix functions as operators
("@" @namespace) ; "as" pattern operator, e.g. x@Constructor
(exp_infix (exp_name) @function)
(exp_apply . (exp_name (variable) @function))
(exp_apply . (exp_name (qualified_variable (variable) @function)))
(variable) @variable
(pat_wildcard) @variable
;; ----------------------------------------------------------------------------
;; Types
(type) @type
(type_variable) @type.parameter
(constructor) @constructor
; True or False
((constructor) @_bool (#match? @_bool "(True|False)")) @constant.builtin.boolean
;; ----------------------------------------------------------------------------
;; Quasi-quotes
(quoter) @function
; Highlighting of quasiquote_body is handled by injections.scm

@ -0,0 +1,11 @@
(string) @string
(identifier) @constant
(number) @constant.numeric
(null) @constant.builtin
[(true) (false)] @constant.builtin.boolean
(comment) @comment

@ -1,12 +1,12 @@
(comment) @comment
(single_line_comment) @comment
(multi_line_comment) @comment
(node
name: (identifier) @function)
(identifier) @variable)
(prop (identifier) @attribute)
(type) @type
(bare_identifier) @variable.other.member
(type (_) @type) @punctuation.bracket
(keyword) @keyword

@ -0,0 +1,3 @@
(node_children) @indent
"}" @outdent

@ -0,0 +1,27 @@
(type (_) @test.inside) @test.around
(node
children: (node_children)? @class.inside) @class.around
(node
children: (node_children)? @function.inside) @function.around
(node (identifier) @function.movement)
[
(single_line_comment)
(multi_line_comment)
] @comment.inside
[
(single_line_comment)+
(multi_line_comment)+
] @comment.around
[
(prop)
(value)
] @parameter.inside
(value (type) ? (_) @parameter.inside @parameter.movement . ) @parameter.around

@ -244,7 +244,10 @@
. (identifier)) @namespace
((type_identifier) @type.builtin
(#match? @function.builtin "^(Byte|Short|Int|Long|UByte|UShort|UInt|ULong|Float|Double|Boolean|Char|String|Array|ByteArray|ShortArray|IntArray|LongArray|UByteArray|UShortArray|UIntArray|ULongArray|FloatArray|DoubleArray|BooleanArray|CharArray|Map|Set|List|EmptyMap|EmptySet|EmptyList|MutableMap|MutableSet|MutableList)$"))
(#match? @type.builtin "^(Byte|Short|Int|Long|UByte|UShort|UInt|ULong|Float|Double|Boolean|Char|String|Array|ByteArray|ShortArray|IntArray|LongArray|UByteArray|UShortArray|UIntArray|ULongArray|FloatArray|DoubleArray|BooleanArray|CharArray|Map|Set|List|EmptyMap|EmptySet|EmptyList|MutableMap|MutableSet|MutableList)$"))
(type_parameter
(type_identifier) @type.parameter)
(type_identifier) @type

@ -0,0 +1,15 @@
; Scopes
[
(class_declaration)
(function_declaration)
] @local.scope
; Definitions
(type_parameter
(type_identifier) @local.definition)
; References
(type_identifier) @local.reference

@ -0,0 +1,19 @@
[
"SYSCONFIG"
"BLOCK"
"LOCATE"
"COMP"
"FREQUENCY"
"PORT"
"IOBUF"
] @keyword
["SITE"] @keyword.storage
["="] @operator
((number) @constant.numeric)
((string) @string)
((line_comment) @comment)

@ -5,6 +5,20 @@
((((comment) @injection.language) .
(indented_string_expression (string_fragment) @injection.content))
(#set! injection.combined))
((binding
(comment) @injection.language
expression: (indented_string_expression (string_fragment) @injection.content))
(#set! injection.combined))
; Common attribute keys corresponding to Python scripts,
; such as those for NixOS VM tests in nixpkgs/nixos/tests.
((binding
attrpath: (attrpath (identifier) @_path)
expression: (indented_string_expression
(string_fragment) @injection.content))
(#match? @_path "(^|\\.)testScript$")
(#set! injection.language "python")
(#set! injection.combined))
; Common attribute keys corresponding to scripts,
; such as those of stdenv.mkDerivation.

@ -8,6 +8,8 @@
[(class_name) (class_type_name) (type_constructor)] @type
(type_variable) @type.parameter
[(constructor_name) (tag)] @constructor
; Functions

@ -1 +1,149 @@
; inherits: haskell
; ----------------------------------------------------------------------------
; Literals and comments
(integer) @constant.numeric.integer
(exp_negation) @constant.numeric.integer
(exp_literal (number)) @constant.numeric.float
(char) @constant.character
[
(string)
(triple_quote_string)
] @string
(comment) @comment
; ----------------------------------------------------------------------------
; Punctuation
[
"("
")"
"{"
"}"
"["
"]"
] @punctuation.bracket
[
(comma)
";"
] @punctuation.delimiter
; ----------------------------------------------------------------------------
; Keywords, operators, includes
; This needs to come before the other "else" in
; order to be highlighted correctly
(class_instance "else" @keyword)
[
"if"
"then"
"else"
"case"
"of"
] @keyword.control.conditional
[
"import"
"module"
] @keyword.control.import
[
(operator)
(constructor_operator)
(type_operator)
(qualified_module) ; grabs the `.` (dot), ex: import System.IO
(all_names)
; `_` wildcards in if-then-else and case-of expressions,
; as well as record updates and operator sections
(wildcard)
"="
"|"
"::"
"∷"
"=>"
"⇒"
"<="
"⇐"
"->"
"→"
"<-"
"←"
"\\"
"`"
"@"
] @operator
(qualified_module (module) @constructor)
(module) @namespace
(qualified_type (module) @namespace)
(qualified_variable (module) @namespace)
(import (module) @namespace)
[
(where)
"let"
"in"
"class"
"instance"
"derive"
"foreign"
"data"
"newtype"
"type"
"as"
"hiding"
"do"
"ado"
"forall"
"∀"
"infix"
"infixl"
"infixr"
] @keyword
(type_role_declaration
"role" @keyword
role: (type_role) @keyword)
(hole) @label
; ----------------------------------------------------------------------------
; Functions and variables
(row_field (field_name) @variable.other.member)
(record_field (field_name) @variable.other.member)
(record_accessor (variable) @variable.other.member)
(exp_record_access (variable) @variable.other.member)
(signature name: (variable) @type)
(function name: (variable) @function)
(class_instance (instance_name) @function)
(derive_declaration (instance_name) @function)
; true or false
((variable) @constant.builtin.boolean
(#match? @constant.builtin.boolean "^(true|false)$"))
; The former one works for `tree-sitter highlight` but not in Helix/Kakoune.
; The latter two work in Helix (but not Kakoune) and are a good compromise between not highlighting anything at all
; as an operator and leaving it to the child nodes, and highlighting everything as an operator.
(exp_ticked (_) @operator)
(exp_ticked (exp_name (variable) @operator))
(exp_ticked (exp_name (qualified_variable (variable) @operator)))
(variable) @variable
("@" @namespace) ; "as" pattern operator, e.g. x@Constructor
; ----------------------------------------------------------------------------
; Types
(type) @type
(constructor) @constructor

@ -1 +1,2 @@
; inherits: haskell
((comment) @injection.content
(#set! injection.language "comment"))

@ -1 +1,4 @@
; inherits: haskell
(signature name: (variable)) @local.definition
(function name: (variable)) @local.definition
(pat_name (variable)) @local.definition
(exp_name (variable)) @local.reference

@ -0,0 +1,13 @@
(comment) @comment.inside
[
(data)
(type)
(newtype)
] @class.around
((signature)? (function rhs:(_) @function.inside)) @function.around
(exp_lambda) @function.around
(data (type_variable) @parameter.inside)
(patterns (_) @parameter.inside)

@ -1 +1,43 @@
; inherits: rust
; Literals
;------------
(string) @string
(boolean) @constant.builtin.boolean
(integer) @constant.numeric.integer
(float) @constant.numeric.float
(char) @constant.character
; Structs
;------------
(enum_variant) @type.enum.variant
(struct_entry (_) @variable.other.member ":")
(struct_name (identifier)) @type
; Comments
;------------
(line_comment) @comment.line
(block_comment) @comment.block
; Punctuation
;------------
"," @punctuation.delimiter
":" @punctuation.delimiter
"(" @punctuation.bracket
")" @punctuation.bracket
"[" @punctuation.bracket
"]" @punctuation.bracket
"{" @punctuation.bracket
"}" @punctuation.bracket
; Special
;------------
(escape_sequence) @constant.character.escape

@ -1 +1,12 @@
; inherits: rust
[
(array)
(map)
(tuple)
(struct)
] @indent
[
"}"
"]"
")"
] @outdent

@ -1 +1,2 @@
; inherits: rust
([(line_comment) (block_comment)] @injection.content
(#set! injection.language "comment"))

@ -9,6 +9,13 @@
; Types
; -------
(type_parameters
(type_identifier) @type.parameter)
(constrained_type_parameter
left: (type_identifier) @type.parameter)
(optional_type_parameter
name: (type_identifier) @type.parameter)
; ---
; Primitives
; ---

@ -1,6 +1,12 @@
([(line_comment) (block_comment)] @injection.content
(#set! injection.language "comment"))
((macro_invocation
macro: (identifier) @_html (#eq? @_html "html")
(token_tree) @injection.content)
(#set! injection.language "html")
(#set! injection.include-children))
((macro_invocation
(token_tree) @injection.content)
(#set! injection.language "rust")

@ -2,6 +2,12 @@
[
(function_item)
(struct_item)
(enum_item)
(union_item)
(type_item)
(trait_item)
(impl_item)
(closure_expression)
(block)
] @local.scope
@ -11,8 +17,15 @@
(parameter
(identifier) @local.definition)
(type_parameters
(type_identifier) @local.definition)
(constrained_type_parameter
left: (type_identifier) @local.definition)
(optional_type_parameter
name: (type_identifier) @local.definition)
(closure_parameters (identifier) @local.definition)
; References
(identifier) @local.reference
(type_identifier) @local.reference

@ -0,0 +1,43 @@
; This roughly follows the description at: https://github.com/ds26gte/scmindent#how-subforms-are-indented
; Exclude literals in the first patterns, since different rules apply for them.
; Similarly, exclude certain keywords (detected by a regular expression).
; If a list has 2 elements on the first line, it is aligned to the second element.
(list . (_) @first . (_) @anchor
(#same-line? @first @anchor)
(#set! "scope" "tail")
(#not-kind-eq? @first "boolean") (#not-kind-eq? @first "character") (#not-kind-eq? @first "string") (#not-kind-eq? @first "number")
(#not-match? @first "def.*|let.*|set!")) @align
; If the first element in a list is also a list and on a line by itself, the outer list is aligned to it
(list . (list) @anchor .
(#set! "scope" "tail")
(#not-kind-eq? @first "boolean") (#not-kind-eq? @first "character") (#not-kind-eq? @first "string") (#not-kind-eq? @first "number")) @align
(list . (list) @anchor . (_) @second
(#not-same-line? @anchor @second)
(#set! "scope" "tail")
(#not-kind-eq? @first "boolean") (#not-kind-eq? @first "character") (#not-kind-eq? @first "string") (#not-kind-eq? @first "number")
(#not-match? @first "def.*|let.*|set!")) @align
; If the first element in a list is not a list and on a line by itself, the outer list is aligned to
; it plus 1 additional space. This cannot currently be modelled exactly by our indent queries,
; but the following is equivalent, assuming that:
; - the indent width is 2 (the default for scheme)
; - There is no space between the opening parenthesis of the list and the first element
(list . (_) @first .
(#not-kind-eq? @first "boolean") (#not-kind-eq? @first "character") (#not-kind-eq? @first "string") (#not-kind-eq? @first "number")
(#not-match? @first "def.*|let.*|set!")) @indent
(list . (_) @first . (_) @second
(#not-same-line? @first @second)
(#not-kind-eq? @first "boolean") (#not-kind-eq? @first "character") (#not-kind-eq? @first "string") (#not-kind-eq? @first "number")
(#not-match? @first "def.*|let.*|set!")) @indent
; If the first element in a list is a literal, align the list to it
(list . [(boolean) (character) (string) (number)] @anchor
(#set! "scope" "tail")) @align
; If the first element is among a set of predefined keywords, align the list to this element
; plus 1 space (using the same workaround as above for now). This is a simplification since actually
; the second line of the list should be indented by 2 spaces more in some cases. Supporting this would
; be possible but require significantly more patterns.
(list . (symbol) @first
(#match? @first "def.*|let.*|set!")) @indent

@ -1,134 +1,168 @@
(invocation
(object_reference
name: (identifier) @function.method))
[
(keyword_gist)
(keyword_btree)
(keyword_hash)
(keyword_gist)
(keyword_spgist)
(keyword_gin)
(keyword_brin)
(cast)
(group_concat)
(invocation)
(keyword_array)
] @function.builtin
(table_reference
name: (identifier) @namespace)
(object_reference
name: (identifier) @variable.other.member)
(relation
table_alias: (identifier) @variable.parameter)
(field
name: (identifier) @variable.other.member)
alias: (identifier) @variable.parameter)
(field
table_alias: (identifier) @variable.parameter
name: (identifier) @variable.other.member)
(comment) @comment
(term
alias: (identifier) @variable.parameter)
[
"("
")"
] @punctuation.bracket
(term
value: (cast
name: (keyword_cast) @function.builtin
parameter: [(literal)]?))
[
";"
","
"."
] @punctuation.delimiter
(literal) @string
(comment) @comment.line
(marginalia) @comment.block
(binary_expression
operator: _ @operator)
((literal) @constant.numeric.integer
(#match? @constant.numeric.integer "^-?\\d+$"))
(unary_expression
operator: _ @operator)
((literal) @constant.numeric.float
(#match? @constant.numeric.float "^-?\\d*\\.\\d*$"))
(all_fields) @special
(parameter) @variable.parameter
[
(keyword_null)
(keyword_true)
(keyword_false)
] @constant.builtin
] @constant.builtin.boolean
((literal) @constant.numeric
(#match? @constant.numeric "^-?\\d*\\.?\\d*$"))
[
(keyword_asc)
(keyword_desc)
(keyword_terminated)
(keyword_escaped)
(keyword_unsigned)
(keyword_nulls)
(keyword_last)
(keyword_delimited)
(keyword_replication)
(keyword_auto_increment)
(keyword_default)
(keyword_collate)
(keyword_concurrently)
(keyword_engine)
(keyword_always)
(keyword_generated)
(keyword_preceding)
(keyword_following)
(keyword_first)
(keyword_current_timestamp)
(keyword_immutable)
(keyword_atomic)
(keyword_parallel)
(keyword_leakproof)
(keyword_safe)
(keyword_cost)
(keyword_strict)
] @attribute
(literal) @string
[
(keyword_materialized)
(keyword_recursive)
(keyword_temp)
(keyword_temporary)
(keyword_unlogged)
(keyword_external)
(keyword_parquet)
(keyword_csv)
(keyword_rcfile)
(keyword_textfile)
(keyword_orc)
(keyword_avro)
(keyword_jsonfile)
(keyword_sequencefile)
(keyword_volatile)
] @keyword.storage.type
[
(keyword_case)
(keyword_when)
(keyword_then)
(keyword_else)
] @keyword.control.conditional
[
(keyword_select)
(keyword_from)
(keyword_where)
(keyword_index)
(keyword_join)
(keyword_primary)
(keyword_delete)
(keyword_create)
(keyword_insert)
(keyword_merge)
(keyword_distinct)
(keyword_replace)
(keyword_update)
(keyword_into)
(keyword_overwrite)
(keyword_matched)
(keyword_values)
(keyword_value)
(keyword_attribute)
(keyword_set)
(keyword_from)
(keyword_left)
(keyword_right)
(keyword_outer)
(keyword_inner)
(keyword_full)
(keyword_outer)
(keyword_cross)
(keyword_join)
(keyword_lateral)
(keyword_on)
(keyword_not)
(keyword_order)
(keyword_group)
(keyword_partition)
(keyword_by)
(keyword_group)
(keyword_with)
(keyword_as)
(keyword_having)
(keyword_desc)
(keyword_asc)
(keyword_limit)
(keyword_offset)
(keyword_primary)
(keyword_create)
(keyword_alter)
(keyword_change)
(keyword_analyze)
(keyword_modify)
(keyword_drop)
(keyword_add)
(keyword_table)
(keyword_tables)
(keyword_view)
(keyword_materialized)
(keyword_column)
(keyword_key)
(keyword_as)
(keyword_distinct)
(keyword_references)
(keyword_foreign)
(keyword_constraint)
; (keyword_cast)
; (keyword_group_concat)
(keyword_separator)
(keyword_max)
(keyword_min)
(keyword_avg)
(keyword_end)
(keyword_force)
(keyword_ignore)
(keyword_using)
(keyword_use)
(keyword_index)
(keyword_for)
(keyword_if)
(keyword_exists)
(keyword_auto_increment)
(keyword_generated)
(keyword_always)
(keyword_collate)
(keyword_character)
(keyword_engine)
(keyword_default)
(keyword_cascade)
(keyword_restrict)
(keyword_with)
(keyword_max)
(keyword_min)
(keyword_avg)
(keyword_column)
(keyword_columns)
(keyword_cross)
(keyword_lateral)
(keyword_natural)
(keyword_alter)
(keyword_drop)
(keyword_add)
(keyword_view)
(keyword_end)
(keyword_is)
(keyword_using)
(keyword_between)
(keyword_window)
(keyword_no)
(keyword_data)
(keyword_type)
@ -136,208 +170,222 @@
(keyword_to)
(keyword_schema)
(keyword_owner)
(keyword_temp)
(keyword_temporary)
(keyword_unlogged)
(keyword_union)
(keyword_authorization)
(keyword_all)
(keyword_any)
(keyword_some)
(keyword_except)
(keyword_intersect)
(keyword_returning)
(keyword_begin)
(keyword_commit)
(keyword_rollback)
(keyword_transaction)
(keyword_only)
(keyword_like)
(keyword_similar)
(keyword_over)
(keyword_nulls)
(keyword_first)
(keyword_change)
(keyword_modify)
(keyword_after)
(keyword_last)
(keyword_window)
(keyword_before)
(keyword_range)
(keyword_rows)
(keyword_groups)
(keyword_between)
(keyword_unbounded)
(keyword_preceding)
(keyword_following)
(keyword_exclude)
(keyword_current)
(keyword_row)
(keyword_ties)
(keyword_others)
(keyword_only)
(keyword_unique)
(keyword_foreign)
(keyword_references)
(keyword_concurrently)
; (keyword_btree)
; (keyword_hash)
; (keyword_gist)
; (keyword_spgist)
; (keyword_gin)
; (keyword_brin)
(keyword_like)
(keyword_similar)
(keyword_preserve)
(keyword_unsigned)
(keyword_zerofill)
(keyword_conflict)
(keyword_do)
(keyword_nothing)
(keyword_high_priority)
(keyword_low_priority)
(keyword_delayed)
(keyword_recursive)
(keyword_cascaded)
(keyword_local)
(keyword_current_timestamp)
(keyword_check)
(keyword_option)
(keyword_format)
(keyword_fields)
(keyword_row)
(keyword_sort)
(keyword_compute)
(keyword_comment)
(keyword_location)
(keyword_cached)
(keyword_uncached)
(keyword_lines)
(keyword_stored)
(keyword_virtual)
(keyword_partitioned)
(keyword_analyze)
(keyword_explain)
(keyword_verbose)
(keyword_truncate)
(keyword_rewrite)
(keyword_optimize)
(keyword_vacuum)
(keyword_wait)
(keyword_nowait)
(keyword_trigger)
(keyword_function)
(keyword_returns)
(keyword_return)
(keyword_setof)
(keyword_atomic)
(keyword_declare)
; (keyword_language)
(keyword_cache)
(keyword_language)
(keyword_sql)
(keyword_called)
(keyword_conflict)
(keyword_declare)
(keyword_filter)
(keyword_function)
(keyword_input)
(keyword_name)
(keyword_oid)
(keyword_options)
(keyword_plpgsql)
(keyword_immutable)
(keyword_stable)
(keyword_volatile)
(keyword_leakproof)
(keyword_parallel)
(keyword_safe)
(keyword_unsafe)
(keyword_precision)
(keyword_regclass)
(keyword_regnamespace)
(keyword_regproc)
(keyword_regtype)
(keyword_restricted)
(keyword_called)
(keyword_return)
(keyword_returns)
(keyword_input)
(keyword_strict)
(keyword_cost)
(keyword_rows)
(keyword_separator)
(keyword_setof)
(keyword_stable)
(keyword_support)
(keyword_external)
(keyword_stored)
(keyword_cached)
(keyword_uncached)
(keyword_replication)
(keyword_tblproperties)
(keyword_options)
(keyword_compute)
(keyword_stats)
(keyword_statistics)
(keyword_optimize)
(keyword_rewrite)
(keyword_bin_pack)
(keyword_incremental)
(keyword_location)
(keyword_partitioned)
(keyword_comment)
(keyword_sort)
(keyword_format)
(keyword_delimited)
(keyword_fields)
(keyword_terminated)
(keyword_escaped)
(keyword_lines)
(keyword_cache)
(keyword_metadata)
(keyword_noscan)
(keyword_parquet)
(keyword_rcfile)
(keyword_csv)
(keyword_textfile)
(keyword_avro)
(keyword_sequencefile)
(keyword_orc)
(keyword_avro)
(keyword_jsonfile)
(keyword_precision)
(keyword_inet)
(keyword_trigger)
(keyword_unsafe)
(keyword_admin)
(keyword_connection)
(keyword_cycle)
(keyword_database)
(keyword_encrypted)
(keyword_increment)
(keyword_logged)
(keyword_none)
(keyword_owned)
(keyword_password)
(keyword_reset)
(keyword_role)
(keyword_sequence)
(keyword_start)
(keyword_restart)
(keyword_tablespace)
(keyword_until)
(keyword_user)
(keyword_valid)
(keyword_action)
] @keyword
[
(keyword_case)
(keyword_when)
(keyword_then)
(keyword_else)
(keyword_where)
] @keyword.control.conditional
[
(keyword_in)
(keyword_and)
(keyword_or)
(keyword_is)
] @keyword.operator
(keyword_restrict)
(keyword_unbounded)
(keyword_unique)
(keyword_cascade)
(keyword_delayed)
(keyword_high_priority)
(keyword_low_priority)
(keyword_ignore)
(keyword_nothing)
(keyword_check)
(keyword_option)
(keyword_local)
(keyword_cascaded)
(keyword_wait)
(keyword_nowait)
(keyword_metadata)
(keyword_incremental)
(keyword_bin_pack)
(keyword_noscan)
(keyword_stats)
(keyword_statistics)
(keyword_maxvalue)
(keyword_minvalue)
] @keyword
[
(keyword_int)
(keyword_null)
(keyword_boolean)
(bit)
(keyword_binary)
(keyword_varbinary)
(keyword_image)
(keyword_bit)
(keyword_inet)
(keyword_character)
(keyword_smallserial)
(keyword_serial)
(keyword_bigserial)
(tinyint)
(smallint)
(mediumint)
(int)
(bigint)
(decimal)
(numeric)
(keyword_smallint)
(keyword_mediumint)
(keyword_bigint)
(keyword_tinyint)
(keyword_decimal)
(keyword_float)
(keyword_double)
(keyword_numeric)
(keyword_real)
(double)
(float)
(keyword_money)
(char)
(varchar)
(numeric)
(keyword_string)
(keyword_smallmoney)
(keyword_char)
(keyword_nchar)
(keyword_varchar)
(keyword_nvarchar)
(keyword_varying)
(keyword_text)
(keyword_string)
(keyword_uuid)
(keyword_json)
(keyword_jsonb)
(keyword_xml)
(keyword_bytea)
(keyword_inet)
(enum)
(keyword_enum)
(keyword_date)
(keyword_datetime)
(keyword_time)
(keyword_datetime2)
(keyword_datetimeoffset)
(keyword_smalldatetime)
(keyword_timestamp)
(keyword_timestamptz)
(keyword_interval)
(keyword_geometry)
(keyword_geography)
(keyword_box2d)
(keyword_box3d)
(keyword_oid)
(keyword_name)
(keyword_regclass)
(keyword_regnamespace)
(keyword_regproc)
(keyword_regtype)
(keyword_interval)
] @type.builtin
[
(keyword_in)
(keyword_and)
(keyword_or)
(keyword_not)
(keyword_by)
(keyword_on)
(keyword_do)
(keyword_union)
(keyword_except)
(keyword_intersect)
] @keyword.operator
[
"+"
"-"
"*"
"/"
"%"
"^"
":="
"="
"<"
"<="
"!="
">="
">"
"<>"
"->"
"->>"
"#>"
"#>>"
] @operator
[
"("
")"
] @punctuation.bracket
[
";"
","
"."
] @punctuation.delimiter

@ -0,0 +1,99 @@
(package_identifier) @namespace
(parameter_declaration (identifier) @variable.parameter)
(variadic_parameter_declaration (identifier) @variable.parameter)
(function_declaration
name: (identifier) @function)
(type_spec name: (type_identifier) @type)
(type_identifier) @type
(field_identifier) @variable.other.member
(identifier) @variable
; Function calls
(call_expression
function: (identifier) @function)
(call_expression
function: (selector_expression
field: (field_identifier) @function))
;
; These are Templ specific
;
(component_declaration
name: (component_identifier) @function)
(tag_start) @tag
(tag_end) @tag
(self_closing_tag) @tag
(style_element) @tag
(attribute
name: (attribute_name) @attribute)
(attribute
value: (quoted_attribute_value) @string)
(element_text) @string.special
(style_element_text) @string.special
(css_property
name: (css_property_name) @attribute)
(expression) @function.method
(dynamic_class_attribute_value) @function.method
(component_import
name: (component_identifier) @function)
(component_render) @function
[
"@"
] @operator
[
"func"
"var"
"const"
"templ"
"css"
"type"
"struct"
"range"
"script"
] @keyword.storage.type
[
"return"
] @keyword.control.return
[
"import"
"package"
] @keyword.control.import
[
"else"
"case"
"switch"
"if"
"default"
] @keyword.control.conditional
"for" @keyword.control.repeat
[
(interpreted_string_literal)
(raw_string_literal)
(rune_literal)
] @string
; Comments
(comment) @comment
(element_comment) @comment

@ -0,0 +1,4 @@
((script_block_text) @injection.content (#set! injection.language "javascript"))
((script_element_text) @injection.content (#set! injection.language "javascript"))
((style_element_text) @injection.content (#set! injection.language "css"))

@ -0,0 +1,77 @@
(call
item: (ident) @function)
(call
item: (field field: (ident) @function.method))
(tagged field: (ident) @tag)
(field field: (ident) @tag)
(comment) @comment
; CONTROL
(let "let" @keyword.storage.type)
(branch ["if" "else"] @keyword.control.conditional)
(while "while" @keyword.control.repeat)
(for ["for" "in"] @keyword.control.repeat)
(import "import" @keyword.control.import)
(as "as" @keyword.operator)
(include "include" @keyword.control.import)
(show "show" @keyword.control)
(set "set" @keyword.control)
(return "return" @keyword.control)
(flow ["break" "continue"] @keyword.control)
; OPERATOR
(in ["in" "not"] @keyword.operator)
(and "and" @keyword.operator)
(or "or" @keyword.operator)
(not "not" @keyword.operator)
(sign ["+" "-"] @operator)
(add "+" @operator)
(sub "-" @operator)
(mul "*" @operator)
(div "/" @operator)
(cmp ["==" "<=" ">=" "!=" "<" ">"] @operator)
(fraction "/" @operator)
(fac "!" @operator)
(attach ["^" "_"] @operator)
(wildcard) @operator
; VALUE
(raw_blck "```" @operator) @markup.raw.block
(raw_span "`" @operator) @markup.raw.block
(raw_blck lang: (ident) @tag)
(label) @tag
(ref) @tag
(number) @constant.numeric
(string) @string
(content ["[" "]"] @operator)
(bool) @constant.builtin.boolean
(builtin) @constant.builtin
(none) @constant.builtin
(auto) @constant.builtin
(ident) @variable
(call
item: (builtin) @function.builtin)
; MARKUP
(item "-" @markup.list)
(term ["/" ":"] @markup.list)
(heading ["=" "==" "===" "====" "====="] @markup.heading.marker) @markup.heading
(url) @tag
(emph) @markup.italic
(strong) @markup.bold
(symbol) @constant.character
(shorthand) @constant.builtin
(quote) @markup.quote
(align) @operator
(letter) @constant.character
(linebreak) @constant.builtin
(math "$" @operator)
"#" @operator
"end" @operator
(escape) @constant.character.escape
["(" ")" "{" "}"] @punctuation.bracket
["," ";" ".." ":" "sep"] @punctuation.delimiter
"assign" @punctuation
(field "." @punctuation)

@ -0,0 +1,6 @@
(raw_blck
(blob) @injection.shebang @injection.content)
(raw_blck
lang: (ident) @injection.language
(blob) @injection.content)

@ -10,14 +10,18 @@
[
(kw_forall)
(unique_kw)
(structural_kw)
(type_kw)
(kw_equals)
(do)
(ability)
(where)
] @keyword
(kw_let) @keyword.function
(type_kw) @keyword.storage.type
(unique) @keyword.storage.modifier
(structural) @keyword.storage.modifier
("use") @keyword.control.import
@ -31,6 +35,7 @@
(arrow_symbol)
(">")
(or)
(and)
(bang)
] @operator
@ -47,13 +52,22 @@
;; Types
(record_field name: (wordy_id) @variable.other.member type: (wordy_id) @type)
[
(type_name)
(type_signature)
(effect)
] @type
(type_constructor (type_name (wordy_id) @constructor))
(ability_declaration type_name: (wordy_id) @type type_arg: (wordy_id) @variable.parameter)
(effect (wordy_id) @special) ;; NOTE: an effect is just like a type, but in signature we special case it
;; Namespaces
(path) @namespace
(namespace) @namespace
;; Terms
(type_signature term_name: (path)? @variable term_name: (wordy_id) @variable)
(type_signature (wordy_id) @type)
(type_signature (delayed (wordy_id)) @type)
(term_definition param: (wordy_id) @variable.parameter)
(term_definition) @variable
(function_application function_name: (path)? function_name: (wordy_id) @function)
;; Punctuation
[
@ -70,3 +84,4 @@
"]"
] @punctuation.bracket
(test_watch_expression (wordy_id) @keyword.directive)

@ -0,0 +1,154 @@
# An approximation/port of the Cyan Light Theme from Jetbrains
#
# Original Color Scheme here https://plugins.jetbrains.com/plugin/12102-cyan-light-theme
"attribute" = "blue"
"type" = "shade07"
"type.enum.variant" = "purple"
"constructor" = "shade07"
"constant" = "darker_blue"
"constant.builtin.boolean" = "blue"
"constant.character" = "blue"
"constant.character.escape" = "dark_red"
"constant.numeric" = "blue"
"string" = "green"
"string.regexp" = "blue"
"string.special" = { fg = "dark_red", modifiers = ["underlined"] }
"comment" = "comment_gray"
"variable" = "green_blue"
"variable.builtin" = { fg = "darker_blue" }
"variable.parameter" = "purple"
"variable.other.member" = "purple"
"label" = { fg = "darker_blue", modifiers = ["underlined"] }
"punctuation" = "shade06"
"keyword" = "darker_blue"
"keyword.control.exception" = "darker_blue"
"operator" = "shade06"
"function" = "shade07"
"function.macro" = "yellow"
"function.builtin" = { fg = "shade07", modifiers = ["italic"] }
"function.special" = "dark_red"
"function.method" = "dark_yellow"
"tag" = "darker_blue"
"special" = "shade06"
"namespace" = "darker_blue"
"markup.bold" = { fg = "shade06", modifiers = ["bold"] }
"markup.italic" = { fg = "shade06", modifiers = ["italic"] }
"markup.strikethrough" = { fg = "shade06", modifiers = ["crossed_out"] }
"markup.heading" = { fg = "purple" }
"markup.list" = "darker_blue"
"markup.list.numbered" = "darker_blue"
"markup.list.unnumbered" = "darker_blue"
"markup.link.url" = "shade06"
"markup.link.text" = { fg = "dark_blue", modifiers = ['underlined'] }
"markup.link.label" = "dark_blue"
"markup.quote" = "green"
"markup.raw" = "green"
"markup.raw.inline" = "green"
"markup.raw.block" = "green"
"diff.plus" = "green"
"diff.plus.gutter" = "gutter_green"
"diff.minus" = "red"
"diff.minus.gutter" = "gutter_red"
"diff.delta" = "blue"
"diff.delta.gutter" = "gutter_blue"
# ui specific
"ui.background" = { bg = "shade00" }
"ui.cursor" = { bg = "shade02" }
"ui.cursor.primary" = { bg = "cursor_blue" }
"ui.cursor.match" = { fg = "shade00", bg = "shade04" }
"ui.cursor.primary.select" = { bg = "light_purple" }
"ui.cursor.primary.insert" = { bg = "light_green" }
"ui.selection" = { bg = "lighter_blue" }
"ui.selection.primary" = { bg = "lighter_blue" }
"ui.highlight" = { bg = "faint_blue" }
"ui.cursorline.primary" = { bg = "faint_blue" }
"ui.linenr" = { fg = "shade03" }
"ui.linenr.selected" = { fg = "shade04", bg = "faint_blue", modifiers = [
"bold",
] }
"ui.statusline" = { fg = "shade06", bg = "shade02" }
"ui.statusline.inactive" = { fg = "shade04", bg = "shade01" }
"ui.statusline.normal" = { fg = "shade00", bg = "blue" }
"ui.statusline.insert" = { fg = "shade00", bg = "green" }
"ui.statusline.select" = { fg = "shade00", bg = "purple" }
"ui.popup" = { bg = "shade01", fg = "shade04" }
"ui.window" = { bg = "shade00", fg = "shade04" }
"ui.help" = { fg = "shade06", bg = "shade01" }
"ui.text" = "shade05"
"ui.text.focus" = { fg = "shade07", bg = "light_blue" }
"ui.virtual" = "shade03"
"ui.virtual.ruler" = { bg = "shade04" }
"ui.menu" = { fg = "shade05", bg = "shade01" }
"ui.menu.selected" = { fg = "shade07", bg = "light_blue" }
"hint" = "shade04"
"info" = "light_blue"
"warning" = "orange"
"error" = "red"
"diagnostic" = { modifiers = [] }
"diagnostic.hint" = { underline = { color = "shade04", style = "line" } }
"diagnostic.info" = { underline = { color = "light_blue", style = "line" } }
"diagnostic.warning" = { underline = { color = "orange", style = "curl" } }
"diagnostic.error" = { underline = { color = "red", style = "curl" } }
[palette]
shade00 = "#f2f3f7"
shade01 = "#dadde8"
shade02 = "#c1c6d9"
shade03 = "#a9b0ca"
shade04 = "#525c85"
shade05 = "#434b6c"
shade06 = "#343a54"
shade07 = "#25293c"
background = "#f2f3f7"
foreground = "#25293c"
comment_gray = "#808080"
gutter_blue = "#C3D6E8"
faint_blue = "#E8Eef1"
lighter_blue = "#d0eaff"
light_blue = "#99ccff"
cursor_blue = "#80bfff"
blue = "#0073E6"
dark_blue = "#185b93"
darker_blue = "#000080"
purple = "#660E7A"
light_purple = "#ED9CFF"
gutter_green = "#C9DEC1"
green = "#00733B"
light_green = "#5DCE87"
green_blue = "#458383"
yellow = "#808000"
dark_yellow = "#7A7A43"
light_orange = "#f9c881"
orange = "#F49810"
gutter_red = "#EBBCBC"
red = "#d90016"
dark_red = "#7F0000"

@ -4,9 +4,8 @@ inherits = "darcula"
"ui.background.separator" = { bg = "grey01" }
"ui.menu.scroll" = { fg = "grey02", bg = "grey00" }
"ui.popup" = { fg = "grey03", bg = "grey02" }
"ui.popup" = { fg = "grey05", bg = "grey00" }
"ui.window" = { bg = "grey00" }
"ui.selection" = { bg = "blue" }
"ui.cursorline.secondary" = { bg = "grey03" }
[palette]
@ -15,5 +14,3 @@ grey01 = "#1f1f1f"
grey02 = "#323232"
grey03 = "#555555"
grey04 = "#a8a8a8"
blue = "#104158"

@ -8,7 +8,8 @@
"ui.gutter" = { bg = "grey01" }
"ui.popup" = { fg = "grey05", bg = "grey00" }
"ui.window" = { bg = "grey01" }
"ui.selection" = { bg = "grey03" }
"ui.selection" = { bg = "grey02" }
"ui.selection.primary" = { bg = "blue" }
"ui.statusline" = { fg = "grey04", bg = "grey02" }
"ui.statusline.insert" = { bg = "white", fg = "grey01" }
"ui.statusline.select" = { bg = "orange", fg = "grey01" }
@ -61,7 +62,7 @@
"markup.link.url" = { fg = "lightblue", modifiers = ["underlined"] }
"markup.link.text" = "white"
"markup.quote" = "darkgreen"
"markup.raw" = "white"
"markup.raw" = "purple"
"diff.plus" = "green"
"diff.delta" = "grey"
@ -97,3 +98,4 @@ green = "#32cd32"
grey = "#808080"
darkgreen = "#629755"
lightblue = "#6897bb"
blue = "#104158"

@ -68,6 +68,7 @@
"ui.virtual.whitespace" = { fg = "comment" }
"ui.virtual.wrap" = { fg = "comment" }
"ui.virtual.indent-guide" = { fg = "comment" }
"ui.virtual.inlay-hint" = { fg = "comment" }
"ui.window" = { fg = "black" }
"error" = { fg = "red" }

@ -0,0 +1,114 @@
# Author : Mehedi Hasan <mehedi.r137@gmail.com>
# Based on : https://github.com/rexim/gruber-darker-theme
"attribute" = "fg0"
"keyword" = { fg = "yellow0", modifiers = ["bold"] }
"keyword.directive" = "quartz"
"namespace" = "quartz"
"punctuation" = "fg0"
"punctuation.delimiter" = "fg0"
"operator" = "fg0"
"special" = { fg = "yellow0", modifiers = ["bold"] }
"variable" = "fg0"
"variable.builtin" = { fg = "yellow0", modifiers = ["bold"] }
"variable.parameter" = "fg0"
"type" = "quartz"
"type.builtin" = "yellow0"
"constructor" = { fg = "quartz" }
"function" = "niagara0"
"function.builtin" = "yellow0"
"tag" = "niagara0"
"comment" = { fg = "brown0" }
"constant.character" = { fg = "green0" }
"constant.character.escape" = { fg = "yellow0" }
"constant.builtin" = { fg = "yellow0", modifiers = ["bold"] }
"string" = "green0"
"constant.numeric" = "wisteria"
"label" = "fg0"
"module" = "aqua1"
"diff.plus" = "green1"
"diff.delta" = "orange1"
"diff.minus" = "red0"
"warning" = { fg = "orange1", modifiers = ["bold"] }
"error" = { fg = "red0", modifiers = ["bold"] }
"info" = { fg = "aqua1", modifiers = ["bold"] }
"hint" = { fg = "blue0", modifiers = ["bold"] }
"ui.background" = { bg = "bg0" }
"ui.linenr" = { fg = "bg4" }
"ui.linenr.selected" = { fg = "yellow0" }
"ui.cursorline" = { bg = "bg1" }
"ui.statusline" = { fg = "fg0", bg = "bg1" }
"ui.statusline.normal" = { fg = "bg1", bg = "yellow0", modifiers = ["bold"] }
"ui.statusline.insert" = { fg = "bg1", bg = "blue0", modifiers = ["bold"] }
"ui.statusline.select" = { fg = "bg1", bg = "wisteria", modifiers = ["bold"] }
"ui.statusline.inactive" = { fg = "fg3", bg = "bg1" }
"ui.bufferline" = { fg = "fg3", bg = "bg6" }
"ui.bufferline.active" = { fg = "fg0", bg = "bg7" }
"ui.popup" = { bg = "bg6" }
"ui.window" = { fg = "bg1" }
"ui.help" = { bg = "bg1", fg = "fg0" }
"ui.text" = { fg = "fg0" }
"ui.text.focus" = { bg = "bg5", modifiers = ["bold"] }
"ui.selection" = { bg = "bg2" }
"ui.selection.primary" = { bg = "bg5" }
"ui.cursor.primary" = { bg = "fg0", fg = "niagara1" }
"ui.cursor.match" = { bg = "yellow1" }
"ui.menu" = { fg = "fg0", bg = "bg6" }
"ui.menu.selected" = { fg = "fg0", bg = "bg5", modifiers = ["bold"] }
"ui.virtual.whitespace" = "bg8"
"ui.virtual.indent-guide" = "bg8"
"ui.virtual.ruler" = { bg = "bg1" }
"ui.virtual.inlay-hint" = { fg = "bg7" }
"ui.virtual.wrap" = { fg = "bg2" }
"diagnostic.warning" = { underline = { color = "orange1", style = "dashed" } }
"diagnostic.error" = { underline = { color = "red3", style = "dashed" } }
"diagnostic.info" = { underline = { color = "aqua1", style = "dashed" } }
"diagnostic.hint" = { underline = { color = "blue0", style = "dashed" } }
"markup.heading" = { fg = "aqua1", modifiers = ["bold"] }
"markup.bold" = { modifiers = ["bold"] }
"markup.italic" = { modifiers = ["italic"] }
"markup.strikethrough" = { modifiers = ["crossed_out"] }
"markup.link.url" = { fg = "green1", modifiers = ["underlined"] }
"markup.link.text" = "red3"
"markup.raw" = { fg = "fg0", bg = "bg8", modifiers = ["bold"] }
[palette]
fg0 = "#e4e4ef"
fg1 = "#f4f4ff"
fg2 = "#f5f5f5"
fg3 = "#a89984"
bg0 = "#181818"
bg1 = "#282828"
bg2 = "#453d41"
bg4 = "#52494e"
bg5 = "#404040"
bg6 = "#232323"
bg7 = "#3f3f3f"
bg8 = "#2c2c2c"
red0 = "#f43841"
red1 = "#ff4f58"
red2 = "#2B0A0B"
red3 = "#fb4934"
green0 = "#73c936"
green1 = "#b8bb26"
yellow0 = "#ffdd33"
yellow1 = "#655814"
blue0 = "#5292c8"
orange0 = "#d65d0e"
orange1 = "#fe8019"
brown0 = "#cc8c3c"
quartz = "#95a99f"
niagara0 = "#96a6c8"
niagara1 = "#303540"
wisteria = "#9e95c7"
aqua1 = "#8ec07c"

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 sainnhe
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.

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 arturoalviar
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.

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 sainnhe
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.

@ -0,0 +1,23 @@
# Nord Night
#
# Based on the Nord theme, with minor modifications.
# The Background and the Primary Text color have been slightly darkened.
# The Aurora color palette has been used more generously.
inherits = 'nord'
'constant' = 'nord13'
'constant.builtin.boolean' = 'nord13'
'constant.numeric' = 'nord13'
'keyword.control' = 'nord11'
'keyword.control.conditional' = 'nord11'
'keyword.control.exception' = 'nord11'
'keyword.control.repeat' = 'nord11'
'keyword.control.return' = 'nord11'
'variable.parameter' = 'nord15'
[palette]
nord0 = '#252933'
nord4 = '#C0C5CF'

@ -50,7 +50,7 @@
"keyword.operator" = "nord9"
"keyword.return" = "nord9"
"keyword.storage.modifier" = "nord9"
"keyword.storage.type" = "nord7"
"keyword.storage.type" = "nord9"
# Punctuation
"punctuation" = "nord6"
@ -65,22 +65,22 @@
"string.special" = "nord13"
# Types
"type" = "nord4"
"type" = "nord7"
"type.builtin" = "nord7"
# Variables
"variable" = "nord4"
"variable.builint" = "nord9"
"variable.builtin" = "nord9"
"variable.other.member" = "nord4"
"variable.parameter" = "nord8"
"attribute" = "nord4"
"attribute" = "nord9"
# Misc.
"label" = "nord7"
"namespace" = "nord4"
"operator" = "nord9"
"special" = "nord4"
"tag" = "nord4"
"special" = "nord9"
"tag" = "nord7"
"comment" = { fg = "nord3_bright", modifiers = ["italic"] }
## EDITOR UI COLORS

@ -1,5 +1,6 @@
# Author : Gokul Soumya <gokulps15@gmail.com>
"tag" = { fg = "red" }
"attribute" = { fg = "yellow" }
"comment" = { fg = "light-gray", modifiers = ["italic"] }
"constant" = { fg = "cyan" }

@ -52,6 +52,7 @@
"type" = { fg = "bright2", modifiers = ["bold"] }
"type.builtin" = { fg = "bright2", modifiers = ["bold"] }
"type.parameter" = { fg = "foreground" }
"type.enum" = { fg = "foreground" }
"type.enum.variant" = { fg = "foreground" }

@ -794,11 +794,11 @@ lines.
= 7.3 INDENTING LINES =
=================================================================
Type > to indent a line and < to outdent it.
Type > to indent a line and < to unindent it.
1. Move the cursor to the line marked '-->' below.
2. Move down to the second line and type > to indent it.
3. Move to the third line and type < to outdent it.
3. Move to the third line and type < to unindent it.
--> These lines
are indented
@ -842,7 +842,7 @@ lines.
* Type J to join lines in selection.
* Type < and > to indent / outdent lines.
* Type > and < to indent / unindent lines.
* Press Ctrl-a to increment the selected number.
* Press Ctrl-x to decrement the selected number.

Loading…
Cancel
Save