diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9518a5373..b509ff9e0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -85,6 +85,7 @@ jobs: rust: stable target: x86_64-pc-windows-msvc cross: false + # 23.03: build issues - build: aarch64-macos os: macos-latest rust: stable @@ -113,6 +114,12 @@ jobs: mkdir -p runtime/grammars/sources tar xJf grammars/grammars.tar.xz -C runtime/grammars/sources + # The rust-toolchain action ignores rust-toolchain.toml files. + # Removing this before building with cargo ensures that the rust-toolchain + # is considered the same between installation and usage. + - name: Remove the rust-toolchain.toml file + run: rm rust-toolchain.toml + - name: Install ${{ matrix.rust }} toolchain uses: dtolnay/rust-toolchain@master with: @@ -155,6 +162,10 @@ jobs: shell: bash if: matrix.build == 'aarch64-linux' || matrix.build == 'x86_64-linux' run: | + # Required as of 22.x https://github.com/AppImage/AppImageKit/wiki/FUSE + sudo add-apt-repository universe + sudo apt install libfuse2 + mkdir dist name=dev @@ -244,7 +255,7 @@ jobs: exe=".exe" fi pkgname=helix-$GITHUB_REF_NAME-$platform - mkdir $pkgname + mkdir -p $pkgname cp $source/LICENSE $source/README.md $pkgname mkdir $pkgname/contrib cp -r $source/contrib/completion $pkgname/contrib diff --git a/CHANGELOG.md b/CHANGELOG.md index dc91c9ff3..01184571e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,276 @@ +# 23.03 (2023-03-31) + +23.03 brings some long-awaited and exciting features. Thank you to everyone involved! This release saw changes from 102 contributors. + +For the full log, check out the [git log](https://github.com/helix-editor/helix/compare/22.12..23.03). +Also check out the [release notes](https://helix-editor.com/news/release-23-03-highlights/) for more commentary on larger features. + +Breaking changes: + +- Select diagnostic range in `goto_*_diag` commands ([#4713](https://github.com/helix-editor/helix/pull/4713), [#5164](https://github.com/helix-editor/helix/pull/5164), [#6193](https://github.com/helix-editor/helix/pull/6193)) +- Remove jump behavior from `increment`/`decrement` ([#4123](https://github.com/helix-editor/helix/pull/4123), [#5929](https://github.com/helix-editor/helix/pull/5929)) +- Select change range in `goto_*_change` commands ([#5206](https://github.com/helix-editor/helix/pull/5206)) +- Split file modification indicator from filename statusline elements ([#4731](https://github.com/helix-editor/helix/pull/4731), [#6036](https://github.com/helix-editor/helix/pull/6036)) +- Jump to symbol ranges in LSP goto commands ([#5986](https://github.com/helix-editor/helix/pull/5986)) +- Workspace detection now stops at the first `.helix/` directory (merging multiple `.helix/languages.toml` configurations is no longer supported) ([#5748](https://github.com/helix-editor/helix/pull/5748)) + +Features: + +- Dynamic workspace symbol picker ([#5055](https://github.com/helix-editor/helix/pull/5055)) +- Soft-wrap ([#5420](https://github.com/helix-editor/helix/pull/5420), [#5786](https://github.com/helix-editor/helix/pull/5786), [#5893](https://github.com/helix-editor/helix/pull/5893), [#6142](https://github.com/helix-editor/helix/pull/6142), [#6440](https://github.com/helix-editor/helix/pull/6440)) +- Initial support for LSP snippet completions ([#5864](https://github.com/helix-editor/helix/pull/5864), [b1f7528](https://github.com/helix-editor/helix/commit/b1f7528), [#6263](https://github.com/helix-editor/helix/pull/6263), [bbf4800](https://github.com/helix-editor/helix/commit/bbf4800), [90348b8](https://github.com/helix-editor/helix/commit/90348b8), [f87299f](https://github.com/helix-editor/helix/commit/f87299f), [#6371](https://github.com/helix-editor/helix/pull/6371), [9fe3adc](https://github.com/helix-editor/helix/commit/9fe3adc)) +- Add a statusline element for showing the current version control HEAD ([#5682](https://github.com/helix-editor/helix/pull/5682)) +- Display LSP type hints ([#5420](https://github.com/helix-editor/helix/pull/5420), [#5934](https://github.com/helix-editor/helix/pull/5934), [#6312](https://github.com/helix-editor/helix/pull/6312)) +- Enable the Kitty keyboard protocol on terminals with support ([#4939](https://github.com/helix-editor/helix/pull/4939), [#6170](https://github.com/helix-editor/helix/pull/6170), [#6194](https://github.com/helix-editor/helix/pull/6194), [#6438](https://github.com/helix-editor/helix/pull/6438)) +- Add a statusline element for the basename of the current file ([#5318](https://github.com/helix-editor/helix/pull/5318)) +- Add substring matching syntax for the picker ([#5658](https://github.com/helix-editor/helix/pull/5658)) +- Support LSP `textDocument/prepareRename` ([#6103](https://github.com/helix-editor/helix/pull/6103)) +- Allow multiple runtime directories with priorities ([#5411](https://github.com/helix-editor/helix/pull/5411)) +- Allow configuring whether to insert or replace completions ([#5728](https://github.com/helix-editor/helix/pull/5728)) +- Allow per-workspace config file `.helix/config.toml` ([#5748](https://github.com/helix-editor/helix/pull/5748)) +- Add `workspace-lsp-roots` config option to support multiple LSP roots for use with monorepos ([#5748](https://github.com/helix-editor/helix/pull/5748)) + +Commands: + +- `:pipe-to` which pipes selections into a shell command and ignores output ([#4931](https://github.com/helix-editor/helix/pull/4931)) +- `merge_consecutive_selections` (`A-_`) combines all consecutive selections ([#5047](https://github.com/helix-editor/helix/pull/5047)) +- `rotate_view_reverse` which focuses the previous view ([#5356](https://github.com/helix-editor/helix/pull/5356)) +- `goto_declaration` (`gD`, requires LSP) which jumps to a symbol's declaration ([#5646](https://github.com/helix-editor/helix/pull/5646)) +- `file_picker_in_current_buffer_directory` ([#4666](https://github.com/helix-editor/helix/pull/4666)) +- `:character-info` which shows information about the character under the cursor ([#4000](https://github.com/helix-editor/helix/pull/4000)) +- `:toggle-option` for toggling config options at runtime ([#4085](https://github.com/helix-editor/helix/pull/4085)) +- `dap_restart` for restarting a debug session in DAP ([#5651](https://github.com/helix-editor/helix/pull/5651)) +- `:lsp-stop` to stop the language server of the current buffer ([#5964](https://github.com/helix-editor/helix/pull/5964)) +- `:reset-diff-change` for resetting a diff hunk to its original text ([#4974](https://github.com/helix-editor/helix/pull/4974)) +- `:config-open-workspace` for opening the config file local to the current workspace ([#5748](https://github.com/helix-editor/helix/pull/5748)) + +Usability improvements: + +- Remove empty detail section in completion menu when LSP doesn't send details ([#4902](https://github.com/helix-editor/helix/pull/4902)) +- Pass client information on LSP initialization ([#4904](https://github.com/helix-editor/helix/pull/4904)) +- Allow specifying environment variables for language servers in language config ([#4004](https://github.com/helix-editor/helix/pull/4004)) +- Allow detached git worktrees to be recognized as root paths ([#5097](https://github.com/helix-editor/helix/pull/5097)) +- Improve error message handling for theme loading failures ([#5073](https://github.com/helix-editor/helix/pull/5073)) +- Print the names of binaries required for LSP/DAP in health-check ([#5195](https://github.com/helix-editor/helix/pull/5195)) +- Improve sorting in the picker in cases of ties ([#5169](https://github.com/helix-editor/helix/pull/5169)) +- Add theming for prompt suggestions ([#5104](https://github.com/helix-editor/helix/pull/5104)) +- Open a file picker when using `:open` on directories ([#2707](https://github.com/helix-editor/helix/pull/2707), [#5278](https://github.com/helix-editor/helix/pull/5278)) +- Reload language config with `:config-reload` ([#5239](https://github.com/helix-editor/helix/pull/5239), [#5381](https://github.com/helix-editor/helix/pull/5381), [#5431](https://github.com/helix-editor/helix/pull/5431)) +- Improve indent queries for python when the tree is errored ([#5332](https://github.com/helix-editor/helix/pull/5332)) +- Picker: Open files without closing the picker with `A-ret` ([#4435](https://github.com/helix-editor/helix/pull/4435)) +- Allow theming cursors by primary/secondary and by mode ([#5130](https://github.com/helix-editor/helix/pull/5130)) +- Allow configuration of the minimum width for the line-numbers gutter ([#4724](https://github.com/helix-editor/helix/pull/4724), [#5696](https://github.com/helix-editor/helix/pull/5696)) +- Use filename completer for `:run-shell-command` command ([#5729](https://github.com/helix-editor/helix/pull/5729)) +- Surround with line-endings with `ms` ([#4571](https://github.com/helix-editor/helix/pull/4571)) +- Hide duplicate symlinks in file pickers ([#5658](https://github.com/helix-editor/helix/pull/5658)) +- Tabulate buffer picker contents ([#5777](https://github.com/helix-editor/helix/pull/5777)) +- Add an option to disable LSP ([#4425](https://github.com/helix-editor/helix/pull/4425)) +- Short-circuit tree-sitter and word object motions ([#5851](https://github.com/helix-editor/helix/pull/5851)) +- Add exit code to failed command message ([#5898](https://github.com/helix-editor/helix/pull/5898)) +- Make `m` textobject look for pairs enclosing selections ([#3344](https://github.com/helix-editor/helix/pull/3344)) +- Negotiate LSP position encoding ([#5894](https://github.com/helix-editor/helix/pull/5894), [a48d1a4](https://github.com/helix-editor/helix/commit/a48d1a4)) +- Display deprecated LSP completions with strikethrough ([#5932](https://github.com/helix-editor/helix/pull/5932)) +- Add JSONRPC request ID to failed LSP/DAP request log messages ([#6010](https://github.com/helix-editor/helix/pull/6010), [#6018](https://github.com/helix-editor/helix/pull/6018)) +- Ignore case when filtering LSP completions ([#6008](https://github.com/helix-editor/helix/pull/6008)) +- Show current language when no arguments are passed to `:set-language` ([#5895](https://github.com/helix-editor/helix/pull/5895)) +- Refactor and rewrite all book documentation ([#5534](https://github.com/helix-editor/helix/pull/5534)) +- Separate diagnostic picker message and code ([#6095](https://github.com/helix-editor/helix/pull/6095)) +- Add a config option to bypass undercurl detection ([#6253](https://github.com/helix-editor/helix/pull/6253)) +- Only complete appropriate arguments for typed commands ([#5966](https://github.com/helix-editor/helix/pull/5966)) +- Discard outdated LSP diagnostics ([3c9d5d0](https://github.com/helix-editor/helix/commit/3c9d5d0)) +- Discard outdated LSP workspace edits ([b6a4927](https://github.com/helix-editor/helix/commit/b6a4927)) +- Run shell commands asynchronously ([#6373](https://github.com/helix-editor/helix/pull/6373)) +- Show diagnostic codes in LSP diagnostic messages ([#6378](https://github.com/helix-editor/helix/pull/6378)) +- Highlight the current line in a DAP debug session ([#5957](https://github.com/helix-editor/helix/pull/5957)) +- Hide signature help if it overlaps with the completion menu ([#5523](https://github.com/helix-editor/helix/pull/5523), [7a69c40](https://github.com/helix-editor/helix/commit/7a69c40)) + +Fixes: + +- Fix behavior of `auto-completion` flag for completion-on-trigger ([#5042](https://github.com/helix-editor/helix/pull/5042)) +- Reset editor mode when changing buffers ([#5072](https://github.com/helix-editor/helix/pull/5072)) +- Respect scrolloff settings in mouse movements ([#5255](https://github.com/helix-editor/helix/pull/5255)) +- Avoid trailing `s` when only one file is opened ([#5189](https://github.com/helix-editor/helix/pull/5189)) +- Fix erroneous indent between closers of auto-pairs ([#5330](https://github.com/helix-editor/helix/pull/5330)) +- Expand `~` when parsing file paths in `:open` ([#5329](https://github.com/helix-editor/helix/pull/5329)) +- Fix theme inheritance for default themes ([#5218](https://github.com/helix-editor/helix/pull/5218)) +- Fix `extend_line` with a count when the current line(s) are selected ([#5288](https://github.com/helix-editor/helix/pull/5288)) +- Prompt: Fix autocompletion for paths containing periods ([#5175](https://github.com/helix-editor/helix/pull/5175)) +- Skip serializing JSONRPC params if params is null ([#5471](https://github.com/helix-editor/helix/pull/5471)) +- Fix interaction with the `xclip` clipboard provider ([#5426](https://github.com/helix-editor/helix/pull/5426)) +- Fix undo/redo execution from the command palette ([#5294](https://github.com/helix-editor/helix/pull/5294)) +- Fix highlighting of non-block cursors ([#5575](https://github.com/helix-editor/helix/pull/5575)) +- Fix panic when nooping in `join_selections` and `join_selections_space` ([#5423](https://github.com/helix-editor/helix/pull/5423)) +- Fix selecting a changed file in global search ([#5639](https://github.com/helix-editor/helix/pull/5639)) +- Fix initial syntax highlight layer sort order ([#5196](https://github.com/helix-editor/helix/pull/5196)) +- Fix UTF-8 length handling for shellwords ([#5738](https://github.com/helix-editor/helix/pull/5738)) +- Remove C-j and C-k bindings from the completion menu ([#5070](https://github.com/helix-editor/helix/pull/5070)) +- Always commit to history when pasting ([#5790](https://github.com/helix-editor/helix/pull/5790)) +- Properly handle LSP position encoding ([#5711](https://github.com/helix-editor/helix/pull/5711)) +- Fix infinite loop in `copy_selection_on_prev_line` ([#5888](https://github.com/helix-editor/helix/pull/5888)) +- Fix completion popup positioning ([#5842](https://github.com/helix-editor/helix/pull/5842)) +- Fix a panic when uncommenting a line with only a comment token ([#5933](https://github.com/helix-editor/helix/pull/5933)) +- Fix panic in `goto_window_center` at EOF ([#5987](https://github.com/helix-editor/helix/pull/5987)) +- Ignore invalid file URIs sent by a language server ([#6000](https://github.com/helix-editor/helix/pull/6000)) +- Decode LSP URIs for the workspace diagnostics picker ([#6016](https://github.com/helix-editor/helix/pull/6016)) +- Fix incorrect usages of `tab_width` with `indent_width` ([#5918](https://github.com/helix-editor/helix/pull/5918)) +- DAP: Send Disconnect if the Terminated event is received ([#5532](https://github.com/helix-editor/helix/pull/5532)) +- DAP: Validate key and index exist when requesting variables ([#5628](https://github.com/helix-editor/helix/pull/5628)) +- Check LSP renaming support before prompting for rename text ([#6257](https://github.com/helix-editor/helix/pull/6257)) +- Fix indent guide rendering ([#6136](https://github.com/helix-editor/helix/pull/6136)) +- Fix division by zero panic ([#6155](https://github.com/helix-editor/helix/pull/6155)) +- Fix lacking space panic ([#6109](https://github.com/helix-editor/helix/pull/6109)) +- Send error replies for malformed and unhandled LSP requests ([#6058](https://github.com/helix-editor/helix/pull/6058)) +- Fix table column calculations for dynamic pickers ([#5920](https://github.com/helix-editor/helix/pull/5920)) +- Skip adding jumplist entries for `:` line number previews ([#5751](https://github.com/helix-editor/helix/pull/5751)) +- Fix completion race conditions ([#6173](https://github.com/helix-editor/helix/pull/6173)) +- Fix `shrink_selection` with multiple cursors ([#6093](https://github.com/helix-editor/helix/pull/6093)) +- Fix indentation calculation for lines with mixed tabs/spaces ([#6278](https://github.com/helix-editor/helix/pull/6278)) +- No-op `client/registerCapability` LSP requests ([#6258](https://github.com/helix-editor/helix/pull/6258)) +- Send the STOP signal to all processes in the process group ([#3546](https://github.com/helix-editor/helix/pull/3546)) +- Fix workspace edit client capabilities declaration ([7bf168d](https://github.com/helix-editor/helix/commit/7bf168d)) +- Fix highlighting in picker results with multiple columns ([#6333](https://github.com/helix-editor/helix/pull/6333)) +- Canonicalize paths before stripping the current dir as a prefix ([#6290](https://github.com/helix-editor/helix/pull/6290)) +- Fix truncation behavior for long path names in the file picker ([#6410](https://github.com/helix-editor/helix/pull/6410), [67783dd](https://github.com/helix-editor/helix/commit/67783dd)) +- Fix theme reloading behavior in `:config-reload` ([ab819d8](https://github.com/helix-editor/helix/commit/ab819d8)) + +Themes: + +- Update `serika` ([#5038](https://github.com/helix-editor/helix/pull/5038), [#6344](https://github.com/helix-editor/helix/pull/6344)) +- Update `flatwhite` ([#5036](https://github.com/helix-editor/helix/pull/5036), [#6323](https://github.com/helix-editor/helix/pull/6323)) +- Update `autumn` ([#5051](https://github.com/helix-editor/helix/pull/5051), [#5397](https://github.com/helix-editor/helix/pull/5397), [#6280](https://github.com/helix-editor/helix/pull/6280), [#6316](https://github.com/helix-editor/helix/pull/6316)) +- Update `acme` ([#5019](https://github.com/helix-editor/helix/pull/5019), [#5486](https://github.com/helix-editor/helix/pull/5486), [#5488](https://github.com/helix-editor/helix/pull/5488)) +- Update `gruvbox` themes ([#5066](https://github.com/helix-editor/helix/pull/5066), [#5333](https://github.com/helix-editor/helix/pull/5333), [#5540](https://github.com/helix-editor/helix/pull/5540), [#6285](https://github.com/helix-editor/helix/pull/6285), [#6295](https://github.com/helix-editor/helix/pull/6295)) +- Update `base16_transparent` ([#5105](https://github.com/helix-editor/helix/pull/5105)) +- Update `dark_high_contrast` ([#5105](https://github.com/helix-editor/helix/pull/5105)) +- Update `dracula` ([#5236](https://github.com/helix-editor/helix/pull/5236), [#5627](https://github.com/helix-editor/helix/pull/5627), [#6414](https://github.com/helix-editor/helix/pull/6414)) +- Update `monokai_pro_spectrum` ([#5250](https://github.com/helix-editor/helix/pull/5250), [#5602](https://github.com/helix-editor/helix/pull/5602)) +- Update `rose_pine` ([#5267](https://github.com/helix-editor/helix/pull/5267), [#5489](https://github.com/helix-editor/helix/pull/5489), [#6384](https://github.com/helix-editor/helix/pull/6384)) +- Update `kanagawa` ([#5273](https://github.com/helix-editor/helix/pull/5273), [#5571](https://github.com/helix-editor/helix/pull/5571), [#6085](https://github.com/helix-editor/helix/pull/6085)) +- Update `emacs` ([#5334](https://github.com/helix-editor/helix/pull/5334)) +- Add `github` themes ([#5353](https://github.com/helix-editor/helix/pull/5353), [efeec12](https://github.com/helix-editor/helix/commit/efeec12)) + - Dark themes: `github_dark`, `github_dark_colorblind`, `github_dark_dimmed`, `github_dark_high_contrast`, `github_dark_tritanopia` + - Light themes: `github_light`, `github_light_colorblind`, `github_light_dimmed`, `github_light_high_contrast`, `github_light_tritanopia` +- Update `solarized` variants ([#5445](https://github.com/helix-editor/helix/pull/5445), [#6327](https://github.com/helix-editor/helix/pull/6327)) +- Update `catppuccin` variants ([#5404](https://github.com/helix-editor/helix/pull/5404), [#6107](https://github.com/helix-editor/helix/pull/6107), [#6269](https://github.com/helix-editor/helix/pull/6269), [#6464](https://github.com/helix-editor/helix/pull/6464)) +- Use curly underlines in built-in themes ([#5419](https://github.com/helix-editor/helix/pull/5419)) +- Update `zenburn` ([#5573](https://github.com/helix-editor/helix/pull/5573)) +- Rewrite `snazzy` ([#3971](https://github.com/helix-editor/helix/pull/3971)) +- Add `monokai_aqua` ([#5578](https://github.com/helix-editor/helix/pull/5578)) +- Add `markup.strikethrough` to existing themes ([#5619](https://github.com/helix-editor/helix/pull/5619)) +- Update `sonokai` ([#5440](https://github.com/helix-editor/helix/pull/5440)) +- Update `onedark` ([#5755](https://github.com/helix-editor/helix/pull/5755)) +- Add `ayu_evolve` ([#5638](https://github.com/helix-editor/helix/pull/5638), [#6028](https://github.com/helix-editor/helix/pull/6028), [#6225](https://github.com/helix-editor/helix/pull/6225)) +- Add `jellybeans` ([#5719](https://github.com/helix-editor/helix/pull/5719)) +- Update `fleet_dark` ([#5605](https://github.com/helix-editor/helix/pull/5605), [#6266](https://github.com/helix-editor/helix/pull/6266), [#6324](https://github.com/helix-editor/helix/pull/6324), [#6375](https://github.com/helix-editor/helix/pull/6375)) +- Add `darcula-solid` ([#5778](https://github.com/helix-editor/helix/pull/5778)) +- Remove text background from monokai themes ([#6009](https://github.com/helix-editor/helix/pull/6009)) +- Update `pop_dark` ([#5992](https://github.com/helix-editor/helix/pull/5992), [#6208](https://github.com/helix-editor/helix/pull/6208), [#6227](https://github.com/helix-editor/helix/pull/6227), [#6292](https://github.com/helix-editor/helix/pull/6292)) +- Add `everblush` ([#6086](https://github.com/helix-editor/helix/pull/6086)) +- Add `adwaita-dark` ([#6042](https://github.com/helix-editor/helix/pull/6042), [#6342](https://github.com/helix-editor/helix/pull/6342)) +- Update `papercolor` ([#6162](https://github.com/helix-editor/helix/pull/6162)) +- Update `onelight` ([#6192](https://github.com/helix-editor/helix/pull/6192), [#6276](https://github.com/helix-editor/helix/pull/6276)) +- Add `molokai` ([#6260](https://github.com/helix-editor/helix/pull/6260)) +- Update `ayu` variants ([#6329](https://github.com/helix-editor/helix/pull/6329)) +- Update `tokyonight` variants ([#6349](https://github.com/helix-editor/helix/pull/6349)) +- Update `nord` variants ([#6376](https://github.com/helix-editor/helix/pull/6376)) + +New languages: + +- BibTeX ([#5064](https://github.com/helix-editor/helix/pull/5064)) +- Mermaid.js ([#5147](https://github.com/helix-editor/helix/pull/5147)) +- Crystal ([#4993](https://github.com/helix-editor/helix/pull/4993), [#5205](https://github.com/helix-editor/helix/pull/5205)) +- MATLAB/Octave ([#5192](https://github.com/helix-editor/helix/pull/5192)) +- `tfvars` (uses HCL) ([#5396](https://github.com/helix-editor/helix/pull/5396)) +- Ponylang ([#5416](https://github.com/helix-editor/helix/pull/5416)) +- DHall ([1f6809c](https://github.com/helix-editor/helix/commit/1f6809c)) +- Sagemath ([#5649](https://github.com/helix-editor/helix/pull/5649)) +- MSBuild ([#5793](https://github.com/helix-editor/helix/pull/5793)) +- pem ([#5797](https://github.com/helix-editor/helix/pull/5797)) +- passwd ([#4959](https://github.com/helix-editor/helix/pull/4959)) +- hosts ([#4950](https://github.com/helix-editor/helix/pull/4950), [#5914](https://github.com/helix-editor/helix/pull/5914)) +- uxntal ([#6047](https://github.com/helix-editor/helix/pull/6047)) +- Yuck ([#6064](https://github.com/helix-editor/helix/pull/6064), [#6242](https://github.com/helix-editor/helix/pull/6242)) +- GNU gettext PO ([#5996](https://github.com/helix-editor/helix/pull/5996)) +- Sway ([#6023](https://github.com/helix-editor/helix/pull/6023)) +- NASM ([#6068](https://github.com/helix-editor/helix/pull/6068)) +- PRQL ([#6126](https://github.com/helix-editor/helix/pull/6126)) +- reStructuredText ([#6180](https://github.com/helix-editor/helix/pull/6180)) +- Smithy ([#6370](https://github.com/helix-editor/helix/pull/6370)) +- VHDL ([#5826](https://github.com/helix-editor/helix/pull/5826)) +- Rego (OpenPolicy Agent) ([#6415](https://github.com/helix-editor/helix/pull/6415)) +- Nim ([#6123](https://github.com/helix-editor/helix/pull/6123)) + +Updated languages and queries: + +- Use diff syntax for patch files ([#5085](https://github.com/helix-editor/helix/pull/5085)) +- Add Haskell textobjects ([#5061](https://github.com/helix-editor/helix/pull/5061)) +- Fix commonlisp configuration ([#5091](https://github.com/helix-editor/helix/pull/5091)) +- Update Scheme ([bae890d](https://github.com/helix-editor/helix/commit/bae890d)) +- Add indent queries for Bash ([#5149](https://github.com/helix-editor/helix/pull/5149)) +- Recognize `c++` as a C++ extension ([#5183](https://github.com/helix-editor/helix/pull/5183)) +- Enable HTTP server in `metals` (Scala) config ([#5551](https://github.com/helix-editor/helix/pull/5551)) +- Change V-lang language server to `v ls` from `vls` ([#5677](https://github.com/helix-editor/helix/pull/5677)) +- Inject comment grammar into Nix ([#5208](https://github.com/helix-editor/helix/pull/5208)) +- Update Rust highlights ([#5238](https://github.com/helix-editor/helix/pull/5238), [#5349](https://github.com/helix-editor/helix/pull/5349)) +- Fix HTML injection within Markdown ([#5265](https://github.com/helix-editor/helix/pull/5265)) +- Fix comment token for godot ([#5276](https://github.com/helix-editor/helix/pull/5276)) +- Expand injections for Vue ([#5268](https://github.com/helix-editor/helix/pull/5268)) +- Add `.bash_aliases` as a Bash file-type ([#5347](https://github.com/helix-editor/helix/pull/5347)) +- Fix comment token for sshclientconfig ([#5351](https://github.com/helix-editor/helix/pull/5351)) +- Update Prisma ([#5417](https://github.com/helix-editor/helix/pull/5417)) +- Update C++ ([#5457](https://github.com/helix-editor/helix/pull/5457)) +- Add more file-types for Python ([#5593](https://github.com/helix-editor/helix/pull/5593)) +- Update tree-sitter-scala ([#5576](https://github.com/helix-editor/helix/pull/5576)) +- Add an injection regex for Lua ([#5606](https://github.com/helix-editor/helix/pull/5606)) +- Add `build.gradle` to java roots configuration ([#5641](https://github.com/helix-editor/helix/pull/5641)) +- Add Hub PR files to markdown file-types ([#5634](https://github.com/helix-editor/helix/pull/5634)) +- Add an external formatter configuration for Cue ([#5679](https://github.com/helix-editor/helix/pull/5679)) +- Add injections for builders and writers to Nix ([#5629](https://github.com/helix-editor/helix/pull/5629)) +- Update tree-sitter-xml to fix whitespace parsing ([#5685](https://github.com/helix-editor/helix/pull/5685)) +- Add `Justfile` to the make file-types configuration ([#5687](https://github.com/helix-editor/helix/pull/5687)) +- Update tree-sitter-sql and highlight queries ([#5683](https://github.com/helix-editor/helix/pull/5683), [#5772](https://github.com/helix-editor/helix/pull/5772)) +- Use the bash grammar and queries for env language ([#5720](https://github.com/helix-editor/helix/pull/5720)) +- Add podspec files to ruby file-types ([#5811](https://github.com/helix-editor/helix/pull/5811)) +- Recognize `.C` and `.H` file-types as C++ ([#5808](https://github.com/helix-editor/helix/pull/5808)) +- Recognize plist and mobileconfig files as XML ([#5863](https://github.com/helix-editor/helix/pull/5863)) +- Fix `select` indentation in Go ([#5713](https://github.com/helix-editor/helix/pull/5713)) +- Check for external file modifications when writing ([#5805](https://github.com/helix-editor/helix/pull/5805)) +- Recognize containerfiles as dockerfile syntax ([#5873](https://github.com/helix-editor/helix/pull/5873)) +- Update godot grammar and queries ([#5944](https://github.com/helix-editor/helix/pull/5944), [#6186](https://github.com/helix-editor/helix/pull/6186)) +- Improve DHall highlights ([#5959](https://github.com/helix-editor/helix/pull/5959)) +- Recognize `.env.dist` and `source.env` as env language ([#6003](https://github.com/helix-editor/helix/pull/6003)) +- Update tree-sitter-git-rebase ([#6030](https://github.com/helix-editor/helix/pull/6030), [#6094](https://github.com/helix-editor/helix/pull/6094)) +- Improve SQL highlights ([#6041](https://github.com/helix-editor/helix/pull/6041)) +- Improve markdown highlights and inject LaTeX ([#6100](https://github.com/helix-editor/helix/pull/6100)) +- Add textobject queries for Elm ([#6084](https://github.com/helix-editor/helix/pull/6084)) +- Recognize graphql schema file type ([#6159](https://github.com/helix-editor/helix/pull/6159)) +- Improve highlighting in comments ([#6143](https://github.com/helix-editor/helix/pull/6143)) +- Improve highlighting for JavaScript/TypeScript/ECMAScript languages ([#6205](https://github.com/helix-editor/helix/pull/6205)) +- Improve PHP highlights ([#6203](https://github.com/helix-editor/helix/pull/6203), [#6250](https://github.com/helix-editor/helix/pull/6250), [#6299](https://github.com/helix-editor/helix/pull/6299)) +- Improve Go highlights ([#6204](https://github.com/helix-editor/helix/pull/6204)) +- Highlight unchecked sqlx functions as SQL in Rust ([#6256](https://github.com/helix-editor/helix/pull/6256)) +- Improve Erlang highlights ([cdd6c8d](https://github.com/helix-editor/helix/commit/cdd6c8d)) +- Improve Nix highlights ([fb4d703](https://github.com/helix-editor/helix/commit/fb4d703)) +- Improve gdscript highlights ([#6311](https://github.com/helix-editor/helix/pull/6311)) +- Improve Vlang highlights ([#6279](https://github.com/helix-editor/helix/pull/6279)) +- Improve Makefile highlights ([#6339](https://github.com/helix-editor/helix/pull/6339)) +- Remove auto-pair for `'` in OCaml ([#6381](https://github.com/helix-editor/helix/pull/6381)) +- Fix indents in switch statements in ECMA languages ([#6369](https://github.com/helix-editor/helix/pull/6369)) +- Recognize xlb and storyboard file-types as XML ([#6407](https://github.com/helix-editor/helix/pull/6407)) +- Recognize cts and mts file-types as TypeScript ([#6424](https://github.com/helix-editor/helix/pull/6424)) +- Recognize SVG file-type as XML ([#6431](https://github.com/helix-editor/helix/pull/6431)) +- Add theme scopes for (un)checked list item markup scopes ([#6434](https://github.com/helix-editor/helix/pull/6434)) +- Update git commit grammar and add the comment textobject ([#6439](https://github.com/helix-editor/helix/pull/6439), [#6493](https://github.com/helix-editor/helix/pull/6493)) +- Recognize ARB file-type as JSON ([#6452](https://github.com/helix-editor/helix/pull/6452)) +- Inject markdown into markdown strings in Julia ([#6489](https://github.com/helix-editor/helix/pull/6489)) + +Packaging: + +- Fix Nix flake devShell for darwin hosts ([#5368](https://github.com/helix-editor/helix/pull/5368)) +- Add Appstream metadata file to `contrib/` ([#5643](https://github.com/helix-editor/helix/pull/5643)) +- Increase the MSRV to 1.65 ([#5570](https://github.com/helix-editor/helix/pull/5570), [#6185](https://github.com/helix-editor/helix/pull/6185)) +- Expose the Nix flake's `wrapper` ([#5994](https://github.com/helix-editor/helix/pull/5994)) + # 22.12 (2022-12-06) This is a great big release filled with changes from a 99 contributors. A big _thank you_ to you all! diff --git a/Cargo.lock b/Cargo.lock index 98563fed7..840c664bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,6 +40,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -75,15 +84,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.0.2" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1" +checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813" [[package]] name = "bstr" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" +checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" dependencies = [ "memchr", "once_cell", @@ -102,9 +111,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecount" @@ -114,9 +123,9 @@ checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cassowary" @@ -197,9 +206,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "crc32fast" @@ -238,9 +247,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.82" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453" +checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" dependencies = [ "cc", "cxxbridge-flags", @@ -250,9 +259,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.82" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0" +checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" dependencies = [ "cc", "codespan-reporting", @@ -260,24 +269,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 1.0.104", + "syn 2.0.15", ] [[package]] name = "cxxbridge-flags" -version = "1.0.82" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71" +checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" [[package]] name = "cxxbridge-macro" -version = "1.0.82" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" +checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 1.0.104", + "syn 2.0.15", ] [[package]] @@ -323,15 +332,15 @@ dependencies = [ [[package]] name = "dunce" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "encoding_rs" @@ -353,13 +362,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.2.8" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -384,43 +393,42 @@ dependencies = [ [[package]] name = "etcetera" -version = "0.4.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d017fce18e4e9bfa75e1db51f49f4487bd3f8a7df509b24a46474a956ee962fd" +checksum = "51822eedc6129d8c4d96cec86d56b785e983f943c9ce9fb892e0c2a99a7f47a0" dependencies = [ "cfg-if", - "dirs-next", - "thiserror", + "home", ] [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] [[package]] name = "fern" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd7b0849075e79ee9a1836df22c717d1eba30451796fdc631b04565dd11e2a" +checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee" dependencies = [ "log", ] [[package]] name = "filetime" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" +checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" dependencies = [ "cfg-if", "libc", - "redox_syscall", - "windows-sys 0.42.0", + "redox_syscall 0.2.16", + "windows-sys 0.48.0", ] [[package]] @@ -450,15 +458,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -467,15 +475,15 @@ dependencies = [ [[package]] name = "futures-task" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-core", "futures-task", @@ -495,9 +503,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if", "libc", @@ -506,9 +514,9 @@ dependencies = [ [[package]] name = "gix" -version = "0.41.0" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1853c840375a04e02315cb225b6d802291abfabbf08e500727c98a8670f1bf1" +checksum = "c256ea71cc1967faaefdaad15f334146b7c806f12460dcafd3afed845c8c78dd" dependencies = [ "gix-actor", "gix-attributes", @@ -604,9 +612,9 @@ dependencies = [ [[package]] name = "gix-config" -version = "0.19.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aa7d7dd60256b7a0c0506a1d708ec92767c2662ee57b3301b538eaa3e064f8a" +checksum = "7fbad5ce54a8fc997acc50febd89ec80fa6e97cb7f8d0654cb229936407489d8" dependencies = [ "bstr", "gix-config-value", @@ -615,6 +623,7 @@ dependencies = [ "gix-path", "gix-ref", "gix-sec", + "log", "memchr", "nom", "once_cell", @@ -625,9 +634,9 @@ dependencies = [ [[package]] name = "gix-config-value" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d4a4ba0531e46fe558459557a5b29fb86c3e4b2666c1c0861d93c7c678331" +checksum = "d09154c0c8677e4da0ec35e896f56ee3e338e741b9599fae06075edd83a4081c" dependencies = [ "bitflags 1.3.2", "bstr", @@ -666,9 +675,9 @@ dependencies = [ [[package]] name = "gix-diff" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585b0834d4b6791a848637c4e109545fda9b0f29b591ba55edb33ceda6e7856b" +checksum = "103a0fa79b0d438f5ecb662502f052e530ace4fe1fe8e1c83c0c6da76d728e67" dependencies = [ "gix-hash", "gix-object", @@ -678,9 +687,9 @@ dependencies = [ [[package]] name = "gix-discover" -version = "0.16.0" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b58931ab475a977deff03417e041a66e4bcb76c4e5797e7ec2fcb272ebce01c" +checksum = "6eba8ba458cb8f4a6c33409b0fe650b1258655175a7ffd1d24fafd3ed31d880b" dependencies = [ "bstr", "dunce", @@ -693,9 +702,9 @@ dependencies = [ [[package]] name = "gix-features" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6a9dfa7b3c1a99315203e8b97f8f99f3bd95731590607abeaa5ca31bc41fe3" +checksum = "0b76f9a80f6dd7be66442ae86e1f534effad9546676a392acc95e269d0c21c22" dependencies = [ "crc32fast", "flate2", @@ -720,9 +729,9 @@ dependencies = [ [[package]] name = "gix-hash" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0c5a9f4d621d4f4ea046bb331df5c746ca735b8cae5b234cc2be70ee4dbef0" +checksum = "2a258595457bc192d1f1c59d0d168a1e34e2be9b97a614e14995416185de41a7" dependencies = [ "hex", "thiserror", @@ -730,9 +739,9 @@ dependencies = [ [[package]] name = "gix-hashtable" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9609c1b8f36f12968e6a6098f7cdb52004f7d42d570f47a2d6d7c16612f19acb" +checksum = "e4e55e40dfd694884f0eb78796c5bddcf2f8b295dace47039099dd7e76534973" dependencies = [ "gix-hash", "hashbrown 0.13.2", @@ -741,9 +750,9 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "546ee7855d5d8731288f05a63c07ab41b59cb406660a825ed3fe89d7223823df" +checksum = "717ab601ece7921f59fe86849dbe27d44a46ebb883b5885732c4f30df4996177" dependencies = [ "bitflags 1.3.2", "bstr", @@ -804,9 +813,9 @@ dependencies = [ [[package]] name = "gix-odb" -version = "0.43.0" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa63fce01e5bce663bb24ad01fa2b77266e91b1d1982aab3f67cb0aed8af8169" +checksum = "e83af2e3e36005bfe010927f0dff41fb5acc3e3d89c6f1174135b3a34086bda2" dependencies = [ "arc-swap", "gix-features", @@ -822,9 +831,9 @@ dependencies = [ [[package]] name = "gix-pack" -version = "0.33.0" +version = "0.33.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bc9d22f0d0620d013003ab05ead5c60124b6e1101bc245be9be4fd7e2330cb" +checksum = "9401911c7fe032ad7b31c6a6b5be59cb283d1d6c999417a8215056efe6d635f3" dependencies = [ "clru", "gix-chunk", @@ -844,9 +853,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6c104a66dec149cb8f7aaafc6ab797654cf82d67f050fd0cb7e7294e328354b" +checksum = "32370dce200bb951df013e03dff35b4233fc7a89458642b047629b91734a7e19" dependencies = [ "bstr", "thiserror", @@ -854,9 +863,9 @@ dependencies = [ [[package]] name = "gix-prompt" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20cebf73229debaa82574c4fd20dcaf00fa8d4bfce823a862c4e990d7a0b5b4" +checksum = "0f3034d4d935aef2c7bf719aaa54b88c520e82413118d886ae880a31d5bdee57" dependencies = [ "gix-command", "gix-config-value", @@ -878,9 +887,9 @@ dependencies = [ [[package]] name = "gix-ref" -version = "0.27.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3de7cd1050fa82be4240994defc1f1f2fd9def5d8815dcd005f5ddc5e3dc7511" +checksum = "e4e909396ed3b176823991ccc391c276ae2a015e54edaafa3566d35123cfac9d" dependencies = [ "gix-actor", "gix-features", @@ -911,9 +920,9 @@ dependencies = [ [[package]] name = "gix-revision" -version = "0.12.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed98e4a0254953c64bc913bd23146a1de662067d5cf974cbdde396958b39e5b0" +checksum = "3c6f6ff53f888858afc24bf12628446a14279ceec148df6194481f306f553ad2" dependencies = [ "bstr", "gix-date", @@ -933,14 +942,14 @@ dependencies = [ "dirs", "gix-path", "libc", - "windows", + "windows 0.43.0", ] [[package]] name = "gix-tempfile" -version = "5.0.1" +version = "5.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aed73ef9642f779d609fd19acc332ac1597b978ee87ec11743a68eefaed65bfa" +checksum = "c2ceb30a610e3f5f2d5f9a5114689fde507ba9417705a8cf3429604275b2153c" dependencies = [ "libc", "once_cell", @@ -978,9 +987,9 @@ dependencies = [ [[package]] name = "gix-validate" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69ddb780ea1465255e66818d75b7098371c58dbc9560da4488a44b9f5c7e443" +checksum = "7bd629d3680773e1785e585d76fd4295b740b559cad9141517300d99a0c8c049" dependencies = [ "bstr", "thiserror", @@ -988,9 +997,9 @@ dependencies = [ [[package]] name = "gix-worktree" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "992b8fdade33e079dc61c29f2388ab8e049965ebf7be40efa7f8b80e3c4543fe" +checksum = "54ec9a000b4f24af706c3cc680c7cda235656cbe3216336522f5692773b8a301" dependencies = [ "bstr", "gix-attributes", @@ -1010,7 +1019,7 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.20", "bstr", "fnv", "log", @@ -1032,12 +1041,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "997598b41d53a37a2e3fc5300d5c11d825368c054420a9c65125b8fe1078463f" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.20", "bstr", "grep-matcher", "log", "regex", - "regex-syntax", + "regex-syntax 0.6.29", "thread_local", ] @@ -1080,8 +1089,9 @@ version = "0.6.0" dependencies = [ "ahash 0.8.3", "arc-swap", - "bitflags 2.0.2", + "bitflags 2.2.1", "chrono", + "dunce", "encoding_rs", "etcetera", "hashbrown 0.13.2", @@ -1132,6 +1142,7 @@ dependencies = [ "log", "once_cell", "serde", + "tempfile", "threadpool", "toml", "tree-sitter", @@ -1149,6 +1160,7 @@ dependencies = [ "helix-parsec", "log", "lsp-types", + "parking_lot", "serde", "serde_json", "thiserror", @@ -1204,7 +1216,7 @@ dependencies = [ name = "helix-tui" version = "0.6.0" dependencies = [ - "bitflags 2.0.2", + "bitflags 2.2.1", "cassowary", "crossterm", "helix-core", @@ -1237,7 +1249,7 @@ version = "0.6.0" dependencies = [ "anyhow", "arc-swap", - "bitflags 2.0.2", + "bitflags 2.2.1", "chardetng", "clipboard-win", "crossterm", @@ -1264,13 +1276,19 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.4.3" @@ -1288,16 +1306,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.53" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "winapi", + "windows 0.48.0", ] [[package]] @@ -1349,9 +1367,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", @@ -1384,25 +1402,26 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.4" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ + "hermit-abi 0.3.1", "libc", - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -1415,34 +1434,34 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb" dependencies = [ "cfg-if", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "link-cplusplus" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" dependencies = [ "cc", ] [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" [[package]] name = "lock_api" @@ -1484,9 +1503,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] @@ -1508,21 +1527,21 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] name = "nix" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ "bitflags 1.3.2", "cfg-if", @@ -1532,9 +1551,9 @@ dependencies = [ [[package]] name = "nom" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -1561,11 +1580,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] @@ -1596,15 +1615,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.4" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -1627,18 +1646,18 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] [[package]] name = "prodash" -version = "23.1.1" +version = "23.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d73c6b64cb5b99eb63ca97d378685712617ec0172ff5c04cd47a489d3e2c51f8" +checksum = "9516b775656bc3e8985e19cd4b8c0c0de045095074e453d2c0a513b5f978392d" [[package]] name = "pulldown-cmark" @@ -1696,6 +1715,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -1703,19 +1731,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] [[package]] name = "regex" -version = "1.7.3" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" dependencies = [ - "aho-corasick", + "aho-corasick 1.0.1", "memchr", - "regex-syntax", + "regex-syntax 0.7.1", ] [[package]] @@ -1730,6 +1758,12 @@ version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +[[package]] +name = "regex-syntax" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" + [[package]] name = "ropey" version = "1.6.0" @@ -1742,23 +1776,23 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.7" +version = "0.37.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" +checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "same-file" @@ -1777,35 +1811,35 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scratch" -version = "1.0.2" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "serde" -version = "1.0.158" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.158" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.4", + "syn 2.0.15", ] [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -1814,13 +1848,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.9" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" +checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 1.0.104", + "syn 2.0.15", ] [[package]] @@ -1861,9 +1895,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] @@ -1882,9 +1916,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -1945,15 +1979,15 @@ checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" [[package]] name = "str_indices" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9199fa80c817e074620be84374a520062ebac833f358d74b37060ce4a0f2c0" +checksum = "5f026164926842ec52deb1938fae44f83dfdb82d0a5b0270c5bd5935ab74d6dd" [[package]] name = "syn" -version = "1.0.104" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -1962,9 +1996,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.4" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c622ae390c9302e214c31013517c2061ecb2699935882c60a9b37f82f8625ae" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ "proc-macro2", "quote", @@ -1973,22 +2007,22 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -2030,15 +2064,16 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.4", + "syn 2.0.15", ] [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -2053,9 +2088,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ "itoa", "libc", @@ -2073,9 +2108,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" dependencies = [ "time-core", ] @@ -2091,9 +2126,9 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" @@ -2122,7 +2157,7 @@ checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.4", + "syn 2.0.15", ] [[package]] @@ -2172,8 +2207,9 @@ dependencies = [ [[package]] name = "tree-sitter" -version = "0.20.9" -source = "git+https://github.com/tree-sitter/tree-sitter?rev=c51896d32dcc11a38e41f36e3deb1a6a9c4f4b14#c51896d32dcc11a38e41f36e3deb1a6a9c4f4b14" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e747b1f9b7b931ed39a548c1fae149101497de3c1fc8d9e18c62c1a66c683d3d" dependencies = [ "cc", "regex", @@ -2190,9 +2226,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-bom" @@ -2208,9 +2244,9 @@ checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-linebreak" @@ -2263,12 +2299,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] @@ -2280,9 +2315,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2290,24 +2325,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.104", + "syn 1.0.109", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2315,22 +2350,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn 1.0.104", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "which" @@ -2380,28 +2415,22 @@ version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] -name = "windows-sys" -version = "0.42.0" +name = "windows" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-targets 0.48.0", ] [[package]] @@ -2410,65 +2439,131 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", ] [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" diff --git a/Cargo.toml b/Cargo.toml index aaa21659a..c63518897 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,3 @@ inherits = "test" package.helix-core.opt-level = 2 package.helix-tui.opt-level = 2 package.helix-term.opt-level = 2 - -[patch.crates-io] -tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "c51896d32dcc11a38e41f36e3deb1a6a9c4f4b14" } diff --git a/VERSION b/VERSION index e70b3aebd..35371314c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -22.12 \ No newline at end of file +23.03 \ No newline at end of file diff --git a/book/src/configuration.md b/book/src/configuration.md index e2dfc89ef..1fdbf0052 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -30,6 +30,9 @@ You can use a custom configuration file by specifying it with the `-c` or Additionally, you can reload the configuration file by sending the USR1 signal to the Helix process on Unix operating systems, such as by using the command `pkill -USR1 hx`. +Finally, you can have a `config.toml` local to a project by putting it under a `.helix` directory in your repository. +Its settings will be merged with the configuration directory `config.toml` and the built-in configuration. + ## Editor ### `[editor]` Section @@ -57,7 +60,8 @@ signal to the Helix process on Unix operating systems, such as by using the comm | `rulers` | List of column positions at which to display the rulers. Can be overridden by language specific `rulers` in `languages.toml` file | `[]` | | `bufferline` | Renders a line at the top of the editor displaying open buffers. Can be `always`, `never` or `multiple` (only shown if more than one buffer is in use) | `never` | | `color-modes` | Whether to color the mode indicator with different colors depending on the mode itself | `false` | -| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap_at_text_width` is set | `80` | +| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap-at-text-width` is set | `80` | +| `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml` | `[]` | ### `[editor.statusline]` Section @@ -123,6 +127,7 @@ The following statusline elements can be configured: | `auto-signature-help` | Enable automatic popup of signature help (parameter hints) | `true` | | `display-inlay-hints` | Display inlay hints[^2] | `false` | | `display-signature-help-docs` | Display docs under signature help popup | `true` | +| `snippets` | Enables snippet completions. Requires a server restart (`:lsp-restart`) to take effect after `:config-reload`/`:set`. | `true` | [^1]: By default, a progress spinner is shown in the statusline beside the file path. [^2]: You may also have to activate them in the LSP config for them to appear, not just in Helix. @@ -156,7 +161,7 @@ All git related options are only enabled in a git repository. | Key | Description | Default | |--|--|---------| |`hidden` | Enables ignoring hidden files | true -|`follow-links` | Follow symlinks instead of ignoring them | true +|`follow-symlinks` | Follow symlinks instead of ignoring them | true |`deduplicate-links` | Ignore symlinks that point at files already shown in the picker | true |`parents` | Enables reading ignore files from parent directories | true |`ignore` | Enables reading `.ignore` files | true diff --git a/book/src/from-vim.md b/book/src/from-vim.md index 6ace91027..ffd5addc6 100644 --- a/book/src/from-vim.md +++ b/book/src/from-vim.md @@ -2,9 +2,9 @@ Helix's editing model is strongly inspired from Vim and Kakoune, and a notable difference from Vim (and the most striking similarity to Kakoune) is that Helix -follows the `selection → action` model. This means that the whatever you are -going to act on (a word, a paragraph, a line, etc) is selected first and the -action itself (delete, change, yank, etc) comes second. A cursor is simply a +follows the `selection → action` model. This means that whatever you are +going to act on (a word, a paragraph, a line, etc.) is selected first and the +action itself (delete, change, yank, etc.) comes second. A cursor is simply a single width selection. See also Kakoune's [Migrating from Vim](https://github.com/mawww/kakoune/wiki/Migrating-from-Vim) and Helix's [Migrating from Vim](https://github.com/helix-editor/helix/wiki/Migrating-from-Vim). diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 003ed4a4a..331d212f5 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -9,6 +9,7 @@ | bicep | ✓ | | | `bicep-langserver` | | c | ✓ | ✓ | ✓ | `clangd` | | c-sharp | ✓ | ✓ | | `OmniSharp` | +| cabal | ✓ | | | | | cairo | ✓ | | | | | capnp | ✓ | | ✓ | | | clojure | ✓ | | | `clojure-lsp` | @@ -27,6 +28,7 @@ | diff | ✓ | | | | | dockerfile | ✓ | | | `docker-langserver` | | dot | ✓ | | | `dot-language-server` | +| dtd | ✓ | | | | | edoc | ✓ | | | | | eex | ✓ | | | | | ejs | ✓ | | | | @@ -59,6 +61,7 @@ | heex | ✓ | ✓ | | `elixir-ls` | | hosts | ✓ | | | | | html | ✓ | | | `vscode-html-language-server` | +| hurl | ✓ | | ✓ | | | idris | | | | `idris2-lsp` | | iex | ✓ | | | | | ini | ✓ | | | | @@ -68,7 +71,8 @@ | json | ✓ | | ✓ | `vscode-json-language-server` | | jsonnet | ✓ | | | `jsonnet-language-server` | | jsx | ✓ | ✓ | ✓ | `typescript-language-server` | -| julia | ✓ | | | `julia` | +| julia | ✓ | ✓ | ✓ | `julia` | +| just | ✓ | ✓ | ✓ | | | kdl | ✓ | | | | | kotlin | ✓ | | | `kotlin-language-server` | | latex | ✓ | ✓ | | `texlab` | @@ -79,6 +83,7 @@ | llvm-mir-yaml | ✓ | | ✓ | | | lua | ✓ | ✓ | ✓ | `lua-language-server` | | make | ✓ | | | | +| markdoc | ✓ | | | `markdoc-ls` | | markdown | ✓ | | | `marksman` | | markdown.inline | ✓ | | | | | matlab | ✓ | | | | @@ -94,6 +99,7 @@ | ocaml | ✓ | | ✓ | `ocamllsp` | | ocaml-interface | ✓ | | | `ocamllsp` | | odin | ✓ | | | `ols` | +| opencl | ✓ | ✓ | ✓ | `clangd` | | openscad | ✓ | | | `openscad-lsp` | | org | ✓ | | | | | pascal | ✓ | ✓ | | `pasls` | @@ -116,6 +122,7 @@ | rego | ✓ | | | `regols` | | rescript | ✓ | ✓ | | `rescript-language-server` | | rmarkdown | ✓ | | ✓ | `R` | +| robot | ✓ | | | `robotframework_ls` | | ron | ✓ | | ✓ | | | rst | ✓ | | | | | ruby | ✓ | ✓ | ✓ | `solargraph` | diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 8b367aad8..a9d68b75a 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -46,7 +46,7 @@ | `:character-info`, `:char` | Get info about the character under the primary cursor. | | `:reload` | Discard changes and reload from the source file. | | `:reload-all` | Discard changes and reload all documents from the source files. | -| `:update` | Write changes only if the file has been modified. | +| `:update`, `:u` | Write changes only if the file has been modified. | | `:lsp-workspace-command` | Open workspace command picker | | `:lsp-restart` | Restarts the Language Server that is in use by the current doc | | `:lsp-stop` | Stops the Language Server that is in use by the current doc | @@ -70,6 +70,7 @@ | `:tree-sitter-subtree`, `:ts-subtree` | Display tree sitter subtree under cursor, primarily for debugging queries. | | `:config-reload` | Refresh user config. | | `:config-open` | Open the user config.toml file. | +| `:config-open-workspace` | Open the workspace config.toml file. | | `:log-open` | Open the helix log file. | | `:insert-output` | Run shell command, inserting output before each selection. | | `:append-output` | Run shell command, appending output after each selection. | diff --git a/book/src/install.md b/book/src/install.md index a0e24de72..169e6e0b6 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -12,6 +12,7 @@ - [macOS](#macos) - [Homebrew Core](#homebrew-core) - [Windows](#windows) + - [Winget](#winget) - [Scoop](#scoop) - [Chocolatey](#chocolatey) - [MSYS2](#msys2) @@ -40,8 +41,6 @@ line. ## Linux, macOS, Windows and OpenBSD packaging status -Helix is available for Linux, macOS and Windows via the official repositories listed below. - [![Packaging status](https://repology.org/badge/vertical-allrepos/helix.svg)](https://repology.org/project/helix/versions) ## Linux @@ -50,7 +49,7 @@ The following third party repositories are available: ### Ubuntu -Helix is available via [Maveonair's PPA](https://launchpad.net/~maveonair/+archive/ubuntu/helix-editor): +Add the `PPA` for Helix: ```sh sudo add-apt-repository ppa:maveonair/helix-editor @@ -60,7 +59,7 @@ sudo apt install helix ### Fedora/RHEL -Helix is available via `copr`: +Enable the `COPR` repository for Helix: ```sh sudo dnf copr enable varlad/helix @@ -91,8 +90,8 @@ If you are using a version of Nix without flakes enabled, ### AppImage -Install Helix using [AppImage](https://appimage.org/). -Download Helix AppImage from the [latest releases](https://github.com/helix-editor/helix/releases/latest) page. +Install Helix using the Linux [AppImage](https://appimage.org/) format. +Download the official Helix AppImage from the [latest releases](https://github.com/helix-editor/helix/releases/latest) page. ```sh chmod +x helix-*.AppImage # change permission for executable mode @@ -109,9 +108,17 @@ brew install helix ## Windows -Install on Windows using [Scoop](https://scoop.sh/), [Chocolatey](https://chocolatey.org/) +Install on Windows using [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/), [Scoop](https://scoop.sh/), [Chocolatey](https://chocolatey.org/) or [MSYS2](https://msys2.org/). +### Winget +Windows Package Manager winget command-line tool is by default available on Windows 11 and modern versions of Windows 10 as a part of the App Installer. +You can get [App Installer from the Microsoft Store](https://www.microsoft.com/p/app-installer/9nblggh4nns1#activetab=pivot:overviewtab). If it's already installed, make sure it is updated with the latest version. + +```sh +winget install Helix.Helix +``` + ### Scoop ```sh @@ -134,33 +141,37 @@ pacman -S mingw-w64-ucrt-x86_64-helix ## Building from source -Clone the repository: +Requirements: + +- The [Rust toolchain](https://www.rust-lang.org/tools/install) +- The [Git version control system](https://git-scm.com/) +- A c++14 compatible compiler to build the tree-sitter grammars, for example GCC or Clang + +If you are using the `musl-libc` standard library instead of `glibc` the following environment variable must be set during the build to ensure tree-sitter grammars can be loaded correctly: + +```sh +RUSTFLAGS="-C target-feature=-crt-static" +``` + +1. Clone the repository: ```sh git clone https://github.com/helix-editor/helix cd helix ``` -Compile from source: +2. Compile from source: ```sh cargo install --path helix-term --locked ``` This command will create the `hx` executable and construct the tree-sitter -grammars in the local `runtime` folder. To build the tree-sitter grammars requires -a c++ compiler to be installed, for example `gcc-c++`. - -> 💡 If you are using the musl-libc instead of glibc the following environment variable must be set during the build -> to ensure tree-sitter grammars can be loaded correctly: -> -> ```sh -> RUSTFLAGS="-C target-feature=-crt-static" -> ``` +grammars in the local `runtime` folder. > 💡 Tree-sitter grammars can be fetched and compiled if not pre-packaged. Fetch -> grammars with `hx --grammar fetch` (requires `git`) and compile them with -> `hx --grammar build` (requires a C++ compiler). This will install them in +> grammars with `hx --grammar fetch` and compile them with +> `hx --grammar build`. This will install them in > the `runtime` directory within the user's helix config directory (more > [details below](#multiple-runtime-directories)). diff --git a/book/src/languages.md b/book/src/languages.md index 5ed69505d..fe4db1413 100644 --- a/book/src/languages.md +++ b/book/src/languages.md @@ -63,7 +63,8 @@ These configuration keys are available: | `config` | Language Server configuration | | `grammar` | The tree-sitter grammar to use (defaults to the value of `name`) | | `formatter` | The formatter for the language, it will take precedence over the lsp when defined. The formatter must be able to take the original file as input from stdin and write the formatted file to stdout | -| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap_at_text_width` is set, defaults to `editor.text-width` | +| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap-at-text-width` is set, defaults to `editor.text-width` | +| `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml`. Overwrites the setting of the same name in `config.toml` if set. | ### File-type detection and the `file-types` key diff --git a/book/src/themes.md b/book/src/themes.md index 7accb67f0..56d0372ca 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -278,8 +278,11 @@ These scopes are used for theming the editor interface: | `ui.cursor.primary.normal` | | | `ui.cursor.primary.insert` | | | `ui.cursor.primary.select` | | +| `ui.debug.breakpoint` | Breakpoint indicator, found in the gutter | +| `ui.debug.active` | Indicator for the line at which debugging execution is paused at, found in the gutter | | `ui.gutter` | Gutter | | `ui.gutter.selected` | Gutter for the line the cursor is on | +| `ui.highlight.frameline` | Line at which debugging execution is paused at | | `ui.linenr` | Line numbers | | `ui.linenr.selected` | Line number for the line the cursor is on | | `ui.statusline` | Statusline | diff --git a/contrib/Helix.appdata.xml b/contrib/Helix.appdata.xml index a24284975..b99738a18 100644 --- a/contrib/Helix.appdata.xml +++ b/contrib/Helix.appdata.xml @@ -36,6 +36,9 @@ + + https://helix-editor.com/news/release-23-03-highlights/ + https://helix-editor.com/news/release-22-12-highlights/ diff --git a/flake.lock b/flake.lock index fa292273a..d33c404ef 100644 --- a/flake.lock +++ b/flake.lock @@ -18,9 +18,6 @@ }, "dream2nix": { "inputs": { - "alejandra": [ - "nci" - ], "all-cabal-json": [ "nci" ], @@ -28,6 +25,8 @@ "devshell": [ "nci" ], + "drv-parts": "drv-parts", + "flake-compat": "flake-compat", "flake-parts": [ "nci", "parts" @@ -51,6 +50,7 @@ "nci", "nixpkgs" ], + "nixpkgsV1": "nixpkgsV1", "poetry2nix": [ "nci" ], @@ -62,11 +62,11 @@ ] }, "locked": { - "lastModified": 1677289985, - "narHash": "sha256-lUp06cTTlWubeBGMZqPl9jODM99LpWMcwxRiscFAUJg=", + "lastModified": 1680258209, + "narHash": "sha256-lEo50RXI/17/a9aCIun8Hz62ZJ5JM5RGeTgclIP+Lgc=", "owner": "nix-community", "repo": "dream2nix", - "rev": "28b973a8d4c30cc1cbb3377ea2023a76bc3fb889", + "rev": "6f512b5a220fdb26bd3c659f7b55e4f052ec8b35", "type": "github" }, "original": { @@ -75,6 +75,54 @@ "type": "github" } }, + "drv-parts": { + "inputs": { + "flake-compat": [ + "nci", + "dream2nix", + "flake-compat" + ], + "flake-parts": [ + "nci", + "dream2nix", + "flake-parts" + ], + "nixpkgs": [ + "nci", + "dream2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1680172861, + "narHash": "sha256-QMyI338xRxaHFDlCXdLCtgelGQX2PdlagZALky4ZXJ8=", + "owner": "davhau", + "repo": "drv-parts", + "rev": "ced8a52f62b0a94244713df2225c05c85b416110", + "type": "github" + }, + "original": { + "owner": "davhau", + "repo": "drv-parts", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "locked": { "lastModified": 1659877975, @@ -119,11 +167,11 @@ ] }, "locked": { - "lastModified": 1677297103, - "narHash": "sha256-ArlJIbp9NGV9yvhZdV0SOUFfRlI/kHeKoCk30NbSiLc=", + "lastModified": 1680329418, + "narHash": "sha256-+KN0eQLSZvL1J0kDO8/fxv0UCHTyZCADLmpIfeeiSGo=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "a79272a2cb0942392bb3a5bf9a3ec6bc568795b2", + "rev": "98c1d2ff5155f0fee5d290f6b982cb990839d540", "type": "github" }, "original": { @@ -134,11 +182,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1677063315, - "narHash": "sha256-qiB4ajTeAOVnVSAwCNEEkoybrAlA+cpeiBxLobHndE8=", + "lastModified": 1680213900, + "narHash": "sha256-cIDr5WZIj3EkKyCgj/6j3HBH4Jj1W296z7HTcWj1aMA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "988cc958c57ce4350ec248d2d53087777f9e1949", + "rev": "e3652e0735fbec227f342712f180f4f21f0594f2", "type": "github" }, "original": { @@ -151,11 +199,11 @@ "nixpkgs-lib": { "locked": { "dir": "lib", - "lastModified": 1675183161, - "narHash": "sha256-Zq8sNgAxDckpn7tJo7V1afRSk2eoVbu3OjI1QklGLNg=", + "lastModified": 1678375444, + "narHash": "sha256-XIgHfGvjFvZQ8hrkfocanCDxMefc/77rXeHvYdzBMc8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e1e1b192c1a5aab2960bf0a0bd53a2e8124fa18e", + "rev": "130fa0baaa2b93ec45523fdcde942f6844ee9f6e", "type": "github" }, "original": { @@ -166,6 +214,21 @@ "type": "github" } }, + "nixpkgsV1": { + "locked": { + "lastModified": 1678500271, + "narHash": "sha256-tRBLElf6f02HJGG0ZR7znMNFv/Uf7b2fFInpTHiHaSE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5eb98948b66de29f899c7fe27ae112a47964baf8", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-22.11", + "type": "indirect" + } + }, "parts": { "inputs": { "nixpkgs-lib": [ @@ -174,11 +237,11 @@ ] }, "locked": { - "lastModified": 1675933616, - "narHash": "sha256-/rczJkJHtx16IFxMmAWu5nNYcSXNg1YYXTHoGjLrLUA=", + "lastModified": 1679737941, + "narHash": "sha256-srSD9CwsVPnUMsIZ7Kt/UegkKUEBcTyU1Rev7mO45S0=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "47478a4a003e745402acf63be7f9a092d51b83d7", + "rev": "3502ee99d6dade045bdeaf7b0cd8ec703484c25c", "type": "github" }, "original": { @@ -192,11 +255,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1675933616, - "narHash": "sha256-/rczJkJHtx16IFxMmAWu5nNYcSXNg1YYXTHoGjLrLUA=", + "lastModified": 1679737941, + "narHash": "sha256-srSD9CwsVPnUMsIZ7Kt/UegkKUEBcTyU1Rev7mO45S0=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "47478a4a003e745402acf63be7f9a092d51b83d7", + "rev": "3502ee99d6dade045bdeaf7b0cd8ec703484c25c", "type": "github" }, "original": { @@ -221,11 +284,11 @@ ] }, "locked": { - "lastModified": 1677292251, - "narHash": "sha256-D+6q5Z2MQn3UFJtqsM5/AvVHi3NXKZTIMZt1JGq/spA=", + "lastModified": 1680315536, + "narHash": "sha256-0AsBuKssJMbcRcw4HJQwJsUHhZxR5+gaf6xPQayhR44=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "34cdbf6ad480ce13a6a526f57d8b9e609f3d65dc", + "rev": "5c8c151bdd639074a0051325c16df1a64ee23497", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 2ac764888..6dcaf6cc4 100644 --- a/flake.nix +++ b/flake.nix @@ -123,8 +123,6 @@ then ''$RUSTFLAGS -C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment'' else "$RUSTFLAGS"; in { - # by default NCI adds rust-analyzer component, but helix toolchain doesn't have rust-analyzer - nci.toolchains.shell.components = ["rust-src" "rustfmt" "clippy"]; nci.projects."helix-project".relPath = ""; nci.crates."helix-term" = { overrides = { diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 9dfef9ae2..c10ed735e 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -29,9 +29,10 @@ tree-sitter = "0.20" once_cell = "1.17" arc-swap = "1" regex = "1" -bitflags = "2.0" +bitflags = "2.2" ahash = "0.8.3" hashbrown = { version = "0.13.2", features = ["raw"] } +dunce = "1.0" log = "0.4" serde = { version = "1.0", features = ["derive"] } @@ -44,7 +45,7 @@ encoding_rs = "0.8" chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] } -etcetera = "0.4" +etcetera = "0.7" textwrap = "0.16.0" [dev-dependencies] diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 4d50e48bf..b67e2c8a3 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -36,55 +36,12 @@ pub mod unicode { pub use unicode_width as width; } +pub use helix_loader::find_workspace; + pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option { line.chars().position(|ch| !ch.is_whitespace()) } -/// Find project root. -/// -/// Order of detection: -/// * Top-most folder containing a root marker in current git repository -/// * Git repository root if no marker detected -/// * Top-most folder containing a root marker if not git repository detected -/// * Current working directory as fallback -pub fn find_root(root: Option<&str>, root_markers: &[String]) -> std::path::PathBuf { - let current_dir = std::env::current_dir().expect("unable to determine current directory"); - - let root = match root { - Some(root) => { - let root = std::path::Path::new(root); - if root.is_absolute() { - root.to_path_buf() - } else { - current_dir.join(root) - } - } - None => current_dir.clone(), - }; - - let mut top_marker = None; - for ancestor in root.ancestors() { - if root_markers - .iter() - .any(|marker| ancestor.join(marker).exists()) - { - top_marker = Some(ancestor); - } - - if ancestor.join(".git").exists() { - // Top marker is repo root if not root marker was detected yet - if top_marker.is_none() { - top_marker = Some(ancestor); - } - // Don't go higher than repo if we're in one - break; - } - } - - // Return the found top marker or the current_dir as fallback - top_marker.map_or(current_dir, |a| a.to_path_buf()) -} - pub use ropey::{self, str_utils, Rope, RopeBuilder, RopeSlice}; // pub use tendril::StrTendril as Tendril; diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs index 60af47e5b..b44d149fb 100644 --- a/helix-core/src/movement.rs +++ b/helix-core/src/movement.rs @@ -62,7 +62,7 @@ pub fn move_vertically_visual( annotations: &mut TextAnnotations, ) -> Range { if !text_fmt.soft_wrap { - move_vertically(slice, range, dir, count, behaviour, text_fmt, annotations); + return move_vertically(slice, range, dir, count, behaviour, text_fmt, annotations); } annotations.clear_line_annotations(); let pos = range.cursor(slice); diff --git a/helix-core/src/path.rs b/helix-core/src/path.rs index d59a6baad..efa46c46e 100644 --- a/helix-core/src/path.rs +++ b/helix-core/src/path.rs @@ -40,6 +40,21 @@ pub fn expand_tilde(path: &Path) -> PathBuf { /// needs to improve on. /// Copied from cargo: pub fn get_normalized_path(path: &Path) -> PathBuf { + // normalization strategy is to canonicalize first ancestor path that exists (i.e., canonicalize as much as possible), + // then run handrolled normalization on the non-existent remainder + let (base, path) = path + .ancestors() + .find_map(|base| { + let canonicalized_base = dunce::canonicalize(base).ok()?; + let remainder = path.strip_prefix(base).ok()?.into(); + Some((canonicalized_base, remainder)) + }) + .unwrap_or_else(|| (PathBuf::new(), PathBuf::from(path))); + + if path.as_os_str().is_empty() { + return base; + } + let mut components = path.components().peekable(); let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { components.next(); @@ -63,7 +78,7 @@ pub fn get_normalized_path(path: &Path) -> PathBuf { } } } - ret + base.join(ret) } /// Returns the canonical, absolute form of a path with all intermediate components normalized. @@ -82,13 +97,19 @@ pub fn get_canonicalized_path(path: &Path) -> std::io::Result { } pub fn get_relative_path(path: &Path) -> PathBuf { + let path = PathBuf::from(path); let path = if path.is_absolute() { - let cwdir = std::env::current_dir().expect("couldn't determine current directory"); - path.strip_prefix(cwdir).unwrap_or(path) + let cwdir = std::env::current_dir() + .map(|path| get_normalized_path(&path)) + .expect("couldn't determine current directory"); + get_normalized_path(&path) + .strip_prefix(cwdir) + .map(PathBuf::from) + .unwrap_or(path) } else { path }; - fold_home_dir(path) + fold_home_dir(&path) } /// Returns a truncated filepath where the basepart of the path is reduced to the first diff --git a/helix-core/src/position.rs b/helix-core/src/position.rs index 04bf8c31f..ee764bc64 100644 --- a/helix-core/src/position.rs +++ b/helix-core/src/position.rs @@ -109,7 +109,7 @@ pub fn visual_coords_at_pos(text: RopeSlice, pos: usize, tab_width: usize) -> Po /// softwrapping positions are estimated with an O(1) algorithm /// to ensure consistent performance for large lines (currently unimplemented) /// -/// Usualy you want to use `visual_offset_from_anchor` instead but this function +/// Usually you want to use `visual_offset_from_anchor` instead but this function /// can be useful (and faster) if /// * You already know the visual position of the block /// * You only care about the horizontal offset (column) and not the vertical offset (row) @@ -291,7 +291,7 @@ pub fn pos_at_visual_coords(text: RopeSlice, coords: Position, tab_width: usize) /// /// If no (text) grapheme starts at exactly at the specified column the /// start of the grapheme to the left is returned. If there is no grapheme -/// to the left (for example if the line starts with virtual text) then the positiong +/// to the left (for example if the line starts with virtual text) then the positioning /// of the next grapheme to the right is returned. /// /// If the `line` coordinate is beyond the end of the file, the EOF diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index 8e93c633e..259b131a4 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -38,7 +38,7 @@ use std::borrow::Cow; /// Ranges are considered to be inclusive on the left and /// exclusive on the right, regardless of anchor-head ordering. /// This means, for example, that non-zero-width ranges that -/// are directly adjecent, sharing an edge, do not overlap. +/// are directly adjacent, sharing an edge, do not overlap. /// However, a zero-width range will overlap with the shared /// left-edge of another range. /// diff --git a/helix-core/src/shellwords.rs b/helix-core/src/shellwords.rs index 0883eb917..9d873c366 100644 --- a/helix-core/src/shellwords.rs +++ b/helix-core/src/shellwords.rs @@ -294,14 +294,14 @@ mod test { #[test] fn test_lists() { let input = - r#":set statusline.center ["file-type","file-encoding"] '["list", "in", "qoutes"]'"#; + r#":set statusline.center ["file-type","file-encoding"] '["list", "in", "quotes"]'"#; let shellwords = Shellwords::from(input); let result = shellwords.words().to_vec(); let expected = vec![ Cow::from(":set"), Cow::from("statusline.center"), Cow::from(r#"["file-type","file-encoding"]"#), - Cow::from(r#"["list", "in", "qoutes"]"#), + Cow::from(r#"["list", "in", "quotes"]"#), ]; assert_eq!(expected, result); } diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index e494ee9b1..c34ea81a3 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -20,7 +20,7 @@ use std::{ fmt, hash::{Hash, Hasher}, mem::{replace, transmute}, - path::Path, + path::{Path, PathBuf}, str::FromStr, sync::Arc, }; @@ -127,6 +127,10 @@ pub struct LanguageConfiguration { pub auto_pairs: Option, pub rulers: Option>, // if set, override editor's rulers + + /// Hardcoded LSP root directories relative to the workspace root, like `examples` or `tools/fuzz`. + /// Falling back to the current working directory if none are configured. + pub workspace_lsp_roots: Option>, } #[derive(Debug, PartialEq, Eq, Hash)] @@ -551,6 +555,8 @@ impl LanguageConfiguration { #[serde(default, rename_all = "kebab-case", deny_unknown_fields)] pub struct SoftWrap { /// Soft wrap lines that exceed viewport width. Default to off + // NOTE: Option on purpose because the struct is shared between language config and global config. + // By default the option is None so that the language config falls back to the global config unless explicitly set. pub enable: Option, /// Maximum space left free at the end of the line. /// This space is used to wrap text at word boundaries. If that is not possible within this limit diff --git a/helix-core/src/text_annotations.rs b/helix-core/src/text_annotations.rs index e60931845..11d19d485 100644 --- a/helix-core/src/text_annotations.rs +++ b/helix-core/src/text_annotations.rs @@ -172,7 +172,7 @@ impl TextAnnotations { for char_idx in char_range { if let Some((_, Some(highlight))) = self.overlay_at(char_idx) { // we don't know the number of chars the original grapheme takes - // however it doesn't matter as highlight bounderies are automatically + // however it doesn't matter as highlight boundaries are automatically // aligned to grapheme boundaries in the rendering code highlights.push((highlight.0, char_idx..char_idx + 1)) } @@ -203,7 +203,7 @@ impl TextAnnotations { /// Add new grapheme overlays. /// - /// The overlayed grapheme will be rendered with `highlight` + /// The overlaid grapheme will be rendered with `highlight` /// patched on top of `ui.text`. /// /// The overlays **must be sorted** by their `char_idx`. diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs index ff727d00a..acdfc5b7e 100644 --- a/helix-dap/src/client.rs +++ b/helix-dap/src/client.rs @@ -62,12 +62,10 @@ impl Client { if command.is_empty() { return Result::Err(Error::Other(anyhow!("Command not provided"))); } - if transport == "tcp" && port_arg.is_some() { - Self::tcp_process(command, args, port_arg.unwrap(), id).await - } else if transport == "stdio" { - Self::stdio(command, args, id) - } else { - Result::Err(Error::Other(anyhow!("Incorrect transport {}", transport))) + match (transport, port_arg) { + ("tcp", Some(port_arg)) => Self::tcp_process(command, args, port_arg, id).await, + ("stdio", _) => Self::stdio(command, args, id), + _ => Result::Err(Error::Other(anyhow!("Incorrect transport {}", transport))), } } @@ -512,4 +510,10 @@ impl Client { self.call::(args) } + + pub fn current_stack_frame(&self) -> Option<&StackFrame> { + self.stack_frames + .get(&self.thread_id?)? + .get(self.active_frame?) + } } diff --git a/helix-dap/src/transport.rs b/helix-dap/src/transport.rs index dd03e5685..0f646b6a4 100644 --- a/helix-dap/src/transport.rs +++ b/helix-dap/src/transport.rs @@ -230,38 +230,48 @@ impl Transport { } } - async fn recv( + async fn recv_inner( transport: Arc, mut server_stdout: Box, client_tx: UnboundedSender, - ) { + ) -> Result<()> { let mut recv_buffer = String::new(); loop { - match Self::recv_server_message(&mut server_stdout, &mut recv_buffer).await { - Ok(msg) => { - transport - .process_server_message(&client_tx, msg) - .await - .unwrap(); - } - Err(err) => { - error!("err: <- {:?}", err); - break; - } - } + let msg = Self::recv_server_message(&mut server_stdout, &mut recv_buffer).await?; + transport.process_server_message(&client_tx, msg).await?; } } - async fn send( + async fn recv( + transport: Arc, + server_stdout: Box, + client_tx: UnboundedSender, + ) { + if let Err(err) = Self::recv_inner(transport, server_stdout, client_tx).await { + error!("err: <- {:?}", err); + } + } + + async fn send_inner( transport: Arc, mut server_stdin: Box, mut client_rx: UnboundedReceiver, - ) { + ) -> Result<()> { while let Some(payload) = client_rx.recv().await { transport .send_payload_to_server(&mut server_stdin, payload) - .await - .unwrap() + .await?; + } + Ok(()) + } + + async fn send( + transport: Arc, + server_stdin: Box, + client_rx: UnboundedReceiver, + ) { + if let Err(err) = Self::send_inner(transport, server_stdin, client_rx).await { + error!("err: <- {:?}", err); } } diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index 9225ad1a2..ff8ffb1c8 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -17,7 +17,7 @@ path = "src/main.rs" anyhow = "1" serde = { version = "1.0", features = ["derive"] } toml = "0.7" -etcetera = "0.4" +etcetera = "0.7" tree-sitter = "0.20" once_cell = "1.17" log = "0.4" @@ -27,6 +27,7 @@ log = "0.4" # cloning/compiling tree-sitter grammars cc = { version = "1" } threadpool = { version = "1.0" } +tempfile = "3.5.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -libloading = "0.7" +libloading = "0.8" diff --git a/helix-loader/build.rs b/helix-loader/build.rs index c4b89e6b9..63548a0c8 100644 --- a/helix-loader/build.rs +++ b/helix-loader/build.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::path::Path; use std::process::Command; const VERSION: &str = include_str!("../VERSION"); @@ -11,7 +12,7 @@ fn main() { .filter(|output| output.status.success()) .and_then(|x| String::from_utf8(x.stdout).ok()); - let version: Cow<_> = match git_hash { + let version: Cow<_> = match &git_hash { Some(git_hash) => format!("{} ({})", VERSION, &git_hash[..8]).into(), None => VERSION.into(), }; @@ -23,4 +24,40 @@ fn main() { println!("cargo:rerun-if-changed=../VERSION"); println!("cargo:rustc-env=VERSION_AND_GIT_HASH={}", version); + + if git_hash.is_none() { + return; + } + + // we need to revparse because the git dir could be anywhere if you are + // using detached worktrees but there is no good way to obtain an OsString + // from command output so for now we can't accept non-utf8 paths here + // probably rare enouch where it doesn't matter tough we could use gitoxide + // here but that would be make it a hard dependency and slow compile times + let Some(git_dir): Option = Command::new("git") + .args(["rev-parse", "--git-dir"]) + .output() + .ok() + .filter(|output| output.status.success()) + .and_then(|x| String::from_utf8(x.stdout).ok()) + else{ return; }; + // If heads starts pointing at something else (different branch) + // we need to return + let head = Path::new(&git_dir).join("HEAD"); + if head.exists() { + println!("cargo:rerun-if-changed={}", head.display()); + } + // if the thing head points to (branch) itself changes + // we need to return + let Some(head_ref): Option = Command::new("git") + .args(["symbolic-ref", "HEAD"]) + .output() + .ok() + .filter(|output| output.status.success()) + .and_then(|x| String::from_utf8(x.stdout).ok()) + else{ return; }; + let head_ref = Path::new(&git_dir).join(head_ref); + if head_ref.exists() { + println!("cargo:rerun-if-changed={}", head_ref.display()); + } } diff --git a/helix-loader/src/config.rs b/helix-loader/src/config.rs index 0f329d217..d092d20f7 100644 --- a/helix-loader/src/config.rs +++ b/helix-loader/src/config.rs @@ -9,37 +9,38 @@ pub fn default_lang_config() -> toml::Value { /// User configured languages.toml file, merged with the default config. pub fn user_lang_config() -> Result { - let config = crate::local_config_dirs() - .into_iter() - .chain([crate::config_dir()].into_iter()) - .map(|path| path.join("languages.toml")) - .filter_map(|file| { - std::fs::read_to_string(file) - .map(|config| toml::from_str(&config)) - .ok() - }) - .collect::, _>>()? - .into_iter() - .chain([default_lang_config()].into_iter()) - .fold(toml::Value::Table(toml::value::Table::default()), |a, b| { - // combines for example - // b: - // [[language]] - // name = "toml" - // language-server = { command = "taplo", args = ["lsp", "stdio"] } - // - // a: - // [[language]] - // language-server = { command = "/usr/bin/taplo" } - // - // into: - // [[language]] - // name = "toml" - // language-server = { command = "/usr/bin/taplo" } - // - // thus it overrides the third depth-level of b with values of a if they exist, but otherwise merges their values - crate::merge_toml_values(b, a, 3) - }); + let config = [ + crate::config_dir(), + crate::find_workspace().0.join(".helix"), + ] + .into_iter() + .map(|path| path.join("languages.toml")) + .filter_map(|file| { + std::fs::read_to_string(file) + .map(|config| toml::from_str(&config)) + .ok() + }) + .collect::, _>>()? + .into_iter() + .fold(default_lang_config(), |a, b| { + // combines for example + // b: + // [[language]] + // name = "toml" + // language-server = { command = "taplo", args = ["lsp", "stdio"] } + // + // a: + // [[language]] + // language-server = { command = "/usr/bin/taplo" } + // + // into: + // [[language]] + // name = "toml" + // language-server = { command = "/usr/bin/taplo" } + // + // thus it overrides the third depth-level of b with values of a if they exist, but otherwise merges their values + crate::merge_toml_values(a, b, 3) + }); Ok(config) } diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index a85cb274c..16955187e 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use serde::{Deserialize, Serialize}; use std::fs; use std::time::SystemTime; @@ -8,6 +8,7 @@ use std::{ process::Command, sync::mpsc::channel, }; +use tempfile::TempPath; use tree_sitter::Language; #[cfg(unix)] @@ -97,15 +98,12 @@ pub fn fetch_grammars() -> Result<()> { let mut git_up_to_date = 0; let mut non_git = Vec::new(); - for res in results { + for (grammar_id, res) in results { match res { Ok(FetchStatus::GitUpToDate) => git_up_to_date += 1, - Ok(FetchStatus::GitUpdated { - grammar_id, - revision, - }) => git_updated.push((grammar_id, revision)), - Ok(FetchStatus::NonGit { grammar_id }) => non_git.push(grammar_id), - Err(e) => errors.push(e), + Ok(FetchStatus::GitUpdated { revision }) => git_updated.push((grammar_id, revision)), + Ok(FetchStatus::NonGit) => non_git.push(grammar_id), + Err(e) => errors.push((grammar_id, e)), } } @@ -137,10 +135,10 @@ pub fn fetch_grammars() -> Result<()> { if !errors.is_empty() { let len = errors.len(); - println!("{} grammars failed to fetch", len); - for (i, error) in errors.into_iter().enumerate() { - println!("\tFailure {}/{}: {}", i + 1, len, error); + for (i, (grammar, error)) in errors.into_iter().enumerate() { + println!("Failure {}/{len}: {grammar} {error}", i + 1); } + bail!("{len} grammars failed to fetch"); } Ok(()) @@ -157,11 +155,11 @@ pub fn build_grammars(target: Option) -> Result<()> { let mut already_built = 0; let mut built = Vec::new(); - for res in results { + for (grammar_id, res) in results { match res { Ok(BuildStatus::AlreadyBuilt) => already_built += 1, - Ok(BuildStatus::Built { grammar_id }) => built.push(grammar_id), - Err(e) => errors.push(e), + Ok(BuildStatus::Built) => built.push(grammar_id), + Err(e) => errors.push((grammar_id, e)), } } @@ -178,10 +176,10 @@ pub fn build_grammars(target: Option) -> Result<()> { if !errors.is_empty() { let len = errors.len(); - println!("{} grammars failed to build", len); - for (i, error) in errors.into_iter().enumerate() { - println!("\tFailure {}/{}: {}", i, len, error); + for (i, (grammar_id, error)) in errors.into_iter().enumerate() { + println!("Failure {}/{len}: {grammar_id} {error}", i + 1); } + bail!("{len} grammars failed to build"); } Ok(()) @@ -213,7 +211,7 @@ fn get_grammar_configs() -> Result> { Ok(grammars) } -fn run_parallel(grammars: Vec, job: F) -> Vec> +fn run_parallel(grammars: Vec, job: F) -> Vec<(String, Result)> where F: Fn(GrammarConfiguration) -> Result + Send + 'static + Clone, Res: Send + 'static, @@ -228,7 +226,7 @@ where pool.execute(move || { // Ignore any SendErrors, if any job in another thread has encountered an // error the Receiver will be closed causing this send to fail. - let _ = tx.send(job(grammar)); + let _ = tx.send((grammar.grammar_id.clone(), job(grammar))); }); } @@ -239,13 +237,8 @@ where enum FetchStatus { GitUpToDate, - GitUpdated { - grammar_id: String, - revision: String, - }, - NonGit { - grammar_id: String, - }, + GitUpdated { revision: String }, + NonGit, } fn fetch_grammar(grammar: GrammarConfiguration) -> Result { @@ -286,17 +279,12 @@ fn fetch_grammar(grammar: GrammarConfiguration) -> Result { )?; git(&grammar_dir, ["checkout", &revision])?; - Ok(FetchStatus::GitUpdated { - grammar_id: grammar.grammar_id, - revision, - }) + Ok(FetchStatus::GitUpdated { revision }) } else { Ok(FetchStatus::GitUpToDate) } } else { - Ok(FetchStatus::NonGit { - grammar_id: grammar.grammar_id, - }) + Ok(FetchStatus::NonGit) } } @@ -346,7 +334,7 @@ where enum BuildStatus { AlreadyBuilt, - Built { grammar_id: String }, + Built, } fn build_grammar(grammar: GrammarConfiguration, target: Option<&str>) -> Result { @@ -413,6 +401,18 @@ fn build_tree_sitter_library( let mut library_path = parser_lib_path.join(&grammar.grammar_id); library_path.set_extension(DYLIB_EXTENSION); + // if we are running inside a buildscript emit cargo metadata + // to detect if we are running from a buildscript check some env variables + // that cargo only sets for build scripts + if std::env::var("OUT_DIR").is_ok() && std::env::var("CARGO").is_ok() { + if let Some(scanner_path) = scanner_path.as_ref().and_then(|path| path.to_str()) { + println!("cargo:rerun-if-changed={scanner_path}"); + } + if let Some(parser_path) = parser_path.to_str() { + println!("cargo:rerun-if-changed={parser_path}"); + } + } + let recompile = needs_recompile(&library_path, &parser_path, &scanner_path) .context("Failed to compare source and binary timestamps")?; @@ -433,16 +433,53 @@ fn build_tree_sitter_library( for (key, value) in compiler.env() { command.env(key, value); } + command.args(compiler.args()); + // used to delay dropping the temporary object file until after the compilation is complete + let _path_guard; - if cfg!(all(windows, target_env = "msvc")) { + if compiler.is_like_msvc() { command .args(["/nologo", "/LD", "/I"]) .arg(header_path) .arg("/Od") - .arg("/utf-8"); + .arg("/utf-8") + .arg("/std:c11"); if let Some(scanner_path) = scanner_path.as_ref() { - command.arg(scanner_path); + if scanner_path.extension() == Some("c".as_ref()) { + command.arg(scanner_path); + } else { + let mut cpp_command = Command::new(compiler.path()); + cpp_command.current_dir(src_path); + for (key, value) in compiler.env() { + cpp_command.env(key, value); + } + cpp_command.args(compiler.args()); + let object_file = + library_path.with_file_name(format!("{}_scanner.obj", &grammar.grammar_id)); + cpp_command + .args(["/nologo", "/LD", "/I"]) + .arg(header_path) + .arg("/Od") + .arg("/utf-8") + .arg("/std:c++14") + .arg(format!("/Fo{}", object_file.display())) + .arg("/c") + .arg(scanner_path); + let output = cpp_command + .output() + .context("Failed to execute C++ compiler")?; + + if !output.status.success() { + return Err(anyhow!( + "Parser compilation failed.\nStdout: {}\nStderr: {}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + )); + } + command.arg(&object_file); + _path_guard = TempPath::from_path(object_file); + } } command @@ -454,20 +491,49 @@ fn build_tree_sitter_library( .arg("-shared") .arg("-fPIC") .arg("-fno-exceptions") - .arg("-g") .arg("-I") .arg(header_path) .arg("-o") - .arg(&library_path) - .arg("-O3"); + .arg(&library_path); + if let Some(scanner_path) = scanner_path.as_ref() { if scanner_path.extension() == Some("c".as_ref()) { - command.arg("-xc").arg("-std=c99").arg(scanner_path); + command.arg("-xc").arg("-std=c11").arg(scanner_path); } else { - command.arg(scanner_path); + let mut cpp_command = Command::new(compiler.path()); + cpp_command.current_dir(src_path); + for (key, value) in compiler.env() { + cpp_command.env(key, value); + } + cpp_command.args(compiler.args()); + let object_file = + library_path.with_file_name(format!("{}_scanner.o", &grammar.grammar_id)); + cpp_command + .arg("-fPIC") + .arg("-fno-exceptions") + .arg("-I") + .arg(header_path) + .arg("-o") + .arg(&object_file) + .arg("-std=c++14") + .arg("-c") + .arg(scanner_path); + let output = cpp_command + .output() + .context("Failed to execute C++ compiler")?; + if !output.status.success() { + return Err(anyhow!( + "Parser compilation failed.\nStdout: {}\nStderr: {}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + )); + } + + command.arg(&object_file); + _path_guard = TempPath::from_path(object_file); } } - command.arg("-xc").arg(parser_path); + command.arg("-xc").arg("-std=c11").arg(parser_path); if cfg!(all( unix, not(any(target_os = "macos", target_os = "illumos")) @@ -487,9 +553,7 @@ fn build_tree_sitter_library( )); } - Ok(BuildStatus::Built { - grammar_id: grammar.grammar_id, - }) + Ok(BuildStatus::Built) } fn needs_recompile( diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index 04b44b5aa..6c7169758 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -42,7 +42,7 @@ fn prioritize_runtime_dirs() -> Vec { let mut rt_dirs = Vec::new(); if let Ok(dir) = std::env::var("CARGO_MANIFEST_DIR") { // this is the directory of the crate being run by cargo, we need the workspace path so we take the parent - let path = std::path::PathBuf::from(dir).parent().unwrap().join(RT_DIR); + let path = PathBuf::from(dir).parent().unwrap().join(RT_DIR); log::debug!("runtime dir: {}", path.to_string_lossy()); rt_dirs.push(path); } @@ -113,15 +113,6 @@ pub fn config_dir() -> PathBuf { path } -pub fn local_config_dirs() -> Vec { - let directories = find_local_config_dirs() - .into_iter() - .map(|path| path.join(".helix")) - .collect(); - log::debug!("Located configuration folders: {:?}", directories); - directories -} - pub fn cache_dir() -> PathBuf { // TODO: allow env var override let strategy = choose_base_strategy().expect("Unable to find the config directory!"); @@ -137,6 +128,10 @@ pub fn config_file() -> PathBuf { .unwrap_or_else(|| config_dir().join("config.toml")) } +pub fn workspace_config_file() -> PathBuf { + find_workspace().0.join(".helix").join("config.toml") +} + pub fn lang_config_file() -> PathBuf { config_dir().join("languages.toml") } @@ -145,22 +140,6 @@ pub fn log_file() -> PathBuf { cache_dir().join("helix.log") } -pub fn find_local_config_dirs() -> Vec { - let current_dir = std::env::current_dir().expect("unable to determine current directory"); - let mut directories = Vec::new(); - - for ancestor in current_dir.ancestors() { - if ancestor.join(".git").exists() { - directories.push(ancestor.to_path_buf()); - // Don't go higher than repo if we're in one - break; - } else if ancestor.join(".helix").is_dir() { - directories.push(ancestor.to_path_buf()); - } - } - directories -} - /// Merge two TOML documents, merging values from `right` onto `left` /// /// When an array exists in both `left` and `right`, `right`'s array is @@ -302,3 +281,21 @@ mod merge_toml_tests { ) } } + +/// Finds the current workspace folder. +/// Used as a ceiling dir for LSP root resolution, the filepicker and potentially as a future filewatching root +/// +/// This function starts searching the FS upward from the CWD +/// and returns the first directory that contains either `.git` or `.helix`. +/// If no workspace was found returns (CWD, true). +/// Otherwise (workspace, false) is returned +pub fn find_workspace() -> (PathBuf, bool) { + let current_dir = std::env::current_dir().expect("unable to determine current directory"); + for ancestor in current_dir.ancestors() { + if ancestor.join(".git").exists() || ancestor.join(".helix").exists() { + return (ancestor.to_owned(), false); + } + } + + (current_dir, true) +} diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index 33ec5f309..f85265152 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -27,3 +27,4 @@ thiserror = "1.0" tokio = { version = "1.27", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } tokio-stream = "0.1.12" which = "4.4" +parking_lot = "0.12.1" diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index f93e58263..93e822c44 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -1,22 +1,26 @@ use crate::{ - jsonrpc, + find_lsp_workspace, jsonrpc, transport::{Payload, Transport}, Call, Error, OffsetEncoding, Result, }; -use helix_core::{find_root, ChangeSet, Rope}; +use helix_core::{find_workspace, path, ChangeSet, Rope}; use helix_loader::{self, VERSION_AND_GIT_HASH}; -use lsp::PositionEncodingKind; +use lsp::{ + notification::DidChangeWorkspaceFolders, DidChangeWorkspaceFoldersParams, OneOf, + PositionEncodingKind, WorkspaceFolder, WorkspaceFoldersChangeEvent, +}; use lsp_types as lsp; +use parking_lot::Mutex; use serde::Deserialize; use serde_json::Value; -use std::collections::HashMap; use std::future::Future; use std::process::Stdio; use std::sync::{ atomic::{AtomicU64, Ordering}, Arc, }; +use std::{collections::HashMap, path::PathBuf}; use tokio::{ io::{BufReader, BufWriter}, process::{Child, Command}, @@ -26,6 +30,17 @@ use tokio::{ }, }; +fn workspace_for_uri(uri: lsp::Url) -> WorkspaceFolder { + lsp::WorkspaceFolder { + name: uri + .path_segments() + .and_then(|segments| segments.last()) + .map(|basename| basename.to_string()) + .unwrap_or_default(), + uri, + } +} + #[derive(Debug)] pub struct Client { id: usize, @@ -36,11 +51,121 @@ pub struct Client { config: Option, root_path: std::path::PathBuf, root_uri: Option, - workspace_folders: Vec, + workspace_folders: Mutex>, + initialize_notify: Arc, + /// workspace folders added while the server is still initializing req_timeout: u64, } impl Client { + pub fn try_add_doc( + self: &Arc, + root_markers: &[String], + manual_roots: &[PathBuf], + doc_path: Option<&std::path::PathBuf>, + may_support_workspace: bool, + ) -> bool { + let (workspace, workspace_is_cwd) = find_workspace(); + let workspace = path::get_normalized_path(&workspace); + let root = find_lsp_workspace( + doc_path + .and_then(|x| x.parent().and_then(|x| x.to_str())) + .unwrap_or("."), + root_markers, + manual_roots, + &workspace, + workspace_is_cwd, + ); + let root_uri = root + .as_ref() + .and_then(|root| lsp::Url::from_file_path(root).ok()); + + if self.root_path == root.unwrap_or(workspace) + || root_uri.as_ref().map_or(false, |root_uri| { + self.workspace_folders + .lock() + .iter() + .any(|workspace| &workspace.uri == root_uri) + }) + { + // workspace URI is already registered so we can use this client + return true; + } + + // this server definitely doesn't support multiple workspace, no need to check capabilities + if !may_support_workspace { + return false; + } + + let Some(capabilities) = self.capabilities.get() else { + let client = Arc::clone(self); + // initialization hasn't finished yet, deal with this new root later + // TODO: In the edgecase that a **new root** is added + // for an LSP that **doesn't support workspace_folders** before initaliation is finished + // the new roots are ignored. + // That particular edgecase would require retroactively spawning new LSP + // clients and therefore also require us to retroactively update the corresponding + // documents LSP client handle. It's doable but a pretty weird edgecase so let's + // wait and see if anyone ever runs into it. + tokio::spawn(async move { + client.initialize_notify.notified().await; + if let Some(workspace_folders_caps) = client + .capabilities() + .workspace + .as_ref() + .and_then(|cap| cap.workspace_folders.as_ref()) + .filter(|cap| cap.supported.unwrap_or(false)) + { + client.add_workspace_folder( + root_uri, + &workspace_folders_caps.change_notifications, + ); + } + }); + return true; + }; + + if let Some(workspace_folders_caps) = capabilities + .workspace + .as_ref() + .and_then(|cap| cap.workspace_folders.as_ref()) + .filter(|cap| cap.supported.unwrap_or(false)) + { + self.add_workspace_folder(root_uri, &workspace_folders_caps.change_notifications); + true + } else { + // the server doesn't support multi workspaces, we need a new client + false + } + } + + fn add_workspace_folder( + &self, + root_uri: Option, + change_notifications: &Option>, + ) { + // root_uri is None just means that there isn't really any LSP workspace + // associated with this file. For servers that support multiple workspaces + // there is just one server so we can always just use that shared instance. + // No need to add a new workspace root here as there is no logical root for this file + // let the server deal with this + let Some(root_uri) = root_uri else { + return; + }; + + // server supports workspace folders, let's add the new root to the list + self.workspace_folders + .lock() + .push(workspace_for_uri(root_uri.clone())); + if &Some(OneOf::Left(false)) == change_notifications { + // server specifically opted out of DidWorkspaceChange notifications + // let's assume the server will request the workspace folders itself + // and that we can therefore reuse the client (but are done now) + return; + } + tokio::spawn(self.did_change_workspace(vec![workspace_for_uri(root_uri)], Vec::new())); + } + #[allow(clippy::type_complexity)] #[allow(clippy::too_many_arguments)] pub fn start( @@ -49,6 +174,7 @@ impl Client { config: Option, server_environment: HashMap, root_markers: &[String], + manual_roots: &[PathBuf], id: usize, req_timeout: u64, doc_path: Option<&std::path::PathBuf>, @@ -75,27 +201,26 @@ impl Client { let (server_rx, server_tx, initialize_notify) = Transport::start(reader, writer, stderr, id); - - let root_path = find_root( - doc_path.and_then(|x| x.parent().and_then(|x| x.to_str())), + let (workspace, workspace_is_cwd) = find_workspace(); + let workspace = path::get_normalized_path(&workspace); + let root = find_lsp_workspace( + doc_path + .and_then(|x| x.parent().and_then(|x| x.to_str())) + .unwrap_or("."), root_markers, + manual_roots, + &workspace, + workspace_is_cwd, ); - let root_uri = lsp::Url::from_file_path(root_path.clone()).ok(); + // `root_uri` and `workspace_folder` can be empty in case there is no workspace + // `root_url` can not, use `workspace` as a fallback + let root_path = root.clone().unwrap_or_else(|| workspace.clone()); + let root_uri = root.and_then(|root| lsp::Url::from_file_path(root).ok()); - // TODO: support multiple workspace folders let workspace_folders = root_uri .clone() - .map(|root| { - vec![lsp::WorkspaceFolder { - name: root - .path_segments() - .and_then(|segments| segments.last()) - .map(|basename| basename.to_string()) - .unwrap_or_default(), - uri: root, - }] - }) + .map(|root| vec![workspace_for_uri(root)]) .unwrap_or_default(); let client = Self { @@ -106,10 +231,10 @@ impl Client { capabilities: OnceCell::new(), config, req_timeout, - root_path, root_uri, - workspace_folders, + workspace_folders: Mutex::new(workspace_folders), + initialize_notify: initialize_notify.clone(), }; Ok((client, server_rx, initialize_notify)) @@ -154,7 +279,7 @@ impl Client { "utf-16" => Some(OffsetEncoding::Utf16), "utf-32" => Some(OffsetEncoding::Utf32), encoding => { - log::error!("Server provided invalid position encording {encoding}, defaulting to utf-16"); + log::error!("Server provided invalid position encoding {encoding}, defaulting to utf-16"); None }, }) @@ -165,8 +290,10 @@ impl Client { self.config.as_ref() } - pub fn workspace_folders(&self) -> &[lsp::WorkspaceFolder] { - &self.workspace_folders + pub async fn workspace_folders( + &self, + ) -> parking_lot::MutexGuard<'_, Vec> { + self.workspace_folders.lock() } /// Execute a RPC request on the language server. @@ -286,7 +413,7 @@ impl Client { // General messages // ------------------------------------------------------------------------------------------- - pub(crate) async fn initialize(&self) -> Result { + pub(crate) async fn initialize(&self, enable_snippets: bool) -> Result { if let Some(config) = &self.config { log::info!("Using custom LSP config: {}", config); } @@ -294,7 +421,7 @@ impl Client { #[allow(deprecated)] let params = lsp::InitializeParams { process_id: Some(std::process::id()), - workspace_folders: Some(self.workspace_folders.clone()), + workspace_folders: Some(self.workspace_folders.lock().clone()), // root_path is obsolete, but some clients like pyright still use it so we specify both. // clients will prefer _uri if possible root_path: self.root_path.to_str().map(|path| path.to_owned()), @@ -334,7 +461,7 @@ impl Client { text_document: Some(lsp::TextDocumentClientCapabilities { completion: Some(lsp::CompletionClientCapabilities { completion_item: Some(lsp::CompletionItemCapability { - snippet_support: Some(true), + snippet_support: Some(enable_snippets), resolve_support: Some(lsp::CompletionItemCapabilityResolveSupport { properties: vec![ String::from("documentation"), @@ -413,8 +540,8 @@ impl Client { }), general: Some(lsp::GeneralClientCapabilities { position_encodings: Some(vec![ - PositionEncodingKind::UTF32, PositionEncodingKind::UTF8, + PositionEncodingKind::UTF32, PositionEncodingKind::UTF16, ]), ..Default::default() @@ -465,6 +592,16 @@ impl Client { ) } + pub fn did_change_workspace( + &self, + added: Vec, + removed: Vec, + ) -> impl Future> { + self.notify::(DidChangeWorkspaceFoldersParams { + event: WorkspaceFoldersChangeEvent { added, removed }, + }) + } + // ------------------------------------------------------------------------------------------- // Text document // ------------------------------------------------------------------------------------------- diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 5609a624f..31ee1d75c 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -10,11 +10,15 @@ pub use lsp::{Position, Url}; pub use lsp_types as lsp; use futures_util::stream::select_all::SelectAll; -use helix_core::syntax::{LanguageConfiguration, LanguageServerConfiguration}; +use helix_core::{ + path, + syntax::{LanguageConfiguration, LanguageServerConfiguration}, +}; use tokio::sync::mpsc::UnboundedReceiver; use std::{ collections::{hash_map::Entry, HashMap}, + path::{Path, PathBuf}, sync::{ atomic::{AtomicUsize, Ordering}, Arc, @@ -128,7 +132,11 @@ pub mod util { ) -> Option { let pos_line = pos.line as usize; if pos_line > doc.len_lines() - 1 { - return None; + // If it extends past the end, truncate it to the end. This is because the + // way the LSP describes the range including the last newline is by + // specifying a line number after what we would call the last line. + log::warn!("LSP position {pos:?} out of range assuming EOF"); + return Some(doc.len_chars()); } // We need to be careful here to fully comply ith the LSP spec. @@ -144,10 +152,10 @@ pub mod util { // > ‘\n’, ‘\r\n’ and ‘\r’. Positions are line end character agnostic. // > So you can not specify a position that denotes \r|\n or \n| where | represents the character offset. // - // This means that while the line must be in bounds the `charater` + // This means that while the line must be in bounds the `character` // must be capped to the end of the line. // Note that the end of the line here is **before** the line terminator - // so we must use `line_end_char_index` istead of `doc.line_to_char(pos_line + 1)` + // so we must use `line_end_char_index` instead of `doc.line_to_char(pos_line + 1)` // // FIXME: Helix does not fully comply with the LSP spec for line terminators. // The LSP standard requires that line terminators are ['\n', '\r\n', '\r']. @@ -238,9 +246,20 @@ pub mod util { pub fn lsp_range_to_range( doc: &Rope, - range: lsp::Range, + mut range: lsp::Range, offset_encoding: OffsetEncoding, ) -> Option { + // This is sort of an edgecase. It's not clear from the spec how to deal with + // ranges where end < start. They don't make much sense but vscode simply caps start to end + // and because it's not specified quite a few LS rely on this as a result (for example the TS server) + if range.start > range.end { + log::error!( + "Invalid LSP range start {:?} > end {:?}, using an empty range at the end instead", + range.start, + range.end + ); + range.start = range.end; + } let start = lsp_pos_to_pos(doc, range.start, offset_encoding)?; let end = lsp_pos_to_pos(doc, range.end, offset_encoding)?; @@ -605,7 +624,7 @@ impl Notification { #[derive(Debug)] pub struct Registry { - inner: HashMap)>, + inner: HashMap)>>, counter: AtomicUsize, pub incoming: SelectAll>, @@ -629,18 +648,24 @@ impl Registry { pub fn get_by_id(&self, id: usize) -> Option<&Client> { self.inner .values() + .flatten() .find(|(client_id, _)| client_id == &id) .map(|(_, client)| client.as_ref()) } pub fn remove_by_id(&mut self, id: usize) { - self.inner.retain(|_, (client_id, _)| client_id != &id) + self.inner.retain(|_, clients| { + clients.retain(|&(client_id, _)| client_id != id); + !clients.is_empty() + }) } pub fn restart( &mut self, language_config: &LanguageConfiguration, doc_path: Option<&std::path::PathBuf>, + root_dirs: &[PathBuf], + enable_snippets: bool, ) -> Result>> { let config = match &language_config.language_server { Some(config) => config, @@ -655,15 +680,23 @@ impl Registry { // initialize a new client let id = self.counter.fetch_add(1, Ordering::Relaxed); - let NewClientResult(client, incoming) = - start_client(id, language_config, config, doc_path)?; + let NewClientResult(client, incoming) = start_client( + id, + language_config, + config, + doc_path, + root_dirs, + enable_snippets, + )?; self.incoming.push(UnboundedReceiverStream::new(incoming)); - let (_, old_client) = entry.insert((id, client.clone())); + let old_clients = entry.insert(vec![(id, client.clone())]); - tokio::spawn(async move { - let _ = old_client.force_shutdown().await; - }); + for (_, old_client) in old_clients { + tokio::spawn(async move { + let _ = old_client.force_shutdown().await; + }); + } Ok(Some(client)) } @@ -673,10 +706,12 @@ impl Registry { pub fn stop(&mut self, language_config: &LanguageConfiguration) { let scope = language_config.scope.clone(); - if let Some((_, client)) = self.inner.remove(&scope) { - tokio::spawn(async move { - let _ = client.force_shutdown().await; - }); + if let Some(clients) = self.inner.remove(&scope) { + for (_, client) in clients { + tokio::spawn(async move { + let _ = client.force_shutdown().await; + }); + } } } @@ -684,30 +719,39 @@ impl Registry { &mut self, language_config: &LanguageConfiguration, doc_path: Option<&std::path::PathBuf>, + root_dirs: &[PathBuf], + enable_snippets: bool, ) -> Result>> { let config = match &language_config.language_server { Some(config) => config, None => return Ok(None), }; - match self.inner.entry(language_config.scope.clone()) { - Entry::Occupied(entry) => Ok(Some(entry.get().1.clone())), - Entry::Vacant(entry) => { - // initialize a new client - let id = self.counter.fetch_add(1, Ordering::Relaxed); - - let NewClientResult(client, incoming) = - start_client(id, language_config, config, doc_path)?; - self.incoming.push(UnboundedReceiverStream::new(incoming)); - - entry.insert((id, client.clone())); - Ok(Some(client)) - } + let clients = self.inner.entry(language_config.scope.clone()).or_default(); + // check if we already have a client for this documents root that we can reuse + if let Some((_, client)) = clients.iter_mut().enumerate().find(|(i, (_, client))| { + client.try_add_doc(&language_config.roots, root_dirs, doc_path, *i == 0) + }) { + return Ok(Some(client.1.clone())); } + // initialize a new client + let id = self.counter.fetch_add(1, Ordering::Relaxed); + + let NewClientResult(client, incoming) = start_client( + id, + language_config, + config, + doc_path, + root_dirs, + enable_snippets, + )?; + clients.push((id, client.clone())); + self.incoming.push(UnboundedReceiverStream::new(incoming)); + Ok(Some(client)) } pub fn iter_clients(&self) -> impl Iterator> { - self.inner.values().map(|(_, client)| client) + self.inner.values().flatten().map(|(_, client)| client) } } @@ -798,6 +842,8 @@ fn start_client( config: &LanguageConfiguration, ls_config: &LanguageServerConfiguration, doc_path: Option<&std::path::PathBuf>, + root_dirs: &[PathBuf], + enable_snippets: bool, ) -> Result { let (client, incoming, initialize_notify) = Client::start( &ls_config.command, @@ -805,6 +851,7 @@ fn start_client( config.config.clone(), ls_config.environment.clone(), &config.roots, + config.workspace_lsp_roots.as_deref().unwrap_or(root_dirs), id, ls_config.timeout, doc_path, @@ -820,7 +867,7 @@ fn start_client( .capabilities .get_or_try_init(|| { _client - .initialize() + .initialize(enable_snippets) .map_ok(|response| response.capabilities) }) .await; @@ -842,6 +889,65 @@ fn start_client( Ok(NewClientResult(client, incoming)) } +/// Find an LSP workspace of a file using the following mechanism: +/// * if the file is outside `workspace` return `None` +/// * start at `file` and search the file tree upward +/// * stop the search at the first `root_dirs` entry that contains `file` +/// * if no `root_dirs` matches `file` stop at workspace +/// * Returns the top most directory that contains a `root_marker` +/// * If no root marker and we stopped at a `root_dirs` entry, return the directory we stopped at +/// * If we stopped at `workspace` instead and `workspace_is_cwd == false` return `None` +/// * If we stopped at `workspace` instead and `workspace_is_cwd == true` return `workspace` +pub fn find_lsp_workspace( + file: &str, + root_markers: &[String], + root_dirs: &[PathBuf], + workspace: &Path, + workspace_is_cwd: bool, +) -> Option { + let file = std::path::Path::new(file); + let mut file = if file.is_absolute() { + file.to_path_buf() + } else { + let current_dir = std::env::current_dir().expect("unable to determine current directory"); + current_dir.join(file) + }; + file = path::get_normalized_path(&file); + + if !file.starts_with(workspace) { + return None; + } + + let mut top_marker = None; + for ancestor in file.ancestors() { + if root_markers + .iter() + .any(|marker| ancestor.join(marker).exists()) + { + top_marker = Some(ancestor); + } + + if root_dirs + .iter() + .any(|root_dir| path::get_normalized_path(&workspace.join(root_dir)) == ancestor) + { + // if the worskapce is the cwd do not search any higher for workspaces + // but specify + return Some(top_marker.unwrap_or(workspace).to_owned()); + } + if ancestor == workspace { + // if the workspace is the CWD, let the LSP decide what the workspace + // is + return top_marker + .or_else(|| (!workspace_is_cwd).then_some(workspace)) + .map(Path::to_owned); + } + } + + debug_assert!(false, "workspace must be an ancestor of "); + None +} + #[cfg(test)] mod tests { use super::{lsp, util::*, OffsetEncoding}; @@ -860,16 +966,16 @@ mod tests { test_case!("", (0, 0) => Some(0)); test_case!("", (0, 1) => Some(0)); - test_case!("", (1, 0) => None); + test_case!("", (1, 0) => Some(0)); test_case!("\n\n", (0, 0) => Some(0)); test_case!("\n\n", (1, 0) => Some(1)); test_case!("\n\n", (1, 1) => Some(1)); test_case!("\n\n", (2, 0) => Some(2)); - test_case!("\n\n", (3, 0) => None); + test_case!("\n\n", (3, 0) => Some(2)); test_case!("test\n\n\n\ncase", (4, 3) => Some(11)); test_case!("test\n\n\n\ncase", (4, 4) => Some(12)); test_case!("test\n\n\n\ncase", (4, 5) => Some(12)); - test_case!("", (u32::MAX, u32::MAX) => None); + test_case!("", (u32::MAX, u32::MAX) => Some(0)); } #[test] diff --git a/helix-lsp/src/snippet.rs b/helix-lsp/src/snippet.rs index a4f049e83..ebf3da240 100644 --- a/helix-lsp/src/snippet.rs +++ b/helix-lsp/src/snippet.rs @@ -61,7 +61,7 @@ fn render_elements( offset: &mut usize, tabstops: &mut Vec<(usize, (usize, usize))>, newline_with_offset: &str, - include_placeholer: bool, + include_placeholder: bool, ) { use SnippetElement::*; @@ -89,7 +89,7 @@ fn render_elements( offset, tabstops, newline_with_offset, - include_placeholer, + include_placeholder, ); } &Tabstop { tabstop } => { @@ -100,14 +100,14 @@ fn render_elements( value: inner_snippet_elements, } => { let start_offset = *offset; - if include_placeholer { + if include_placeholder { render_elements( inner_snippet_elements, insert, offset, tabstops, newline_with_offset, - include_placeholer, + include_placeholder, ); } tabstops.push((*tabstop, (start_offset, *offset))); @@ -127,7 +127,7 @@ fn render_elements( pub fn render( snippet: &Snippet<'_>, newline_with_offset: &str, - include_placeholer: bool, + include_placeholder: bool, ) -> (Tendril, Vec>) { let mut insert = Tendril::new(); let mut tabstops = Vec::new(); @@ -139,7 +139,7 @@ pub fn render( &mut offset, &mut tabstops, newline_with_offset, - include_placeholer, + include_placeholder, ); // sort in ascending order (except for 0, which should always be the last one (per lsp doc)) diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 5222ddaa1..7fb6b890a 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -68,7 +68,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.140" +libc = "0.2.142" [build-dependencies] helix-loader = { version = "0.6", path = "../helix-loader" } diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 95faa01b0..b54d6835a 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -25,7 +25,7 @@ use crate::{ config::Config, job::Jobs, keymap::Keymaps, - ui::{self, overlay::overlayed}, + ui::{self, overlay::overlaid}, }; use log::{debug, error, warn}; @@ -169,7 +169,7 @@ impl Application { std::env::set_current_dir(first).context("set current dir")?; editor.new_file(Action::VerticalSplit); let picker = ui::file_picker(".".into(), &config.load().editor); - compositor.push(Box::new(overlayed(picker))); + compositor.push(Box::new(overlaid(picker))); } else { let nr_of_files = args.files.len(); for (i, (file, pos)) in args.files.into_iter().enumerate() { @@ -361,6 +361,9 @@ impl Application { ConfigEvent::Update(editor_config) => { let mut app_config = (*self.config.load().clone()).clone(); app_config.editor = *editor_config; + if let Err(err) = self.terminal.reconfigure(app_config.editor.clone().into()) { + self.editor.set_error(err.to_string()); + }; self.config.store(Arc::new(app_config)); } } @@ -393,20 +396,23 @@ impl Application { /// Refresh theme after config change fn refresh_theme(&mut self, config: &Config) -> Result<(), Error> { - if let Some(theme) = config.theme.clone() { - let true_color = self.true_color(); - let theme = self - .theme_loader - .load(&theme) - .map_err(|err| anyhow::anyhow!("Failed to load theme `{}`: {}", theme, err))?; - - if true_color || theme.is_16_color() { - self.editor.set_theme(theme); - } else { - anyhow::bail!("theme requires truecolor support, which is not available") - } - } + let true_color = config.editor.true_color || crate::true_color(); + let theme = config + .theme + .as_ref() + .and_then(|theme| { + self.theme_loader + .load(theme) + .map_err(|e| { + log::warn!("failed to load theme `{}` - {}", theme, e); + e + }) + .ok() + .filter(|theme| (true_color || theme.is_16_color())) + }) + .unwrap_or_else(|| self.theme_loader.default_theme(true_color)); + self.editor.set_theme(theme); Ok(()) } @@ -416,6 +422,8 @@ impl Application { .map_err(|err| anyhow::anyhow!("Failed to load config: {}", err))?; self.refresh_language_config()?; self.refresh_theme(&default_config)?; + self.terminal + .reconfigure(default_config.editor.clone().into())?; // Store new config self.config.store(Arc::new(default_config)); Ok(()) @@ -431,10 +439,6 @@ impl Application { } } - fn true_color(&self) -> bool { - self.config.load().editor.true_color || crate::true_color() - } - #[cfg(windows)] // no signal handling available on windows pub async fn handle_signals(&mut self, _signal: ()) {} @@ -472,7 +476,17 @@ impl Application { } } signal::SIGCONT => { - self.claim_term().await.unwrap(); + // Copy/Paste from same issue from neovim: + // https://github.com/neovim/neovim/issues/12322 + // https://github.com/neovim/neovim/pull/13084 + for retries in 1..=10 { + match self.claim_term().await { + Ok(()) => break, + Err(err) if retries == 10 => panic!("Failed to claim terminal: {}", err), + Err(_) => continue, + } + } + // redraw the terminal let area = self.terminal.size().expect("couldn't get terminal size"); self.compositor.resize(area); @@ -1018,7 +1032,7 @@ impl Application { let language_server = self.editor.language_servers.get_by_id(server_id).unwrap(); - Ok(json!(language_server.workspace_folders())) + Ok(json!(&*language_server.workspace_folders().await)) } Ok(MethodCall::WorkspaceConfiguration(params)) => { let result: Vec<_> = params @@ -1034,8 +1048,7 @@ impl Application { None => self .editor .language_servers - .get_by_id(server_id) - .unwrap() + .get_by_id(server_id)? .config()?, }; if let Some(section) = item.section.as_ref() { diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 98c530854..b91d95d29 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -12,7 +12,7 @@ pub use typed::*; use helix_core::{ char_idx_at_visual_offset, comment, doc_formatter::TextFormat, - encoding, find_first_non_whitespace_char, find_root, graphemes, + encoding, find_first_non_whitespace_char, find_workspace, graphemes, history::UndoKind, increment, indent, indent::IndentStyle, @@ -54,8 +54,8 @@ use crate::{ job::Callback, keymap::ReverseKeymap, ui::{ - self, editor::InsertEvent, overlay::overlayed, FilePicker, Picker, Popup, Prompt, - PromptEvent, + self, editor::InsertEvent, lsp::SignatureHelp, overlay::overlaid, FilePicker, Picker, + Popup, Prompt, PromptEvent, }, }; @@ -347,6 +347,7 @@ impl MappableCommand { goto_first_nonwhitespace, "Goto first non-blank in line", trim_selections, "Trim whitespace from selections", extend_to_line_start, "Extend to line start", + extend_to_first_nonwhitespace, "Extend to first non-blank in line", extend_to_line_end, "Extend to line end", extend_to_line_end_newline, "Extend to line end", signature_help, "Show signature help", @@ -841,6 +842,24 @@ fn kill_to_line_end(cx: &mut Context) { fn goto_first_nonwhitespace(cx: &mut Context) { let (view, doc) = current!(cx.editor); + + goto_first_nonwhitespace_impl( + view, + doc, + if cx.editor.mode == Mode::Select { + Movement::Extend + } else { + Movement::Move + }, + ) +} + +fn extend_to_first_nonwhitespace(cx: &mut Context) { + let (view, doc) = current!(cx.editor); + goto_first_nonwhitespace_impl(view, doc, Movement::Extend) +} + +fn goto_first_nonwhitespace_impl(view: &mut View, doc: &mut Document, movement: Movement) { let text = doc.text().slice(..); let selection = doc.selection(view.id).clone().transform(|range| { @@ -848,7 +867,7 @@ fn goto_first_nonwhitespace(cx: &mut Context) { if let Some(pos) = find_first_non_whitespace_char(text.line(line)) { let pos = pos + text.line_to_char(line); - range.put_cursor(text, pos, cx.editor.mode == Mode::Select) + range.put_cursor(text, pos, movement == Movement::Extend) } else { range } @@ -1563,7 +1582,7 @@ fn half_page_down(cx: &mut Context) { } #[allow(deprecated)] -// currently uses the deprected `visual_coords_at_pos`/`pos_at_visual_coords` functions +// currently uses the deprecated `visual_coords_at_pos`/`pos_at_visual_coords` functions // as this function ignores softwrapping (and virtual text) and instead only cares // about "text visual position" // @@ -2149,7 +2168,7 @@ fn global_search(cx: &mut Context) { Some((path.clone().into(), Some((*line_num, *line_num)))) }, ); - compositor.push(Box::new(overlayed(picker))); + compositor.push(Box::new(overlaid(picker))); }, )); Ok(call) @@ -2421,11 +2440,9 @@ fn append_mode(cx: &mut Context) { } fn file_picker(cx: &mut Context) { - // We don't specify language markers, root will be the root of the current - // git repo or the current dir if we're not in a repo - let root = find_root(None, &[]); + let root = find_workspace().0; let picker = ui::file_picker(root, &cx.editor.config()); - cx.push_layer(Box::new(overlayed(picker))); + cx.push_layer(Box::new(overlaid(picker))); } fn file_picker_in_current_buffer_directory(cx: &mut Context) { @@ -2442,12 +2459,12 @@ fn file_picker_in_current_buffer_directory(cx: &mut Context) { }; let picker = ui::file_picker(path, &cx.editor.config()); - cx.push_layer(Box::new(overlayed(picker))); + cx.push_layer(Box::new(overlaid(picker))); } fn file_picker_in_current_directory(cx: &mut Context) { let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("./")); let picker = ui::file_picker(cwd, &cx.editor.config()); - cx.push_layer(Box::new(overlayed(picker))); + cx.push_layer(Box::new(overlaid(picker))); } fn buffer_picker(cx: &mut Context) { @@ -2512,7 +2529,7 @@ fn buffer_picker(cx: &mut Context) { Some((meta.id.into(), Some((line, line)))) }, ); - cx.push_layer(Box::new(overlayed(picker))); + cx.push_layer(Box::new(overlaid(picker))); } fn jumplist_picker(cx: &mut Context) { @@ -2551,6 +2568,13 @@ fn jumplist_picker(cx: &mut Context) { } } + for (view, _) in cx.editor.tree.views_mut() { + for doc_id in view.jumps.iter().map(|e| e.0).collect::>().iter() { + let doc = doc_mut!(cx.editor, doc_id); + view.sync_changes(doc); + } + } + let new_meta = |view: &View, doc_id: DocumentId, selection: Selection| { let doc = &cx.editor.documents.get(&doc_id); let text = doc.map_or("".into(), |d| { @@ -2594,7 +2618,7 @@ fn jumplist_picker(cx: &mut Context) { Some((meta.path.clone()?.into(), Some((line, line)))) }, ); - cx.push_layer(Box::new(overlayed(picker))); + cx.push_layer(Box::new(overlaid(picker))); } impl ui::menu::Item for MappableCommand { @@ -2668,7 +2692,7 @@ pub fn command_palette(cx: &mut Context) { } } }); - compositor.push(Box::new(overlayed(picker))); + compositor.push(Box::new(overlaid(picker))); }, )); } @@ -4189,7 +4213,7 @@ pub fn completion(cx: &mut Context) { None => return, }; - // setup a chanel that allows the request to be canceled + // setup a channel that allows the request to be canceled let (tx, rx) = oneshot::channel(); // set completion_request so that this request can be canceled // by setting completion_request, the old channel stored there is dropped @@ -4242,7 +4266,7 @@ pub fn completion(cx: &mut Context) { let (view, doc) = current_ref!(editor); // check if the completion request is stale. // - // Completions are completed asynchrounsly and therefore the user could + // Completions are completed asynchronously and therefore the user could //switch document/view or leave insert mode. In all of thoise cases the // completion should be discarded if editor.mode != Mode::Insert || view.id != trigger_view || doc.id() != trigger_doc { @@ -4265,7 +4289,7 @@ pub fn completion(cx: &mut Context) { } let size = compositor.size(); let ui = compositor.find::().unwrap(); - ui.set_completion( + let completion_area = ui.set_completion( editor, savepoint, items, @@ -4274,6 +4298,15 @@ pub fn completion(cx: &mut Context) { trigger_offset, size, ); + let size = compositor.size(); + let signature_help_area = compositor + .find_id::>(SignatureHelp::ID) + .map(|signature_help| signature_help.area(size, editor)); + // Delete the signature help popup if they intersect. + if matches!((completion_area, signature_help_area),(Some(a), Some(b)) if a.intersects(b)) + { + compositor.remove(SignatureHelp::ID); + } }, ); } diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index dac1e9d52..8efdc9cfa 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -2,7 +2,7 @@ use super::{Context, Editor}; use crate::{ compositor::{self, Compositor}, job::{Callback, Jobs}, - ui::{self, overlay::overlayed, FilePicker, Picker, Popup, Prompt, PromptEvent, Text}, + ui::{self, overlay::overlaid, FilePicker, Picker, Popup, Prompt, PromptEvent, Text}, }; use dap::{StackFrame, Thread, ThreadStates}; use helix_core::syntax::{DebugArgumentValue, DebugConfigCompletion, DebugTemplate}; @@ -270,7 +270,7 @@ pub fn dap_launch(cx: &mut Context) { let templates = config.templates.clone(); - cx.push_layer(Box::new(overlayed(Picker::new( + cx.push_layer(Box::new(overlaid(Picker::new( templates, (), |cx, template, _action| { diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 02f0ddbe6..fb1ba5998 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -26,7 +26,7 @@ use helix_view::{ use crate::{ compositor::{self, Compositor}, ui::{ - self, lsp::SignatureHelp, overlay::overlayed, DynamicPicker, FileLocation, FilePicker, + self, lsp::SignatureHelp, overlay::overlaid, DynamicPicker, FileLocation, FilePicker, Popup, PromptEvent, }, }; @@ -81,7 +81,7 @@ impl ui::menu::Item for lsp::Location { // Most commonly, this will not allocate, especially on Unix systems where the root prefix // is a simple `/` and not `C:\` (with whatever drive letter) - write!(&mut res, ":{}", self.range.start.line) + write!(&mut res, ":{}", self.range.start.line + 1) .expect("Will only failed if allocating fail"); res.into() } @@ -205,7 +205,9 @@ fn jump_to_location( log::warn!("lsp position out of bounds - {:?}", location.range); return; }; - doc.set_selection(view.id, Selection::single(new_range.anchor, new_range.head)); + // we flip the range so that the cursor sits on the start of the symbol + // (for example start of the function). + doc.set_selection(view.id, Selection::single(new_range.head, new_range.anchor)); align_view(doc, view, Align::Center); } @@ -372,7 +374,7 @@ pub fn symbol_picker(cx: &mut Context) { }; let picker = sym_picker(symbols, current_url, offset_encoding); - compositor.push(Box::new(overlayed(picker))) + compositor.push(Box::new(overlaid(picker))) } }, ) @@ -431,7 +433,7 @@ pub fn workspace_symbol_picker(cx: &mut Context) { future.boxed() }; let dyn_picker = DynamicPicker::new(picker, Box::new(get_symbols)); - compositor.push(Box::new(overlayed(dyn_picker))) + compositor.push(Box::new(overlaid(dyn_picker))) }, ) } @@ -454,7 +456,7 @@ pub fn diagnostics_picker(cx: &mut Context) { DiagnosticsFormat::HideSourcePath, offset_encoding, ); - cx.push_layer(Box::new(overlayed(picker))); + cx.push_layer(Box::new(overlaid(picker))); } } @@ -471,7 +473,7 @@ pub fn workspace_diagnostics_picker(cx: &mut Context) { DiagnosticsFormat::ShowSourcePath, offset_encoding, ); - cx.push_layer(Box::new(overlayed(picker))); + cx.push_layer(Box::new(overlaid(picker))); } impl ui::menu::Item for lsp::CodeActionOrCommand { @@ -491,7 +493,7 @@ impl ui::menu::Item for lsp::CodeActionOrCommand { /// /// While the `kind` field is defined as open ended in the LSP spec (any value may be used) /// in practice a closed set of common values (mostly suggested in the LSP spec) are used. -/// VSCode displays each of these categories seperatly (seperated by a heading in the codeactions picker) +/// VSCode displays each of these categories separately (separated by a heading in the codeactions picker) /// to make them easier to navigate. Helix does not display these headings to the user. /// However it does sort code actions by their categories to achieve the same order as the VScode picker, /// just without the headings. @@ -521,7 +523,7 @@ fn action_category(action: &CodeActionOrCommand) -> u32 { } } -fn action_prefered(action: &CodeActionOrCommand) -> bool { +fn action_preferred(action: &CodeActionOrCommand) -> bool { matches!( action, CodeActionOrCommand::CodeAction(CodeAction { @@ -600,12 +602,12 @@ pub fn code_action(cx: &mut Context) { } // Sort codeactions into a useful order. This behaviour is only partially described in the LSP spec. - // Many details are modeled after vscode because langauge servers are usually tested against it. + // Many details are modeled after vscode because language servers are usually tested against it. // VScode sorts the codeaction two times: // // First the codeactions that fix some diagnostics are moved to the front. // If both codeactions fix some diagnostics (or both fix none) the codeaction - // that is marked with `is_preffered` is shown first. The codeactions are then shown in seperate + // that is marked with `is_preferred` is shown first. The codeactions are then shown in separate // submenus that only contain a certain category (see `action_category`) of actions. // // Below this done in in a single sorting step @@ -627,10 +629,10 @@ pub fn code_action(cx: &mut Context) { return order; } - // if one of the codeactions is marked as prefered show it first + // if one of the codeactions is marked as preferred show it first // otherwise keep the original LSP sorting - action_prefered(action1) - .cmp(&action_prefered(action2)) + action_preferred(action1) + .cmp(&action_preferred(action2)) .reverse() }); @@ -955,7 +957,7 @@ fn goto_impl( }, move |_editor, location| Some(location_to_file_location(location)), ); - compositor.push(Box::new(overlayed(picker))); + compositor.push(Box::new(overlaid(picker))); } } } @@ -1271,10 +1273,25 @@ pub fn signature_help_impl(cx: &mut Context, invoked: SignatureHelpInvoked) { contents.set_active_param_range(active_param_range()); let old_popup = compositor.find_id::>(SignatureHelp::ID); - let popup = Popup::new(SignatureHelp::ID, contents) + let mut popup = Popup::new(SignatureHelp::ID, contents) .position(old_popup.and_then(|p| p.get_position())) .position_bias(Open::Above) .ignore_escape_key(true); + + // Don't create a popup if it intersects the auto-complete menu. + let size = compositor.size(); + if compositor + .find::() + .unwrap() + .completion + .as_mut() + .map(|completion| completion.area(size, editor)) + .filter(|area| area.intersects(popup.area(size, editor))) + .is_some() + { + return; + } + compositor.replace_or_push(SignatureHelp::ID, popup); }, ); diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 2c72686da..ea82dc366 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -116,7 +116,7 @@ fn open(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> let call: job::Callback = job::Callback::EditorCompositor(Box::new( move |editor: &mut Editor, compositor: &mut Compositor| { let picker = ui::file_picker(path, &editor.config()); - compositor.push(Box::new(overlayed(picker))); + compositor.push(Box::new(overlaid(picker))); }, )); Ok(call) @@ -1335,7 +1335,7 @@ fn lsp_workspace_command( let picker = ui::Picker::new(commands, (), |cx, command, _action| { execute_lsp_command(cx.editor, command.clone()); }); - compositor.push(Box::new(overlayed(picker))) + compositor.push(Box::new(overlaid(picker))) }, )); Ok(call) @@ -1371,13 +1371,19 @@ fn lsp_restart( return Ok(()); } + let editor_config = cx.editor.config.load(); let (_view, doc) = current!(cx.editor); let config = doc .language_config() .context("LSP not defined for the current document")?; let scope = config.scope.clone(); - cx.editor.language_servers.restart(config, doc.path())?; + cx.editor.language_servers.restart( + config, + doc.path(), + &editor_config.workspace_lsp_roots, + editor_config.lsp.snippets, + )?; // This collect is needed because refresh_language_server would need to re-borrow editor. let document_ids_to_refresh: Vec = cx @@ -1764,12 +1770,12 @@ fn toggle_option( let pointer = format!("/{}", key.replace('.', "/")); let value = config.pointer_mut(&pointer).ok_or_else(key_error)?; - if let Value::Bool(b) = *value { - *value = Value::Bool(!b); - } else { + let Value::Bool(old_value) = *value else { anyhow::bail!("Key `{}` is not toggle-able", key) - } + }; + let new_value = !old_value; + *value = Value::Bool(new_value); // This unwrap should never fail because we only replace one boolean value // with another, maintaining a valid json config let config = serde_json::from_value(config).unwrap(); @@ -1778,6 +1784,8 @@ fn toggle_option( .config_events .0 .send(ConfigEvent::Update(config))?; + cx.editor + .set_status(format!("Option `{}` is now set to `{}`", key, new_value)); Ok(()) } @@ -1970,6 +1978,20 @@ fn open_config( Ok(()) } +fn open_workspace_config( + cx: &mut compositor::Context, + _args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + + cx.editor + .open(&helix_loader::workspace_config_file(), Action::Replace)?; + Ok(()) +} + fn open_log( cx: &mut compositor::Context, _args: &[Cow], @@ -2105,20 +2127,16 @@ fn reset_diff_change( let scrolloff = editor.config().scrolloff; let (view, doc) = current!(editor); - // TODO refactor to use let..else once MSRV is raised to 1.65 - let handle = match doc.diff_handle() { - Some(handle) => handle, - None => bail!("Diff is not available in the current buffer"), + let Some(handle) = doc.diff_handle() else { + bail!("Diff is not available in the current buffer") }; let diff = handle.load(); let doc_text = doc.text().slice(..); let line = doc.selection(view.id).primary().cursor_line(doc_text); - // TODO refactor to use let..else once MSRV is raised to 1.65 - let hunk_idx = match diff.hunk_at(line as u32, true) { - Some(hunk_idx) => hunk_idx, - None => bail!("There is no change at the cursor"), + let Some(hunk_idx) = diff.hunk_at(line as u32, true) else { + bail!("There is no change at the cursor") }; let hunk = diff.nth_hunk(hunk_idx); let diff_base = diff.diff_base(); @@ -2479,7 +2497,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ }, TypableCommand { name: "update", - aliases: &[], + aliases: &["u"], doc: "Write changes only if the file has been modified.", fun: update, signature: CommandSignature::none(), @@ -2646,6 +2664,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: open_config, signature: CommandSignature::none(), }, + TypableCommand { + name: "config-open-workspace", + aliases: &[], + doc: "Open the workspace config.toml file.", + fun: open_workspace_config, + signature: CommandSignature::none(), + }, TypableCommand { name: "log-open", aliases: &[], diff --git a/helix-term/src/config.rs b/helix-term/src/config.rs index 4407a882f..9776ef7a4 100644 --- a/helix-term/src/config.rs +++ b/helix-term/src/config.rs @@ -1,27 +1,34 @@ -use crate::keymap::{default::default, merge_keys, Keymap}; +use crate::keymap; +use crate::keymap::{merge_keys, Keymap}; +use helix_loader::merge_toml_values; use helix_view::document::Mode; use serde::Deserialize; use std::collections::HashMap; use std::fmt::Display; +use std::fs; use std::io::Error as IOError; -use std::path::PathBuf; use toml::de::Error as TomlError; -#[derive(Debug, Clone, PartialEq, Deserialize)] -#[serde(deny_unknown_fields)] +#[derive(Debug, Clone, PartialEq)] pub struct Config { pub theme: Option, - #[serde(default = "default")] pub keys: HashMap, - #[serde(default)] pub editor: helix_view::editor::Config, } +#[derive(Debug, Clone, PartialEq, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigRaw { + pub theme: Option, + pub keys: Option>, + pub editor: Option, +} + impl Default for Config { fn default() -> Config { Config { theme: None, - keys: default(), + keys: keymap::default(), editor: helix_view::editor::Config::default(), } } @@ -33,6 +40,12 @@ pub enum ConfigLoadError { Error(IOError), } +impl Default for ConfigLoadError { + fn default() -> Self { + ConfigLoadError::Error(IOError::new(std::io::ErrorKind::NotFound, "place holder")) + } +} + impl Display for ConfigLoadError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -43,17 +56,72 @@ impl Display for ConfigLoadError { } impl Config { - pub fn load(config_path: PathBuf) -> Result { - match std::fs::read_to_string(config_path) { - Ok(config) => toml::from_str(&config) - .map(merge_keys) - .map_err(ConfigLoadError::BadConfig), - Err(err) => Err(ConfigLoadError::Error(err)), - } + pub fn load( + global: Result, + local: Result, + ) -> Result { + let global_config: Result = + global.and_then(|file| toml::from_str(&file).map_err(ConfigLoadError::BadConfig)); + let local_config: Result = + local.and_then(|file| toml::from_str(&file).map_err(ConfigLoadError::BadConfig)); + let res = match (global_config, local_config) { + (Ok(global), Ok(local)) => { + let mut keys = keymap::default(); + if let Some(global_keys) = global.keys { + merge_keys(&mut keys, global_keys) + } + if let Some(local_keys) = local.keys { + merge_keys(&mut keys, local_keys) + } + + let editor = match (global.editor, local.editor) { + (None, None) => helix_view::editor::Config::default(), + (None, Some(val)) | (Some(val), None) => { + val.try_into().map_err(ConfigLoadError::BadConfig)? + } + (Some(global), Some(local)) => merge_toml_values(global, local, 3) + .try_into() + .map_err(ConfigLoadError::BadConfig)?, + }; + + Config { + theme: local.theme.or(global.theme), + keys, + editor, + } + } + // if any configs are invalid return that first + (_, Err(ConfigLoadError::BadConfig(err))) + | (Err(ConfigLoadError::BadConfig(err)), _) => { + return Err(ConfigLoadError::BadConfig(err)) + } + (Ok(config), Err(_)) | (Err(_), Ok(config)) => { + let mut keys = keymap::default(); + if let Some(keymap) = config.keys { + merge_keys(&mut keys, keymap); + } + Config { + theme: config.theme, + keys, + editor: config.editor.map_or_else( + || Ok(helix_view::editor::Config::default()), + |val| val.try_into().map_err(ConfigLoadError::BadConfig), + )?, + } + } + // these are just two io errors return the one for the global config + (Err(err), Err(_)) => return Err(err), + }; + + Ok(res) } pub fn load_default() -> Result { - Config::load(helix_loader::config_file()) + let global_config = + fs::read_to_string(helix_loader::config_file()).map_err(ConfigLoadError::Error); + let local_config = fs::read_to_string(helix_loader::workspace_config_file()) + .map_err(ConfigLoadError::Error); + Config::load(global_config, local_config) } } @@ -61,6 +129,12 @@ impl Config { mod tests { use super::*; + impl Config { + fn load_test(config: &str) -> Config { + Config::load(Ok(config.to_owned()), Err(ConfigLoadError::default())).unwrap() + } + } + #[test] fn parsing_keymaps_config_file() { use crate::keymap; @@ -77,18 +151,24 @@ mod tests { A-F12 = "move_next_word_end" "#; + let mut keys = keymap::default(); + merge_keys( + &mut keys, + hashmap! { + Mode::Insert => Keymap::new(keymap!({ "Insert mode" + "y" => move_line_down, + "S-C-a" => delete_selection, + })), + Mode::Normal => Keymap::new(keymap!({ "Normal mode" + "A-F12" => move_next_word_end, + })), + }, + ); + assert_eq!( - toml::from_str::(sample_keymaps).unwrap(), + Config::load_test(sample_keymaps), Config { - keys: hashmap! { - Mode::Insert => Keymap::new(keymap!({ "Insert mode" - "y" => move_line_down, - "S-C-a" => delete_selection, - })), - Mode::Normal => Keymap::new(keymap!({ "Normal mode" - "A-F12" => move_next_word_end, - })), - }, + keys, ..Default::default() } ); @@ -97,11 +177,11 @@ mod tests { #[test] fn keys_resolve_to_correct_defaults() { // From serde default - let default_keys = toml::from_str::("").unwrap().keys; - assert_eq!(default_keys, default()); + let default_keys = Config::load_test("").keys; + assert_eq!(default_keys, keymap::default()); // From the Default trait let default_keys = Config::default().keys; - assert_eq!(default_keys, default()); + assert_eq!(default_keys, keymap::default()); } } diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index e94a5f66b..3033c6a48 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -2,7 +2,6 @@ pub mod default; pub mod macros; pub use crate::commands::MappableCommand; -use crate::config::Config; use arc_swap::{ access::{DynAccess, DynGuard}, ArcSwap, @@ -16,7 +15,7 @@ use std::{ sync::Arc, }; -use default::default; +pub use default::default; use macros::key; #[derive(Debug, Clone)] @@ -417,12 +416,10 @@ impl Default for Keymaps { } /// Merge default config keys with user overwritten keys for custom user config. -pub fn merge_keys(mut config: Config) -> Config { - let mut delta = std::mem::replace(&mut config.keys, default()); - for (mode, keys) in &mut config.keys { +pub fn merge_keys(dst: &mut HashMap, mut delta: HashMap) { + for (mode, keys) in dst { keys.merge(delta.remove(mode).unwrap_or_default()) } - config } #[cfg(test)] @@ -449,26 +446,24 @@ mod tests { #[test] fn merge_partial_keys() { - let config = Config { - keys: hashmap! { - Mode::Normal => Keymap::new( - keymap!({ "Normal mode" - "i" => normal_mode, - "无" => insert_mode, - "z" => jump_backward, - "g" => { "Merge into goto mode" - "$" => goto_line_end, - "g" => delete_char_forward, - }, - }) - ) - }, - ..Default::default() + let keymap = hashmap! { + Mode::Normal => Keymap::new( + keymap!({ "Normal mode" + "i" => normal_mode, + "无" => insert_mode, + "z" => jump_backward, + "g" => { "Merge into goto mode" + "$" => goto_line_end, + "g" => delete_char_forward, + }, + }) + ) }; - let mut merged_config = merge_keys(config.clone()); - assert_ne!(config, merged_config); + let mut merged_keyamp = default(); + merge_keys(&mut merged_keyamp, keymap.clone()); + assert_ne!(keymap, merged_keyamp); - let mut keymap = Keymaps::new(Box::new(Constant(merged_config.keys.clone()))); + let mut keymap = Keymaps::new(Box::new(Constant(merged_keyamp.clone()))); assert_eq!( keymap.get(Mode::Normal, key!('i')), KeymapResult::Matched(MappableCommand::normal_mode), @@ -486,7 +481,7 @@ mod tests { "Leaf should replace node" ); - let keymap = merged_config.keys.get_mut(&Mode::Normal).unwrap(); + let keymap = merged_keyamp.get_mut(&Mode::Normal).unwrap(); // Assumes that `g` is a node in default keymap assert_eq!( keymap.root().search(&[key!('g'), key!('$')]).unwrap(), @@ -506,30 +501,28 @@ mod tests { "Old leaves in subnode should be present in merged node" ); - assert!(merged_config.keys.get(&Mode::Normal).unwrap().len() > 1); - assert!(merged_config.keys.get(&Mode::Insert).unwrap().len() > 0); + assert!(merged_keyamp.get(&Mode::Normal).unwrap().len() > 1); + assert!(merged_keyamp.get(&Mode::Insert).unwrap().len() > 0); } #[test] fn order_should_be_set() { - let config = Config { - keys: hashmap! { - Mode::Normal => Keymap::new( - keymap!({ "Normal mode" - "space" => { "" - "s" => { "" - "v" => vsplit, - "c" => hsplit, - }, + let keymap = hashmap! { + Mode::Normal => Keymap::new( + keymap!({ "Normal mode" + "space" => { "" + "s" => { "" + "v" => vsplit, + "c" => hsplit, }, - }) - ) - }, - ..Default::default() + }, + }) + ) }; - let mut merged_config = merge_keys(config.clone()); - assert_ne!(config, merged_config); - let keymap = merged_config.keys.get_mut(&Mode::Normal).unwrap(); + let mut merged_keyamp = default(); + merge_keys(&mut merged_keyamp, keymap.clone()); + assert_ne!(keymap, merged_keyamp); + let keymap = merged_keyamp.get_mut(&Mode::Normal).unwrap(); // Make sure mapping works assert_eq!( keymap diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index aac5c5379..e0c3f6e70 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -3,7 +3,7 @@ use crossterm::event::EventStream; use helix_loader::VERSION_AND_GIT_HASH; use helix_term::application::Application; use helix_term::args::Args; -use helix_term::config::Config; +use helix_term::config::{Config, ConfigLoadError}; use std::path::PathBuf; fn setup_logging(logpath: PathBuf, verbosity: u64) -> Result<()> { @@ -126,18 +126,19 @@ FLAGS: helix_loader::initialize_config_file(args.config_file.clone()); - let config = match std::fs::read_to_string(helix_loader::config_file()) { - Ok(config) => toml::from_str(&config) - .map(helix_term::keymap::merge_keys) - .unwrap_or_else(|err| { - eprintln!("Bad config: {}", err); - eprintln!("Press to continue with default config"); - use std::io::Read; - let _ = std::io::stdin().read(&mut []); - Config::default() - }), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => Config::default(), - Err(err) => return Err(Error::new(err)), + let config = match Config::load_default() { + Ok(config) => config, + Err(ConfigLoadError::Error(err)) if err.kind() == std::io::ErrorKind::NotFound => { + Config::default() + } + Err(ConfigLoadError::Error(err)) => return Err(Error::new(err)), + Err(ConfigLoadError::BadConfig(err)) => { + eprintln!("Bad config: {}", err); + eprintln!("Press to continue with default config"); + use std::io::Read; + let _ = std::io::stdin().read(&mut []); + Config::default() + } }; let syn_loader_conf = helix_core::config::user_syntax_loader().unwrap_or_else(|err| { diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index da6b5ddcb..bc216509f 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -141,16 +141,12 @@ impl Completion { } }; - let start_offset = - match util::lsp_pos_to_pos(doc.text(), edit.range.start, offset_encoding) { - Some(start) => start as i128 - primary_cursor as i128, - None => return Transaction::new(doc.text()), - }; - let end_offset = - match util::lsp_pos_to_pos(doc.text(), edit.range.end, offset_encoding) { - Some(end) => end as i128 - primary_cursor as i128, - None => return Transaction::new(doc.text()), - }; + let Some(range) = util::lsp_range_to_range(doc.text(), edit.range, offset_encoding) else{ + return Transaction::new(doc.text()); + }; + + let start_offset = range.anchor as i128 - primary_cursor as i128; + let end_offset = range.head as i128 - primary_cursor as i128; (Some((start_offset, end_offset)), edit.new_text) } else { @@ -414,6 +410,10 @@ impl Completion { true } + + pub fn area(&mut self, viewport: Rect, editor: &Editor) -> Rect { + self.popup.area(viewport, editor) + } } impl Component for Completion { @@ -481,7 +481,7 @@ impl Component for Completion { }; let popup_area = { - let (popup_x, popup_y) = self.popup.get_rel_position(area, cx); + let (popup_x, popup_y) = self.popup.get_rel_position(area, cx.editor); let (popup_width, popup_height) = self.popup.get_size(); Rect::new(popup_x, popup_y, popup_width, popup_height) }; diff --git a/helix-term/src/ui/document.rs b/helix-term/src/ui/document.rs index 39c209505..80da1c542 100644 --- a/helix-term/src/ui/document.rs +++ b/helix-term/src/ui/document.rs @@ -118,7 +118,7 @@ pub fn render_document( fn translate_positions( char_pos: usize, - first_visisble_char_idx: usize, + first_visible_char_idx: usize, translated_positions: &mut [TranslatedPosition], text_fmt: &TextFormat, renderer: &mut TextRenderer, @@ -126,7 +126,7 @@ fn translate_positions( ) { // check if any positions translated on the fly (like cursor) has been reached for (char_idx, callback) in &mut *translated_positions { - if *char_idx < char_pos && *char_idx >= first_visisble_char_idx { + if *char_idx < char_pos && *char_idx >= first_visible_char_idx { // by replacing the char_index with usize::MAX large number we ensure // that the same position is only translated once // text will never reach usize::MAX as rust memory allocations are limited @@ -259,7 +259,7 @@ pub fn render_text<'t>( } } - // aquire the correct grapheme style + // acquire the correct grapheme style if char_pos >= style_span.1 { style_span = styles.next().unwrap_or((Style::default(), usize::MAX)); } @@ -404,7 +404,7 @@ impl<'a> TextRenderer<'a> { let cut_off_start = self.col_offset.saturating_sub(position.col); let is_whitespace = grapheme.is_whitespace(); - // TODO is it correct to apply the whitspace style to all unicode white spaces? + // TODO is it correct to apply the whitespace style to all unicode white spaces? if is_whitespace { style = style.patch(self.whitespace_style); } diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 4cac0fa8b..fd8e8fb21 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -93,40 +93,6 @@ impl EditorView { let mut line_decorations: Vec> = Vec::new(); let mut translated_positions: Vec = Vec::new(); - // DAP: Highlight current stack frame position - let stack_frame = editor.debugger.as_ref().and_then(|debugger| { - if let (Some(frame), Some(thread_id)) = (debugger.active_frame, debugger.thread_id) { - debugger - .stack_frames - .get(&thread_id) - .and_then(|bt| bt.get(frame)) - } else { - None - } - }); - if let Some(frame) = stack_frame { - if doc.path().is_some() - && frame - .source - .as_ref() - .and_then(|source| source.path.as_ref()) - == doc.path() - { - let line = frame.line - 1; // convert to 0-indexing - let style = theme.get("ui.highlight"); - let line_decoration = move |renderer: &mut TextRenderer, pos: LinePos| { - if pos.doc_line != line { - return; - } - renderer - .surface - .set_style(Rect::new(area.x, pos.visual_line, area.width, 1), style); - }; - - line_decorations.push(Box::new(line_decoration)); - } - } - if is_focused && config.cursorline { line_decorations.push(Self::cursorline_decorator(doc, view, theme)) } @@ -135,6 +101,23 @@ impl EditorView { Self::highlight_cursorcolumn(doc, view, surface, theme, inner, &text_annotations); } + // Set DAP highlights, if needed. + if let Some(frame) = editor.current_stack_frame() { + let dap_line = frame.line.saturating_sub(1) as usize; + let style = theme.get("ui.highlight.frameline"); + let line_decoration = move |renderer: &mut TextRenderer, pos: LinePos| { + if pos.doc_line != dap_line { + return; + } + renderer.surface.set_style( + Rect::new(inner.x, inner.y + pos.visual_line, inner.width, 1), + style, + ); + }; + + line_decorations.push(Box::new(line_decoration)); + } + let mut highlights = Self::doc_syntax_highlights(doc, view.offset.anchor, inner.height, theme); let overlay_highlights = Self::overlay_syntax_highlights( @@ -422,6 +405,7 @@ impl EditorView { let primary_selection_scope = theme .find_scope_index_exact("ui.selection.primary") .unwrap_or(selection_scope); + let base_cursor_scope = theme .find_scope_index_exact("ui.cursor") .unwrap_or(selection_scope); @@ -968,7 +952,7 @@ impl EditorView { start_offset: usize, trigger_offset: usize, size: Rect, - ) { + ) -> Option { let mut completion = Completion::new( editor, savepoint, @@ -980,15 +964,17 @@ impl EditorView { if completion.is_empty() { // skip if we got no completion results - return; + return None; } + let area = completion.area(size, editor); editor.last_completion = None; self.last_insert.1.push(InsertEvent::TriggerCompletion); // TODO : propagate required size on resize to completion too completion.required_size((size.width, size.height)); self.completion = Some(completion); + Some(area) } pub fn clear_completion(&mut self, editor: &mut Editor) { @@ -1272,13 +1258,15 @@ impl Component for EditorView { // let completion swallow the event if necessary let mut consumed = false; if let Some(completion) = &mut self.completion { - // use a fake context here - let mut cx = Context { - editor: cx.editor, - jobs: cx.jobs, - scroll: None, + let res = { + // use a fake context here + let mut cx = Context { + editor: cx.editor, + jobs: cx.jobs, + scroll: None, + }; + completion.handle_event(event, &mut cx) }; - let res = completion.handle_event(event, &mut cx); if let EventResult::Consumed(callback) = res { consumed = true; @@ -1286,6 +1274,12 @@ impl Component for EditorView { if callback.is_some() { // assume close_fn self.clear_completion(cx.editor); + + // In case the popup was deleted because of an intersection w/ the auto-complete menu. + commands::signature_help_impl( + &mut cx, + commands::SignatureHelpInvoked::Automatic, + ); } } } diff --git a/helix-term/src/ui/fuzzy_match.rs b/helix-term/src/ui/fuzzy_match.rs index b406702ff..22dc3a7fa 100644 --- a/helix-term/src/ui/fuzzy_match.rs +++ b/helix-term/src/ui/fuzzy_match.rs @@ -54,7 +54,7 @@ impl QueryAtom { } fn indices(&self, matcher: &Matcher, item: &str, indices: &mut Vec) -> bool { - // for inverse there are no indicies to return + // for inverse there are no indices to return // just return whether we matched if self.inverse { return self.matches(matcher, item); @@ -120,7 +120,7 @@ enum QueryAtomKind { /// /// Usage: `foo` Fuzzy, - /// Item contains query atom as a continous substring + /// Item contains query atom as a continuous substring /// /// Usage `'foo` Substring, @@ -213,7 +213,7 @@ impl FuzzyQuery { Some(score) } - pub fn fuzzy_indicies(&self, item: &str, matcher: &Matcher) -> Option<(i64, Vec)> { + pub fn fuzzy_indices(&self, item: &str, matcher: &Matcher) -> Option<(i64, Vec)> { let (score, mut indices) = self.first_fuzzy_atom.as_ref().map_or_else( || Some((0, Vec::new())), |atom| matcher.fuzzy_indices(item, atom), diff --git a/helix-term/src/ui/fuzzy_match/test.rs b/helix-term/src/ui/fuzzy_match/test.rs index 3f90ef681..5df79eeb1 100644 --- a/helix-term/src/ui/fuzzy_match/test.rs +++ b/helix-term/src/ui/fuzzy_match/test.rs @@ -7,8 +7,8 @@ fn run_test<'a>(query: &str, items: &'a [&'a str]) -> Vec { items .iter() .filter_map(|item| { - let (_, indicies) = query.fuzzy_indicies(item, &matcher)?; - let matched_string = indicies + let (_, indices) = query.fuzzy_indices(item, &matcher)?; + let matched_string = indices .iter() .map(|&pos| item.chars().nth(pos).unwrap()) .collect(); diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index 30625acee..bdad2e408 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -347,6 +347,7 @@ impl Component for Menu { offset: scroll, selected: self.cursor, }, + false, ); if let Some(cursor) = self.cursor { diff --git a/helix-term/src/ui/overlay.rs b/helix-term/src/ui/overlay.rs index 5b2bc8060..ff184d407 100644 --- a/helix-term/src/ui/overlay.rs +++ b/helix-term/src/ui/overlay.rs @@ -16,7 +16,7 @@ pub struct Overlay { } /// Surrounds the component with a margin of 5% on each side, and an additional 2 rows at the bottom -pub fn overlayed(content: T) -> Overlay { +pub fn overlaid(content: T) -> Overlay { Overlay { content, calc_child_size: Box::new(|rect: Rect| clip_rect_relative(rect.clip_bottom(2), 90, 90)), diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 3294a2a1d..e7a7de909 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -794,7 +794,7 @@ impl Component for Picker { // might be inconsistencies. This is the best we can do since only the // text in Row is displayed to the end user. let (_score, highlights) = FuzzyQuery::new(self.prompt.line()) - .fuzzy_indicies(&line, &self.matcher) + .fuzzy_indices(&line, &self.matcher) .unwrap_or_default(); let highlight_byte_ranges: Vec<_> = line @@ -885,6 +885,7 @@ impl Component for Picker { offset: 0, selected: Some(cursor), }, + self.truncate_start, ); } diff --git a/helix-term/src/ui/popup.rs b/helix-term/src/ui/popup.rs index 5a95c1bba..dff7b2319 100644 --- a/helix-term/src/ui/popup.rs +++ b/helix-term/src/ui/popup.rs @@ -6,7 +6,10 @@ use crate::{ use tui::buffer::Buffer as Surface; use helix_core::Position; -use helix_view::graphics::{Margin, Rect}; +use helix_view::{ + graphics::{Margin, Rect}, + Editor, +}; // TODO: share logic with Menu, it's essentially Popup(render_fn), but render fn needs to return // a width/height hint. maybe Popup(Box) @@ -88,10 +91,10 @@ impl Popup { /// Calculate the position where the popup should be rendered and return the coordinates of the /// top left corner. - pub fn get_rel_position(&mut self, viewport: Rect, cx: &Context) -> (u16, u16) { + pub fn get_rel_position(&mut self, viewport: Rect, editor: &Editor) -> (u16, u16) { let position = self .position - .get_or_insert_with(|| cx.editor.cursor().0.unwrap_or_default()); + .get_or_insert_with(|| editor.cursor().0.unwrap_or_default()); let (width, height) = self.size; @@ -155,6 +158,16 @@ impl Popup { pub fn contents_mut(&mut self) -> &mut T { &mut self.contents } + + pub fn area(&mut self, viewport: Rect, editor: &Editor) -> Rect { + // trigger required_size so we recalculate if the child changed + self.required_size((viewport.width, viewport.height)); + + let (rel_x, rel_y) = self.get_rel_position(viewport, editor); + + // clip to viewport + viewport.intersection(Rect::new(rel_x, rel_y, self.size.0, self.size.1)) + } } impl Component for Popup { @@ -232,16 +245,9 @@ impl Component for Popup { } fn render(&mut self, viewport: Rect, surface: &mut Surface, cx: &mut Context) { - // trigger required_size so we recalculate if the child changed - self.required_size((viewport.width, viewport.height)); - + let area = self.area(viewport, cx.editor); cx.scroll = Some(self.scroll); - let (rel_x, rel_y) = self.get_rel_position(viewport, cx); - - // clip to viewport - let area = viewport.intersection(Rect::new(rel_x, rel_y, self.size.0, self.size.1)); - // clear area let background = cx.editor.theme.get("ui.popup"); surface.clear_with(area, background); diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 35ae8c2a8..a9ccfb737 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -511,11 +511,21 @@ impl Component for Prompt { ctrl!('e') | key!(End) => self.move_end(), ctrl!('a') | key!(Home) => self.move_start(), ctrl!('w') | alt!(Backspace) | ctrl!(Backspace) => { - self.delete_word_backwards(cx.editor) + self.delete_word_backwards(cx.editor); + (self.callback_fn)(cx, &self.line, PromptEvent::Update); + } + alt!('d') | alt!(Delete) | ctrl!(Delete) => { + self.delete_word_forwards(cx.editor); + (self.callback_fn)(cx, &self.line, PromptEvent::Update); + } + ctrl!('k') => { + self.kill_to_end_of_line(cx.editor); + (self.callback_fn)(cx, &self.line, PromptEvent::Update); + } + ctrl!('u') => { + self.kill_to_start_of_line(cx.editor); + (self.callback_fn)(cx, &self.line, PromptEvent::Update); } - alt!('d') | alt!(Delete) | ctrl!(Delete) => self.delete_word_forwards(cx.editor), - ctrl!('k') => self.kill_to_end_of_line(cx.editor), - ctrl!('u') => self.kill_to_start_of_line(cx.editor), ctrl!('h') | key!(Backspace) | shift!(Backspace) => { self.delete_char_backwards(cx.editor); (self.callback_fn)(cx, &self.line, PromptEvent::Update); diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs index cec374afa..d77eefed0 100644 --- a/helix-term/tests/integration.rs +++ b/helix-term/tests/integration.rs @@ -2,8 +2,6 @@ mod test { mod helpers; - use std::path::PathBuf; - use helix_core::{syntax::AutoPairConfig, Selection}; use helix_term::config::Config; diff --git a/helix-term/tests/test/commands/write.rs b/helix-term/tests/test/commands/write.rs index 0ea66a12d..26515b7ae 100644 --- a/helix-term/tests/test/commands/write.rs +++ b/helix-term/tests/test/commands/write.rs @@ -3,7 +3,7 @@ use std::{ ops::RangeInclusive, }; -use helix_core::diagnostic::Severity; +use helix_core::{diagnostic::Severity, path::get_normalized_path}; use helix_view::doc; use super::*; @@ -23,7 +23,7 @@ async fn test_write_quit_fail() -> anyhow::Result<()> { assert_eq!(1, docs.len()); let doc = docs.pop().unwrap(); - assert_eq!(Some(file.path()), doc.path().map(PathBuf::as_path)); + assert_eq!(Some(&get_normalized_path(file.path())), doc.path()); assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); }), false, @@ -269,7 +269,7 @@ async fn test_write_scratch_to_new_path() -> anyhow::Result<()> { assert_eq!(1, docs.len()); let doc = docs.pop().unwrap(); - assert_eq!(Some(&file.path().to_path_buf()), doc.path()); + assert_eq!(Some(&get_normalized_path(file.path())), doc.path()); }), false, ) @@ -341,7 +341,7 @@ async fn test_write_new_path() -> anyhow::Result<()> { Some(&|app| { let doc = doc!(app.editor); assert!(!app.editor.is_err()); - assert_eq!(file1.path(), doc.path().unwrap()); + assert_eq!(&get_normalized_path(file1.path()), doc.path().unwrap()); }), ), ( @@ -349,7 +349,7 @@ async fn test_write_new_path() -> anyhow::Result<()> { Some(&|app| { let doc = doc!(app.editor); assert!(!app.editor.is_err()); - assert_eq!(file2.path(), doc.path().unwrap()); + assert_eq!(&get_normalized_path(file2.path()), doc.path().unwrap()); assert!(app.editor.document_by_path(file1.path()).is_none()); }), ), diff --git a/helix-term/tests/test/helpers.rs b/helix-term/tests/test/helpers.rs index ccd07bfa5..30fe7d0ed 100644 --- a/helix-term/tests/test/helpers.rs +++ b/helix-term/tests/test/helpers.rs @@ -1,6 +1,7 @@ use std::{ fs::File, io::{Read, Write}, + mem::replace, path::PathBuf, time::Duration, }; @@ -222,10 +223,11 @@ pub fn temp_file_with_contents>( /// Generates a config with defaults more suitable for integration tests pub fn test_config() -> Config { - merge_keys(Config { + Config { editor: test_editor_config(), + keys: helix_term::keymap::default(), ..Default::default() - }) + } } pub fn test_editor_config() -> helix_view::editor::Config { @@ -300,8 +302,10 @@ impl AppBuilder { // Remove this attribute once `with_config` is used in a test: #[allow(dead_code)] - pub fn with_config(mut self, config: Config) -> Self { - self.config = helix_term::keymap::merge_keys(config); + pub fn with_config(mut self, mut config: Config) -> Self { + let keys = replace(&mut config.keys, helix_term::keymap::default()); + merge_keys(&mut config.keys, keys); + self.config = config; self } diff --git a/helix-term/tests/test/movement.rs b/helix-term/tests/test/movement.rs index e10ec6f5d..9a48cdbcb 100644 --- a/helix-term/tests/test/movement.rs +++ b/helix-term/tests/test/movement.rs @@ -391,7 +391,7 @@ async fn cursor_position_newly_opened_file() -> anyhow::Result<()> { #[tokio::test(flavor = "multi_thread")] async fn cursor_position_append_eof() -> anyhow::Result<()> { - // Selection is fowards + // Selection is forwards test(( "#[foo|]#", "abar", diff --git a/helix-term/tests/test/splits.rs b/helix-term/tests/test/splits.rs index 96ced21a5..1d70f24a6 100644 --- a/helix-term/tests/test/splits.rs +++ b/helix-term/tests/test/splits.rs @@ -1,5 +1,7 @@ use super::*; +use helix_core::path::get_normalized_path; + #[tokio::test(flavor = "multi_thread")] async fn test_split_write_quit_all() -> anyhow::Result<()> { let mut file1 = tempfile::NamedTempFile::new()?; @@ -25,21 +27,21 @@ async fn test_split_write_quit_all() -> anyhow::Result<()> { let doc1 = docs .iter() - .find(|doc| doc.path().unwrap() == file1.path()) + .find(|doc| doc.path().unwrap() == &get_normalized_path(file1.path())) .unwrap(); assert_eq!("hello1", doc1.text().to_string()); let doc2 = docs .iter() - .find(|doc| doc.path().unwrap() == file2.path()) + .find(|doc| doc.path().unwrap() == &get_normalized_path(file2.path())) .unwrap(); assert_eq!("hello2", doc2.text().to_string()); let doc3 = docs .iter() - .find(|doc| doc.path().unwrap() == file3.path()) + .find(|doc| doc.path().unwrap() == &get_normalized_path(file3.path())) .unwrap(); assert_eq!("hello3", doc3.text().to_string()); diff --git a/helix-tui/Cargo.toml b/helix-tui/Cargo.toml index 5a250bdc1..735669298 100644 --- a/helix-tui/Cargo.toml +++ b/helix-tui/Cargo.toml @@ -16,7 +16,7 @@ include = ["src/**/*", "README.md"] default = ["crossterm"] [dependencies] -bitflags = "2.0" +bitflags = "2.2" cassowary = "0.3" unicode-segmentation = "1.10" crossterm = { version = "0.26", optional = true } diff --git a/helix-tui/src/backend/crossterm.rs b/helix-tui/src/backend/crossterm.rs index 4b230f539..0c32028ec 100644 --- a/helix-tui/src/backend/crossterm.rs +++ b/helix-tui/src/backend/crossterm.rs @@ -63,6 +63,7 @@ pub struct CrosstermBackend { buffer: W, capabilities: Capabilities, supports_keyboard_enhancement_protocol: OnceCell, + mouse_capture_enabled: bool, } impl CrosstermBackend @@ -74,25 +75,25 @@ where buffer, capabilities: Capabilities::from_env_or_default(config), supports_keyboard_enhancement_protocol: OnceCell::new(), + mouse_capture_enabled: false, } } #[inline] - fn supports_keyboard_enhancement_protocol(&self) -> io::Result { - self.supports_keyboard_enhancement_protocol - .get_or_try_init(|| { + fn supports_keyboard_enhancement_protocol(&self) -> bool { + *self.supports_keyboard_enhancement_protocol + .get_or_init(|| { use std::time::Instant; let now = Instant::now(); - let support = terminal::supports_keyboard_enhancement(); + let supported = matches!(terminal::supports_keyboard_enhancement(), Ok(true)); log::debug!( "The keyboard enhancement protocol is {}supported in this terminal (checked in {:?})", - if matches!(support, Ok(true)) { "" } else { "not " }, + if supported { "" } else { "not " }, Instant::now().duration_since(now) ); - support + supported }) - .copied() } } @@ -124,8 +125,9 @@ where execute!(self.buffer, terminal::Clear(terminal::ClearType::All))?; if config.enable_mouse_capture { execute!(self.buffer, EnableMouseCapture)?; + self.mouse_capture_enabled = true; } - if self.supports_keyboard_enhancement_protocol()? { + if self.supports_keyboard_enhancement_protocol() { execute!( self.buffer, PushKeyboardEnhancementFlags( @@ -137,13 +139,26 @@ where Ok(()) } + fn reconfigure(&mut self, config: Config) -> io::Result<()> { + if self.mouse_capture_enabled != config.enable_mouse_capture { + if config.enable_mouse_capture { + execute!(self.buffer, EnableMouseCapture)?; + } else { + execute!(self.buffer, DisableMouseCapture)?; + } + self.mouse_capture_enabled = config.enable_mouse_capture; + } + + Ok(()) + } + fn restore(&mut self, config: Config) -> io::Result<()> { // reset cursor shape write!(self.buffer, "\x1B[0 q")?; if config.enable_mouse_capture { execute!(self.buffer, DisableMouseCapture)?; } - if self.supports_keyboard_enhancement_protocol()? { + if self.supports_keyboard_enhancement_protocol() { execute!(self.buffer, PopKeyboardEnhancementFlags)?; } execute!( @@ -345,9 +360,9 @@ impl ModifierDiff { } } -/// Crossterm uses semicolon as a seperator for colors -/// this is actually not spec compliant (altough commonly supported) -/// However the correct approach is to use colons as a seperator. +/// Crossterm uses semicolon as a separator for colors +/// this is actually not spec compliant (although commonly supported) +/// However the correct approach is to use colons as a separator. /// This usually doesn't make a difference for emulators that do support colored underlines. /// However terminals that do not support colored underlines will ignore underlines colors with colons /// while escape sequences with semicolons are always processed which leads to weird visual artifacts. diff --git a/helix-tui/src/backend/mod.rs b/helix-tui/src/backend/mod.rs index 6d7c38942..6994bc6f5 100644 --- a/helix-tui/src/backend/mod.rs +++ b/helix-tui/src/backend/mod.rs @@ -14,6 +14,7 @@ pub use self::test::TestBackend; pub trait Backend { fn claim(&mut self, config: Config) -> Result<(), io::Error>; + fn reconfigure(&mut self, config: Config) -> Result<(), io::Error>; fn restore(&mut self, config: Config) -> Result<(), io::Error>; fn force_restore() -> Result<(), io::Error>; fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error> diff --git a/helix-tui/src/backend/test.rs b/helix-tui/src/backend/test.rs index ff133ff3e..771cc3094 100644 --- a/helix-tui/src/backend/test.rs +++ b/helix-tui/src/backend/test.rs @@ -111,6 +111,10 @@ impl Backend for TestBackend { Ok(()) } + fn reconfigure(&mut self, _config: Config) -> Result<(), io::Error> { + Ok(()) + } + fn restore(&mut self, _config: Config) -> Result<(), io::Error> { Ok(()) } diff --git a/helix-tui/src/buffer.rs b/helix-tui/src/buffer.rs index b1fd44787..8e0b0adf9 100644 --- a/helix-tui/src/buffer.rs +++ b/helix-tui/src/buffer.rs @@ -433,6 +433,47 @@ impl Buffer { (x_offset as u16, y) } + pub fn set_spans_truncated(&mut self, x: u16, y: u16, spans: &Spans, width: u16) -> (u16, u16) { + // prevent panic if out of range + if !self.in_bounds(x, y) || width == 0 { + return (x, y); + } + + let mut x_offset = x as usize; + let max_offset = min(self.area.right(), width.saturating_add(x)); + let mut start_index = self.index_of(x, y); + let mut index = self.index_of(max_offset as u16, y); + + let content_width = spans.width(); + let truncated = content_width > width as usize; + if truncated { + self.content[start_index].set_symbol("…"); + start_index += 1; + } else { + index -= width as usize - content_width; + } + for span in spans.0.iter().rev() { + for s in span.content.graphemes(true).rev() { + let width = s.width(); + if width == 0 { + continue; + } + let start = index - width; + if start < start_index { + break; + } + self.content[start].set_symbol(s); + self.content[start].set_style(span.style); + for i in start + 1..index { + self.content[i].reset(); + } + index -= width; + x_offset += width; + } + } + (x_offset as u16, y) + } + pub fn set_spans(&mut self, x: u16, y: u16, spans: &Spans, width: u16) -> (u16, u16) { let mut remaining_width = width; let mut x = x; diff --git a/helix-tui/src/terminal.rs b/helix-tui/src/terminal.rs index 802a8c1d9..8b7342751 100644 --- a/helix-tui/src/terminal.rs +++ b/helix-tui/src/terminal.rs @@ -116,6 +116,10 @@ where self.backend.claim(config) } + pub fn reconfigure(&mut self, config: Config) -> io::Result<()> { + self.backend.reconfigure(config) + } + pub fn restore(&mut self, config: Config) -> io::Result<()> { self.backend.restore(config) } diff --git a/helix-tui/src/widgets/table.rs b/helix-tui/src/widgets/table.rs index 400f65e0a..97762167e 100644 --- a/helix-tui/src/widgets/table.rs +++ b/helix-tui/src/widgets/table.rs @@ -354,7 +354,13 @@ impl TableState { impl<'a> Table<'a> { // type State = TableState; - pub fn render_table(mut self, area: Rect, buf: &mut Buffer, state: &mut TableState) { + pub fn render_table( + mut self, + area: Rect, + buf: &mut Buffer, + state: &mut TableState, + truncate: bool, + ) { if area.area() == 0 { return; } @@ -401,6 +407,7 @@ impl<'a> Table<'a> { width: *width, height: max_header_height, }, + truncate, ); col += *width + self.column_spacing; } @@ -457,6 +464,7 @@ impl<'a> Table<'a> { width: *width, height: table_row.height, }, + truncate, ); col += *width + self.column_spacing; } @@ -464,20 +472,24 @@ impl<'a> Table<'a> { } } -fn render_cell(buf: &mut Buffer, cell: &Cell, area: Rect) { +fn render_cell(buf: &mut Buffer, cell: &Cell, area: Rect, truncate: bool) { buf.set_style(area, cell.style); for (i, spans) in cell.content.lines.iter().enumerate() { if i as u16 >= area.height { break; } - buf.set_spans(area.x, area.y + i as u16, spans, area.width); + if truncate { + buf.set_spans_truncated(area.x, area.y + i as u16, spans, area.width); + } else { + buf.set_spans(area.x, area.y + i as u16, spans, area.width); + } } } impl<'a> Widget for Table<'a> { fn render(self, area: Rect, buf: &mut Buffer) { let mut state = TableState::default(); - Table::render_table(self, area, buf, &mut state); + Table::render_table(self, area, buf, &mut state, false); } } diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml index b32c028bd..8a226a0bb 100644 --- a/helix-vcs/Cargo.toml +++ b/helix-vcs/Cargo.toml @@ -17,7 +17,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.41.0", default-features = false , optional = true } +gix = { version = "0.43.0", default-features = false , optional = true } imara-diff = "0.1.5" anyhow = "1" diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index 4f7b08edd..049705956 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -14,7 +14,7 @@ default = [] term = ["crossterm"] [dependencies] -bitflags = "2.0" +bitflags = "2.2" anyhow = "1" helix-core = { version = "0.6", path = "../helix-core" } helix-loader = { version = "0.6", path = "../helix-loader" } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index ee535b5c0..52f86f2da 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -10,6 +10,7 @@ use crate::{ view::ViewPosition, Align, Document, DocumentId, View, ViewId, }; +use dap::StackFrame; use helix_vcs::DiffProviderRegistry; use futures_util::stream::select_all::SelectAll; @@ -281,6 +282,8 @@ pub struct Config { /// Whether to color modes with different colors. Defaults to `false`. pub color_modes: bool, pub soft_wrap: SoftWrap, + /// Workspace specific lsp ceiling dirs + pub workspace_lsp_roots: Vec, } #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -349,6 +352,8 @@ pub struct LspConfig { pub display_signature_help_docs: bool, /// Display inlay hints pub display_inlay_hints: bool, + /// Whether to enable snippet support + pub snippets: bool, } impl Default for LspConfig { @@ -359,6 +364,7 @@ impl Default for LspConfig { auto_signature_help: true, display_signature_help_docs: true, display_inlay_hints: false, + snippets: true, } } } @@ -743,9 +749,13 @@ impl Default for Config { bufferline: BufferLine::default(), indent_guides: IndentGuidesConfig::default(), color_modes: false, - soft_wrap: SoftWrap::default(), + soft_wrap: SoftWrap { + enable: Some(false), + ..SoftWrap::default() + }, text_width: 80, completion_replace: false, + workspace_lsp_roots: Vec::new(), } } } @@ -844,7 +854,7 @@ pub struct Editor { pub config_events: (UnboundedSender, UnboundedReceiver), /// Allows asynchronous tasks to control the rendering /// The `Notify` allows asynchronous tasks to request the editor to perform a redraw - /// The `RwLock` blocks the editor from performing the render until an exclusive lock can be aquired + /// The `RwLock` blocks the editor from performing the render until an exclusive lock can be acquired pub redraw_handle: RedrawHandle, pub needs_redraw: bool, /// Cached position of the cursor calculated during rendering. @@ -1086,15 +1096,15 @@ impl Editor { } // if doc doesn't have a URL it's a scratch buffer, ignore it - let (lang, path) = { - let doc = self.document(doc_id)?; - (doc.language.clone(), doc.path().cloned()) - }; + let doc = self.document(doc_id)?; + let (lang, path) = (doc.language.clone(), doc.path().cloned()); + let config = doc.config.load(); + let root_dirs = &config.workspace_lsp_roots; // try to find a language server based on the language name let language_server = lang.as_ref().and_then(|language| { self.language_servers - .get(language, path.as_ref()) + .get(language, path.as_ref(), root_dirs, config.lsp.snippets) .map_err(|e| { log::error!( "Failed to initialize the LSP for `{}` {{ {} }}", @@ -1652,6 +1662,12 @@ impl Editor { doc.restore_cursor = false; } } + + pub fn current_stack_frame(&self) -> Option<&StackFrame> { + self.debugger + .as_ref() + .and_then(|debugger| debugger.current_stack_frame()) + } } fn try_restore_indent(doc: &mut Document, view: &mut View) { diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 36e8e16a4..3ecae9195 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -2,7 +2,7 @@ use std::fmt::Write; use crate::{ editor::GutterType, - graphics::{Color, Style, UnderlineStyle}, + graphics::{Style, UnderlineStyle}, Document, Editor, Theme, View, }; @@ -245,9 +245,9 @@ pub fn breakpoints<'doc>( theme: &Theme, _is_focused: bool, ) -> GutterFn<'doc> { - let warning = theme.get("warning"); let error = theme.get("error"); let info = theme.get("info"); + let breakpoint_style = theme.get("ui.debug.breakpoint"); let breakpoints = doc.path().and_then(|path| editor.breakpoints.get(path)); @@ -265,30 +265,52 @@ pub fn breakpoints<'doc>( .iter() .find(|breakpoint| breakpoint.line == line)?; - let mut style = if breakpoint.condition.is_some() && breakpoint.log_message.is_some() { + let style = if breakpoint.condition.is_some() && breakpoint.log_message.is_some() { error.underline_style(UnderlineStyle::Line) } else if breakpoint.condition.is_some() { error } else if breakpoint.log_message.is_some() { info } else { - warning + breakpoint_style }; - if !breakpoint.verified { - // Faded colors - style = if let Some(Color::Rgb(r, g, b)) = style.fg { - style.fg(Color::Rgb( - ((r as f32) * 0.4).floor() as u8, - ((g as f32) * 0.4).floor() as u8, - ((b as f32) * 0.4).floor() as u8, - )) - } else { - style.fg(Color::Gray) - } - }; + let sym = if breakpoint.verified { "●" } else { "◯" }; + write!(out, "{}", sym).unwrap(); + Some(style) + }, + ) +} + +fn execution_pause_indicator<'doc>( + editor: &'doc Editor, + doc: &'doc Document, + theme: &Theme, + is_focused: bool, +) -> GutterFn<'doc> { + let style = theme.get("ui.debug.active"); + let current_stack_frame = editor.current_stack_frame(); + let frame_line = current_stack_frame.map(|frame| frame.line - 1); + let frame_source_path = current_stack_frame.map(|frame| { + frame + .source + .as_ref() + .and_then(|source| source.path.as_ref()) + }); + let should_display_for_current_doc = + doc.path().is_some() && frame_source_path.unwrap_or(None) == doc.path(); + + Box::new( + move |line: usize, _selected: bool, first_visual_line: bool, out: &mut String| { + if !first_visual_line + || !is_focused + || line != frame_line? + || !should_display_for_current_doc + { + return None; + } - let sym = if breakpoint.verified { "▲" } else { "⊚" }; + let sym = "▶"; write!(out, "{}", sym).unwrap(); Some(style) }, @@ -304,9 +326,11 @@ pub fn diagnostics_or_breakpoints<'doc>( ) -> GutterFn<'doc> { let mut diagnostics = diagnostic(editor, doc, view, theme, is_focused); let mut breakpoints = breakpoints(editor, doc, view, theme, is_focused); + let mut execution_pause_indicator = execution_pause_indicator(editor, doc, theme, is_focused); Box::new(move |line, selected, first_visual_line: bool, out| { - breakpoints(line, selected, first_visual_line, out) + execution_pause_indicator(line, selected, first_visual_line, out) + .or_else(|| breakpoints(line, selected, first_visual_line, out)) .or_else(|| diagnostics(line, selected, first_visual_line, out)) }) } diff --git a/helix-view/src/handlers/dap.rs b/helix-view/src/handlers/dap.rs index 107c29be5..3da01494d 100644 --- a/helix-view/src/handlers/dap.rs +++ b/helix-view/src/handlers/dap.rs @@ -321,6 +321,7 @@ impl Editor { } } None => { + self.debugger = None; self.set_status( "Terminated debugging session and disconnected debugger.", ); diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 5d79ff26b..a8cc59260 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -128,7 +128,7 @@ impl Loader { let parent_palette = parent_theme_toml.get("palette"); let palette = theme_toml.get("palette"); - // handle the table seperately since it needs a `merge_depth` of 2 + // handle the table separately since it needs a `merge_depth` of 2 // this would conflict with the rest of the theme merge strategy let palette_values = match (parent_palette, palette) { (Some(parent_palette), Some(palette)) => { diff --git a/languages.toml b/languages.toml index 0a0e29bae..abf76d7c2 100644 --- a/languages.toml +++ b/languages.toml @@ -212,7 +212,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"] +file-types = ["cc", "hh", "c++", "cpp", "hpp", "h", "ipp", "tpp", "cxx", "hxx", "ixx", "txx", "ino", "C", "H", "cu", "cuh"] roots = [] comment-token = "//" language-server = { command = "clangd" } @@ -606,7 +606,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "ruby" -source = { git = "https://github.com/tree-sitter/tree-sitter-ruby", rev = "4c600a463d97e36a0ca5ac57e11f3ac8c297a0fa" } +source = { git = "https://github.com/tree-sitter/tree-sitter-ruby", rev = "206c7077164372c596ffa8eaadb9435c28941364" } [[language]] name = "bash" @@ -875,14 +875,14 @@ name = "haskell" scope = "source.haskell" injection-regex = "haskell" file-types = ["hs", "hs-boot"] -roots = ["Setup.hs", "stack.yaml", "*.cabal"] +roots = ["Setup.hs", "stack.yaml", "cabal.project"] comment-token = "--" language-server = { command = "haskell-language-server-wrapper", args = ["--lsp"] } indent = { tab-width = 2, unit = " " } [[grammar]] name = "haskell" -source = { git = "https://github.com/tree-sitter/tree-sitter-haskell", rev = "b6ec26f181dd059eedd506fa5fbeae1b8e5556c8" } +source = { git = "https://github.com/tree-sitter/tree-sitter-haskell", rev = "98fc7f59049aeb713ab9b72a8ff25dcaaef81087" } [[language]] name = "purescript" @@ -978,8 +978,8 @@ source = { git = "https://github.com/uyha/tree-sitter-cmake", rev = "6e51463ef30 [[language]] name = "make" scope = "source.make" -file-types = ["Makefile", "makefile", "mk", "Justfile", "justfile", ".justfile"] -injection-regex = "(make|makefile|Makefile|mk|just)" +file-types = ["Makefile", "makefile", "mk"] +injection-regex = "(make|makefile|Makefile|mk)" roots = [] comment-token = "#" indent = { tab-width = 4, unit = "\t" } @@ -1126,7 +1126,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "markdown" -source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "7e7aa9a25ca9729db9fe22912f8f47bdb403a979", subpath = "tree-sitter-markdown" } +source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "fa6bfd51727e4bef99f7eec5f43947f73d64ea7d", subpath = "tree-sitter-markdown" } [[language]] name = "markdown.inline" @@ -1138,7 +1138,7 @@ grammar = "markdown_inline" [[grammar]] name = "markdown_inline" -source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "7e7aa9a25ca9729db9fe22912f8f47bdb403a979", subpath = "tree-sitter-markdown-inline" } +source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "fa6bfd51727e4bef99f7eec5f43947f73d64ea7d", subpath = "tree-sitter-markdown-inline" } [[language]] name = "dart" @@ -1194,7 +1194,7 @@ text-width = 72 [[grammar]] name = "git-commit" -source = { git = "https://github.com/the-mikedavis/tree-sitter-git-commit", rev = "7421fd81840950c0ff4191733cee3b6ac06cb295" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-git-commit", rev = "db88cffa3952dd2328b741af5d0fc69bdb76704f" } [[language]] name = "diff" @@ -1425,7 +1425,7 @@ language-server = { command = "gleam", args = ["lsp"] } [[grammar]] name = "gleam" -source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "d6cbdf3477fcdb0b4d811518a356f9b5cd1795ed" } +source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "ae79782c00656945db69641378e688cdb78d52c1" } [[language]] name = "ron" @@ -1437,6 +1437,20 @@ comment-token = "//" indent = { tab-width = 4, unit = " " } grammar = "rust" +[[language]] +name = "robot" +scope = "source.robot" +injection-regex = "robot" +file-types = ["robot", "resource"] +comment-token = "#" +roots = [] +indent = { tab-width = 4, unit = " " } +language-server = { command = "robotframework_ls" } + +[[grammar]] +name = "robot" +source = { git = "https://github.com/Hubro/tree-sitter-robot", rev = "f1142bfaa6acfce95e25d2c6d18d218f4f533927" } + [[language]] name = "r" scope = "source.r" @@ -1446,7 +1460,7 @@ shebangs = ["r", "R"] roots = [] comment-token = "#" indent = { tab-width = 2, unit = " " } -language-server = { command = "R", args = ["--slave", "-e", "languageserver::run()"] } +language-server = { command = "R", args = ["--no-echo", "-e", "languageserver::run()"] } [[grammar]] name = "r" @@ -1545,6 +1559,7 @@ file-types = ["gd"] shebangs = [] roots = ["project.godot"] auto-format = true +formatter = { command = "gdformat", args = ["-"] } comment-token = "#" indent = { tab-width = 4, unit = "\t" } @@ -2068,7 +2083,7 @@ source = { git = "https://github.com/Unoqwy/tree-sitter-kdl", rev = "e1cd292c6d1 name = "xml" scope = "source.xml" injection-regex = "xml" -file-types = ["xml", "mobileconfig", "plist", "xib", "storyboard", "svg"] +file-types = ["xml", "mobileconfig", "plist", "xib", "storyboard", "svg", "xsd"] indent = { tab-width = 2, unit = " " } roots = [] @@ -2084,6 +2099,26 @@ roots = [] name = "xml" source = { git = "https://github.com/RenjiSann/tree-sitter-xml", rev = "48a7c2b6fb9d515577e115e6788937e837815651" } + +[[language]] +name = "dtd" +scope = "source.dtd" +injection-regex = "dtd" +file-types = ["dtd", "ent"] +indent = {tab-width = 2, unit = " "} +roots = [] + +[language.auto-pairs] +'(' = ')' +'[' = ']' +'"' = '"' +"'" = "'" +'<' = '>' + +[[grammar]] +name = "dtd" +source = { git = "https://github.com/KMikeeU/tree-sitter-dtd", rev = "6116becb02a6b8e9588ef73d300a9ba4622e156f"} + [[language]] name = "wit" scope = "source.wit" @@ -2364,7 +2399,7 @@ file-types = ["smithy"] roots = ["smithy-build.json"] comment-token = "//" indent = { tab-width = 4, unit = " " } -language-server = { command = "cs", args = ["launch", "com.disneystreaming.smithy:smithy-language-server:latest.release", "--", "0"] } +language-server = { command = "cs", args = ["launch", "--contrib", "smithy-language-server", "--", "0"] } [[grammar]] name = "smithy" @@ -2421,3 +2456,65 @@ language-server = { command = "nimlangserver" } [[grammar]] name = "nim" source = { git = "https://github.com/aMOPel/tree-sitter-nim", rev = "240239b232550e431d67de250d1b5856209e7f06" } + +[[language]] +name = "cabal" +scope = "source.cabal" +file-types = [ "cabal" ] +roots = ["cabal.project", "Setup.hs"] +indent = { tab-width = 2, unit = " " } +comment-token = "--" + +[[grammar]] +name = "cabal" +source = { git = "https://gitlab.com/magus/tree-sitter-cabal", rev = "7d5fa6887ae05a0b06d046f1e754c197c8ad869b" } + +[[language]] +name = "hurl" +scope = "source.hurl" +injection-regex = "hurl" +file-types = ["hurl"] +roots = [] +comment-token = "#" +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "hurl" +source = { git = "https://github.com/pfeiferj/tree-sitter-hurl", rev = "264c42064b61ee21abe88d0061f29a0523352e22" } + +[[language]] +name = "markdoc" +scope = "text.markdoc" +roots = [] +file-types = ["mdoc"] +language-server = { command = "markdoc-ls", args = ["--stdio"] } + +[[grammar]] +name = "markdoc" +source = { git = "https://github.com/markdoc-extra/tree-sitter-markdoc", rev = "5ffe71b29e8a3f94823913ea9cea51fcfa7e3bf8" } + +[[language]] +name = "opencl" +scope = "source.cl" +injection-regex = "(cl|opencl)" +file-types = ["cl"] +roots = [] +comment-token = "//" +language-server = { command = "clangd" } + +[[grammar]] +name = "opencl" +source = { git = "https://github.com/lefp/tree-sitter-opencl", rev = "8e1d24a57066b3cd1bb9685bbc1ca9de5c1b78fb" } + +[[language]] +name = "just" +scope = "source.just" +file-types = ["justfile", "Justfile", "just"] +injection-regex = "just" +roots = [] +comment-token = "#" +indent = { tab-width = 4, unit = "\t" } + +[[grammar]] +name = "just" +source = { git = "https://github.com/IndianBoy42/tree-sitter-just", rev = "8af0aab79854aaf25b620a52c39485849922f766" } diff --git a/runtime/queries/c/highlights.scm b/runtime/queries/c/highlights.scm index 8122216d8..07915f4e3 100644 --- a/runtime/queries/c/highlights.scm +++ b/runtime/queries/c/highlights.scm @@ -107,6 +107,7 @@ (null) @constant (number_literal) @constant.numeric (char_literal) @constant.character +(escape_sequence) @constant.character.escape (call_expression function: (identifier) @function) diff --git a/runtime/queries/cabal/highlights.scm b/runtime/queries/cabal/highlights.scm new file mode 100644 index 000000000..d6b9f4627 --- /dev/null +++ b/runtime/queries/cabal/highlights.scm @@ -0,0 +1,15 @@ +(comment) @comment + +[ + "cabal-version" + (field_name) +] @type + +(section_name) @type + +[ + (section_type) + "if" + "elseif" + "else" +] @keyword diff --git a/runtime/queries/dtd/highlights.scm b/runtime/queries/dtd/highlights.scm new file mode 100644 index 000000000..cb3d482b5 --- /dev/null +++ b/runtime/queries/dtd/highlights.scm @@ -0,0 +1,39 @@ +; highlights.scm + +(comment) @comment + +[ + "ELEMENT" + "ATTLIST" +] @keyword + +[ + "#REQUIRED" + "#IMPLIED" + "#FIXED" + "#PCDATA" +] @keyword.directive + +[ + "EMPTY" + "ANY" + "SYSTEM" + "PUBLIC" +] @constant + +(element_name) @module + + +(attribute_name) @attribute + +(system_literal) @string +(pubid_literal) @string +(attribute_value) @string + +[ + ">" + "" + "" (scissors)] @punctuation.delimiter +(trailer + key: (trailer_key) @variable.other.member + value: (trailer_value) @string) + +[":" "=" "->" (scissors)] @punctuation.delimiter (comment) @comment diff --git a/runtime/queries/gleam/highlights.scm b/runtime/queries/gleam/highlights.scm index 34b3ce65c..56222b8fd 100644 --- a/runtime/queries/gleam/highlights.scm +++ b/runtime/queries/gleam/highlights.scm @@ -77,6 +77,7 @@ "if" "import" "let" + "panic" "todo" "try" "type" diff --git a/runtime/queries/go/indents.scm b/runtime/queries/go/indents.scm index e439a9055..b2befab08 100644 --- a/runtime/queries/go/indents.scm +++ b/runtime/queries/go/indents.scm @@ -14,8 +14,6 @@ (argument_list) (field_declaration_list) (block) - (type_switch_statement) - (expression_switch_statement) (var_declaration) ] @indent @@ -24,5 +22,19 @@ ")" ] @outdent -((_ "}" @outdent) @outer (#not-kind-eq? @outer "select_statement")) -(communication_case) @extend +; Switches and selects aren't indented, only their case bodies are. +; Outdent all closing braces except those closing switches or selects. +( + (_ "}" @outdent) @outer + (#not-kind-eq? @outer "select_statement") + (#not-kind-eq? @outer "type_switch_statement") + (#not-kind-eq? @outer "expression_switch_statement") +) + +; Starting a line after a new case should indent. +[ + (communication_case) + (expression_case) + (default_case) + (type_case) +] @extend diff --git a/runtime/queries/go/locals.scm b/runtime/queries/go/locals.scm index d240e2b78..aae562571 100644 --- a/runtime/queries/go/locals.scm +++ b/runtime/queries/go/locals.scm @@ -12,7 +12,7 @@ (identifier) @local.definition)) (var_spec - name: (identifier) @local.definition) + (identifier) @local.definition) (for_statement (range_clause diff --git a/runtime/queries/haskell/injections.scm b/runtime/queries/haskell/injections.scm index 321c90add..788b8b8c6 100644 --- a/runtime/queries/haskell/injections.scm +++ b/runtime/queries/haskell/injections.scm @@ -1,2 +1,6 @@ ((comment) @injection.content (#set! injection.language "comment")) + +(quasiquote + (quoter) @injection.language + (quasiquote_body) @injection.content) diff --git a/runtime/queries/haskell/textobjects.scm b/runtime/queries/haskell/textobjects.scm index 9870dc4a4..457fba1a7 100644 --- a/runtime/queries/haskell/textobjects.scm +++ b/runtime/queries/haskell/textobjects.scm @@ -2,7 +2,7 @@ [ (adt) - (decl_type) + (type_alias) (newtype) ] @class.around diff --git a/runtime/queries/hurl/highlights.scm b/runtime/queries/hurl/highlights.scm new file mode 100644 index 000000000..c066b2844 --- /dev/null +++ b/runtime/queries/hurl/highlights.scm @@ -0,0 +1,127 @@ +[ + "[QueryStringParams]" + "[FormParams]" + "[MultipartFormData]" + "[Cookies]" + "[Captures]" + "[Asserts]" + "[Options]" + "[BasicAuth]" +] @attribute + +(comment) @comment + +[ + (key_string) + (json_key_string) +] @variable.other.member + +(value_string) @string +(quoted_string) @string +(json_string) @string +(file_value) @string.special.path +(regex) @string.regex + +[ + "\\" + (regex_escaped_char) + (quoted_string_escaped_char) + (key_string_escaped_char) + (value_string_escaped_char) + (oneline_string_escaped_char) + (multiline_string_escaped_char) + (filename_escaped_char) + (json_string_escaped_char) +] @constant.character.escape + +(method) @type.builtin +(multiline_string_type) @type + +[ + "status" + "url" + "header" + "cookie" + "body" + "xpath" + "jsonpath" + "regex" + "variable" + "duration" + "sha256" + "md5" + "bytes" +] @function.builtin + +(filter) @attribute + +(version) @string.special +[ + "null" + "cacert" + "location" + "insecure" + "max-redirs" + "retry" + "retry-interval" + "retry-max-count" + (variable_option "variable") + "verbose" + "very-verbose" +] @constant.builtin + +(boolean) @constant.builtin.boolean + +(variable_name) @variable + +[ + "not" + "equals" + "==" + "notEquals" + "!=" + "greaterThan" + ">" + "greaterThanOrEquals" + ">=" + "lessThan" + "<" + "lessThanOrEquals" + "<=" + "startsWith" + "endsWith" + "contains" + "matches" + "exists" + "includes" + "isInteger" + "isFloat" + "isBoolean" + "isString" + "isCollection" +] @keyword.operator + +(integer) @constant.numeric.integer +(float) @constant.numeric.float +(status) @constant.numeric +(json_number) @constant.numeric.float + +[ + ":" + "," +] @punctuation.delimiter + +[ + "[" + "]" + "{" + "}" + "{{" + "}}" +] @punctuation.special + +[ + "base64," + "file," + "hex," +] @string.special \ No newline at end of file diff --git a/runtime/queries/hurl/indents.scm b/runtime/queries/hurl/indents.scm new file mode 100644 index 000000000..d436f76fd --- /dev/null +++ b/runtime/queries/hurl/indents.scm @@ -0,0 +1,11 @@ +[ + (json_object) + (json_array) + (xml_tag) +] @indent + +[ + "}" + "]" + (xml_close_tag) +] @outdent diff --git a/runtime/queries/hurl/injections.scm b/runtime/queries/hurl/injections.scm new file mode 100644 index 000000000..a0d238173 --- /dev/null +++ b/runtime/queries/hurl/injections.scm @@ -0,0 +1,14 @@ +((comment) @injection.content + (#set! injection.language "comment")) + +((json_value) @injection.content + (#set! injection.language "json")) + +((xml) @injection.content + (#set! injection.language "xml")) + +((multiline_string + (multiline_string_type) @injection.language + (multiline_string_content) @injection.content) + (#set! injection.include-children) + (#set! injection.combined)) diff --git a/runtime/queries/julia/indents.scm b/runtime/queries/julia/indents.scm new file mode 100644 index 000000000..08f55aa7f --- /dev/null +++ b/runtime/queries/julia/indents.scm @@ -0,0 +1,16 @@ +[ + (struct_definition) + (macro_definition) + (function_definition) + (compound_expression) + (let_statement) + (if_statement) + (for_statement) + (while_statement) + (do_clause) + (parameter_list) +] @indent + +[ + "end" +] @outdent diff --git a/runtime/queries/julia/injections.scm b/runtime/queries/julia/injections.scm index ce4011f20..fd174a4a0 100644 --- a/runtime/queries/julia/injections.scm +++ b/runtime/queries/julia/injections.scm @@ -26,3 +26,9 @@ prefix: (identifier) @function.macro) @injection.content (#eq? @function.macro "re") (#set! injection.language "regex")) + +( + (prefixed_string_literal + prefix: (identifier) @function.macro) @injection.content + (#eq? @function.macro "md") + (#set! injection.language "markdown")) diff --git a/runtime/queries/julia/textobjects.scm b/runtime/queries/julia/textobjects.scm new file mode 100644 index 000000000..1927c2b18 --- /dev/null +++ b/runtime/queries/julia/textobjects.scm @@ -0,0 +1,46 @@ +(function_definition (_)? @function.inside) @function.around + +(short_function_definition (_)? @function.inside) @function.around + +(macro_definition (_)? @function.inside) @function.around + +(struct_definition (_)? @class.inside) @class.around + +(abstract_definition (_)? @class.inside) @class.around + +(primitive_definition (_)? @class.inside) @class.around + +(parameter_list + ; Match all children of parameter_list *except* keyword_parameters + ([(identifier) + (slurp_parameter) + (optional_parameter) + (typed_parameter) + (tuple_expression) + (interpolation_expression) + (call_expression)] + @parameter.inside . ","? @parameter.around) @parameter.around) + +(keyword_parameters + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +(argument_list + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +(type_parameter_list + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +(line_comment) @comment.inside + +(line_comment)+ @comment.around + +(block_comment) @comment.inside + +(block_comment)+ @comment.around + +(_expression (macro_identifier + (identifier) @_name + (#match? @_name "^(test|test_throws|test_logs|inferred|test_deprecated|test_warn|test_nowarn|test_broken|test_skip)$") + ) + . + (macro_argument_list) @test.inside) @test.around diff --git a/runtime/queries/just/folds.scm b/runtime/queries/just/folds.scm new file mode 100644 index 000000000..6fc68fbd4 --- /dev/null +++ b/runtime/queries/just/folds.scm @@ -0,0 +1,4 @@ +(body) @fold +(recipe) @fold +(interpolation) @fold +(item (_) @fold) diff --git a/runtime/queries/just/highlights.scm b/runtime/queries/just/highlights.scm new file mode 100644 index 000000000..1026f654f --- /dev/null +++ b/runtime/queries/just/highlights.scm @@ -0,0 +1,33 @@ +(assignment (NAME) @variable) +(alias (NAME) @variable) +(value (NAME) @variable) +(parameter (NAME) @variable) +(setting (NAME) @keyword) +(setting "shell" @keyword) + +(call (NAME) @function) +(dependency (NAME) @function) +(depcall (NAME) @function) +(recipeheader (NAME) @function) + +(depcall (expression) @variable.parameter) +(parameter) @variable.parameter +(variadic_parameters) @variable.parameter + +["if" "else"] @keyword.control.conditional + +(string) @string + +(boolean ["true" "false"]) @constant.builtin.boolean + +(comment) @comment + +; (interpolation) @string + +(shebang interpreter:(TEXT) @keyword ) @comment + +["export" "alias" "set"] @keyword + +["@" "==" "!=" "+" ":="] @operator + +[ "(" ")" "[" "]" "{{" "}}" "{" "}"] @punctuation.bracket diff --git a/runtime/queries/just/indents.scm b/runtime/queries/just/indents.scm new file mode 100644 index 000000000..3db597466 --- /dev/null +++ b/runtime/queries/just/indents.scm @@ -0,0 +1,3 @@ +[ + (recipe_body) +] @indent diff --git a/runtime/queries/just/injections.scm b/runtime/queries/just/injections.scm new file mode 100644 index 000000000..cae1035ae --- /dev/null +++ b/runtime/queries/just/injections.scm @@ -0,0 +1,16 @@ +((comment) @injection.content + (#set! injection.language "comment")) + +(shebang_recipe + (shebang + interpreter:(TEXT) @injection.language) + (shebang_body) @injection.content +) + +(source_file + (item (setting lang:(NAME) @injection.language)) + (item (recipe (body (recipe_body) @injection.content))) +) + +; ((interpolation (expression) @injection.content) +; (#set! injection.language "just")) diff --git a/runtime/queries/just/locals.scm b/runtime/queries/just/locals.scm new file mode 100644 index 000000000..18e162a97 --- /dev/null +++ b/runtime/queries/just/locals.scm @@ -0,0 +1,10 @@ +(assignment (NAME) @local.definition) +(alias left:(NAME) @local.definition) +(alias right:(NAME) @local.reference) +(value (NAME) @local.reference) +(parameter (NAME) @local.definition) + +(call (NAME) @local.reference) +(dependency (NAME) @local.reference) +(depcall (NAME) @local.reference) +(recipeheader (NAME) @local.definition) diff --git a/runtime/queries/just/textobjects.scm b/runtime/queries/just/textobjects.scm new file mode 100644 index 000000000..4be379587 --- /dev/null +++ b/runtime/queries/just/textobjects.scm @@ -0,0 +1,48 @@ +(body) @function.inside +(recipe) @function.around +(expression + if:(expression) @function.inside +) +(expression + else:(expression) @function.inside +) +(interpolation (expression) @function.inside) @function.around +(settinglist (stringlist) @function.inside) @function.around + +(call (NAME) @class.inside) @class.around +(dependency (NAME) @class.inside) @class.around +(depcall (NAME) @class.inside) + +(dependency) @parameter.around +(depcall) @parameter.inside +(depcall (expression) @parameter.inside) + +(stringlist + (string) @parameter.inside + . ","? @_end + ; Commented out since we don't support `#make-range!` at the moment + ; (#make-range! "parameter.around" @parameter.inside @_end) +) +(parameters + [(parameter) + (variadic_parameters)] @parameter.inside + . " "? @_end + ; Commented out since we don't support `#make-range!` at the moment + ; (#make-range! "parameter.around" @parameter.inside @_end) +) + +(expression + (condition) @function.inside +) @function.around +(expression + if:(expression) @function.inside +) +(expression + else:(expression) @function.inside +) + +(item [(alias) (assignment) (export) (setting)]) @class.around +(recipeheader) @class.around +(line) @class.around + +(comment) @comment.around diff --git a/runtime/queries/markdoc/highlights.scm b/runtime/queries/markdoc/highlights.scm new file mode 100644 index 000000000..8251e9afe --- /dev/null +++ b/runtime/queries/markdoc/highlights.scm @@ -0,0 +1,16 @@ +tag_name: (identifier) @tag +(tag_self_closing "/" @tag) +(tag_close "/" @tag) +([(tag_start) (tag_end) "="] @tag) +(attribute [key : (identifier)] @attribute) +(attribute [shorthand : (identifier)] @attribute) +(variable [variable : (identifier) (variable_sigil)] @variable) +(variable_tail property : (identifier) @variable.other.member) +(function function_name : (identifier) @function) +(function_parameter_named parameter : (identifier) @variable.parameter) + +(hash_key key: (identifier) @variable.other.member) +(string) @string +(number) @constant.numeric +(boolean) @constant.builtin.boolean +(null) @constant.builtin diff --git a/runtime/queries/markdoc/injections.scm b/runtime/queries/markdoc/injections.scm new file mode 100644 index 000000000..1594546ba --- /dev/null +++ b/runtime/queries/markdoc/injections.scm @@ -0,0 +1,2 @@ +((markdown) @injection.content + (#set! injection.language "markdown")) diff --git a/runtime/queries/opencl/highlights.scm b/runtime/queries/opencl/highlights.scm new file mode 100644 index 000000000..9d76d6c66 --- /dev/null +++ b/runtime/queries/opencl/highlights.scm @@ -0,0 +1,150 @@ +[ + "sizeof" + ; @todo why does "uniform" break highlighting? + ; "uniform" ; OpenCL C 3.0.13 reserves this as a keyword, but doesn't seem to use it for anything + (function_qualifier) +] @keyword + +[ + "enum" + "struct" + "typedef" + "union" +] @keyword.storage.type + +[ + "extern" + "register" + (type_qualifier) + (access_qualifier) + (storage_class_specifier) + (address_space_qualifier) +] @keyword.storage.modifier + +[ + "goto" + "break" + "continue" +] @keyword.control + +[ + "do" + "for" + "while" +] @keyword.control.repeat + +[ + "if" + "else" + "switch" + "case" + "default" +] @keyword.control.conditional + +"return" @keyword.control.return + +[ + "defined" + "#define" + "#elif" + "#else" + "#endif" + "#if" + "#ifdef" + "#ifndef" + "#include" + (preproc_directive) +] @keyword.directive + +(pointer_declarator "*" @type.builtin) +(abstract_pointer_declarator "*" @type.builtin) + +[ + "+" + "-" + "*" + "/" + "++" + "--" + "%" + "==" + "!=" + ">" + "<" + ">=" + "<=" + "&&" + "||" + "!" + "&" + "|" + "^" + "~" + "<<" + ">>" + "=" + "+=" + "-=" + "*=" + "/=" + "%=" + "<<=" + ">>=" + "&=" + "^=" + "|=" + "?" +] @operator + +(conditional_expression ":" @operator) + +"..." @punctuation + +["," "." ":" ";" "->" "::"] @punctuation.delimiter + +["(" ")" "[" "]" "{" "}"] @punctuation.bracket + +[(true) (false)] @constant.builtin.boolean + +(enumerator name: (identifier) @type.enum.variant) + +(string_literal) @string +(system_lib_string) @string + +(null) @constant +(number_literal) @constant.numeric +(char_literal) @constant.character + +(call_expression + function: (identifier) @function) +(call_expression + function: (field_expression + field: (field_identifier) @function)) +(call_expression (argument_list (identifier) @variable)) +(function_declarator + declarator: [(identifier) (field_identifier)] @function) +(parameter_declaration + declarator: (identifier) @variable.parameter) +(parameter_declaration + (pointer_declarator + declarator: (identifier) @variable.parameter)) +(preproc_function_def + name: (identifier) @function.special) + +(attribute + name: (identifier) @attribute) + +(field_identifier) @variable.other.member +(statement_identifier) @label +(type_identifier) @type +(scalar_type) @type.builtin +(sized_type_specifier) @type.builtin +(vector_type) @type.builtin +(other_builtin_type) @type.builtin + +((identifier) @constant + (#match? @constant "^[A-Z][A-Z\\d_]*$")) + +(identifier) @variable + +(comment) @comment diff --git a/runtime/queries/opencl/indents.scm b/runtime/queries/opencl/indents.scm new file mode 100644 index 000000000..a5a5208ca --- /dev/null +++ b/runtime/queries/opencl/indents.scm @@ -0,0 +1 @@ +; inherits: c diff --git a/runtime/queries/opencl/injections.scm b/runtime/queries/opencl/injections.scm new file mode 100644 index 000000000..a5a5208ca --- /dev/null +++ b/runtime/queries/opencl/injections.scm @@ -0,0 +1 @@ +; inherits: c diff --git a/runtime/queries/opencl/textobjects.scm b/runtime/queries/opencl/textobjects.scm new file mode 100644 index 000000000..a5a5208ca --- /dev/null +++ b/runtime/queries/opencl/textobjects.scm @@ -0,0 +1 @@ +; inherits: c diff --git a/runtime/queries/python/highlights.scm b/runtime/queries/python/highlights.scm index 70b91efbe..0c6a83c54 100644 --- a/runtime/queries/python/highlights.scm +++ b/runtime/queries/python/highlights.scm @@ -94,7 +94,7 @@ ; Variables ((identifier) @constant - (#match? @constant "^[A-Z_]{2,}$")) + (#match? @constant "^_*[A-Z][A-Z\\d_]*$")) ((identifier) @type (#match? @type "^[A-Z]")) diff --git a/runtime/queries/robot/highlights.scm b/runtime/queries/robot/highlights.scm new file mode 100644 index 000000000..60f416b7b --- /dev/null +++ b/runtime/queries/robot/highlights.scm @@ -0,0 +1,21 @@ +(comment) @comment +(ellipses) @punctuation.delimiter + +(section_header) @keyword +(extra_text) @comment + +(setting_statement) @keyword + +(variable_definition (variable_name) @variable) + +(keyword_definition (name) @function) +(keyword_definition (body (keyword_setting) @keyword)) + +(test_case_definition (name) @property) + +(keyword_invocation (keyword) @function) + +(argument (text_chunk) @string) +(argument (scalar_variable) @string.special) +(argument (list_variable) @string.special) +(argument (dictionary_variable) @string.special) diff --git a/runtime/queries/ruby/highlights.scm b/runtime/queries/ruby/highlights.scm index 898f8f794..7c69276ba 100644 --- a/runtime/queries/ruby/highlights.scm +++ b/runtime/queries/ruby/highlights.scm @@ -1,44 +1,67 @@ ; Keywords [ + "BEGIN" + "END" "alias" - "and" "begin" - "break" - "case" "class" - "def" "do" - "else" - "elsif" "end" - "ensure" - "for" - "if" - "in" "module" - "next" - "or" + "in" "rescue" - "retry" - "return" - "then" - "unless" - "until" + "ensure" +] @keyword + +[ + "if" + "else" + "elsif" "when" + "case" + "unless" + "then" +] @keyword.control.conditional + +[ + "for" "while" + "retry" + "until" + "redo" +] @keyword.control.repeat + +[ "yield" -] @keyword + "return" + "next" + "break" +] @keyword.control.return + +[ + "def" + "undef" +] @keyword.function + +((identifier) @keyword.control.import + (#match? @keyword.control.import "^(require|require_relative|load|autoload)$")) + +[ + "or" + "and" + "not" +] @keyword.operator -((identifier) @keyword - (#match? @keyword "^(private|protected|public)$")) +((identifier) @keyword.control.exception + (#match? @keyword.control.exception "^(raise|fail)$")) ; Function calls -((identifier) @function.method.builtin - (#eq? @function.method.builtin "require")) +((identifier) @function.builtin + (#match? @function.builtin "^(attr|attr_accessor|attr_reader|attr_writer|include|prepend|refine|private|protected|public)$")) -"defined?" @function.method.builtin +"defined?" @function.builtin (call method: [(identifier) (constant)] @function.method) @@ -58,7 +81,10 @@ ] @variable.other.member ((identifier) @constant.builtin - (#match? @constant.builtin "^__(FILE|LINE|ENCODING)__$")) + (#match? @constant.builtin "^(__FILE__|__LINE__|__ENCODING__)$")) + +((constant) @constant.builtin + (#match? @constant.builtin "^(ENV|ARGV|ARGF|RUBY_PLATFORM|RUBY_RELEASE_DATE|RUBY_VERSION|STDERR|STDIN|STDOUT|TOPLEVEL_BINDING)$")) ((constant) @constant (#match? @constant "^[A-Z\\d_]+$")) @@ -66,22 +92,23 @@ (constant) @constructor (self) @variable.builtin -(super) @variable.builtin +(super) @function.builtin +[(forward_parameter)(forward_argument)] @variable.parameter +(keyword_parameter name:((_)":" @variable.parameter) @variable.parameter) +(optional_parameter name:((_)"=" @operator) @variable.parameter) +(optional_parameter name: (identifier) @variable.parameter) +(splat_parameter name: (identifier) @variable.parameter) @variable.parameter +(hash_splat_parameter name: (identifier) @variable.parameter) @variable.parameter +(method_parameters (identifier) @variable.parameter) (block_parameter (identifier) @variable.parameter) (block_parameters (identifier) @variable.parameter) -(destructured_parameter (identifier) @variable.parameter) -(hash_splat_parameter (identifier) @variable.parameter) -(lambda_parameters (identifier) @variable.parameter) -(method_parameters (identifier) @variable.parameter) -(splat_parameter (identifier) @variable.parameter) - -(keyword_parameter name: (identifier) @variable.parameter) -(optional_parameter name: (identifier) @variable.parameter) ((identifier) @function.method (#is-not? local)) -(identifier) @variable +[ + (identifier) +] @variable ; Literals @@ -96,10 +123,11 @@ [ (simple_symbol) (delimited_symbol) - (hash_key_symbol) (bare_symbol) ] @string.special.symbol +(pair key: ((_)":" @string.special.symbol) @string.special.symbol) + (regex) @string.regexp (escape_sequence) @constant.character.escape @@ -112,7 +140,7 @@ (nil) (true) (false) -]@constant.builtin +] @constant.builtin (interpolation "#{" @punctuation.special @@ -121,20 +149,36 @@ (comment) @comment ; Operators - [ -"=" +":" +"?" +"~" "=>" "->" +"!" ] @operator +(assignment + "=" @operator) + +(operator_assignment + operator: ["+=" "-=" "*=" "**=" "/=" "||=" "|=" "&&=" "&=" "%=" ">>=" "<<=" "^="] @operator) + +(binary + operator: ["/" "|" "==" "===" "||" "&&" ">>" "<<" "<" ">" "<=" ">=" "&" "^" "!~" "=~" "<=>" "**" "*" "!=" "%" "-" "+"] @operator) + +(range + operator: [".." "..."] @operator) + [ "," ";" "." + "&." ] @punctuation.delimiter [ + "|" "(" ")" "[" diff --git a/runtime/queries/ruby/injections.scm b/runtime/queries/ruby/injections.scm index 321c90add..1a865df19 100644 --- a/runtime/queries/ruby/injections.scm +++ b/runtime/queries/ruby/injections.scm @@ -1,2 +1,8 @@ ((comment) @injection.content (#set! injection.language "comment")) + +((heredoc_body + (heredoc_content) @injection.content + (heredoc_end) @name + (#set! injection.language "sql")) + (#eq? @name "SQL")) diff --git a/runtime/themes/acme.toml b/runtime/themes/acme.toml index e1d66ff8f..650924741 100644 --- a/runtime/themes/acme.toml +++ b/runtime/themes/acme.toml @@ -12,6 +12,8 @@ "ui.virtual.ruler" = { bg = "acme_bar_bg" } "ui.cursor.match" = {bg="acme_bar_bg"} "ui.cursor" = {bg="cursor", fg="white"} +"ui.debug" = {fg="orange"} +"ui.highlight.frameline" = {bg="#da8581"} "string" = "red" "comment" = "green" "ui.help" = {fg="black", bg="acme_bg"} diff --git a/runtime/themes/autumn.toml b/runtime/themes/autumn.toml index 1430e0a8e..4474b0d41 100644 --- a/runtime/themes/autumn.toml +++ b/runtime/themes/autumn.toml @@ -26,6 +26,8 @@ "ui.cursor.primary" = { fg = "my_white", modifiers = ["reversed"] } "ui.cursorline.primary" = { bg = "my_black" } "ui.cursorline.secondary" = { bg = "my_black" } +"ui.highlight.frameline" = { bg = "#8b6904" } +"ui.debug" = { fg = "my_yellow1", bg = "my_gray0" } "ui.text" = "my_white" "operator" = "my_white" "ui.text.focus" = "my_white" diff --git a/runtime/themes/ayu_dark.toml b/runtime/themes/ayu_dark.toml index 37060a244..0b011b0ea 100644 --- a/runtime/themes/ayu_dark.toml +++ b/runtime/themes/ayu_dark.toml @@ -22,7 +22,10 @@ "namespace" = "blue" "markup.heading" = "orange" "markup.list" = "yellow" -"markup.raw.block" = { bg = "gray", fg = "orange" } +"markup.bold" = { fg = "orange", modifiers = ["bold"] } +"markup.italic" = { fg = "orange", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } +"markup.raw.block" = "orange" "markup.link.url" = "blue" "markup.link.text" = "yellow" "markup.link.label" = "green" @@ -33,11 +36,15 @@ # Interface "ui.background"= { bg = "background" } -"ui.cursor" = { fg = "dark_gray", bg = "orange" } +"ui.cursor" = { fg = "dark_gray", bg = "yellow" } +"ui.cursor.primary" = { fg = "dark_gray", bg = "orange" } "ui.cursor.match" = "orange" "ui.linenr" = "dark_gray" "ui.linenr.selected" = "gray" "ui.statusline" = { fg = "foreground", bg = "black" } +"ui.statusline.normal" = { fg = "black", bg = "blue" } +"ui.statusline.insert" = { fg = "black", bg = "orange" } +"ui.statusline.select" = { fg = "black", bg = "magenta" } "ui.cursorline" = { bg = "black" } "ui.popup" = { fg = "#7B91b3", bg = "black" } "ui.window" = "dark_gray" @@ -61,6 +68,8 @@ "diagnostic.error"= { underline = { color = "red", style="curl"} } "ui.bufferline" = { fg = "gray", bg = "background" } "ui.bufferline.active" = { fg = "foreground", bg = "dark_gray" } +"ui.debug" = { fg = "orange", bg = "background" } +"ui.highlight.frameline" = { bg = "#0067a3" } "special" = "orange" diff --git a/runtime/themes/ayu_light.toml b/runtime/themes/ayu_light.toml index 58b25484c..6c405381d 100644 --- a/runtime/themes/ayu_light.toml +++ b/runtime/themes/ayu_light.toml @@ -22,8 +22,11 @@ "namespace" = "blue" "markup.heading" = "orange" "markup.list" = "yellow" -"markup.raw.block" = { bg = "gray", fg = "orange" } -"markup.link.url" = "blue" +"markup.bold" = { fg = "orange", modifiers = ["bold"] } +"markup.italic" = { fg = "orange", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } +"markup.raw.block" = "orange" +"markup.link.url" = { fg = "blue", modifiers = ["underlined"] } "markup.link.text" = "yellow" "markup.link.label" = "green" "markup.quote" = "yellow" @@ -33,11 +36,15 @@ # Interface "ui.background"= { bg = "background" } -"ui.cursor" = { fg = "dark_gray", bg = "orange" } +"ui.cursor" = { fg = "dark_gray", bg = "yellow" } +"ui.cursor.primary" = { fg = "dark_gray", bg = "orange" } "ui.cursor.match" = "orange" "ui.linenr" = "dark_gray" "ui.linenr.selected" = "gray" "ui.statusline" = { fg = "foreground", bg = "black" } +"ui.statusline.normal" = { fg = "black", bg = "blue" } +"ui.statusline.insert" = { fg = "black", bg = "orange" } +"ui.statusline.select" = { fg = "black", bg = "magenta" } "ui.cursorline" = { bg = "black" } "ui.popup" = { fg = "#7B91b3", bg = "black" } "ui.window" = "dark_gray" @@ -61,6 +68,8 @@ "diagnostic.error"= { underline = { color = "red", style = "curl" } } "ui.bufferline" = { fg = "gray", bg = "background" } "ui.bufferline.active" = { fg = "foreground", bg = "dark_gray" } +"ui.debug" = { fg = "orange", bg = "background" } +"ui.highlight.frameline" = { bg = "#cfe0f2" } "special" = "orange" diff --git a/runtime/themes/ayu_mirage.toml b/runtime/themes/ayu_mirage.toml index 4c1f8fa65..a4b74fcfb 100644 --- a/runtime/themes/ayu_mirage.toml +++ b/runtime/themes/ayu_mirage.toml @@ -22,7 +22,10 @@ "namespace" = "blue" "markup.heading" = "orange" "markup.list" = "yellow" -"markup.raw.block" = { bg = "gray", fg = "orange" } +"markup.bold" = { fg = "orange", modifiers = ["bold"] } +"markup.italic" = { fg = "orange", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } +"markup.raw.block" = "orange" "markup.link.url" = "blue" "markup.link.text" = "yellow" "markup.link.label" = "green" @@ -33,11 +36,15 @@ # Interface "ui.background"= { bg = "background" } -"ui.cursor" = { fg = "dark_gray", bg = "orange" } +"ui.cursor" = { fg = "dark_gray", bg = "yellow" } +"ui.cursor.primary" = { fg = "dark_gray", bg = "orange" } "ui.cursor.match" = "orange" "ui.linenr" = "dark_gray" "ui.linenr.selected" = "gray" "ui.statusline" = { fg = "foreground", bg = "black" } +"ui.statusline.normal" = { fg = "black", bg = "blue" } +"ui.statusline.insert" = { fg = "black", bg = "orange" } +"ui.statusline.select" = { fg = "black", bg = "magenta" } "ui.cursorline" = { bg = "black" } "ui.popup" = { fg = "#7B91b3", bg = "black" } "ui.window" = "dark_gray" @@ -61,6 +68,8 @@ "diagnostic.error"= { underline = { color = "red", style = "curl" } } "ui.bufferline" = { fg = "gray", bg = "background" } "ui.bufferline.active" = { fg = "foreground", bg = "dark_gray" } +"ui.debug" = { fg = "orange", bg = "background" } +"ui.highlight.frameline" = { bg = "#0067a3" } "special" = "orange" diff --git a/runtime/themes/base16_transparent.toml b/runtime/themes/base16_transparent.toml index fd07cb281..c314ae8c5 100644 --- a/runtime/themes/base16_transparent.toml +++ b/runtime/themes/base16_transparent.toml @@ -3,13 +3,15 @@ "ui.background" = { fg = "white"} "ui.background.separator" = { fg = "gray" } +"ui.text" = { fg = "light-gray" } +"ui.text.focus" = { fg = "white" } "ui.menu" = { fg = "white" } "ui.menu.selected" = { modifiers = ["reversed"] } "ui.menu.scroll" = { fg = "light-gray" } "ui.linenr" = { fg = "light-gray" } "ui.linenr.selected" = { fg = "white", modifiers = ["bold"] } "ui.popup" = { fg = "white" } -"ui.window" = { fg = "white" } +"ui.window" = { fg = "gray" } "ui.selection" = { bg = "gray" } "comment" = "light-gray" "ui.statusline" = { fg = "white" } @@ -25,6 +27,10 @@ "ui.virtual.ruler" = { bg = "gray" } "ui.virtual.whitespace" = "gray" "ui.virtual.indent-guide" = "gray" +"ui.virtual.inlay-hint" = { fg = "white", bg = "gray" } +"ui.virtual.inlay-hint.parameter" = { fg = "white", bg = "gray"} +"ui.virtual.inlay-hint.type" = { fg = "white", bg = "gray"} +"ui.virtual.wrap" = "gray" "variable" = "light-red" "constant.numeric" = "yellow" diff --git a/runtime/themes/boo_berry.toml b/runtime/themes/boo_berry.toml index 62e3b372c..d3a3e2232 100644 --- a/runtime/themes/boo_berry.toml +++ b/runtime/themes/boo_berry.toml @@ -52,6 +52,7 @@ "ui.virtual.whitespace" = { fg = "berry_desaturated" } "ui.virtual.ruler" = { bg = "berry_dim" } "ui.virtual.indent-guide" = { fg = "berry_fade" } +"ui.virtual.inlay-hint" = { fg = "berry_desaturated" } "diff.plus" = { fg = "mint" } "diff.delta" = { fg = "gold" } diff --git a/runtime/themes/catppuccin_mocha.toml b/runtime/themes/catppuccin_mocha.toml index 87cfe41d1..126613bc7 100644 --- a/runtime/themes/catppuccin_mocha.toml +++ b/runtime/themes/catppuccin_mocha.toml @@ -13,7 +13,7 @@ "string.regexp" = "peach" "string.special" = "blue" -"comment" = { fg = "surface2", modifiers = ["italic"] } +"comment" = { fg = "overlay1", modifiers = ["italic"] } "variable" = "text" "variable.parameter" = { fg = "maroon", modifiers = ["italic"] } @@ -26,15 +26,16 @@ "punctuation.special" = "sky" "keyword" = "mauve" +"keyword.storage.modifier.ref" = "teal" "keyword.control.conditional" = { fg = "mauve", modifiers = ["italic"] } "operator" = "sky" "function" = "blue" -"function.builtin" = "peach" "function.macro" = "mauve" "tag" = "mauve" +"attribute" = "blue" "namespace" = { fg = "blue", modifiers = ["italic"] } @@ -51,7 +52,7 @@ "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } "markup.strikethrough" = { modifiers = ["crossed_out"] } -"markup.link.url" = { fg = "rosewater", modifiers = ["italic", "underlined"] } +"markup.link.url" = { fg = "rosewater", modifiers = ["underlined"] } "markup.link.text" = "blue" "markup.raw" = "flamingo" @@ -66,7 +67,7 @@ "ui.linenr" = { fg = "surface1" } "ui.linenr.selected" = { fg = "lavender" } -"ui.statusline" = { fg = "text", bg = "mantle" } +"ui.statusline" = { fg = "subtext1", bg = "mantle" } "ui.statusline.inactive" = { fg = "surface2", bg = "mantle" } "ui.statusline.normal" = { fg = "base", bg = "lavender", modifiers = ["bold"] } "ui.statusline.insert" = { fg = "base", bg = "green", modifiers = ["bold"] } @@ -76,12 +77,9 @@ "ui.window" = { fg = "crust" } "ui.help" = { fg = "overlay2", bg = "surface0" } -"ui.bufferline" = { fg = "surface1", bg = "mantle" } -"ui.bufferline.active" = { fg = "text", bg = "base", modifiers = [ - "bold", - "italic", -] } -"ui.bufferline.background" = { bg = "surface0" } +"ui.bufferline" = { fg = "subtext0", bg = "mantle" } +"ui.bufferline.active" = { fg = "mauve", bg = "base", underline = { color = "mauve", style = "line" } } +"ui.bufferline.background" = { bg = "crust" } "ui.text" = "text" "ui.text.focus" = { fg = "text", bg = "surface0", modifiers = ["bold"] } diff --git a/runtime/themes/darcula.toml b/runtime/themes/darcula.toml index 2779a9440..53a271bd2 100644 --- a/runtime/themes/darcula.toml +++ b/runtime/themes/darcula.toml @@ -23,6 +23,7 @@ "ui.virtual.ruler" = { bg = "grey02" } "ui.virtual.indent-guide" = "grey02" "ui.virtual.whitespace" = "grey03" +"ui.virtual.inlay-hint" = { fg = "grey03", modifiers = ["italic"] } "ui.bufferline" = { fg = "grey04", bg = "grey00" } "ui.bufferline.active" = { fg = "grey07", bg = "grey02" } diff --git a/runtime/themes/dark_high_contrast.toml b/runtime/themes/dark_high_contrast.toml index 897c31e25..51701cfce 100644 --- a/runtime/themes/dark_high_contrast.toml +++ b/runtime/themes/dark_high_contrast.toml @@ -8,9 +8,14 @@ "ui.text" = "white" "ui.text.focus" = { modifiers = ["reversed"] } # file picker selected +"ui.virtual" = "gray" "ui.virtual.whitespace" = "gray" "ui.virtual.ruler" = { fg = "white", bg = "gray" } "ui.virtual.indent-guide" = "white" +"ui.virtual.inlay-hint" = { fg = "black", bg = "orange" } +"ui.virtual.inlay-hint.parameter" = { fg = "black", bg = "orange" } +"ui.virtual.inlay-hint.type" = { fg = "black", bg = "orange" } +"ui.virtual.wrap" = "gray" "ui.statusline" = { fg = "white", bg = "deep_blue" } "ui.statusline.inactive" = { fg = "gray", bg = "deep_blue" } @@ -22,7 +27,7 @@ "ui.cursor" = { fg = "black", bg = "white" } "ui.cursor.insert" = { fg = "black", bg = "white" } "ui.cursor.select" = { fg = "black", bg = "white" } -"ui.cursor.match" = { bg = "white", modifiers = ["dim"] } +"ui.cursor.match" = { modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "black", bg = "white", modifiers = ["slow_blink"] } "ui.cursor.secondary" = "white" "ui.cursorline.primary" = { bg = "deep_blue", underline = { color = "orange", style = "double_line" } } diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index 8bde4708d..bfdd620d0 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -1,78 +1,133 @@ # Author : Sebastian Zivota -"comment" = { fg = "comment" } -"constant" = { fg = "purple" } -"constant.character.escape" = { fg = "pink" } -"function" = { fg = "green" } -"keyword" = { fg = "pink" } -"operator" = { fg = "pink" } -"punctuation" = { fg = "foreground" } -"string" = { fg = "yellow" } -"string.regexp" = { fg = "red" } -"tag" = { fg = "pink" } -"type" = { fg = "cyan", modifiers = ["italic"] } -"type.enum.variant" = { fg = "foreground", modifiers = ["italic"] } -"variable" = { fg = "foreground" } -"variable.builtin" = { fg = "cyan", modifiers = ["italic"] } -"variable.parameter" = { fg ="orange", modifiers = ["italic"] } +# Author : Chirikumbrah -"diff.plus" = { fg = "green" } -"diff.delta" = { fg = "orange" } -"diff.minus" = { fg = "red" } +"annotation" = { fg = "foreground" } +"attribute" = { fg = "green", modifiers = ["italic"] } +"comment" = { fg = "comment" } +"comment.block.documentation" = { fg = "comment" } +"comment.block" = { fg = "comment" } +"comment.line" = { fg = "comment" } +"constant" = { fg = "purple" } +"constant.numeric" = { fg = "purple" } +"constant.builtin" = { fg = "purple" } +"constant.builtin.boolean" = { fg = "purple" } +"constant.character" = { fg = "cyan" } +"constant.character.escape" = { fg = "pink" } +"constant.macro" = { fg = "purple" } +"constructor" = { fg = "purple" } +"function" = { fg = "green" } +"function.builtin" = { fg = "green" } +"function.method" = { fg = "green" } +"function.macro" = { fg = "purple" } +"function.call" = { fg = "green" } +"keyword" = { fg = "pink" } +"keyword.operator" = { fg = "pink" } +"keyword.function" = { fg = "pink" } +"keyword.return" = { fg = "pink" } +"keyword.control.import" = { fg = "pink" } +"keyword.directive" = { fg = "green" } +"keyword.control.repeat" = { fg = "pink" } +"keyword.control.conditional" = { fg = "pink" } +"keyword.control.exception" = { fg = "purple" } +"keyword.storage" = { fg = "pink" } +"keyword.storage.type" = { fg = "cyan", modifiers = ["italic"] } +"keyword.storage.modifier" = { fg = "pink" } +"tag" = { fg = "pink" } +"tag.attribute" = { fg = "purple" } +"tag.delimiter" = { fg = "foreground" } +"label" = { fg = "cyan" } +"punctuation" = { fg = "foreground" } +"punctuation.bracket" = { fg = "foreground" } +"punctuation.delimiter" = { fg = "foreground" } +"punctuation.special" = { fg = "pink" } +"special" = { fg = "pink" } +"string" = { fg = "yellow" } +"string.special" = { fg = "orange" } +"string.symbol" = { fg = "yellow" } +"string.regexp" = { fg = "red" } +"type.builtin" = { fg = "cyan" } +"type" = { fg = "cyan", modifiers = ["italic"] } +"type.enum.variant" = { fg = "foreground", modifiers = ["italic"] } +"variable" = { fg = "foreground" } +"variable.builtin" = { fg = "purple", modifiers = ["italic"] } +"variable.parameter" = { fg = "orange", modifiers = ["italic"] } +"variable.other" = { fg = "cyan" } +"variable.other.member" = { fg = "purple" } -"ui.background" = { fg = "foreground", bg = "background" } -"ui.cursor" = { fg = "background", bg = "orange", modifiers = ["dim"] } -"ui.cursor.match" = { fg = "green", modifiers = ["underlined"] } -"ui.cursor.primary" = { fg = "background", bg = "cyan", modifiers = ["dim"] } -"ui.cursorline.primary" = { bg = "background_dark" } -"ui.help" = { fg = "foreground", bg = "background_dark" } -"ui.linenr" = { fg = "comment" } -"ui.linenr.selected" = { fg = "foreground" } -"ui.menu" = { fg = "foreground", bg = "background_dark" } -"ui.menu.selected" = { fg = "cyan", bg = "background_dark" } -"ui.popup" = { fg = "foreground", bg = "background_dark" } -"ui.selection" = { bg = "secondary_highlight" } -"ui.selection.primary" = { bg = "primary_highlight" } -"ui.statusline" = { fg = "foreground", bg = "background_dark" } -"ui.statusline.inactive" = { fg = "comment", bg = "background_dark" } -"ui.statusline.normal" = { fg = "background_dark", bg = "cyan" } -"ui.statusline.insert" = { fg = "background_dark", bg = "green" } -"ui.statusline.select" = { fg = "background_dark", bg = "purple" } -"ui.text" = { fg = "foreground" } -"ui.text.focus" = { fg = "cyan" } -"ui.window" = { fg = "foreground" } -"ui.virtual.whitespace" = { fg = "subtle" } -"ui.virtual.wrap" = { fg = "subtle" } -"ui.virtual.ruler" = { bg = "background_dark"} -"error" = { fg = "red" } -"warning" = { fg = "cyan" } +"diff.plus" = { fg = "green" } +"diff.delta" = { fg = "orange" } +"diff.minus" = { fg = "red" } +"ui.background" = { fg = "foreground", bg = "background" } +"ui.cursor.match" = { fg = "foreground", bg = "grey" } +"ui.cursor" = { fg = "background", bg = "purple", modifiers = ["dim"] } +"ui.cursor.normal" = { fg = "background", bg = "purple", modifiers = ["dim"] } +"ui.cursor.insert" = { fg = "background", bg = "green", modifiers = ["dim"] } +"ui.cursor.select" = { fg = "background", bg = "cyan", modifiers = ["dim"] } +"ui.cursor.primary.normal" = { fg = "background", bg = "purple" } +"ui.cursor.primary.insert" = { fg = "background", bg = "green" } +"ui.cursor.primary.select" = { fg = "background", bg = "cyan" } +"ui.cursorline.primary" = { bg = "cursorline" } +"ui.help" = { fg = "foreground", bg = "black" } +"ui.debug" = { fg = "red" } +"ui.highlight.frameline" = { fg = "background", bg = "red" } +"ui.linenr" = { fg = "comment" } +"ui.linenr.selected" = { fg = "foreground" } +"ui.menu" = { fg = "foreground", bg = "black" } +"ui.menu.selected" = { fg = "cyan", bg = "black" } +"ui.popup" = { fg = "foreground", bg = "black" } +"ui.selection.primary" = { bg = "selection_primary" } +"ui.selection" = { bg = "selection" } +"ui.statusline" = { fg = "foreground", bg = "darker" } +"ui.statusline.inactive" = { fg = "comment", bg = "darker" } +"ui.statusline.normal" = { fg = "black", bg = "purple" } +"ui.statusline.insert" = { fg = "black", bg = "green" } +"ui.statusline.select" = { fg = "black", bg = "cyan" } +"ui.text" = { fg = "foreground" } +"ui.text.focus" = { fg = "cyan" } +"ui.window" = { fg = "foreground" } +"ui.virtual.whitespace" = { fg = "subtle" } +"ui.virtual.wrap" = { fg = "subtle" } +"ui.virtual.ruler" = { bg = "black" } +"ui.virtual.inlay-hint" = { fg = "cyan" } +"ui.virtual.inlay-hint.parameter" = { fg = "cyan", modifiers = ["italic", "dim"] } +"ui.virtual.inlay-hint.type" = { fg = "cyan", modifiers = ["italic", "dim"] } +"hint" = { fg = "purple" } +"error" = { fg = "red" } +"warning" = { fg = "yellow" } +"info" = { fg = "cyan" } +"markup.heading" = { fg = "purple", modifiers = ["bold"] } +"markup.list" = { fg = "cyan" } +"markup.bold" = { fg = "orange", modifiers = ["bold"] } +"markup.italic" = { fg = "yellow", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } +"markup.link.url" = { fg = "cyan" } +"markup.link.text" = { fg = "pink" } +"markup.quote" = { fg = "yellow", modifiers = ["italic"] } +"markup.raw" = { fg = "foreground" } +"diagnostic" = { underline = { color = "orange", style = "curl" } } +"diagnostic.hint" = { underline = { color = "purple", style = "curl" } } +"diagnostic.warning" = { underline = { color = "yellow", style = "curl" } } +"diagnostic.error" = { underline = { color = "red", style = "curl" } } +"diagnostic.info" = { underline = { color = "cyan", style = "curl" } } +"definition" = { underline = { color = "cyan" } } -"markup.heading" = { fg = "purple", modifiers = ["bold"] } -"markup.list" = "cyan" -"markup.bold" = { fg = "orange", modifiers = ["bold"] } -"markup.italic" = { fg = "yellow", modifiers = ["italic"] } -"markup.strikethrough" = { modifiers = ["crossed_out"] } -"markup.link.url" = "cyan" -"markup.link.text" = "pink" -"markup.quote" = { fg = "yellow", modifiers = ["italic"] } -"markup.raw" = { fg = "foreground" } - -"diagnostic".underline = { color = "orange", style = "curl" } -"diagnostic.error".underline = { color = "red", style = "curl" } [palette] -background = "#282a36" -background_dark = "#21222c" -primary_highlight = "#800049" -secondary_highlight = "#4d4f66" -subtle = "#424450" -foreground = "#f8f8f2" -comment = "#6272a4" -red = "#ff5555" -orange = "#ffb86c" -yellow = "#f1fa8c" -green = "#50fa7b" -purple = "#bd93f9" -cyan = "#8be9fd" -pink = "#ff79c6" - +foreground = "#f8f8f2" +background = "#282A36" +cursorline = "#2d303e" +darker = "#222430" +black = "#191A21" +grey = "#666771" +comment = "#6272A4" +selection_primary = "#44475a" +selection = "#363848" +subtle = "#424450" +red = "#ff5555" +orange = "#ffb86c" +yellow = "#f1fa8c" +green = "#50fa7b" +purple = "#BD93F9" +cyan = "#8be9fd" +pink = "#ff79c6" diff --git a/runtime/themes/dracula_at_night.toml b/runtime/themes/dracula_at_night.toml index 9f10ec90f..b2e3b9a9f 100644 --- a/runtime/themes/dracula_at_night.toml +++ b/runtime/themes/dracula_at_night.toml @@ -25,6 +25,8 @@ "ui.cursor.match" = { fg = "green", modifiers = ["underlined"] } "ui.cursor.primary" = { fg = "background", bg = "cyan", modifiers = ["dim"] } "ui.help" = { fg = "foreground", bg = "background_dark" } +"ui.debug" = { fg = "red" } +"ui.highlight.frameline" = { fg = "black", bg = "red" } "ui.linenr" = { fg = "comment" } "ui.linenr.selected" = { fg = "foreground" } "ui.menu" = { fg = "foreground", bg = "background_dark" } diff --git a/runtime/themes/emacs.toml b/runtime/themes/emacs.toml index bb33e2d8b..513af60e1 100644 --- a/runtime/themes/emacs.toml +++ b/runtime/themes/emacs.toml @@ -70,6 +70,7 @@ "ui.selection.primary" = { bg = "lightgoldenrod2" } "ui.virtual.whitespace" = "highlight" "ui.virtual.ruler" = { bg = "gray95" } +"ui.virtual.inlay-hint" = { fg = "gray75" } "ui.cursorline.primary" = { bg = "darkseagreen2" } "ui.cursorline.secondary" = { bg = "darkseagreen2" } diff --git a/runtime/themes/everforest_dark.toml b/runtime/themes/everforest_dark.toml index 4947e4f3b..6903d1e54 100644 --- a/runtime/themes/everforest_dark.toml +++ b/runtime/themes/everforest_dark.toml @@ -1,114 +1,130 @@ -# Everforest (Dark Hard) -# Author: CptPotato +# Everforest (Dark Medium) +# Authors: CptPotato, basbebe # Original Author: # URL: https://github.com/sainnhe/everforest -# Filename: autoload/everforest.vim +# Filename: colors/everforest.vim # Author: sainnhe # Email: sainnhe@gmail.com # License: MIT License "type" = "yellow" -"constant" = "purple" +"constant" = "fg" +"constant.builtin" = { fg = "purple", modifiers = ["italic"] } +"constant.builtin.boolean" = "purple" "constant.numeric" = "purple" -"constant.character.escape" = "orange" -"string" = "green" -"string.regexp" = "blue" -"comment" = "grey0" +"constant.character.escape" = "green" +"string" = "aqua" +"string.regexp" = "green" +"string.special" = "yellow" +"comment" = { fg = "grey1", modifiers = ["italic"] } "variable" = "fg" -"variable.builtin" = "blue" +"variable.builtin" = { fg = "purple", modifiers = ["italic"] } "variable.parameter" = "fg" -"variable.other.member" = "fg" -"label" = "aqua" +"variable.other.member" = "blue" +"label" = "orange" "punctuation" = "grey2" -"punctuation.delimiter" = "grey2" +"punctuation.delimiter" = "grey1" "punctuation.bracket" = "fg" +"punctuation.special" = "blue" "keyword" = "red" -"keyword.directive" = "aqua" +"keyword.operator" = "orange" +"keyword.directive" = "purple" +"keyword.storage" = "red" "operator" = "orange" "function" = "green" -"function.builtin" = "blue" -"function.macro" = "aqua" -"tag" = "yellow" -"namespace" = "aqua" -"attribute" = "aqua" -"constructor" = "yellow" -"module" = "blue" -"special" = "orange" +"function.macro" = "green" +"tag" = "orange" +"namespace" = { fg = "yellow", modifiers = ["italic"] } +"attribute" = { fg = "purple", modifiers = ["italic"] } +"constructor" = "green" +"module" = "yellow" +"special" = "blue" -"markup.heading.marker" = "grey2" +"markup.heading.marker" = "grey1" "markup.heading.1" = { fg = "red", modifiers = ["bold"] } "markup.heading.2" = { fg = "orange", modifiers = ["bold"] } "markup.heading.3" = { fg = "yellow", modifiers = ["bold"] } "markup.heading.4" = { fg = "green", modifiers = ["bold"] } "markup.heading.5" = { fg = "blue", modifiers = ["bold"] } -"markup.heading.6" = { fg = "fg", modifiers = ["bold"] } +"markup.heading.6" = { fg = "purple", modifiers = ["bold"] } "markup.list" = "red" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } "markup.strikethrough" = { modifiers = ["crossed_out"] } -"markup.link.url" = { fg = "blue", modifiers = ["underlined"] } +"markup.link.url" = { fg = "blue", underline = { style = "line" } } +"markup.link.label" = "orange" "markup.link.text" = "purple" -"markup.quote" = "grey2" -"markup.raw" = "green" +"markup.quote" = "grey1" +"markup.raw.inline" = "green" +"markup.raw.block" = "aqua" "diff.plus" = "green" -"diff.delta" = "orange" +"diff.delta" = "blue" "diff.minus" = "red" "ui.background" = { bg = "bg0" } -"ui.background.separator" = "grey0" -"ui.cursor" = { fg = "bg0", bg = "fg" } -"ui.cursor.match" = { fg = "orange", bg = "bg_yellow" } +"ui.background.separator" = "bg_visual" +"ui.cursor" = { fg = "bg1", bg = "grey2" } "ui.cursor.insert" = { fg = "bg0", bg = "grey1" } "ui.cursor.select" = { fg = "bg0", bg = "blue" } +"ui.cursor.match" = { fg = "orange", bg = "bg_yellow" } +"ui.cursor.primary" = { fg = "bg0", bg = "fg" } "ui.cursorline.primary" = { bg = "bg1" } -"ui.cursorline.secondary" = { bg = "bg1" } +"ui.cursorline.secondary" = { bg = "bg2" } "ui.selection" = { bg = "bg3" } "ui.linenr" = "grey0" -"ui.linenr.selected" = "fg" +"ui.linenr.selected" = "grey2" "ui.statusline" = { fg = "grey2", bg = "bg3" } "ui.statusline.inactive" = { fg = "grey0", bg = "bg1" } -"ui.statusline.normal" = { fg = "bg0", bg = "grey2", modifiers = ["bold"] } -"ui.statusline.insert" = { fg = "bg0", bg = "yellow", modifiers = ["bold"] } +"ui.statusline.normal" = { fg = "bg0", bg = "statusline1", modifiers = [ + "bold", +] } +"ui.statusline.insert" = { fg = "bg0", bg = "statusline2", modifiers = [ + "bold", +] } "ui.statusline.select" = { fg = "bg0", bg = "blue", modifiers = ["bold"] } -"ui.bufferline" = { fg = "grey0", bg = "bg1" } -"ui.bufferline.active" = { fg = "fg", bg = "bg3", modifiers = ["bold"] } +"ui.bufferline" = { fg = "grey2", bg = "bg3" } +"ui.bufferline.active" = { fg = "bg0", bg = "statusline1", modifiers = [ + "bold", +] } "ui.popup" = { fg = "grey2", bg = "bg2" } -"ui.window" = { fg = "grey0", bg = "bg0" } +"ui.window" = { fg = "bg4", bg = "bg_dim" } "ui.help" = { fg = "fg", bg = "bg2" } "ui.text" = "fg" "ui.text.focus" = "fg" "ui.menu" = { fg = "fg", bg = "bg3" } "ui.menu.selected" = { fg = "bg0", bg = "green" } +"ui.virtual.ruler" = { bg = "bg3" } "ui.virtual.whitespace" = { fg = "bg4" } "ui.virtual.indent-guide" = { fg = "bg4" } -"ui.virtual.ruler" = { bg = "bg3" } +"ui.virtual.inlay-hint" = { fg = "grey0" } +"ui.virtual.wrap" = { fg = "grey0" } -"hint" = "blue" -"info" = "aqua" +"hint" = "green" +"info" = "blue" "warning" = "yellow" "error" = "red" -"diagnostic.hint" = { underline = { color = "blue", style = "curl" } } -"diagnostic.info" = { underline = { color = "aqua", style = "curl" } } +"diagnostic.hint" = { underline = { color = "green", style = "curl" } } +"diagnostic.info" = { underline = { color = "blue", style = "curl" } } "diagnostic.warning" = { underline = { color = "yellow", style = "curl" } } "diagnostic.error" = { underline = { color = "red", style = "curl" } } - [palette] -bg0 = "#2b3339" -bg1 = "#323c41" -bg2 = "#3a454a" -bg3 = "#445055" -bg4 = "#4c555b" -bg5 = "#53605c" -bg_visual = "#503946" -bg_red = "#4e3e43" -bg_green = "#404d44" -bg_blue = "#394f5a" -bg_yellow = "#4a4940" +bg_dim = "#232a2e" +bg0 = "#2d353b" +bg1 = "#343f44" +bg2 = "#3d484d" +bg3 = "#475258" +bg4 = "#4f585e" +bg5 = "#56635f" +bg_visual = "#543a48" +bg_red = "#514045" +bg_green = "#425047" +bg_blue = "#3a515d" +bg_yellow = "#4d4c43" fg = "#d3c6aa" red = "#e67e80" @@ -118,6 +134,7 @@ green = "#a7c080" aqua = "#83c092" blue = "#7fbbb3" purple = "#d699b6" + grey0 = "#7a8478" grey1 = "#859289" grey2 = "#9da9a0" diff --git a/runtime/themes/everforest_light.toml b/runtime/themes/everforest_light.toml index f9a55b0a8..cf39e23d6 100644 --- a/runtime/themes/everforest_light.toml +++ b/runtime/themes/everforest_light.toml @@ -1,122 +1,143 @@ -# Everforest (Dark Hard) -# Author: CptPotato +# Everforest (Light Medium) +# Authors: CptPotato, WindSoilder, basbebe # Original Author: # URL: https://github.com/sainnhe/everforest -# Filename: autoload/everforest.vim +# Filename: colors/everforest.vim # Author: sainnhe # Email: sainnhe@gmail.com # License: MIT License "type" = "yellow" -"constant" = "purple" +"constant" = "fg" +"constant.builtin" = { fg = "purple", modifiers = ["italic"] } +"constant.builtin.boolean" = "purple" "constant.numeric" = "purple" -"constant.character.escape" = "orange" -"string" = "green" -"string.regexp" = "blue" -"comment" = "grey0" +"constant.character.escape" = "green" +"string" = "aqua" +"string.regexp" = "green" +"string.special" = "yellow" +"comment" = { fg = "grey1", modifiers = ["italic"] } "variable" = "fg" -"variable.builtin" = "blue" +"variable.builtin" = { fg = "purple", modifiers = ["italic"] } "variable.parameter" = "fg" -"variable.other.member" = "fg" -"label" = "aqua" +"variable.other.member" = "blue" +"label" = "orange" "punctuation" = "grey2" -"punctuation.delimiter" = "grey2" +"punctuation.delimiter" = "grey1" "punctuation.bracket" = "fg" +"punctuation.special" = "blue" "keyword" = "red" -"keyword.directive" = "aqua" +"keyword.operator" = "orange" +"keyword.directive" = "purple" +"keyword.storage" = "red" "operator" = "orange" "function" = "green" -"function.builtin" = "blue" -"function.macro" = "aqua" -"tag" = "yellow" -"namespace" = "aqua" -"attribute" = "aqua" -"constructor" = "yellow" -"module" = "blue" -"special" = "orange" +"function.macro" = "green" +"tag" = "orange" +"namespace" = { fg = "yellow", modifiers = ["italic"] } +"attribute" = { fg = "purple", modifiers = ["italic"] } +"constructor" = "green" +"module" = "yellow" +"special" = "blue" -"markup.heading.marker" = "grey2" +"markup.heading.marker" = "grey1" "markup.heading.1" = { fg = "red", modifiers = ["bold"] } "markup.heading.2" = { fg = "orange", modifiers = ["bold"] } "markup.heading.3" = { fg = "yellow", modifiers = ["bold"] } "markup.heading.4" = { fg = "green", modifiers = ["bold"] } "markup.heading.5" = { fg = "blue", modifiers = ["bold"] } -"markup.heading.6" = { fg = "fg", modifiers = ["bold"] } +"markup.heading.6" = { fg = "purple", modifiers = ["bold"] } "markup.list" = "red" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } "markup.strikethrough" = { modifiers = ["crossed_out"] } -"markup.link.url" = { fg = "blue", modifiers = ["underlined"] } +"markup.link.url" = { fg = "blue", underline = { style = "line" } } +"markup.link.label" = "orange" "markup.link.text" = "purple" -"markup.quote" = "grey2" -"markup.raw" = "green" +"markup.quote" = "grey1" +"markup.raw.inline" = "green" +"markup.raw.block" = "aqua" "diff.plus" = "green" -"diff.delta" = "orange" +"diff.delta" = "blue" "diff.minus" = "red" "ui.background" = { bg = "bg0" } -"ui.background.separator" = "grey0" -"ui.cursor" = { fg = "bg0", bg = "fg" } -"ui.cursor.match" = { fg = "orange", bg = "bg_yellow" } +"ui.background.separator" = "bg_visual" +"ui.cursor" = { fg = "bg1", bg = "grey2" } "ui.cursor.insert" = { fg = "bg0", bg = "grey1" } "ui.cursor.select" = { fg = "bg0", bg = "blue" } +"ui.cursor.match" = { bg = "bg4", modifiers = ["bold"] } +"ui.cursor.primary" = { fg = "bg0", bg = "fg" } "ui.cursorline.primary" = { bg = "bg1" } -"ui.cursorline.secondary" = { bg = "bg1" } +"ui.cursorline.secondary" = { bg = "bg2" } "ui.selection" = { bg = "bg3" } "ui.linenr" = "grey0" -"ui.linenr.selected" = "fg" +"ui.linenr.selected" = "grey2" "ui.statusline" = { fg = "grey2", bg = "bg3" } "ui.statusline.inactive" = { fg = "grey0", bg = "bg1" } -"ui.statusline.normal" = { fg = "bg0", bg = "grey2", modifiers = ["bold"] } -"ui.statusline.insert" = { fg = "bg0", bg = "yellow", modifiers = ["bold"] } +"ui.statusline.normal" = { fg = "bg0", bg = "statusline1", modifiers = [ + "bold", +] } +"ui.statusline.insert" = { fg = "bg0", bg = "statusline2", modifiers = [ + "bold", +] } "ui.statusline.select" = { fg = "bg0", bg = "blue", modifiers = ["bold"] } -"ui.bufferline" = { fg = "grey0", bg = "bg1" } -"ui.bufferline.active" = { fg = "fg", bg = "bg3", modifiers = ["bold"] } +"ui.bufferline" = { fg = "grey2", bg = "bg3" } +"ui.bufferline.active" = { fg = "bg0", bg = "statusline1", modifiers = [ + "bold", +] } "ui.popup" = { fg = "grey2", bg = "bg2" } -"ui.window" = { fg = "grey0", bg = "bg0" } +"ui.window" = { fg = "bg4", bg = "bg_dim" } "ui.help" = { fg = "fg", bg = "bg2" } "ui.text" = "fg" "ui.text.focus" = "fg" "ui.menu" = { fg = "fg", bg = "bg3" } "ui.menu.selected" = { fg = "bg0", bg = "green" } +"ui.virtual.ruler" = { bg = "bg3" } "ui.virtual.whitespace" = { fg = "bg4" } "ui.virtual.indent-guide" = { fg = "bg4" } -"ui.virtual.ruler" = { bg = "bg3" } +"ui.virtual.inlay-hint" = { fg = "grey0" } +"ui.virtual.wrap" = { fg = "grey0" } -"hint" = "blue" -"info" = "aqua" +"hint" = "green" +"info" = "blue" "warning" = "yellow" "error" = "red" -"diagnostic.hint" = { underline = { color = "blue", style = "curl" } } -"diagnostic.info" = { underline = { color = "aqua", style = "curl" } } +"diagnostic.hint" = { underline = { color = "green", style = "curl" } } +"diagnostic.info" = { underline = { color = "blue", style = "curl" } } "diagnostic.warning" = { underline = { color = "yellow", style = "curl" } } "diagnostic.error" = { underline = { color = "red", style = "curl" } } [palette] -bg0 = "#fff9e8" -bg1 = "#f7f4e0" -bg2 = "#f0eed9" -bg3 = "#e9e8d2" -bg4 = "#e1ddcb" -bg5 = "#bec5b2" -bg_visual = "#edf0cd" -bg_red = "#fce5dc" -bg_green = "#f1f3d4" -bg_blue = "#eaf2eb" -bg_yellow = "#fbefd0" +bg_dim = "#efebd4" +bg0 = "#fdf6e3" +bg1 = "#f4f0d9" +bg2 = "#efebd4" +bg3 = "#e6e2cc" +bg4 = "#e0dcc7" +bg5 = "#bdc3af" +bg_red = "#fbe3da" +bg_visual = "#eaedc8" +bg_yellow = "#faedcd" +bg_green = "#f0f1d2" +bg_blue = "#e9f0e9" fg = "#5c6a72" red = "#f85552" orange = "#f57d26" yellow = "#dfa000" green = "#8da101" -aqua = "#35a77c" blue = "#3a94c5" +aqua = "#35a77c" purple = "#df69ba" + grey0 = "#a6b0a0" grey1 = "#939f91" grey2 = "#829181" +statusline1 = "#93b259" +statusline2 = "#708089" +statusline3 = "#e66868" diff --git a/runtime/themes/ferra.toml b/runtime/themes/ferra.toml new file mode 100644 index 000000000..360ad02f6 --- /dev/null +++ b/runtime/themes/ferra.toml @@ -0,0 +1,84 @@ +# Author : Casper Rogild Storm + +"comment" = { fg = "ferra_bark", modifiers = ["italic"] } +"constant" = { fg = "ferra_sage" } +"function" = { fg = "ferra_coral" } +"function.macro" = { fg = "ferra_mist" } +"keyword" = { fg = "ferra_mist" } +"operator" = { fg = "ferra_mist" } +"punctuation" = { fg = "ferra_blush" } +"string" = { fg = "ferra_sage" } +"type" = { fg = "ferra_rose" } +"variable" = { fg = "ferra_blush" } +"variable.builtin" = { fg = "ferra_rose" } +"tag" = { fg = "ferra_sage" } +"label" = { fg = "ferra_sage" } +"attribute" = { fg = "ferra_blush" } +"namespace" = { fg = "ferra_blush" } +"module" = { fg = "ferra_blush" } + +"markup.heading" = { fg = "ferra_sage", modifiers = ["bold"] } +"markup.heading.marker" = { fg = "ferra_bark" } +"markup.list" = { fg = "ferra_mist" } +"markup.bold" = { modifiers = ["bold"] } +"markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } +"markup.link.url" = { fg = "ferra_rose", modifiers = ["underlined"] } +"markup.link.text" = { fg = "ferra_rose" } +"markup.quote" = { fg = "ferra_bark" } +"markup.raw" = { fg = "ferra_coral" } + +"ui.background" = { bg = "ferra_night" } +"ui.cursor" = { fg = "ferra_night", bg = "ferra_blush" } +"ui.cursor.match" = { fg = "ferra_night", bg = "ferra_bark" } +"ui.cursor.select" = { fg = "ferra_night", bg = "ferra_rose" } +"ui.cursor.insert" = { fg = "ferra_night", bg = "ferra_coral" } +"ui.linenr" = { fg = "ferra_bark" } +"ui.linenr.selected" = { fg = "ferra_blush" } +"ui.cursorline" = { fg = "ferra_blush", bg = "ferra_ash" } +"ui.statusline" = { fg = "ferra_blush", bg = "ferra_ash" } +"ui.statusline.inactive" = { fg = "ferra_bark", bg = "ferra_ash" } +"ui.statusline.normal" = { fg = "ferra_ash", bg = "ferra_blush" } +"ui.statusline.insert" = { fg = "ferra_ash", bg = "ferra_coral" } +"ui.statusline.select" = { fg = "ferra_ash", bg = "ferra_rose" } +"ui.popup" = { fg = "ferra_blush", bg = "ferra_ash" } +"ui.window" = { fg = "ferra_bark", bg = "ferra_night" } +"ui.help" = { fg = "ferra_blush", bg = "ferra_ash" } +"ui.text" = { fg = "ferra_blush" } +"ui.text.focus" = { fg = "ferra_coral" } +"ui.menu" = { fg = "ferra_blush", bg = "ferra_ash" } +"ui.menu.selected" = { fg = "ferra_coral", bg = "ferra_ash" } +"ui.selection" = { bg = "ferra_umber", fg = "ferra_night" } +"ui.selection.primary" = { bg = "ferra_night", fg = "ferra_umber" } +"ui.virtual" = { fg = "ferra_bark" } +"ui.virtual.whitespace" = { fg = "ferra_bark" } +"ui.virtual.ruler" = { bg = "ferra_ash" } +"ui.virtual.indent-guide" = { fg = "ferra_ash" } +"ui.virtual.inlay-hint" = { fg = "ferra_bark" } + +"diff.plus" = { fg = "ferra_sage" } +"diff.delta" = { fg = "ferra_blush" } +"diff.minus" = { fg = "ferra_ember" } + +"error" = { fg = "ferra_ember" } +"warning" = { fg = "ferra_honey" } +"info" = { fg = "ferra_blush" } +"hint" = { fg = "ferra_blush" } + +"diagnostic.warning" = { underline = { color = "ferra_honey", style = "curl" } } +"diagnostic.error" = { underline = { color = "ferra_ember", style = "curl" } } +"diagnostic.info" = { underline = { color = "ferra_blush", style = "curl" } } +"diagnostic.hint" = { underline = { color = "ferra_blush", style = "curl" } } + +[palette] +ferra_night = "#2b292d" +ferra_ash = "#383539" +ferra_umber = "#4d424b" +ferra_bark = "#6F5D63" +ferra_mist = "#D1D1E0" +ferra_sage = "#B1B695" +ferra_blush = "#fecdb2" +ferra_coral = "#ffa07a" +ferra_rose = "#F6B6C9" +ferra_ember = "#e06b75" +ferra_honey = "#F5D76E" diff --git a/runtime/themes/kanagawa.toml b/runtime/themes/kanagawa.toml index a7d33f3ee..d0576a4e3 100644 --- a/runtime/themes/kanagawa.toml +++ b/runtime/themes/kanagawa.toml @@ -16,6 +16,9 @@ "ui.virtual" = "sumiInk4" "ui.virtual.ruler" = { bg = "sumiInk2" } +"ui.virtual.inlay-hint" = "fujiGray" +"ui.virtual.inlay-hint.parameter" = { fg = "carpYellow", modifiers = ["dim"] } +"ui.virtual.inlay-hint.type" = { fg = "waveAqua2", modifiers = ["dim"] } "ui.statusline" = { fg = "oldWhite", bg = "sumiInk0" } "ui.statusline.inactive" = { fg = "fujiGray", bg = "sumiInk0" } diff --git a/runtime/themes/mellow.toml b/runtime/themes/mellow.toml index 279fd5c2b..16d7b6086 100644 --- a/runtime/themes/mellow.toml +++ b/runtime/themes/mellow.toml @@ -80,6 +80,7 @@ "ui.virtual" = { fg = "gray02" } "ui.virtual.indent-guide" = { fg = "gray02" } +"ui.virtual.inlay-hint" = { fg = "gray04" } "ui.selection" = { bg = "gray03" } "ui.selection.primary" = { bg = "gray03" } diff --git a/runtime/themes/nightfox.toml b/runtime/themes/nightfox.toml index 8cddbbaef..fad56d189 100644 --- a/runtime/themes/nightfox.toml +++ b/runtime/themes/nightfox.toml @@ -33,6 +33,7 @@ "ui.virtual.ruler" = { bg = "bg3" } # Vertical rulers (colored columns in editing area). "ui.virtual.whitespace" = { fg = "bg3" } # Whitespace markers in editing area. "ui.virtual.indent-guide" = { fg = "black" } # Vertical indent width guides +"ui.virtual.inlay-hint" = { fg = "comment", bg = "bg2" } # Default style for inlay hints of all kinds "ui.statusline" = { fg = "fg2", bg = "bg0" } # Status line. "ui.statusline.inactive" = { fg = "fg3", bg = "bg0" } # Status line in unfocused windows. diff --git a/runtime/themes/onedark.toml b/runtime/themes/onedark.toml index 81ca04630..21101ea75 100644 --- a/runtime/themes/onedark.toml +++ b/runtime/themes/onedark.toml @@ -54,6 +54,7 @@ "ui.virtual.indent-guide" = { fg = "faint-gray" } "ui.virtual.whitespace" = { fg = "light-gray" } "ui.virtual.ruler" = { bg = "gray" } +"ui.virtual.inlay-hint" = { fg = "light-gray" } "ui.cursor" = { fg = "white", modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "white", modifiers = ["reversed"] } @@ -64,6 +65,7 @@ "ui.cursorline.primary" = { bg = "light-black" } "ui.highlight" = { bg = "gray" } +"ui.highlight.frameline" = { bg = "#97202a" } "ui.linenr" = { fg = "linenr" } "ui.linenr.selected" = { fg = "white" } @@ -84,6 +86,8 @@ "ui.menu.selected" = { fg = "black", bg = "blue" } "ui.menu.scroll" = { fg = "white", bg = "light-gray" } +"ui.debug" = { fg = "red" } + [palette] yellow = "#E5C07B" diff --git a/runtime/themes/onedarker.toml b/runtime/themes/onedarker.toml index 33f900cc0..7169fd025 100644 --- a/runtime/themes/onedarker.toml +++ b/runtime/themes/onedarker.toml @@ -78,6 +78,8 @@ "ui.text.focus" = { fg = "white", bg = "light-black", modifiers = ["bold"] } "ui.help" = { fg = "white", bg = "gray" } +"ui.debug" = { fg = "red" } +"ui.highlight.frameline" = { bg = "#97202a" } "ui.popup" = { bg = "gray" } "ui.window" = { fg = "gray" } "ui.menu" = { fg = "white", bg = "gray" } diff --git a/runtime/themes/rasmus.toml b/runtime/themes/rasmus.toml index 3158a6a45..bcfb0c66c 100644 --- a/runtime/themes/rasmus.toml +++ b/runtime/themes/rasmus.toml @@ -85,6 +85,7 @@ "ui.virtual" = { fg = "gray03" } "ui.virtual.indent-guide" = { fg = "gray04" } +"ui.virtual.inlay-hint" = { fg = "gray05" } "ui.selection" = { bg = "gray03" } "ui.selection.primary" = { bg = "gray03" } diff --git a/runtime/themes/rose_pine.toml b/runtime/themes/rose_pine.toml index ea17ac224..e1d968941 100644 --- a/runtime/themes/rose_pine.toml +++ b/runtime/themes/rose_pine.toml @@ -32,11 +32,11 @@ "ui.help" = { fg = "subtle", bg = "overlay" } "ui.text" = { fg = "text" } -# "ui.text.focus" = {} +"ui.text.focus" = { bg = "overlay" } "ui.text.info" = { fg = "subtle" } "ui.virtual.ruler" = { bg = "overlay" } -"ui.virtual.whitespace" = { fg = "highlight_low" } +"ui.virtual.whitespace" = { fg = "highlight_high" } "ui.virtual.indent-guide" = { fg = "muted" } "ui.virtual.inlay-hint" = { fg = "subtle" } @@ -61,6 +61,7 @@ "diagnostic.info" = { underline = { color = "foam", style = "curl" } } "diagnostic.warning" = { underline = { color = "gold", style = "curl" } } "diagnostic.error" = { underline = { color = "love", style = "curl" } } +"special" = "rose" "attribute" = "iris" diff --git a/runtime/themes/varua.toml b/runtime/themes/varua.toml index c1afaca0a..b07ab08dc 100644 --- a/runtime/themes/varua.toml +++ b/runtime/themes/varua.toml @@ -65,6 +65,8 @@ "ui.virtual.whitespace" = "grey0" "ui.statusline.insert" = { bg = "green", fg = "bg2" } "ui.statusline.select" = { bg = "blue", fg = "bg2" } +"ui.virtual.wrap" = { fg = "grey0" } +"ui.virtual.inlay-hint" = { fg = "grey1" } "hint" = "blue" "info" = "aqua" diff --git a/runtime/themes/zenburn.toml b/runtime/themes/zenburn.toml index 4c019a2c5..8518e78f8 100644 --- a/runtime/themes/zenburn.toml +++ b/runtime/themes/zenburn.toml @@ -8,7 +8,8 @@ "ui.popup" = { bg = "uibg" } "ui.selection" = { bg = "#304a3d" } "ui.selection.primary" = { bg = "#2f2f2f" } -"comment" = { fg = "#7f9f7f" } +"comment" = { fg = "comment" } +"ui.virtual.inlay-hint" = { fg = "comment" } "comment.block.documentation" = { fg = "black", modifiers = ["bold"] } "ui.statusline" = { bg = "statusbg", fg = "#ccdc90" } "ui.statusline.inactive" = { fg = '#2e3330', bg = '#88b090' } @@ -50,6 +51,7 @@ "error" = "errorfg" [palette] +comment = "#7f9f7f" bg = "#3f3f3f" uibg = "#2c2e2e" constant = "#dca3a3" diff --git a/runtime/tutor b/runtime/tutor index a6682ed92..df4d6d541 100644 --- a/runtime/tutor +++ b/runtime/tutor @@ -994,7 +994,7 @@ lines. * Type * to set the search register to the primary selection. - * Type n / N in Visual mode to add selections on each search + * Type n / N in Select mode to add selections on each search match. * Press Ctrl-s to save position to the jumplist. diff --git a/theme.toml b/theme.toml index b67eaecc3..dd1a5d889 100644 --- a/theme.toml +++ b/theme.toml @@ -69,7 +69,9 @@ label = "honey" "ui.cursor" = { modifiers = ["reversed"] } "ui.cursorline.primary" = { bg = "bossanova" } "ui.highlight" = { bg = "bossanova" } - +"ui.highlight.frameline" = { bg = "#634450" } +"ui.debug" = { fg = "#634450" } +"ui.debug.breakpoint" = { fg = "apricot" } "ui.menu" = { fg = "lavender", bg = "revolver" } "ui.menu.selected" = { fg = "revolver", bg = "white" } "ui.menu.scroll" = { fg = "lavender", bg = "comet" }