Compare commits

...

1345 Commits

Author SHA1 Message Date
Michael Davis
2dbec4c933 Add a document for the runtime directory
This help topic should otherwise belong under `runtime/help/topics`
but it should be accessible if the runtime directory is not correctly
installed.

This article shows up under `:help topics` because of the symlink
but can also be accessed by `:help runtime` if necessary.
2022-12-12 21:41:31 -06:00
Michael Davis
233b10f7fc Use markdown instead of text for help files 2022-12-12 20:27:33 -06:00
Michael Davis
0e037802c2 Use an overlayed component for the topics picker
This prevents the topics file picker from consuming the whole screen
and makes it consistent with the standard file and buffer pickers.
2022-12-12 20:22:04 -06:00
Michael Davis
19111e1478 Use doc_mut! macro for document accesses 2022-12-12 20:21:44 -06:00
Michael Davis
816dfee64a Bail on zero-arg :help invocation 2022-12-12 20:06:07 -06:00
Omnikar
321fce3ba6 Add :help command 2022-12-12 20:02:36 -06:00
dependabot[bot]
fa436fa680 build(deps): bump tokio from 1.22.0 to 1.23.0 (#5137)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.22.0 to 1.23.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.22.0...tokio-1.23.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-12 17:25:05 -06:00
dependabot[bot]
f995f2610b build(deps): bump serde from 1.0.149 to 1.0.150 (#5138)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.149 to 1.0.150.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.149...v1.0.150)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-12 17:20:26 -06:00
Blaž Hrastnik
bae890d8fa Update tree-sitter-scheme 2022-12-12 17:50:12 +09:00
Alexander Schlögl
0b96021643 Add :pipe-to typable command that ignores shell output (#4931) 2022-12-11 20:06:24 -06:00
Marco Ieni
d5ab974d38 chore(book): link repository (#5101) 2022-12-11 19:59:53 -06:00
garlic0x1
a34ba071be Fix commonlisp filetypes typo and auto-pairs (#5091) 2022-12-11 19:59:27 -06:00
Slug
c5bfb792b2 update(theme): adjust base16_transparent and dark_high_contrast (#5105) 2022-12-11 12:14:10 -06:00
Michael Davis
cdc54f50a2 Reset mode when changing buffers (#5072)
* Reset mode when changing buffers

This is similar to the change in
e4c9d4082a: reset the editor to normal
mode when changing buffers. Usually the editor is already in normal
mode but it's possible to setup insert-mode keybindings that change
buffers.

* Move normal mode entering code to Editor

This should be called internally in the Editor when changing documents
(Editor::switch) or changing focuses (Editor::focus).
2022-12-12 00:04:08 +09:00
Pascal Kuthe
70d78123b9 properly handle detachted git worktrees (#5097) 2022-12-11 19:20:34 +09:00
Ollie Charles
0e8ea13696 Add Haskell text objects (#5061) 2022-12-10 14:03:18 -06:00
Danilo Spinella
f323ffabcc Treat patches as diff files (#5085) 2022-12-09 18:40:27 -06:00
Felipe S. S. Schneider
d14de27709 Add support for the BibTeX file format (#5064) 2022-12-08 22:33:08 -06:00
two-six
37e7dd1df5 Update diagnostic.error background for acme theme (#5019) 2022-12-08 22:11:25 -06:00
TotalKrill
16e13b9789 allow specifying environment for language servers in language.toml (#4004)
Signed-off-by: Stephen Wakely <fungus.humungus@gmail.com>
Co-authored-by: Stephen Wakely <fungus.humungus@gmail.com>
Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-12-08 22:09:23 -06:00
Jummit
2ea20a23e2 Fix LSP completions ignoring auto-completion option (#5042) 2022-12-08 22:02:34 -06:00
Matouš Dzivjak
8abed3bd78 feat(lsp): pass client_info on initialization (#4904)
Pass client name ('helix') and client version (version / git hash)
to LSP server on initialization.
2022-12-08 21:57:03 -06:00
ath3
6798a6651f Only write newlines in menu selection popup if the lsp returns detail (#4902) 2022-12-08 21:55:15 -06:00
cor
d914642089 use curl underlines for gruvbox_dark_hard (#5066) 2022-12-08 21:48:56 -06:00
LeoniePhiline
36eff1da8c fix(tutor): Capitalize first letter of a sentence (#5075) 2022-12-08 20:58:15 -06:00
Jens Getreu
f8b75a245a Autumn theme: use new features (#5051)
Co-authored-by: Jens Getreu <jens.getreu@dlh.lu>
2022-12-08 10:48:01 +09:00
Alexander Brevig
a4de86e7af fix(theme): git gutter for flatwhite (#5036) 2022-12-07 20:30:46 +09:00
Alexander Brevig
9d4236941d fix(theme): serika toml syntax valid (#5038) 2022-12-07 20:29:56 +09:00
Michael Davis
96ff64a84a Add changelog notes for 22.12 (#4822)
* Add changelog notes for 22.12

* Bump VERSION to 22.12
2022-12-07 11:54:50 +09:00
Jonathan LEI
d3f670c0e2 Use OSC 52 for tmux copy (#5027) 2022-12-07 11:11:45 +09:00
Kristoffer Flottorp
e9d43c284b Fleetish theme renamed to fleet dark and adjusted to match official theme. (#4997)
* remove fleetish.toml

* add fleet_dark.toml

* adjust colors for tags and markup lists

* Add type.enum.variant

* correct color for focused elements

* adjust builtins and keywords

Co-authored-by: krfl <kr.fl@outlook.com>
2022-12-07 10:08:34 +09:00
Pascal Kuthe
af532147c9 Add command/keybinding to jump between hunks (#4650)
* add command and keybding to jump to next/prev hunk

* add textobject for change

* Update helix-vcs/src/diff.rs

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>

* select entire hunk instead of first char

* fix selection range

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-12-06 23:18:33 +09:00
Narazaki Shuji
453a75a373 fix: align view after jumplist_picker (#3743)
* Add `View::ensure_cursor_in_view_center` to adjust view after searching and jumping

Also `offset_coodrs_to_in_view` was refactored to reduce duplicated position calculations.

* Fix a wrong offset calculation in `offset_coords_to_in_view_center`

It ignored `scrolloff` if `centering` is false.
2022-12-06 11:16:08 +09:00
dependabot[bot]
952f292d25 build(deps): bump serde from 1.0.148 to 1.0.149 (#5017)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.148 to 1.0.149.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.148...v1.0.149)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-06 10:30:11 +09:00
dependabot[bot]
dbed90c5a6 build(deps): bump git-repository from 0.26.0 to 0.29.0 (#5016)
Bumps [git-repository](https://github.com/Byron/gitoxide) from 0.26.0 to 0.29.0.
- [Release notes](https://github.com/Byron/gitoxide/releases)
- [Changelog](https://github.com/Byron/gitoxide/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Byron/gitoxide/compare/git-repository-v0.26.0...git-repository-v0.29.0)

---
updated-dependencies:
- dependency-name: git-repository
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-06 10:30:04 +09:00
Michael Davis
2077f5e26a Apply completion edits to all cursors (#4496)
Completion edits - either basic `insert_text` strings or structured
`text_edit`s - are assumed by the LSP spec to apply to the current
cursor (or at least the trigger point). We can use the range (if any)
and text given by the Language Server to create a transaction that
changes all ranges in the current selection though, allowing auto-
complete to affect multiple cursors.
2022-12-06 10:29:40 +09:00
nosa
7210c58a51 Change default TS object bindings (#3782)
* Change default TS object bindings

Changes 'match inside/around' bindings for:
- type definition from `c` to `t`
- comments from `o` to `c`
- tests from `t` to `T`

Also changes those for the `]` / `[` bindings.

* Update docs for changed keybinds

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-12-06 10:13:41 +09:00
VuiMuich
5691ada822 Change diff colors for serika themes (#5015) 2022-12-05 16:28:20 -06:00
Matouš Dzivjak
5781aa0264 feat(highlights): go builtin funcs and types (#5010)
Add highlight scopes for golang built-in functions and types.
Based on https://pkg.go.dev/builtin.
2022-12-06 00:16:25 +09:00
two-six
f712d316e5 Update Acme and Nord Light for git gutters (#4999)
* Update acme.toml

* Update nord_light.toml

* Update runtime/themes/nord_light.toml

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>

* Update acme.toml

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-12-05 22:48:20 +09:00
Pascal Kuthe
b0f20f13e3 fix git diff when core.autocrlf is enabled (#4995) 2022-12-05 22:46:59 +09:00
Pascal Kuthe
1e31bc3f77 Reduce log message about diff timeout from warn to info (#5012) 2022-12-05 22:18:42 +09:00
Blaž Hrastnik
03ca18b377 Update language support docs 2022-12-05 15:02:13 +09:00
Blaž Hrastnik
417676953b Add basic support for common lisp 2022-12-05 14:40:41 +09:00
farwyler
59cfe95776 Add support for single-line comments to scss (#5003) 2022-12-04 09:45:31 -06:00
Michael Davis
c13c6d56b6 Use logo for contrib icon (#4982) 2022-12-04 11:07:17 +09:00
PORTALSURFER
e9d0645f66 Adjusted hex themes for new gutter diff colors (#4990)
* added 2 themes

* diff feature fixes

adjusted the skin to better work with the new diff coloring features

propagates to child skins like
- hex_toxic

* fine tuning so it all is a bit softer

* fine tuning to be softer

* added new version, lavender
2022-12-04 11:06:40 +09:00
Jens Getreu
326a0dab06 Autumn theme: adjust some gray colors (#4996) 2022-12-04 11:03:42 +09:00
Aleksey Kuznetsov
2123e91e56 Enable auto format for css and scss files (#4987)
provideFormatter enables capability in LS and
auto-format performs format on save
2022-12-03 08:24:43 -06:00
Michael Davis
bcdb475b71 Fix transaction composition order in History::changes_since (#4981)
* Add a undo/redo split test case for crossing branches

* history: Switch up/down transaction chaining order

The old code tends to work in practice because, usually, either up_txns
or down_txns are empty. When both have contents though, we can run into
a panic trying to compose them all since they will disagree on the
length of the text. This fixes the panic test case in the parent
commit.
2022-12-03 12:09:08 +09:00
Luna
dc00291b48 Update Doom Acario for git gutters (#4979)
Edited the diff.delta from green to blue.
2022-12-03 11:26:10 +09:00
Anton Romanov
224a024d39 Update zenburn theme for git gutters (#4977) 2022-12-03 11:26:01 +09:00
Pascal Kuthe
b677c6a019 Add logo with text included (#4973) 2022-12-03 11:05:15 +09:00
alex 孙欣乐
59b886cf5e nightfox theme: Use brighter colors for diff scopes (#4966) 2022-12-02 08:24:00 -06:00
Matouš Dzivjak
d0bc38d6fa feat(lang): bump tree-sitter-go (#4969)
Update tree-sitter-go to latest with updated support for generics.

See: 0fa917a702..05900faa3c
for full diff.
2022-12-02 08:06:35 -06:00
lesleyrs
39ce82b7a5 Add Ctrl-i alias for Windows (#4961) 2022-12-02 08:02:29 -06:00
Michael Davis
8c2692caf1 Use the logo as the favicon for the docs book (#4971) 2022-12-02 22:45:06 +09:00
Matouš Dzivjak
c38519c57a feat(docs): style readme & add badges (#4970)
Centre Helix title and logo and add badge with latest
release and link to matrix chat.
2022-12-02 20:56:36 +09:00
Blaž Hrastnik
98c121c9fc Detect WezTerm and mark it as undercurl/Smulx capable 2022-12-02 17:42:10 +09:00
Blaž Hrastnik
e92651816d Forgot to set the height 2022-12-02 12:07:08 +09:00
Blaž Hrastnik
dc1ec56322 Add the new logo! 2022-12-02 12:06:17 +09:00
Blaž Hrastnik
700f8ba252 Use cargo fmt's --check 2022-12-02 10:33:53 +09:00
sigmaSd
4960c41f18 feat(lsp): add support for lsp Diagnostic{}.data (#4935) 2022-12-02 10:18:45 +09:00
Michael Davis
8291654326 reload_all: Ensure view is synced with doc history before reload (#4965) 2022-12-02 10:18:32 +09:00
Bertrand Bousquet
71a3a23f42 Varua theme updates (cursorline, statusline) (#4964) 2022-12-02 10:18:18 +09:00
Tshepang Mbambo
e3f05603ac tutor: Clarify space searching instructions (#4953) 2022-12-01 15:55:52 -06:00
Tshepang Mbambo
a8a54be6bc Fix nightly clippy lints (#4954) 2022-12-01 10:37:38 -06:00
Pascal Kuthe
5a3ff74221 Show (git) diff signs in gutter (#3890)
* Show (git) diff signs in gutter (#3890)

Avoid string allocation when git diffing

Incrementally diff using changesets

refactor diffs to be provider indepndent and improve git implementation

remove dependency on zlib-ng

switch to asynchronus diffing with similar

Update helix-vcs/Cargo.toml

fix toml formatting

Co-authored-by: Ivan Tham <pickfire@riseup.net>

fix typo in documentation

use ropey reexpors from helix-core

fix crash when creating new file

remove useless use if io::Cursor

fix spelling mistakes

implement suggested improvement to repository loading

improve git test isolation

remove lefover comments

Co-authored-by: univerz <univerz@fu-solution.com>

fixed spelling mistake

minor cosmetic changes

fix: set self.differ to None if decoding the diff_base fails

fixup formatting

Co-authored-by: Ivan Tham <pickfire@riseup.net>

reload diff_base when file is reloaded from disk

switch to imara-diff

Fixup formatting

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>

Redraw buffer whenever a diff is updated.

Only store hunks instead of changes for individual lines to easily allow
jumping between them

Update to latest gitoxide version

Change default diff gutter position

Only update gutter after timeout

* update diff gutter synchronously, with a timeout

* Apply suggestions from code review

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>

* address review comments and ensure lock is always aquired

* remove configuration for redraw timeout

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-12-01 17:35:23 +09:00
Michael Davis
67415e096e Fix file-types declaration for racket (#4915)
Both the racket and scheme entries used the rkt file-extension. This
commit removes that entry for scheme and so that the racket entry takes
precedence. We explicitly point to the scheme grammar now and setup
queries that inherit from scheme. This should enable using the racket
language server configuration.
2022-11-30 23:27:08 +09:00
André Sá
664d08e70d Fix ayu theme cursor issue (#4764) 2022-11-29 17:30:06 -06:00
Michael Davis
607c74efde Handle disambiguated keycodes (#4887)
Media keys are sent despite `DISAMBIGUATE_ESCAPE_CODES` being unset.
Previously we panicked on these. This change translates the
disambiguated keys from crossterm so that they do not cause a panic.
2022-11-30 01:15:55 +09:00
Michael Davis
260341ed80 Sync all document changes on view focus 2022-11-30 01:15:20 +09:00
Michael Davis
4802f26a23 Add a test case for undo/redo across splits 2022-11-30 01:15:20 +09:00
Michael Davis
9387dfafed Use lowest common ancestor search in History::changes_since 2022-11-30 01:15:20 +09:00
Michael Davis
9a9e462183 Call View::apply within Document::append_changes_to_history 2022-11-30 01:15:20 +09:00
Michael Davis
2709ce3332 Sync changes with view in undo/redo/earlier/later 2022-11-30 01:15:20 +09:00
Michael Davis
53c2855643 Remove calls to View::apply in undo/redo/earlier/later 2022-11-30 01:15:20 +09:00
Michael Davis
056a19a003 Sync changes between doc and view on switch 2022-11-30 01:15:20 +09:00
Michael Davis
4d1f5389f9 Revert "Don't apply transactions to Views in undo/redo"
This reverts commit fd00f3a70e.
2022-11-30 01:15:20 +09:00
Michael Davis
df5457a6e7 Remove eager application of transactions to all views 2022-11-30 01:15:20 +09:00
Kirawi
04df9e4445 delete outdated reference to cessen/ropey#25 (#4928) 2022-11-28 19:07:47 -06:00
Erik Bünnig
5c213f7de4 fix(grammar): Add block_comment and comment_environment injection for latex comments (#4922) 2022-11-28 09:19:16 -06:00
Pascal Kuthe
da355a3231 Significantly improve performance of :reload (#4457)
* bump ropey to 1.5.1-alpha

* significantly improve performance of :reload
2022-11-28 11:20:54 +09:00
Pascal Kuthe
a549328ef2 bump ropey to 1.5.1-alpha 2022-11-28 02:51:26 +01:00
Chickenkeeper
bf908cc4a1 Update CSS syntax highlighting (#4882) 2022-11-27 19:11:12 -06:00
gavincrawford
583c2a5456 Fix Go variable indentation (#4906) 2022-11-27 09:36:52 -06:00
Filipe Azevedo
f0f295a667 reload-all: Only update viewport when view focuses on the doc (#4901) 2022-11-26 14:40:43 -06:00
Lennard Hofmann
fc811726e0 Update tree-sitter-java and add Java textobjects (#4886) 2022-11-26 10:17:10 -06:00
Michael Davis
8529d756fa Remove selections for closed views on all documents (#4888)
Previously we removed selections for a closed view on only the
currently focused document. A view might have selections in other
documents though, so the view needs to be removed from all documents.
2022-11-26 11:52:22 +09:00
Matouš Dzivjak
4e52d4d6f4 feat(themes): improve fleetish (#4813)
Small adjustements to the fleetish theme to improve readability
in certain cases. Specifically:

- use darker background for menues as it (purely subjectively) loooks
  better
- use different color for `constant.buildin.boolean` and
  `keyword` to make statements such as `return true` read better
- use different colors for different markup link parts
- destructure the config where appliable
2022-11-26 10:52:34 +09:00
Chickenkeeper
f2a55331d0 Bump tree-sitter-html version (#4881) 2022-11-25 19:43:41 -06:00
Jan Scheer
6cdc567372 add theme nightfox (#4769)
This theme is an adaptation of
github.com/EdenEast/nightfox.nvim
2022-11-25 19:41:37 -06:00
Michael Davis
2271c3aed9 Clear line on <ret> when line is all whitespace (#4854)
This matches the insert-mode behavior for Vim and Kakoune: if the
current line is empty except for whitespace, `<ret>` should insert a
line ending at the beginning of the line, moving any indentation to the
next line.
2022-11-25 11:40:48 +09:00
Michael Davis
e6dad960cf Drain pending requests on language server termination (#4852)
This prevents a freeze while shutting down when using `efm-langserver`.
`efm-langserver` exits immediately after seeing a shutdown request,
without responding to the request. We block awaiting the reply to the
shutdown request which will never come, so we time out.

This change responds to any pending requests with `Err` saying that the
stream has been closed.
2022-11-24 11:07:42 +09:00
Jonathan LEI
1d21683321 Exit select mode on surround commands (#4858) 2022-11-24 11:07:19 +09:00
Michael Davis
ee06d4d337 Update tree-sitter-gleam
This update includes a handful of fixes, a new binary concatenation
operator (already highlighted by the `binary_operator` rule), and a
new `use` language construct. The nodes are backwards compatible but
this update introduces two new nodes for highlighting: `use` and `<-`.
2022-11-24 11:07:05 +09:00
Michael Davis
cbc72e84d7 Update tree-sitter-heex
tree-sitter-heex split out the ending_expression_value from the
partial_expression value which can help with indentation.
2022-11-24 11:07:05 +09:00
Michael Davis
5a1bed2b70 Add parameter highlights to Erlang
This doesn't work robustly (within pattern matches). Only regular
bindings are highlighted as parameters. In order to highlight all
parameters even in matches, we would need an arbitrary nesting operator
in queries which doesn't exist yet in tree-sitter.
2022-11-24 11:07:05 +09:00
Michael Davis
452f7d071c Improve Edoc highlighting within Erlang
This highlights edoc within Erlang comments. The trick was to have
the Erlang grammar consume newlines and then give them to EDoc in the
injection to use so that line-wise elements could be parsed accurately.
2022-11-24 11:07:05 +09:00
Michael Davis
a3f321a531 Follow parent links when calculating changes since a revision
The 'revisions' field on History can't be treated as linear: each
Revision in the revisions Vec has a parent link and an optional child
link. We can follow those to unroll the recent history.
2022-11-24 10:57:12 +09:00
Michael Davis
4a103db622 Apply inversions to Views on undo/redo
When using undo/redo, the history revision can be decremented. In that
case we should apply the inversions since the given revision in
History::changes_since. This prevents panics with jumplist operations
when a session uses undo/redo to move the jumplist selection outside
of the document.
2022-11-24 10:57:12 +09:00
Michael Davis
fd00f3a70e Don't apply transactions to Views in undo/redo
View::apply should only be called by EditorView after
42e37a571e. This change removes the
duplicate calls within undo/redo which could cause a panic.
2022-11-24 10:57:12 +09:00
Michael Davis
94eb3de776 Add test case that panics on undo
This case panics since undo/redo call View::apply and here, the edit
that moves the jumplist selection out-of-bounds is not yet applied when
View::apply is called in undo/redo. View::apply should only be called
by the EditorView now.
2022-11-24 10:57:12 +09:00
Tshepang Mbambo
590a628460 tutor: Add missing quotes (#4832) 2022-11-22 21:51:17 -06:00
alois31
26ec1cf39a Add QML language support (#4842)
Fixes https://github.com/helix-editor/helix/issues/2771
2022-11-22 21:49:02 -06:00
Michael Davis
42e37a571e Apply transactions to all views (#4733)
* Add a test case for updating jumplists across windows

* Apply transactions to all views on history changes

This ensures that jumplist selections follow changes in documents, even
when there are multiple views (for example a split where both windows
edit the same document).

* Leave TODOs for cleaning up View::apply

* Use Iterator::reduce to compose history transactions

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-11-23 12:28:49 +09:00
dependabot[bot]
642a961c03 build(deps): bump tokio from 1.21.2 to 1.22.0 (#4846)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.21.2 to 1.22.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.21.2...tokio-1.22.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-22 13:24:37 -06:00
dependabot[bot]
5ad3befe9a build(deps): bump Swatinem/rust-cache from 1 to 2 (#4843)
Bumps [Swatinem/rust-cache](https://github.com/Swatinem/rust-cache) from 1 to 2.
- [Release notes](https://github.com/Swatinem/rust-cache/releases)
- [Changelog](https://github.com/Swatinem/rust-cache/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Swatinem/rust-cache/compare/v1...v2)

---
updated-dependencies:
- dependency-name: Swatinem/rust-cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-22 18:15:36 +09:00
Blaž Hrastnik
6aa345a6ce ci: Simplify tag name fetching (set-output is deprecated) 2022-11-22 18:08:11 +09:00
Blaž Hrastnik
33ae498e9f ci: Remove a bunch of actions-rs/cargo uses 2022-11-22 18:08:11 +09:00
Pascal Kuthe
f538b69759 significantly improve treesitter performance while editing large files (#4716)
* significantly improve treesitter performance while editing large files

* Apply stylistic suggestions from code review

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>

* use PartialEq and Hash instead of a freestanding function

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-11-22 11:54:22 +09:00
Michael Davis
9059c65a53 lsp: Check server provider capabilities (#3554)
Language Servers may signal that they do not support a method in
the initialization result (server capabilities). We can check these
when making LSP requests and hint in the status line when a method
is not supported by the server. This can also prevent crashes in
servers which assume that clients do not send requests for methods
which are disabled in the server capabilities.

There is an existing pattern the LSP client module where a method
returns `Option<impl Future<Output = Result<_>>>` with `None` signaling
no support in the server. This change extends this pattern to the rest
of the client functions. And we log an error to the statusline for
manually triggered LSP calls which return `None`.
2022-11-22 11:52:23 +09:00
Bob
1db01caec7 remove duplicated shell calls (#3465) 2022-11-22 10:55:46 +09:00
Michael Davis
8102c3224f Limit the number of items in the jumplist (#4750)
Previously, jumplists could grow unchecked. Every transaction is
applied to jumplist selections to ensure that they are up to date
and within document bounds, so this would cause every edit to become
more expensive as jumplist lengths increased throughout a session.
Setting a maximum number of entries limits the cost.

Vim and Neovim limit their jumplists:

* b298fe6cba/src/structs.h (L141)
* e8cc489acc/src/nvim/mark_defs.h (L57)

Notably, Kakoune does not. In Kakoune, changes are applied to jumplist
entries lazily as you hit `<C-o>`/`<C-i>` though, so Kakoune doesn't
have the same growing cost concerns. Kakoune also does not have a
concept of a View which limits the cost further.

Vim and Neovim limit to 100. This seems unreasonably high to me so I've
set this to 30 to start. We can increase if this is problematically
low.
2022-11-22 10:54:50 +09:00
dependabot[bot]
4443885b38 build(deps): bump cc from 1.0.76 to 1.0.77 (#4844)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.0.76 to 1.0.77.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Commits](https://github.com/rust-lang/cc-rs/compare/1.0.76...1.0.77)

---
updated-dependencies:
- dependency-name: cc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-21 17:47:45 -06:00
dependabot[bot]
4ef6621c24 build(deps): bump serde_json from 1.0.87 to 1.0.88 (#4845)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.87 to 1.0.88.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.87...v1.0.88)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-21 17:46:59 -06:00
Yusuf Bera Ertan
48e44720e4 build(nix): don't run tests in builds since CI runs them already, update inputs (#4834) 2022-11-21 09:06:43 -06:00
Michael Davis
0b2bb061b9 Bump TREE_SITTER_MATCH_LIMIT to 256 (#4830)
The limit of 64 breaks some highlighting in Erlang files with
complicated record definitions. Bumping to 256  seems to work on all
files I have seen.
2022-11-21 18:13:59 +09:00
Michael Davis
bbde897ac3 Select new pasted text in normal mode only (#4824)
d6323b7cbc changed the behavior of paste
to select the newly inserted text. This is preferrable in normal mode
because it's useful to be able to act on the new text. This behavior
is worse for insert or select mode though:

* In insert mode, the cursor ends up on the last character of the newly
  selected text, so further typing inserts text before the last
  character.
* In select mode, the current selection is replaced with the new text
  selection which doesn't extend the current selection. With this
  change, the selection is extended to include the new text.

This aligns the behavior more closely with Kakoune, but it's
coincidental instead of intentional: Kakoune doesn't implement
bracketed paste (AFAIK) which causes this behavior in insert mode,
and Kakoune doesn't have a select mode.
2022-11-21 11:49:44 +09:00
A-Walrus
2f9ca3840a Add preview for scratch buffers in buffer picker (#3454) 2022-11-20 19:58:35 -06:00
Sora
420e33a600 Implement simple indents.scm for Elixir (#4821) 2022-11-20 18:36:19 -06:00
Chickenkeeper
117239ea45 Fix broken html doctype highlighting (#4829) 2022-11-20 12:51:58 -06:00
Filipe Azevedo
8dac863a5b Add :reload-all command (#4663) 2022-11-20 12:39:26 -06:00
Matthew Toohey
46eb185d45 build(nix): update nci (#4823) 2022-11-19 19:54:47 -06:00
Lennard Hofmann
0e23e4f882 Make r<tab> and f<tab> work (#4817)
Previously, commands such as `r<tab>` (replace with tab) or `t<tab>`
(select till tab) had no effect. This is because `KeyCode::Tab` needs
special treatment (like `KeyCode::Enter`).
2022-11-19 11:08:03 -06:00
Blaž Hrastnik
7e99087fa3 minor: render_diagnostics doesn't require &self either 2022-11-19 15:41:55 +09:00
Blaž Hrastnik
a640ab6b1f Avoid repeatedly loading config 2022-11-19 15:41:03 +09:00
Michael Davis
8be2d1dcbf Handle language server termination (#4797)
This change handles a language server exiting. This was a UX sore-spot:
if a language server crashed, Helix did not recognize the exit and
continued to send requests to it. All requests would timeout since they
would not receive responses. This would also hold-up Helix closing
itself down since it would try to gracefully shutdown the server which
is implemented in the LSP spec as a request.

We could attempt to automatically restart the language server on crash.
I left this for future work since that change will need to be slightly
complicated: it will need to cover the case of a language server
repeatedly crashing.
2022-11-19 13:14:36 +09:00
ath3
598bd8bf11 Update tree-sitter-cmake (#4809) 2022-11-18 14:13:13 -06:00
Michael Davis
89efb4f711 lsp: Resolve completion item asynchronously on idle-timeout (#4781)
d7d0d5ffb7 resolves completion items on
the idle-timeout event. The `Completion::resolve_completion_item`
function blocks on the LSP request though, which blocks the compositor
and in turn blocks the event loop. So until the language server returns
the resolved completion item, Helix is unable to respond to keypresses
or other LSP messages.

This is typically ok since the resolution request is fast but for some
language servers this can be problematic, and ideally we shouldn't be
blocking like this anyways.

When receiving a `completionItem/resolve` request, the Volar server
sends a `workspace/configuration` request to Helix and blocks itself
on the response, leading to a deadlock. Eventually the resolve request
times out within Helix but Helix is locked up and unresponsive in that
window.

This change resolves the completion item without blocking the
compositor.
2022-11-19 03:27:46 +09:00
Ollie Charles
eada6d534e Match .hs-boot files to Haskell (#4800)
Haskell source files are now either `.hs` (as before) or `.hs-boot`, which is a type of Haskell file that only contains type declarations (https://downloads.haskell.org/ghc/latest/docs/users_guide/separate_compilation.html#how-to-compile-mutually-recursive-modules)
2022-11-18 08:36:40 -06:00
Rohit K Viswanath
58e7e1c5e3 Theme: Mellow (#4770) 2022-11-18 08:33:55 -06:00
wes adams
19694877aa When buffer closes, focus on parent buffer (#4766) 2022-11-17 20:53:49 -06:00
Austen Adler
1569d2000b Select surrounding characters when using match/surround (m) mode (#4752)
Co-authored-by: Austen Adler <agadler@austenadler.com>
2022-11-17 20:46:03 -06:00
Felipe S. S. Schneider
9a4e6fdf25 Add support for color modes with Monokai Pro (#4789) 2022-11-17 20:22:49 -06:00
Blaž Hrastnik
767b179839 Update lang-support doc 2022-11-18 10:53:08 +09:00
Blaž Hrastnik
433ccef3fc Make nil the preferred language server over rnix-lsp 2022-11-18 09:52:05 +09:00
ChrHorn
322e957ea1 Remove prefix filtering from autocomplete menu (#4578)
PR #4134 switched the autocomplete menu from alphabetical to fuzzy
sorting. This commit removes the still existing filtering by prefix and
should enable full fuzzy sorting of the autocomplete menu.

closes #3084, #1807

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-11-17 10:16:03 +09:00
kristopherbullinger
7483c76222 update x_offset calculation in Buffer::set_string_truncated (#3839)
when `truncate_start` is `true`, the `x_offset` is now properly updated
according to the width of the content or the truncated length.
2022-11-17 10:06:50 +09:00
Michael Davis
94346356e7 Use TreeCursor to pretty-print :tree-sitter-subtree (#4606)
The current `:tree-sitter-subtree` has a bug for field-names when the
field name belongs to an unnamed child node. Take this ruby example:

    def self.method_name
      true
    end

The subtree given by tree-sitter-cli is:

    (singleton_method [2, 0] - [4, 3]
      object: (self [2, 4] - [2, 8])
      name: (identifier [2, 9] - [2, 20])
      body: (body_statement [3, 2] - [3, 6]
        (true [3, 2] - [3, 6])))

But the `:tree-sitter-subtree` output was

    (singleton_method
      object: (self)
      body: (identifier)
      (body_statement (true)))

The `singleton_method` rule defines the `name` and `body` fields in an
unnamed helper rule `_method_rest` and the old implementation of
`pretty_print_tree_impl` would pass the `field_name` down from the
named `singleton_method` node.

To fix it we switch to the [TreeCursor] API which is recommended by
the tree-sitter docs for traversing the tree. `TreeCursor::field_name`
accurately determines the field name for the current cursor position
even when the node is unnamed.

[TreeCursor]: https://docs.rs/tree-sitter/0.20.9/tree_sitter/struct.TreeCursor.html
2022-11-17 10:03:02 +09:00
Michael Davis
c6b83368b3 Capture word parts while calculating shellwords (#4632)
This fixes an edge case for completing shellwords. With a file
"a b.txt" in the current directory, the sequence `:open a\<tab>`
will result in the prompt containing `:open aa\ b.txt`. This is
because the length of the input which is trimmed when replacing with
completion is calculated on the part of the input which is parsed by
shellwords and then escaped (in a separate operation), which is lossy.
In this case it loses the trailing backslash.

The fix provided here refactors shellwords to track both the _words_
(shellwords with quotes and escapes resolved) and the _parts_ (chunks
of the input which turned into each word, with separating whitespace
removed). When calculating how much of the input to delete when
replacing with the completion item, we now use the length of the last
part.

This also allows us to eliminate the duplicate work done in the
`ends_with_whitespace` check.
2022-11-17 10:00:48 +09:00
Michael Davis
b474ee1843 Factor out common code for focusing the next view (#4607)
There is some common code between Editor::focus_next and Editor::focus
that can be eliminated by refactoring Tree::focus_next into a function
that only returns the next ViewId.
2022-11-17 09:59:59 +09:00
Michael Davis
6eec14ee37 Use key-sequence format for command palette keybinds (#4712)
The text within the command palette used a custom format to display
the keybinding for a command. This change switches to the key sequence
format that we use for pending keys and macros.
2022-11-17 09:58:54 +09:00
Pascal Kuthe
4b89177e53 sort fuzzy matches with equal score by length in picker (#4698) 2022-11-16 17:28:20 -06:00
Blaž Hrastnik
fe11ae2218 minor: Simplify some command code 2022-11-16 18:14:30 +09:00
Blaž Hrastnik
a3173c2280 minor: cloning filter and using count() is wasteful here 2022-11-16 18:14:30 +09:00
Garrett D'Amore
f843967059 Improvements to Meson syntax. (#4572)
Co-authored-by: Garrett D'Amore <garrett.damore@weka.io>
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-11-15 20:17:03 -06:00
dependabot[bot]
70ebbd018a build(deps): bump chrono from 0.4.22 to 0.4.23 (#4747)
Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.22 to 0.4.23.
- [Release notes](https://github.com/chronotope/chrono/releases)
- [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md)
- [Commits](https://github.com/chronotope/chrono/compare/v0.4.22...v0.4.23)

---
updated-dependencies:
- dependency-name: chrono
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-15 13:20:39 -06:00
dxtr85
888368dae9 Fix deprecation warnings for chrono 0.4.23 (#4738)
Co-authored-by: dxtr <dxtr@W540.mito>
2022-11-15 13:08:29 -06:00
Blaž Hrastnik
df6d04425d fix build 2022-11-15 23:34:00 +09:00
Armin Ronacher
392a018aeb Add command to add word boundaries to search (#4322)
* Add command to add word boundaries to search

* Calculate string capacity before building
2022-11-15 23:16:27 +09:00
Manos Mertzianis
77be98c783 Popup scrollbar (#4449)
* init

* cargo fmt

* optimisation of the scrollbar render both for Menu and Popup. Toggling off scrollbar for Popup<Menu>, since Menu has its own

* rendering scroll track

* removed unnecessary cast

* improve memory allocation

* small correction
2022-11-15 23:15:52 +09:00
ath3
3b7760dfb0 Refactor blackhole register (#4504) 2022-11-15 23:14:18 +09:00
Michael Davis
652497bdd6 Use tree-sitter-bicep fork with sources checked in (#4751) 2022-11-15 14:57:36 +09:00
Sora
506e8caba7 Remove Statement in Zig indentation query (#4745) 2022-11-14 19:46:38 -06:00
Gaurav Tyagi
91ff903bf3 Add global error/warning count statusline element (#4569) 2022-11-14 19:46:07 -06:00
Jonathan
1233c9a989 Add support for Bicep files (#4403) 2022-11-14 19:43:22 -06:00
dependabot[bot]
4791bd66b7 build(deps): bump cc from 1.0.74 to 1.0.76 (#4748)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.0.74 to 1.0.76.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Commits](https://github.com/rust-lang/cc-rs/compare/1.0.74...1.0.76)

---
updated-dependencies:
- dependency-name: cc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-14 18:24:32 -06:00
dependabot[bot]
4f924f4771 build(deps): bump similar from 2.2.0 to 2.2.1 (#4746)
Bumps [similar](https://github.com/mitsuhiko/similar) from 2.2.0 to 2.2.1.
- [Release notes](https://github.com/mitsuhiko/similar/releases)
- [Changelog](https://github.com/mitsuhiko/similar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mitsuhiko/similar/compare/2.2.0...2.2.1)

---
updated-dependencies:
- dependency-name: similar
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-14 18:23:17 -06:00
Michael Davis
c74b97447f Fix range offsets for multiple shell insertions (#4619)
d6323b7cbc introduced a regression for
shell commands like `|`, `!`, and `<A-!>` which caused the new
selections to be incorrect. This caused a panic when piping (`|`)
would cause the new range to extend past the document end.

The paste version of this bug was fixed in
48a3965ab4.

This change also inherits the direction of the new range from the old
range and adds integration tests to ensure that the behavior isn't
broken in the future.
2022-11-14 09:45:52 +09:00
wes adams
fd585c1ee4 Statusline indicator to show number of selected chars (#4682)
Co-authored-by: wes adams <wadams@grayshift.com>
2022-11-12 11:31:09 -06:00
asvln
1f72d34249 rename description for goto_line_end_newline 2022-11-11 19:14:08 -06:00
asvln
7468fa28fd add extend_prev_word_end command 2022-11-11 19:14:08 -06:00
Alexis (Poliorcetics) Bourget
e232333d4a fix: Outdated Rust queries after TS update
Ref: 3ddebf46e6
2022-11-11 18:43:55 -06:00
Alexis (Poliorcetics) Bourget
53b70d821e deps: Update tree-sitter-rust (supports let-else && let-chains) 2022-11-11 18:43:55 -06:00
Bruce Hopkins
bc0a3037ea feat(commands): increment by range (#4418) 2022-11-11 13:50:25 -05:00
Anton Romanov
5b73c8c724 Add port of VIM's Zenburn, a low-contrast color scheme for Vim (#4613) 2022-11-11 08:15:22 -06:00
Chris Kipp
d7be5463c5 update scala roots (#4701)
This adds in a couple more roots that are common in Scala.

- `build.sc` which is used in Mill
- `build.gradle` for Scala Gradle projects
- `.scala-build` for scala-cli projects
2022-11-11 07:49:56 -06:00
Gabriel Dinner-David
7367abd6c6 Update typescript grammar and queries (#4703)
* fix(grammars): update treesitter grammar and queries

* add override keyword

* Update runtime/queries/typescript/highlights.scm

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-11-11 14:42:56 +09:00
Pascal Kuthe
bb5a122cde improve performance of tree sitter query captures (for text object motions in particular) (#4707)
* add tree sitter match limit to avoid slowdowns for larger files

Affects all tree sitter queries and should speedup both
syntax highlighting and text object queries.
This has been shown to fix significant slowdowns with textobjects
for rust files as small as 3k loc.

* Apply suggestions from code review

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-11-11 10:47:12 +09:00
Philip Giuliani
e17ad2722a Enable elixir-ls for heex language (#4679) 2022-11-10 09:21:31 -06:00
janos-r
bc52b0369b theme dark_plus color-modes insert and select (#4678) 2022-11-10 09:18:38 -06:00
Chris Kipp
183d1fadf4 feat: add sc to filetypes for Scala (#4697)
Files ending in `.sc` are known as "Scala Scripts". The scalac compiler
knows how to handle these, popular tools like
[Ammonite](https://github.com/com-lihaoyi/Ammonite) and
[scala-cli](https://github.com/Virtuslab/scala-cli) use them, and even
some Scala build tools like [mill](https://github.com/com-lihaoyi/mill)
use them as their build files (`build.sc`). This change just makes sure
that they are treated as Scala files so Metals kicks in.
2022-11-10 09:17:01 -06:00
André Sá
d7136d691a Update ayu themes (#4662) 2022-11-09 18:42:44 -06:00
Blaž Hrastnik
758bace221 fix test compilation 2022-11-09 22:17:14 +09:00
Blaž Hrastnik
264a455c18 Move terminal out of compositor 2022-11-09 22:10:49 +09:00
Blaž Hrastnik
00d7b18097 This term specific behavior really doesn't belong to compositor 2022-11-09 21:47:46 +09:00
Blaž Hrastnik
b2e7171fed Drop terminal interaction in compositor.size() 2022-11-09 21:37:56 +09:00
Blaž Hrastnik
d4f5cab7b5 Re-enable format_selections for a single selection range 2022-11-09 18:17:23 +09:00
Matthias Deiml
dee5b2a983 Add LSP workspace command picker (#3140)
* Add workspace command picker

* Make command typable

* Add optional argument to lsp-workspace-command
2022-11-09 18:17:09 +09:00
Michael Davis
3e84434c69 Fix panic from indenting on tree with errors
`deepest_preceding` is known to be a descendant of `node`. Repeated
calls of `Node::parent` _should_ eventually turn `deepest_preceding`
into `node`, but when the node is errored (the tree contains a syntax
error), `Node::parent` returns None.

In the typescript case:

    if(true) &&true
    //      ^ press enter here

The tree is:

    (program [0, 0] - [1, 0]
      (if_statement [0, 0] - [0, 15]
        condition: (parenthesized_expression [0, 2] - [0, 8]
          (true [0, 3] - [0, 7]))
        consequence: (expression_statement [0, 8] - [0, 15]
          (binary_expression [0, 8] - [0, 15]
            left: (identifier [0, 8] - [0, 8])
            right: (true [0, 11] - [0, 15])))))

`node` is the `program` node and `deepest_preceding` is the
`binary_expression`. The tree is errored on the `binary_expression`
node with `(MISSING identifier [0, 8] - [0, 8])`.

In the C++ case:

    ; <<
    // press enter after the ';'

The tree is:

    (translation_unit [0, 0] - [1, 0]
      (expression_statement [0, 0] - [0, 1])
      (ERROR [0, 1] - [0, 4]
        (identifier [0, 1] - [0, 1])))

`node` is the `translation_unit` and `deepest_preceding` is the `ERROR`
node.

In both cases, `Node::parent` on the errored node returns None.
2022-11-09 12:41:07 +09:00
Michael Davis
260ae3a0f4 style: Only call extend_nodes when deepest_preceding is Some 2022-11-09 12:41:07 +09:00
Kirawi
a19eee6450 Update dark_plus diff colors (#4661) 2022-11-08 15:06:27 -06:00
Anton Romanov
07d3157273 [rust highlights] fix scoped attribute macro matching (#4659)
Without this scoped attribute macros are not matched as macros.
Eg
```
  #[path::macro]
```
2022-11-08 13:41:09 -06:00
Marko Klobučar Ledinšćak
d8e9c85f5e error! on unknown CompletionItemKind (#4658) 2022-11-08 12:36:01 -06:00
Zhizhen He
0c30aeea5b fix typo (#4656) 2022-11-08 11:02:49 -06:00
0xflotus
75d7e0555e fix: small error (#4651) 2022-11-08 08:29:48 -06:00
Max Hille
64359f8b48 bash completion: use builtin filenames option (#4648)
Use a builtin bash option which detects filenames in completion outputs
and reflects this in sensible <tab> completion behaviour.
2022-11-08 07:50:17 -06:00
Blaž Hrastnik
bb303cf41d fix tests 2022-11-08 22:20:32 +09:00
Blaž Hrastnik
cd8bbbc044 fix tests 2022-11-08 21:48:56 +09:00
Doug Kelkhoff
7ed9e9cf25 Dynamically resize line number gutter width (#3469)
* dynamically resize line number gutter width

* removing digits lower-bound, permitting spacer

* removing max line num char limit; adding notes; qualified successors; notes

* updating tests to use new line number width when testing views

* linenr width based on document line count

* using min width of 2 so line numbers relative is useful

* lint rolling; removing unnecessary type parameter lifetime

* merge change resolution

* reformat code

* rename row_styler to style; add int_log resource

* adding spacer to gutters default; updating book config entry

* adding view.inner_height(), swap for loop for iterator

* reverting change of current! to view! now that doc is not needed
2022-11-08 21:19:59 +09:00
Blaž Hrastnik
c94feed83d core: Move state into the history module 2022-11-08 21:03:54 +09:00
Blaž Hrastnik
13126823f8 lsp: Support insertReplace
Fixes #4473
2022-11-08 20:50:49 +09:00
Danillo Melo
188aff059b Improve Ruby TextObjects (#4601) 2022-11-07 19:43:00 -06:00
dependabot[bot]
535cf90093 build(deps): bump regex from 1.6.0 to 1.7.0 (#4640)
Bumps [regex](https://github.com/rust-lang/regex) from 1.6.0 to 1.7.0.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.6.0...1.7.0)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-07 18:07:21 -06:00
dependabot[bot]
5bfe84fb4f build(deps): bump libloading from 0.7.3 to 0.7.4 (#4639)
Bumps [libloading](https://github.com/nagisa/rust_libloading) from 0.7.3 to 0.7.4.
- [Release notes](https://github.com/nagisa/rust_libloading/releases)
- [Commits](https://github.com/nagisa/rust_libloading/compare/0.7.3...0.7.4)

---
updated-dependencies:
- dependency-name: libloading
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-07 18:06:05 -06:00
Tobias Kohlbau
6cafd81e41 tutor: fix wording in recap for chapter 5 (#4629)
In recap for chapter 5.1 specify that the cursor is duplicted to the next suitable line
instead of the next line.

Signed-off-by: Tobias Kohlbau <tobias@kohlbau.de>
2022-11-07 07:53:29 -06:00
Ryan Palmer
da8f29eaa7 Fixed disorienting selection palette on Gruvbox theme (#4626)
Co-authored-by: ryan.palmer <ryan.palmer@servicenow.com>
2022-11-07 07:32:40 -06:00
Jonathan LEI
eddf9f0b7f Run clippy on workspace in CI (#4614) 2022-11-07 13:39:18 +09:00
Michael Davis
140df92d79 Fix command-mode completion behavior when input is escaped
If `a\ b.txt` were a local file, `:o a\ <tab>` would fill the prompt
with `:o aa\ b.txt` because the replacement range was calculated using
the shellwords-parsed part. Escaping the part before calculating its
length fixes this edge-case.
2022-11-07 13:38:16 +09:00
Michael Davis
3d283b2ca4 Escape filenames in command completion
This changes the completion items to be rendered with shellword
escaping, so a file `a b.txt` is rendered as `a\ b.txt` which matches
how it should be inputted.
2022-11-07 13:38:16 +09:00
Michael Davis
1536a65289 Fix whitespace handling in command-mode completion
8584b38cfb switched to shellwords for
completion in command-mode. This changes the conditions for choosing
whether to complete the command or use the command's completer.

This change processes the input as shellwords up-front and uses
shellword logic about whitespace to determine whether the command
or argument should be completed.
2022-11-07 13:38:16 +09:00
Michael Davis
48a3965ab4 Fix range offsets in multi-selection paste (#4608)
* Fix range offsets in multi-selection paste

d6323b7cbc introduced a regression with
multi-selection paste where pasting would not adjust the ranges
correctly. To fix it, we need to track the total number of characters
inserted in each changed selection and use that offset to slide each
new range forwards.

* Inherit selection directions on paste

* Add an integration-test for multi-selection pasting
2022-11-06 23:56:45 +09:00
ChrHorn
4ec2a21c6e Update Julia grammar, queries (#4588) 2022-11-05 13:30:40 -05:00
Michael Davis
3814987298 Fix panic on paste from blackhole register (#4497)
The sequence "_y"_p panics because the blackhole register contains an
empty values vec. This causes a panic when pasting since it unwraps
a `slice::last`.
2022-11-05 01:04:16 +09:00
Michael Davis
d6323b7cbc Select text inserted by shell or paste (#4458)
This follows changes in Kakoune to the same effects:

* p/<space>p: 266d1c37d0
* !/<A-!>: 85b78dda2e

Selecting the new data inserted by shell or pasting is often more
useful than retaining a selection of the pre-paste/insert content.
2022-11-05 01:02:19 +09:00
Blaž Hrastnik
9a898be959 nix: Bump flake dependencies 2022-11-04 21:06:28 +09:00
Blaž Hrastnik
c2c1280f02 Resolve a bunch of upcoming clippy lints 2022-11-04 21:06:28 +09:00
Antoine Stevan
921d351013 bump up LhKipp/tree-sitter-nu's version to latest (#4583) 2022-11-03 21:20:14 -05:00
throwaway-helix-zsh
d357f1673f Use language=bash when shebang line uses zsh (#4582)
This PR makes the editor use language=bash when the shebang line uses
zsh. This is in the same line as using language=bash for zsh related
file (~/.zshrc, ~/.zshenv etc.) as we already do.
2022-11-03 21:18:24 -05:00
ChrHorn
c667ff8da3 Increase default language server timeout for Julia (#4575) 2022-11-03 21:17:06 -05:00
Michael Davis
ba394dca6d Fix panic from two windows editing the same document (#4570)
* Clamp highlighting range to be within document

This fixes a panic possible when two vsplits of the same document
exist and enough lines are deleted from the document so that one of
the windows focuses past the end of the document.

* Ensure cursor is in view on window change

If two windows are editing the same document, one may delete enough of
the document so that the other window is pointing at a blank page (past
the document end). In this change we ensure that the cursor is within
view whenever we switch to a new window (for example with `<C-w>w`).

* Update helix-term/src/ui/editor.rs

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-11-03 15:09:21 +09:00
Charlie Groves
1bed2f3043 Use OSC 52 as a fallback for setting the system clipboard (#3220)
This adds a simple base64 implementation to keep us from adding a crate for one function. It's
mostly based on
a675443d32/src/engine/naive.rs (L42)
2022-11-02 10:12:40 +09:00
Yuriy
b156f57618 Add indentation for Python pattern matching
Add indentation for `match` and `case`.
2022-11-01 20:10:11 -05:00
Yuriy
e0b034dcd1 Add syntax highlighting for Python pattern matching
Add syntax highlighting for `match` and `case` keywords in Python
(https://peps.python.org/pep-0636/).
2022-11-01 20:10:11 -05:00
Jonathan LEI
db3383c76e Exit select mode on replace commands (#4554) 2022-11-01 20:08:25 -05:00
Garrett D'Amore
185236c3a4 Fix D unittest injection query. (#4562) 2022-11-01 19:44:56 -05:00
Yuriy Gabuev
c803ef8753 Fix delete_char_backward for paired characters (#4558)
When backward-deleting a character, if this character and the following
character form a Pair, we want to delete both. However, there is a bug
that deletes both characters also if both characters are closers of some
Pair.

This commit fixes that by adding an additional check that the deleted
character should be an opener in a Pair.

Closes https://github.com/helix-editor/helix/issues/4544.
2022-11-01 23:48:43 +09:00
Poliorcetics
8ff92c7492 Add missed test attribute in #4316 (#4557) 2022-11-01 21:37:19 +09:00
Armin Ronacher
8584b38cfb Correctly handle escaping in completion (#4316)
* Correctly handle escaping in completion

* Added escaping tests
2022-11-01 20:48:37 +09:00
Yusuf Bera Ertan
3881fef39d build(nix): update nci, fixup flake (#4537) 2022-10-31 19:52:03 -05:00
dependabot[bot]
e5319ea8c5 build(deps): bump once_cell from 1.15.0 to 1.16.0 (#4548)
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.15.0 to 1.16.0.
- [Release notes](https://github.com/matklad/once_cell/releases)
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.15.0...v1.16.0)

---
updated-dependencies:
- dependency-name: once_cell
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-31 19:31:08 -05:00
Jonas Everaert
79c7203a38 Added missing keywords to wat (wasm) hightlights (#4542)
added "if", "then", "else", "block", "loop", "end" and "mut" to the wat highlights.
2022-10-31 19:30:08 -05:00
dependabot[bot]
3792d9ebb7 build(deps): bump lsp-types from 0.93.1 to 0.93.2 (#4550)
Bumps [lsp-types](https://github.com/gluon-lang/lsp-types) from 0.93.1 to 0.93.2.
- [Release notes](https://github.com/gluon-lang/lsp-types/releases)
- [Changelog](https://github.com/gluon-lang/lsp-types/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gluon-lang/lsp-types/compare/v0.93.1...v0.93.2)

---
updated-dependencies:
- dependency-name: lsp-types
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-31 19:29:32 -05:00
dependabot[bot]
92b13f9e71 build(deps): bump cc from 1.0.73 to 1.0.74 (#4549)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.0.73 to 1.0.74.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Commits](https://github.com/rust-lang/cc-rs/compare/1.0.73...1.0.74)

---
updated-dependencies:
- dependency-name: cc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-31 19:29:01 -05:00
Sebastian Hoß
9b247b1104 Update SSH client config grammar & highlight queries (#4538)
Co-authored-by: Sebastian Hoß <seb@hoß.de>
2022-10-31 19:27:53 -05:00
seshotake
ed7ea8c9ba add highlights for env and ini file formats (#4536) 2022-10-31 19:23:09 -05:00
hh9527
9df4358492 Support WIT grammar (#4525) 2022-10-31 18:48:01 -05:00
dependabot[bot]
df3c6412ac build(deps): bump cachix/cachix-action from 11 to 12 (#4547)
Bumps [cachix/cachix-action](https://github.com/cachix/cachix-action) from 11 to 12.
- [Release notes](https://github.com/cachix/cachix-action/releases)
- [Commits](https://github.com/cachix/cachix-action/compare/v11...v12)

---
updated-dependencies:
- dependency-name: cachix/cachix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-31 18:21:51 -05:00
Konstantin Podsvirov
f41f28b662 Update windows install instructions (#4530) 2022-10-30 11:55:31 -05:00
seshotake
f6710879d1 Update SQL grammar (#4529) 2022-10-30 11:54:37 -05:00
Triton171
908529ccac Update LaTex grammar (#4528)
Fix comment injection & add highlighting for math delimiters.
2022-10-30 11:45:58 -05:00
Matthew Toohey
00cf12f571 fix: make scroll aware of tabs and wide characters (#4519) 2022-10-29 16:23:18 -05:00
Matthew Toohey
f054a3f3ed feat(lang): add xml (#4518) 2022-10-29 15:41:28 -05:00
Poliorcetics
2935e9da19 feat: Categorize Rust's keywords using more specific scopes (#4510) 2022-10-29 10:36:26 -05:00
Kristoffer Flottorp
e3eaad1479 Fleetish: Adjustments to resemble official theme and reworked diagnostics to reduce subconjunctival hemorrhage (#4487) 2022-10-29 10:35:35 -05:00
Jaden
b5e7501935 feat(lang): add kdl grammar (#4481) 2022-10-29 10:33:23 -05:00
Matthias Deiml
5e256e4a98 Make shell_impl concurrent (#3180) 2022-10-29 10:24:33 -05:00
Poliorcetics
c58e1729ce fix: Never create automatic doc popups outside of Insert mode (#4456) 2022-10-28 18:20:55 -05:00
rsteube
26f21da531 language: added vhs (#4486) 2022-10-28 08:22:41 -05:00
Michael Davis
cefdface3b Include colons for typable commands in command palette (#4495)
Before:

    Goto next buffer. [buffer-next]

After:

    Goto next buffer. [:buffer-next]
2022-10-28 21:42:40 +09:00
Dario Oddenino
6752c7d347 Trim quotes and braces from paths in goto_file_impl (#4370)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-10-27 20:31:28 -05:00
Sora
de5b100556 Add the debugger for Zig (#4492) 2022-10-27 20:19:01 -05:00
lazytanuki
b4a3dd8f89 feat(lsp): LSP preselected items appear first in completion menu (#4480)
* feat(lsp): LSP preselected items appear first in completion menu

* fix: shorter diff
2022-10-27 23:16:55 +09:00
Matthias Deiml
b1ffbbd49f Include unnamed children for html injected into inline markdown (#4478) 2022-10-27 08:40:47 -05:00
Matthias Deiml
27217bb435 Update tree-sitter markdown grammar (#4483) 2022-10-27 08:39:22 -05:00
A-Walrus
c4d7cde6c8 Allow the area to be bigger than u16 (width and height remain u16) (#4318)
Now the editor can fill **very** large terminals.
Changed/removed tests which check the truncating behaviour.
2022-10-26 12:00:13 +09:00
James O. D. Hunt
ac0fe29867 commands: Make no arg ':theme' show name (#3740)
Most commands that accept an argument show their current value if no
argument is specified. The `:theme` command previously displayed an
error message in the status bar if not provided with an argument:

```
Theme name not provided
```

It now shows the current theme name in the status bar if no argument is
specified.

Signed-off-by: James O. D. Hunt <jamesodhunt@gmail.com>

Signed-off-by: James O. D. Hunt <jamesodhunt@gmail.com>
2022-10-26 11:59:50 +09:00
Gaurav Tyagi
ba9e50e93b Add :update that will write the changes if the file has been modified. (#4426)
* add command update that will write the changes if file hasn been modified

* add docs

* update the docs
2022-10-26 11:58:49 +09:00
Michał Zabielski
65edf9c198 fix: repeating repeat operator (#4450) 2022-10-25 21:15:46 -05:00
GabrielDertoni
9fae4b8118 fix: terminal freezing on shell_insert_output
This bug occurs on `shell_insert_output` and `shell_append_output`
commands.

The previous implementation would create a child process using the Rust
stdlib's `Command` builder. However, when nothing should be piped in
from the editor, the default value for `stdin` would be used. According
to the Rust stdlib documentation that is `Stdio::inherit` which will
make the child process inherit the parent process' stdin. This would
cause the terminal to freeze.

This change will set the child process' stdin to `Stdio::null` whenever
it doesn't pipe it. In the `if` statement where this change was made
there was an extra condition for windows that I am not sure if would
require some special treatment.
2022-10-25 20:24:44 -05:00
Michael Davis
c47ca33137 Render diagnostics in the file picker preview (#4324)
This is mostly for the sake of the diagnostics pickers: without
rendering the diagnostic styles, it's hard to tell where the entries
in the picker are pointing to.
2022-10-25 21:03:35 +09:00
dependabot[bot]
001e4e304b build(deps): bump serde from 1.0.145 to 1.0.147 (#4463)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-24 18:37:25 -05:00
dependabot[bot]
6aacdaaf9f build(deps): bump futures-executor from 0.3.24 to 0.3.25 (#4464)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-24 18:35:12 -05:00
dependabot[bot]
02385599e1 build(deps): bump serde_json from 1.0.86 to 1.0.87 (#4462)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-24 18:18:50 -05:00
dependabot[bot]
093842988b build(deps): bump termini from 0.1.2 to 0.1.4 (#4461)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-24 18:18:41 -05:00
dependabot[bot]
6ea2c54152 build(deps): bump futures-util from 0.3.24 to 0.3.25 (#4460)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-24 18:14:27 -05:00
dependabot[bot]
45da569a4c build(deps): bump anyhow from 1.0.65 to 1.0.66 (#4459)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-24 18:14:05 -05:00
Owen Lynch
d8ffa02255 Update scala treesitter grammar (#4353) 2022-10-24 17:44:36 -05:00
Mike Trinkala
801984c7fc Update textwrap to 0.16.0 (#4437) 2022-10-23 18:02:58 -05:00
Mr. E
ce469abfe2 feat(themes): add mode-specific styles to the tokyonight themes (#4415)
Co-authored-by: SoraTenshi <dream@neoncity.dev>
2022-10-22 14:25:41 -05:00
Michael Davis
d7d0d5ffb7 lsp: Resolve completion items missing documentation on idle (#4406)
Some language servers may not send the `documentation` field if it
is expensive to compute. Clients can request the missing field with
a completionItem/resolve request.

In this change we use the idle-timeout event to ensure that the current
completion item is resolved.
2022-10-22 10:04:50 +09:00
Michael Davis
17daf6ac0a Change syntax for suffix file-types configurations (#4414)
The change in d801a6693c to search for
suffixes in `file-types` is too permissive: files like the tutor or
`*.txt` files are now mistakenly interpreted as R or perl,
respectively.

This change changes the syntax for specifying a file-types entry that
matches by suffix:

```toml
file-types = [{ suffix = ".git/config" }]
```

And changes the file-type detection to first search for any non-suffix
patterns and then search for suffixes only with the file-types entries
marked explicitly as suffixes.
2022-10-22 09:34:15 +09:00
Mehedi Hasan
131d8392bb Theme: Papercolor: Fixed cursorline background (#4317) 2022-10-21 17:37:10 -05:00
PORTALSURFER
a449192ee9 Added 2 new themes (#4367) 2022-10-21 17:35:02 -05:00
Sora
664064b3cc Add textobjects.scm for zig (#4409) 2022-10-21 17:32:29 -05:00
Christian Speich
79ef39ab3a syntax: Don't force lower-case for filenames (#4346)
Just like for grammars we currently force a lower-case of the name for
some actions (like filesystem lookup). To make this consistent and less
surprising for users, we remove this lower-casing here.

Note: it is still the preferred way to name both language and grammar in
lower-case

Signed-off-by: Christian Speich <cspeich@emlix.com>
2022-10-21 08:11:25 -05:00
Christian Speich
4b85aeb2b6 grammar: Don't require lower-case (#4346)
Currently we always lower-case the grammar name when loading it. While it
is somewhat of an convention to name tree-sitter grammars in lowercase
there is no rule to enforce it.

This patch removes the lower-casing to allow all possible grammar names.

Signed-off-by: Christian Speich <cspeich@emlix.com>
2022-10-21 08:11:25 -05:00
Alexis (Poliorcetics) Bourget
34389e1d54 nit: Do less allocations in ui::menu::Item::label implementations
This complicates the code a little but it often divides by two the number of allocations done by
the functions. LSP labels especially can easily be called dozens of time in a single menu popup,
when listing references for example.
2022-10-21 07:42:33 -05:00
Alexis (Poliorcetics) Bourget
3aea33a415 nit: move an allocation to happen after a continue, making sure it's
not done for nothing
2022-10-21 07:42:33 -05:00
Skyler Hawthorne
5a848344a9 fix: write-all crash (#4384)
When we do auto formatting, the code that takes the LSP's response and applies
the changes to the document are just getting the currently focused view and
giving that to the function, basically always assuming that the document that
we're applying the change to is in focus, and not in a background view.

This is usually fine for a single view, even if it's a buffer in the
background, because it's still the same view and the selection will get updated
accordingly for when you switch back to it. But it's obviously a problem for
when there are multiple views, because if you don't have the target document in
focus, it will ask the document to update the wrong view, hence the crash.

The problem with this is picking which view to apply any selection change to.
In the absence of any more data points on the views themselves, we simply pick
the first view associated with the document we are saving.
2022-10-21 16:43:22 +09:00
Nimrod
bad49ef2d0 Fix unexpected behavior in delete_word_backward and delete_word_forward (#4392) 2022-10-21 15:08:37 +09:00
Skyler Hawthorne
f486f34ebe flush writes on force quit (#4397)
When force quitting, we need to block on the pending writes to ensure
that write commands succeed before exiting, and also to avoid a crash
when all the views are gone before the auto format call returns from
the LS.
2022-10-21 13:28:29 +09:00
Blaž Hrastnik
74a6a2282e Add undercurl styles to the default theme 2022-10-21 13:27:05 +09:00
Blaž Hrastnik
511d9d8a52 cargo fmt 2022-10-21 13:26:22 +09:00
Charlie Groves
7e29ee6dae Autosave all when the terminal loses focus (#3178)
* Autosave all when the terminal loses focus

* Correct comment on focus config

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>

* Need a block_try_flush_writes in all quit_all paths

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-10-21 10:35:02 +09:00
A-Walrus
4ff5feeb0c Fix shellwords delimiter handling (#4098)
* Fix shellwords delimiter handling

This allows commands such as `:set statusline.center ["file-type"]` to
work. Before the quotes within the list would mess it up.
Also added a test to ensure correct behavior

* Rename Delimiter -> OnWhitespace
2022-10-21 10:06:57 +09:00
Pascal Kuthe
9af7c1c9f3 Sort by fixed diagnostics/is_preffered within codeaction categories 2022-10-21 10:03:00 +09:00
Pascal Kuthe
189aa0bfcf never sort menu items when no fuzzy matching is possible 2022-10-21 10:03:00 +09:00
Pascal Kuthe
dc3527f52d use permalink to vscode repo 2022-10-21 10:03:00 +09:00
Pascal Kuthe
8d8b5d6624 use stable sort instead of allocating new vectors 2022-10-21 10:03:00 +09:00
Pascal Kuthe
c70d762a7b sort autocompletins by fuzzy match 2022-10-21 10:03:00 +09:00
Pascal Kuthe
8673c1ec0c sort codeaction by their kind instead of alphabetically 2022-10-21 10:03:00 +09:00
Kirawi
ce399471f0 simplify encoding test macro (#4385) 2022-10-21 09:58:13 +09:00
Greg Troszak
fbf8078611 Clarify use of HELIX_RUNTIME (#4382) 2022-10-20 19:39:30 -05:00
Skyler Hawthorne
6a0b450f55 Fix multi byte auto pairs (#4024)
* Fix test::print for Unicode

The print function was not generating correct translations when
the input has Unicode (non-ASCII) in it. This is due to its use of
String::len, which gives the length in bytes, not chars.

* Fix multi-code point auto pairs

The current code for auto pairs is counting offsets by summing the
length of the open and closing chars with char::len_utf8. Unfortunately,
this gives back bytes, and the offset needs to be in chars.

Additionally, it was discovered that there was a preexisting bug where
the selection was not computed correctly in the case that the cursor
was:

1. a single grapheme in width
2. this grapheme was more than one char
3. the direction of the cursor is backwards
4. a secondary range

In this case, the offset was not being added into the anchor. This was
fixed.

* migrate auto pairs tests to integration

* review comments
2022-10-21 09:22:20 +09:00
Matouš Dzivjak
e25af1f744 feat(view): re-use align_view function (#4390) 2022-10-20 18:53:05 -05:00
Michael Davis
66238e8556 Silence dead_code warning on AppBuilder::with_config
This function is not currently used but is likely to be useful in
the future, so this change silences the dead_code warning.
2022-10-21 08:43:15 +09:00
Michael Davis
313579d27c Remove language-server configuration in integration tests
This change removes language server configuration from the default
languages.toml config for integration tests. No integration-tests
currently depend on the availability of a language server but if any
future test needs to, it may provide a language server configuration
by passing an override into the `test_syntax_conf` helper.

Language-servers in integration tests cause false-positive failures
when running integration tests in GitHub Actions CI. The Windows
runner appears to have `clangd` installed and all OS runners have
the `R` binary installed but not the `R` language server package.
If a test file created by `tempfile::NamedTempFile` happens to have a
file extension of `r`, the test will most likely fail because the
R language server will fail to start and will become a broken pipe,
meaning that it will fail to shutdown within the timeout, causing a
false-positive failure. This happens surprisingly often in practice.

Language servers (especially rust-analyzer) also emit unnecessary
log output when initializing, which this change silences.
2022-10-21 08:43:15 +09:00
Michael Davis
1243db11a5 Use helix_view::apply_transaction in integration-tests
`helix_view::apply_transaction` closes over `Document::apply` and
`View::apply` to ensure that jumplist entries are updated when a
document changes from a transaction. `Document::apply` shouldn't
be called directly - this helper function should be used instead.
2022-10-21 08:43:15 +09:00
Matouš Dzivjak
4cff625054 chore(view): remove indent_unit helper fn (#4389) 2022-10-20 17:05:04 -05:00
Garrett D'Amore
36f97b6aad Add support for D (#4372)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-10-20 16:54:17 -05:00
Jared Ramirez
de607830a2 Upgrade rescript tree sitter & highlights (#4356)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-10-20 16:30:16 -05:00
Matouš Dzivjak
eee8362015 fix(commands): no last picker error (#4387) 2022-10-20 15:50:54 -05:00
midnightexigent
d801a6693c Allow using path suffixes to associate language file-types (#2455)
* feat(syntax): add strategy to associate file to language through pattern

File path will match if it ends with any of the file types provided in the config.
Also used this feature to add support for the .git/config and .ssh/config files

* Add /etc/ssh/ssh_config to languages.toml

* cargo xtask docgen

* Update languages.md

* Update languages.md

* Update book/src/languages.md

Co-authored-by: Ivan Tham <pickfire@riseup.net>

* Update book/src/languages.md

Co-authored-by: Ivan Tham <pickfire@riseup.net>

Co-authored-by: Ivan Tham <pickfire@riseup.net>
2022-10-20 23:13:56 +09:00
Blaž Hrastnik
78c0cdc519 Merge pull request #2267 from dead10ck/fix-write-fail
Write path fixes
2022-10-20 23:11:22 +09:00
Alex
8c9bb23650 Update windows install instructions (#4351) 2022-10-19 17:19:03 -05:00
Fisher Darling
4174b25b3d Pretty print tree-sitter-subtree expression (#4295) 2022-10-19 17:17:50 -05:00
Sukera
a7e7c2cc05 Add roots for julia to languages.toml (#4361) 2022-10-19 07:53:22 -05:00
Blaž Hrastnik
418a622db9 Merge pull request #4061 from pascalkuthe/undercurl-modifier
Support different kinds of underline rendering (updated)
2022-10-19 13:51:13 +09:00
Skyler Hawthorne
756253b43f fix tree_sitter_scopes 2022-10-19 00:01:00 -04:00
Skyler Hawthorne
9a406b569b reduce LSP timeout to 3s 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
759d55cc81 fail if doc save sender is closed 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
e645804b0a Editor::flush_writes returns an error 2022-10-18 22:31:39 -04:00
Blaž Hrastnik
52ba550098 Use flush_writes in application.close() 2022-10-18 22:31:39 -04:00
Blaž Hrastnik
2a43ee0164 doc.close() now unused 2022-10-18 22:31:39 -04:00
Blaž Hrastnik
1b6f7319cd Wire up save_queue as a part of new_document rather than open 2022-10-18 22:31:39 -04:00
Blaž Hrastnik
55b50d9e83 Seems like this flush is unnecessary 2022-10-18 22:31:39 -04:00
Blaž Hrastnik
b155e861ad Use a write_count to determine how many writes left to flush 2022-10-18 22:31:39 -04:00
Blaž Hrastnik
b0212b3611 Deduplicate flush_writes 2022-10-18 22:31:39 -04:00
Blaž Hrastnik
30c93994b5 Use a single save_queue on the editor 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
beb3427bfb improve app close failure display 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
bf378e71b0 fix tests 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
31d1bbfddb review comments 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
9e64974f13 remove Document::format_and_save 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
3f07885b35 document should save even if formatter fails 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
b530a86d1f remove Callback::Compositor variant
To reduce likelihood of accidental discarding of important callbacks
2022-10-18 22:31:39 -04:00
Skyler Hawthorne
b3fc31a211 move language server refresh to document saved event handler 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
af03df3413 fix write scratch buffer to file 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
18c32118b1 Save text in document saved events, use in status message 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
f82a551b98 Rename doc save event names to past tense 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
6cffc7f05d Add note about log level for integration tests 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
57de4e6251 various fixes in write-all path 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
7b11e9ac69 fix erroneous write sender close
This was not distinguishing the error types when trying a receive on an empty
receiver, which was erroneously causing the sender to be closed when trying to
flush the writes when there were none
2022-10-18 22:31:39 -04:00
Skyler Hawthorne
d544376590 reset idle timer for all events 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
e5fd5e2a9c fix panic when view of pending write is closed 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
faa00d4cc3 increase LSP shutdown timeout
The Clang LAP takes a long time to shut down on Windows
2022-10-18 22:31:39 -04:00
Skyler Hawthorne
8c667ef8de factor editor event handling into function 2022-10-18 22:31:39 -04:00
Skyler Hawthorne
aaa1450678 fix write-quit with auto format
write-quit will now save all files successfully even when there is auto
formatting
2022-10-18 22:31:39 -04:00
Skyler Hawthorne
c9418582d2 fix modified status with auto format 2022-10-18 22:31:38 -04:00
Skyler Hawthorne
cb23399dee improve reliability of shutdown 2022-10-18 22:31:38 -04:00
Skyler Hawthorne
b8a07f7d15 add conditional noop render back
It makes it much slower without stubbing this out
2022-10-18 22:31:38 -04:00
Skyler Hawthorne
69c9e44ef2 update write-quit to wait for saves 2022-10-18 22:31:38 -04:00
Skyler Hawthorne
e1f7bdb1d2 fix buffer-close 2022-10-18 22:31:38 -04:00
Skyler Hawthorne
83b6042b97 fix(write): do not set new path on document until write succeeds
If a document is written with a new path, currently, in the event that
the write fails, the document still gets its path changed. This fixes
it so that the path is not updated unless the write succeeds.
2022-10-18 22:31:38 -04:00
Skyler Hawthorne
a5a93182cd fix: buffer-close ensuring writes
Make sure buffer-close waits for the document to finish its writes.
2022-10-18 22:31:38 -04:00
Skyler Hawthorne
d706194597 chore(write): serialize write operations within a Document
The way that document writes are handled are by submitting them to the
async job pool, which are all executed opportunistically out of order. It
was discovered that this can lead to write inconsistencies when there
are multiple writes to the same file in quick succession.

This seeks to fix this problem by removing document writes from the
general pool of jobs and into its own specialized event. Now when a
user submits a write with one of the write commands, a request is simply
queued up in a new mpsc channel that each Document makes to handle its own
writes. This way, if multiple writes are submitted on the same document,
they are executed in order, while still allowing concurrent writes for
different documents.
2022-10-18 22:31:38 -04:00
Peter Phillips
faf0c521d1 Fix link to textobjects usage from keymap documentation (#4357) 2022-10-18 21:16:44 -05:00
Jonathan LEI
1a772d1b67 Fix deleting word from end of buffer (#4328) 2022-10-18 19:53:58 -05:00
zetashift
0c14d9f869 Add a first version of kanagawa theme (#4300) 2022-10-18 19:32:02 -05:00
Roberto Vidal
1f74cf45d4 display tree sitter scopes in a popup (#4337) 2022-10-19 00:00:00 +05:30
Philipp Mildenberger
d17ffc47f0 Use the same WalkBuilder configuration for the global search file picker as the default file picker (#4334)
Skip searching .git in global search, similar to how file picker skips listing files in .git.
2022-10-18 22:58:16 +05:30
dependabot[bot]
fee5db161b build(deps): bump cachix/install-nix-action from 17 to 18 (#4340)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-17 20:03:04 -05:00
dependabot[bot]
414214f883 build(deps): bump tokio-stream from 0.1.10 to 0.1.11 (#4341)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-17 19:56:29 -05:00
dependabot[bot]
38746b04b4 build(deps): bump cachix/cachix-action from 10 to 11 (#4339)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-17 19:55:15 -05:00
Clay
b07ef6bec3 Bump tree-sitter-elixir (#4333) 2022-10-18 01:05:14 +09:00
A-Walrus
8bbddf90ff Replace in_bounds with calculation of end_indent
Instead of repeatedly checking if it is in_bounds, calculate the
max_indent beforehand and just loop. I added a debug_assert to "prove"
that it never tries drawing out of bounds.
2022-10-18 00:38:16 +09:00
A-Walrus
1de02a147c Only draw indent guides within bounds
Better performance, and otherwise very long lines with lots of tabs
will wrap around the u16 and come back on the other side, messing up
the beginning skip_levels.
2022-10-18 00:38:16 +09:00
A-Walrus
2c36e33e0a Make skip_levels a u8 2022-10-18 00:38:16 +09:00
A-Walrus
3ba665d804 Fix rendering of lines longer than 2^16
Before things would be cast to u16 earlier than needed, which would
cause problems for insanely long lines (longer than 2^16 ~ 65 thousand)
2022-10-18 00:38:16 +09:00
Gokul Soumya
4e691d6247 Change diagnostic picker keybind to <space>d (#4229)
Also changes workspace diagnostic picker bindings to <space>D and
changes the debug menu keybind to <space>g, the previous diagnostic
picker keybind. This brings the diagnostic picker bindings more in
line with the jump to next/previous diagnostic bindings which are
currently on ]d and [d.
2022-10-17 16:45:42 +09:00
Blaž Hrastnik
09a6df199e Support Cairo 0.10 syntax 2022-10-17 10:35:15 +09:00
Blaž Hrastnik
431f9c14f3 Support Cairo 0.10 syntax 2022-10-17 10:35:15 +09:00
Jonathan LEI
17488f14d6 Fix Cairo comment token 2022-10-17 10:35:15 +09:00
echoriiku
b29531ceab Fix readability of highlighted text on the rose_pine themes using official palettes (#4221) 2022-10-17 10:34:38 +09:00
Brandon Dong
a330b5d224 Fix selecting pop dark theme (#4323) 2022-10-16 19:19:19 -05:00
Michael Davis
50b191a7df Log failures to load tree-sitter parsers as error (#4315)
Info logs don't show up in the log file by default, but this line
should: failures to load tree-sitter parser objects are useful errors.
A parser might fail to load it is misconfigured
(https://github.com/helix-editor/helix/pull/4303#discussion_r996448543)
or if the file does not exist.
2022-10-17 01:29:57 +05:30
Michael Davis
5f4f171b73 Fix debug assertion for diagnostic sort order (#4319)
The debug assertion that document diagnostics are sorted incorrectly
panics for cases like `[161..164, 162..162]`. The merging behavior
in the following lines that relies on the assertion only needs the
input ranges to be sorted by `range.start`, so this change simplifies
the assertion to only catch violations of that assumption.
2022-10-17 01:22:04 +05:30
Ben White-Horne
63fe423710 Show keys required to enter each minor mode (#4302)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-10-16 11:58:18 -05:00
Filip Dutescu
2457111bf0 feat(csharp,debug): add C# debugger support (#4213) 2022-10-15 15:33:57 -05:00
Wojciech Kępka
661f48d62f themes: Add bogster_light theme (#4265)
Co-authored-by: Wojciech Kępka <wojciech.kepka@softax.pl>
2022-10-15 12:12:14 -05:00
Wojciech Kępka
05ca21cb1b themes: Update bogster theme (#4264)
Co-authored-by: Wojciech Kępka <wojciech.kepka@softax.pl>
2022-10-15 12:08:13 -05:00
Chickenkeeper
1c08c80e4f C# syntax highlight tweaks (#4285) 2022-10-15 11:29:50 -05:00
Sora
f444ba8beb Fixup Zig Indent Queries (#4281) 2022-10-15 11:10:16 -05:00
ZJPzjp
0e8e7cae3b fix :insert-output doc: inserting output **before** each selection (#4286) 2022-10-15 11:07:42 -05:00
Sam McCall
aef37d43d7 c/c++ highlighting: various tweaks
- treat `restrict`/`_Atomic` like `const`/`volatile` => @keyword.storage.modifier
- highlight `unsigned int` as builtin => @type.builtin
- recognize `static_cast` and friends => @keyword
- `template` is a kind of entity like `typename` => @keyword.storage.type
- many declaration modifiers have nothing to do with storage/types
  (explicit, friend, access specifiers, inline in C++) => @keyword
- fix floats highlighted as integer => @constant.numeric
2022-10-15 09:33:43 -05:00
Sam McCall
a3ed9169df c/c++ highlights: *& are @type or @operator based on context (#4278) 2022-10-14 20:05:39 -05:00
Poliorcetics
45e038f4d5 nit: remove a String allocation that is immediately used as an &str (#4277) 2022-10-14 17:35:00 -05:00
Nathaniel Graham
e80beaa7b0 Changed Selection Yank Message (#4275)
Co-authored-by: Nathaniel Graham <ngraham@protonmail.com>
2022-10-14 12:51:15 -05:00
Dario Oddenino
2d958d6c50 Add support for Purescript language (#4242) 2022-10-14 11:57:52 -05:00
IrishMaestro
13d81b7478 Created heisenberg theme for helix editor (#4209) 2022-10-13 20:35:02 -05:00
Chickenkeeper
b4e795d704 Fix C++ syntax highlighting, and improve C & WGSL highlighting (#4079) 2022-10-13 20:31:32 -05:00
Ben Lee-Cohen
cf4a5cca96 Monokai Pro Octagon statusline modes (#4247) 2022-10-13 20:26:03 -05:00
Pascal Kuthe
66a49080bc merge underline-style and underline-color into a single table 2022-10-13 19:03:58 +02:00
Tim Siegel
5077ce76b3 tutor: Normalize key names, capitalization, etc. 2022-10-12 18:12:54 -05:00
Tim Siegel
425df93fb8 book: Refer to keys by key names, not representations
This is an attempt to clean up the inconsistent way that keys are
written in various places. These rules require the fewest changes to the
existing text.

Use the "Key name", as defined in remapping.md, which uses
"Some-Modifiers-PascalCaseKey". The "Representation", which uses
"S-M-lowercasekey", is only used for configuration entries.

For key combinations which do not present a popup, just present the keys
one after the other, with no intervening space, like `]p`.

For key combinations which present a popup, separate them with ` + `,
like `Space + f`.

The Ctrl modifier is called Ctrl, not Control.
2022-10-12 18:12:54 -05:00
Tim Siegel
e542f2e08f tutor: Minor grammar fix
No need to say additionally, as well, also, etc. One is enough.
2022-10-12 18:12:54 -05:00
Tim Siegel
f5f4d3dc2a tutor: Clarify forward reference to "primary selection" 2022-10-12 18:12:54 -05:00
Tim Siegel
0571fa4d56 tutor: Clarify first multi-cursor example
If the reader is unfortunate enough to place the cursor at the beginning
of the line on step #1, subsequent steps will fail.
2022-10-12 18:12:54 -05:00
Tim Siegel
6db39eacd3 tutor: Clarify forward reference to "select command"
The phrase "Like the select command" suggests that the reader has been
introduced to select already. That doesn't happen until the next
chapter.
2022-10-12 18:12:54 -05:00
Michael Davis
e16c632760 Apply transactions to the jumplist for undo/redo (#4227)
Undo/redo/earlier/later call `Document::apply_impl` which applies
transactions to the document. These transactions also need to be
applied to the view as in 0aedef0.
2022-10-13 00:57:40 +09:00
Armin Ronacher
7f75458e6f Fix some commands not showing names in palette (#4223) 2022-10-12 09:02:10 -05:00
Lennard Hofmann
a24fae3b3c Update tree-sitter-lua and add textobjects for Lua (#3552) 2022-10-12 08:45:56 -05:00
Graic
68909dcef4 Fix append cursor location when selection anchor is at end of document (#4147) 2022-10-12 08:34:35 -05:00
Pascal Kuthe
963a0ac0bb fix terminfo detection 2022-10-12 11:33:48 +02:00
Jacob Kiesel
c54a0363bb Rearrange README.md slightly (#4206) 2022-10-11 18:54:18 -05:00
Brian Orwe
f4d96b2ca3 Fix confusion with using --hsplit --vsplit on startup at same time (#4202) 2022-10-11 09:25:42 -04:00
Pascal Kuthe
328c4d002f adress review comments 2022-10-11 12:11:33 +02:00
Daniel Ebert
081327695f Rename extend indent captures.
Clarify comments in indent code.
2022-10-11 16:48:04 +09:00
Daniel Ebert
dc443487d4 Slightly change the behavior of the @stop-extend capture.
This improves the behavior in case of multiple nested extensions.
2022-10-11 16:48:04 +09:00
Daniel Ebert
2b02785f19 Improve code style for tree-sitter indentation.
Split extend logic into a separate file.
2022-10-11 16:48:04 +09:00
Triton171
05832f90cb Fix a bug that caused the indent for the line below to also be added in rare cases at the beginning of a file. 2022-10-11 16:48:04 +09:00
Triton171
1ceecbd062 Fix clippy warning. 2022-10-11 16:48:04 +09:00
Triton171
8f19956218 Add python indentation support to docs.
Document @extend-indented and @stop-extend captures for indent queries.
2022-10-11 16:48:04 +09:00
Triton171
3ab9abb642 Add extend-indented and stop-extend captures for indent queries.
Improve and re-enable python indent queries.
2022-10-11 16:48:04 +09:00
Alex
8c4ae4df1c update everforest theme (#3998) 2022-10-11 16:43:52 +09:00
Stuart Baker
ce2a5b6d9f Add colours "color-modes" to ayu_light theme (#4109)
* Rename "dark gray" to "light gray"

* Add colours for statusline modes

* Use UI background for inactive panes
2022-10-11 15:48:55 +09:00
Pascal Kuthe
543d75da23 do not reparse unmodified injections (#4146) 2022-10-11 15:48:12 +09:00
Alexis (Poliorcetics) Bourget
b58899bc8e fix: remove unneeded allocations when calling helix_view::Info::new 2022-10-11 15:47:11 +09:00
Alexis (Poliorcetics) Bourget
28cb89eadb chore: fix clippy linting 2022-10-11 15:47:11 +09:00
Michael Davis
65febe0cf4 Overlay all diagnostics with highest severity on top (#4113)
Here we separate the diagnostics by severity and then overlay the Vec
of spans for each severity on top of the highlights. The error
diagnostics end up overlaid on the warning diagnostics, which are
overlaid on the hints, overlaid on info, overlaid on any other severity
(default), then overlaid on the syntax highlights.

This fixes two things:

* Error diagnostics are now always visible when overlapped with other
  diagnostics.
* Ghost text is eliminated.
    * Ghost text was caused by duplicate diagnostics at the EOF:
      overlaps within the merged `Vec<(usize, Range<usize>)>` violate
      assumptions in `helix_core::syntax::Merge`.
    * When we push a new range, we check it against the last range and
      merge the two if they overlap. This is safe because they both
      have the same severity and therefore highlight.

The actual merge is skipped for any of these when they are empty, so
this is very fast in practice. For some data, I threw together an FPS
counter which renders as fast as possible and logs the renders per
second.

With no diagnostics, I see an FPS gain from this change from 868 FPS
to 878 (+1.1%) on a release build on a Rust file. On an Erlang file
with 12 error diagnostics and 6 warnings in view (233 errors and 66
warnings total), I see a decrease in average FPS from 795 to 790
(-0.6%) on a release build.
2022-10-11 15:46:47 +09:00
Pascal Kuthe
1a87cbd508 remove filterting with C-space from picker 2022-10-11 12:25:28 +09:00
Pascal Kuthe
7af599e0af Treat space as a seperator instead of a character in fuzzy picker 2022-10-11 12:25:28 +09:00
Michael Davis
c388e16e09 Add a helper function for applying transactions
It is easy to forget to call `Document::apply` and/or `View::apply` in
the correct order. This commit introduces a helper function which
closes over both calls.
2022-10-11 12:17:32 +09:00
Michael Davis
0aedef0333 Apply transactions to Views
This change adds View::apply calls for all Document::apply call-sites,
ensuring that changes to a document do not leave invalid entries in
the View's jumplist.
2022-10-11 12:17:32 +09:00
Michael Davis
d418f0795d Add View::apply for adjusting jumplist ranges
Applying a transaction to a View adjusts the ranges in the jumplist
to ensure that they remain within the text of the document and follow
regular selection invariants (for example, must be have a width of at
least one).
2022-10-11 12:17:32 +09:00
Blaž Hrastnik
a85e386298 picker: Highlight the document on idle timeout 2022-10-11 09:53:55 +09:00
Gokul Soumya
001858b11f Propagate idle timeout event to components (#3172) 2022-10-11 09:10:01 +09:00
dependabot[bot]
5e1c589d43 build(deps): bump serde_json from 1.0.85 to 1.0.86 (#4187)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-10 18:44:40 -05:00
gbprod
9f36468b15 Change twig tree-sitter grammar (#4176) 2022-10-10 16:27:14 -05:00
Sumit Sahrawat
a079f2c9bd Add some vertical characters to the editor.indent-guides documentation (#4163)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-10-10 16:23:14 -05:00
David
7af7dadd17 Add instructions for gnome desktop support using the .desktop file (#4165) 2022-10-10 12:23:36 -05:00
Brandon Dong
530f9e3c53 Fix goto/view center mismatch (#4135) 2022-10-10 12:12:48 -05:00
Chickenkeeper
8e8ba06f60 Improve C# syntax highlighting (#4118) 2022-10-10 12:07:14 -05:00
S1m
d27551d814 Use different cursor color for primary cursor for ayu_mirage (#4140) 2022-10-10 10:26:10 -05:00
Mike Sampson
9b7f349f5c tutor: 5.5 add missing words (#4160) 2022-10-09 14:15:28 -05:00
A-Walrus
c15f1ea274 Add cursorcolumn (#4084)
* Implement cursorcolumn

* Add documentation

* Separate column style from line with fallback

* Fallback to cursorcolumn first

* Switch to non-fallback try_get_exact

Add new function `try_get_exact`, which doesn't perform fallback,
and use that instead because the fallback behaviour is being handled
manually.
2022-10-09 03:28:42 +09:00
Pascal Kuthe
2f7088c1f3 fix typo
Co-authored-by: Omnikar <omkar.subramaniam@icloud.com>
2022-10-08 17:43:32 +02:00
pascalkuthe
ad0eb4094b add deprectation not for underlined modifier to docs 2022-10-08 16:39:02 +02:00
Brandon Dong
18cfe864f4 Fix incorrect scrolloff default in documentation (#4136) 2022-10-08 03:22:35 +09:00
Pascal Kuthe
4c36c067b0 avoid visual artificats on terminal emulators that do not support underline colors 2022-10-07 00:18:49 +02:00
Pascal Kuthe
7bc324fde9 make casing consistent with other configuration 2022-10-06 20:50:54 +02:00
Pascal Kuthe
114610f7dc switch to termini for terminfo 2022-10-06 20:46:24 +02:00
Oleksii Dorozhkin
4d4be0e880 Update sonokai.toml (#4089) 2022-10-07 00:53:05 +09:00
allanderek
9ca4ac6901 Pallettise the bogster theme and, more importantly, add support for color-modes to the bogster theme. (#4121) 2022-10-07 00:52:10 +09:00
Jonathan
4595683622 Fix tutor typo (#4116) 2022-10-06 05:04:01 +09:00
A-Walrus
c927d61791 Fix bugs in search wraparound message (#4101) 2022-10-04 16:49:43 -05:00
Jaden
ccb38e7696 doc: add theme inheritance example (#4096) 2022-10-04 16:33:45 -05:00
Poliorcetics
ed5febf4b3 doc: add example to disable arrow keys in insert mode (#4088) 2022-10-04 09:40:51 -05:00
dependabot[bot]
581fe5c675 build(deps): bump thiserror from 1.0.36 to 1.0.37 (#4095)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-03 18:38:56 -05:00
dependabot[bot]
6b0fffb647 build(deps): bump tokio from 1.21.1 to 1.21.2 (#4094)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-03 18:38:43 -05:00
dependabot[bot]
7c33b9c76d build(deps): bump smallvec from 1.9.0 to 1.10.0 (#4093)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-03 18:38:24 -05:00
Skyler Hawthorne
27b70696df Exit gracefully when close operation fails (#4081)
If the close method fails, the editor will quit before restoring the
terminal. This causes the shell to break if, e.g. the LS times out
shutting down.

This fixes this by always restoring the terminal after closing, and
printing out a message to stderr if there is an error.
2022-10-04 00:35:42 +09:00
Michael Davis
6cca7375ec Automatically track pseudo-pending text (#4077)
This change automatically tracks pending text for for commands which use
on-next-key callbacks. For example, `t` will await the next key event
and "t" will be shown in the bottom right-hand corner to show that we're
in a pending state.

Previously, the text for these on-next-key commands needed to be
hard-coded into the command definition which had some drawbacks:

* It was easy to forget to write and clear the pending text.
* If a command was remapped in a custom config, the pending text would
  still show the old key.

With this change, pending text is automatically tracked based on the
key events that lead to the command being executed. This works even
when the command is remapped in config and when the on-next-key
callback is nested under some key sequence (for example `mi`).
2022-10-04 00:14:57 +09:00
Karsten Gebbert
9124c231f4 respond to SIGUSR1 by reloading config (#3952)
* respond to SIGUSR1 by reloading config

* document USR1 signal handling
2022-10-04 00:08:32 +09:00
Ivan Tham
3d59d3f8be Keep arrow and special keys in insert (#3915)
* Keep arrow and special keys in insert

Advanced users won't need it and is useful for beginners.
Revert part of #3671.

* Change text for insert mode section

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>

* Remove ctrl-up/down in insert

* Reorganize insert keys and docs

* Improve page up experience on last tutor

The last tutor page can page down multiple times and it will break the
heading on the 80x24 screen paging when reaching the last page, this
keeps the style the same and make sure page up and down won't break it.

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-10-04 00:08:15 +09:00
A-Walrus
1d8bb2249b Change focus to modified docs on quit (#3872)
* Change focus to modified docs on quit

When quitting with modified documents, automatically switch focus to
one of them.

* Update helix-term/src/commands/typed.rs

Co-authored-by: Poliorcetics <poliorcetics@users.noreply.github.com>

* Make it work with buffer-close-all and the like

* Cleanup

Use Cow instead of String, and rename DoesntExist -> DoesNotExist

Co-authored-by: Poliorcetics <poliorcetics@users.noreply.github.com>
2022-10-04 00:07:21 +09:00
Robin
6764744ce9 Add option to skip the first indent guide (#3819)
* Add option to skip the first indent guide

* reorder skip_first option

* change indent-guides.skip_first to a number

* rename skip -> skip_levels

* add skip_levels to the book

* Update book/src/configuration.md

Co-authored-by: A-Walrus <58790821+A-Walrus@users.noreply.github.com>

* Update helix-term/src/ui/editor.rs

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>

Co-authored-by: Robin <robinvandijk@klippa.com>
Co-authored-by: A-Walrus <58790821+A-Walrus@users.noreply.github.com>
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-10-04 00:07:04 +09:00
Michael Davis
dbec057363 Rename I/A "Insert at start/end of line" (#3753)
* keymap: Rename A "Insert at end of line"

The language for the `A` binding is potentially confusing because
`A` behaves like `i` done at the end of the line rather than `a`.
This change renames the command to match Kakoune's language[^1].

[^1]: 021da117cf/src/normal.cc (L2229)

* keymap: Rename I `insert_at_line_start`
2022-10-04 00:05:08 +09:00
Kirawi
772af7ffb1 remove split-debuginfo setting (#3691)
According to [the rustc book](https://doc.rust-lang.org/rustc/codegen-options/index.html#split-debuginfo), this is not supported on Windows. It also prevents Helix from compiling on the latest nightly.
2022-10-04 00:04:19 +09:00
ath3
7c9809eeb2 Find workspace from document path (#3553) 2022-10-04 00:02:49 +09:00
Ivan Tham
66bbba9024 Select inserted space after join (#3549)
* Select inserted space after join

* Split join_selections with space selection to A-J

Kakoune does that too and some users may still want to retain their selections.

* Update join_selections docs
2022-10-04 00:02:14 +09:00
Michael Davis
4a3b776b78 rust: Highlight function signatures as functions (#4073)
This stanza highlights functions within trait definitions. For example,
in:

    pub trait Widget {
        fn render(self, area: Rect, buf: &mut Buffer);
    }

`render` is currently highlighted as a variable. With this change it's
highlighted as a function.
2022-10-03 23:56:50 +09:00
nuid32
576c34f84e Add command names to command palette (#4071) 2022-10-03 23:56:43 +09:00
Ivan Tham
93f26a3048 Fix signature help panic when too large (#4030)
When signature help is too large it may cause a panic when it is too
large, now I just make the hover do an intersection with surface to make
sure it never overflow.
2022-10-03 23:56:24 +09:00
greg-enbala
63ff9309ce goto_window_* extends selection (#3985)
* goto_window_* extends selection

* Don't push to the jumplist
2022-10-03 23:55:26 +09:00
Alexis Kalabura
b9ff5d0e0a [lsp-restart]: call the force_shutdown method for the old_client (#3972)
* [lsp-restart]: call the shutdown_and_exit method for the old_client

* change shutdown_and_exit to force_shutdown

* remove extra log
2022-10-03 23:54:46 +09:00
Joshua Pauline
c144cc0b04 feat(statusline): add option to show total line numbers in file (#3960)
* feat(statusline): add option to show total line numbers in file

* feat(line numbers): add config to doc book
2022-10-03 23:54:00 +09:00
Slug
519857d632 Add dark high contrast theme refer to vscode (#3312)
* Add dark high contrast theme

* Add my sign

* Fix typo

* Change gray to white for comment and remove Italic
2022-10-03 23:45:56 +09:00
PeepNSheep
77f33e7b20 Add configureable statusline mode names (#3311)
* Added 'long-mode' statusline element

* Added customizable statusline mode names

* Removed a string clone

* Added documentation

* Updated documentation, moved modenames to a seperate section

* Update configuration.md

* Documentation update

* Documentation update

* Documentation update

* Update configuration.md

* Update configuration.md

* Fixed merge error

* Update configuration.md

* Update configuration.md
2022-10-03 23:45:32 +09:00
ChrHorn
589d17c758 Add ui.gutter.selected option for themes (#3303)
* add `ui.gutter.selected`

* add `ui.gutter`, `ui.gutter.selected` to docs
2022-10-03 23:44:45 +09:00
Michael Davis
6939dd3adb Add tests for select-mode TS textobjects 2022-10-03 10:44:08 -04:00
Michael Davis
c253139790 Extend textobject selections in select mode 2022-10-03 10:44:08 -04:00
Michael Davis
032d76ccf2 Use Range::with_direction consistently 2022-10-03 10:44:08 -04:00
Michael Davis
274f2ea459 Use requested direction for new textobject selection range
This changes the behavior of operations like `]f`/`[f` to set the
direction of the new range to the direction of the action.

The original behavior was to always use the head of the next function.
This is inconsistent with the behavior of goto_next_paragraph and makes
it impossible to create extend variants of the textobject motions.

This causes a behavior change when there are nested functions. The
behavior in the parent commit is that repeated uses of `]f` will
select every function in the file even if nested. With this commit,
functions are skipped.

It's notable that it's possible to emulate the original behavior by
using the `ensure_selections_forward` (A-:) command between invocations
of `]f`.
2022-10-03 10:44:08 -04:00
A-Walrus
f3958aa1fd Cycled to end/beginning + no more matches msgs (#3176)
* Show status msg when next/prev cycles around

* Add msg when there is no wraparound

* Cleanup code

* Change msg to "Wrapped around document"
2022-10-03 23:43:26 +09:00
Christoph Schmidler
2fac9e24e5 Inherit theme (#3067)
* Add RawTheme to handle inheritance with theme palette

* Add a intermediate step in theme loading

it uses RawTheme struct to load the original ThemePalette, so we can merge it with the inherited one.

* Load default themes via RawThemes, remove Theme deserialization

* Allow naming custom theme same as inherited one

* Remove RawTheme and use toml::Value directly

* Resolve all review changes resulting in a cleaner code

* Simplify return for Loader::load

* Add  implementation to avoid extra step for loading of base themes
2022-10-03 23:34:29 +09:00
A-Walrus
57dc5fbe3a Show "Invalid regex" message on enter (Validate) (#3049)
* Show "Invalid regex" message on enter (Validate)

* Reset selection on invalid regex

* Add popup for invalid regex

* Replace set_position with position

* Make popup auto close
2022-10-03 23:33:48 +09:00
Joe
bcba5d67f9 Add goto preview (#2982) 2022-10-03 23:33:20 +09:00
David
18f6ec7a8e Update treesitter markdown (#4078)
* Update treesitter markdown

* Update inline and add table injections
2022-10-03 23:14:16 +09:00
Matt Freitas-Stavola
9d1793c45b Add pseudo_pending for t/T/f/F (#4062) 2022-10-02 14:32:30 -05:00
Kirawi
8c2cc43017 diff full-doc LSP edits (#4041)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-10-02 14:23:23 -05:00
nuid32
6caa7a7f56 Onedarker theme: some improvements (#4069) 2022-10-02 11:19:55 -05:00
Pascal Kuthe
71ee589bbc make underline_style a seperate option
Underline styles are mutally exclusive and overwrite each other.
Therefore implementing as an modifier lead to incorrect behaviour
when the underline style is overwritten.

For backwards compatability the "underline" modified is retained (but
deprecated). Instead the "underline_style" and "underline_color"
optios should be used to style underlines.
2022-10-01 19:29:46 +02:00
nuid32
5b5f1bd39a Adjust light-gray in onedarker theme (#4060) 2022-10-01 10:37:18 -05:00
Gokul Soumya
79d3d44c3d Detect extended underline support using terminfo
The cxterminfo crate has been used over popular alternatives
like `term` since it supports querying for extended capabilities
and also for it's small codebase size (which will make it easy
to inline it into helix in the future if required).
2022-10-01 17:00:40 +02:00
A-Walrus
de72b9c04c Update theme documentation 2022-10-01 17:00:36 +02:00
A-Walrus
79a39c1063 Fix failing tests
Add underline field to doctests, and fix bugs
2022-10-01 17:00:35 +02:00
A-Walrus
3ad7d543ca Add separate color for underlines 2022-10-01 17:00:34 +02:00
Gokul Soumya
999b45b28c Support different kinds of underline rendering
Adds four new  modifiers that can be used in themes:

- undercurled
- underdashed
- underdotted
- double-underline
2022-10-01 17:00:32 +02:00
zensayyy
c9584251f3 Ensure cursor in view after format (#4047)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-10-01 09:32:09 -05:00
Roberto Vidal
cc257e9bf9 Add support for webassembly text format (#4040) 2022-10-01 09:13:52 -05:00
nuid32
2113b1bb2f themes: Add onedarker (#3980) 2022-10-01 09:11:15 -05:00
Chickenkeeper
60aa7d3607 WGSL syntax highlighting fix (#3996) 2022-09-30 17:43:07 -05:00
Maximilian Muecke
8a7a6e4cff Add comment injection for R (#4031) 2022-09-29 13:11:45 -05:00
joleaf
c4aec0a5c5 tutor: missing <ESC> before removing the second cursor (#4027)
This step was missing in section 5.2 of tutor.
2022-09-29 11:02:55 -04:00
Sora
038ad6289f Fix tutor typo favourite to favorite (#4007) 2022-09-28 18:50:24 -05:00
Sven-Hendrik Haase
5dbca0fc08 Add gruvbox dark (#3948)
* Add gruvbox dark

* fixup! Add gruvbox dark
2022-09-28 22:50:53 +08:00
Erin Kim
bdc7b35214 nix: replace runCommandNoCC with runCommand (#3992) 2022-09-27 08:01:58 -05:00
dependabot[bot]
8fc493137d build(deps): bump serde from 1.0.144 to 1.0.145 (#3989)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-26 18:43:30 -05:00
dependabot[bot]
cc0018a7d3 build(deps): bump thiserror from 1.0.35 to 1.0.36 (#3991)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-26 18:43:14 -05:00
dependabot[bot]
e3fbeeb789 build(deps): bump unicode-general-category from 0.5.1 to 0.6.0 (#3990)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-26 18:36:40 -05:00
Jacob Chandler
90468ad6c5 fix: Improve JSX and TSX tag highlighting (#3973) 2022-09-26 18:27:54 -05:00
dependabot[bot]
d2bb7f5a09 build(deps): bump tokio-stream from 0.1.9 to 0.1.10 (#3988)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-26 18:22:48 -05:00
dependabot[bot]
fd4cdf0b1f build(deps): bump once_cell from 1.14.0 to 1.15.0 (#3987)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-26 18:19:50 -05:00
Oskar Köök
98dd9c4f2b Remove do_block from Ruby indents (#3976)
`do_block` and `block` seem to conflict, causing double-indentation in some cases. Removing `do_block` does not seem to have any negative effect, while fixing the double-indentation issue.
2022-09-26 13:04:32 -04:00
Oskar Köök
c196a90684 Add documentation for max-line-length (#3974) 2022-09-26 07:56:07 -05:00
Poliorcetics
e8f0886b21 chore: remove unneeded attribute after MSRV bump to 1.61 (#3961) 2022-09-25 08:12:33 -05:00
Clay
1a4a9b86d7 heex: upgrade grammar, add roots matching elixir (#3959) 2022-09-25 15:51:25 +09:00
Invader Zim
42e30e7afa Add bufferline colors to 15 themes (#3881)
Themes:

* acme
* ayu_dark
* ayu_light
* ayu_mirage
* base16_default_dark
* base16_default_light
* bogster
* catppuccin_frappe
* catppuccin_latte
* catppuccin_macchiato
* catppuccin_mocha
* darcula
* dark_plus
* doom_acario_dark
* emacs
2022-09-23 14:32:37 -05:00
adrian5
0d8d8a4ed6 docs: Punctuation on tutor (#3888) 2022-09-23 12:01:41 -05:00
Riccardo Binetti
3a245fe792 Add mix.exs and mix.lock as Elixir root markers (#3917) 2022-09-23 11:40:16 -05:00
Riccardo Binetti
888f4fef6f Split helix_core::find_root and helix_loader::find_local_config_dirs (#3929)
* Split helix_core::find_root and helix_loader::find_local_config_dirs

The documentation of find_root described the following priority for
detecting a project root:
- 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

The commit contained in https://github.com/helix-editor/helix/pull/1249
extracted and changed the implementation of find_root in find_root_impl,
actually reversing its result order (since that is the order that made
sense for the local configuration merge, from innermost to outermost
ancestors).

Since the two uses of find_root_impl have different requirements (and
it's not a matter of reversing the order of results since, e.g., the top
repository dir should be used by find_root only if there's not marker in
other dirs), this PR splits the two implementations in two different
specialized functions.

In doing so, find_root_impl is removed and the implementation is moved
back in find_root, moving it closer to the documented behaviour thus
making it easier to verify it's actually correct

* helix-core: remove Option from find_root return type

It always returns some result, so Option is not needed
2022-09-23 17:04:07 +09:00
Pascal Kuthe
4133f1f424 Document MSRV policy (#3913) 2022-09-23 15:58:00 +09:00
A-Walrus
eb6fd283dc Deduplicate regexes in search_selection command (#3941) 2022-09-22 23:33:30 +08:00
Henrik Tjäder
e621848d07 Theme: Papercolor: Tune inactive statusline (#3938) 2022-09-22 07:28:05 -05:00
Michael Davis
6e168b5099 Improve keymap errors from command typos (#3931)
* Improve keymap errors from command typos

Currently, opening helix with a config containing a bad command mapping
fails with a cryptic error. For example, say we have a config (bad.toml)
with a command name that doesn't exist:

    [keys.normal]
    b = "buffer_close" # should be ":buffer-close"

When we `hx -c bad.toml`, we get...

> Bad config: data did not match any variant of untagged enum KeyTrie for key `keys.normal` at line 1 column 1
> Press <ENTER> to continue with default config

This is because of the way that Serde tries to deserialize untagged
enums such as `helix_term::keymap::KeyTrie`. From the Serde docs[^1]:

> Serde will try to match the data against each variant in order and the
> first one that deserializes successfully is the one returned.

`MappableCommand::deserialize` fails (returns an Err variant) when a
command does not exist. Serde interprets this as the `KeyTrie::Leaf`
variant failing to match and declares that the input data doesn't
"match any variant of untagged enum KeyTrie."

Luckily the variants of KeyTrie are orthogonal in structure: we can tell
them apart by the type hints from a `serde:🇩🇪:Visitor`. This change
uses a custom Deserialize implementation along with a Visitor that
discerns which variant of the KeyTrie applies. With this change, the
above failure becomes:

> Bad config: No command named 'buffer_close' for key `keys.normal.b` at line 2 column 5
> Press <ENTER> to continue with default config

We also provide more explicit information about the expectations on
the field. A config with an unexpected type produces a message with
that information and the expectation:

    [keys.normal]
    b = 1

> Bad config: invalid type: integer `1`, expected a command, list of commands, or sub-keymap for key `keys.normal.b` at line 2 column 5
> Press <ENTER> to continue with default config

[^1]: https://serde.rs/enum-representations.html#untagged

* Update helix-term/src/keymap.rs

Co-authored-by: Ivan Tham <pickfire@riseup.net>

Co-authored-by: Ivan Tham <pickfire@riseup.net>
2022-09-22 09:30:42 +08:00
gavincrawford
1dd1476a9e Fix highlighting on single-character Rust consts (#3927)
Co-authored-by: Kirawi <67773714+kirawi@users.noreply.github.com>
Co-authored-by: Gavin Crawford <gavincrawford@users.noreply.github.com>
2022-09-21 17:55:28 -05:00
taupiqueur
75362dce83 Fix the picker’s keymap documentation (#3925) 2022-09-21 13:51:48 -05:00
Benedikt Müller
5467c65f82 fix fish completions for --config & --log (#3912) 2022-09-20 07:35:00 -05:00
Filipe Azevedo
385ccdfc9c add :lsp-restart command (#3435) 2022-09-20 16:44:36 +09:00
Joe
aa00a470f3 Fix preview bug (#3644)
* Fix preview bug

* Add comment to empty case
2022-09-20 16:40:48 +09:00
Blaž Hrastnik
1df32c917c diagnostics: Use Vec<Tag> instead of Option<Vec<Tag>> 2022-09-20 16:28:00 +09:00
Luke Cycon
64b0745413 Track source and tags in diagnostics (#3898) 2022-09-20 16:21:15 +09:00
Tobias Hunger
130793dfd0 Add command line parameter to specify log file (#3807)
* Add command line parameter to specify log file

I had the logs of my debug helix mixed in with the logs from the
production helix.

Add a `--log` command line argument to redirect any logs to other
files, making my debugging easier :-)

* Update completion files with `--log` argument
2022-09-20 16:11:30 +09:00
Michael Davis
8988c1ecc7 Re-sort diagnostics after transaction transform (#3895)
Applying document-change transactions to diagnostic ranges is not stable
with respect to the ordering of diagnostics. This can cause diagnostics
to become temporarily unordered with some edits to a document, which can
eventually break some invariants/assumptions in syntax::merge.

With this change, Document::diagnostics are always sorted.
2022-09-20 16:08:58 +09:00
dependabot[bot]
947ff63e6d build(deps): bump textwrap from 0.15.0 to 0.15.1 (#3906)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-19 18:29:00 -05:00
dependabot[bot]
26c3c99330 build(deps): bump unicode-segmentation from 1.9.0 to 1.10.0 (#3903)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-19 18:28:38 -05:00
dependabot[bot]
674bfec984 build(deps): bump unicode-width from 0.1.9 to 0.1.10 (#3902)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-19 18:28:12 -05:00
dependabot[bot]
2450166927 build(deps): bump tokio from 1.21.0 to 1.21.1 (#3904)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-19 18:27:04 -05:00
dependabot[bot]
3acdf9fdf9 build(deps): bump thiserror from 1.0.34 to 1.0.35 (#3905)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-19 18:26:18 -05:00
dependabot[bot]
e85d6c37d4 build(deps): bump anyhow from 1.0.64 to 1.0.65 (#3907)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-19 18:25:22 -05:00
Alexander Brevig
08b2ecc99a feat: xtask themelint (#3234)
* feat: cargo xtask themelint <theme>

* fix: add docs and print json error status

* fix: refactor paths -> path

* fix: remove unused function

* fix: only report one err per scope (ui.statusline is reported if none of ui.statusline.* is recognized)

* fix: save work for later

* fix: finally decided on a design

* fix: ready for discussion

* fix: better rules

* fix: lint precision

* fix: String -> &'static str

* fix: allowlist not denylist for file type

* fix: add missing and indication of what's needed

* fix: copy pasteable errors

* fix: use Loader:read_names

* Update xtask/src/helpers.rs

Co-authored-by: Ivan Tham <pickfire@riseup.net>

* fix: remove into and clone for str

* Update book/src/themes.md

Co-authored-by: Ivan Tham <pickfire@riseup.net>

* fix: better lint output

* fix: cleaner logic for lint reporting

* style: use explicit imports

* Pascal support (#3542)

* fix: add difference check for statusline normal,insert,select

* fix: fg for whitespace and early exit if and one is ok

* chore: cleaning up, no idea how these got here or how this will look

* chore: revert from older commit?

* refactor: use static fn to equalize api between difference and existance

* refactor: querycheck and clippy

* refactor: clippy fixes

* fix: query-check behaves as before

* fix: error with x of y message, not total count

* fix: consistent reporting and less mutable state

* fix: selection difference ref #3942 ref #1833

Co-authored-by: Ivan Tham <pickfire@riseup.net>
Co-authored-by: ath3 <45574139+ath3@users.noreply.github.com>
2022-09-19 21:38:20 +08:00
Pascal Kuthe
5ea7855977 raise msrv to 1.59 (#3896) 2022-09-19 12:03:51 +09:00
Alex Suraci
ea25ed6431 add bass language + highlighting (#3771) 2022-09-18 12:06:51 -05:00
Artem Pyanykh
08937fc00e Add Markdown LSP via Marksman
Marksman is an LSP server for Markdown: https://github.com/artempyanykh/marksman
It supports a bunch of LSP features: symbols, references, rename, diag,
etc. and already has integrations with emacs, neovim, and vscode.
2022-09-17 20:58:42 +02:00
taupiqueur
a73e83ef4d Fix typos (#3858) 2022-09-17 06:34:48 -05:00
Nick Ogden
19384cc3a1 Add darcula theme based upon Intelij Darcula (#3739) 2022-09-16 11:21:56 -05:00
Benjamin Streit
714db9c666 fix: Improving JSX and TSX indents (#3853) 2022-09-16 16:51:19 +09:00
Kristoffer Flottorp
111d2dafd3 Improve flatwhite theme (#3843)
Co-authored-by: krfl <kr.fl@outlook.com>
2022-09-16 11:39:06 +09:00
Kristoffer Flottorp
73f8e9902b improve fleetish theme (#3844)
Co-authored-by: krfl <kr.fl@outlook.com>
2022-09-16 11:38:54 +09:00
Ben Noordhuis
b5be72bff7 Canonicalize executable path
When looking up the runtime/ directory relative to the executable path,
canonicalize the path first in case the executable is a symbolic link.

Fixes #3768
2022-09-13 17:50:02 -04:00
Michael Davis
ec81ec1e8d flake: Fix devShell on aarch64-darwin (#3810)
LLDB is marked broken on all arches except for x86_64-linux. With this
change, I can use `nix develop` on aarch64-darwin.
2022-09-13 22:50:53 +09:00
A-Walrus
d38950bdf9 Remove border from code actions popup (#3444) 2022-09-13 05:24:48 -04:00
A-Walrus
ac460ac837 Render html <code> tags as code in markdown (#3425) 2022-09-13 05:14:16 -04:00
Benjamin Streit
ffb41a94f0 feat: Syntax highlighting for Astro files (#3829) 2022-09-13 01:53:55 -05:00
Skyler Hawthorne
0d8ffa6b4a add example config for all removed insert mode bindings (#3827) 2022-09-13 01:49:18 -05:00
Alexander Brevig
16b9a1841f fix: map_err()? instead of unwrap (#3826) 2022-09-13 15:08:23 +09:00
dependabot[bot]
800a490676 build(deps): bump url from 2.2.2 to 2.3.1 (#3828)
Bumps [url](https://github.com/servo/rust-url) from 2.2.2 to 2.3.1.
- [Release notes](https://github.com/servo/rust-url/releases)
- [Commits](https://github.com/servo/rust-url/compare/v2.2.2...v2.3.1)

---
updated-dependencies:
- dependency-name: url
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-13 10:01:38 +09:00
Alex Mayer
23027a454a Clean Up Nord Theme (#3792)
- Add markup styles
- Replace custom colors with Nord colors
- Clean up code spacing
2022-09-12 23:32:24 +09:00
Michael Davis
936ad884eb Remove arrow key recommendation from tutor (#3811) 2022-09-12 23:15:54 +09:00
Fanda Vacek
865a1a4cb3 Make whitespace in monokai-pro-spectrum theme one step dimmer to avoid (#3814)
the white space confusion with hyphen

Co-authored-by: Fanda Vacek <fvacek@elektroline.cz>
2022-09-12 23:15:41 +09:00
Pablo Ovelleiro Corral
03612174ee Update usage.md with paragraph textobject(#3797) 2022-09-11 16:41:35 +05:30
yvt
b191ecf828 Strip release binary by setting profile.release.strip in a pre-build step (#3780)
* chore(ci): remove the strip step from the release CI workflow

* chore(ci): set `profile.release.strip = true` in the release CI workflow
2022-09-11 11:15:07 +09:00
Blaž Hrastnik
c2e41082e4 Remove the .txt suffix from tutor
The tutor file is loaded as .txt which can potentially spawn a
language server. Then the path is unset, but the LS remains active.
This can cause panics since updates are now submitted for a doc
with no path.

As a quick workaround we remove the extension which should avoid
detection.

Fixes #3730
2022-09-11 11:11:07 +09:00
Erasin
a15420ed1c Add textobject for gdscript (#3760) 2022-09-10 08:47:08 -05:00
Erasin
54e78dd24f Add godot resource support (#3759)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-09-10 08:45:52 -05:00
yvt
5489c9ad4e chore: rename .cargo/{config -> config.toml} 2022-09-10 08:44:31 -05:00
yvt
02d6102540 chore(ci): upgrade actions/upload-artifact to v3
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-09-10 08:36:48 -05:00
yvt
0090a2d86f chore(ci): support "preview" release CI runs
Expands the trigger sources of the release CI workflow (`release.yml`),
allowing the developers to test changes to `.github/workflows/release.yml`
easily. The new trigger sources start the workflow in a "preview" mode, in
which it publishes build outputs as a CI artifact instead of creating a new
release so that they can be manually inspected.

The following events trigger the preview mode:

- Pushing to any branch matching the glob pattern `patch/ci-release-*`.
- Opening a pull request that modifies `.github/workflows/release.yml`.
- Pushing versioning tags to a forked repository.
2022-09-10 08:36:48 -05:00
yvt
29fe0c3862 Enable CI builds for riscv64-linux (#3685) 2022-09-10 08:35:35 -05:00
A-Walrus
9c627c65e5 Improve error handling for config-reload (#3668)
* Don't change config to default when refreshing invalid config

* Propely handle theme errors with config-reload

* Extract refresh theme into seperate function
2022-09-10 22:32:49 +09:00
A-Walrus
75e6a64327 Switch to Result for invalid language 2022-09-10 22:23:38 +09:00
A-Walrus
e8add6f46d Add error handling to set language command
If you type a nonexistant language an appropriate message will show,
and the language won't be changed.
2022-09-10 22:23:38 +09:00
A-Walrus
cc47d3fb9d Add text to language completer 2022-09-10 22:23:38 +09:00
Evan Richter
01ee42bb14 ordinals instead of indexes when listing grammar fetch errors (#3773) 2022-09-10 14:14:03 +09:00
Soc Virnyl S. Estela
fae9203c3e Add papercolor dark variant (#3742) 2022-09-08 19:02:06 -05:00
Matouš Dzivjak
321cce3f13 enable lint option
Enable lint option to highlight unused vars, etc.
and take full advantage of the running language server.
2022-09-08 18:38:41 -05:00
Matouš Dzivjak
76b3f502c4 feat(lsp): jsonnet-language-server
Add jsonnet-language-server for jsonnet language.
See: https://github.com/grafana/jsonnet-language-server
2022-09-08 18:38:41 -05:00
ChemicalXandco
7210b39587 change to openscad-lsp (#3750) 2022-09-08 18:36:03 -05:00
Akseli
8a1047c844 Add "markdown" as a possible filetype (#3749) 2022-09-08 18:29:36 -05:00
Skyler Hawthorne
e12690e2f5 Remove default insert mode movement bindings
Helix is first and foremost a modal editor. Willingness to support non-modal
editing is there, but it is not one that should be encouraged with the default
settings. There are an increasing number of users who are stumbling because
they are trying to use Helix as a non-modal editor, so this is an effort to
encourage new users to stop and take notice that Helix has a different paradigm
than VSCode, Sublime, etc. Users can still add these bindings back to their own
configs if they wish.
2022-09-08 17:36:04 -05:00
Matouš Dzivjak
5ab85283e9 feat(languages): jsonnet (#3714)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-09-08 09:04:18 -05:00
Benoît Cortier
16ce036bdf Add good default rulers when editing git messages (#3738)
Around 50 columns for the summary is good because it is often used as
heading or as subject in emails. 72 columns for the body is generally
good because some tools do not wrap long lines (`git log` with pager
`less` is a good example). Helix's `:reflow` command is really good to
help with the second point.

Linux kernel documentation says:

> For these reasons, the ``summary`` must be no more than 70-75
> characters, and it must describe both what the patch changes, as well
> as why the patch might be necessary.  It is challenging to be both
> succinct and descriptive, but that is what a well-written summary
> should do.

Source:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst#n627

tpope:
https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html

Commit message style guide for Git:
https://commit.style/
2022-09-07 16:29:41 -04:00
Giorbo
5b1113766d Add syntax highlighting for SML (#3692)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-09-07 13:13:06 -05:00
A-Walrus
e14b48af2e Fix :reflow panic by enusring cursor in view (#3733) 2022-09-07 12:50:54 -05:00
Blaž Hrastnik
a123fb6057 Remove LspNotDefined, instead return an Option<> 2022-09-07 16:42:33 +09:00
A-Walrus
fe37a66046 Handle formatter errors, and save anyway (#3684)
If formatting fails, report error to log and save without formatting.
2022-09-07 16:22:48 +09:00
Michael Davis
301f5d7cf7 Fix Rust attribute highlights (#3729) 2022-09-07 12:45:51 +09:00
Timothy DeHerrera
1fe32737fa nix: fix highlighting rules
* avoid coloring `identifier`s globally
* fix function application when not part of `select_expression`
* add `has_attribute_expression` highlighting
* fix precendence for interpolation, which should be after select
* highlight `@` as delimiter
2022-09-06 19:47:33 -05:00
yvt
b7380313a5 chore(ci): build AppImage for aarch64-linux 2022-09-06 18:42:02 -05:00
yvt
038a91d204 chore(ci): build binary for aarch64-linux 2022-09-06 18:42:02 -05:00
yvt
1fc97a9a20 chore(ci): install a pre-release version of Cross 2022-09-06 18:42:02 -05:00
Rohit K Viswanath
14f12c8a0b Theme: Rasmus (#3728) 2022-09-06 17:51:02 -05:00
Timothy DeHerrera
5ed751c67d remove ^$ from injection regexs 2022-09-06 17:39:41 -05:00
Timothy DeHerrera
665e27ff9d nix: add language injections
By simply placing a comment with the name of the desired language just
before a multi-line string, that language will be injected.

Also, common functions and attributes which are expected to be shell
code are automatically injected.
2022-09-06 17:39:41 -05:00
Michael Davis
43b31f702a Update tree-sitter-diff (#3708)
This change also renames the grammar from `git-diff` to `diff`.
The grammar covers regular diff syntax so I renamed the repository
a while ago.
2022-09-06 12:02:37 +09:00
dependabot[bot]
f7c216d497 build(deps): bump tokio from 1.20.1 to 1.21.0 (#3716)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.20.1 to 1.21.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.20.1...tokio-1.21.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-06 11:25:54 +09:00
dependabot[bot]
b85d0c597a build(deps): bump tree-sitter from 0.20.8 to 0.20.9 (#3719)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-05 18:51:33 -05:00
dependabot[bot]
8667a4d2be build(deps): bump anyhow from 1.0.63 to 1.0.64 (#3718)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-05 18:48:58 -05:00
dependabot[bot]
c34929b134 build(deps): bump thiserror from 1.0.33 to 1.0.34 (#3717)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-05 18:33:50 -05:00
dependabot[bot]
5e1296b888 build(deps): bump once_cell from 1.13.1 to 1.14.0 (#3715)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-05 18:33:01 -05:00
Kirawi
8882615483 Delete hooks.md (#3711) 2022-09-05 14:38:37 -05:00
Clay
da8071047a Elixir: update tree-sitter queries (#3645) 2022-09-05 08:49:41 -05:00
NotAgentBilly
df1ed0a5fd xcopy - assume destination is a directory (#3686) 2022-09-05 08:42:17 -05:00
Lennard Hofmann
fb92d71d08 Update tree-sitter-fish to latest commit (#3704) 2022-09-05 08:35:14 -05:00
Michael Kohl
16197664ab Add file_picker_in_current_directory to keymap.md (#3701) 2022-09-05 15:11:06 +09:00
Blaž Hrastnik
1acdfaa073 fix: View needs to retain the original scroll offset on split 2022-09-05 11:58:00 +09:00
Michael Davis
9c3c6a1c22 Fix off-by-one in extend_line_above (#3689)
`extend_line_above` (and `extend_line` when facing backwards) skip
a line when the current range does not fully cover a line.

Before this change:

    foo
    b#[|a]#r
    baz

With `extend_line_above` or `extend_line` selected the line above.

    #[|foo
    bar]#
    baz

Which is inconsistent with `extend_line_below`. This commit changes
the behavior to select the current line when it is not already
selected.

    foo
    #[|bar]#
    baz

Then further calls of `extend_line_above` extend the selection up
line-wise.
2022-09-05 11:34:49 +09:00
Blaž Hrastnik
20ed8c2595 tree-sitter-solidity: Use upstream, update queries 2022-09-05 10:50:32 +09:00
Blaž Hrastnik
44b447947c fix: lsp: Don't send didOpen events for documents with no URL
Fixes #3683
2022-09-04 17:28:17 +09:00
Blaž Hrastnik
cc4b71274a minor: Simplify another document_mut statement 2022-09-04 17:27:15 +09:00
Michael Davis
f0d1caafcf Look for the external formatter before invoking it (#3670)
Currently it is not possible to save a file with a language that
has an external formatter configuration unless the external
formatter is installed, even if the language has a Language Server
configuration capable of auto-format. This change checks that the
external formatter exists before using it to create a formatting
callback.
2022-09-04 09:59:20 +05:30
Fangrui Song
0d76775453 Fix typos in tutor (#3664) 2022-09-03 17:30:03 -05:00
A-Walrus
c93d52cc8a Fix cargo doc warnings, and add GitHub action to ensure it (#3650) 2022-09-03 09:58:16 -05:00
Yusuf Bera Ertan
59f7b07c86 build(nix): update flake deps (#3663) 2022-09-03 13:16:34 +09:00
Blaž Hrastnik
6ec4017a8d Expand doc/view macros to allow fetching specific id
This simplifies the code and hides away unwraps
2022-09-03 12:36:06 +09:00
Blaž Hrastnik
1caba2d3e8 lsp: Don't log "LSP not defined" errors in the logfile 2022-09-03 12:18:08 +09:00
Yusuf Bera Ertan
e917a8e0be build(nix): update nci, refactor flake, seperate wrapping, add source filtering (#3657) 2022-09-02 17:54:07 -05:00
bootra
3c38fe9c70 update boo_berry theme for statusline and indent-guide (#3653) 2022-09-02 17:34:22 -05:00
Charles Hall
b3b164f0d5 Highlight SQL in sqlx::{query,query_as}!() in Rust (#3647) 2022-09-02 17:26:42 -05:00
voroskoi
6e5e38c2ba update zig grammar and highlight rules (#3621) 2022-09-02 17:22:07 -05:00
aaron404
e8730ca5fd initial implementation of bufferline (#2759)
* initial implementation of bufferline

* fixed lint

* changed to 'bufferline', added enum for config modes, some cleanup

* fixed lint

* added file modification indicator

* removed redundant code, added proper themeing with fallback, changed 'file modified' indicator

* remove commented code

* Update helix-term/src/ui/editor.rs

simplify text and offset computation

Co-authored-by: Gokul Soumya <gokulps15@gmail.com>

* add ui.bufferline.background key for themes

Co-authored-by: lazytanuki <43273245+lazytanuki@users.noreply.github.com>

* address PR comments

* Update helix-term/src/ui/editor.rs

* simplify computation of editor area:

* change to set_stringn to avoid overflow

* Update configuration.md

Updates documentation to reflect decision re: defaulting to never showing bufferline.

* addressed pr comments

* fix build error

* address pr comments

* revert accidental change

Co-authored-by: Gokul Soumya <gokulps15@gmail.com>
Co-authored-by: lazytanuki <43273245+lazytanuki@users.noreply.github.com>
Co-authored-by: Seth Bromberger <sbromberger@users.noreply.github.com>
2022-09-02 11:39:38 +09:00
Bertrand Bousquet
04a4033b6c theme: Add Varua color scheme (#3610) 2022-09-01 19:57:37 -05:00
Michael Davis
66276ce630 Changelog notes for 22.08.1 (#3639) 2022-09-01 12:07:46 -05:00
A-Walrus
45dbcb6783 Fix closing buffer with custom keymap (#3633)
* Fix closing buffer with custom keymap

* Add comment explaining if
2022-09-02 01:59:39 +09:00
Fanda Vacek
ec28b2b5cc Change MonokaiProSpectrum theme error background from red to magenta. (#3627)
Co-authored-by: Fanda Vacek <fvacek@elektroline.cz>
2022-09-01 07:45:22 -05:00
Charles Hall
04e1cbe33f fix: typo in tutor about searching compared to vim (#3625) 2022-09-01 07:41:15 -05:00
Blaž Hrastnik
5c2b77b41f Make mode editor-wide rather than per-document 2022-09-01 16:14:38 +09:00
Blaž Hrastnik
10d9355b34 Update deps 2022-09-01 16:00:19 +09:00
Saber Haj Rabiee
1cbf552554 fix: prevents storing last prompt if is top of stack (#3609) 2022-09-01 10:29:15 +09:00
Michael Davis
ee94031fc4 Bump VERSION to 22.08 2022-08-31 11:43:51 -05:00
Michael Davis
22c5f2474d Add changelog entries for 22.08 2022-08-31 11:37:17 -05:00
Michael Davis
7c34f20dca Fix Prompt::handle_event compilation 2022-08-31 11:37:17 -05:00
Frojdholm
4c9f144dac fix: Recalculate completion when going through prompt history (#3193)
* fix: Recalculate completion when going through prompt history

* Update completion when the prompt line is changed

It should not be possible to update the line without also updating the
completion since the completion holds an index into the line.

* Fix Prompt::with_line recalculate completion

with_line was the last function where recalculate completion had to be
done manually. This function now also recalculates the completion so
that it's impossible to forget.

* Exit selection when recalculating completion

Keeping the selection index when the completion has been recalculated
doesn't make sense. This clears the selection automatically, removing
most needs to manually clear it.

* Remove &mut on save_filter

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-09-01 01:26:21 +09:00
Gokul Soumya
e3e71fa36b Show clipboard info in --health output (#2947)
* Show clipboard info in --health output

* health: Separate 'languages' category from 'all'

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-09-01 01:23:45 +09:00
Charlie Groves
5c3f43a7f0 Share the restore_term code between panic and normal exits (#3612)
It was starting to diverge as the normal exit code was restoring the prompt but the panic code
wasn't, and the panic code was disabling bracketed paste but the normal code wasn't.

This changes the panic path slightly in that we won't disable raw mode if exiting alternate screen
and disabling bracketed paste fails. If that happens, things are so busted I don't think it matters
anyway.
2022-09-01 01:23:21 +09:00
Michael Davis
93c6a337c4 Avoid command execution hooks on closed docs (#3613)
Fixes a panic with a config like:

    [keys.normal.space]
    x = [":buffer-close"]

by bailing out of the command-execution handling if the document
doesn't exist after handling a command.
2022-09-01 01:20:55 +09:00
Michael Davis
83f177d270 Refactor goto_ts_object_impl as a motion (#3264)
This refactor changes the overall structure of the goto_ts_object_impl
command without removing any functionality from its behavior. The
refactored motion:

* acts on all selections instead of reducing to one selection
* may be repeated with the `repeat_last_motion` (A-.) command
* informs the user when the syntax-tree is not accessible in the current buffer
2022-08-31 17:48:33 +09:00
Michael Davis
7547a961bb Discard LSP publishDiagnostic when LS is not initialized (#3403)
This is invalid according to the [LSP spec]:

> In addition the server is not allowed to send any requests
> or notifications to the client until it has responded with an
> InitializeResult, with the exception that during the initialize
> request the server is allowed to send the notifications
> window/showMessage, window/logMessage and telemetry/event as well
> as the window/showMessageRequest request to the client.

So we should discard the message when the language server is not
yet initialized. This can happen if the server sends
textDocument/publishDiagnostics before responding to the initialize
request. clojure-lsp appears to exhibit this behavior in the wild.

[LSP Spec]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize
2022-08-31 17:47:18 +09:00
Michael Davis
03f0ef93ac Update tree-sitter-rust to latest
There don't appear to be any regressions from the updates.
Also included is a fix which highlights the "#" as in attributes
as punctuation. This was previously unhighlighted.
2022-08-31 17:46:34 +09:00
Michael Davis
ac669ade05 erlang: Fix highlighting of empty records
For example

    -record(state, {})

Would not highlight `state` as a type since the alternation didn't
allow for an empty tuple. Allowing the inner atom of the tuple to be
optional fixes this case.
2022-08-31 17:46:34 +09:00
Michael Davis
acf3599723 erlang: Use Edoc style auto-pairs
Specifically this changes backtic's right-hand-side pair character
to single-quote which is the syntax for inline and block code in
Edoc.
2022-08-31 17:46:34 +09:00
Michael Davis
00d88e540e Fix missing C highlights
* "const" keyword
* booleans
* <=/>= operators
2022-08-31 17:46:34 +09:00
Michael Davis
d7d9ca37e5 Reword the feature_request issue template as enhancement (#3481) 2022-08-31 17:45:49 +09:00
Michael Davis
e441b1c472 packaging: Point to homebrew-core instead of tap (#3513) 2022-08-31 17:45:38 +09:00
Michael Davis
73d5bd739e Delete invalid indents.scm queries 2022-08-31 17:45:23 +09:00
Michael Davis
4e4c6da3bf Add query-check xtask 2022-08-31 17:45:23 +09:00
Michael Davis
fa1dc7e508 tree-sitter: Prevent panic on loading queries 2022-08-31 17:45:23 +09:00
Michael Davis
4c789cfbda tree-sitter: Refactor lazy query loading
The code for loading queries can be shared between indent and
textobjects queries. In both cases we want to kick an error
message out to the logs.
2022-08-31 17:45:23 +09:00
Blaž Hrastnik
12ddd03d3b fix: Don't translate mouse up events as down 2022-08-31 11:36:18 +09:00
Michael Davis
701cea54d2 jumplist: Add documents to view history (#3593)
This change adds documents to the view's document history Vec.
(This is used by `ga` for example to access the last buffer.)

Previously, a sequence like so would have confusing behavior:

1. Open file A: any document with an active language server
2. Find some definition that lives in another file - file B - with `gd`
3. Jump back in the jumplist with `C-o` to file A
4. Use `ga` intending to switch back to file B

The behavior prior to this change was that `ga` would switch to file
A: you could not use `ga` to switch to file B.
2022-08-31 10:45:47 +09:00
Lucy
404db2ebee Move mode transition logic to handle_keymap_event() (#2634)
Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-08-31 10:44:06 +09:00
A-Walrus
78189dd9c1 Fix extra selection with regex anchors (^,$) (#3598)
Also added a bunch of tests to ensure correct behaviour
2022-08-31 10:42:58 +09:00
Michael Davis
9e24f2aa81 Use the original document and view for mode transition hooks (#3508)
When changing focus, the lookup with `current!` may change the
view and end up executing mode transition hooks on the newly
focused view. We should use the same view and document to execute
mode transition hooks so that switching away from a view triggers
history save points.
2022-08-31 10:34:04 +09:00
Alexander Brevig
16525349db Themes update (#3587)
* lint: snazzy

* lint: pop-dark

* lint: penumbra+

* lint: noctis_bordo

* lint: ingrid

* lint: flatwhite

* lint: doom_acario_dark

* lint: dark_plus

* lint: boo_berry

* fix: use 47345E per author instruction

* lint: bogster

* lint: everforest

* lint: acme

* lint: serika

* fix: use nasty_red per author suggestion

* lint: nord

* lint: dracula

* lint: gruvbox

* fix: cursorline gruvbox

* lint: autumn

* fix: no fg for cursorline

* lint: ayu

* lint: rose_pine

* lint: monokai

* lint: solarized

* lint: spacebones

* fix: penumbra bg!=sky

* Update runtime/themes/ayu_light.toml

Co-authored-by: Ivan Tham <pickfire@riseup.net>

* Update runtime/themes/ayu_light.toml

Co-authored-by: Ivan Tham <pickfire@riseup.net>

* fix: fg for ui.help thanks @pickfire

* fix: ingrid with input from @intarga

Co-authored-by: Ivan Tham <pickfire@riseup.net>
2022-08-31 10:27:40 +09:00
dependabot[bot]
86b80e6ce6 build(deps): bump iana-time-zone from 0.1.44 to 0.1.47 (#3611)
Bumps [iana-time-zone](https://github.com/strawlab/iana-time-zone) from 0.1.44 to 0.1.47.
- [Release notes](https://github.com/strawlab/iana-time-zone/releases)
- [Changelog](https://github.com/strawlab/iana-time-zone/blob/main/CHANGELOG.md)
- [Commits](https://github.com/strawlab/iana-time-zone/compare/0.1.44...v0.1.47)

---
updated-dependencies:
- dependency-name: iana-time-zone
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-31 08:47:03 +09:00
Kristoffer Flottorp
1de17a2530 Fix fleetish theme (#3607)
Co-authored-by: krfl <kr.fl@outlook.com>
2022-08-30 08:15:38 -05:00
Blaž Hrastnik
e77b7d147c fix: Recalculate completion after pasting into prompt 2022-08-30 12:27:04 +09:00
Blaž Hrastnik
8a4fbf6daf completion: remove_follow links on filename_impl
We don't need to follow links since we're only scanning the current
directory level (non-recursive).
2022-08-30 12:23:49 +09:00
PiergiorgioZagaria
d2cec25395 Fix process spawning error handling (#3349)
* Fix process spawning error handling

* Log stderr in any case
2022-08-30 11:02:34 +09:00
Michael Davis
5f043dde56 Derive Document language name from languages.toml name key (#3338)
* Derive Document language name from `languages.toml` `name` key

This changes switches from deriving the language name from the
`languages.toml` `scope` key to `name` (`language_id` in the
`LanguageConfiguration` type). For the most part it works to derive the
language name from scope by chopping off `source.` or `rsplit_once` on
`.` but for some languages we have now like html (`text.html.basic`),
it doesn't. This also should be a more accurate fallback for the
`language_id` method which is used in LSP and currently uses the
`rsplit_once` strategy.

Here we expose the language's name as `language_name` on `Document` and
replace ad-hoc calculations of the language name with the new method.

This is most impactful for the `file-type` statusline element which is
using `language_id`.

* Use `Document::language_name` for the `file-type` statusline element

The `file-type` indicator element in the statusline was using
`Document::language_id` which is meant to be used to for telling
Language Servers what language we're using. That works for languages
with `language-server` configurations in `languages.toml` but shows
text otherwise. The new `Document::language_name` method from the
parent commit is a more accurate way to determine the language.
2022-08-30 10:59:45 +09:00
A-Walrus
ae81fbdbf6 Allow less than and greater than in macros (#3556)
* Allow less than and greater than in macros

* Fix failing test
2022-08-30 10:58:51 +09:00
dependabot[bot]
841766ef82 build(deps): bump futures-executor from 0.3.23 to 0.3.24 (#3602)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-29 18:55:26 -05:00
dependabot[bot]
50d5463f90 build(deps): bump futures-util from 0.3.23 to 0.3.24 (#3603)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-29 18:54:58 -05:00
dependabot[bot]
ca4b6eab74 build(deps): bump lsp-types from 0.93.0 to 0.93.1 (#3601)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-29 18:54:24 -05:00
Roman Chumak
ab67788e76 Sonokai (#3595)
Co-authored-by: Roman Chumak <p4ymak@yandex.ru>
2022-08-29 09:00:43 -05:00
Bob
411c5e4871 let extend-line respect range direction (#3046)
* let extend-line respect range direction

* fix extend above logic

* keep `x` existing binding

* Update book/src/keymap.md

Co-authored-by: Ivan Tham <pickfire@riseup.net>

Co-authored-by: Ivan Tham <pickfire@riseup.net>
2022-08-29 10:00:40 +09:00
Charlie Groves
f38ede8631 Add bracketed paste (#3233) 2022-08-29 09:48:49 +09:00
unrelentingtech
51b62230da Add wezterm to get_terminal_provider (#3588)
https://github.com/wez/wezterm is a terminal emulator with its own built-in multiplexer
2022-08-29 09:24:22 +09:00
Kristoffer Flottorp
eeb0a9f504 Add fleetish theme. Based on the unreleased JetBrains Fleet editor (#3591)
Co-authored-by: krfl <kr.fl@outlook.com>
2022-08-29 09:23:54 +09:00
Soc Virnyl S. Estela
abb9f139c5 update colors for papercolor-light (#3585)
* theme: add papercolor light

* fix typo

* add markup highlighting

* theme: added diff colors 

forgot to add it to PaperColor Light

* fix some ui colors

* assign more color for markup headings

* change heading color to bright7
2022-08-29 07:58:05 +08:00
David
db18206795 Fix rust text objects (#3590) 2022-08-28 16:03:39 -05:00
Gustavo Bogarín
e066782782 Add c-sharp textobjects (#3494)
Co-authored-by: Gustavo Bogarín <gbogarin@outlook.com>
Co-authored-by: Gustavo Bogarín <gbogarin@posibillian.tech>
2022-08-27 09:24:47 -05:00
ath3
86a8ea57bb Pascal support (#3542) 2022-08-25 17:59:02 -05:00
Luna
f0fb3407d2 Fixed Doom acario theme (#3533) (#3539)
Changed the `namespace` style to fix the issue (#3533).

I also made the theme look a little closer to how it looks in Emacs, I did however opt to still have it slightly different as I found it easier to read with my port than on the original in Emacs.
I also sorted most keys (mainly from line 8 to 28) for the theme to be in alphabetical order, so it's easier to have a quick glance where they are.
2022-08-25 23:35:43 +08:00
Michael Davis
28c5e2170e Update tree-sitter-ruby (#3527) 2022-08-25 09:15:44 +09:00
ath3
0a22148559 AWK Regex injection (#3535) 2022-08-24 16:14:56 -05:00
ath3
45add73fb1 AWK support (#3528) 2022-08-24 11:58:15 -05:00
Christoph Horn
facde9f18c Julia queries: fix non-consecutive docstring highlight 2022-08-24 11:55:47 -05:00
Christoph Horn
26b2f0a1b5 Julia queries: prevent constructors to be highlighted as functions
Also improves the captures of the remaining identifiers.
2022-08-24 11:55:47 -05:00
Christoph Horn
5806db1e5c Julia queries: limit markdown highlighting to docstrings 2022-08-24 11:55:47 -05:00
Christoph Horn
f5c00b9bc9 Julia queries: major refactoring of highlights.scm, add regex injections, locals 2022-08-24 11:55:47 -05:00
Christoph Horn
77f11bf272 Julia queries: update grammar, fix breaking changes 2022-08-24 11:55:47 -05:00
Jaden
2b16fd43f9 feat(lang): Add esdl grammar (#3526) 2022-08-24 09:51:10 -05:00
seb-bl
ccae718a67 Improve dart indent (#3419) 2022-08-23 21:35:57 -05:00
ChemicalXandco
6b912b8641 add syntax highlights for xit (#3521) 2022-08-23 20:52:01 -05:00
Clay
99b1e8ad89 Fix markdown indented code block rendering (#3503) 2022-08-24 09:12:04 +09:00
Blaž Hrastnik
e4c9d4082a fix: Reset document mode when losing focus
Fixes #3090
2022-08-23 14:07:50 +09:00
Blaž Hrastnik
7b8e4ac95a Editor: remove duplication for view focus/swap commands 2022-08-23 11:44:10 +09:00
Ivan Tham
dd2b9e55a2 Reduce health tick width
Use the same tick as book to reduce margin of whitespace errors.
2022-08-22 19:27:26 -05:00
dependabot[bot]
f32f451b98 build(deps): bump once_cell from 1.13.0 to 1.13.1 (#3511)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-22 19:17:31 -05:00
dependabot[bot]
25f5e8c5d1 build(deps): bump serde_json from 1.0.83 to 1.0.85 (#3510)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-22 19:17:08 -05:00
dependabot[bot]
650cf76d44 build(deps): bump serde from 1.0.142 to 1.0.144 (#3512)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-22 19:16:36 -05:00
dependabot[bot]
f6a1078684 build(deps): bump anyhow from 1.0.61 to 1.0.62 (#3509)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-22 19:15:59 -05:00
Charlie Groves
18909aafe2 Update to crossterm-0.25 (#3390) 2022-08-22 10:29:30 +09:00
Blaž Hrastnik
d993c6349b One more windows fix... 2022-08-22 10:29:11 +09:00
Blaž Hrastnik
e863f6fe27 Fix compilation on windows 2022-08-22 10:18:53 +09:00
Blaž Hrastnik
cb7615e0ed Make external terminal provider configurable
Fixes #1699
2022-08-22 10:11:04 +09:00
ScribblyBirb
7e330697e1 Update tree-sitter-elm to latest commit (#3497) 2022-08-21 15:42:19 -05:00
A-Walrus
ed74e6d5d4 Switch to tabpad configuration option (#3458)
Virtual whitespace tabs are created from the `tab` character padded
with `tabpad` up to  the tab width.
2022-08-21 13:54:02 +09:00
Michael Davis
e61c0b461c Update tree-sitter-org (#3489)
The update fixes a bug that caused the external scanner to hang during
error recovery.

Looking at the diff, there are no structural changes in this update.
There are a few new fields and it looks like some edge-case fixes
but nothing that breaks compatibility with the current queries.
2022-08-21 13:52:52 +09:00
Vince Mutolo
59968d27a4 add penumbra+ theme (#3398)
Co-authored-by: Vince Mutolo <vince@mutolo.org>
2022-08-20 19:26:22 -05:00
Alexander Brevig
aef00a3ab6 feat: add taskwarrior to languages so task N edit is nice (#3468)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-08-19 19:16:54 -05:00
jdrst
9b0fd51318 removes deprecated stdio flag for omnisharp (#3480) 2022-08-19 08:44:17 -05:00
Saber Haj Rabiee
1577a9d0ab style: fixes unused_parens warnings on nightly builds (#3471) 2022-08-18 18:07:18 -05:00
Soc Virnyl S. Estela
bdd1192a35 add diff colors in PaperColor Light (#3470) 2022-08-18 08:24:54 -05:00
Soc Virnyl S. Estela
c18b54263a theme: add papercolor light (#3426)
* theme: add papercolor light

* fix typo

* add markup highlighting
2022-08-17 22:31:17 +08:00
Daniel S Poulin
7711db3a3a Adjust m textobject description and minor code clarification (#3343)
* Update description of `m` textobject to its actual functionality

Sometime recently the functionality of `m` was changed to match the
nearest pair to the cursor, rather than the former functionality of
matching the pair only if the cursor was on one of the brace characters
directly.

* Rename surround methods to reflect that they work on pairs

The current naming suggests that they may work generally on any
textobject, whereas their implementation really focuses on pairs.

* Change description of m textobject to match actual functionality

The current implementation of `m` no longer merely looks at the pair
character the cursor is on, but actually will search for the pair
(defined in helix-core/src/surround.rs) that encloses the cursor, and
not the entire selection.

* Accept suggested wording change

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>

* Prefix pair surround for consistency

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-08-17 10:41:59 +09:00
Michael Davis
254d558907 Update tree-sitter-swift (#3461) 2022-08-17 10:40:21 +09:00
A-Walrus
d6e4fd15fc Fix failing test with unicode-lines feature (#3455) 2022-08-17 10:37:34 +09:00
Poliorcetics
6618cf2d68 feat: shorten output for grammar fetching and building (#3396)
New look:

```
Fetching 102 grammars
98 up to date git grammars
4 updated grammars
        bash      now on 275effdfc0edce774acf7d481f9ea195c6c403cd
        beancount now on 4cbd1f09cd07c1f1fabf867c2cf354f9da53cc4c
        c         now on f05e279aedde06a25801c3f2b2cc8ac17fac52ae
        c-sharp   now on 53a65a908167d6556e1fcdb67f1ee62aac101dda
```

```
Building 102 grammars
100 grammars already built
2 grammars built now
        ["bash", "rust"]
```
2022-08-17 10:37:10 +09:00
Yevgnen
956fbab488 Add emacs theme (#3410) 2022-08-16 19:57:28 -05:00
dependabot[bot]
2968756baf build(deps): bump futures-executor from 0.3.21 to 0.3.23 (#3446)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-15 18:29:32 -05:00
dependabot[bot]
941e023e97 build(deps): bump futures-util from 0.3.21 to 0.3.23 (#3448)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-15 18:28:57 -05:00
dependabot[bot]
f9dc1f33ea build(deps): bump chrono from 0.4.19 to 0.4.22 (#3447)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-15 18:23:26 -05:00
dependabot[bot]
52c8de55a0 build(deps): bump anyhow from 1.0.60 to 1.0.61 (#3449)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-15 18:20:33 -05:00
ChrHorn
a7ff39fe3e remove duplicate entries from theme picker (#3439) 2022-08-16 00:18:04 +09:00
Manuel Schmidbauer
8a75795472 Improved file-picker configuration documentation (#3422) 2022-08-14 13:36:08 -05:00
nosa
c5deb30814 Theme Related Fixes (#3412) 2022-08-14 08:35:15 -05:00
n0s4
8deaebde26 Fix typos in ayu themes, also remove trailing space 2022-08-12 10:57:03 -05:00
n0s4
b565fff0f2 Fix Typos in base16_transparent
Fixes #3373.
2022-08-12 10:57:03 -05:00
Erasin
1eeca10675 Fix Markdown Metadata (#3400) 2022-08-12 09:27:50 -05:00
Kyle L. Davis
21f2affa16 Fix conditional setting of stdin handle on Windows (#3379)
* Revert 3121353c6a

* Switch to conditional compilation

* Run formatter

* Switch from conditional compilation to compile-time bool
2022-08-12 11:27:18 +09:00
Vince Mutolo
7559b77d53 highlight closure pipes as brackets (#3397)
Co-authored-by: Vince Mutolo <vince@mutolo.org>
2022-08-11 19:00:03 -05:00
Itay123TheKing
80dde577b0 Fix hyperlink at the bottom of CONTRIBUTING.md (#3392) 2022-08-11 08:57:17 -05:00
notusknot
d773a6e5f2 Update keymap.md to have Tab and Shift-tab listed (#3365)
Co-authored-by: notusknot <notusknot@gmail.com>
2022-08-11 00:21:37 -05:00
Joshua Suskalo
d192d59753 Update Clojure language definition (#3387) 2022-08-10 16:57:23 -05:00
Erasin
921027fb32 Update tree-sitter-latex and highlights (#3370)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-08-10 07:29:43 -05:00
jdrst
598aa7c424 adds xcopy param to recursively copy runtime folder (#3378) 2022-08-09 20:47:04 -05:00
dependabot[bot]
404defb59b build(deps): bump anyhow from 1.0.59 to 1.0.60 (#3363)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.59 to 1.0.60.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.59...1.0.60)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-09 11:51:20 +09:00
Michael Davis
672ea98b05 Advertise WorkspaceSymbolClientCapabilities support (#3361) 2022-08-09 11:51:10 +09:00
Gokul Soumya
634b6d455f Add custom event type replacing crossterm's Event (#3169)
Ported over from 61365dfbf3 in the `gui` branch. This will allow
adding our own events, most notably an idle timer event (useful
for adding debounced input in [dynamic pickers][1] used by interactive
global search and workspace symbols).

[1]: https://github.com/helix-editor/helix/pull/3110

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-08-09 10:31:26 +09:00
Kyle L. Davis
4ce5a94552 Add language: beancount (#3297)
Co-authored-by: erasin <erasinoo@gmail.com>
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
Co-authored-by: Erasin <erasinoo@gmail.com>
2022-08-08 17:59:55 -05:00
Erasin
d9321134f6 slint indents 2022-08-08 17:57:08 -05:00
Erasin
f09d2bc56b Add slint-ui support
<https://slint-ui.com/>
lsp: <https://github.com/slint-ui/slint/tree/HEAD/tools/lsp>
tree-sitter-slint: <https://github.com/jrmoulton/tree-sitter-slint>
2022-08-08 17:57:08 -05:00
Skyler Hawthorne
3e11017ade revert chrono to 0.4.19
This is causing builds to fail when there is no time zone info, e.g. Alpine,
Android
2022-08-07 12:19:47 -05:00
A-Walrus
6b84344e20 Add completion for nested settings (#3183)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-08-06 12:16:18 -05:00
Michael Davis
973c51c3e9 Remove C-n and C-p from the insert mode keymap (#3340)
These are read-line-like bindings which we'd like to minimize in
insert mode in general.

In particular these two are troublesome if you have a low
`editor.idle-timeout` config and are using LSP completions: the
behavior of C-n/C-p switches from moving down/up lines to moving
down/up the completion menu, so if you hit C-n too quickly
expecting to be in the completion menu, you'll end up moving down
a line instead. Using C-p moves you back up the line but doesn't
re-trigger the completion menu. This kind of timing related change
to behavior isn't realistically that big of a deal but it can be
annoying.
2022-08-07 01:25:09 +09:00
Matthias Deiml
ea04220874 Use split_parser branch for markdown grammar (#3108) 2022-08-06 10:56:48 -05:00
A-Walrus
c00b8f7ad7 Fix tab highlight when tab is partially visible (#3313)
* Fix tab highlight when tab is partially visible

* Make it style based, and not truncation based

Dealing with truncating is a mess, especially when it comes to wide
unicode graphemes. This way it should work no matter what.

* Inline style calculation into branches
2022-08-07 00:46:50 +09:00
A-Walrus
fdd8bbf16b Fix indent guide styling (#3324)
* Fix incorrect indent guide styling

Before the indent guides on top of whitespace inherited the theme
from them. Now they do not.

* Fix dark_plus theme indent_guides

* Use whitespace style as fallback for indent-guide

* Fix dark_plus theme indent_guides

* Move indent_guide style patching out of loop
2022-08-07 00:46:23 +09:00
Daniel S Poulin
4dd35777f4 Attempt to bring spacebones light up to speed with recent features (#3342) 2022-08-06 09:40:10 -05:00
A. Taha Baki
24f5a47cec Rosé Pine Moon Theme (#3229) 2022-08-06 07:14:13 -05:00
Luna
7176c84844 Add Doom's Acario dark theme. (#3308) 2022-08-06 07:07:14 -05:00
ChrHorn
23f4a40a7a Rust queries: add (function_item) as a local scope (#3345) 2022-08-06 05:58:06 -05:00
Kyle L. Davis
63ec10950f Fix comment (#3334) 2022-08-05 20:13:58 -05:00
Erasin
bf6f7042fe Fix php hightlight (#3317)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-08-05 07:34:03 -05:00
Dario Oddenino
3121353c6a Avoid setting stdin handle when not necessary (#3248)
* Avoid setting stdin handle when not necessary

Avoid setting the stdin handle in `shell_impl` when the input argument
is None.

This permits to run commands with no stdin with :sh

* refactoring to avoid code duplication

* making clippy happy

* Process variable name fix
2022-08-05 11:15:50 +09:00
Alexander Brevig
c2a6d29ffc fix: add elvish completions (#3331) 2022-08-05 09:50:47 +09:00
A-Walrus
cfa882557e Fix nondeterministic highlighting (#3275)
* Fix nondeterministic highlighting

This is done by prefering matches in the begining, ie for
`keyword.function`, `keyword` is a better match than `function`.

* Use all positions and not just leftmost

Fixes possible edgecase with something like `function.method.builtin`
and the queries `function.builtin` and `function.method`

* Switch to bitmask for slightly better performance

* Make matches from the start of string

Also change comments to match new behaviour
2022-08-05 09:12:14 +09:00
Michael Davis
f32c05db85 Detect indent-style in :set-language (#3330)
Indent style may change when choosing a language with `:set-language`.
Line-endings most likely will not change, but `:set-language` should
have a similar effect as reloading a file (`:reload`), plus the two
are currently grouped in the implementation and line-ending detection
is not particularly expensive.
2022-08-05 09:11:31 +09:00
Blaž Hrastnik
ee1214d6e5 Update dependencies (chrono) 2022-08-05 09:10:07 +09:00
Matthias Deiml
0ee2061102 Avoid copying fragments (#3136)
* Avoid copying fragments

* Add slice / slices method

* Better documentation for fragment and slice methods
2022-08-04 14:44:43 +09:00
Omnikar
afd292e3b9 Resolve clippy lints (#3307) 2022-08-04 14:32:59 +09:00
Michael Davis
5d33dbacac add a CLI flag for specifying config file location (#2666) 2022-08-04 13:05:52 +09:00
PiergiorgioZagaria
219d2c2515 Change default formatter for any language (#2942)
* Change default formatter for any language

* Fix clippy error

* Close stdin for Stdio formatters

* Better indentation and pattern matching

* Return Result<Option<...>> for fn format instead of Option

* Remove unwrap for stdin

* Handle FormatterErrors instead of Result<Option<...>>

* Use Transaction instead of LspFormatting

* Use Transaction directly in Document::format

* Perform stdin type formatting asynchronously

* Rename formatter.type values to kebab-case

* Debug format for displaying io::ErrorKind (msrv fix)

* Solve conflict?

* Use only stdio type formatters

* Remove FormatterType enum

* Remove old comment

* Check if the formatter exited correctly

* Add formatter configuration to the book

* Avoid allocations when writing to stdin and formatting errors

* Remove unused import

Co-authored-by: Gokul Soumya <gokulps15@gmail.com>
2022-08-04 13:01:48 +09:00
Charlie Groves
c5f8a835f5 Add a .ignore file to make ripgrep more useful (#3315)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-08-03 09:00:39 -05:00
Alexander Brevig
6e7774bb79 Add .gitattributes (#3318) 2022-08-03 08:21:51 -05:00
Charlie Groves
4b6c4ae6ee Fix LF line-endings (#3316) 2022-08-03 07:53:57 -05:00
Matthias Deiml
6b244e2fef Exclude only named children without injection.include-children (#3129)
* Exclude only named children without injection.include-children

* Add injection.include-unnamed-children parameter
2022-08-03 19:18:17 +09:00
Michael Davis
08b442f4cc Inherit javascript/typescript from common 'ecma' queries (#3301)
JavaScript queries now contain a few lines that prevent them from
being used whole-sale in typescript with `; inherits: javascript`.
Here we follow nvim-treesitter's way of using a fake 'ecma' language
as a common base for JavaScript and TypeScript to share as much as
we can.
2022-08-03 14:09:44 +09:00
Kirawi
69f84e2516 theme ui.virtual.indent-guide in dark_plus (#3302) 2022-08-02 10:13:22 -05:00
yvt
aa4394ce12 chore(ci): match *-macos by checking suffix
Simplifies a conditional expression in the CI workflow configuration.

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-08-02 12:04:09 +09:00
yvt
6d16d2cbc9 feat: support grammar cross-compilation 2022-08-02 12:04:09 +09:00
yvt
f6f054ae5b fix(loader): pass cc::Tool::args()
Certain targets, such as `aarch64-apple-*`, require additional compiler
flags to cross-compile for the intended target.
2022-08-02 12:04:09 +09:00
yvt
4461090c3d chore(ci): build binary for aarch64-macos
The tests are conditionally disabled for this target because the x86_64 CI
host is unable to run AArch64 binaries. (There is no officially-supported
reverse Rosetta 2.)
2022-08-02 12:04:09 +09:00
dependabot[bot]
eef9eff20d build(deps): bump pulldown-cmark from 0.9.1 to 0.9.2 (#3294)
Bumps [pulldown-cmark](https://github.com/raphlinus/pulldown-cmark) from 0.9.1 to 0.9.2.
- [Release notes](https://github.com/raphlinus/pulldown-cmark/releases)
- [Commits](https://github.com/raphlinus/pulldown-cmark/compare/v0.9.1...v0.9.2)

---
updated-dependencies:
- dependency-name: pulldown-cmark
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-02 10:07:01 +09:00
dependabot[bot]
f3a3b09337 build(deps): bump similar from 2.1.0 to 2.2.0 (#3293)
Bumps [similar](https://github.com/mitsuhiko/similar) from 2.1.0 to 2.2.0.
- [Release notes](https://github.com/mitsuhiko/similar/releases)
- [Changelog](https://github.com/mitsuhiko/similar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mitsuhiko/similar/compare/2.1.0...2.2.0)

---
updated-dependencies:
- dependency-name: similar
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-02 10:06:46 +09:00
dependabot[bot]
d07d694fe7 build(deps): bump serde from 1.0.140 to 1.0.141 (#3292)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.140 to 1.0.141.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.140...v1.0.141)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-02 10:06:38 +09:00
dependabot[bot]
9643556376 build(deps): bump anyhow from 1.0.58 to 1.0.59 (#3291)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.58 to 1.0.59.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.58...1.0.59)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-02 10:06:28 +09:00
dependabot[bot]
f4b1f9af9a build(deps): bump arc-swap from 1.5.0 to 1.5.1 (#3290)
Bumps [arc-swap](https://github.com/vorner/arc-swap) from 1.5.0 to 1.5.1.
- [Release notes](https://github.com/vorner/arc-swap/releases)
- [Changelog](https://github.com/vorner/arc-swap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vorner/arc-swap/compare/v1.5.0...v1.5.1)

---
updated-dependencies:
- dependency-name: arc-swap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-02 10:06:22 +09:00
Eric K
d693b37445 Modified restore_term fn in application.rs. Changed '\x1B[2 q' to '\x1B[0 q' to restore cursor to user default after exiting helix (#3289) 2022-08-02 10:05:45 +09:00
ChrHorn
11367488ac Improve Python queries, add locals (#3284) 2022-08-01 16:14:07 -05:00
ChrHorn
0c08ff1596 update catppuccin theme(s) to new palettes (#3281) 2022-08-01 15:23:23 -05:00
ChrHorn
59bf1669ec javascript queries: fix parameters (#3280) 2022-08-01 15:15:17 -05:00
Alexander Brevig
07019c3905 fix: gruvbox color modes (#3202)
* fix: gruvbox color modes

* increase contrast, and use blue and not purple
2022-08-01 12:21:37 +09:00
Charlie Groves
9f4802e101 Only add cargo-tarpaulin on x86_64 (#3252)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-07-31 14:52:54 -05:00
A-Walrus
c15b494288 Fix align_selection behaviour with tabs (#3276) 2022-07-31 14:45:51 -05:00
Banst
7e06681413 feat: add cue support (#3262) 2022-07-31 07:04:57 -05:00
Danilo Spinella
110eb73045 Add cwd parameter which is not optional anymore (#3240) 2022-07-31 06:59:15 -05:00
Danilo Spinella
ab616ab718 Add rust-version (MSRV) to helix-term package (#3244) 2022-07-31 17:09:18 +09:00
Amit Beka
fe3a9a868e clipboard: add logging and healthcheck (#3271)
* add logging to clipboard setup

* healthcheck: add clipboard provider name

Co-authored-by: amitbeka <--->
2022-07-31 17:05:34 +09:00
Alexander Brevig
e405e88c86 Flatwhite Theme (#3236) 2022-07-30 12:35:39 -05:00
Erasin
919edfb323 Add Graphviz Dot lang support (#3241)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-07-30 12:34:00 -05:00
A-Walrus
5ca98edfb1 Don't add empty prompt input to history (#3259) 2022-07-30 12:17:01 -05:00
Gokul Soumya
a8b123fe17 Fix byte index error in signature help highlighting
The language server sends a char offset range within the
signature help label text to highlight as the current parameter,
but helix uses byte offset ranges for rendering highlights. This
was brought up in the [review of the original signature help PR][1],
but the ranges were being highlighted correctly, and there were no
out of bound or indexing panics. Turns out rust-analyzer was
[incorrectly sending byte offsets] instead of char offsets and this
made it seem like all was well and good with offsets in helix during
initial testing.

[1]: https://github.com/helix-editor/helix/pull/1755#discussion_r906715371
[2]: https://github.com/rust-lang/rust-analyzer/pull/12272
2022-07-29 14:31:21 +09:00
Slug
14eca318a7 Add transparent theme based on base16_default (#3216) 2022-07-28 18:14:34 -05:00
Erasin
a1c969012d Fix cursorline and selection themes for onelight (#3226) 2022-07-28 16:58:04 -05:00
Erasin
681c0a91dc Add textobject for javascript (#3213) 2022-07-28 08:31:20 -05:00
Kyle L. Davis
cca83af3fd Update README command table (#3224) 2022-07-28 05:37:10 -05:00
Michael Davis
9ed9c3faca Remove let_declaration from Rust locals tracking (#3212) 2022-07-28 12:04:50 +09:00
Philipp Mildenberger
bf74a4652d JS/TS highlighting improvements (#3219) 2022-07-27 13:56:58 -05:00
Yusuf Bera Ertan
85a5df0391 build(nix): add a way to override what grammars get built (#3141) 2022-07-27 12:52:07 -05:00
Ricardo Silva
2f1d3d0899 Add LSP config for Odin (#3214) 2022-07-27 12:28:20 -05:00
MilanVasko
9a49623721 Use OR of all selections in search_selection command (#3138)
Closes #2312
2022-07-27 18:02:19 +09:00
Seth Bromberger
846a6b65c3 add configurable / theme-able statusline separator string (#3175)
* add configurable separator element to statusline

* themable separator

* clippy fixes

* changed default separator to │

* doc updates
2022-07-27 08:47:22 +09:00
A-Walrus
61856f1d64 Nord color modes (#3200)
* Add color modes to nord theme

* Add color-modes to nord_light theme and fixup

Fg color was not set in some places and defaulted incorrectly.
2022-07-26 22:43:39 +09:00
Erasin
df5ab8b40c Fix: Python hightlight (#3201) 2022-07-26 22:31:14 +09:00
Seth Bromberger
3dd2196e4f add position-percentage as a statusline indicator (#3168)
* added position-pct as a statusline indicator

* removed unnecessary mutable reference

* pct -> percent

* percent -> percentage
2022-07-26 15:05:12 +09:00
Gokul Soumya
de8ade8967 Shorten embedded command descriptions (#3070)
* Shorten embedded command descriptions

- Compact descriptions in command palette and infobox

* Shorten typed command descriptions

* Fix typo in decrement command description
2022-07-26 12:04:23 +09:00
Erasin
42115d02bc Suport diagnostic code (#3096)
* add code for diagnostic.

This PR provides a solution to resolve #2994. missing Code Actions for lsp

* remote unused import
2022-07-26 10:26:50 +09:00
n0s4
4f21f430e4 Remove vale from .gitignore 2022-07-26 10:22:28 +09:00
n0s4
d97c4ee217 Spacing 2022-07-26 10:22:28 +09:00
n0s4
d95c7eaa29 Fixes + consistency
Some lines went longer than the titlebars, fixed regex in
SPLITTING SELECTIONS which wasn't actually correct.
Changed 1 "bat" to a "cat" in ADDING SELECTION ON NEXT
SEARCH MATCH which makes it harder to do with a simple
s select.
2022-07-26 10:22:28 +09:00
n0s4
348951f6f9 Add SPLITTING SELECTIONS 2022-07-26 10:22:28 +09:00
n0s4
b0f8d74db9 Spelling 2022-07-26 10:22:28 +09:00
n0s4
771de41155 Add CYCLING AND REMOVING SELECTIONS 2022-07-26 10:22:28 +09:00
n0s4
9114672419 Move Jumplist section and add recap 2022-07-26 10:22:28 +09:00
n0s4
4e76436b20 Add 'ADDING SELECTION ON NEXT SEARCH MATCH' 2022-07-26 10:22:28 +09:00
n0s4
d2b292660d Add SEARCH FOR SELECTION 2022-07-26 10:22:28 +09:00
n0s4
c7f9caf6bd Add REGISTERS, update MACROS accordingly 2022-07-26 10:22:28 +09:00
n0s4
29ee7f6d01 Add REPLACING WITH YANKED TEXT and INCREMENTING/DECREMTING
Also some consistency issues
 - redundant/dated comment in JOINING LINES
 - spacing around slashes
 - etc.
2022-07-26 10:22:28 +09:00
n0s4
92d94e1f7e Add REPITITION section 2022-07-26 10:22:28 +09:00
n0s4
88902d1f59 Improve ALIGN SELECTIONS section 2022-07-26 10:22:28 +09:00
n0s4
ec4c2f3965 Reduce A-; section to a note on section 3.7
Also fixed consistency of capitalisation and spacing of notes.
2022-07-26 10:22:28 +09:00
n0s4
ce732ce664 Correct recap numbers. 2022-07-26 10:22:28 +09:00
n0s4
d0381d942d Line too long + grammar. 2022-07-26 10:22:28 +09:00
n0s4
5accb5cd58 Add vale to gitignore + spelling 2022-07-26 10:22:28 +09:00
n0s4
68acdbb9a2 Added REPLACE and moved SELECTING TO A CHARACTER into the same chapter. 2022-07-26 10:22:28 +09:00
n0s4
1fed3a2220 Add 'ALIGN SELECTIONS' and 'SPLIT SELECTIONS ON LINES' 2022-07-26 10:22:28 +09:00
n0s4
15e1a0ebf2 Move COLLAPSING SELECTION to MOTIONS AND SELECTIONS.
Also had to do a little rewording to fit the recap for MOTIONS AND SELECTIONS.
2022-07-26 10:22:28 +09:00
n0s4
aa5cebae22 Added Select mode section.
Also added a note about X on "SELECTING LINES".
2022-07-26 10:22:28 +09:00
n0s4
a0d01455ac Re-order sections. 2022-07-26 10:22:28 +09:00
Kirawi
0a2646e720 Improve python highlighting (#3103)
* improve python queries

* update python grammar to `0.20.2`

* fix variadic parameter scope

* add punctuation scopes

* fix order of punctuation scopes

* undo  `embedded` delete
2022-07-26 10:17:51 +09:00
Daniel Longeuay
2ede98c4b4 feat(tree-sitter): add go template support (#3091)
* feat(tree-sitter):  add go template support

* fix(tree-sitter): 🐛 go template highlight scope selectors

* chore(tree-sitter): 🔧 update go template grammar commit
2022-07-26 10:17:28 +09:00
Mr. E
d4a5413255 feat(themes): add mode-specific styles to the dracula themes (#3135) 2022-07-26 10:17:00 +09:00
Clay
b55573dc1d Add elixir & heex comment textobjects (#3179) 2022-07-26 10:14:45 +09:00
Blaž Hrastnik
255c1734cf Rename padding to spacer, remove by default 2022-07-26 10:10:06 +09:00
Ivan Tham
2f980471f8 Make gutters padding automatic (#3163)
Remove padding gutter type, and automatically add 1 padding if gutters is
non-empty.
2022-07-26 10:08:09 +09:00
Seth Bromberger
bfdcfec8c9 add spacer element to statusline (#3165)
* add spacer element to statusline

* docs
2022-07-26 10:07:59 +09:00
André Sá
742d16026e Add ayu themes (#3184) 2022-07-26 10:05:27 +09:00
Joe
d0c63409cc Add table of contents to keymap.md (#3174) 2022-07-26 09:41:09 +09:00
A-Walrus
cb142b5750 Highlight constructor in monokai theme (#3131) 2022-07-26 09:40:56 +09:00
Philipp Mildenberger
235237ddc4 Refactor 'helix-loader::merge_toml_values' to use a 'merge-depth' instead of 'merge_toplevel_arrays' (#3080)
- This ensures that other values than just the arrays are overridden, like nested objects, where it makes sense
- merge_depth is set to 3 so that top-level language features are merged (like 'scope'), but everything deeper is overridden with the user-config
2022-07-26 09:40:38 +09:00
bootra
b7fa9ba601 Fix non-msvc grammar compile on Windows (#3190) 2022-07-26 09:33:53 +09:00
dependabot[bot]
73a308c665 build(deps): bump serde from 1.0.139 to 1.0.140 (#3194)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.139 to 1.0.140.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.139...v1.0.140)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-26 08:17:14 +08:00
bootradev
4db01b3f82 add support for rulers to boo_berry theme (#3191) 2022-07-26 00:03:15 +05:30
Erasin
dad6d0f3b2 Fix: svelte indets.scm (#3147) 2022-07-24 17:42:27 +09:00
Joe
d6fd93788c Add rabl/jbuilder/jb extensions for Ruby (#3173)
* Add rabl and jbuilder

* Add jb
2022-07-24 11:50:04 +09:00
Clay
ec85fb9ab6 Improve HEEx comment highlights, inject comment lang (#3170) 2022-07-24 11:49:52 +09:00
Kyle L. Davis
dfc31e74af Fix different document panic (#3160)
Would panic when given the view for the current document for a different document.
2022-07-23 18:42:28 +09:00
Andrey Tkachenko
1b3a10d906 Add vh verilog header file type to file-types (#3158) 2022-07-23 09:35:20 +05:30
Michael Davis
19e51c8264 add release checklist and changelog curation docs (#2598)
* add release checklist and changelog curation docs

* remove step for deleting '-dev' suffix from VERSION
2022-07-22 10:31:40 +09:00
Aiko Mastboom
4589111d12 helix_view::theme [WARN] Theme (#3119)
* helix_view::theme [WARN] Theme

* updated: warning, error, info, hint colours
https://github.com/catppuccin/catppuccin/blob/main/docs/style-guide.md#typography

Co-authored-by: Aiko Mastboom <git@aiko.sh>
2022-07-22 10:31:02 +09:00
Mr. E
b05fcaadad Indent with tabs by default (#3095) 2022-07-22 10:30:21 +09:00
Philipp Mildenberger
b6c700fce9 Replace '; inherits <language>' in treesitter queries with <language> queries instead of appending them (#2470)
Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-07-22 10:28:32 +09:00
Houkime
52bb1103f8 Auto pair-removal (#2940)
* auto pair-removal

Fixes https://github.com/helix-editor/helix/issues/1673

* autopairs removal: use doc autopairs

* autopairs-removal: limit to one-char selections

* use single_grapheme() to check if range is one char

* fix errouneous deletes of " and other symmetric autopairs when at buffer start

Co-authored-by: Houkime <>
2022-07-22 10:23:52 +09:00
Robin
19b7864062 keep jump/file history when using :split (#3031)
* keep jump/file history when using :split

* move history cloning into the switch function

Co-authored-by: Robin <robinvandijk@klippa.com>
2022-07-22 10:23:00 +09:00
Bob
2f53644c6d jumplist picker (#3033)
* jumplist picker

* remove jumps slicing

Co-authored-by: Benoît Cortier <bcortier@proton.me>

* remove unnecessary deref format! parameter

Co-authored-by: Benoît Cortier <bcortier@proton.me>

Co-authored-by: Benoît Cortier <bcortier@proton.me>
2022-07-22 10:21:46 +09:00
Clay
e560212ec5 Gleam: add support for built-in language server (#3139)
* Add gleam lsp support

* Docgen gleam lsp support
2022-07-22 10:19:42 +09:00
0rphee
76756f0e5d add statusline.{mode} colors and tweak various settings (#3128) 2022-07-21 12:26:54 +05:30
Alexis Kalabura
8b2a14153b add statusline element to display file line endings (#3113)
* add statusline element to display file line endings

* run cargo fmt --all

* change the word *ending* from plural to singular

* support for the unicode-lines feature flag
2022-07-21 13:03:12 +09:00
Blaž Hrastnik
906259cc41 fix: Indent levels could bleed over on the left edge
Fixes #3087
Refs #3105
    #	modified:   theme.toml
2022-07-20 17:06:33 +09:00
Erasin
3b1ba7fb12 Add color-modes for onelight theme (#3104)
Add keyword.function and keyword.storage.type for TS
2022-07-20 11:55:22 +09:00
Mr. E
b6e06c8c0c feat(themes): add mode-specific styles to the onedark theme (#3098) 2022-07-20 11:55:08 +09:00
Michael Davis
9753da6ab7 Fix locals tracking in Rust closures (#3027)
The fix comes from the rewriting of the `closure_parameters` stanza:
it was capturing the entire `closure_parameters` node including
paretheses, whitespace, and commas. Capturing the identifiers within
fixes the tracking.

In order to make sure locals definitions from closure parameters don't
leak out of the body of the closure, though, we should also mark the
closure itself as a locals scope.
2022-07-20 11:51:35 +09:00
Gokul Soumya
791bf7e50a Add lsp signature help (#1755)
* Add lsp signature help

* Do not move signature help popup on multiple triggers

* Highlight current parameter in signature help

* Auto close signature help

* Position signature help above to not block completion

* Update signature help on backspace/insert mode delete

* Add lsp.auto-signature-help config option

* Add serde default annotation for LspConfig

* Show LSP inactive message only if signature help is invoked manually

* Do not assume valid signature help response from LSP

Malformed LSP responses are common, and these should not crash the
editor.

* Check signature help capability before sending request

* Reuse Open enum for PositionBias in popup

* Close signature popup and exit insert mode on escape

* Add config to control signature help docs display

* Use new Margin api in signature help

* Invoke signature help on changing to insert mode
2022-07-19 11:28:24 +09:00
dependabot[bot]
02f0099210 build(deps): bump grep-searcher from 0.1.8 to 0.1.10 (#3101)
Bumps [grep-searcher](https://github.com/BurntSushi/ripgrep) from 0.1.8 to 0.1.10.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/ripgrep/compare/grep-searcher-0.1.8...grep-searcher-0.1.10)

---
updated-dependencies:
- dependency-name: grep-searcher
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-19 11:24:03 +09:00
dependabot[bot]
ddc0ea751c build(deps): bump clipboard-win from 4.4.1 to 4.4.2 (#3100)
Bumps [clipboard-win](https://github.com/DoumanAsh/clipboard-win) from 4.4.1 to 4.4.2.
- [Release notes](https://github.com/DoumanAsh/clipboard-win/releases)
- [Commits](https://github.com/DoumanAsh/clipboard-win/commits)

---
updated-dependencies:
- dependency-name: clipboard-win
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-19 07:17:07 +05:30
dependabot[bot]
77e5890859 build(deps): bump grep-regex from 0.1.9 to 0.1.10 (#3102)
Bumps [grep-regex](https://github.com/BurntSushi/ripgrep) from 0.1.9 to 0.1.10.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/ripgrep/compare/grep-regex-0.1.9...grep-regex-0.1.10)

---
updated-dependencies:
- dependency-name: grep-regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-19 07:15:57 +05:30
Bob
e5c7aaed91 support prefilling prompt (#2459)
* support prefilling prompt

* introduce with_line builder method in Prompt

* extract show_prompt

* use textobject_word as fallback input
2022-07-18 10:17:13 +09:00
Narazaki Shuji
55b45ec4a4 Set the selection point of the first file correctly (#3073) 2022-07-18 10:14:36 +09:00
Ivan Tham
e8214fb1e6 Make gutters padding optional (#2996)
If all gutters are removed, there are still an extra one padding, would be nice
to remove that to save some space.
2022-07-18 10:13:47 +09:00
Bob
2a8d38c27b support toggling pickers' preview panel (#3021)
* support toggling pickers' preview panel

* add doc for toggling preview
2022-07-18 10:11:25 +09:00
Mr. E
dbf68e0370 Customizable/configurable status line (#2434)
* feat(statusline): add the file type (language id) to the status line

* refactor(statusline): move the statusline implementation into an own struct

* refactor(statusline): split the statusline implementation into different functions

* refactor(statusline): Append elements using a consistent API

This is a preparation for the configurability which is about to be
implemented.

* refactor(statusline): implement render_diagnostics()

This avoid cluttering the render() function and will simplify
configurability.

* feat(statusline): make the status line configurable

* refactor(statusline): make clippy happy

* refactor(statusline): avoid intermediate StatusLineObject

Use a more functional approach to obtain render functions and write to
the buffers, and avoid an intermediate StatusLineElement object.

* fix(statusline): avoid rendering the left elements twice

* refactor(statusline): make clippy happy again

* refactor(statusline): rename `buffer` into `parts`

* refactor(statusline): ensure the match is exhaustive

* fix(statusline): avoid an overflow when calculating the maximal center width

* chore(statusline): Describe the statusline configurability in the book

* chore(statusline): Correct and add documentation

* refactor(statusline): refactor some code following the code review

Avoid very small helper functions for the diagnositcs and inline them
instead.
Rename the config field `status_line` to `statusline` to remain
consistent with `bufferline`.

* chore(statusline): adjust documentation following the config field refactoring

* revert(statusline): revert regression introduced by c0a1870

* chore(statusline): slight adjustment in the configuration documentation

* feat(statusline): integrate changes from #2676 after rebasing

* refactor(statusline): remove the StatusLine struct

Because none of the functions need `Self` and all of them are in an own
file, there is no explicit need for the struct.

* fix(statusline): restore the configurability of color modes

The configuration was ignored after reintegrating the changes of #2676
in 8d28f95.

* fix(statusline): remove the spinner padding

* refactor(statusline): remove unnecessary format!()
2022-07-18 09:57:01 +09:00
Joe
43761d426c Remove .git extension from SCSS tree-sitter repo url (#3089) 2022-07-17 21:41:05 +05:30
Joe
0c9594e41e Add SCSS language support (#3074) 2022-07-17 17:55:20 +08:00
Alex Kim
bcacc703d7 fix wrong value for cursor shape config in the docs (#3081) 2022-07-15 20:21:34 +05:30
Benoît Cortier
333ab27837 feat(term): uniformize word-wise movement and deletion (#2500)
Ctrl-based shortcuts are common in numerous applications.

This change:
- Adds Ctrl+{Left/Right/Backspace/Delete} for word-wise movement/deletion in prompt, picker, …
- Removes Alt-Left and Alt-Right in prompt, picker, …
- Adds Alt-Delete in insert mode for forward word deletion

In some terminals, Alt-Backspace might not work because it is ambigous.
See: https://github.com/helix-editor/helix/pull/2193#issuecomment-1105042501
Hence, Alt alternative is not removed.
2022-07-15 21:59:00 +08:00
Bob
8681fb6d9e respect count in treesitter movement (#3058) 2022-07-14 08:08:09 +08:00
Bob
4418924ec3 respect count for selecting next/previous match (#3056) 2022-07-13 23:01:42 +08:00
Bob
e6a6e251c5 respect count for repeating motion (#3057) 2022-07-13 23:00:24 +08:00
Termina94
3cced1e3c8 Add cursorline colour to darkplus theme (#3054)
Co-authored-by: Dean Revell <revell@gmail.com>
2022-07-12 15:18:41 -05:00
0rphee
7951ebfd4d [Theme] Noctis (#3043) 2022-07-12 12:42:17 -05:00
Mateusz S. Szczygieł
5f69beb87f Add textobjects.scm to GLSL (#3051) 2022-07-12 10:13:57 -05:00
Philipp Mildenberger
e97b8607c1 Added ungrammar language support (#3048) 2022-07-12 10:06:53 -05:00
dependabot[bot]
fb62569785 build(deps): bump regex from 1.5.5 to 1.6.0 (#3041)
Bumps [regex](https://github.com/rust-lang/regex) from 1.5.5 to 1.6.0.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.5.5...1.6.0)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-12 11:17:24 +09:00
dependabot[bot]
930f98053e build(deps): bump serde from 1.0.138 to 1.0.139 (#3040)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-12 07:44:00 +05:30
Austen LeBeau
0cb0c30618 add fortran language (#3025) 2022-07-10 11:27:44 -05:00
Slug
e109022bfd fix: error that caused usize to overflow (#3024)
* fix: error that caused usize to overflow

* update: changed check_sub to saturating_sub
2022-07-10 10:54:06 +02:00
Timothy DeHerrera
718c3baebe nix: pass makeWrapperArgs to wrapProgram (#3003) 2022-07-09 11:17:44 -05:00
Timothy DeHerrera
fefa4d8c59 nix flake: make the binary cache "just work" (#2999) 2022-07-09 11:09:37 -05:00
Amit Beka
6100b1ba08 book: add wiki links to the title page and install page (#3017)
Co-authored-by: amitbeka <--->
2022-07-09 11:08:47 -05:00
Gokul Soumya
21b66ba068 lsp: Add workspace/applyEdit to client capabilites (#3012)
The functionality already existed, but the capability wasn't being
reported correctly to the server:

230ba264bf/helix-term/src/application.rs (L716-L728)
2022-07-09 07:31:15 +09:00
Gokul Soumya
b7a3531b8f theme(onedark): Remove bg for window separator (#3011) 2022-07-08 15:24:09 -05:00
Jake Langford
230ba264bf Introduce storage highlighting for typescript/javascript (#2961) 2022-07-06 08:54:07 -05:00
Ivan Tham
e35abe38f3 Remove broken ledger tag highlight (#2988) 2022-07-06 07:35:36 -05:00
Gokul Soumya
af35c62407 Show file path only in workspace diagnostic picker 2022-07-06 13:06:46 +02:00
Gokul Soumya
a43bcc8765 Display error code only if not none 2022-07-06 13:06:46 +02:00
Gokul Soumya
0c104685c0 Sub sort diagnostics by line number 2022-07-06 13:06:46 +02:00
Gokul Soumya
2c37e25cb5 Display diagnostic text before code in picker 2022-07-06 13:06:46 +02:00
Gokul Soumya
c4e022971d Remove source from diagnostic picker display
It is usually the name of the LSP and doesn't add much
useful information.
2022-07-06 13:06:46 +02:00
Erin van der Veen
e0cf19c612 Update tree-sitter-nickel (#2987) 2022-07-06 13:05:51 +02:00
A-Walrus
1378b911b6 Fix some typos (#2978) 2022-07-05 21:49:54 -05:00
Ivan Tham
b612211070 Update tree-sitter-ledger (#2936) 2022-07-05 09:12:28 -05:00
Michael Davis
aacd0c8aa5 Update TSQ queries (#2960)
A few changes to make TSQ highlights better:

* A parsing error has been fixed in the grammar itself
    * Previously tree-sitter-tsq did not parse the variables
      in predicates like `(#set! injection.language "javascript")`
* Theme nodes as `tag`
    * The newly added node to the parser (from the above fix) is
      `variable` which takes over the `variable` capture from nodes
* Highlight known predicates as `function` and unsupported
  predicates as `error`
    * This may help when translating queries from nvim-treesitter.
      For example `#any-of?` is a common one used in nvim-treesitter
      queries but not implemented in Helix or tree-sitter-cli.
* Inject tree-sitter-regex into `#match?` predicates
2022-07-05 20:01:05 +09:00
Matthew Toohey
d78354c537 add language idris (#2971) 2022-07-05 20:00:38 +09:00
Joe
b26e7e2e8f Add live preview to theme picker (#1798)
* Add theme picker with live preview

* Add live theme preview to :theme command

* cargo fmt

* Fix clippy warnings

* Remove picker variant

* Remove unused import

* Cleanup

* Change current_theme to last_theme

* Fix accidental comment flash deletion

* Typo

* Remove theme cache

* Add some comments

* Refactor some theme handling

TIL flatmap on Option is called  and_then

* Remove unnecessary renames

* Constrain last_theme theme preview lifecycle

* Switch to bitflag implementation

* Better handling of last_theme

* Sort theme names

* Better memory juggling

* Missed a branch

* Remove name from theme, switch bitand to &

* cargo fmt

* Update helix-view/src/editor.rs

* Switch boolean to enum

* Remove bitflag impl

* cargo fmt

* Remove un-needed type arg

* cargo fmt
2022-07-05 19:44:16 +09:00
Michael Davis
85411bed83 DAP: Make cwd required in RunTerminalArguments
The spec has `cwd` in `RunInTerminalRequestArguments` as non-optional:
https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_RunInTerminal
2022-07-05 12:34:03 +02:00
Michael Davis
44f596334a DAP: Skip serializing Options when None
DAP follows the same strict TypeScript interface syntax as LSP
which states:

> The document uses TypeScript interfaces in strict mode to describe
> these. This means for example that a `null` value has to be explicitly
> listed and that a mandatory property must be listed even if a falsify
> value might exist.

So we have to skip serializing any fields that end in `?` instead
of passing `null`.
2022-07-05 12:34:03 +02:00
Jens Getreu
936ed3a226 Add Autumn night theme
Under some light conditions, one prefers a high contrast theme.
2022-07-05 12:33:37 +02:00
Jens Getreu
2e709859c4 Autumn theme: slightly adjust contrast 2022-07-05 12:33:37 +02:00
dependabot[bot]
f3e8b0f34b build(deps): bump smallvec from 1.8.1 to 1.9.0 (#2976)
Bumps [smallvec](https://github.com/servo/rust-smallvec) from 1.8.1 to 1.9.0.
- [Release notes](https://github.com/servo/rust-smallvec/releases)
- [Commits](https://github.com/servo/rust-smallvec/compare/v1.8.1...v1.9.0)

---
updated-dependencies:
- dependency-name: smallvec
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-05 19:31:01 +09:00
dependabot[bot]
f3467399b7 build(deps): bump crossterm from 0.23.0 to 0.24.0 (#2968)
Bumps [crossterm](https://github.com/crossterm-rs/crossterm) from 0.23.0 to 0.24.0.
- [Release notes](https://github.com/crossterm-rs/crossterm/releases)
- [Changelog](https://github.com/crossterm-rs/crossterm/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossterm-rs/crossterm/compare/0.23...0.24)

---
updated-dependencies:
- dependency-name: crossterm
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-05 19:30:33 +09:00
dependabot[bot]
ba255e3e3e build(deps): bump serde_json from 1.0.81 to 1.0.82 (#2966)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.81 to 1.0.82.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.81...v1.0.82)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-05 19:25:56 +09:00
dependabot[bot]
1fc8cbeb68 build(deps): bump log from 0.4.14 to 0.4.17 (#2965)
Bumps [log](https://github.com/rust-lang/log) from 0.4.14 to 0.4.17.
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/compare/0.4.14...0.4.17)

---
updated-dependencies:
- dependency-name: log
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-05 19:24:37 +09:00
dependabot[bot]
b98567f248 build(deps): bump which from 4.2.4 to 4.2.5 (#2964)
Bumps [which](https://github.com/harryfei/which-rs) from 4.2.4 to 4.2.5.
- [Release notes](https://github.com/harryfei/which-rs/releases)
- [Commits](https://github.com/harryfei/which-rs/compare/4.2.4...4.2.5)

---
updated-dependencies:
- dependency-name: which
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-05 19:24:07 +09:00
dependabot[bot]
700431d665 build(deps): bump encoding_rs from 0.8.30 to 0.8.31 (#2963)
Bumps [encoding_rs](https://github.com/hsivonen/encoding_rs) from 0.8.30 to 0.8.31.
- [Release notes](https://github.com/hsivonen/encoding_rs/releases)
- [Commits](https://github.com/hsivonen/encoding_rs/compare/v0.8.30...v0.8.31)

---
updated-dependencies:
- dependency-name: encoding_rs
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-05 19:19:27 +09:00
dependabot[bot]
c88d736d5c build(deps): bump once_cell from 1.12.0 to 1.13.0 (#2969)
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/matklad/once_cell/releases)
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.12.0...v1.13.0)

---
updated-dependencies:
- dependency-name: once_cell
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-05 11:04:03 +08:00
dependabot[bot]
a679efa8ce build(deps): bump serde from 1.0.136 to 1.0.138 (#2967)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.136 to 1.0.138.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.136...v1.0.138)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-05 08:20:12 +05:30
Skyler Hawthorne
f392e35439 feat(theme): solarized: add cursorline, ruler, indent guide (#2962) 2022-07-04 18:06:44 -05:00
A-Walrus
2ac1de305e Fix backwards selection duplication widening bug (#2945)
* Fix backwards selection duplication widening bug

* Add integration tests

* Make tests line-ending agnostic

Make tests line-ending agnostic

Use indoc to fix tests

Fix line-ending on test input
2022-07-05 07:51:15 +09:00
川田 恵氏 (Kawada Keishi a.k.a megumish)
244825b9e1 Add runtime xcopy command on powershell in docs (#2958) 2022-07-04 12:32:46 -05:00
0rphee
e58d28a972 Add Haskell roots (#2954) 2022-07-03 22:44:17 -05:00
rsteube
4c30a3609a languages: added elvish (#2948) 2022-07-03 16:19:12 -05:00
ChrHorn
9f43dbc45d Highlight whole row in picker menus (#2939) 2022-07-02 17:29:46 +05:30
Gokul Soumya
6e2aaed5c2 Reuse menu::Item trait in picker (#2814)
* Refactor menu::Item to accomodate external state

Will be useful for storing editor state when reused by pickers.

* Add some type aliases for readability

* Reuse menu::Item trait in picker

This opens the way for merging the menu and picker code in the
future, since a picker is essentially a menu + prompt. More
excitingly, this change will also allow aligning items in the
picker, which would be useful (for example) in the command palette
for aligning the descriptions to the left and the keybinds to
the right in two separate columns.

The item formatting of each picker has been kept as is, even though
there is room for improvement now that we can format the data into
columns, since that is better tackled in a separate PR.

* Rename menu::Item::EditorData to Data

* Call and inline filter_text() in sort_text() completion

* Rename diagnostic picker's Item::Data
2022-07-02 13:21:27 +02:00
nosa
290b3ebbbe Update night_owl for cursorline (#2938) 2022-07-01 14:09:59 -05:00
Michael Jones
1fde77ad9d Sort themes, language & files by score & then name (#2675)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-07-01 11:06:14 -05:00
ramojus
cc3aded185 add statusline mode colors to meliora theme (#2933) 2022-07-01 21:24:33 +09:00
Blaž Hrastnik
a1c1abca2b fix CI 2022-07-01 21:24:10 +09:00
nosa
8a19196ad5 Updated for #2676 , but I took the opportunity to do some other changes. (#2929)
- Misspelling of 'modifiers' for markdown.heading.1 and 2.
- Errors are now just underlined instead of in red.
- Diagnostics are dimmed, as well as whitespace.
- Add constant.builtin.
2022-07-01 19:18:39 +09:00
Blaž Hrastnik
9ae70cc410 Disable tree-sitter python indents, use fallback for now
There's been a lot of complaints about the state of python indentation
and the fallback actually works better until the solution proposed
in https://github.com/helix-editor/helix/issues/763#issuecomment-1137894973=
is implemented.
2022-07-01 19:17:19 +09:00
Michael Jones
d8abd1eaf3 Sort themes, language & files by score & then name (#2675)
* Sort themes by score & then name

Previously the themes were appearing unordered after typing ':theme '.
This sorts them first by fuzzy score and then by name so that they
generally appear in a more ordered fashion in the initial list.

The sort by name does not really pay off when there is a score so an
alternative approach would be to sort by name if there is string to
fuzzy match against and otherwise sort by score.

I've lowercased the names as that avoids lower case & upper case letters
being sorted into separate groups. There might be a preferable approach
to that though.

* Sort language & files by score then name

And change to use sort_unstable_by instead of sort_unstable_by_key as it
allows us to avoid some allocations.

I don't fully understand the flow of the 'filename_impl' function but
this seems to deliver the desired results.

* Remove unnecessary reference

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-07-01 18:33:52 +09:00
plexom
f10b6f6ee2 adds --vsplit and --hsplit arguments (#2773)
* adds --vsplit and --hsplit arguments

* moved comment

* fixed lint (third time's a charm)

* changed vsplit and hsplit from two separate bools to type Option<Layout>, and some cleanup
2022-07-01 18:27:32 +09:00
Benjamin Rich
15d96c843a Add new key bindings to view mode (#2803)
* Make view mode more pager-like

Addresses #2721

* Remove view mode bindings for J and K
2022-07-01 18:27:18 +09:00
Sora
edee2f4c34 Fix backwards character deletion on other whitespaces (#2855)
* delete_backwards_char accepts any type of whitespace

* Fix inconsistency, where unicode whitespaces are treated as normal whitespaces

* Changed back to direct whitespace match

* Only accept explicit whitespace / tabs

Co-authored-by: s0LA1337 <dreamer@neoncity.dev>
2022-07-01 18:08:48 +09:00
two-six
444bc24a26 [Theme] Nord Light (#2908)
* add theme

* updated nord_light

* update to colors

* last update to colors
2022-07-01 18:08:27 +09:00
Erasin
051a7f0606 add cursorline to one light theme (#2925) 2022-07-01 18:07:46 +09:00
Jens Getreu
7baa8e837b Add color-modes to Autumn theme (#2928)
Co-authored-by: Jens Getreu <jens.getreu@dlh.lu>
2022-07-01 18:06:16 +09:00
Michael Davis
c5600c9c01 markdown: limit raw block highlight to code fence content 2022-07-01 11:04:23 +02:00
Michael Davis
c8dba2f4c6 erlang: highlight modules in behaviour attributes 2022-07-01 11:04:23 +02:00
Michael Davis
19acbfe02d erlang: highlight records with macro names
You might use a macro like `?MODULE` to name a record:

    -record(?MODULE, {a, b, c}).

With this fix, the record fields correctly get `variable.other.member`
highlights.
2022-07-01 11:04:23 +02:00
Michael Davis
bf1aa8876c git-commit: fix highlight edge cases
* branch message with current branch and diverged branch has been
  added to the parser
* scissors used in verbose commits are marked as a punctuation
  delimiter
    * we could use comment instead since they're visually the
      same but IMO this works better
2022-07-01 11:04:23 +02:00
Michael Davis
a890c4a64d tsq: update parser to fix escaping double quotes
This includes a fix for the new HTML highlights introduced a few
parent commits back:

    ["\"" (attribute_name)] @string

Would get tripped up and the entire line would be highlighted as
a string. Now `\"` is a valid escape.

I'm switching to my fork as the primary repo as the upstream hasn't
been touched in over a year (mostly because stability afaict) but
it has no watchers currently so I'm not hopeful that my PR will
be merged.
2022-07-01 11:04:23 +02:00
Michael Davis
d8f036f0a9 erlang: update parser for fix on remote calls 2022-07-01 11:04:23 +02:00
Michael Davis
199a2460ca make: add injection-regex 2022-07-01 11:04:23 +02:00
Michael Davis
4a0dab8bc2 erlang: fix '#match?' for specs/callbacks 2022-07-01 11:04:23 +02:00
Michael Davis
e4e8a39bf7 replace module captures with namespace
`module` is undocumented and does not exist in other themes. The
equivalent existing scope based on usage (Elixir for example) is
`namespace`.
2022-07-01 11:04:23 +02:00
Michael Davis
016e97314c html: highlight punctuation
* `/>` as in self-closing tags like `<hr/>`
* `=` as in the separator between attribute name and value `<a href="bar">`
2022-07-01 11:04:23 +02:00
Michael Davis
7cf88f2bac edoc: prevent rogue punctuation highlights
Punctuation highlights would show up outside of where they
were valid, for example using parentheses in some text. This
change prevents that by gating the captures to being under
the named nodes in which they are valid.
2022-07-01 11:04:23 +02:00
Michael Davis
78c944ebc3 rust: fix highlight corner-cases
* add punctuation highlights for commas as in function parameters
* remove stray `variable.parameter` highlight
    * I couldn't find any regressions from this and it fixes an
      edge case I ran into (but sadly did not record 😓)
* highlight `fn` as `keyword.function`
    * the theme docs have `fn` as an example so it seems fitting
2022-07-01 11:04:23 +02:00
Michael Davis
beb19fe1bd bash: expand injection-regex to common shells 2022-07-01 11:04:23 +02:00
Michael Davis
ca82cd86e6 markdown: highlight punctuation 2022-07-01 11:04:23 +02:00
Michael Davis
bd527c84e6 erlang: highlight unary '#' as punctuation.bracket
The '#' character may either be interpreted as a map when used
like so:

    %% Example 1
    #{a => b}

Or as an operator which updates an existing map when the left-hand
side is an expression:

    %% Example 2
    MyMap#{a => b}

This commit changes the highlight to `punctuation.bracket` when used
as a character in a literal map (example 1) and keeps the `operator`
highlight when used for updating (example 2).
2022-07-01 11:04:23 +02:00
Michael Davis
d523280e85 erlang: highlight nullary macros as constants 2022-07-01 11:04:23 +02:00
Sora
26501afe13 Update cursorline for tokyonight + tokyonight_storm (#2927)
Co-authored-by: s0LA1337 <dreamer@neoncity.dev>
2022-06-30 17:14:55 -05:00
Skyler Hawthorne
f2768da1f6 add mode colors to solarized (#2926) 2022-07-01 06:52:31 +09:00
Mathspy
d06800f1dd Add mode specific styles (#2676)
* Add mode specific styles

In similar vein to neovim's lualine and similar statusline packages this
allows helix users to style their mode based on which mode it is thus
making each mode more visually distinct at a glance

* Add an example based on rosepine

* Add editor.colors-mode config

* Document statusline mode styles
2022-06-30 18:26:00 +09:00
Falco Hirschenberger
ed89f8897e Add workspace and document diagnostics picker (#2013)
* Add workspace and document diagnostics picker

fixes #1891

* Fix some of @archseer's annotations

* Add From<&Spans> impl for String

* More descriptive parameter names.

* Adding From<Cow<str>> impls for Span and Spans

* Add new keymap entries to docs

* Avoid some clones

* Fix api change

* Update helix-term/src/application.rs

Co-authored-by: Bjorn Ove Hay Andersen <bjrnove@gmail.com>

* Fix a clippy hint

* Sort diagnostics first by URL and then by severity.

* Sort diagnostics first by URL and then by severity.

* Ignore missing lsp severity entries

* Add truncated filepath

* Typo

* Strip cwd from paths and use url-path without schema

* Make tests a doctest

* Better variable names

Co-authored-by: Falco Hirschenberger <falco.hirschenberger@itwm.fraunhofer.de>
Co-authored-by: Bjorn Ove Hay Andersen <bjrnove@gmail.com>
2022-06-30 18:16:18 +09:00
Jens Getreu
94fc41a419 Add cursorline to Autumn theme (#2918)
Co-authored-by: Jens Getreu <jens.getreu@dlh.lu>
2022-06-29 14:14:16 -05:00
Ben Lee-Cohen
15ac1142cf Adding a cursorline for the Nord theme (#2916) 2022-06-29 09:13:49 -05:00
Stuart Hinson
6ac6080969 primary cursorline for Dracula theme (#2915) 2022-06-29 09:08:05 -05:00
Michael Davis
bf1db737d4 nix: update nixCargoIntegration (#2907)
This fixes the aarch64-darwin build - the newer revision uses the
cCompiler override to compile tree-sitter with clang instead of
gcc (which fails).
2022-06-29 17:53:56 +09:00
Seth Bromberger
07e7a13a9e fixes background reset (#2900)
* fixes background reset

* moves creation of default style out of loop

* patches with background_style

* removes commented code
2022-06-28 23:59:10 +09:00
PabloMansanet
030de46e6b Fix recursive macro crash and empty macro lockout (#2902) 2022-06-28 21:30:27 +09:00
dependabot[bot]
ac1d8fa505 build(deps): bump smallvec from 1.8.0 to 1.8.1 (#2901)
Bumps [smallvec](https://github.com/servo/rust-smallvec) from 1.8.0 to 1.8.1.
- [Release notes](https://github.com/servo/rust-smallvec/releases)
- [Commits](https://github.com/servo/rust-smallvec/compare/v1.8.0...v1.8.1)

---
updated-dependencies:
- dependency-name: smallvec
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-28 19:36:38 +09:00
dependabot[bot]
d900b8bb23 build(deps): bump thiserror from 1.0.30 to 1.0.31 (#2899)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.30 to 1.0.31.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/1.0.30...1.0.31)

---
updated-dependencies:
- dependency-name: thiserror
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-28 19:36:28 +09:00
dependabot[bot]
247ebd6689 build(deps): bump indoc from 1.0.3 to 1.0.6 (#2898)
Bumps [indoc](https://github.com/dtolnay/indoc) from 1.0.3 to 1.0.6.
- [Release notes](https://github.com/dtolnay/indoc/releases)
- [Commits](https://github.com/dtolnay/indoc/compare/1.0.3...1.0.6)

---
updated-dependencies:
- dependency-name: indoc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-28 18:25:17 +09:00
dependabot[bot]
2963fdbed1 build(deps): bump cc from 1.0.72 to 1.0.73 (#2897)
Bumps [cc](https://github.com/alexcrichton/cc-rs) from 1.0.72 to 1.0.73.
- [Release notes](https://github.com/alexcrichton/cc-rs/releases)
- [Commits](https://github.com/alexcrichton/cc-rs/compare/1.0.72...1.0.73)

---
updated-dependencies:
- dependency-name: cc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-28 18:25:08 +09:00
Michael Davis
64de0b7288 add docs for cursorline scopes (#2904) 2022-06-28 08:55:09 +05:30
Michael Davis
64cf4c859b support Bazel languages (#2903) 2022-06-28 08:48:38 +05:30
dependabot[bot]
6f932375bf build(deps): bump serde_json from 1.0.79 to 1.0.81 (#2896)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.79 to 1.0.81.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.79...v1.0.81)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-28 07:55:25 +08:00
dependabot[bot]
fd644ccfa2 build(deps): bump tree-sitter from 0.20.4 to 0.20.8 (#2895)
Bumps [tree-sitter](https://github.com/tree-sitter/tree-sitter) from 0.20.4 to 0.20.8.
- [Release notes](https://github.com/tree-sitter/tree-sitter/releases)
- [Commits](https://github.com/tree-sitter/tree-sitter/commits)

---
updated-dependencies:
- dependency-name: tree-sitter
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-28 07:52:27 +08:00
Gokul Soumya
3108a11d35 Refactor handling of mouse events (#2893)
- Simplified match statements by destructuring MouseEvent struct
  at the top and then matching on event.kind.
- Extracted out closures for calculating (1) position and view
  of mouse click and (2) gutter coordinates and view of mouse click.
2022-06-28 01:05:07 +09:00
Gokul Soumya
23ce5f1837 Add cursorline scope for onedark theme (#2892) 2022-06-27 17:36:41 +02:00
ramojus
db2aa57074 update meliora theme (#2890) 2022-06-27 07:49:09 -05:00
lazytanuki
096abdd19b feat: highlight / select symbol under cursor using LSP textDocument/documentHighlight (#2738)
* feat: highlight symbol under cursor using LSP textDocument/documentHighlight

* fix: please clippy

* fix: shorter description and code style
2022-06-27 20:19:56 +09:00
Blaž Hrastnik
fde9e034d4 Only draw cursorline in the currently focused buffer 2022-06-27 17:51:22 +09:00
Blaž Hrastnik
425de09d21 Fix tests again 2022-06-27 17:35:23 +09:00
Blaž Hrastnik
24f03097e3 Remove some more unwraps 2022-06-27 17:27:44 +09:00
Blaž Hrastnik
33d287a9ad Add a default cursorline style for the primary selection 2022-06-27 17:27:24 +09:00
Tobias Menzi
8dc86beabd Implement cursorline (#2170)
* Implement cursorline

* Binary search possible lines
2022-06-27 17:09:34 +09:00
Gokul Soumya
a26943de4e Right align scrollbar with track in completion popup (#2754)
- Align the scollbar to the right edge of the popup rather than at
  a margin of one.
- Add a scrollbar track and a new scope `ui.menu.scroll`.
2022-06-27 16:52:31 +09:00
Ramojus
c113531db9 add meliora theme (#2884) 2022-06-26 23:40:08 -05:00
Kihaya Sugiura
24351c20d4 languages: Fix ruby rakefile and gemfile file type (#2875) 2022-06-26 12:04:53 -05:00
Gokul Soumya
16ccc7ead8 Add single width left margin for completion popup (#2728)
* Add single width left margin for completion popup

* Clear with ui.menu style before rendering menu

When rendering a completion popup, the popup component will clear
the area with ui.popup and then the menu component would draw over
it using a table component. We remove the left edge of the area
before passing it to the table component (so that it will be left
as padding), and the table component uses ui.menu as the style.
If ui.menu and ui.popup are different the left edge of the popup
will look different from the rest of the popup. We avoid this by
clearing the whole area with ui.menu in Menu::render
2022-06-26 17:56:35 +09:00
Amit Beka
ba85779902 book: fix the description of dot repeat (#2878)
Co-authored-by: amitbeka <--->
2022-06-25 15:28:26 -05:00
Triton171
e1b1a5ebc0 Fix edge-case in tree-sitter expand_selection selection command (#2877)
Co-authored-by: Triton171 <triton0171@gmail.com>
2022-06-25 13:12:30 -05:00
two-six
18435899b2 [Theme] Acme (#2876) 2022-06-25 12:09:04 -05:00
Hekno25
33e6df8707 feat: add wgsl_analyzer as wgsl language server (#2872) 2022-06-24 16:21:26 -05:00
Saber Haj Rabiee
3dbad0442f fixes showing the last prompt on empty input (#2870) 2022-06-24 17:14:48 +02:00
Michael Davis
d948ace67b check selection's visible width when copying on mouse click (#2711)
* check selection's visible width when copying on mouse click

Mouse-click-up copies the selection produced by dragging. The event
is ignored if the selection has a width of 1 though so you don't
copy when clicking rather than dragging. The current check copies
text when it has a visible width of 1 but is actually multiple
characters in the rope like a CRLF line-ending. With this change
we check the unicode width of the character(s) in the selection
rather than the range length, so clicking on a CRLF line-ending
does not copy.

* use range.fragment to simplify getting the primary selection width
2022-06-24 22:58:04 +09:00
farwyler
886cff3bcc Redetect indent and line endings after language server replaces documents (#2778)
* redetect indent and line endings after language server replaces document

* removes nested if

* always redetect indent and line endings after format

This reverts commit 764d14f55894dc7213e48022dfa0f91829b8ef59.
2022-06-24 22:56:18 +09:00
Seth Bromberger
c107f4ea49 fixes #2856 by resetting style on diagnostic (#2861) 2022-06-22 20:53:36 +02:00
Gokul Soumya
301065fe4d Fix scrollbar length proportional to total menu items (#2860)
The scrollbar length used to increase with more entries in the menu,
which was counter-intuitive to how scrollbars worked in most
applications. Turns out there was a typo in the floor division
implementation :)
2022-06-23 03:00:12 +09:00
Erin van der Veen
b365f2d614 update tree-sitter-nickel to include ' in ident (#2859)
see https://github.com/nickel-lang/tree-sitter-nickel/pull/9
and  https://github.com/tweag/nickel/pull/737
2022-06-22 20:01:54 +09:00
Yusuf Bera Ertan
8c86cd56cb build(nix): update flake deps, add default.nix file 2022-06-21 17:39:30 -05:00
dependabot[bot]
5b3b6ffc9e build(deps): bump regex from 1.5.4 to 1.5.5 (#2851)
Bumps [regex](https://github.com/rust-lang/regex) from 1.5.4 to 1.5.5.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.5.4...1.5.5)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-22 03:42:22 +09:00
Blaž Hrastnik
23b5b1e25a Remove a couple more unwraps 2022-06-22 02:26:24 +09:00
Blaž Hrastnik
19dccade7c Merge pull request #2359 from dead10ck/test-harness
Integration testing harness
2022-06-21 18:59:02 +02:00
Termina94
a17626a822 add history suggest to global search (#2717)
Co-authored-by: Dean Revell <revell@gmail.com>
2022-06-22 01:52:25 +09:00
Gokul Soumya
8e8367eea6 Refactor Margin for fine grained control (#2727) 2022-06-22 01:52:08 +09:00
ath3
ce85b9716d Enable shellwords for Windows (with escaping disabled) (#2767) 2022-06-22 01:48:01 +09:00
Gokul Soumya
8b67acf130 Format keys identically in statusline and command palette (#2790)
The command palette previously used + as a delimiter for denoting
a single key in a key sequence, (like C+w). This was at odds with
how the statusline displayed them with pending keys (like <C-w>).
This patch changes the palette formatting to the statusline formatting
2022-06-22 01:46:50 +09:00
Gokul Soumya
8ad0b83e30 Make indent guides configurable 2022-06-21 18:43:25 +02:00
Gokul Soumya
924b4ebb39 Add theme scopes for indent guides 2022-06-21 18:43:25 +02:00
Gokul Soumya
8c4c923e80 Add indent guides support 2022-06-21 18:43:25 +02:00
Blaž Hrastnik
458b89e21d Merge branch 'master' into test-harness 2022-06-21 18:38:21 +02:00
Matthew Toohey
6a3f7f2c39 feat: make move_vertically aware of tabs and wide characters (#2620)
* feat: make `move_vertically` aware of tabs and wide characters

* refactor: replace unnecessary checked_sub with comparison

* refactor: leave pos_at_coords unchanged and introduce separate pos_at_visual_coords

* style: include comment to explain `pos_at_visual_coords` breaking condition

* refactor: use `pos_at_visual_coords` in `text_pos_at_screen_coords`

* feat: make `copy_selection_on_line` aware of wide characters
2022-06-22 01:36:36 +09:00
Mathspy
fa4934cff9 Default rulers color to red (#2669)
* Default rulers color to red

Currently if the theme a user is using doesn't have `ui.virtual.rulers`
set and they set up a ruler it just fails silently making it really hard
to figure out what went wrong. Did they set incorrectly set the ruler?
Are they using an outdated version of Helix that doesn't support rulers?

This happened to me today, I even switched to the default theme with
the assumption that maybe my theme just doesn't have the rulers setup
properly and it still didn't work.

Not sure if this is a good idea or not, feel free to suggest better
alternatives!

* Use builtin Style methods instead of Bevy style defaults

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>

* Only default the style if there's no ui or ui.virtual

* Update themes style from ui.virtual to ui.virtual.whitespace

* Revert ui.virtual change in onelight theme

* Prefer unwrap_or_else

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-06-22 01:35:25 +09:00
Michael Davis
9f676dab57 add test textobjects queries for erlang,gleam,go,python,rust 2022-06-21 11:32:03 -05:00
Connor Lay (Clay)
67f6c85792 text-objects: add test capture & elixir queries 2022-06-21 11:32:03 -05:00
A-Walrus
43027d9104 Display highest severity diagnostic in gutter (#2835)
* Display highest severity diagnostic in gutter

* Improve gutter diagnostic performance

Very slight improvement (doesn't really make a difference), iterates over the diagnostics of the line
once instead of twice.

* Add comment justifying unwrap
2022-06-21 08:09:43 +05:30
dependabot[bot]
009f8c4d3b build(deps): bump anyhow from 1.0.57 to 1.0.58 (#2843)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.57 to 1.0.58.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.57...1.0.58)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-21 08:08:45 +05:30
Michael Davis
0ad10ce6f7 rewrite language configuration docs (#2838)
This change moves the configuration tables from the Adding
Languages guide into the overall Languages section. It also
adds more detailed documentation on the `language-server`
configuration key and fixes a typo in the "mylang" example
(the scope was `scope.mylang` instead of `source.mylang`).
2022-06-21 01:15:50 +02:00
Mathis Brossier
8c64c3dfa3 mouse selection now uses character indexing (#2839) 2022-06-20 20:41:34 +02:00
farwyler
cad4e03a00 adds missing tree-sitter-comment injection for js/ts (#2763) 2022-06-20 10:55:51 -05:00
lazytanuki
55f4f69515 fix: do not color health summary when stdout is piped (#2836)
* fix: do not color health summary when stdout is piped

* fix: use crossterm instead of is-terminal
2022-06-20 17:07:32 +02:00
Joe
e2878a6e21 Add noctis bordo theme (#2830) 2022-06-20 09:21:21 -05:00
Skyler Hawthorne
5f7c247430 replace phrase in tests 2022-06-19 00:00:31 -04:00
Skyler Hawthorne
665286c199 factor new Application with file arg to function 2022-06-19 00:00:31 -04:00
Skyler Hawthorne
65bf6836b7 update docs for integration tests 2022-06-19 00:00:31 -04:00
Skyler Hawthorne
086b63ab1b add integration-test cargo alias 2022-06-18 23:57:47 -04:00
Skyler Hawthorne
41bf1d5811 fix(command): write-quit: do not quit if write fails
During write-quit, if the file fails to be written for any reason, helix
will still quit without saving the changes. This fixes this behavior by
introducing fallibility to the asynchronous job queues. This will also
benefit all contexts which may depend on these job queues.

Fixes #1575
2022-06-18 23:57:47 -04:00
Skyler Hawthorne
fac36bc5ea add test for write-quit happy path 2022-06-18 23:57:47 -04:00
Skyler Hawthorne
7c0bca186c rename test helpers 2022-06-18 23:57:47 -04:00
Skyler Hawthorne
526c9be8ca consolidate idle timer logic, make conditional 2022-06-18 23:57:47 -04:00
Skyler Hawthorne
374724f5ac ignore failing write path tests until fixes are merged 2022-06-18 23:57:47 -04:00
Skyler Hawthorne
8d8d389536 rename top level module to satisfy cargo fmt 2022-06-18 23:57:47 -04:00
Skyler Hawthorne
acf931709a use a read only file to ensure write failure 2022-06-18 23:57:47 -04:00
Skyler Hawthorne
ef8fe5a5ce use system's appropriate line ending 2022-06-18 23:57:47 -04:00
Skyler Hawthorne
28e94fb261 need the full languages config for integration tests 2022-06-18 23:57:47 -04:00
Skyler Hawthorne
4e34ee7d2e don't read from stdin for integration tests 2022-06-18 23:57:47 -04:00
Skyler Hawthorne
cb0440be85 use env var for integration test log level 2022-06-18 23:57:47 -04:00
Skyler Hawthorne
652cdda833 use test terminal backend for integration tests 2022-06-18 23:57:47 -04:00
Skyler Hawthorne
ed950fcc56 Add more context; Editor::open doesn't need to own path 2022-06-18 23:57:45 -04:00
Skyler Hawthorne
1533f48934 use Results in integration tests for more error context 2022-06-18 23:54:03 -04:00
Skyler Hawthorne
2fbf833630 add integration feature to github tests 2022-06-18 23:54:03 -04:00
Skyler Hawthorne
2386c81ebc use idle timer instead of fixed timeout 2022-06-18 23:54:03 -04:00
Skyler Hawthorne
40120967e9 tests for buffer-close 2022-06-18 23:54:03 -04:00
Skyler Hawthorne
07fc80aece tests for serialized writes 2022-06-18 23:54:03 -04:00
Skyler Hawthorne
ee705dcb33 use main application event loop
Use the Application's main event loop to allow LSP, file writes, etc
2022-06-18 23:54:03 -04:00
Skyler Hawthorne
36e5809f63 add test for ensuring the initial cursor on a newly opened file 2022-06-18 23:54:03 -04:00
Skyler Hawthorne
267605d147 reorganize tests into groups 2022-06-18 23:54:03 -04:00
Skyler Hawthorne
84bbe6b8f3 refactor helpers, use new test helpers 2022-06-18 23:54:03 -04:00
Skyler Hawthorne
0f3c10a021 Fix initial selection of Document in new view
When a new View of a Document is created, a default cursor of 0, 0 is
created, and it does not get normalized to a single width cursor until
at least one movement of the cursor happens. This appears to have no
practical negative effect that I could find, but it makes tests difficult
to work with, since the initial selection is not what you expect it to be.

This changes the initial selection of a new View to be the width of the
first grapheme in the text.
2022-06-18 23:54:03 -04:00
Skyler Hawthorne
502d3290fb improve test harness
* Use new macro syntax for encoding sequences of keys
* Make convenience helpers for common test pattern
* Use indoc for inline indented raw strings
* Add feature flag for integration testing to disable rendering
2022-06-18 23:54:03 -04:00
Blaž Hrastnik
308cab3e5c Integration testing harness 2022-06-18 23:54:03 -04:00
Blaž Hrastnik
adb6cd5376 Simplify handle_terminal_events signature 2022-06-18 23:54:03 -04:00
Skyler Hawthorne
0623a72599 move config parsing back into main 2022-06-18 23:54:03 -04:00
A-Walrus
ad15e7b5e8 Add "<<=" operator to Rust syntax highlighting (#2805) 2022-06-18 11:44:21 -05:00
Michael Davis
45ce1ebdb6 embed jsonrpc types from jsonrpc-core crate (#2801)
We should not depend on jsonrpc-core anymore:

* The project just announced it's no longer actively maintained[^1],
  preferring their new implementation in `jsonrpsee`.
* The types are too strict: we would benefit from removing some
  `#[serde(deny_unknown_fields)]` annotations to allow language
  servers that disrespect the spec[^2].
* We don't use much of the project. Just the types out of core.
  These are easy to embed directly into the `helix-lsp` crate.

[^1]: https://github.com/paritytech/jsonrpc/pull/674
[^2]: https://github.com/helix-editor/helix/issues/2786
2022-06-18 12:59:57 +09:00
Clay
b13e534b92 HEEx: upgrade version and support new special_attribute node (#2800) 2022-06-17 17:30:28 -05:00
Henry
15807d5f27 simplify some keymap key names follow up tests (#2694) 2022-06-17 09:51:45 -05:00
Grenier Célestin
33ea3eff05 Update theme base16_default (ui.menu) (#2794) 2022-06-17 20:24:18 +09:00
nosa
21d12e1487 Restore section spacing in tutor. (#2791) 2022-06-16 17:28:55 -05:00
Gygaxis Vainhardt
debd2405d9 views -> buffers in write-all (#2788) 2022-06-16 16:09:30 -05:00
Axot
4d604d3b50 Add clojure language support (#2780)
Co-authored-by: Mateusz Ledwoń <mateusz.ledwon@iteo.com>
2022-06-16 11:47:52 -05:00
nosa
3b1866f959 update tutor (#2716)
* update tutor

* Capitalize "command mode ".

* Update runtime/tutor.txt

Editing mistake.

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-06-15 15:31:26 -05:00
Bjorn Ove Hay Andersen
794576a5b0 Update auto-pairs and idle-timeout when the config is reloaded (#2736) 2022-06-15 22:59:58 +05:30
Tennix
11dadab371 Add migrate from Vim wiki link (#2781) 2022-06-15 11:04:17 -05:00
Frojdholm
402f285ba5 Improve markdown list rendering (#2687)
* Cleanup old commented code

* Implement line breaks in markdown rendering

* Implement markdown nested, numbered and multiparagraph lists
2022-06-15 13:20:19 +09:00
Roland Kovacs
c2cc2037b5 Better handling of symlinks (#2718)
- Add file-picker.follow-symlinks configuration option (default is true), this
  also controls if filename and directory completers follow symlinks.

- Update FilePicker to set editor error if opening a file fails, instead of
  panicing.

Fix #1548
Fix #2246
2022-06-15 13:17:17 +09:00
Anton Romanov
7983c71752 Introduce storage_class highlight scope (#2731) 2022-06-14 12:35:36 -05:00
Michael Davis
cdeab337cd simplify fallback for selected line-number theming (#2768) 2022-06-14 21:40:38 +05:30
Ryang Sohn
3bd5545577 Add a check to prevent re-selecting same range (#2760) 2022-06-14 08:37:40 -05:00
Kappa
d7bd441675 Cleanup for runtime/tutor.txt (#2590) 2022-06-13 23:12:13 +08:00
Bjorn Ove Hay Andersen
3b2d4031f1 Clarified the text in chapter 3 of the tutor (#2735)
* Clarified the text in chapter 3 of the tutor (#2725)

* Adjusted section 3.1 to better show how C works
2022-06-13 09:00:40 -05:00
Jonas Tepe
a766b32ed1 Expand chapter one recap of tutor
This add the missing variant of entering insert mode
to the chapter 1 recap section.
2022-06-12 14:12:52 -05:00
Ivan
0bc7259672 add prisma tree-sitter and lsp support (#2703)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-06-12 14:08:51 -05:00
Gokul Soumya
e9283b20b4 Add docstring for language_server!() macro (#2750) 2022-06-12 09:53:58 +09:00
Gokul Soumya
0b8a00ac96 Refactor textobject node capture (#2741) 2022-06-12 00:39:21 +09:00
Daniel Hines
9b9c3e5ae2 add rust-analyzer to shell environment (#2739) 2022-06-11 17:23:18 +09:00
Clay
f37ffaa3a1 elixirLS disable dialyzer by default (#2710)
Not all Elixir projects use dialyzer and it can cause the editor
to slow down quite a bit on large projects if the PLT is not built.

See https://github.com/elixir-lsp/elixir-ls#dialyzer-integration=
2022-06-10 10:45:17 +09:00
Danny
567e71fbbc fix spelling of catppuccin theme (#2713) 2022-06-08 23:33:26 +05:30
Frojdholm
e0532771cc Do not add extra line breaks in markdown lists (#2689) 2022-06-08 09:44:07 +09:00
Michael Davis
4a27e2d938 capture rust closures as function textobjects
Closures like

    iter.map(|a| a + 1)

Are sort-of functions, so `]f` or `maf` or `mif` can apply to them
as well as named function definitions.
2022-06-07 20:03:31 +09:00
Michael Davis
f7a3d35752 add textobject queries for gleam 2022-06-07 20:03:31 +09:00
Michael Davis
bcafdf404f add textobject queries for elixir 2022-06-07 20:03:31 +09:00
Michael Davis
7a9147489e add textobject queries for erlang 2022-06-07 20:03:31 +09:00
dependabot[bot]
9f8df05d96 build(deps): bump tokio-stream from 0.1.8 to 0.1.9 (#2690)
Bumps [tokio-stream](https://github.com/tokio-rs/tokio) from 0.1.8 to 0.1.9.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-stream-0.1.8...tokio-stream-0.1.9)

---
updated-dependencies:
- dependency-name: tokio-stream
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-07 14:51:36 +09:00
dependabot[bot]
5c7d9d6027 build(deps): bump tokio from 1.18.2 to 1.19.2 (#2691)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.18.2 to 1.19.2.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/commits)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-07 11:10:00 +05:30
Yusuf Bera Ertan
bb83ea8393 chore(nix): format nix files with alejandra, update deps, minor code refactors (#2683) 2022-06-06 14:24:52 -05:00
farwyler
f0d1c85553 support for openscad (#2680)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-06-06 12:26:56 -05:00
Blaž Hrastnik
26dbdb70fb Refactor push_jump so we're not needlessly fetching doc twice 2022-06-07 00:23:41 +09:00
Blaž Hrastnik
3d9923969a minor: Simplify Document.language_id() 2022-06-07 00:23:41 +09:00
Blaž Hrastnik
b14c258a2c prompt: If submitting empty prompt, use default (last used) 2022-06-07 00:23:40 +09:00
Henry
8351a82c2c simplify some keymap key names (#2677) 2022-06-05 21:22:10 -05:00
Michael Davis
0035c29fc1 Use a minimal binary to fetch grammar sources in release CI (#2557)
This is an optimization for the release CI. The release CI can take
a while since it compiles release builds for all operating systems.
We cut down on duplicate work and overall time by fetching
tree-sitter grammar repositories and then using those repositories
in all later steps. Previously we built all of helix just to run

    helix_loader::grammar::fetch_grammars()

which is wasteful on time. With this change we only build the
helix-loader crate.
2022-06-05 19:53:20 +09:00
Termina94
f1ae496860 Add shell insert commands to typable and config (#2589)
* Add shell insert commands to typable and config

* generate docs

Co-authored-by: Dean Revell <revell@gmail.com>
2022-06-05 19:52:41 +09:00
farwyler
f92a25a856 Passing extra formatting options to LSPs (#2635)
* allows passing extra formatting options to LSPs

- adds optional field 'format' to [[language]] sections in 'languages.toml'

- passes specified options the LSPs via FormattingOptions

* cleaner conversion of formatting properties

* move formatting options inside lsp::Client

* cleans up formatting properties merge
2022-06-05 19:50:57 +09:00
gavynriebau
b2bd87df81 Fix crash due to cycles when replaying macros (#2647)
In certain circumstances it was possible to get into an infinite loop
when replaying macros such as when different macros attempt to replay
each other.

This commit adds changes to track which macros are currently being
replayed and prevent getting into infinite loops.
2022-06-05 19:49:41 +09:00
Michael Davis
1c2aaf3baf ensure :quit and :quit! take no arguments (#2654) 2022-06-05 19:48:16 +09:00
yzwduck
d24ca66dbb Avoid modifying jumplist until jumping to ref (#2670)
When a goto command is cancelled, the jumplist should remain unchanged.

This commit delays saving the current selection to the jumplist until
jumping to a reference.
2022-06-05 19:44:55 +09:00
gavynriebau
026241cf72 Fix panic on close last buffer (#2367) (#2658)
* Fix panic on close last buffer (#2367)

In certain circumstances it was possible to cause a panic when closing
buffers due to some mishandling of view document history.

A change has been made to delete removed documents from the history of
accessed documents for each view. The ensures we don't attempt to jump
to a deleted document by mistake.

* Move remove document code into View function 'remove_document'

* Replace 'view.jumps.remove' call with 'view.remove_document' call
2022-06-05 11:27:41 +09:00
nosa
5b4e0a304b Update selection style of Night Owl (#2668) 2022-06-04 10:40:39 +05:30
nosa
dfd0754394 Update keymap docs for window swapping (#2659) 2022-06-03 07:09:35 -05:00
Michael Davis
fd4858c03d add tree-sitter-jsdoc (#2650) 2022-06-03 10:26:47 +05:30
Michael Davis
42d780b103 add tree-sitter-edoc (#2640)
* add tree-sitter-edoc

* fix escape character capture in markdown queries

* add field negation operator "!" to tsq highlights
2022-06-03 07:41:17 +08:00
Kirawi
4f3d0a7706 append set_line_ending to document history (#2649) 2022-06-02 10:46:53 -05:00
Frojdholm
f7c27b604f Ignore SendErrors when handling grammars (#2641)
When handling grammars, fetching and building is done in a thread
pool.  Results are communicated over channels and the receiving
channel is closed on first error. This causes subsequent sends to
fail causing a mess in stderr. This ignores all SendErrors causing
only the first error to be printed.
2022-06-02 16:54:11 +09:00
Blaž Hrastnik
378f438fb0 fix: lsp: be more defensive about URI conversions 2022-06-02 14:07:19 +09:00
Blaž Hrastnik
6de6a3edbb fix: lsp: be more defensive about URI conversions 2022-06-02 14:07:19 +09:00
Blaž Hrastnik
3d91c99c3e fix: lsp: Sort edits by start range, Omnisharp sends them in reverse 2022-06-02 14:07:19 +09:00
Michael Zeller
99e08f50bd catpuccin ui.popup should be a different color from ui.background (#2644) 2022-06-01 16:11:58 -05:00
Fanda Vacek
8d4c954060 CPON parser supports unsigned int (#2643)
Co-authored-by: Fanda Vacek <fvacek@elektroline.cz>
2022-06-01 15:11:14 -05:00
Ryan Russell
ae12c58f0f Improve Readability (#2639) 2022-06-01 12:01:37 -05:00
Ben Lee-Cohen
fc666db6b9 Solarized Light: Fixing menu colors and adding English translation (#2626) 2022-05-31 10:15:32 -05:00
Andrey Tkachenko
fa2eeccc57 Fix unwrap error when undo after shell_append_output (#2625) 2022-05-31 23:08:16 +09:00
Clay
fc8c488322 Elixir: inject Markdown into docs, remove h sigil HEEx injection (#2619)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-05-30 21:32:14 -05:00
Timothy DeHerrera
eba82250bb feat(lang): Update Nix grammar & improve queries (#2472) 2022-05-30 13:47:18 -05:00
Blaž Hrastnik
370a16d0f0 Update to ropey 1.5 2022-05-30 12:29:07 +09:00
Blaž Hrastnik
5ed6223990 fix: Remove empty scratch buffer from jumplists when removing it
Fixes #1238
2022-05-30 01:22:17 +09:00
Paul Graydon
710c4a84b2 Adjust colors in tokyonight themes (#2606) 2022-05-29 10:56:10 -05:00
Michael Zeller
b43074dad3 illumos linker doesn't currently have -z relro (#2602) 2022-05-29 10:52:48 -05:00
Marcin Puc
cd4622db9b Update from-source install instruction in README (#2603) 2022-05-29 10:52:26 -05:00
Hugo
89c6e8aa94 Remove unnecessary unwrap (#2599)
`strip_prefix` will itself check whether the string starts with the
prefix, so the extra call to `starts_with` was unnecessary.
2022-05-29 11:13:21 +09:00
Blaž Hrastnik
10415a8069 Bump dependencies, allow retain_mut for now 2022-05-29 11:10:49 +09:00
Michael Davis
93e6eac15a mention the C++ compiler in the grammar build failure message (#2597)
Earlier in the builder we enable C++ (`.cpp(true)`) but only mention
the C compiler in the build failure message. Some grammars that have
C++ external scanners can provoke build failures in this step if a
C++ compiler isn't installed, so mentioning it in the error message
should help out debugging.
2022-05-29 11:06:31 +09:00
pancake
7706a4a0d8 Add Vlang tree-sitter in the languages.toml (#2526)
Co-authored-by: pancake <pancake@nopcode.org>
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-05-28 14:46:10 -05:00
booklearner
7c107d0d3a Fix link to pop-dark in CHANGELOG.md (#2594) 2022-05-28 13:11:31 -05:00
Blaž Hrastnik
27609f5065 Fix the VERSION file 2022-05-29 01:07:30 +09:00
nitish-17
b31788102e mention the requirement of C++ compiler for building grammar in doc (#2592) 2022-05-28 11:02:47 -05:00
Blaž Hrastnik
a106341fd7 Fix release action 2022-05-28 23:23:08 +09:00
Michael Davis
46f9320709 add 22.05 changelog notes (#2584) 2022-05-28 09:18:15 -05:00
Michael Davis
efae76160d add section on syntax tree motions to the usage docs (#2568) 2022-05-26 10:39:58 +09:00
Ben Lee-Cohen
7160e745f7 Changing Macro color to avoid color confusion
I noticed that in Rust, `println!`being a macro, it matched the color of string literals. This was visually confusing to me, so I checked what the nvim catpuccin theme (https://github.com/catppuccin/nvim) does. While it is pretty different, it does use different colors for strings and all function types: https://share.cleanshot.com/RLG2y1

I don't know if blue or red makes more sense given the other syntax choices, but wanted to propose this change cc @IsotoxalDev
2022-05-25 09:54:20 -05:00
Michael Davis
82da9bd4f2 update Erlang grammar and queries
The update to the grammar itself covers the case where the document
is a single expression without a trailing newline such as "min(A, B)".
A small change to the parser now parses these expressions correctly
which improves the display of the function head in the signature
help popup.

The update to the queries marks 'andalso', 'orelse', 'not', etc. as
`@keyword.operator` which improves the look - it looks odd to see
operators that are words highlighted the same as tokens like '->'
or '=:='.
2022-05-25 21:26:26 +09:00
Michael Davis
45dd54082e update Gleam grammar and queries
With respect to the queries:

The locals scope for functions was not large enough, so a function's
parameter could outlive the function body. To fix it, we just widen
the scope to the `function` node.

See also https://github.com/gleam-lang/tree-sitter-gleam/issues/25

With respect to the parser:

An external scanner has been added that fixes the parsing of strings.
Previously, a comment inside a string would act like a comment rather
than string contents.

See also https://github.com/gleam-lang/tree-sitter-gleam/issues/14#issuecomment-1129263640

A new constructor node has been added as well which makes type
highlighting more fine grained.

See also https://github.com/gleam-lang/tree-sitter-gleam/pull/29
2022-05-25 21:26:26 +09:00
Andrey Tkachenko
10463fe32c Add parameter.around text object query 2022-05-25 21:26:06 +09:00
dependabot[bot]
da29527258 build(deps): bump once_cell from 1.10.0 to 1.12.0
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.10.0 to 1.12.0.
- [Release notes](https://github.com/matklad/once_cell/releases)
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.10.0...v1.12.0)

---
updated-dependencies:
- dependency-name: once_cell
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-25 21:25:47 +09:00
dependabot[bot]
a13ff27023 build(deps): bump regex from 1.5.5 to 1.5.6
Bumps [regex](https://github.com/rust-lang/regex) from 1.5.5 to 1.5.6.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.5.5...1.5.6)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-25 21:25:34 +09:00
Andrey Tkachenko
67fe16008e Basic verilog support (#2552) 2022-05-24 12:52:32 -05:00
Erasin
386dccc84e Add lua lsp (#2560) 2022-05-24 10:03:53 -05:00
Isotoxal
c429ed660f Add Catppuccin Theme (#2546)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-05-24 09:02:26 -05:00
Blaž Hrastnik
d6865cdca3 nix: bump dependencies 2022-05-24 09:37:17 +09:00
Michael Davis
89c0998aee lower MSRV to 1.57.0
This line uses the Display trait for io::ErrorKind which was
stabilized in Rust 1.60.0. We can set MSRV all the way back to
1.57.0 by replacing it with a pretty-print.

Closes #2460.
2022-05-24 01:05:19 +09:00
Michael Davis
92df5a5425 check MSRV in CI
It's very easy to use new rust features without realizing it since
the CI and local development workflows may use the latest rust version.
We try to keep some backwards compatibility with rust versions to make
packaging easier for some OS-level package-managers like Void Linux's.
See #1881.

This change runs the "Check" step for the pinned version of rust in
the rust-toolchain.toml file as well as the MSRV version in a matrix.
In order to bump the MSRV, we need to edit

    .github/workflows/msrv-rust-toolchain.toml

This commit sets the MSRV as 1.60.0 but a later child commit will
reduce the MSRV back to 1.57.0.

Closes #2482.
2022-05-24 01:05:19 +09:00
Michael Davis
aa87adf54b pin the rust toolchain to 1.61.0
1.61.0 in particular introduced new clippy lints that unexpectedly
failed CI until addressed. The lints are a bit tough to fix since
the toolchain action starts using new rust versions almost immediately
after release, so if you aren't using rustup, you may have a hard
time reproducing the lint results until your package manager updates
rust.

This brings an extra burden that we have to remember to make a
commit/PR to update rust in CI.
2022-05-24 01:05:19 +09:00
Michael Davis
f6531c9db0 inherit rust toolchain channel from rust-toolchain.toml
We've forked actions-rs/toolchain and merged
https://github.com/actions-rs/toolchain/pull/209
so we can take advantage of full support of `rust-toolchain.toml`.
Without that PR, the action fails because the `rustup` version
built into the runners by default is too old. #2528 covers switching
back to the upstream when it includes those changes.
2022-05-24 01:05:19 +09:00
Blaž Hrastnik
35303f749e Replace handwritten CI cache with Swatinem/rust-cache
The cache kept growing as dependencies kept changing and updating.
2022-05-23 13:48:00 +09:00
Jens Getreu
6801b28da0 Highlight active window in Autumn theme (#2531)
Co-authored-by: Jens Getreu <jens.getreu@dlh.lu>
2022-05-22 10:40:27 -05:00
Joel
682bcc3a32 fix: missing quotes around variable.other.member 2022-05-22 18:36:51 +09:00
Joel
0018545263 fix: remove duplicated ui.help in themes
the bottom value is used, so i've removed the top `ui.help` values from all themes

also, the values are not merged, so:

```toml
"ui.help" = { modifiers = ["reversed"] }
"ui.help" = { fg = "white", bg = "black" }
```

is equal to:

```toml
"ui.help" = { fg = "white", bg = "black" }
```
2022-05-22 18:36:51 +09:00
Daniel S Poulin
0c05447d49 Add shrink equivalent of extend_to_line_bounds (#2450)
* Add shrink equivalent of extend_to_line_bounds

* Add a check for being past rope end in end position calc

* Include the EOL character in calculations

* Bind to `A-x` for now

* Document new keybind
2022-05-22 10:33:11 +09:00
Ivan Tham
5bcb31a6df Make Borders u8 2022-05-22 10:26:32 +09:00
Ivan Tham
1837b5e4a6 Refactor Block with Default and bitflags
Specifying empty for bitflags is not recommended, it is now removed and added
Default. For BorderType, it now defaults to plain.
2022-05-22 10:26:32 +09:00
kyrime
bfc4ff4dcf Add theme key for picker separator (#2523)
Co-authored-by: ky <>
2022-05-22 10:24:51 +09:00
Leoi Hung Kin
5c864922d8 Fix panic when reloading a shrunk file (#2506)
* fix panic when reloading a shrunk file

* linting

* use scrolloff
2022-05-22 10:24:32 +09:00
Blaž Hrastnik
8df8ff27c2 cargo xtask docgen 2022-05-22 00:20:45 +09:00
Blaž Hrastnik
d25bae844c Add Scheme support
Skipped scm for now :/ it overlaps with tree-sitter-tsq
2022-05-22 00:01:07 +09:00
Roland Kovacs
6bd8924436 Move Tree nodes on view swap
Instead of moving the Node contents on view swap if they have the same parent
reorder them to keep traversal order otherwise re-parent them.
2022-05-21 08:53:16 -05:00
Roland Kovacs
3f10473d30 Implement view swapping
* add Tree::swap_split_in_direction()
* add swap_view_{left,down,up,right} commands, bound to H,J,K,L
  respectively in the Window menu(s)
* add test for view swapping
2022-05-21 08:53:16 -05:00
Jacob Thompson
e8e252648f Added a default lsp server for Java in languages.toml (#2511)
* Added a default lsp server for Java in languages.toml

* Added a default lsp server for Java in languages.toml cont.

Co-authored-by: Jacob Thompson <a01657923@usu.edu>
2022-05-20 15:17:46 +09:00
Michael Davis
e04bb8b891 address rust 1.61.0 clippy lints (#2514) 2022-05-20 12:16:11 +09:00
Christoph Horn
9be810fd01 add missing ui.menu to themes, fix issues with some themes 2022-05-20 10:32:59 +09:00
Christoph Horn
e7e13dcf06 add ui.menu to default theme 2022-05-20 10:32:59 +09:00
Christoph Horn
82fb217b6a use ui.menu instead of ui.statusline for command completion menu theme 2022-05-20 10:32:59 +09:00
Robert Walter
776686ab24 Separate colors for different diagnostics types (#2437)
* feat(theme): add separate diagnostic colors

This commit adds separate diagnostic highlight colors for the different
types of LSP severities. If the severity type doesn't exist or is
unknown, we use some fallback coloring which was in use before this
commit.

Some initial color options were also added in the theme.toml

Resolves issue #2157

* feat(theme): add docs for new diagnostic options

* feat(theme): adjust defaults & reduce redundancy

- the different colors for different diagnostic severities are now
  disabled in the default theme, instead diagnostics are just generally
  underlined (as prior to the changes of this feature)
- the theme querying is now done once instead of every iteration in the
  loop of processing every diagnostic message
2022-05-20 10:30:28 +09:00
Paul Scott
09f9f70576 Python highlight decorator attribute 2022-05-20 10:28:52 +09:00
Paul Scott
2a2030142f Python highlight keyword argument as parameter 2022-05-20 10:28:52 +09:00
Paul Scott
e680f9644d Python handling highlighting parameters with defaults 2022-05-20 10:28:52 +09:00
Paul Scott
abef250c58 Python highlight improvements: type, parameter etc
* str, list, etc. handled as @function.builtin and @type.builtin
* None and non-conforming type indentifiers as @type in type hints
* class identifiers treated as @type
* @constructor used for constructor definitions and calls rather than
  as a catch-all for type-like things
* Parameters highlighted
* self and cls as @variable.builtin
* improved decorator highlighting as part of @function

Re-ordering of some statements to give more accurate priority.
2022-05-20 10:28:52 +09:00
Zeddicus414
8e8d4ba27f dark_plus theme constructor should be green. 2022-05-20 10:28:52 +09:00
Zeddicus414
a6da99a144 Change python highlights.scm to more fully utilize the themes.
Create type keywords
Allow _CONSTANTS to start with _
Highlight constants before constructors
Move some keywords into @keyword.control
2022-05-20 10:28:52 +09:00
Bob
6462542fc5 support insert register in prompt (#2458)
* support insert register in prompt

* use next_char_handler instead of a flag

* Fix clippy issue

* show autoinfo when inserting register

* Revert "show autoinfo when inserting register"

This reverts commit 5488344de1.

* use completion instead of autoinfo

autoinfo is overlapped when using prompt

* recalculate_completion after inserting register

* Update helix-term/src/ui/prompt.rs

Co-authored-by: Ivan Tham <pickfire@riseup.net>

Co-authored-by: Ivan Tham <pickfire@riseup.net>
2022-05-20 10:27:59 +09:00
Roland Kovacs
8958bf0a92 Implement view transpose (#2461)
Change the layout of existing split view from horizontal to vertical and
vica-versa. It only effects the focused view and its siblings, i.e. not
recursive.

Command is mapped to 't' or 'C-t' under the Window menus.
2022-05-20 10:25:04 +09:00
Andrey Tkachenko
62fd1f6999 Include macro attributes to impls, structs, enums, functions etc. textobjects (#2494) 2022-05-20 10:19:46 +09:00
Alexis Kalabura
301ed9b48f deletion of lines affecting popup scrolling (#2497) 2022-05-20 10:18:19 +09:00
midnightexigent
8493b5fca6 Add tree-sitter ssh client config queries (#2498)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-05-18 14:49:50 -05:00
dependabot[bot]
29121a18b5 build(deps): bump signal-hook from 0.3.13 to 0.3.14 (#2485)
Bumps [signal-hook](https://github.com/vorner/signal-hook) from 0.3.13 to 0.3.14.
- [Release notes](https://github.com/vorner/signal-hook/releases)
- [Changelog](https://github.com/vorner/signal-hook/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vorner/signal-hook/compare/v0.3.13...v0.3.14)

---
updated-dependencies:
- dependency-name: signal-hook
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-17 14:45:43 +09:00
Michael Davis
50dd11985c prevent panic when handling an LSP response with no request (#2475)
A language server may push a response which doesn't belong to any
request. With this change, we discard the response rather than
crashing.

In the case of #2474, the language server sends an error message
with a null request ID which should not ever exist in the
`pending_requests` HashMap.

closes #2474
2022-05-17 14:45:34 +09:00
dependabot[bot]
0258cf45f3 build(deps): bump etcetera from 0.3.2 to 0.4.0 (#2486)
Bumps [etcetera](https://github.com/arzg/etcetera) from 0.3.2 to 0.4.0.
- [Release notes](https://github.com/arzg/etcetera/releases)
- [Commits](https://github.com/arzg/etcetera/commits)

---
updated-dependencies:
- dependency-name: etcetera
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-17 12:32:18 +09:00
Alexis Geoffrey
595213ca74 Change default Hare tab width to 8 (#2480) 2022-05-16 16:48:28 +09:00
Timothy DeHerrera
823eaad1a1 Add Snazzy theme (#2473) 2022-05-14 16:49:06 -05:00
spindlebink
af387e6873 Default to tabs instead of spaces for Odin files (#2464) 2022-05-12 08:23:38 -05:00
Blaž Hrastnik
7b287f636f nix: update flake dependencies 2022-05-11 11:02:40 +09:00
Blaž Hrastnik
7ae6cad52e Don't panic on LSP parsing errors
This made sense initially when the implementation was still new (so we
got user reports more frequently), but a parsing error now generally
signifies a language server isn't properly implementing the spec.
2022-05-11 11:00:55 +09:00
Blaž Hrastnik
8b1a03a178 Add FUNDING.yml 2022-05-11 10:51:20 +09:00
amaihoefner
a5bc69c2b5 feat(commands): add log-open command (#2422) 2022-05-11 10:18:45 +09:00
Ivan Tham
0477d02894 Exclude cursor when doing ctrl-w (#2431)
Currently ctrl-w in insert mode deletes the cursor which results in
unexpected behavior. The patch also reduces the selection to cursor before
performing prev word to remove the behavior of removing unnecessary text
when nothing should be removed.

1. `::#(|)#::` after `ctrl-w` should be `#(|)#::`, previously `#(|)#:`
2. `#(|::)#` after `ctrl-w` should be `#(|::)#`, previously `#(|)#`

Fix #2390
2022-05-11 10:12:27 +09:00
Alexis Kalabura
c80ac84978 Run debug console in windows (#2294) 2022-05-11 10:06:57 +09:00
unrelentingtech
2cb1ea7127 feat(lang): add Meson language support (#2314)
https://mesonbuild.com/Syntax.html
2022-05-11 10:06:37 +09:00
EmmChriss
807cdc60bf configurable lsp request timeout (#2405) 2022-05-11 09:54:35 +09:00
Michael Davis
247ab25bc0 prefer Document::set_selection to inserting selections directly (#2411)
Inserting these with the `HashMap::insert` method evades the call
to `Selection::ensure_invariants`. The effect is that the scratch
buffer (or other buffers opened through these code-paths) can start
with a selection at (0, 0), when a file with equivalent contents ("\n")
would start with (0, 1).

I.e.:

    hx

and

    touch f
    hx f

start with different selections even though they have an equivalent
Rope. With this change they both start with (0, 1).
2022-05-11 09:53:54 +09:00
Michael Davis
e0b5cdfb47 prevent selection collapse when inserting a newline (#2414)
Inserting a newline currently collapses any connected selections when inserting
or appending. It's happening because we're reducing the selections down to
their cursors (`let selection = ..` line) and then computing the new selection
based on the cursor. We're discarding the original head and anchor information
which are necessary to emulate Kakoune's behavior.

In Kakoune, inserting a newline retains the existing selection and _slides_
it (moves head and anchor by the same amount) forward by the newline and
indentation amount. Appending a newline extends the selection to include the
newline and any new indentation.

With the implementation of insert_newline here, we slide by adding the global
and local offsets to both head and anchor. We extend by adding the global
offset to both head and anchor but the local offset only to the head.
2022-05-11 09:53:43 +09:00
dependabot[bot]
40647f03ed build(deps): bump serde_json from 1.0.80 to 1.0.81 (#2447)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.80 to 1.0.81.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.80...v1.0.81)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-10 07:55:31 +08:00
dependabot[bot]
544a05dabf build(deps): bump tokio from 1.18.1 to 1.18.2 (#2448)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.18.1 to 1.18.2.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.18.1...tokio-1.18.2)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-10 07:55:01 +08:00
Yt
ae19aaf1a6 languages: add inc files to php (#2440) 2022-05-09 05:53:03 -05:00
Fanda Vacek
f3164c1174 Monokai pro spectrum theme shows error in yellow on red background (#2433)
Co-authored-by: Fanda Vacek <fvacek@elektroline.cz>
2022-05-08 13:16:29 -05:00
Fanda Vacek
76d55c0d9e Cpon support tree sitter version bumped (#2424)
Co-authored-by: Fanda Vacek <fvacek@elektroline.cz>
2022-05-07 06:47:15 -05:00
ChrHorn
b38c268097 fix Markdown list highlighting (#2401) 2022-05-07 11:26:34 +09:00
Robert Walter
495ba40eaf feat(languages): add odin language (#2399) 2022-05-05 12:09:09 -05:00
Ben Lee-Cohen
2f240b018e Adding the global gitignore to the default (#2410) 2022-05-05 10:58:18 -05:00
Matthew Toohey
a5f4925f53 feat(languages): git-ignore and git-attributes (#2397) 2022-05-05 08:47:28 -05:00
ChrHorn
fc61796895 TOML highlight: use variable.other.member instead of string for quoted keys (#2391) 2022-05-05 16:14:17 +09:00
Pavel Borzenkov
f1a77370cf feat(languages): detect 't' as perl (#2395) 2022-05-04 08:32:05 -05:00
ChrHorn
5ab669f1ac replace constant.number with constant.numeric (#2389) 2022-05-04 14:51:31 +09:00
Ben Lee-Cohen
09a17e4fa3 Making the 'set-option' command help more descriptive. (#2365)
* Making the 'set-option' command help more descriptive.

* Adding the generated docs

* Making the message multi-line

* Replace newline with break in generated docs
2022-05-04 11:17:08 +09:00
Michael Davis
f59b3b91c8 rewrite auto-pairs docs (#2384) 2022-05-04 11:16:34 +09:00
Matthew Toohey
25d128b5b3 feat(languages): detect cjs as javascript (#2387) 2022-05-03 20:55:40 -05:00
Johann Dahm
e529ca1b92 Fix build on aarch64-darwin (#1789)
Co-authored-by: Yusuf Bera Ertan <y.bera003.06@protonmail.com>
2022-05-03 17:32:44 -05:00
Matouš Dzivjak
d2b1add1f4 feat(term): wrap command palette in overlay (#2378)
Looks better and is consistent with the rest, nothing else.
2022-05-03 17:28:41 +09:00
dependabot[bot]
042463a4d1 build(deps): bump serde_json from 1.0.79 to 1.0.80 (#2376)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.79 to 1.0.80.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.79...v1.0.80)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-03 09:31:55 +09:00
dependabot[bot]
e418fae61b build(deps): bump serde from 1.0.136 to 1.0.137 (#2375)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.136 to 1.0.137.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.136...v1.0.137)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-03 09:31:34 +09:00
dependabot[bot]
0f1fce9af6 build(deps): bump log from 0.4.16 to 0.4.17 (#2374)
Bumps [log](https://github.com/rust-lang/log) from 0.4.16 to 0.4.17.
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/commits/0.4.17)

---
updated-dependencies:
- dependency-name: log
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-03 09:31:23 +09:00
dependabot[bot]
fc35791af9 build(deps): bump tokio from 1.17.0 to 1.18.1 (#2373)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.17.0 to 1.18.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.17.0...tokio-1.18.1)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-03 09:31:05 +09:00
dependabot[bot]
feea518300 build(deps): bump thiserror from 1.0.30 to 1.0.31 (#2372)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.30 to 1.0.31.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/1.0.30...1.0.31)

---
updated-dependencies:
- dependency-name: thiserror
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-03 09:30:46 +09:00
Robert Walter
fba198c1e0 Add documentation for hx --health (#2357) 2022-05-02 16:46:25 -05:00
AntonioLucibello
ac2ea800ce Add undo checkpoint command (#2115)
* added undo checkpoint command

* changed add_undo_checkpoint to commit_undo_checkpoint

* mapped commit_undo_checkpoint to Alt-u

* Update default.rs

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-05-02 23:45:20 +09:00
Kirawi
77ff8d3550 cfg-gate unused functions on macos & windows (#2332) 2022-05-02 23:31:23 +09:00
unrelentingtech
20162a426b feat(commands): make it possible to disable format-on-save via the 'auto-format' option (#2321) 2022-05-02 23:31:07 +09:00
Vince Mutolo
f9baced216 add reflow command (#2128)
* add reflow command

Users need to be able to hard-wrap text for many applications, including
comments in code, git commit messages, plaintext documentation, etc. It
often falls to the user to manually insert line breaks where appropriate
in order to hard-wrap text.

This commit introduces the "reflow" command (both in the TUI and core
library) to automatically hard-wrap selected text to a given number of
characters (defined by Unicode "extended grapheme clusters"). It handles
lines with a repeated prefix, such as comments ("//") and indentation.

* reflow: consider newlines to be word separators

* replace custom reflow impl with textwrap crate

* Sync reflow command docs with book

* reflow: add default max_line_len language setting

Co-authored-by: Vince Mutolo <vince@mutolo.org>
2022-05-02 23:24:22 +09:00
Roland Kovacs
567ddef388 Auto-complete directory members (#1801) (#1907)
Allow tab-completion to continue when there is only a single, unambigous
completion target which is a directory. This allows e.g. nested directories
to be quickly drilled down just by hitting <tab> instead of first selecting
the completion then hitting <enter>.
2022-05-02 23:18:41 +09:00
Ryosuke Hayashi
f85f0b7272 Add run-shell-command for Commands (#1682)
* add run_shell_command

* docgen

* fix command name

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>

* refactored Info::new

* show 'Command failed' if execution fails

* TypedCommand takes care of error handling and printing the error to the statusline.

* docgen

* use Popup instead of autoinfo

* remove to_string in format!

* Revert chage in info.rs

* Show "Command succeed" when success

* Fix info.rs

Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
2022-05-02 23:15:02 +09:00
Fanda Vacek
1668183590 feat(lang): Cpon lang support (#2355)
Co-authored-by: Fanda Vacek <fvacek@elektroline.cz>
2022-05-01 09:34:46 -05:00
Blaž Hrastnik
ede01b5f1e num_cpus apparently unused in helix-term 2022-05-01 11:40:04 +09:00
Blaž Hrastnik
ade4cbffaa Add a nop clipboard provider for wasm 2022-05-01 11:39:31 +09:00
Blaž Hrastnik
9191af3f8d helix-loader + helix-core now compile for WASM 2022-05-01 11:39:07 +09:00
Blaž Hrastnik
8bb89dafa2 cargo xtask docgen 2022-05-01 11:37:14 +09:00
Blaž Hrastnik
73879052c1 Add Cairo support 2022-05-01 11:24:17 +09:00
unrelentingtech
2c60798b00 feat(ui): add nbsp (non-breaking space) to rendered whitespace (#2322) 2022-04-30 09:48:52 +09:00
Michael Davis
e4c2618099 prevent rendering visible whitespace on trailing cursor (#2331) 2022-04-30 09:48:11 +09:00
unrelentingtech
2687b8fb3b feat(ui): treat slashes as word separators in prompt (#2315)
When fiddling with paths in a :o prompt, one usually would want Ctrl-W to erase a path segment
rather than the whole path. This is how Ctrl-W works in e.g. (neo)vim out of the box.
2022-04-30 09:46:51 +09:00
nosa
0106173375 Add Night Owl Color Theme. (#2330) 2022-04-29 17:27:09 -05:00
unrelentingtech
8e77e3388c feat(lang): add devicetree (Flattened Device Tree Source) (#2329) 2022-04-29 15:08:00 -05:00
unrelentingtech
030e7ab988 fix(docs): cleanup obsolete indents.toml mentions (#2327) 2022-04-29 12:40:59 -05:00
Erasin
668b39d1df change cursor for copy selection (#2323) 2022-04-29 11:11:36 -05:00
Yang Tang
667cdf929f Fix spelling errors in some themes (#2324) 2022-04-29 11:03:46 -05:00
Erin van der Veen
21487d13fd feat(lang): Update nickel to include "rec" keyword (#2320) 2022-04-29 07:34:15 -05:00
Gokul Soumya
22ae1b92a6 Fix tests for surround primitives 2022-04-29 15:51:14 +09:00
Gokul Soumya
76175dbd6d Support m in surround delete and replace 2022-04-29 15:51:14 +09:00
Gokul Soumya
de15d70171 Add m textobject to select closest surround pair 2022-04-29 15:51:14 +09:00
Ivan Tham
c22873c33f Change A-left right to C-left right in insert (#2193)
Currently A-left move one word left and the behavior will be more
consistent for people coming GUI world if the key was changed to control
given that both browsers and editors like vscode uses C-left right by
default to move word rather than alt.
2022-04-29 15:50:01 +09:00
Ivan Tham
ab6a00e196 Make A-hjkl tree-sitter nav A-pion (#2205)
A-hl currently is not very consistent with hl when next object is
selected, since it may go up/down or left/right and this behavior is
confusing such that some people think it should swap the keys with A-jk,
so it is better to use A-pn since that only specifies two direction.

A-jk have the same issue as in it usually moves right and is not
consistent with the behavior of jk so people may think A-hl is better,
maybe A-oi is better here since A-hl will be swapped to A-pn, A-oi can
convey the meaning of in and out, similar to some window manager keys?
2022-04-29 15:49:15 +09:00
nosa
e10cf08516 Extend tutor file (#2133)
* Adds tutorial sections for multiple areas including:
- Changing selections to uppercase / lowercase
- yanking and pasting
- macros
- selecting to chars with t and f

PS: I got kind of carried away and put off commiting for a while,
    will commit to commit more often in the future.

* Changed section titles to all uppercase

* Added recap and section about jumplist

* Added sections for searching in file, joining lines and indenting lines.

* Removed some trailing whitespace

* Evened out the space between sections to all be 5 lines

* Add section on opening lines (o) and recap

* Changed the amount of lines between sections

This is so that - on a 24 line terminal -
only one section is visible at a time and
page up/page down goes straight to the next
section keeping the header at the top.

* Punctuation error

Co-authored-by: Omnikar <omkar.subramaniam@icloud.com>

* Punctuation error

Co-authored-by: Omnikar <omkar.subramaniam@icloud.com>

* Spelling error

Co-authored-by: Omnikar <omkar.subramaniam@icloud.com>

* Remove unnecessary word

Co-authored-by: Omnikar <omkar.subramaniam@icloud.com>

* Reword note about searches

Co-authored-by: Omnikar <omkar.subramaniam@icloud.com>

* Change word

Co-authored-by: Omnikar <omkar.subramaniam@icloud.com>

* Update tutor file

* Made some small changes suggested by Omnikar

* Added better demo for macros.

* Small changes

- Add newlines at the end
- Make "MACROS" section fit into 22 lines
- Correct mistake of saying helix copied to clipboard in "COPYING AND PASTING TEXT"

* Reformatted notes in copying/pasting section to fit in screen

* Add a note about n and N and their difference to Vim.

* Combine f and t commands into one section.

* Removed t/T section which was merged into the f/F section.

* Merge sections on manipulating case into one.

* Gave section's numbers

* Convert 'press' to 'type' in some places

* Added examples of how prompt lines should look.

* Reformatted notes in copy/pasting section.

* More rewording to more comfortably fit sections on screen.

* Grammatical error.

* Missing periods.

* Missing capital + small reformat

* Fix mis-numbered section

* Reworded to use these conventions when referring to inputs:
- "Press" for single keypresses
- "Type" for multiple keypresses / modifiers
- "Use" when referencing two inputs as a pair.

* till not 'til

* Say 'press' instead of 'type' when referring to symbols

* 'outdent' not 'unindent'

* Typo and grammar.

* Replace all 'press's with 'type's (apart from places it would make no sense in).

* Improve examples for joining and indenting lines.

* Section alignment.

Co-authored-by: Omnikar <omkar.subramaniam@icloud.com>
2022-04-29 09:52:11 +08:00
CossonLeo
477b88e99c Wrap current directory picker with overlay widget (#2308) 2022-04-28 22:17:24 +09:00
chunghha
3a398eec56 fix typos (#2304) 2022-04-27 14:21:20 -05:00
Alexis Kalabura
2e46961886 feat(lsp): add toml lsp (#2302) 2022-04-27 13:48:04 -05:00
Gokul Soumya
3626e38e51 Add ui.virtual theme scopes for onedark theme 2022-04-27 13:40:00 -05:00
Matouš Dzivjak
52f5a4228a feat(commands): better handling of buffer-close (#1397)
* feat(commands): better handling of buffer-close

Previously, when closing buffer, you would loose cursor position in other docs.
Also, all splits where the buffer was open would be closed.

This PR changes the behavior, if the view has also other buffer
previously viewed it switches back to the last one instead of the view
being closed. As a side effect, since the views are persisted,
 the cursor history is persisted as well.

Fixes: https://github.com/helix-editor/helix/issues/1186

* Adjust buffer close behavior

* Remove closed documents from jump history

* Fix after rebase
2022-04-28 01:14:46 +09:00
Erasin
a3c0b4db48 Add onelight theme variant (#2287) 2022-04-27 08:09:45 -05:00
meak
1a3d6252b9 feat(lang): add hare language support (#2289)
Co-authored-by: Mehdi Katranji <hello@mek.yt>
2022-04-26 14:55:00 -05:00
Michael Davis
773736b03a Fix paste direction for typed paste commands (#2288) 2022-04-26 23:01:45 +05:30
Tomas Roos
fcd0ca3912 Fix base16_terminal theme using incorrect ansi-color (#2279) 2022-04-26 07:53:02 -05:00
dependabot[bot]
3d3145d511 build(deps): bump anyhow from 1.0.56 to 1.0.57 (#2273)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.56 to 1.0.57.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.56...1.0.57)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-26 11:20:58 +08:00
Jens Getreu
8eb15f5283 Autumn theme: improve markup highlighting (#2270)
Co-authored-by: Jens Getreu <jens.getreu@dlh.lu>
2022-04-25 12:39:24 -05:00
Lucy
b65fb0f64a Fix typo (#2264) 2022-04-25 07:26:02 -05:00
matt rice
db47761154 register publish_diagnostics client capability (#2241) 2022-04-25 11:14:46 +09:00
ttys3
a8cb46680d feat(lsp): add vala language support (#2243) 2022-04-24 11:21:07 -05:00
workingj
ea02b46c5d Add Pop-Dark Theme (#2189) 2022-04-24 08:04:47 -05:00
Daniel
15db6031bb Add :get-option command (#2231) 2022-04-24 16:00:18 +05:30
Michael Davis
3f2bd7770e Rename paragraph motion commands from move to goto (#2226)
* fix command name for next/prev paragraph motion

* rename move_next/prev_paragraph to goto_next/prev_paragraph
2022-04-24 10:48:22 +09:00
Lukas
5ca8dfe57c fix(lsp): divide hcl into seperate languages (#2244) 2022-04-23 16:08:12 -05:00
Paul Graydon
6047506ec5 Add tokyonight_storm theme variant (#2240) 2022-04-23 08:56:43 -05:00
Lukas
1c1ba006ae feat(lsp): add yaml lsp (#2234) 2022-04-23 08:38:29 -05:00
Michael Davis
2c7f770aa9 Only merge top-level array when merging languages.toml (#2215)
* Revert "Revert "override nested arrays when merging TOML (#2145)""

This reverts commit 35d2693630.

* flip top-level table merging flag
2022-04-23 17:10:34 +09:00
ttys3
19d042dde6 chore(lsp): check rename capabilities before send rename action (#2203) 2022-04-23 17:09:16 +09:00
Ivan Tham
c1d3d49f3f Fix ctrl-u on insert behavior (#1957)
* Fix ctrl-u on insert behavior

Now should follow vim behavior more
- no longer remove text on cursor
- no longer remove selected text while inserting
- first kill to start non-whitespace, start, previous new line

* Add comment for c-u parts
2022-04-23 17:03:52 +09:00
Kirawi
dd5a7c6191 Replace line endings using set_line_ending command (#1871)
* set_line_ending: now replace line endings

* use ending.len_chars() directly

* account for unicode-lines feaure in line-ending doc
2022-04-23 17:01:08 +09:00
Justin Ma
5c2570582b feat(lang): add nushell language support (#2225)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-04-22 09:37:51 -05:00
Jens Getreu
3c250b7528 Add autumn theme (#2212)
Co-authored-by: Jens Getreu <jens.getreu@dlh.lu>
2022-04-22 08:54:43 -05:00
Michael Davis
6de2e7634f Document ui.virtual.ruler scope in theme docs (#2199)
From the rulers feature (#2060)
2022-04-20 23:34:17 +05:30
ttys3
4144c9d2f2 feat(lang): add go.mod and go.work support (#2197) 2022-04-20 11:16:02 -05:00
ttys3
8d335f63f0 chore(filetype): bash and hcl file type add more common used extensions or files (#2201) 2022-04-20 11:08:57 -05:00
Jappie Klooster
b0bceb5674 Fix nix shell by hardcoding the flakecompat library (#2196) 2022-04-20 09:55:09 -05:00
Erin van der Veen
9616477197 Add Nickel language (#2173) 2022-04-20 09:31:59 -05:00
Emil Fresk
5247d3ae2d dark_plus: Add the borders color from the original theme (#2186) 2022-04-20 08:44:00 -05:00
Blaž Hrastnik
35d2693630 Revert "override nested arrays when merging TOML (#2145)"
Looks like there's some follow-up issues

This reverts commit c8cfd0b1a0.
2022-04-20 17:09:03 +09:00
Michael Davis
1525e3c6c8 theme ui.virtual capture for existing themes 2022-04-20 11:37:23 +09:00
Omnikar
e6b865ed0b allow whitespace to be rendered
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-04-20 11:37:23 +09:00
adaliaramon
94eba0e66a Added ability to remap 0 if it is not part of a count (#2174)
* Added ability to remap 0

* Removed duplicated match body
2022-04-20 10:50:13 +09:00
Ivan Tham
2a853cd41d Fix open on multiline selection (#2161)
Select multiple line and open should be based on the whole selection
and not just the line of the cursor, which causes weird behavior like
opening in the middle of the selection which user might not expect.
2022-04-20 10:46:46 +09:00
Thomas
5d5b6bab9b Add rulers option (#2060)
* Add color_column option

* Rename to ruler

Co-authored-by: DeviousStoat <devious@stoat.com>
2022-04-20 10:44:32 +09:00
matan h
02426072cb add table of OS/command for copy/symlink the runtime folder to the config (#2073)
* create table of OS and commands in the readme

* add link to wiki from health check (without color; just simple println)

* move the table from readme to docs and add link from the readme to docs

* drop copy on unix,and apply some style fixes from the conversations

* by mistake, I edit master insted of develop

* remove this file from pr

* Update README.md

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>

* copy table to readme

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-04-20 10:44:11 +09:00
Matthew Toohey
e452b97cdc AppImage (#2089)
* Add desktop entry file

Co-authored-by: NNB <n.at@aleeas.com>

* Add placeholder icon for AppImage

* Add AppImage step to release workflow

* Exclude grammar sources from AppImage

Co-authored-by: NNB <n.at@aleeas.com>
2022-04-20 10:43:52 +09:00
Michael Davis
c8cfd0b1a0 override nested arrays when merging TOML (#2145)
We merge the elements of arrays for the top-level array. For
`languages.toml`, this is the array of languages. For any nested
arrays, we simply take the `right` array as-is instead of using
the union of `left` and `right`.

closes #1000
2022-04-20 10:43:09 +09:00
Andrey Tkachenko
3a7bf1c40c Restore document state on completion cancel (#2096) 2022-04-20 10:42:33 +09:00
dependabot[bot]
cc68fa857d build(deps): bump toml from 0.5.8 to 0.5.9 (#2166)
Bumps [toml](https://github.com/alexcrichton/toml-rs) from 0.5.8 to 0.5.9.
- [Release notes](https://github.com/alexcrichton/toml-rs/releases)
- [Commits](https://github.com/alexcrichton/toml-rs/compare/0.5.8...0.5.9)

---
updated-dependencies:
- dependency-name: toml
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-19 08:54:20 +09:00
dependabot[bot]
c53ec95708 build(deps): bump fern from 0.6.0 to 0.6.1 (#2165)
Bumps [fern](https://github.com/daboross/fern) from 0.6.0 to 0.6.1.
- [Release notes](https://github.com/daboross/fern/releases)
- [Changelog](https://github.com/daboross/fern/blob/main/CHANGELOG.md)
- [Commits](https://github.com/daboross/fern/compare/fern-0.6.0...fern-0.6.1)

---
updated-dependencies:
- dependency-name: fern
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-19 08:54:09 +09:00
Paul Graydon
015a582d44 Add tokyonight theme (#2162) 2022-04-18 21:50:19 +05:30
Michael Davis
4e877de54d Fix Golang textobject queries (#2153)
* log textobject query construction errors

The current behavior is that invalid queries are discarded silently
which makes it difficult to debug invalid textobjects (either invalid
syntax or an update may have come through that changed the valid set
of nodes).

* fix golang textobject query

`method_spec_list` used to be a named node but was removed (I think
for Helix, it was when updated to pull in the support for generics).
Instead of a named node for the list of method specs we have a bunch
of `method_spec` children nodes now. We can match on the set of them
with a `+` wildcard.

Example go for this query:

    type Shape interface {
       area() float64
       perimeter() float64
    }

Which is parsed as:

    (source_file
      (type_declaration
        (type_spec
          name: (type_identifier)
          type: (interface_type
            (method_spec
              name: (field_identifier)
              parameters: (parameter_list)
              result: (type_identifier))
            (method_spec
              name: (field_identifier)
              parameters: (parameter_list)
              result: (type_identifier))))))
2022-04-18 23:14:48 +08:00
Michael Davis
449d1dfdfb prevent panic when receiving malformed LSP PublishDiagnostic (#2160)
Instead of panicing we can discard the malformed diagnostic. This
`.parse()` fails commonly when a non-conformant language server gives
a diagnostic with a location that breaks the spec:

    { "character": 0, "line": -1 }

can currently be returned by ElixirLS and the python LS. Other
messages in this block are discarded but this one feels special enough
to log.
2022-04-18 23:11:28 +08:00
Lucy
4b1fe367fa Remove dim attribute in onedark ui.linenr (#2155) 2022-04-18 15:52:26 +05:30
Ben Lee-Cohen
2bddec02e7 Fixing (in two ways) a small typo (#2156) 2022-04-18 13:12:47 +09:00
Kirawi
c2a40d9d52 Add support for local language configuration (#1249)
* add local configuration

* move config loading to Application::new

* simplify find_root_impl
2022-04-18 12:10:51 +09:00
Danillo Melo
be656c14e3 Ruby TextObjects and more file extensions (#2143) 2022-04-17 19:25:44 -05:00
Michael Davis
ad36a024da Update tree-sitters Erlang and HEEx (#2149) 2022-04-17 23:16:22 +05:30
Terry Brash
c45fb08a93 Add JavaScript control keywords (#2140) 2022-04-17 15:14:55 +09:00
AntonioLucibello
b67e0616dd Add command to extend selection to line above (#2117)
* added command to extend selection to line above

* fixed view not scrolling up when reaching top of the screen

* refactored shared code into separate impl
2022-04-17 12:26:14 +09:00
Robin Jadoul
33b7483db5 Send active diagnostics to LSP when requesting code actions. (#2005)
* Send active diagnostics to LSP when requesting code actions.

This allows for e.g. clangd to properly send the quickfix code actions
corresponding to those diagnostics as options.
The LSP spec v3.16.0 introduced an opaque `data` member that would allow
the server to persist arbitrary data between the diagnostic and the code
actions request, but this is not supported yet by this commit.

* Reuse existing range_to_lsp_range functionality
2022-04-17 12:05:23 +09:00
Thomas
2eca2901f3 Pipe typable command (#1972)
Co-authored-by: DeviousStoat <devious@stoat.com>
2022-04-17 12:03:47 +09:00
Andrey Tkachenko
dc8fef5dd3 Fixes #1991 LSP Auto-import (#2088) 2022-04-16 10:43:54 +09:00
Dr. David A. Kunz
b04c425c63 Make gutters configurable (#1967)
* config option line numbers none

* view tests

* added tests

* doc

* comment

* Make gutters configurable

* docu

* docu

* rm none docu

* order

* order

* precedence

* simpler

* rm todo

* fixed clippy

* order

* double quotes

* only allow diagnostics and line-numbers

* tests

* docu

* format

* rm short variant and more docu

* performance improvements

* typo

* rename
2022-04-16 10:41:25 +09:00
Evan Lecklider
450f348925 Add make file-type "mk" to languages.toml (#2120) 2022-04-15 12:15:17 -05:00
EmmChriss
50df924811 gdscript support (#1985) 2022-04-16 00:35:23 +09:00
nosa
893963df0a Additions to 'themes' section of docs (#2098)
* Added more descriptions to the themes part of the docs

* Add more descriptions to themes section of the docs

* capitalised first letters of descriptions in docs

Co-authored-by: Joe Mckay <jm@pop-os.localdomain>
2022-04-15 09:58:16 +09:00
Jared Ramirez
460e6a857b feat(languages): SQL (#2097) 2022-04-14 13:26:20 -05:00
Blaž Hrastnik
764adbdcf6 fix: prompt: pass through unmapped keys regardless of modifiers
Ctrl + Alt is apparently another common sequence for AltGr:
https://devblogs.microsoft.com/oldnewthing/20040329-00/?p=40003

Fixes #595
Fixes #2080
2022-04-13 15:19:42 +09:00
Michael Davis
4836bb38d3 add tree-sitter-heex
HEEx is a templating engine on top of Elixir's EEx templating
language specific to HTML that is included in Phoenix.LiveView
(though I think the plan is to eventually include it in base
Phoenix). It's a superset of EEx with some additional features
like components and slots.

The injections don't work perfectly because the Elixir grammar is
newline sensitive (the _terminator rule). See
https://github.com/elixir-lang/tree-sitter-elixir/issues/24
for more information.
2022-04-13 14:28:51 +09:00
Michael Davis
9d095e0fdc add tree-sitter-eex
EEx is an templating language for Elixir. Since the incremental
parsing refactor we can used combined injections which allows us
to add EEx support.
2022-04-13 14:28:51 +09:00
Michael Davis
4ac94a5c43 remove error highlighting for tree-sitter-elixir
This will become more important with the HEEx grammar being added.
Error highlighting with the Elixir grammar is a bit jumpy because
in some scenarios, a bit of missing syntax can force tree-sitter to
give up on error recovery and mark the entire tree as an error.
This ends up looking bad when editing. We don't typically highlight
error nodes so I'm inclined to leave it out of the highlights here.
2022-04-13 14:28:51 +09:00
Michael Davis
8c3c90198a update tree-sitter-elixir
The new revision handles a case that I come across often: a stab
clause (i.e. '->') with an empty right hand side:

    Enum.map(xs, fn x ->
    end)

The old version would parse the "end" token as an error.

This is technically valid syntax but more importantly it comes up
very often when editing, and the old revision would flicker between
the keyword highlight and the warning highlight.
2022-04-13 14:28:51 +09:00
scgtrp
740f565c80 Document values for editor.cursor-shape (#2094)
These are hinted at in the example config at the top (except `none`), but really should be listed explicitly near the option itself for clarity.
2022-04-13 13:00:17 +09:00
Ivan Tham
62283fdadb Make textobject select last paragraph (#1992)
* Make textobject select last paragraph

Last paragraph shoud be selected if the cursor was placed on the
whitespace paragraph part and `map` is done, otherwise it would do
nothing useful, but now we select backwards for the last paragraph
which behaves similarly to kakoune, making `map` useful for the last
paragraph with whitespace. Example usecase is to copy and paste last
ledger cli paragraph quickly by `mapyp` to duplicate last entry.

* Fix typo in core textobject

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2022-04-13 10:02:53 +09:00
Roland Kovacs
a0c6c45c1b Fix panic when using set-language on a scratch (#1996)
Skip launching a language server if a document doesn't have a valid URL.
2022-04-13 10:02:14 +09:00
Nirmal Patel
3deb1c9230 Add true or false checkbox in health output table (#1947)
hx --health output table's second and third columns were not showing
symbols like ✔ or ✘ to indicate whether LSP or DAP binaries were found.
This change adds these symbols to improve accessibility.

Fixes #1894

Signed-off-by: Nirmal Patel <npate012@gmail.com>
2022-04-12 17:21:16 +09:00
Benedikt Müller
1fb6144432 Add shell completion (#2022)
* Add shell completion

* Add shell completion to release
2022-04-12 17:10:21 +09:00
Omnikar
660e0e44b2 Add :write! to create nonexistent subdirectories (#1839)
* Make `:write` create nonexistent subdirectories

Prompting as to whether this should take place remains a TODO.

* Move subdirectory creation to new `w!` command
2022-04-12 16:52:54 +09:00
unrelentingtech
d5c0866978 Apply ui.gutter style to empty gutters (#2032)
The unstyled column on the left from the diagnostics_or_breakpoints gutter
looks sad if you want to add a background to all gutters. Let's fix this.
2022-04-12 16:48:30 +09:00
dependabot[bot]
f3dcb4034f build(deps): bump lsp-types from 0.92.1 to 0.93.0 (#2084)
Bumps [lsp-types](https://github.com/gluon-lang/lsp-types) from 0.92.1 to 0.93.0.
- [Release notes](https://github.com/gluon-lang/lsp-types/releases)
- [Changelog](https://github.com/gluon-lang/lsp-types/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gluon-lang/lsp-types/compare/v0.92.1...v0.93.0)

---
updated-dependencies:
- dependency-name: lsp-types
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-12 12:12:30 +09:00
dependabot[bot]
6530d452a0 build(deps): bump encoding_rs from 0.8.30 to 0.8.31 (#2083)
Bumps [encoding_rs](https://github.com/hsivonen/encoding_rs) from 0.8.30 to 0.8.31.
- [Release notes](https://github.com/hsivonen/encoding_rs/releases)
- [Commits](https://github.com/hsivonen/encoding_rs/compare/v0.8.30...v0.8.31)

---
updated-dependencies:
- dependency-name: encoding_rs
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-12 12:12:03 +09:00
dependabot[bot]
14079bd17b build(deps): bump cachix/install-nix-action from 16 to 17 (#2081)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-11 18:34:39 -05:00
dependabot[bot]
f9ddc8a9ac build(deps): bump actions/download-artifact from 2 to 3 (#2082)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-11 18:34:29 -05:00
Aral Balkan
7cb6e07ba0 Improve Dracula Theme selections (#2075) (#2077) 2022-04-11 09:21:41 -05:00
Michael Davis
3d79c60a1f Rewrite Language Support docs (#2065) 2022-04-10 23:20:05 +05:30
gavynriebau
562874a720 Add command for picking files from CWD (#1600)
The `file_picker_at_current_directory` command opens the file picker at
the current working directory (CWD). This can be useful when paired with
the built-in `:cd` command which changes the CWD.

It has been mapped to `space F` by default.
2022-04-10 11:30:09 +09:00
Michael Davis
494306ad7a add tree-sitter-embedded-template (erb & ejs) (#2055)
After the incremental parsing rewrite for injections (which was released
in 22.03 https://helix-editor.com/news/release-22-03-highlights/#incremental-injection-parsing-rewrite),
we can now do combined injections which lets us pull in some templating
grammars. The most notable of those is embedded-template - a pretty
straightforward grammar that covers ERB and EJS.

The grammar and highlights queries are shared between the two but they have
different injections.
2022-04-10 08:23:06 +09:00
Michael Davis
78b1600943 Improve documentation on Language Server installation (#2037) 2022-04-09 12:17:32 +05:30
Kurenshe Nurdaulet
0b410b0a16 Add default language server for Vue (#2043) 2022-04-08 21:04:22 -05:00
Evan Relf
7779dbfcb8 docs: Quote TOML keys containing dots (#2040) 2022-04-08 17:21:52 -05:00
Sam Sartor
209ec4468b Add dracula at night theme (#2008) 2022-04-08 15:53:12 -05:00
unrelentingtech
7f461895b0 Add language server command for OCaml (#2035) 2022-04-08 15:02:25 -05:00
Aaron Housh
9caf7c0d5a Add swift language (#2033) 2022-04-08 13:10:37 -05:00
Karl Grasegger
8e12fd5290 PHP roots and languageserver improvements (#2031)
Co-authored-by: Karl Grasegger <karl.grasegger@gebruederheitz.de>
2022-04-08 12:57:46 -05:00
Michael Davis
19ff21eaa2 Remove usage of format ident feature from tests (#2028) 2022-04-08 21:26:50 +05:30
David
61d1684a32 Add default language server for CSS (#2025) 2022-04-08 10:06:54 -05:00
David
22629ca211 Add default language server for JSON (#2024) 2022-04-08 10:06:41 -05:00
David
b5efb9d66c Add default language server for HTML (#2018) 2022-04-08 08:36:10 -05:00
Gaeulbyul
581ac5660f Fix typo (pallete -> palette) (#2020) 2022-04-08 08:35:11 -05:00
Kirawi
2d4f94eb27 [dark_plus] update tag and ui.menu.selected colors (#2014) 2022-04-07 21:08:16 -05:00
Gokul Soumya
420b5b8301 Compute style only once per source highlight event (#1966)
During a single HighlightEvent::Source, the highlight spans do not
change and we can merge them into a single style at the beginning
of the event and use it instead of re-computing it for every grapheme
2022-04-08 09:42:57 +09:00
Matthew Toohey
31c468ab95 add languages r and rmarkdown (#1998)
* add languages `r` and `rmarkdown`

* r: fix highlights

* rmarkdown: add eof in queries

* rmarkdown: update lang-support.md

* r: fix highlight query precedence
2022-04-08 09:30:44 +09:00
tomKPZ
d37369c1e0 Add paragraph textobject to match infobox (#1969) 2022-04-07 09:11:14 +08:00
Michael Davis
b03421a8c0 remove hardcoded '/' from grammar source path (#1986) 2022-04-07 00:32:00 +09:00
Michael Davis
275c05008f fix keymap doc typo for 'delete' in insert-mode (#1990)
closes #1980
see also #1180
2022-04-07 00:31:40 +09:00
Kirawi
b333186721 [dark_plus] update markup colors (#1989) 2022-04-07 00:31:28 +09:00
bootradev
0eb87996a8 add boo_berry theme (#1962) 2022-04-06 01:06:51 +09:00
VuiMuich
eb84d9493c add language ron (#1925) 2022-04-05 07:39:22 -05:00
Danilo Spinella
6b80cb8a77 Fix toggle_comments command on multiple selections (#1882) 2022-04-05 10:01:58 +09:00
Roland Kovacs
d962e06e91 Add runtime language configuration (#1794) (#1866)
* Add runtime language configuration (#1794)

* Add set-language typable command to change the language of current buffer.
* Add completer for available language options.

* Update set-language to refresh language server as well

* Add language id based config lookup on `syntax::Loader`.
* Add `Document::set_language3` to set programming language based on language
  id.
* Update `Editor::refresh_language_server` to try language detection only if
  language is not already set.

* Remove language detection from Editor::refresh_language_server

* Move document language detection to where the scratch buffer is saved.
* Rename Document::set_language3 to Document::set_language_by_language_id.

* Remove unnecessary clone in completers::language
2022-04-05 09:56:14 +09:00
Ivan Tham
6fc6f87260 Fix next paragraph logic over muliple blank lines (#1951)
Fix #1928
2022-04-05 09:43:14 +09:00
Ivan Tham
e7beb32fd7 Add paragraph to last motion (#1956)
Fix #1954
2022-04-05 09:43:04 +09:00
Ivan Tham
d3c8286ea0 Bump crossterm to 0.32.2 (#1955)
Deduplicates mio dependency which results no crate duplication now and
7 lesser crate for cargo to build.
2022-04-05 09:41:28 +09:00
Rose Hudson
f8c83f9885 clear terminal after switching to alternate screen
when using helix over mosh, the screen doesn't get cleared and
characters get left all over the place until they are overwritten. with
this change, the screen gets properly cleared as soon as helix starts
2022-04-04 16:41:11 +09:00
Kirawi
3fc4ea2938 [dark_plus] remove ui.text background (#1950) 2022-04-03 17:59:02 -05:00
Dr. David A. Kunz
9782204f73 Add typed commands buffer-next and buffer-previous (#1940) 2022-04-03 17:56:46 +05:30
Ivan Tham
ec21de0844 Add missing # back to test output 2022-04-03 00:46:53 +09:00
Ivan Tham
8b91ecde40 Rename _para to _paragraph 2022-04-03 00:46:53 +09:00
Gokul Soumya
64c2490f2d Refactor test print to be more readable 2022-04-03 00:46:53 +09:00
Ivan Tham
45b76db506 Change test mark from ^@ to #[|]# 2022-04-03 00:46:53 +09:00
Ivan Tham
8350ee9a0e Add paragraph textobject
Change parameter/argument key from p to a since paragraph only have p
but parameter are also called arguments sometimes and a is not used.
2022-04-03 00:46:53 +09:00
Ivan Tham
e2a6e33b98 Add next paragraph 2022-04-03 00:46:53 +09:00
Ivan Tham
8b02bf2ea8 Add (prev) paragraph motion
Also improved testing facility.

Fix #1580
2022-04-03 00:46:53 +09:00
Lauri Gustafsson
e4561d1dde Add texlab language server for latex (#1922) 2022-04-02 09:00:05 -05:00
Simon H
36d1df71fc Added checkmarks to health.rs output, Resolves #1894 (#1918)
* Added checkmarks to health.rs output

* replaced found/not found text with checkmarks
2022-04-02 17:32:36 +09:00
Michael Davis
ffdc2f1793 separate JSX queries from javascript (#1921)
It looks like a24fb17b2a (and
855e438f55) broke the typescript
highlights because typescript

    ; inherits: javascript

but it doesn't have those named nodes in its grammar.

So instead we can separate out JSX into its own language and copy
over everything from javascript and supplement it with the new
JSX highlights. Luckily there isn't too much duplication, just the
language configuration parts - we can re-use the parser with the
languages.toml `grammar` key and most of the queries with `inherits`.
2022-04-02 10:07:35 +09:00
joezak11
deb7ee6595 Update bash tree sitter (#1917) 2022-04-01 08:48:39 -05:00
jeepee
85c23b31de Avoid unnecessary clone when formatting error (#1903)
Instead of first cloning the query and then allocating again to format
the error, format the error using a reference to the query.
2022-04-01 22:16:51 +09:00
jeepee
8165febe23 Fix start-position of next search (#1904)
The search implementation would start searching at the next grapheme
boundary after the previous selection. In case the next occurence of the
needle is immediately after the current selection, this occurence would
not be found (without wraparound) because the first grapheme is skipped.

The correct approach is to use the ensure_grapheme_boundary functions instead
of using the functions that skip unconditionally to the next grapheme.
2022-04-01 22:16:09 +09:00
antoyo
47fe739757 Jump to the next number on the line before incrementing (#1778)
* Jump to the next number on the line before incrementing

Partially fix #1645

* Refactor to avoid duplicating find_nth_next
2022-04-01 22:14:37 +09:00
Blaž Hrastnik
855e438f55 jsx: Add special highlighting to component names 2022-04-01 17:18:44 +09:00
Blaž Hrastnik
a24fb17b2a Add JSX highlighting queries 2022-04-01 17:14:25 +09:00
Amine Hmida
d0ff2ffd89 Add support for jsx (#1906)
* Add support for javascriptreact language

* Add support for jsx files
2022-04-01 17:08:34 +09:00
جاد
a9635659f7 Reintroduce win32yank as a clipboard provider on Linux for WSL2 + Windows 10 (#1912)
* feat(clipboard): reintroduce win32yank for wsl2 linux

* refactor(clipboard): adjust win32yank position to not interrupt wayland/x11

Co-authored-by: jiqb <gthbji@ml1.net>
2022-04-01 11:35:47 +09:00
Triton171
6bb2298391 Fix an issue that caused an empty indentation query to be used instead of using the fallback method of copying the indentation from the current line. (#1908)
Co-authored-by: Triton171 <triton0171@gmail.com>
2022-04-01 11:27:06 +09:00
Blaž Hrastnik
8adf0c1b3a lsp: Implement support for workspace_folders (currently just one)
Refs #1898
2022-04-01 11:20:41 +09:00
Blaž Hrastnik
236c6b7707 fix: copy_selections was broken with selections (not cursors) 2022-04-01 10:11:44 +09:00
Marcin Puc
924462edda Add install instructions for Void Linux (#1911) 2022-03-31 14:55:55 -05:00
Blaž Hrastnik
84e799f0e4 fix: Some LSPs still want rootPath, so provide it
Refs #1898
2022-03-31 17:45:51 +09:00
Rohan Jain
5d61631507 Resolve conflicts between prompt/picker bindings (#1792)
Currently, the picker's re-using a few bindings which are also present
in the prompt. This causes some editing behaviours to not function on
the picker.

**Ctrl + k** and **Ctrl + j**
This should kill till the end of the line on prompt, but is overridden
by the picker for scrolling. Since there are redundancies (`Ctrl + p`,
`Ctrl + n`), we can remove it from picker.

**Ctrl + f** and **Ctrl + b**
This are used by the prompt for back/forward movement. We could modify
it to be Ctrl + d and Ctrl + u, to match the `vim` behaviour.
2022-03-31 16:51:11 +09:00
Michael Davis
ef91b6500c set VERSION file to dev (#1883)
* set VERSION file to dev

* bump to 22.05-dev
2022-03-31 16:31:38 +09:00
Blaž Hrastnik
d15c875214 Add a TODO for the future 2022-03-31 15:59:09 +09:00
Blaž Hrastnik
ab7885e934 fix: copy_selection needs to account for to() being exclusive
Fixes #1367
Fixes #1590
2022-03-31 15:59:09 +09:00
Max
4eed4c26e9 Use fromTOML on Nix >= 2.6.0 (#1892) 2022-03-30 11:28:05 -05:00
Triton171
58758fee61 Indentation rework (#1562)
* WIP: Rework indentation system

* Add ComplexNode for context-aware indentation (including a proof of concept for assignment statements in rust)

* Add switch statements to Go indents.toml (fixes the second half of issue #1523)
Remove commented-out code

* Migrate all existing indentation queries.
Add more options to ComplexNode and use them to improve C/C++ indentation.

* Add comments & replace Option<Vec<_>> with Vec<_>

* Add more detailed documentation for tree-sitter indentation

* Improve code style in indent.rs

* Use tree-sitter queries for indentation instead of TOML config.
Migrate existing indent queries.

* Add documentation for the new indent queries.
Change xtask docgen to look for indents.scm instead of indents.toml

* Improve code style in indent.rs.
Fix an issue with the rust indent query.

* Move indentation test sources to separate files.
Add `#not-kind-eq?`, `#same-line?` and `#not-same-line` custom predicates.
Improve the rust and c indent queries.

* Fix indent test.
Improve rust indent queries.

* Move indentation tests to integration test folder.

* Improve code style in indent.rs.
Reuse tree-sitter cursors for indentation queries.

* Migrate HCL indent query

* Replace custom loading in indent tests with a designated languages.toml

* Update indent query file name for --health command.

* Fix single-space formatting in indent queries.

* Add explanation for unwrapping.

Co-authored-by: Triton171 <triton0171@gmail.com>
2022-03-31 00:08:07 +09:00
Blaž Hrastnik
c18de0e8f0 fix: Don't rely on FormattingOptions::default()
Refs #1884
2022-03-30 15:19:21 +09:00
Nirmal Patel
8702aaaefc Handle BrokenPipe when piping hx --health through head (#1876)
Co-authored-by: Gokul Soumya <gokulps15@gmail.com>
2022-03-30 10:39:25 +05:30
Michael Davis
7cd6050235 add tree-sitter-gleam 2022-03-30 13:24:53 +09:00
Michael Davis
1819478940 update tree-sitter-elixir
news:

- tree-sitter-elixir now powers Elixir syntax highlighting on github.com
- GitHub now supports code-navigation for Elixir repos via
  tree-sitter-elixir

changes:

- modules now use the `@module` highlight, which was added upstream to
  tree-sitter
    - it seems appropriate to use `@namespace` to follow helix convention
- added nullary range operator (e.g. `Enum.to_list(..) == []`), a new syntax
  for elixir 1.14
- a fix for stab clause nodes mis-highlighting when the right hand side of
  the stab clause contained multiple simple expressions
2022-03-30 13:24:53 +09:00
Michael Davis
e2a50711d5 update tree-sitter-erlang
changes:

- typed fields within records which do not declare a default
  value are now correctly highlighted as record fields
- the EEP49 'maybe' form is now parsed
- fixes for highlights for 'begin' and 'after' tokens
2022-03-30 13:24:53 +09:00
Marcin Puc
f2dd3d4469 Avoid using the format ident Rust feature (#1881) 2022-03-30 09:08:30 +09:00
Michael Davis
c8082a1133 update screenshot (#1879) 2022-03-30 00:16:57 +09:00
608 changed files with 41205 additions and 9494 deletions

View File

@@ -1,2 +0,0 @@
[alias]
xtask = "run --package xtask --"

3
.cargo/config.toml Normal file
View File

@@ -0,0 +1,3 @@
[alias]
xtask = "run --package xtask --"
integration-test = "test --features integration --workspace --test integration"

11
.gitattributes vendored Normal file
View File

@@ -0,0 +1,11 @@
# Auto detect text files and perform normalization
* text=auto
*.rs text diff=rust
*.toml text diff=toml
*.scm text diff=scheme
*.md text diff=markdown
book/theme/highlight.js linguist-vendored
Cargo.lock text

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
open_collective: helix-editor

13
.github/ISSUE_TEMPLATE/enhancement.md vendored Normal file
View File

@@ -0,0 +1,13 @@
---
name: Enhancement
about: Suggest an improvement
title: ''
labels: C-enhancement
assignees: ''
---
<!--
Your enhancement may already be reported!
Please search on the issue tracker before creating a new issue.
If this is an idea for a feature, please open an "Idea" Discussion instead.
-->

View File

@@ -1,13 +0,0 @@
---
name: Feature request
about: Suggest a new feature or improvement
title: ''
labels: C-enhancement
assignees: ''
---
<!-- Your feature may already be reported!
Please search on the issue tracker before creating one. -->
#### Describe your feature request

View File

@@ -11,98 +11,62 @@ jobs:
check:
name: Check
runs-on: ubuntu-latest
strategy:
matrix:
rust: [stable, msrv]
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Use MSRV rust toolchain
if: matrix.rust == 'msrv'
run: cp .github/workflows/msrv-rust-toolchain.toml rust-toolchain.toml
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
uses: helix-editor/rust-toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- name: Cache cargo registry
uses: actions/cache@v3
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-registry-
- name: Cache cargo index
uses: actions/cache@v3
with:
path: ~/.cargo/git
key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-index-
- name: Cache cargo target dir
uses: actions/cache@v3
with:
path: target
key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-build-target-
- uses: Swatinem/rust-cache@v2
- name: Run cargo check
uses: actions-rs/cargo@v1
with:
command: check
run: cargo check
test:
name: Test Suite
runs-on: ${{ matrix.os }}
env:
RUST_BACKTRACE: 1
HELIX_LOG_LEVEL: info
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
uses: helix-editor/rust-toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
- name: Cache cargo registry
uses: actions/cache@v3
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-registry-
- name: Cache cargo index
uses: actions/cache@v3
with:
path: ~/.cargo/git
key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-index-
- name: Cache cargo target dir
uses: actions/cache@v3
with:
path: target
key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-build-target-
- name: Copy minimal languages config
run: cp .github/workflows/languages.toml ./languages.toml
- uses: Swatinem/rust-cache@v2
- name: Cache test tree-sitter grammar
uses: actions/cache@v3
with:
path: runtime/grammars
key: ${{ runner.os }}-v2-tree-sitter-grammars-${{ hashFiles('languages.toml') }}
restore-keys: ${{ runner.os }}-v2-tree-sitter-grammars-
key: ${{ runner.os }}-stable-v${{ env.CACHE_VERSION }}-tree-sitter-grammars-${{ hashFiles('languages.toml') }}
restore-keys: ${{ runner.os }}-stable-v${{ env.CACHE_VERSION }}-tree-sitter-grammars-
- name: Run cargo test
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace
run: cargo test --workspace
- name: Run cargo integration-test
run: cargo integration-test
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
rust: [stable]
lints:
name: Lints
@@ -112,45 +76,24 @@ jobs:
uses: actions/checkout@v3
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
uses: helix-editor/rust-toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy
- name: Cache cargo registry
uses: actions/cache@v3
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-registry-
- name: Cache cargo index
uses: actions/cache@v3
with:
path: ~/.cargo/git
key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-index-
- name: Cache cargo target dir
uses: actions/cache@v3
with:
path: target
key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-build-target-
- uses: Swatinem/rust-cache@v2
- name: Run cargo fmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
run: cargo fmt --all --check
- name: Run cargo clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --all-targets -- -D warnings
run: cargo clippy --workspace --all-targets -- -D warnings
- name: Run cargo doc
run: cargo doc --no-deps --workspace --document-private-items
env:
RUSTDOCFLAGS: -D warnings
docs:
name: Docs
@@ -160,38 +103,15 @@ jobs:
uses: actions/checkout@v3
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
uses: helix-editor/rust-toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- name: Cache cargo registry
uses: actions/cache@v3
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-registry-
- name: Cache cargo index
uses: actions/cache@v3
with:
path: ~/.cargo/git
key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-index-
- name: Cache cargo target dir
uses: actions/cache@v3
with:
path: target
key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-build-target-
- uses: Swatinem/rust-cache@v2
- name: Generate docs
uses: actions-rs/cargo@v1
with:
command: xtask
args: docgen
run: cargo xtask docgen
- name: Check uncommitted documentation changes
run: |
@@ -200,3 +120,20 @@ jobs:
|| (echo "Run 'cargo xtask docgen', commit the changes and push again" \
&& exit 1)
queries:
name: Tree-sitter queries
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install stable toolchain
uses: helix-editor/rust-toolchain@v1
with:
profile: minimal
override: true
- uses: Swatinem/rust-cache@v2
- name: Generate docs
run: cargo xtask query-check

View File

@@ -14,13 +14,13 @@ jobs:
uses: actions/checkout@v3
- name: Install nix
uses: cachix/install-nix-action@v16
uses: cachix/install-nix-action@v18
- name: Authenticate with Cachix
uses: cachix/cachix-action@v10
uses: cachix/cachix-action@v12
with:
name: helix
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build nix flake
run: nix build
run: nix build -L

View File

@@ -11,7 +11,7 @@ indent = { tab-width = 4, unit = " " }
[[grammar]]
name = "rust"
source = { git = "https://github.com/tree-sitter/tree-sitter-rust", rev = "a360da0a29a19c281d08295a35ecd0544d2da211" }
source = { git = "https://github.com/tree-sitter/tree-sitter-rust", rev = "0431a2c60828731f27491ee9fdefe25e250ce9c9" }
[[language]]
name = "nix"

View File

@@ -0,0 +1,3 @@
[toolchain]
channel = "1.61.0"
components = ["rustfmt", "rust-src"]

View File

@@ -4,6 +4,18 @@ on:
tags:
- '[0-9]+.[0-9]+'
- '[0-9]+.[0-9]+.[0-9]+'
branches:
- 'patch/ci-release-*'
pull_request:
paths:
- '.github/workflows/release.yml'
env:
# Preview mode: Publishes the build output as a CI artifact instead of creating
# a release, allowing for manual inspection of the output. This mode is
# activated if the CI run was triggered by events other than pushed tags, or
# if the repository is a fork.
preview: ${{ !startsWith(github.ref, 'refs/tags/') || github.repository != 'helix-editor/helix' }}
jobs:
fetch-grammars:
@@ -14,40 +26,15 @@ jobs:
uses: actions/checkout@v3
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
uses: helix-editor/rust-toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- name: Cache cargo registry
uses: actions/cache@v3
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-registry-
- name: Cache cargo index
uses: actions/cache@v3
with:
path: ~/.cargo/git
key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-index-
- name: Cache cargo target dir
uses: actions/cache@v3
with:
path: target
key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-v2-cargo-build-target-
- uses: Swatinem/rust-cache@v2
- name: Fetch tree-sitter grammars
uses: actions-rs/cargo@v1
env:
HELIX_DISABLE_AUTO_GRAMMAR_BUILD: yes
with:
command: run
args: -- --grammar fetch
run: cargo run --package=helix-loader --bin=hx-loader
- name: Bundle grammars
run: tar cJf grammars.tar.xz -C runtime/grammars/sources .
@@ -71,11 +58,16 @@ jobs:
rust: stable
target: x86_64-unknown-linux-gnu
cross: false
# - build: aarch64-linux
# os: ubuntu-20.04
# rust: stable
# target: aarch64-unknown-linux-gnu
# cross: true
- build: aarch64-linux
os: ubuntu-20.04
rust: stable
target: aarch64-unknown-linux-gnu
cross: true
- build: riscv64-linux
os: ubuntu-20.04
rust: stable
target: riscv64gc-unknown-linux-gnu
cross: true
- build: x86_64-macos
os: macos-latest
rust: stable
@@ -86,10 +78,12 @@ jobs:
rust: stable
target: x86_64-pc-windows-msvc
cross: false
# - build: aarch64-macos
# os: macos-latest
# rust: stable
# target: aarch64-apple-darwin
- build: aarch64-macos
os: macos-latest
rust: stable
target: aarch64-apple-darwin
cross: false
skip_tests: true # x86_64 host can't run aarch64 code
# - build: x86_64-win-gnu
# os: windows-2019
# rust: stable-x86_64-gnu
@@ -104,7 +98,7 @@ jobs:
uses: actions/checkout@v3
- name: Download grammars
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
- name: Move grammars under runtime
if: "!startsWith(matrix.os, 'windows')"
@@ -120,13 +114,30 @@ jobs:
target: ${{ matrix.target }}
override: true
# Install a pre-release version of Cross
# TODO: We need to pre-install Cross because we need cross-rs/cross#591 to
# get a newer C++ compiler toolchain. Remove this step when Cross
# 0.3.0, which includes cross-rs/cross#591, is released.
- name: Install Cross
if: "matrix.cross"
run: cargo install cross --git https://github.com/cross-rs/cross.git --rev 47df5c76e7cba682823a0b6aa6d95c17b31ba63a
- name: Run cargo test
uses: actions-rs/cargo@v1
if: "!matrix.skip_tests"
with:
use-cross: ${{ matrix.cross }}
command: test
args: --release --locked --target ${{ matrix.target }} --workspace
- name: Set profile.release.strip = true
shell: bash
run: |
cat >> .cargo/config.toml <<EOF
[profile.release]
strip = true
EOF
- name: Build release binary
uses: actions-rs/cargo@v1
with:
@@ -134,29 +145,62 @@ jobs:
command: build
args: --release --locked --target ${{ matrix.target }}
- name: Strip release binary (linux and macos)
if: matrix.build == 'x86_64-linux' || matrix.build == 'x86_64-macos'
run: strip "target/${{ matrix.target }}/release/hx"
- name: Strip release binary (arm)
if: matrix.build == 'aarch64-linux'
- name: Build AppImage
shell: bash
if: matrix.build == 'aarch64-linux' || matrix.build == 'x86_64-linux'
run: |
docker run --rm -v \
"$PWD/target:/target:Z" \
rustembedded/cross:${{ matrix.target }} \
aarch64-linux-gnu-strip \
/target/${{ matrix.target }}/release/hx
mkdir dist
name=dev
if [[ $GITHUB_REF == refs/tags/* ]]; then
name=${GITHUB_REF:10}
fi
build="${{ matrix.build }}"
export VERSION="$name"
export ARCH=${build%-linux}
export APP=helix
export OUTPUT="helix-$VERSION-$ARCH.AppImage"
export UPDATE_INFORMATION="gh-releases-zsync|$GITHUB_REPOSITORY_OWNER|helix|latest|$APP-*-$ARCH.AppImage.zsync"
mkdir -p "$APP.AppDir"/usr/{bin,lib/helix}
cp "target/${{ matrix.target }}/release/hx" "$APP.AppDir/usr/bin/hx"
rm -rf runtime/grammars/sources
cp -r runtime "$APP.AppDir/usr/lib/helix/runtime"
cat << 'EOF' > "$APP.AppDir/AppRun"
#!/bin/sh
APPDIR="$(dirname "$(readlink -f "${0}")")"
HELIX_RUNTIME="$APPDIR/usr/lib/helix/runtime" exec "$APPDIR/usr/bin/hx" "$@"
EOF
chmod 755 "$APP.AppDir/AppRun"
curl -Lo linuxdeploy-x86_64.AppImage \
https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
chmod +x linuxdeploy-x86_64.AppImage
./linuxdeploy-x86_64.AppImage \
--appdir "$APP.AppDir" -d contrib/Helix.desktop \
-i contrib/helix.png --output appimage
mv "$APP-$VERSION-$ARCH.AppImage" \
"$APP-$VERSION-$ARCH.AppImage.zsync" dist
- name: Build archive
shell: bash
run: |
mkdir dist
mkdir -p dist
if [ "${{ matrix.os }}" = "windows-2019" ]; then
cp "target/${{ matrix.target }}/release/hx.exe" "dist/"
else
cp "target/${{ matrix.target }}/release/hx" "dist/"
fi
rm -rf runtime/grammars/sources
if [ -d runtime/grammars/sources ]; then
rm -rf runtime/grammars/sources
fi
cp -r runtime dist
- uses: actions/upload-artifact@v3
@@ -172,17 +216,7 @@ jobs:
- name: Checkout sources
uses: actions/checkout@v3
- uses: actions/download-artifact@v2
- name: Calculate tag name
run: |
name=dev
if [[ $GITHUB_REF == refs/tags/* ]]; then
name=${GITHUB_REF:10}
fi
echo ::set-output name=val::$name
echo TAG=$name >> $GITHUB_ENV
id: tagname
- uses: actions/download-artifact@v3
- name: Build archive
shell: bash
@@ -203,13 +237,19 @@ jobs:
if [[ $platform =~ "windows" ]]; then
exe=".exe"
fi
pkgname=helix-$TAG-$platform
pkgname=helix-$GITHUB_REF_NAME-$platform
mkdir $pkgname
cp $source/LICENSE $source/README.md $pkgname
mkdir $pkgname/contrib
cp -r $source/contrib/completion $pkgname/contrib
mv bins-$platform/runtime $pkgname/
mv bins-$platform/hx$exe $pkgname
chmod +x $pkgname/hx$exe
if [[ "$platform" = "aarch64-linux" || "$platform" = "x86_64-linux" ]]; then
mv bins-$platform/helix-*.AppImage* dist/
fi
if [ "$exe" = "" ]; then
tar cJf dist/$pkgname.tar.xz $pkgname
else
@@ -217,14 +257,22 @@ jobs:
fi
done
tar cJf dist/helix-$TAG-source.tar.xz -C $source .
tar cJf dist/helix-$GITHUB_REF_NAME-source.tar.xz -C $source .
mv dist $source/
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
if: env.preview == 'false'
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: dist/*
file_glob: true
tag: ${{ steps.tagname.outputs.val }}
tag: ${{ github.ref_name }}
overwrite: true
- name: Upload binaries as artifact
uses: actions/upload-artifact@v3
if: env.preview == 'true'
with:
name: release
path: dist/*

1
.gitignore vendored
View File

@@ -1,6 +1,5 @@
target
.direnv
helix-term/rustfmt.toml
helix-syntax/languages/
result
runtime/grammars

5
.ignore Normal file
View File

@@ -0,0 +1,5 @@
# Things that we don't want ripgrep to search that we do want in git
# https://github.com/BurntSushi/ripgrep/blob/master/GUIDE.md#automatic-filtering
# Minified JS vendored from mdbook
book/theme/highlight.js

View File

@@ -1,3 +1,743 @@
# 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!
As usual, the following is a summary of each of the changes since the last release.
For the full log, check out the [git log](https://github.com/helix-editor/helix/compare/22.08.1..22.12).
Breaking changes:
- Remove readline-like navigation bindings from the default insert mode keymap ([e12690e](https://github.com/helix-editor/helix/commit/e12690e), [#3811](https://github.com/helix-editor/helix/pull/3811), [#3827](https://github.com/helix-editor/helix/pull/3827), [#3915](https://github.com/helix-editor/helix/pull/3915), [#4088](https://github.com/helix-editor/helix/pull/4088))
- Rename `append_to_line` as `insert_at_line_end` and `prepend_to_line` as `insert_at_line_start` ([#3753](https://github.com/helix-editor/helix/pull/3753))
- Swap diagnostic picker and debug mode bindings in the space keymap ([#4229](https://github.com/helix-editor/helix/pull/4229))
- Select newly inserted text on paste or from shell commands ([#4458](https://github.com/helix-editor/helix/pull/4458), [#4608](https://github.com/helix-editor/helix/pull/4608), [#4619](https://github.com/helix-editor/helix/pull/4619), [#4824](https://github.com/helix-editor/helix/pull/4824))
- Select newly inserted surrounding characters on `ms<char>` ([#4752](https://github.com/helix-editor/helix/pull/4752))
- Exit select-mode after executing `replace_*` commands ([#4554](https://github.com/helix-editor/helix/pull/4554))
- Exit select-mode after executing surround commands ([#4858](https://github.com/helix-editor/helix/pull/4858))
- Change tree-sitter text-object keys ([#3782](https://github.com/helix-editor/helix/pull/3782))
- Rename `fleetish` theme to `fleet_dark` ([#4997](https://github.com/helix-editor/helix/pull/4997))
Features:
- Bufferline ([#2759](https://github.com/helix-editor/helix/pull/2759))
- Support underline styles and colors ([#4061](https://github.com/helix-editor/helix/pull/4061), [98c121c](https://github.com/helix-editor/helix/commit/98c121c))
- Inheritance for themes ([#3067](https://github.com/helix-editor/helix/pull/3067), [#4096](https://github.com/helix-editor/helix/pull/4096))
- Cursorcolumn ([#4084](https://github.com/helix-editor/helix/pull/4084))
- Overhauled system for writing files and quiting ([#2267](https://github.com/helix-editor/helix/pull/2267), [#4397](https://github.com/helix-editor/helix/pull/4397))
- Autosave when terminal loses focus ([#3178](https://github.com/helix-editor/helix/pull/3178))
- Use OSC52 as a fallback for the system clipboard ([#3220](https://github.com/helix-editor/helix/pull/3220))
- Show git diffs in the gutter ([#3890](https://github.com/helix-editor/helix/pull/3890), [#5012](https://github.com/helix-editor/helix/pull/5012), [#4995](https://github.com/helix-editor/helix/pull/4995))
- Add a logo ([dc1ec56](https://github.com/helix-editor/helix/commit/dc1ec56))
- Multi-cursor completion ([#4496](https://github.com/helix-editor/helix/pull/4496))
Commands:
- `file_picker_in_current_directory` (`<space>F`) ([#3701](https://github.com/helix-editor/helix/pull/3701))
- `:lsp-restart` to restart the current document's language server ([#3435](https://github.com/helix-editor/helix/pull/3435), [#3972](https://github.com/helix-editor/helix/pull/3972))
- `join_selections_space` (`A-j`) which joins selections and selects the joining whitespace ([#3549](https://github.com/helix-editor/helix/pull/3549))
- `:update` to write the current file if it is modified ([#4426](https://github.com/helix-editor/helix/pull/4426))
- `:lsp-workspace-command` for picking LSP commands to execute ([#3140](https://github.com/helix-editor/helix/pull/3140))
- `extend_prev_word_end` - the extend variant for `move_prev_word_end` ([7468fa2](https://github.com/helix-editor/helix/commit/7468fa2))
- `make_search_word_bounded` which adds regex word boundaries to the current search register value ([#4322](https://github.com/helix-editor/helix/pull/4322))
- `:reload-all` - `:reload` for all open buffers ([#4663](https://github.com/helix-editor/helix/pull/4663), [#4901](https://github.com/helix-editor/helix/pull/4901))
- `goto_next_change` (`]g`), `goto_prev_change` (`[g`), `goto_first_change` (`[G`), `goto_last_change` (`]G`) textobjects for jumping between VCS changes ([#4650](https://github.com/helix-editor/helix/pull/4650))
Usability improvements and fixes:
- Don't log 'LSP not defined' errors in the logfile ([1caba2d](https://github.com/helix-editor/helix/commit/1caba2d))
- Look for the external formatter program before invoking it ([#3670](https://github.com/helix-editor/helix/pull/3670))
- Don't send LSP didOpen events for documents without URLs ([44b4479](https://github.com/helix-editor/helix/commit/44b4479))
- Fix off-by-one in `extend_line_above` command ([#3689](https://github.com/helix-editor/helix/pull/3689))
- Use the original scroll offset when opening a split ([1acdfaa](https://github.com/helix-editor/helix/commit/1acdfaa))
- Handle auto-formatting failures and save the file anyway ([#3684](https://github.com/helix-editor/helix/pull/3684))
- Ensure the cursor is in view after `:reflow` ([#3733](https://github.com/helix-editor/helix/pull/3733))
- Add default rulers and reflow config for git commit messages ([#3738](https://github.com/helix-editor/helix/pull/3738))
- Improve grammar fetching and building output ([#3773](https://github.com/helix-editor/helix/pull/3773))
- Add a `text` language to language completion ([cc47d3f](https://github.com/helix-editor/helix/commit/cc47d3f))
- Improve error handling for `:set-language` ([e8add6f](https://github.com/helix-editor/helix/commit/e8add6f))
- Improve error handling for `:config-reload` ([#3668](https://github.com/helix-editor/helix/pull/3668))
- Improve error handling when passing improper ranges to syntax highlighting ([#3826](https://github.com/helix-editor/helix/pull/3826))
- Render `<code>` tags as raw markup in markdown ([#3425](https://github.com/helix-editor/helix/pull/3425))
- Remove border around the LSP code-actions popup ([#3444](https://github.com/helix-editor/helix/pull/3444))
- Canonicalize the path to the runtime directory ([#3794](https://github.com/helix-editor/helix/pull/3794))
- Add a `themelint` xtask for linting themes ([#3234](https://github.com/helix-editor/helix/pull/3234))
- Re-sort LSP diagnostics after applying transactions ([#3895](https://github.com/helix-editor/helix/pull/3895), [#4319](https://github.com/helix-editor/helix/pull/4319))
- Add a command-line flag to specify the log file ([#3807](https://github.com/helix-editor/helix/pull/3807))
- Track source and tag information in LSP diagnostics ([#3898](https://github.com/helix-editor/helix/pull/3898), [1df32c9](https://github.com/helix-editor/helix/commit/1df32c9))
- Fix theme returning to normal when exiting the `:theme` completion ([#3644](https://github.com/helix-editor/helix/pull/3644))
- Improve error messages for invalid commands in the keymap ([#3931](https://github.com/helix-editor/helix/pull/3931))
- Deduplicate regexs in `search_selection` command ([#3941](https://github.com/helix-editor/helix/pull/3941))
- Split the finding of LSP root and config roots ([#3929](https://github.com/helix-editor/helix/pull/3929))
- Ensure that the cursor is within view after auto-formatting ([#4047](https://github.com/helix-editor/helix/pull/4047))
- Add pseudo-pending to commands with on-next-key callbacks ([#4062](https://github.com/helix-editor/helix/pull/4062), [#4077](https://github.com/helix-editor/helix/pull/4077))
- Add live preview to `:goto` ([#2982](https://github.com/helix-editor/helix/pull/2982))
- Show regex compilation failure in a popup ([#3049](https://github.com/helix-editor/helix/pull/3049))
- Add 'cycled to end' and 'no more matches' for search ([#3176](https://github.com/helix-editor/helix/pull/3176), [#4101](https://github.com/helix-editor/helix/pull/4101))
- Add extending behavior to tree-sitter textobjects ([#3266](https://github.com/helix-editor/helix/pull/3266))
- Add `ui.gutter.selected` option for themes ([#3303](https://github.com/helix-editor/helix/pull/3303))
- Make statusline mode names configurable ([#3311](https://github.com/helix-editor/helix/pull/3311))
- Add a statusline element for total line count ([#3960](https://github.com/helix-editor/helix/pull/3960))
- Add extending behavior to `goto_window_*` commands ([#3985](https://github.com/helix-editor/helix/pull/3985))
- Fix a panic in signature help when the preview is too large ([#4030](https://github.com/helix-editor/helix/pull/4030))
- Add command names to the command palette ([#4071](https://github.com/helix-editor/helix/pull/4071), [#4223](https://github.com/helix-editor/helix/pull/4223), [#4495](https://github.com/helix-editor/helix/pull/4495))
- Find the LSP workspace root from the current document's path ([#3553](https://github.com/helix-editor/helix/pull/3553))
- Add an option to skip indent-guide levels ([#3819](https://github.com/helix-editor/helix/pull/3819), [2c36e33](https://github.com/helix-editor/helix/commit/2c36e33))
- Change focus to modified docs on quit ([#3872](https://github.com/helix-editor/helix/pull/3872))
- Respond to `USR1` signal by reloading config ([#3952](https://github.com/helix-editor/helix/pull/3952))
- Exit gracefully when the close operation fails ([#4081](https://github.com/helix-editor/helix/pull/4081))
- Fix goto/view center mismatch ([#4135](https://github.com/helix-editor/helix/pull/4135))
- Highlight the current file picker document on idle-timeout ([#3172](https://github.com/helix-editor/helix/pull/3172), [a85e386](https://github.com/helix-editor/helix/commit/a85e386))
- Apply transactions to jumplist selections ([#4186](https://github.com/helix-editor/helix/pull/4186), [#4227](https://github.com/helix-editor/helix/pull/4227), [#4733](https://github.com/helix-editor/helix/pull/4733), [#4865](https://github.com/helix-editor/helix/pull/4865), [#4912](https://github.com/helix-editor/helix/pull/4912), [#4965](https://github.com/helix-editor/helix/pull/4965), [#4981](https://github.com/helix-editor/helix/pull/4981))
- Use space as a separator for fuzzy matcher ([#3969](https://github.com/helix-editor/helix/pull/3969))
- Overlay all diagnostics with highest severity on top ([#4113](https://github.com/helix-editor/helix/pull/4113))
- Avoid re-parsing unmodified tree-sitter injections ([#4146](https://github.com/helix-editor/helix/pull/4146))
- Add extending captures for indentation, re-enable python indentation ([#3382](https://github.com/helix-editor/helix/pull/3382), [3e84434](https://github.com/helix-editor/helix/commit/3e84434))
- Only allow either `--vsplit` or `--hsplit` CLI flags at once ([#4202](https://github.com/helix-editor/helix/pull/4202))
- Fix append cursor location when selection anchor is at the end of the document ([#4147](https://github.com/helix-editor/helix/pull/4147))
- Improve selection yanking message ([#4275](https://github.com/helix-editor/helix/pull/4275))
- Log failures to load tree-sitter grammars as errors ([#4315](https://github.com/helix-editor/helix/pull/4315))
- Fix rendering of lines longer than 65,536 columns ([#4172](https://github.com/helix-editor/helix/pull/4172))
- Skip searching `.git` in `global_search` ([#4334](https://github.com/helix-editor/helix/pull/4334))
- Display tree-sitter scopes in a popup ([#4337](https://github.com/helix-editor/helix/pull/4337))
- Fix deleting a word from the end of the buffer ([#4328](https://github.com/helix-editor/helix/pull/4328))
- Pretty print the syntax tree in `:tree-sitter-subtree` ([#4295](https://github.com/helix-editor/helix/pull/4295), [#4606](https://github.com/helix-editor/helix/pull/4606))
- Allow specifying suffixes for file-type detection ([#2455](https://github.com/helix-editor/helix/pull/2455), [#4414](https://github.com/helix-editor/helix/pull/4414))
- Fix multi-byte auto-pairs ([#4024](https://github.com/helix-editor/helix/pull/4024))
- Improve sort scoring for LSP code-actions and completions ([#4134](https://github.com/helix-editor/helix/pull/4134))
- Fix the handling of quotes within shellwords ([#4098](https://github.com/helix-editor/helix/pull/4098))
- Fix `delete_word_backward` and `delete_word_forward` on newlines ([#4392](https://github.com/helix-editor/helix/pull/4392))
- Fix 'no entry found for key' crash on `:write-all` ([#4384](https://github.com/helix-editor/helix/pull/4384))
- Remove lowercase requirement for tree-sitter grammars ([#4346](https://github.com/helix-editor/helix/pull/4346))
- Resolve LSP completion items on idle-timeout ([#4406](https://github.com/helix-editor/helix/pull/4406), [#4797](https://github.com/helix-editor/helix/pull/4797))
- Render diagnostics in the file picker preview ([#4324](https://github.com/helix-editor/helix/pull/4324))
- Fix terminal freezing on `shell_insert_output` ([#4156](https://github.com/helix-editor/helix/pull/4156))
- Allow use of the count in the repeat operator (`.`) ([#4450](https://github.com/helix-editor/helix/pull/4450))
- Show the current theme name on `:theme` with no arguments ([#3740](https://github.com/helix-editor/helix/pull/3740))
- Fix rendering in very large terminals ([#4318](https://github.com/helix-editor/helix/pull/4318))
- Sort LSP preselected items to the top of the completion menu ([#4480](https://github.com/helix-editor/helix/pull/4480))
- Trim braces and quotes from paths in goto-file ([#4370](https://github.com/helix-editor/helix/pull/4370))
- Prevent automatic signature help outside of insert mode ([#4456](https://github.com/helix-editor/helix/pull/4456))
- Fix freezes with external programs that process stdin and stdout concurrently ([#4180](https://github.com/helix-editor/helix/pull/4180))
- Make `scroll` aware of tabs and wide characters ([#4519](https://github.com/helix-editor/helix/pull/4519))
- Correctly handle escaping in `command_mode` completion ([#4316](https://github.com/helix-editor/helix/pull/4316), [#4587](https://github.com/helix-editor/helix/pull/4587), [#4632](https://github.com/helix-editor/helix/pull/4632))
- Fix `delete_char_backward` for paired characters ([#4558](https://github.com/helix-editor/helix/pull/4558))
- Fix crash from two windows editing the same document ([#4570](https://github.com/helix-editor/helix/pull/4570))
- Fix pasting from the blackhole register ([#4497](https://github.com/helix-editor/helix/pull/4497))
- Support LSP insertReplace completion items ([1312682](https://github.com/helix-editor/helix/commit/1312682))
- Dynamically resize the line number gutter width ([#3469](https://github.com/helix-editor/helix/pull/3469))
- Fix crash for unknown completion item kinds ([#4658](https://github.com/helix-editor/helix/pull/4658))
- Re-enable `format_selections` for single selection ranges ([d4f5cab](https://github.com/helix-editor/helix/commit/d4f5cab))
- Limit the number of in-progress tree-sitter query matches ([#4707](https://github.com/helix-editor/helix/pull/4707), [#4830](https://github.com/helix-editor/helix/pull/4830))
- Use the special `#` register with `increment`/`decrement` to change by range number ([#4418](https://github.com/helix-editor/helix/pull/4418))
- Add a statusline element to show number of selected chars ([#4682](https://github.com/helix-editor/helix/pull/4682))
- Add a statusline element showing global LSP diagnostic warning and error counts ([#4569](https://github.com/helix-editor/helix/pull/4569))
- Add a scrollbar to popups ([#4449](https://github.com/helix-editor/helix/pull/4449))
- Prefer shorter matches in fuzzy matcher scoring ([#4698](https://github.com/helix-editor/helix/pull/4698))
- Use key-sequence format for command palette keybinds ([#4712](https://github.com/helix-editor/helix/pull/4712))
- Remove prefix filtering from autocompletion menu ([#4578](https://github.com/helix-editor/helix/pull/4578))
- Focus on the parent buffer when closing a split ([#4766](https://github.com/helix-editor/helix/pull/4766))
- Handle language server termination ([#4797](https://github.com/helix-editor/helix/pull/4797), [#4852](https://github.com/helix-editor/helix/pull/4852))
- Allow `r`/`t`/`f` to work on tab characters ([#4817](https://github.com/helix-editor/helix/pull/4817))
- Show a preview for scratch buffers in the buffer picker ([#3454](https://github.com/helix-editor/helix/pull/3454))
- Set a limit of entries in the jumplist ([#4750](https://github.com/helix-editor/helix/pull/4750))
- Re-use shell outputs when inserting or appending shell output ([#3465](https://github.com/helix-editor/helix/pull/3465))
- Check LSP server provider capabilities ([#3554](https://github.com/helix-editor/helix/pull/3554))
- Improve tree-sitter parsing performance on files with many language layers ([#4716](https://github.com/helix-editor/helix/pull/4716))
- Move indentation to the next line when using `<ret>` on a line with only whitespace ([#4854](https://github.com/helix-editor/helix/pull/4854))
- Remove selections for closed views from all documents ([#4888](https://github.com/helix-editor/helix/pull/4888))
- Improve performance of the `:reload` command ([#4457](https://github.com/helix-editor/helix/pull/4457))
- Properly handle media keys ([#4887](https://github.com/helix-editor/helix/pull/4887))
- Support LSP diagnostic data field ([#4935](https://github.com/helix-editor/helix/pull/4935))
- Handle C-i keycode as tab ([#4961](https://github.com/helix-editor/helix/pull/4961))
- Fix view alignment for jumplist picker jumps ([#3743](https://github.com/helix-editor/helix/pull/3743))
- Use OSC52 for tmux clipboard provider ([#5027](https://github.com/helix-editor/helix/pull/5027))
Themes:
- Add `varua` ([#3610](https://github.com/helix-editor/helix/pull/3610), [#4964](https://github.com/helix-editor/helix/pull/4964))
- Update `boo_berry` ([#3653](https://github.com/helix-editor/helix/pull/3653))
- Add `rasmus` ([#3728](https://github.com/helix-editor/helix/pull/3728))
- Add `papercolor_dark` ([#3742](https://github.com/helix-editor/helix/pull/3742))
- Update `monokai_pro_spectrum` ([#3814](https://github.com/helix-editor/helix/pull/3814))
- Update `nord` ([#3792](https://github.com/helix-editor/helix/pull/3792))
- Update `fleetish` ([#3844](https://github.com/helix-editor/helix/pull/3844), [#4487](https://github.com/helix-editor/helix/pull/4487), [#4813](https://github.com/helix-editor/helix/pull/4813))
- Update `flatwhite` ([#3843](https://github.com/helix-editor/helix/pull/3843))
- Add `darcula` ([#3739](https://github.com/helix-editor/helix/pull/3739))
- Update `papercolor` ([#3938](https://github.com/helix-editor/helix/pull/3938), [#4317](https://github.com/helix-editor/helix/pull/4317))
- Add bufferline colors to multiple themes ([#3881](https://github.com/helix-editor/helix/pull/3881))
- Add `gruvbox_dark_hard` ([#3948](https://github.com/helix-editor/helix/pull/3948))
- Add `onedarker` ([#3980](https://github.com/helix-editor/helix/pull/3980), [#4060](https://github.com/helix-editor/helix/pull/4060))
- Add `dark_high_contrast` ([#3312](https://github.com/helix-editor/helix/pull/3312))
- Update `bogster` ([#4121](https://github.com/helix-editor/helix/pull/4121), [#4264](https://github.com/helix-editor/helix/pull/4264))
- Update `sonokai` ([#4089](https://github.com/helix-editor/helix/pull/4089))
- Update `ayu_*` themes ([#4140](https://github.com/helix-editor/helix/pull/4140), [#4109](https://github.com/helix-editor/helix/pull/4109), [#4662](https://github.com/helix-editor/helix/pull/4662), [#4764](https://github.com/helix-editor/helix/pull/4764))
- Update `everforest` ([#3998](https://github.com/helix-editor/helix/pull/3998))
- Update `monokai_pro_octagon` ([#4247](https://github.com/helix-editor/helix/pull/4247))
- Add `heisenberg` ([#4209](https://github.com/helix-editor/helix/pull/4209))
- Add `bogster_light` ([#4265](https://github.com/helix-editor/helix/pull/4265))
- Update `pop-dark` ([#4323](https://github.com/helix-editor/helix/pull/4323))
- Update `rose_pine` ([#4221](https://github.com/helix-editor/helix/pull/4221))
- Add `kanagawa` ([#4300](https://github.com/helix-editor/helix/pull/4300))
- Add `hex_steel`, `hex_toxic` and `hex_lavendar` ([#4367](https://github.com/helix-editor/helix/pull/4367), [#4990](https://github.com/helix-editor/helix/pull/4990))
- Update `tokyonight` and `tokyonight_storm` ([#4415](https://github.com/helix-editor/helix/pull/4415))
- Update `gruvbox` ([#4626](https://github.com/helix-editor/helix/pull/4626))
- Update `dark_plus` ([#4661](https://github.com/helix-editor/helix/pull/4661), [#4678](https://github.com/helix-editor/helix/pull/4678))
- Add `zenburn` ([#4613](https://github.com/helix-editor/helix/pull/4613), [#4977](https://github.com/helix-editor/helix/pull/4977))
- Update `monokai_pro` ([#4789](https://github.com/helix-editor/helix/pull/4789))
- Add `mellow` ([#4770](https://github.com/helix-editor/helix/pull/4770))
- Add `nightfox` ([#4769](https://github.com/helix-editor/helix/pull/4769), [#4966](https://github.com/helix-editor/helix/pull/4966))
- Update `doom_acario_dark` ([#4979](https://github.com/helix-editor/helix/pull/4979))
- Update `autumn` ([#4996](https://github.com/helix-editor/helix/pull/4996))
- Update `acme` ([#4999](https://github.com/helix-editor/helix/pull/4999))
- Update `nord_light` ([#4999](https://github.com/helix-editor/helix/pull/4999))
- Update `serika_*` ([#5015](https://github.com/helix-editor/helix/pull/5015))
LSP configurations:
- Switch to `openscad-lsp` for OpenScad ([#3750](https://github.com/helix-editor/helix/pull/3750))
- Support Jsonnet ([#3748](https://github.com/helix-editor/helix/pull/3748))
- Support Markdown ([#3499](https://github.com/helix-editor/helix/pull/3499))
- Support Bass ([#3771](https://github.com/helix-editor/helix/pull/3771))
- Set roots configuration for Elixir and HEEx ([#3917](https://github.com/helix-editor/helix/pull/3917), [#3959](https://github.com/helix-editor/helix/pull/3959))
- Support Purescript ([#4242](https://github.com/helix-editor/helix/pull/4242))
- Set roots configuration for Julia ([#4361](https://github.com/helix-editor/helix/pull/4361))
- Support D ([#4372](https://github.com/helix-editor/helix/pull/4372))
- Increase default language server timeout for Julia ([#4575](https://github.com/helix-editor/helix/pull/4575))
- Use ElixirLS for HEEx ([#4679](https://github.com/helix-editor/helix/pull/4679))
- Support Bicep ([#4403](https://github.com/helix-editor/helix/pull/4403))
- Switch to `nil` for Nix ([433ccef](https://github.com/helix-editor/helix/commit/433ccef))
- Support QML ([#4842](https://github.com/helix-editor/helix/pull/4842))
- Enable auto-format for CSS ([#4987](https://github.com/helix-editor/helix/pull/4987))
- Support CommonLisp ([4176769](https://github.com/helix-editor/helix/commit/4176769))
New languages:
- SML ([#3692](https://github.com/helix-editor/helix/pull/3692))
- Jsonnet ([#3714](https://github.com/helix-editor/helix/pull/3714))
- Godot resource ([#3759](https://github.com/helix-editor/helix/pull/3759))
- Astro ([#3829](https://github.com/helix-editor/helix/pull/3829))
- SSH config ([#2455](https://github.com/helix-editor/helix/pull/2455), [#4538](https://github.com/helix-editor/helix/pull/4538))
- Bass ([#3771](https://github.com/helix-editor/helix/pull/3771))
- WAT (WebAssembly text format) ([#4040](https://github.com/helix-editor/helix/pull/4040), [#4542](https://github.com/helix-editor/helix/pull/4542))
- Purescript ([#4242](https://github.com/helix-editor/helix/pull/4242))
- D ([#4372](https://github.com/helix-editor/helix/pull/4372), [#4562](https://github.com/helix-editor/helix/pull/4562))
- VHS ([#4486](https://github.com/helix-editor/helix/pull/4486))
- KDL ([#4481](https://github.com/helix-editor/helix/pull/4481))
- XML ([#4518](https://github.com/helix-editor/helix/pull/4518))
- WIT ([#4525](https://github.com/helix-editor/helix/pull/4525))
- ENV ([#4536](https://github.com/helix-editor/helix/pull/4536))
- INI ([#4538](https://github.com/helix-editor/helix/pull/4538))
- Bicep ([#4403](https://github.com/helix-editor/helix/pull/4403), [#4751](https://github.com/helix-editor/helix/pull/4751))
- QML ([#4842](https://github.com/helix-editor/helix/pull/4842))
- CommonLisp ([4176769](https://github.com/helix-editor/helix/commit/4176769))
Updated languages and queries:
- Zig ([#3621](https://github.com/helix-editor/helix/pull/3621), [#4745](https://github.com/helix-editor/helix/pull/4745))
- Rust ([#3647](https://github.com/helix-editor/helix/pull/3647), [#3729](https://github.com/helix-editor/helix/pull/3729), [#3927](https://github.com/helix-editor/helix/pull/3927), [#4073](https://github.com/helix-editor/helix/pull/4073), [#4510](https://github.com/helix-editor/helix/pull/4510), [#4659](https://github.com/helix-editor/helix/pull/4659), [#4717](https://github.com/helix-editor/helix/pull/4717))
- Solidity ([20ed8c2](https://github.com/helix-editor/helix/commit/20ed8c2))
- Fish ([#3704](https://github.com/helix-editor/helix/pull/3704))
- Elixir ([#3645](https://github.com/helix-editor/helix/pull/3645), [#4333](https://github.com/helix-editor/helix/pull/4333), [#4821](https://github.com/helix-editor/helix/pull/4821))
- Diff ([#3708](https://github.com/helix-editor/helix/pull/3708))
- Nix ([665e27f](https://github.com/helix-editor/helix/commit/665e27f), [1fe3273](https://github.com/helix-editor/helix/commit/1fe3273))
- Markdown ([#3749](https://github.com/helix-editor/helix/pull/3749), [#4078](https://github.com/helix-editor/helix/pull/4078), [#4483](https://github.com/helix-editor/helix/pull/4483), [#4478](https://github.com/helix-editor/helix/pull/4478))
- GDScript ([#3760](https://github.com/helix-editor/helix/pull/3760))
- JSX and TSX ([#3853](https://github.com/helix-editor/helix/pull/3853), [#3973](https://github.com/helix-editor/helix/pull/3973))
- Ruby ([#3976](https://github.com/helix-editor/helix/pull/3976), [#4601](https://github.com/helix-editor/helix/pull/4601))
- R ([#4031](https://github.com/helix-editor/helix/pull/4031))
- WGSL ([#3996](https://github.com/helix-editor/helix/pull/3996), [#4079](https://github.com/helix-editor/helix/pull/4079))
- C# ([#4118](https://github.com/helix-editor/helix/pull/4118), [#4281](https://github.com/helix-editor/helix/pull/4281), [#4213](https://github.com/helix-editor/helix/pull/4213))
- Twig ([#4176](https://github.com/helix-editor/helix/pull/4176))
- Lua ([#3552](https://github.com/helix-editor/helix/pull/3552))
- C/C++ ([#4079](https://github.com/helix-editor/helix/pull/4079), [#4278](https://github.com/helix-editor/helix/pull/4278), [#4282](https://github.com/helix-editor/helix/pull/4282))
- Cairo ([17488f1](https://github.com/helix-editor/helix/commit/17488f1), [431f9c1](https://github.com/helix-editor/helix/commit/431f9c1), [09a6df1](https://github.com/helix-editor/helix/commit/09a6df1))
- Rescript ([#4356](https://github.com/helix-editor/helix/pull/4356))
- Zig ([#4409](https://github.com/helix-editor/helix/pull/4409))
- Scala ([#4353](https://github.com/helix-editor/helix/pull/4353), [#4697](https://github.com/helix-editor/helix/pull/4697), [#4701](https://github.com/helix-editor/helix/pull/4701))
- LaTeX ([#4528](https://github.com/helix-editor/helix/pull/4528), [#4922](https://github.com/helix-editor/helix/pull/4922))
- SQL ([#4529](https://github.com/helix-editor/helix/pull/4529))
- Python ([#4560](https://github.com/helix-editor/helix/pull/4560))
- Bash/Zsh ([#4582](https://github.com/helix-editor/helix/pull/4582))
- Nu ([#4583](https://github.com/helix-editor/helix/pull/4583))
- Julia ([#4588](https://github.com/helix-editor/helix/pull/4588))
- Typescript ([#4703](https://github.com/helix-editor/helix/pull/4703))
- Meson ([#4572](https://github.com/helix-editor/helix/pull/4572))
- Haskell ([#4800](https://github.com/helix-editor/helix/pull/4800))
- CMake ([#4809](https://github.com/helix-editor/helix/pull/4809))
- HTML ([#4829](https://github.com/helix-editor/helix/pull/4829), [#4881](https://github.com/helix-editor/helix/pull/4881))
- Java ([#4886](https://github.com/helix-editor/helix/pull/4886))
- Go ([#4906](https://github.com/helix-editor/helix/pull/4906), [#4969](https://github.com/helix-editor/helix/pull/4969), [#5010](https://github.com/helix-editor/helix/pull/5010))
- CSS ([#4882](https://github.com/helix-editor/helix/pull/4882))
- Racket ([#4915](https://github.com/helix-editor/helix/pull/4915))
- SCSS ([#5003](https://github.com/helix-editor/helix/pull/5003))
Packaging:
- Filter relevant source files in the Nix flake ([#3657](https://github.com/helix-editor/helix/pull/3657))
- Build a binary for `aarch64-linux` in the release CI ([038a91d](https://github.com/helix-editor/helix/commit/038a91d))
- Build an AppImage for `aarch64-linux` in the release CI ([b738031](https://github.com/helix-editor/helix/commit/b738031))
- Enable CI builds for `riscv64-linux` ([#3685](https://github.com/helix-editor/helix/pull/3685))
- Support preview releases in CI ([0090a2d](https://github.com/helix-editor/helix/commit/0090a2d))
- Strip binaries built in CI ([#3780](https://github.com/helix-editor/helix/pull/3780))
- Fix the development shell for the Nix Flake on `aarch64-darwin` ([#3810](https://github.com/helix-editor/helix/pull/3810))
- Raise the MSRV and create an MSRV policy ([#3896](https://github.com/helix-editor/helix/pull/3896), [#3913](https://github.com/helix-editor/helix/pull/3913), [#3961](https://github.com/helix-editor/helix/pull/3961))
- Fix Fish completions for `--config` and `--log` flags ([#3912](https://github.com/helix-editor/helix/pull/3912))
- Use builtin filenames option in Bash completion ([#4648](https://github.com/helix-editor/helix/pull/4648))
# 22.08.1 (2022-09-01)
This is a patch release that fixes a panic caused by closing splits or buffers. ([#3633](https://github.com/helix-editor/helix/pull/3633))
# 22.08 (2022-08-31)
A big _thank you_ to our contributors! This release had 87 contributors.
As usual, the following is a summary of each of the changes since the last release.
For the full log, check out the [git log](https://github.com/helix-editor/helix/compare/22.05..22.08).
Breaking changes:
- Special keymap names for `+`, `;` and `%` have been replaced with those literal characters ([#2677](https://github.com/helix-editor/helix/pull/2677), [#3556](https://github.com/helix-editor/helix/pull/3556))
- `A-Left` and `A-Right` have become `C-Left` and `C-Right` for word-wise motion ([#2500](https://github.com/helix-editor/helix/pull/2500))
- The `catppuccin` theme's name has been corrected from `catpuccin` ([#2713](https://github.com/helix-editor/helix/pull/2713))
- `catppuccin` has been replaced by its variants, `catppuccin_frappe`, `catppuccin_latte`, `catppuccin_macchiato`, `catppuccin_mocha` ([#3281](https://github.com/helix-editor/helix/pull/3281))
- `C-n` and `C-p` have been removed from the default insert mode keymap ([#3340](https://github.com/helix-editor/helix/pull/3340))
- The `extend_line` command has been replaced with `extend_line_below` and a new `extend_line` command now exists ([#3046](https://github.com/helix-editor/helix/pull/3046))
Features:
- Add an integration testing harness ([#2359](https://github.com/helix-editor/helix/pull/2359))
- Indent guides ([#1796](https://github.com/helix-editor/helix/pull/1796), [906259c](https://github.com/helix-editor/helix/commit/906259c))
- Cursorline ([#2170](https://github.com/helix-editor/helix/pull/2170), [fde9e03](https://github.com/helix-editor/helix/commit/fde9e03))
- Select all instances of the symbol under the cursor (`<space>h`) ([#2738](https://github.com/helix-editor/helix/pull/2738))
- A picker for document and workspace LSP diagnostics (`<space>g`/`<space>G`) ([#2013](https://github.com/helix-editor/helix/pull/2013), [#2984](https://github.com/helix-editor/helix/pull/2984))
- Allow styling the mode indicator per-mode ([#2676](https://github.com/helix-editor/helix/pull/2676))
- Live preview for the theme picker ([#1798](https://github.com/helix-editor/helix/pull/1798))
- Configurable statusline ([#2434](https://github.com/helix-editor/helix/pull/2434))
- LSP SignatureHelp ([#1755](https://github.com/helix-editor/helix/pull/1755), [a8b123f](https://github.com/helix-editor/helix/commit/a8b123f))
- A picker for the jumplist ([#3033](https://github.com/helix-editor/helix/pull/3033))
- Configurable external formatter binaries ([#2942](https://github.com/helix-editor/helix/pull/2942))
- Bracketed paste support ([#3233](https://github.com/helix-editor/helix/pull/3233), [12ddd03](https://github.com/helix-editor/helix/commit/12ddd03))
Commands:
- `:insert-output` and `:append-output` which insert/append output from a shell command ([#2589](https://github.com/helix-editor/helix/pull/2589))
- The `t` textobject (`]t`/`[t`/`mit`/`mat`) for navigating tests ([#2807](https://github.com/helix-editor/helix/pull/2807))
- `C-Backspace` and `C-Delete` for word-wise deletion in prompts and pickers ([#2500](https://github.com/helix-editor/helix/pull/2500))
- `A-Delete` for forward word-wise deletion in insert mode ([#2500](https://github.com/helix-editor/helix/pull/2500))
- `C-t` for toggling the preview pane in pickers ([#3021](https://github.com/helix-editor/helix/pull/3021))
- `extend_line` now extends in the direction of the cursor ([#3046](https://github.com/helix-editor/helix/pull/3046))
Usability improvements and fixes:
- Fix tree-sitter parser builds on illumos ([#2602](https://github.com/helix-editor/helix/pull/2602))
- Remove empty stratch buffer from jumplists when removing ([5ed6223](https://github.com/helix-editor/helix/commit/5ed6223))
- Fix panic on undo after `shell_append_output` ([#2625](https://github.com/helix-editor/helix/pull/2625))
- Sort LSP edits by start range ([3d91c99](https://github.com/helix-editor/helix/commit/3d91c99))
- Be more defensive about LSP URI conversions ([6de6a3e](https://github.com/helix-editor/helix/commit/6de6a3e), [378f438](https://github.com/helix-editor/helix/commit/378f438))
- Ignore SendErrors when grammar builds fail ([#2641](https://github.com/helix-editor/helix/pull/2641))
- Append `set_line_ending` to document history ([#2649](https://github.com/helix-editor/helix/pull/2649))
- Use last prompt entry when empty ([b14c258](https://github.com/helix-editor/helix/commit/b14c258), [#2870](https://github.com/helix-editor/helix/pull/2870))
- Do not add extra line breaks in markdown lists ([#2689](https://github.com/helix-editor/helix/pull/2689))
- Disable dialyzer by default for ElixirLS ([#2710](https://github.com/helix-editor/helix/pull/2710))
- Refactor textobject node capture ([#2741](https://github.com/helix-editor/helix/pull/2741))
- Prevent re-selecting the same range with `expand_selection` ([#2760](https://github.com/helix-editor/helix/pull/2760))
- Introduce `keyword.storage` highlight scope ([#2731](https://github.com/helix-editor/helix/pull/2731))
- Handle symlinks more consistently ([#2718](https://github.com/helix-editor/helix/pull/2718))
- Improve markdown list rendering ([#2687](https://github.com/helix-editor/helix/pull/2687))
- Update auto-pairs and idle-timout settings when the config is reloaded ([#2736](https://github.com/helix-editor/helix/pull/2736))
- Fix panic on closing last buffer ([#2658](https://github.com/helix-editor/helix/pull/2658))
- Prevent modifying jumplist until jumping to a reference ([#2670](https://github.com/helix-editor/helix/pull/2670))
- Ensure `:quit` and `:quit!` take no arguments ([#2654](https://github.com/helix-editor/helix/pull/2654))
- Fix crash due to cycles when replaying macros ([#2647](https://github.com/helix-editor/helix/pull/2647))
- Pass LSP FormattingOptions ([#2635](https://github.com/helix-editor/helix/pull/2635))
- Prevent showing colors when the health-check is piped ([#2836](https://github.com/helix-editor/helix/pull/2836))
- Use character indexing for mouse selection ([#2839](https://github.com/helix-editor/helix/pull/2839))
- Display the highest severity diagnostic for a line in the gutter ([#2835](https://github.com/helix-editor/helix/pull/2835))
- Default the ruler color to red background ([#2669](https://github.com/helix-editor/helix/pull/2669))
- Make `move_vertically` aware of tabs and wide characters ([#2620](https://github.com/helix-editor/helix/pull/2620))
- Enable shellwords for Windows ([#2767](https://github.com/helix-editor/helix/pull/2767))
- Add history suggestions to global search ([#2717](https://github.com/helix-editor/helix/pull/2717))
- Fix the scrollbar's length proportional to total menu items ([#2860](https://github.com/helix-editor/helix/pull/2860))
- Reset terminal modifiers for diagnostic text ([#2861](https://github.com/helix-editor/helix/pull/2861), [#2900](https://github.com/helix-editor/helix/pull/2900))
- Redetect indents and line-endings after a Language Server replaces the document ([#2778](https://github.com/helix-editor/helix/pull/2778))
- Check selection's visible width when copying on mouse click ([#2711](https://github.com/helix-editor/helix/pull/2711))
- Fix edge-case in tree-sitter `expand_selection` command ([#2877](https://github.com/helix-editor/helix/pull/2877))
- Add a single-width left margin for the completion popup ([#2728](https://github.com/helix-editor/helix/pull/2728))
- Right-align the scrollbar in the completion popup ([#2754](https://github.com/helix-editor/helix/pull/2754))
- Fix recursive macro crash and empty macro lockout ([#2902](https://github.com/helix-editor/helix/pull/2902))
- Fix backwards character deletion on other whitespaces ([#2855](https://github.com/helix-editor/helix/pull/2855))
- Add search and space/backspace bindings to view modes ([#2803](https://github.com/helix-editor/helix/pull/2803))
- Add `--vsplit` and `--hsplit` CLI arguments for opening in splits ([#2773](https://github.com/helix-editor/helix/pull/2773), [#3073](https://github.com/helix-editor/helix/pull/3073))
- Sort themes, languages and files inputs by score and name ([#2675](https://github.com/helix-editor/helix/pull/2675))
- Highlight entire rows in ([#2939](https://github.com/helix-editor/helix/pull/2939))
- Fix backwards selection duplication widening bug ([#2945](https://github.com/helix-editor/helix/pull/2945), [#3024](https://github.com/helix-editor/helix/pull/3024))
- Skip serializing Option type DAP fields ([44f5963](https://github.com/helix-editor/helix/commit/44f5963))
- Fix required `cwd` field in DAP `RunTerminalArguments` type ([85411be](https://github.com/helix-editor/helix/commit/85411be), [#3240](https://github.com/helix-editor/helix/pull/3240))
- Add LSP `workspace/applyEdit` to client capabilities ([#3012](https://github.com/helix-editor/helix/pull/3012))
- Respect count for repeating motion ([#3057](https://github.com/helix-editor/helix/pull/3057))
- Respect count for selecting next/previous match ([#3056](https://github.com/helix-editor/helix/pull/3056))
- Respect count for tree-sitter motions ([#3058](https://github.com/helix-editor/helix/pull/3058))
- Make gutters padding optional ([#2996](https://github.com/helix-editor/helix/pull/2996))
- Support pre-filling prompts ([#2459](https://github.com/helix-editor/helix/pull/2459), [#3259](https://github.com/helix-editor/helix/pull/3259))
- Add statusline element to display file line-endings ([#3113](https://github.com/helix-editor/helix/pull/3113))
- Keep jump and file history when using `:split` ([#3031](https://github.com/helix-editor/helix/pull/3031), [#3160](https://github.com/helix-editor/helix/pull/3160))
- Make tree-sitter query `; inherits <language>` feature imperative ([#2470](https://github.com/helix-editor/helix/pull/2470))
- Indent with tabs by default ([#3095](https://github.com/helix-editor/helix/pull/3095))
- Fix non-msvc grammar compilation on Windows ([#3190](https://github.com/helix-editor/helix/pull/3190))
- Add spacer element to the statusline ([#3165](https://github.com/helix-editor/helix/pull/3165), [255c173](https://github.com/helix-editor/helix/commit/255c173))
- Make gutters padding automatic ([#3163](https://github.com/helix-editor/helix/pull/3163))
- Add `code` for LSP `Diagnostic` type ([#3096](https://github.com/helix-editor/helix/pull/3096))
- Add position percentage to the statusline ([#3168](https://github.com/helix-editor/helix/pull/3168))
- Add a configurable and themable statusline separator string ([#3175](https://github.com/helix-editor/helix/pull/3175))
- Use OR of all selections when `search_selection` acts on multiple selections ([#3138](https://github.com/helix-editor/helix/pull/3138))
- Add clipboard information to logs and the healthcheck ([#3271](https://github.com/helix-editor/helix/pull/3271))
- Fix align selection behavior on tabs ([#3276](https://github.com/helix-editor/helix/pull/3276))
- Fix terminal cursor shape reset ([#3289](https://github.com/helix-editor/helix/pull/3289))
- Add an `injection.include-unnamed-children` predicate to injections queries ([#3129](https://github.com/helix-editor/helix/pull/3129))
- Add a `-c`/`--config` CLI flag for specifying config file location ([#2666](https://github.com/helix-editor/helix/pull/2666))
- Detect indent-style in `:set-language` command ([#3330](https://github.com/helix-editor/helix/pull/3330))
- Fix non-deterministic highlighting ([#3275](https://github.com/helix-editor/helix/pull/3275))
- Avoid setting the stdin handle when not necessary ([#3248](https://github.com/helix-editor/helix/pull/3248), [#3379](https://github.com/helix-editor/helix/pull/3379))
- Fix indent guide styling ([#3324](https://github.com/helix-editor/helix/pull/3324))
- Fix tab highlight when tab is partially visible ([#3313](https://github.com/helix-editor/helix/pull/3313))
- Add completion for nested settings ([#3183](https://github.com/helix-editor/helix/pull/3183))
- Advertise WorkspaceSymbolClientCapabilities LSP client capability ([#3361](https://github.com/helix-editor/helix/pull/3361))
- Remove duplicate entries from the theme picker ([#3439](https://github.com/helix-editor/helix/pull/3439))
- Shorted output for grammar fetching and building ([#3396](https://github.com/helix-editor/helix/pull/3396))
- Add a `tabpad` option for visible tab padding whitespace characters ([#3458](https://github.com/helix-editor/helix/pull/3458))
- Make DAP external terminal provider configurable ([cb7615e](https://github.com/helix-editor/helix/commit/cb7615e))
- Use health checkmark character with shorter width ([#3505](https://github.com/helix-editor/helix/pull/3505))
- Reset document mode to normal on view focus loss ([e4c9d40](https://github.com/helix-editor/helix/commit/e4c9d40))
- Render indented code-blocks in markdown ([#3503](https://github.com/helix-editor/helix/pull/3503))
- Add WezTerm to DAP terminal provider defaults ([#3588](https://github.com/helix-editor/helix/pull/3588))
- Derive `Document` language name from `languages.toml` `name` key ([#3338](https://github.com/helix-editor/helix/pull/3338))
- Fix process spawning error handling ([#3349](https://github.com/helix-editor/helix/pull/3349))
- Don't resolve links for `:o` completion ([8a4fbf6](https://github.com/helix-editor/helix/commit/8a4fbf6))
- Recalculate completion after pasting into prompt ([e77b7d1](https://github.com/helix-editor/helix/commit/e77b7d1))
- Fix extra selections with regex anchors ([#3598](https://github.com/helix-editor/helix/pull/3598))
- Move mode transition logic to `handle_keymap_event` ([#2634](https://github.com/helix-editor/helix/pull/2634))
- Add documents to view history when using the jumplist ([#3593](https://github.com/helix-editor/helix/pull/3593))
- Prevent panic when loading tree-sitter queries ([fa1dc7e](https://github.com/helix-editor/helix/commit/fa1dc7e))
- Discard LSP publishDiagnostic when LS is not initialized ([#3403](https://github.com/helix-editor/helix/pull/3403))
- Refactor tree-sitter textobject motions as repeatable motions ([#3264](https://github.com/helix-editor/helix/pull/3264))
- Avoid command execution hooks on closed docs ([#3613](https://github.com/helix-editor/helix/pull/3613))
- Share `restore_term` code between panic and normal exits ([#2612](https://github.com/helix-editor/helix/pull/2612))
- Show clipboard info in `--health` output ([#2947](https://github.com/helix-editor/helix/pull/2947))
- Recalculate completion when going through prompt history ([#3193](https://github.com/helix-editor/helix/pull/3193))
Themes:
- Update `tokyonight` and `tokyonight_storm` themes ([#2606](https://github.com/helix-editor/helix/pull/2606))
- Update `solarized_light` themes ([#2626](https://github.com/helix-editor/helix/pull/2626))
- Fix `catpuccin` `ui.popup` theme ([#2644](https://github.com/helix-editor/helix/pull/2644))
- Update selection style of `night_owl` ([#2668](https://github.com/helix-editor/helix/pull/2668))
- Fix spelling of `catppuccin` theme ([#2713](https://github.com/helix-editor/helix/pull/2713))
- Update `base16_default`'s `ui.menu` ([#2794](https://github.com/helix-editor/helix/pull/2794))
- Add `noctis_bordo` ([#2830](https://github.com/helix-editor/helix/pull/2830))
- Add `acme` ([#2876](https://github.com/helix-editor/helix/pull/2876))
- Add `meliora` ([#2884](https://github.com/helix-editor/helix/pull/2884), [#2890](https://github.com/helix-editor/helix/pull/2890))
- Add cursorline scopes to various themes ([33d287a](https://github.com/helix-editor/helix/commit/33d287a), [#2892](https://github.com/helix-editor/helix/pull/2892), [#2915](https://github.com/helix-editor/helix/pull/2915), [#2916](https://github.com/helix-editor/helix/pull/2916), [#2918](https://github.com/helix-editor/helix/pull/2918), [#2927](https://github.com/helix-editor/helix/pull/2927), [#2925](https://github.com/helix-editor/helix/pull/2925), [#2938](https://github.com/helix-editor/helix/pull/2938), [#2962](https://github.com/helix-editor/helix/pull/2962), [#3054](https://github.com/helix-editor/helix/pull/3054))
- Add mode colors to various themes ([#2926](https://github.com/helix-editor/helix/pull/2926), [#2933](https://github.com/helix-editor/helix/pull/2933), [#2929](https://github.com/helix-editor/helix/pull/2929), [#3098](https://github.com/helix-editor/helix/pull/3098), [#3104](https://github.com/helix-editor/helix/pull/3104), [#3128](https://github.com/helix-editor/helix/pull/3128), [#3135](https://github.com/helix-editor/helix/pull/3135), [#3200](https://github.com/helix-editor/helix/pull/3200))
- Add `nord_light` ([#2908](https://github.com/helix-editor/helix/pull/2908))
- Update `night_owl` ([#2929](https://github.com/helix-editor/helix/pull/2929))
- Update `autumn` ([2e70985](https://github.com/helix-editor/helix/commit/2e70985), [936ed3a](https://github.com/helix-editor/helix/commit/936ed3a))
- Update `one_dark` ([#3011](https://github.com/helix-editor/helix/pull/3011))
- Add `noctis` ([#3043](https://github.com/helix-editor/helix/pull/3043), [#3128](https://github.com/helix-editor/helix/pull/3128))
- Update `boo_berry` ([#3191](https://github.com/helix-editor/helix/pull/3191))
- Update `monokai` ([#3131](https://github.com/helix-editor/helix/pull/3131))
- Add `ayu_dark`, `ayu_light`, `ayu_mirage` ([#3184](https://github.com/helix-editor/helix/pull/3184))
- Update `onelight` ([#3226](https://github.com/helix-editor/helix/pull/3226))
- Add `base16_transparent` ([#3216](https://github.com/helix-editor/helix/pull/3216), [b565fff](https://github.com/helix-editor/helix/commit/b565fff))
- Add `flatwhite` ([#3236](https://github.com/helix-editor/helix/pull/3236))
- Update `dark_plus` ([#3302](https://github.com/helix-editor/helix/pull/3302))
- Add `doom_acario_dark` ([#3308](https://github.com/helix-editor/helix/pull/3308), [#3539](https://github.com/helix-editor/helix/pull/3539))
- Add `rose_pine_moon` ([#3229](https://github.com/helix-editor/helix/pull/3229))
- Update `spacebones_light` ([#3342](https://github.com/helix-editor/helix/pull/3342))
- Fix typos in themes ([8deaebd](https://github.com/helix-editor/helix/commit/8deaebd), [#3412](https://github.com/helix-editor/helix/pull/3412))
- Add `emacs` ([#3410](https://github.com/helix-editor/helix/pull/3410))
- Add `papercolor-light` ([#3426](https://github.com/helix-editor/helix/pull/3426), [#3470](https://github.com/helix-editor/helix/pull/3470), [#3585](https://github.com/helix-editor/helix/pull/3585))
- Add `penumbra+` ([#3398](https://github.com/helix-editor/helix/pull/3398))
- Add `fleetish` ([#3591](https://github.com/helix-editor/helix/pull/3591), [#3607](https://github.com/helix-editor/helix/pull/3607))
- Add `sonokai` ([#3595](https://github.com/helix-editor/helix/pull/3595))
- Update all themes for theme lints ([#3587](https://github.com/helix-editor/helix/pull/3587))
LSP:
- V ([#2526](https://github.com/helix-editor/helix/pull/2526))
- Prisma ([#2703](https://github.com/helix-editor/helix/pull/2703))
- Clojure ([#2780](https://github.com/helix-editor/helix/pull/2780))
- WGSL ([#2872](https://github.com/helix-editor/helix/pull/2872))
- Elvish ([#2948](https://github.com/helix-editor/helix/pull/2948))
- Idris ([#2971](https://github.com/helix-editor/helix/pull/2971))
- Fortran ([#3025](https://github.com/helix-editor/helix/pull/3025))
- Gleam ([#3139](https://github.com/helix-editor/helix/pull/3139))
- Odin ([#3214](https://github.com/helix-editor/helix/pull/3214))
New languages:
- V ([#2526](https://github.com/helix-editor/helix/pull/2526))
- EDoc ([#2640](https://github.com/helix-editor/helix/pull/2640))
- JSDoc ([#2650](https://github.com/helix-editor/helix/pull/2650))
- OpenSCAD ([#2680](https://github.com/helix-editor/helix/pull/2680))
- Prisma ([#2703](https://github.com/helix-editor/helix/pull/2703))
- Clojure ([#2780](https://github.com/helix-editor/helix/pull/2780))
- Starlark ([#2903](https://github.com/helix-editor/helix/pull/2903))
- Elvish ([#2948](https://github.com/helix-editor/helix/pull/2948))
- Fortran ([#3025](https://github.com/helix-editor/helix/pull/3025))
- Ungrammar ([#3048](https://github.com/helix-editor/helix/pull/3048))
- SCSS ([#3074](https://github.com/helix-editor/helix/pull/3074))
- Go Template ([#3091](https://github.com/helix-editor/helix/pull/3091))
- Graphviz dot ([#3241](https://github.com/helix-editor/helix/pull/3241))
- Cue ([#3262](https://github.com/helix-editor/helix/pull/3262))
- Slint ([#3355](https://github.com/helix-editor/helix/pull/3355))
- Beancount ([#3297](https://github.com/helix-editor/helix/pull/3297))
- Taskwarrior ([#3468](https://github.com/helix-editor/helix/pull/3468))
- xit ([#3521](https://github.com/helix-editor/helix/pull/3521))
- ESDL ([#3526](https://github.com/helix-editor/helix/pull/3526))
- Awk ([#3528](https://github.com/helix-editor/helix/pull/3528), [#3535](https://github.com/helix-editor/helix/pull/3535))
- Pascal ([#3542](https://github.com/helix-editor/helix/pull/3542))
Updated languages and queries:
- Nix ([#2472](https://github.com/helix-editor/helix/pull/2472))
- Elixir ([#2619](https://github.com/helix-editor/helix/pull/2619))
- CPON ([#2643](https://github.com/helix-editor/helix/pull/2643))
- Textobjects queries for Erlang, Elixir, Gleam ([#2661](https://github.com/helix-editor/helix/pull/2661))
- Capture rust closures as function textobjects ([4a27e2d](https://github.com/helix-editor/helix/commit/4a27e2d))
- Heex ([#2800](https://github.com/helix-editor/helix/pull/2800), [#3170](https://github.com/helix-editor/helix/pull/3170))
- Add `<<=` operator highlighting for Rust ([#2805](https://github.com/helix-editor/helix/pull/2805))
- Fix comment injection in JavaScript/TypeScript ([#2763](https://github.com/helix-editor/helix/pull/2763))
- Nickel ([#2859](https://github.com/helix-editor/helix/pull/2859))
- Add `Rakefile` and `Gemfile` to Ruby file-types ([#2875](https://github.com/helix-editor/helix/pull/2875))
- Erlang ([#2910](https://github.com/helix-editor/helix/pull/2910), [ac669ad](https://github.com/helix-editor/helix/commit/ac669ad))
- Markdown ([#2910](https://github.com/helix-editor/helix/pull/2910), [#3108](https://github.com/helix-editor/helix/pull/3108), [#3400](https://github.com/helix-editor/helix/pull/3400))
- Bash ([#2910](https://github.com/helix-editor/helix/pull/2910))
- Rust ([#2910](https://github.com/helix-editor/helix/pull/2910), [#3397](https://github.com/helix-editor/helix/pull/3397))
- Edoc ([#2910](https://github.com/helix-editor/helix/pull/2910))
- HTML ([#2910](https://github.com/helix-editor/helix/pull/2910))
- Make ([#2910](https://github.com/helix-editor/helix/pull/2910))
- TSQ ([#2910](https://github.com/helix-editor/helix/pull/2910), [#2960](https://github.com/helix-editor/helix/pull/2960))
- git-commit ([#2910](https://github.com/helix-editor/helix/pull/2910))
- Use default fallback for Python indents ([9ae70cc](https://github.com/helix-editor/helix/commit/9ae70cc))
- Add Haskell LSP roots ([#2954](https://github.com/helix-editor/helix/pull/2954))
- Ledger ([#2936](https://github.com/helix-editor/helix/pull/2936), [#2988](https://github.com/helix-editor/helix/pull/2988))
- Nickel ([#2987](https://github.com/helix-editor/helix/pull/2987))
- JavaScript/TypeScript ([#2961](https://github.com/helix-editor/helix/pull/2961), [#3219](https://github.com/helix-editor/helix/pull/3219), [#3213](https://github.com/helix-editor/helix/pull/3213), [#3280](https://github.com/helix-editor/helix/pull/3280), [#3301](https://github.com/helix-editor/helix/pull/3301))
- GLSL ([#3051](https://github.com/helix-editor/helix/pull/3051))
- Fix locals tracking in Rust ([#3027](https://github.com/helix-editor/helix/pull/3027), [#3212](https://github.com/helix-editor/helix/pull/3212), [#3345](https://github.com/helix-editor/helix/pull/3345))
- Verilog ([#3158](https://github.com/helix-editor/helix/pull/3158))
- Ruby ([#3173](https://github.com/helix-editor/helix/pull/3173), [#3527](https://github.com/helix-editor/helix/pull/3527))
- Svelte ([#3147](https://github.com/helix-editor/helix/pull/3147))
- Add Elixir and HEEx comment textobjects ([#3179](https://github.com/helix-editor/helix/pull/3179))
- Python ([#3103](https://github.com/helix-editor/helix/pull/3103), [#3201](https://github.com/helix-editor/helix/pull/3201), [#3284](https://github.com/helix-editor/helix/pull/3284))
- PHP ([#3317](https://github.com/helix-editor/helix/pull/3317))
- Latex ([#3370](https://github.com/helix-editor/helix/pull/3370))
- Clojure ([#3387](https://github.com/helix-editor/helix/pull/3387))
- Swift ([#3461](https://github.com/helix-editor/helix/pull/3461))
- C# ([#3480](https://github.com/helix-editor/helix/pull/3480), [#3494](https://github.com/helix-editor/helix/pull/3494))
- Org ([#3489](https://github.com/helix-editor/helix/pull/3489))
- Elm ([#3497](https://github.com/helix-editor/helix/pull/3497))
- Dart ([#3419](https://github.com/helix-editor/helix/pull/3419))
- Julia ([#3507](https://github.com/helix-editor/helix/pull/3507))
- Fix Rust textobjects ([#3590](https://github.com/helix-editor/helix/pull/3590))
- C ([00d88e5](https://github.com/helix-editor/helix/commit/00d88e5))
- Update Rust ([0ef0ef9](https://github.com/helix-editor/helix/commit/0ef0ef9))
Packaging:
- Add `rust-analyzer` to Nix flake devShell ([#2739](https://github.com/helix-editor/helix/pull/2739))
- Add cachix information to the Nix flake ([#2999](https://github.com/helix-editor/helix/pull/2999))
- Pass makeWrapperArgs to wrapProgram in the Nix flake ([#3003](https://github.com/helix-editor/helix/pull/3003))
- Add a way to override which grammars are built by Nix ([#3141](https://github.com/helix-editor/helix/pull/3141))
- Add a GitHub actions release for `aarch64-macos` ([#3137](https://github.com/helix-editor/helix/pull/3137))
- Add shell auto-completions for Elvish ([#3331](https://github.com/helix-editor/helix/pull/3331))
# 22.05 (2022-05-28)
An even bigger shout out than usual to all the contributors - we had a whopping
110 contributors in this release! That's more than double the number of
contributors as last release!
Check out some of the highlights in the [news section](https://helix-editor.com/news/release-22-05-highlights/).
As usual, the following is a summary of each of the changes since the last release.
For the full log, check out the [git log](https://github.com/helix-editor/helix/compare/22.03..22.05).
Breaking Changes:
- Removed `C-j`, `C-k` bindings from file picker ([#1792](https://github.com/helix-editor/helix/pull/1792))
- Replaced `C-f` with `C-d` and `C-b` with `C-u` bindings in file picker ([#1792](https://github.com/helix-editor/helix/pull/1792))
- `A-hjkl` bindings have been moved to `A-pion` ([#2205](https://github.com/helix-editor/helix/pull/2205))
- `A-Left`/`A-Right` have been moved to `C-Left`/`C-Right` ([#2193](https://github.com/helix-editor/helix/pull/2193))
Features:
- The indentation mechanism has been reworked ([#1562](https://github.com/helix-editor/helix/pull/1562), [#1908](https://github.com/helix-editor/helix/pull/1908))
- Configurable gutters ([#1967](https://github.com/helix-editor/helix/pull/1967))
- Support for local language configuration ([#1249](https://github.com/helix-editor/helix/pull/1249))
- Configurable themed rulers ([#2060](https://github.com/helix-editor/helix/pull/2060))
- Render visible whitespace ([e6b865e](https://github.com/helix-editor/helix/commit/e6b865e), [#2322](https://github.com/helix-editor/helix/pull/2322), [#2331](https://github.com/helix-editor/helix/pull/2331))
Commands:
- Paragraph motion and textobject (`]p`, `[p`) ([#1627](https://github.com/helix-editor/helix/pull/1627), [#1956](https://github.com/helix-editor/helix/pull/1956), [#1969](https://github.com/helix-editor/helix/pull/1969), [#1992](https://github.com/helix-editor/helix/pull/1992), [#2226](https://github.com/helix-editor/helix/pull/2226))
- `:buffer-next`, `:buffer-previous` ([#1940](https://github.com/helix-editor/helix/pull/1940))
- `:set-language` to set the buffers language ([#1866](https://github.com/helix-editor/helix/pull/1866), [#1996](https://github.com/helix-editor/helix/pull/1996))
- Command for picking files from the current working directory (`Space-F`) ([#1600](https://github.com/helix-editor/helix/pull/1600), [#2308](https://github.com/helix-editor/helix/pull/2308))
- `:write!` which creates non-existent subdirectories ([#1839](https://github.com/helix-editor/helix/pull/1839))
- Add `m` textobject that selects closest surrounding pair ([de15d70](https://github.com/helix-editor/helix/commit/de15d70), [76175db](https://github.com/helix-editor/helix/commit/76175db))
- `:pipe` typable command for piping selections ([#1972](https://github.com/helix-editor/helix/pull/1972))
- `extend_line_above` which extends to previous lines ([#2117](https://github.com/helix-editor/helix/pull/2117))
- `set_line_ending` which replaces line endings ([#1871](https://github.com/helix-editor/helix/pull/1871))
- `:get-option` for getting the current value of an option (`:get`) ([#2231](https://github.com/helix-editor/helix/pull/2231))
- `:run-shell-command` which does not interact with selections ([#1682](https://github.com/helix-editor/helix/pull/1682))
- `:reflow` which hard-wraps selected text ([#2128](https://github.com/helix-editor/helix/pull/2128))
- `commit_undo_checkpoint` which adds an undo checkpoint ([#2115](https://github.com/helix-editor/helix/pull/2115))
- `:log-open` which opens the log file ([#2422](https://github.com/helix-editor/helix/pull/2422))
- `transpose_view` which transposes window splits ([#2461](https://github.com/helix-editor/helix/pull/2461))
- View-swapping: `swap_view_right`, `swap_view_left`, `swap_view_up`, `swap_view_down` ([#2445](https://github.com/helix-editor/helix/pull/2445))
- `shrink_to_line_bounds` which shrinks selections to line-bounds ([#2450](https://github.com/helix-editor/helix/pull/2450))
Usability improvements and fixes:
- Handle broken pipes when piping `hx --health` through `head` ([#1876](https://github.com/helix-editor/helix/pull/1876))
- Fix for `copy_selection` on newlines ([ab7885e](https://github.com/helix-editor/helix/commit/ab7885e), [236c6b7](https://github.com/helix-editor/helix/commit/236c6b7))
- Use `win32yank` clipboard provider on WSL2 ([#1912](https://github.com/helix-editor/helix/pull/1912))
- Jump to the next number on the line before incrementing ([#1778](https://github.com/helix-editor/helix/pull/1778))
- Fix start position of next search ([#1904](https://github.com/helix-editor/helix/pull/1904))
- Use check and X marks for health check output ([#1918](https://github.com/helix-editor/helix/pull/1918))
- Clear terminal after switching to alternate screens ([#1944](https://github.com/helix-editor/helix/pull/1944))
- Fix `toggle_comments` command on multiple selections ([#1882](https://github.com/helix-editor/helix/pull/1882))
- Apply `ui.gutter` theming to empty gutter spans ([#2032](https://github.com/helix-editor/helix/pull/2032))
- Use checkboxes in `hx --health` output ([#1947](https://github.com/helix-editor/helix/pull/1947))
- Pass unmapped keys through prompt regardless of modifiers ([764adbd](https://github.com/helix-editor/helix/commit/764adbd))
- LSP: pull formatting options from config ([c18de0e](https://github.com/helix-editor/helix/commit/c18de0e))
- LSP: provide `rootPath` ([84e799f](https://github.com/helix-editor/helix/commit/84e799f))
- LSP: implement `workspace_folders` ([8adf0c1](https://github.com/helix-editor/helix/commit/8adf0c1))
- LSP: fix auto-import ([#2088](https://github.com/helix-editor/helix/pull/2088))
- Send active diagnostic to LSP when requesting code actions ([#2005](https://github.com/helix-editor/helix/pull/2005))
- Prevent panic when parsing malformed LSP `PublishDiagnostic` ([#2160](https://github.com/helix-editor/helix/pull/2160))
- Restore document state on completion cancel ([#2096](https://github.com/helix-editor/helix/pull/2096))
- Only merge top-level array when merging `languages.toml` ([#2145](https://github.com/helix-editor/helix/pull/2145), [#2215](https://github.com/helix-editor/helix/pull/2215))
- Fix open on multiline selection ([#2161](https://github.com/helix-editor/helix/pull/2161))
- Allow re-binding `0` if it is not used in a count ([#2174](https://github.com/helix-editor/helix/pull/2174))
- Fix `ctrl-u` behavior in insert mode ([#1957](https://github.com/helix-editor/helix/pull/1957))
- Check LSP rename capabilities before sending rename action ([#2203](https://github.com/helix-editor/helix/pull/2203))
- Register the `publish_diagnostics` LSP capability ([#2241](https://github.com/helix-editor/helix/pull/2241))
- Fix paste direction for typed paste commands ([#2288](https://github.com/helix-editor/helix/pull/2288))
- Improve handling of buffer-close ([#1397](https://github.com/helix-editor/helix/pull/1397))
- Extend the tutor file ([#2133](https://github.com/helix-editor/helix/pull/2133))
- Treat slashes as word separators in prompts ([#2315](https://github.com/helix-editor/helix/pull/2315))
- Auto-complete directory members ([#1682](https://github.com/helix-editor/helix/pull/1682))
- Allow disabling format-on-save as a global editor setting ([#2321](https://github.com/helix-editor/helix/pull/2321))
- Wrap command palette in overlay ([#2378](https://github.com/helix-editor/helix/pull/2378))
- Prevent selections from collapsing when inserting newlines ([#2414](https://github.com/helix-editor/helix/pull/2414))
- Allow configuration of LSP request timeout ([#2405](https://github.com/helix-editor/helix/pull/2405))
- Use debug console on Windows for DAP terminal ([#2294](https://github.com/helix-editor/helix/pull/2294))
- Exclude cursor when deleting with `C-w` in insert mode ([#2431](https://github.com/helix-editor/helix/pull/2431))
- Prevent panics from LSP parsing errors ([7ae6cad](https://github.com/helix-editor/helix/commit/7ae6cad))
- Prevent panics from LSP responses without requests ([#2475](https://github.com/helix-editor/helix/pull/2475))
- Fix scroll rate for documentation popups ([#2497](https://github.com/helix-editor/helix/pull/2497))
- Support inserting into prompts from registers ([#2458](https://github.com/helix-editor/helix/pull/2458))
- Separate theme scopes for diagnostic types ([#2437](https://github.com/helix-editor/helix/pull/2437))
- Use `ui.menu` instead of `ui.statusline` for command completion menu theming ([82fb217](https://github.com/helix-editor/helix/commit/82fb217))
- Panic when reloading a shrunk file ([#2506](https://github.com/helix-editor/helix/pull/2506))
- Add theme key for picker separator ([#2523](https://github.com/helix-editor/helix/pull/2523))
Themes:
- Remove `ui.text` background from dark_plus ([#1950](https://github.com/helix-editor/helix/pull/1950))
- Add `boo_berry` ([#1962](https://github.com/helix-editor/helix/pull/1962))
- Update `dark_plus` markup colors ([#1989](https://github.com/helix-editor/helix/pull/1989))
- Update `dark_plus` `tag` and `ui.menu.selected` colors ([#2014](https://github.com/helix-editor/helix/pull/2014))
- Add `dracula_at_night` ([#2008](https://github.com/helix-editor/helix/pull/2008))
- Improve `dracula` selection theming ([#2077](https://github.com/helix-editor/helix/pull/2077))
- Remove dim attribute on `onedark` line-number gutter ([#2155](https://github.com/helix-editor/helix/pull/2155))
- Add `tokyonight` ([#2162](https://github.com/helix-editor/helix/pull/2162))
- Use border colors from the original `dark_plus` theme ([#2186](https://github.com/helix-editor/helix/pull/2186))
- Add `autumn` ([#2212](https://github.com/helix-editor/helix/pull/2212), [#2270](https://github.com/helix-editor/helix/pull/2270), [#2531](https://github.com/helix-editor/helix/pull/2531))
- Add `tokyonight_storm` ([#2240](https://github.com/helix-editor/helix/pull/2240))
- Add `pop-dark` ([#2189](https://github.com/helix-editor/helix/pull/2189))
- Fix `base16_terminal` theme using incorrect ansi-color ([#2279](https://github.com/helix-editor/helix/pull/2279))
- Add `onelight` ([#2287](https://github.com/helix-editor/helix/pull/2287), [#2323](https://github.com/helix-editor/helix/pull/2323))
- Add `ui.virtual` scopes to `onedark` theme ([3626e38](https://github.com/helix-editor/helix/commit/3626e38))
- Add `night_owl` ([#2330](https://github.com/helix-editor/helix/pull/2330))
- Use yellow foreground and red background for `monokai_pro_spectrum` ([#2433](https://github.com/helix-editor/helix/pull/2433))
- Add `snazzy` ([#2473](https://github.com/helix-editor/helix/pull/2473))
- Update `dark_plus` constructor color ([8e8d4ba](https://github.com/helix-editor/helix/commit/8e8d4ba))
- Add `ui.menu` to the default theme ([e7e13dc](https://github.com/helix-editor/helix/commit/e7e13dc))
- Add `ui.menu` to any themes missing the key ([9be810f](https://github.com/helix-editor/helix/commit/9be810f))
- Add `catppuccin` ([#2546](https://github.com/helix-editor/helix/pull/2546), [7160e74](https://github.com/helix-editor/helix/commit/7160e74))
LSP:
- Use texlab for latex ([#1922](https://github.com/helix-editor/helix/pull/1922))
- HTML ([#2018](https://github.com/helix-editor/helix/pull/2018))
- JSON ([#2024](https://github.com/helix-editor/helix/pull/2024))
- CSS ([#2025](https://github.com/helix-editor/helix/pull/2025))
- PHP ([#2031](https://github.com/helix-editor/helix/pull/2031))
- Swift ([#2033](https://github.com/helix-editor/helix/pull/2033))
- OCaml ([#2035](https://github.com/helix-editor/helix/pull/2035))
- Vue ([#2043](https://github.com/helix-editor/helix/pull/2043))
- Yaml ([#2234](https://github.com/helix-editor/helix/pull/2234))
- Vala ([#2243](https://github.com/helix-editor/helix/pull/2243))
- TOML ([#2302](https://github.com/helix-editor/helix/pull/2302))
- Java ([#2511](https://github.com/helix-editor/helix/pull/2511))
- Lua ([#2560](https://github.com/helix-editor/helix/pull/2560))
- Verilog ([#2552](https://github.com/helix-editor/helix/pull/2552))
New Languages:
- JSX ([#1906](https://github.com/helix-editor/helix/pull/1906), [a24fb17](https://github.com/helix-editor/helix/commit/a24fb17), [855e438](https://github.com/helix-editor/helix/commit/855e438), [#1921](https://github.com/helix-editor/helix/pull/1921))
- Rust Object Notation (RON) ([#1925](https://github.com/helix-editor/helix/pull/1925))
- R and R Markdown ([#1998](https://github.com/helix-editor/helix/pull/1998))
- Swift ([#2033](https://github.com/helix-editor/helix/pull/2033))
- EJS and ERB ([#2055](https://github.com/helix-editor/helix/pull/2055))
- EEx ([9d095e0](https://github.com/helix-editor/helix/commit/9d095e0))
- HEEx ([4836bb3](https://github.com/helix-editor/helix/commit/4836bb3), [#2149](https://github.com/helix-editor/helix/pull/2149))
- SQL ([#2097](https://github.com/helix-editor/helix/pull/2097))
- GDScript ([#1985](https://github.com/helix-editor/helix/pull/1985))
- Nickel ([#2173](https://github.com/helix-editor/helix/pull/2173), [#2320](https://github.com/helix-editor/helix/pull/2320))
- `go.mod` and `go.work` ([#2197](https://github.com/helix-editor/helix/pull/2197))
- Nushell ([#2225](https://github.com/helix-editor/helix/pull/2225))
- Vala ([#2243](https://github.com/helix-editor/helix/pull/2243))
- Hare ([#2289](https://github.com/helix-editor/helix/pull/2289), [#2480](https://github.com/helix-editor/helix/pull/2480))
- DeviceTree ([#2329](https://github.com/helix-editor/helix/pull/2329))
- Cairo ([7387905](https://github.com/helix-editor/helix/commit/7387905))
- CPON ([#2355](https://github.com/helix-editor/helix/pull/2355), [#2424](https://github.com/helix-editor/helix/pull/2424))
- git-ignore ([#2397](https://github.com/helix-editor/helix/pull/2397))
- git-attributes ([#2397](https://github.com/helix-editor/helix/pull/2397))
- Odin ([#2399](https://github.com/helix-editor/helix/pull/2399), [#2464](https://github.com/helix-editor/helix/pull/2464))
- Meson ([#2314](https://github.com/helix-editor/helix/pull/2314))
- SSH Client Config ([#2498](https://github.com/helix-editor/helix/pull/2498))
- Scheme ([d25bae8](https://github.com/helix-editor/helix/commit/d25bae8))
- Verilog ([#2552](https://github.com/helix-editor/helix/pull/2552))
Updated Languages and Queries:
- Erlang ([e2a5071](https://github.com/helix-editor/helix/commit/e2a5071), [#2149](https://github.com/helix-editor/helix/pull/2149), [82da9bd](https://github.com/helix-editor/helix/commit/82da9bd))
- Elixir ([1819478](https://github.com/helix-editor/helix/commit/1819478), [8c3c901](https://github.com/helix-editor/helix/commit/8c3c901), [4ac94a5](https://github.com/helix-editor/helix/commit/4ac94a5))
- Gleam ([7cd6050](https://github.com/helix-editor/helix/commit/7cd6050), [45dd540](https://github.com/helix-editor/helix/commit/45dd540))
- Bash ([#1917](https://github.com/helix-editor/helix/pull/1917))
- JavaScript ([#2140](https://github.com/helix-editor/helix/pull/2140))
- Ruby textobject queries ([#2143](https://github.com/helix-editor/helix/pull/2143))
- Fix Golang textobject queries ([#2153](https://github.com/helix-editor/helix/pull/2153))
- Add more bash and HCL file extensions ([#2201](https://github.com/helix-editor/helix/pull/2201))
- Divide HCL and tfvars into separate languages ([#2244](https://github.com/helix-editor/helix/pull/2244))
- Use JavaScript for `cjs` files ([#2387](https://github.com/helix-editor/helix/pull/2387))
- Use Perl for `t` files ([#2395](https://github.com/helix-editor/helix/pull/2395))
- Use `markup.list` scopes for lists ([#2401](https://github.com/helix-editor/helix/pull/2401))
- Use PHP for `inc` files ([#2440](https://github.com/helix-editor/helix/pull/2440))
- Improve Rust textobjects ([#2494](https://github.com/helix-editor/helix/pull/2494), [10463fe](https://github.com/helix-editor/helix/commit/10463fe))
- Python ([#2451](https://github.com/helix-editor/helix/pull/2451))
Packaging:
- Use `builtins.fromTOML` in Nix Flake on Nix 2.6+ ([#1892](https://github.com/helix-editor/helix/pull/1892))
- Shell auto-completion files are now available ([#2022](https://github.com/helix-editor/helix/pull/2022))
- Create an AppImage on release ([#2089](https://github.com/helix-editor/helix/pull/2089))
# 22.03 (2022-03-28)
A big shout out to all the contributors! We had 51 contributors in this release.
@@ -230,7 +970,7 @@ Usability improvements and fixes:
- File picker configuration ([#988](https://github.com/helix-editor/helix/pull/988))
- Fix surround cursor position calculation ([#1183](https://github.com/helix-editor/helix/pull/1183))
- Accept count for goto_window ([#1033](https://github.com/helix-editor/helix/pull/1033))
- Make kill_to_line_end behave like emacs ([#1235](https://github.com/helix-editor/helix/pull/1235))
- Make kill_to_line_end behave like Emacs ([#1235](https://github.com/helix-editor/helix/pull/1235))
- Only use a single documentation popup ([#1241](https://github.com/helix-editor/helix/pull/1241))
- ui: popup: Don't allow scrolling past the end of content ([`3307f44c`](https://github.com/helix-editor/helix/commit/3307f44c))
- Open files with spaces in filename, allow opening multiple files ([#1231](https://github.com/helix-editor/helix/pull/1231))
@@ -445,7 +1185,7 @@ Fixes:
- A bunch of bugs regarding `o`/`O` behavior ([#281](https://github.com/helix-editor/helix/pull/281))
- `~` expansion now works in file completion ([#284](https://github.com/helix-editor/helix/pull/284))
- Several UI related overflow crashes ([#318](https://github.com/helix-editor/helix/pull/318))
- Fix a test failure occuring only on `test --release` ([`4f108ab1`](https://github.com/helix-editor/helix/commit/4f108ab1b2197809506bd7305ad903a3525eabfa))
- Fix a test failure occurring only on `test --release` ([`4f108ab1`](https://github.com/helix-editor/helix/commit/4f108ab1b2197809506bd7305ad903a3525eabfa))
- Prompts now support unicode input ([#295](https://github.com/helix-editor/helix/pull/295))
- Completion documentation no longer overlaps the popup ([#322](https://github.com/helix-editor/helix/pull/322))
- Fix a crash when trying to select `^` ([`9c534614`](https://github.com/helix-editor/helix/commit/9c53461429a3e72e3b1fb87d7ca490e168d7dee2))
@@ -468,7 +1208,7 @@ to distinguish it in bug reports..
on cargo run. `~/.config/helix/runtime` can also be used.
- Registers can now be selected via " (for example `"ay`)
- Support for Nix files was added
- Movement is now fully tested and matches kakoune implementation
- Movement is now fully tested and matches Kakoune implementation
- A per-file LSP symbol picker was added to space+s
- Selection can be replaced with yanked text via R
@@ -492,7 +1232,7 @@ Keymaps:
- The runtime/ can now optionally be embedded in the binary
- Haskell syntax added
- Window mode (ctrl-w) added
- Show matching bracket (vim's matchbrackets)
- Show matching bracket (Vim's matchbrackets)
- Themes now support style modifiers
- First user contributed theme
- Create a document if it doesn't exist yet on save

1671
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,7 @@ members = [
"helix-lsp",
"helix-dap",
"helix-loader",
"helix-vcs",
"xtask",
]
@@ -14,9 +15,6 @@ default-members = [
"helix-term"
]
[profile.dev]
split-debuginfo = "unpacked"
[profile.release]
lto = "thin"
# debug = true

105
README.md
View File

@@ -1,14 +1,27 @@
# Helix
<div align="center">
<h1>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="logo_dark.svg">
<source media="(prefers-color-scheme: light)" srcset="logo_light.svg">
<img alt="Helix" height="128" src="logo_light.svg">
</picture>
</h1>
[![Build status](https://github.com/helix-editor/helix/actions/workflows/build.yml/badge.svg)](https://github.com/helix-editor/helix/actions)
[![GitHub Release](https://img.shields.io/github/v/release/helix-editor/helix)](https://github.com/helix-editor/helix/releases/latest)
[![Documentation](https://shields.io/badge/-documentation-452859)](https://docs.helix-editor.com/)
[![GitHub contributors](https://img.shields.io/github/contributors/helix-editor/helix)](https://github.com/helix-editor/helix/graphs/contributors)
[![Matrix Space](https://img.shields.io/matrix/helix-community:matrix.org)](https://matrix.to/#/#helix-community:matrix.org)
</div>
![Screenshot](./screenshot.png)
A kakoune / neovim inspired editor, written in Rust.
A Kakoune / Neovim inspired editor, written in Rust.
The editing model is very heavily based on kakoune; during development I found
myself agreeing with most of kakoune's design decisions.
The editing model is very heavily based on Kakoune; during development I found
myself agreeing with most of Kakoune's design decisions.
For more information, see the [website](https://helix-editor.com) or
[documentation](https://docs.helix-editor.com/).
@@ -25,29 +38,58 @@ All shortcuts/keymaps can be found [in the documentation on the website](https:/
- Smart, incremental syntax highlighting and code editing via tree-sitter
It's a terminal-based editor first, but I'd like to explore a custom renderer
(similar to emacs) in wgpu or skulpin.
(similar to Emacs) in wgpu or skulpin.
Note: Only certain languages have indentation definitions at the moment. Check
`runtime/queries/<lang>/` for `indents.toml`.
`runtime/queries/<lang>/` for `indents.scm`.
# Installation
We provide packaging for various distributions, but here's a quick method to
build from source.
Packages are available for various distributions (see [Installation docs](https://docs.helix-editor.com/install.html)).
```
If you would like to build from source:
```shell
git clone https://github.com/helix-editor/helix
cd helix
cargo install --path helix-term
hx --grammar fetch
hx --grammar build
```
This will install the `hx` binary to `$HOME/.cargo/bin` and build tree-sitter grammars.
This will install the `hx` binary to `$HOME/.cargo/bin` and build tree-sitter grammars in `./runtime/grammars`.
Helix also needs its runtime files so make sure to copy/symlink the `runtime/` directory into the
Helix needs its runtime files so make sure to copy/symlink the `runtime/` directory into the
config directory (for example `~/.config/helix/runtime` on Linux/macOS, or `%AppData%/helix/runtime` on Windows).
This location can be overridden via the `HELIX_RUNTIME` environment variable.
| OS | Command |
| -------------------- | ------------------------------------------------ |
| Windows (Cmd) | `xcopy /e /i runtime %AppData%\helix\runtime` |
| Windows (PowerShell) | `xcopy /e /i runtime $Env:AppData\helix\runtime` |
| Linux / macOS | `ln -s $PWD/runtime ~/.config/helix/runtime` |
Starting with Windows Vista you can also create symbolic links on Windows. Note that this requires
elevated privileges - i.e. PowerShell or Cmd must be run as administrator.
**PowerShell:**
```powershell
New-Item -ItemType SymbolicLink -Target "runtime" -Path "$Env:AppData\helix\runtime"
```
**Cmd:**
```cmd
cd %appdata%\helix
mklink /D runtime "<helix-repo>\runtime"
```
The runtime location can be overridden via the `HELIX_RUNTIME` environment variable.
> NOTE: if `HELIX_RUNTIME` is set prior to calling `cargo install --path helix-term`,
> tree-sitter grammars will be built in `$HELIX_RUNTIME/grammars`.
If you plan on keeping the repo locally, an alternative to copying/symlinking
runtime files is to set `HELIX_RUNTIME=/path/to/helix/runtime`
(`HELIX_RUNTIME=$PWD/runtime` if you're in the helix repo directory).
Packages already solve this for you by wrapping the `hx` binary with a wrapper
that sets the variable to the install dir.
@@ -55,17 +97,40 @@ that sets the variable to the install dir.
> NOTE: running via cargo also doesn't require setting explicit `HELIX_RUNTIME` path, it will automatically
> detect the `runtime` directory in the project root.
If you want to customize your `languages.toml` config,
tree-sitter grammars may be manually fetched and built with `hx --grammar fetch` and `hx --grammar build`.
In order to use LSP features like auto-complete, you will need to
[install the appropriate Language Server](https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers)
for a language.
[![Packaging status](https://repology.org/badge/vertical-allrepos/helix.svg)](https://repology.org/project/helix/versions)
## MacOS
## Adding Helix to your desktop environment
Helix can be installed on MacOS through homebrew via:
If installing from source, to use Helix in desktop environments that supports [XDG desktop menu](https://specifications.freedesktop.org/menu-spec/menu-spec-latest.html), including Gnome and KDE, copy the provided `.desktop` file to the correct folder:
```bash
cp contrib/Helix.desktop ~/.local/share/applications
```
To use another terminal than the default, you will need to modify the `.desktop` file. For example, to use `kitty`:
```bash
sed -i "s|Exec=hx %F|Exec=kitty hx %F|g" ~/.local/share/applications/Helix.desktop
sed -i "s|Terminal=true|Terminal=false|g" ~/.local/share/applications/Helix.desktop
```
Please note: there is no icon for Helix yet, so the system default will be used.
## macOS
Helix can be installed on macOS through homebrew:
```
brew tap helix-editor/helix
brew install helix
```
# Contributing
Contributing guidelines can be found [here](./docs/CONTRIBUTING.md).
@@ -75,3 +140,7 @@ Contributing guidelines can be found [here](./docs/CONTRIBUTING.md).
Your question might already be answered on the [FAQ](https://github.com/helix-editor/helix/wiki/FAQ).
Discuss the project on the community [Matrix Space](https://matrix.to/#/#helix-community:matrix.org) (make sure to join `#helix-editor:matrix.org` if you're on a client that doesn't support Matrix Spaces yet).
# Credits
Thanks to [@JakeHL](https://github.com/JakeHL) for designing the logo!

View File

@@ -1 +1 @@
22.03
22.12

View File

@@ -1,6 +1,6 @@
# Author: NNB <nnbnh@protonmail.com>
"ui.menu" = "black"
"ui.menu" = { fg = "black", bg = "white" }
"ui.menu.selected" = { modifiers = ["reversed"] }
"ui.linenr" = { fg = "gray", bg = "black" }
"ui.popup" = { modifiers = ["reversed"] }
@@ -10,7 +10,6 @@
"comment" = { fg = "gray" }
"ui.statusline" = { fg = "black", bg = "white" }
"ui.statusline.inactive" = { fg = "gray", bg = "white" }
"ui.help" = { modifiers = ["reversed"] }
"ui.cursor" = { fg = "white", modifiers = ["reversed"] }
"variable" = "red"
"constant.numeric" = "yellow"

View File

@@ -9,3 +9,4 @@ edit-url-template = "https://github.com/helix-editor/helix/tree/master/book/{pat
cname = "docs.helix-editor.com"
default-theme = "colibri"
preferred-dark-theme = "colibri"
git-repository-url = "https://github.com/helix-editor/helix"

View File

@@ -11,8 +11,8 @@
- [Configuration](./configuration.md)
- [Themes](./themes.md)
- [Key Remapping](./remapping.md)
- [Hooks](./hooks.md)
- [Languages](./languages.md)
- [Guides](./guides/README.md)
- [Adding Languages](./guides/adding_languages.md)
- [Adding Textobject Queries](./guides/textobject.md)
- [Adding Indent Queries](./guides/indent.md)

View File

@@ -1,5 +1,5 @@
# Commands
Command mode can be activated by pressing `:`, similar to vim. Built-in commands:
Command mode can be activated by pressing `:`, similar to Vim. Built-in commands:
{{#include ./generated/typable-cmd.md}}

View File

@@ -25,36 +25,106 @@ select = "underline"
hidden = false
```
You may also specify a file to use for configuration with the `-c` or
`--config` CLI argument: `hx -c path/to/custom-config.toml`.
It is also possible to trigger configuration file reloading by sending the `USR1`
signal to the helix process, e.g. via `pkill -USR1 hx`. This is only supported
on unix operating systems.
## Editor
### `[editor]` Section
| Key | Description | Default |
|--|--|---------|
| `scrolloff` | Number of lines of padding around the edge of the screen when scrolling. | `3` |
| `scrolloff` | Number of lines of padding around the edge of the screen when scrolling. | `5` |
| `mouse` | Enable mouse mode. | `true` |
| `middle-click-paste` | Middle click paste support. | `true` |
| `scroll-lines` | Number of lines to scroll per scroll wheel step. | `3` |
| `shell` | Shell to use when running external commands. | Unix: `["sh", "-c"]`<br/>Windows: `["cmd", "/C"]` |
| `line-number` | Line number display: `absolute` simply shows each line's number, while `relative` shows the distance from the current line. When unfocused or in insert mode, `relative` will still show absolute line numbers. | `absolute` |
| `cursorline` | Highlight all lines with a cursor. | `false` |
| `cursorcolumn` | Highlight all columns with a cursor. | `false` |
| `gutters` | Gutters to display: Available are `diagnostics` and `diff` and `line-numbers` and `spacer`, note that `diagnostics` also includes other features like breakpoints, 1-width padding will be inserted if gutters is non-empty | `["diagnostics", "spacer", "line-numbers", "spacer", "diff"]` |
| `auto-completion` | Enable automatic pop up of auto-completion. | `true` |
| `auto-format` | Enable automatic formatting on save. | `true` |
| `auto-save` | Enable automatic saving on focus moving away from Helix. Requires [focus event support](https://github.com/helix-editor/helix/wiki/Terminal-Support) from your terminal. | `false` |
| `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant. | `400` |
| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
| `auto-info` | Whether to display infoboxes | `true` |
| `true-color` | Set to `true` to override automatic detection of terminal truecolor support in the event of a false negative. | `false` |
| `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` |
### `[editor.statusline]` Section
Allows configuring the statusline at the bottom of the editor.
The configuration distinguishes between three areas of the status line:
`[ ... ... LEFT ... ... | ... ... ... ... CENTER ... ... ... ... | ... ... RIGHT ... ... ]`
Statusline elements can be defined as follows:
```toml
[editor.statusline]
left = ["mode", "spinner"]
center = ["file-name"]
right = ["diagnostics", "selections", "position", "file-encoding", "file-line-ending", "file-type"]
separator = "│"
mode.normal = "NORMAL"
mode.insert = "INSERT"
mode.select = "SELECT"
```
The `[editor.statusline]` key takes the following sub-keys:
| Key | Description | Default |
| --- | --- | --- |
| `left` | A list of elements aligned to the left of the statusline | `["mode", "spinner", "file-name"]` |
| `center` | A list of elements aligned to the middle of the statusline | `[]` |
| `right` | A list of elements aligned to the right of the statusline | `["diagnostics", "selections", "position", "file-encoding"]` |
| `separator` | The character used to separate elements in the statusline | `"│"` |
| `mode.normal` | The text shown in the `mode` element for normal mode | `"NOR"` |
| `mode.insert` | The text shown in the `mode` element for insert mode | `"INS"` |
| `mode.select` | The text shown in the `mode` element for select mode | `"SEL"` |
The following statusline elements can be configured:
| Key | Description |
| ------ | ----------- |
| `mode` | The current editor mode (`mode.normal`/`mode.insert`/`mode.select`) |
| `spinner` | A progress spinner indicating LSP activity |
| `file-name` | The path/name of the opened file |
| `file-encoding` | The encoding of the opened file if it differs from UTF-8 |
| `file-line-ending` | The file line endings (CRLF or LF) |
| `total-line-numbers` | The total line numbers of the opened file |
| `file-type` | The type of the opened file |
| `diagnostics` | The number of warnings and/or errors |
| `workspace-diagnostics` | The number of warnings and/or errors on workspace |
| `selections` | The number of active selections |
| `primary-selection-length` | The number of characters currently in primary selection |
| `position` | The cursor position |
| `position-percentage` | The cursor position as a percentage of the total number of lines |
| `separator` | The string defined in `editor.statusline.separator` (defaults to `"│"`) |
| `spacer` | Inserts a space between elements (multiple/contiguous spacers may be specified) |
### `[editor.lsp]` Section
| Key | Description | Default |
| --- | ----------- | ------- |
| `display-messages` | Display LSP progress messages below statusline[^1] | `false` |
| Key | Description | Default |
| --- | ----------- | ------- |
| `display-messages` | Display LSP progress messages below statusline[^1] | `false` |
| `auto-signature-help` | Enable automatic popup of signature help (parameter hints) | `true` |
| `display-signature-help-docs` | Display docs under signature help popup | `true` |
[^1]: A progress spinner is always shown in the statusline beside the file path.
[^1]: By default, a progress spinner is shown in the statusline beside the file path.
### `[editor.cursor-shape]` Section
Defines the shape of cursor in each mode. Note that due to limitations
of the terminal environment, only the primary cursor can change shape.
Valid values for these options are `block`, `bar`, `underline`, or `hidden`.
| Key | Description | Default |
| --- | ----------- | ------- |
@@ -74,6 +144,8 @@ files and files listed within ignore files are ignored by (not visible in) the
helix file picker and global search. There is also one other key, `max-depth`
available, which is not defined by default.
All git related options are only enabled in a git repository.
| Key | Description | Default |
|--|--|---------|
|`hidden` | Enables ignoring hidden files. | true
@@ -86,16 +158,18 @@ available, which is not defined by default.
### `[editor.auto-pairs]` Section
Enable automatic insertion of pairs to parentheses, brackets, etc. Can be
a simple boolean value, or a specific mapping of pairs of single characters.
Enables automatic insertion of pairs to parentheses, brackets, etc. Can be a
simple boolean value, or a specific mapping of pairs of single characters.
| Key | Description |
| --- | ----------- |
| `false` | Completely disable auto pairing, regardless of language-specific settings
| `true` | Use the default pairs: <code>(){}[]''""``</code>
| Mapping of pairs | e.g. `{ "(" = ")", "{" = "}", ... }`
To disable auto-pairs altogether, set `auto-pairs` to `false`:
Example
```toml
[editor]
auto-pairs = false # defaults to `true`
```
The default pairs are <code>(){}[]''""``</code>, but these can be customized by
setting `auto-pairs` to a TOML table:
```toml
[editor.auto-pairs]
@@ -134,3 +208,50 @@ Search specific options.
|--|--|---------|
| `smart-case` | Enable smart case regex searching (case insensitive unless pattern contains upper case characters) | `true` |
| `wrap-around`| Whether the search should wrap after depleting the matches | `true` |
### `[editor.whitespace]` Section
Options for rendering whitespace with visible characters. Use `:set whitespace.render all` to temporarily enable visible whitespace.
| Key | Description | Default |
|-----|-------------|---------|
| `render` | Whether to render whitespace. May either be `"all"` or `"none"`, or a table with sub-keys `space`, `tab`, and `newline`. | `"none"` |
| `characters` | Literal characters to use when rendering whitespace. Sub-keys may be any of `tab`, `space`, `nbsp`, `newline` or `tabpad` | See example below |
Example
```toml
[editor.whitespace]
render = "all"
# or control each character
[editor.whitespace.render]
space = "all"
tab = "all"
newline = "none"
[editor.whitespace.characters]
space = "·"
nbsp = "⍽"
tab = "→"
newline = "⏎"
tabpad = "·" # Tabs will look like "→···" (depending on tab width)
```
### `[editor.indent-guides]` Section
Options for rendering vertical indent guides.
| Key | Description | Default |
| --- | --- | --- |
| `render` | Whether to render indent guides. | `false` |
| `character` | Literal character to use for rendering the indent guide | `│` |
| `skip-levels` | Number of indent levels to skip | `0` |
Example:
```toml
[editor.indent-guides]
render = true
character = "╎" # Some characters that work well: "▏", "┆", "┊", "⸽"
skip-levels = 1
```

View File

@@ -1,12 +1,12 @@
# Migrating from Vim
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
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
single width selection.
See also Kakoune's [Migrating from Vim](https://github.com/mawww/kakoune/wiki/Migrating-from-Vim).
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).
> TODO: Mention texobjects, surround, registers
> TODO: Mention textobjects, surround, registers

View File

@@ -1,68 +1,139 @@
| Language | Syntax Highlighting | Treesitter Textobjects | Auto Indent | Default LSP |
| --- | --- | --- | --- | --- |
| astro | ✓ | | | |
| awk | ✓ | ✓ | | `awk-language-server` |
| bash | ✓ | | | `bash-language-server` |
| bass | ✓ | | | `bass` |
| beancount | ✓ | | | |
| bibtex | ✓ | | | `texlab` |
| bicep | ✓ | | | `bicep-langserver` |
| c | ✓ | ✓ | ✓ | `clangd` |
| c-sharp | ✓ | | | `OmniSharp` |
| c-sharp | ✓ | | | `OmniSharp` |
| cairo | ✓ | | | |
| clojure | ✓ | | | `clojure-lsp` |
| cmake | ✓ | ✓ | ✓ | `cmake-language-server` |
| comment | ✓ | | | |
| common-lisp | ✓ | | | `cl-lsp` |
| cpon | ✓ | | ✓ | |
| cpp | ✓ | ✓ | ✓ | `clangd` |
| css | ✓ | | | |
| css | ✓ | | | `vscode-css-language-server` |
| cue | ✓ | | | `cuelsp` |
| d | ✓ | ✓ | ✓ | `serve-d` |
| dart | ✓ | | ✓ | `dart` |
| devicetree | ✓ | | | |
| diff | ✓ | | | |
| dockerfile | ✓ | | | `docker-langserver` |
| elixir | ✓ | | | `elixir-ls` |
| dot | ✓ | | | `dot-language-server` |
| edoc | ✓ | | | |
| eex | ✓ | | | |
| ejs | ✓ | | | |
| elixir | ✓ | ✓ | ✓ | `elixir-ls` |
| elm | ✓ | | | `elm-language-server` |
| erlang | ✓ | | | |
| elvish | ✓ | | | `elvish` |
| env | ✓ | | | |
| erb | ✓ | | | |
| erlang | ✓ | ✓ | | `erlang_ls` |
| esdl | ✓ | | | |
| fish | ✓ | ✓ | ✓ | |
| fortran | ✓ | | ✓ | `fortls` |
| gdscript | ✓ | ✓ | | |
| git-attributes | ✓ | | | |
| git-commit | ✓ | | | |
| git-config | ✓ | | | |
| git-diff | ✓ | | | |
| git-ignore | ✓ | | | |
| git-rebase | ✓ | | | |
| glsl | ✓ | | ✓ | |
| gleam | ✓ | ✓ | | `gleam` |
| glsl | ✓ | ✓ | ✓ | |
| go | ✓ | ✓ | ✓ | `gopls` |
| godot-resource | ✓ | | | |
| gomod | ✓ | | | `gopls` |
| gotmpl | ✓ | | | `gopls` |
| gowork | ✓ | | | `gopls` |
| graphql | ✓ | | | |
| haskell | ✓ | | | `haskell-language-server-wrapper` |
| hare | ✓ | | | |
| haskell | ✓ | ✓ | | `haskell-language-server-wrapper` |
| hcl | ✓ | | ✓ | `terraform-ls` |
| html | ✓ | | | |
| heex | ✓ | ✓ | | `elixir-ls` |
| html | ✓ | | | `vscode-html-language-server` |
| idris | | | | `idris2-lsp` |
| iex | ✓ | | | |
| java | ✓ | | | |
| javascript | ✓ | | ✓ | `typescript-language-server` |
| json | ✓ | | ✓ | |
| ini | ✓ | | | |
| java | ✓ | ✓ | | `jdtls` |
| javascript | ✓ | | ✓ | `typescript-language-server` |
| jsdoc | ✓ | | | |
| json | ✓ | | ✓ | `vscode-json-language-server` |
| jsonnet | ✓ | | | `jsonnet-language-server` |
| jsx | ✓ | ✓ | ✓ | `typescript-language-server` |
| julia | ✓ | | | `julia` |
| kdl | ✓ | | | |
| kotlin | ✓ | | | `kotlin-language-server` |
| latex | ✓ | | | |
| latex | ✓ | | | `texlab` |
| lean | ✓ | | | `lean` |
| ledger | ✓ | | | |
| llvm | ✓ | ✓ | ✓ | |
| llvm-mir | ✓ | ✓ | ✓ | |
| llvm-mir-yaml | ✓ | | ✓ | |
| lua | ✓ | | ✓ | |
| lua | ✓ | | ✓ | `lua-language-server` |
| make | ✓ | | | |
| markdown | ✓ | | | |
| markdown | ✓ | | | `marksman` |
| markdown.inline | ✓ | | | |
| meson | ✓ | | ✓ | |
| mint | | | | `mint` |
| nix | ✓ | | ✓ | `rnix-lsp` |
| ocaml | ✓ | | | |
| ocaml-interface | ✓ | | | |
| nickel | ✓ | | ✓ | `nls` |
| nix | ✓ | | | `nil` |
| nu | ✓ | | | |
| ocaml | ✓ | | ✓ | `ocamllsp` |
| ocaml-interface | ✓ | | | `ocamllsp` |
| odin | ✓ | | | `ols` |
| openscad | ✓ | | | `openscad-lsp` |
| org | ✓ | | | |
| pascal | ✓ | ✓ | | `pasls` |
| perl | ✓ | ✓ | ✓ | |
| php | ✓ | ✓ | ✓ | |
| php | ✓ | ✓ | ✓ | `intelephense` |
| prisma | ✓ | | | `prisma-language-server` |
| prolog | | | | `swipl` |
| protobuf | ✓ | | ✓ | |
| purescript | ✓ | | | `purescript-language-server` |
| python | ✓ | ✓ | ✓ | `pylsp` |
| racket | | | | `racket` |
| qml | | | | `qmlls` |
| r | ✓ | | | `R` |
| racket | ✓ | | | `racket` |
| regex | ✓ | | | |
| rescript | ✓ | ✓ | | `rescript-language-server` |
| ruby | ✓ | | ✓ | `solargraph` |
| rmarkdown | ✓ | | ✓ | `R` |
| ron | ✓ | | ✓ | |
| ruby | ✓ | ✓ | ✓ | `solargraph` |
| rust | ✓ | ✓ | ✓ | `rust-analyzer` |
| scala | ✓ | | ✓ | `metals` |
| scheme | ✓ | | | |
| scss | ✓ | | | `vscode-css-language-server` |
| slint | ✓ | | ✓ | `slint-lsp` |
| sml | ✓ | | | |
| solidity | ✓ | | | `solc` |
| svelte | ✓ | | | `svelteserver` |
| sql | ✓ | | | |
| sshclientconfig | ✓ | | | |
| starlark | ✓ | ✓ | | |
| svelte | ✓ | | | `svelteserver` |
| swift | ✓ | | | `sourcekit-lsp` |
| tablegen | ✓ | ✓ | ✓ | |
| toml | ✓ | | | |
| task | ✓ | | | |
| tfvars | | | | `terraform-ls` |
| toml | ✓ | | | `taplo` |
| tsq | ✓ | | | |
| tsx | ✓ | | | `typescript-language-server` |
| tsx | ✓ | | | `typescript-language-server` |
| twig | ✓ | | | |
| typescript | ✓ | | ✓ | `typescript-language-server` |
| vue | ✓ | | | |
| wgsl | ✓ | | | |
| yaml | ✓ | | | |
| zig | ✓ | | ✓ | `zls` |
| typescript | ✓ | | ✓ | `typescript-language-server` |
| ungrammar | ✓ | | | |
| v | ✓ | | | `vls` |
| vala | ✓ | | | `vala-language-server` |
| verilog | ✓ | ✓ | | `svlangserver` |
| vhs | ✓ | | | |
| vue | ✓ | | | `vls` |
| wast | ✓ | | | |
| wat | ✓ | | | |
| wgsl | ✓ | | | `wgsl_analyzer` |
| wit | ✓ | | ✓ | |
| xit | ✓ | | | |
| xml | ✓ | | ✓ | |
| yaml | ✓ | | ✓ | `yaml-language-server` |
| zig | ✓ | ✓ | ✓ | `zls` |

View File

@@ -1,31 +1,34 @@
| Name | Description |
| --- | --- |
| `:quit`, `:q` | Close the current view. |
| `:quit!`, `:q!` | Close the current view forcefully (ignoring unsaved changes). |
| `:quit!`, `:q!` | Force close the current view, ignoring unsaved changes. |
| `:open`, `:o` | Open a file from disk into the current view. |
| `:buffer-close`, `:bc`, `:bclose` | Close the current buffer. |
| `:buffer-close!`, `:bc!`, `:bclose!` | Close the current buffer forcefully (ignoring unsaved changes). |
| `:buffer-close!`, `:bc!`, `:bclose!` | Close the current buffer forcefully, ignoring unsaved changes. |
| `:buffer-close-others`, `:bco`, `:bcloseother` | Close all buffers but the currently focused one. |
| `:buffer-close-others!`, `:bco!`, `:bcloseother!` | Close all buffers but the currently focused one. |
| `:buffer-close-all`, `:bca`, `:bcloseall` | Close all buffers, without quiting. |
| `:buffer-close-all!`, `:bca!`, `:bcloseall!` | Close all buffers forcefully (ignoring unsaved changes), without quiting. |
| `:buffer-close-others!`, `:bco!`, `:bcloseother!` | Force close all buffers but the currently focused one. |
| `:buffer-close-all`, `:bca`, `:bcloseall` | Close all buffers without quitting. |
| `:buffer-close-all!`, `:bca!`, `:bcloseall!` | Force close all buffers ignoring unsaved changes without quitting. |
| `:buffer-next`, `:bn`, `:bnext` | Goto next buffer. |
| `:buffer-previous`, `:bp`, `:bprev` | Goto previous buffer. |
| `:write`, `:w` | Write changes to disk. Accepts an optional path (:write some/path.txt) |
| `:write!`, `:w!` | Force write changes to disk creating necessary subdirectories. Accepts an optional path (:write some/path.txt) |
| `:new`, `:n` | Create a new scratch buffer. |
| `:format`, `:fmt` | Format the file using the LSP formatter. |
| `:indent-style` | Set the indentation style for editing. ('t' for tabs or 1-8 for number of spaces.) |
| `:line-ending` | Set the document's default line ending. Options: crlf, lf, cr, ff, nel. |
| `:line-ending` | Set the document's default line ending. Options: crlf, lf. |
| `:earlier`, `:ear` | Jump back to an earlier point in edit history. Accepts a number of steps or a time span. |
| `:later`, `:lat` | Jump to a later point in edit history. Accepts a number of steps or a time span. |
| `:write-quit`, `:wq`, `:x` | Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt) |
| `:write-quit!`, `:wq!`, `:x!` | Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt) |
| `:write-all`, `:wa` | Write changes from all views to disk. |
| `:write-quit-all`, `:wqa`, `:xa` | Write changes from all views to disk and close all views. |
| `:write-quit-all!`, `:wqa!`, `:xa!` | Write changes from all views to disk and close all views forcefully (ignoring unsaved changes). |
| `:write-all`, `:wa` | Write changes from all buffers to disk. |
| `:write-quit-all`, `:wqa`, `:xa` | Write changes from all buffers to disk and close all views. |
| `:write-quit-all!`, `:wqa!`, `:xa!` | Write changes from all buffers to disk and close all views forcefully (ignoring unsaved changes). |
| `:quit-all`, `:qa` | Close all views. |
| `:quit-all!`, `:qa!` | Close all views forcefully (ignoring unsaved changes). |
| `:quit-all!`, `:qa!` | Force close all views ignoring unsaved changes. |
| `:cquit`, `:cq` | Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2). |
| `:cquit!`, `:cq!` | Quit with exit code (default 1) forcefully (ignoring unsaved changes). Accepts an optional integer exit code (:cq! 2). |
| `:theme` | Change the editor theme. |
| `:cquit!`, `:cq!` | Force quit with exit code (default 1) ignoring unsaved changes. Accepts an optional integer exit code (:cq! 2). |
| `:theme` | Change the editor theme (show current theme if no name specified). |
| `:clipboard-yank` | Yank main selection into system clipboard. |
| `:clipboard-yank-join` | Yank joined selections into system clipboard. A separator can be provided as first argument. Default value is newline. |
| `:primary-clipboard-yank` | Yank main selection into system primary clipboard. |
@@ -39,8 +42,12 @@
| `:show-clipboard-provider` | Show clipboard provider name in status bar. |
| `:change-current-directory`, `:cd` | Change the current working directory. |
| `:show-directory`, `:pwd` | Show the current working directory. |
| `:encoding` | Set encoding based on `https://encoding.spec.whatwg.org` |
| `:encoding` | Set encoding. Based on `https://encoding.spec.whatwg.org`. |
| `: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. |
| `:lsp-workspace-command` | Open workspace command picker |
| `:lsp-restart` | Restarts the Language Server that is in use by the current doc |
| `:tree-sitter-scopes` | Display tree sitter scopes, primarily for theming and development. |
| `:debug-start`, `:dbg` | Start a debug session from a given template with given parameters. |
| `:debug-remote`, `:dbg-tcp` | Connect to a debug adapter by TCP address and start a debugging session from a given template with given parameters. |
@@ -50,10 +57,20 @@
| `:hsplit`, `:hs`, `:sp` | Open the file in a horizontal split. |
| `:hsplit-new`, `:hnew` | Open a scratch buffer in a horizontal split. |
| `:tutor` | Open the tutorial. |
| `:goto`, `:g` | Go to line number. |
| `:set-option`, `:set` | Set a config option at runtime |
| `:goto`, `:g` | Goto line number. |
| `:set-language`, `:lang` | Set the language of current buffer. |
| `:set-option`, `:set` | Set a config option at runtime.<br>For example to disable smart case search, use `:set search.smart-case false`. |
| `:get-option`, `:get` | Get the current value of a config option. |
| `:sort` | Sort ranges in selection. |
| `:rsort` | Sort ranges in selection in reverse order. |
| `:reflow` | Hard-wrap the current selection of lines to a given width. |
| `:tree-sitter-subtree`, `:ts-subtree` | Display tree sitter subtree under cursor, primarily for debugging queries. |
| `:config-reload` | Refreshes helix's config. |
| `:config-open` | Open the helix config.toml file. |
| `:config-reload` | Refresh user config. |
| `:config-open` | Open the user 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. |
| `:pipe` | Pipe each selection to the shell command. |
| `:pipe-to` | Pipe each selection to the shell command, ignoring output. |
| `:run-shell-command`, `:sh` | Run a shell command |
| `:help`, `:h` | Open documentation for a command or keybind. |

View File

@@ -1,4 +1,4 @@
# Guides
This section contains guides for adding new language server configurations,
tree-sitter grammers, textobject queries, etc.
tree-sitter grammars, textobject queries, etc.

View File

@@ -2,67 +2,23 @@
## Language configuration
To add a new language, you need to add a `language` entry to the
[`languages.toml`][languages.toml] found in the root of the repository;
this `languages.toml` file is included at compilation time, and is
distinct from the `languages.toml` file in the user's [configuration
directory](../configuration.md).
To add a new language, you need to add a `[[language]]` entry to the
`languages.toml` (see the [language configuration section]).
```toml
[[language]]
name = "mylang"
scope = "scope.mylang"
injection-regex = "^mylang$"
file-types = ["mylang", "myl"]
comment-token = "#"
indent = { tab-width = 2, unit = " " }
```
These are the available keys and descriptions for the file.
| Key | Description |
| ---- | ----------- |
| `name` | The name of the language |
| `scope` | A string like `source.js` that identifies the language. Currently, we strive to match the scope names used by popular TextMate grammars and by the Linguist library. Usually `source.<name>` or `text.<name>` in case of markup languages |
| `injection-regex` | regex pattern that will be tested against a language name in order to determine whether this language should be used for a potential [language injection][treesitter-language-injection] site. |
| `file-types` | The filetypes of the language, for example `["yml", "yaml"]`. Extensions and full file names are supported. |
| `shebangs` | The interpreters from the shebang line, for example `["sh", "bash"]` |
| `roots` | A set of marker files to look for when trying to find the workspace root. For example `Cargo.lock`, `yarn.lock` |
| `auto-format` | Whether to autoformat this language when saving |
| `diagnostic-severity` | Minimal severity of diagnostic for it to be displayed. (Allowed values: `Error`, `Warning`, `Info`, `Hint`) |
| `comment-token` | The token to use as a comment-token |
| `indent` | The indent to use. Has sub keys `tab-width` and `unit` |
| `config` | Language server configuration |
| `grammar` | The tree-sitter grammar to use (defaults to the value of `name`) |
When adding a new language or Language Server configuration for an existing
language, run `cargo xtask docgen` to add the new configuration to the
[Language Support][lang-support] docs before creating a pull request.
When adding a Language Server configuration, be sure to update the
[Language Server Wiki][install-lsp-wiki] with installation notes.
## Grammar configuration
If a tree-sitter grammar is available for the language, add a new `grammar`
If a tree-sitter grammar is available for the language, add a new `[[grammar]]`
entry to `languages.toml`.
```toml
[[grammar]]
name = "mylang"
source = { git = "https://github.com/example/mylang", rev = "a250c4582510ff34767ec3b7dcdd3c24e8c8aa68" }
```
Grammar configuration takes these keys:
| Key | Description |
| --- | ----------- |
| `name` | The name of the tree-sitter grammar |
| `source` | The method of fetching the grammar - a table with a schema defined below |
Where `source` is a table with either these keys when using a grammar from a
git repository:
| Key | Description |
| --- | ----------- |
| `git` | A git remote URL from which the grammar should be cloned |
| `rev` | The revision (commit hash or tag) which should be fetched |
| `subpath` | A path within the grammar directory which should be built. Some grammar repositories host multiple grammars (for example `tree-sitter-typescript` and `tree-sitter-ocaml`) in subdirectories. This key is used to point `hx --grammar build` to the correct path for compilation. When omitted, the root of repository is used |
Or a `path` key with an absolute path to a locally available grammar directory.
You may use the `source.path` key rather than `source.git` with an absolute path
to a locally available grammar for testing, but switch to `source.git` before
submitting a pull request.
## Queries
@@ -73,7 +29,7 @@ language with the path `runtime/queries/<name>/`. The tree-sitter
gives more info on how to write queries.
> NOTE: When evaluating queries, the first matching query takes
precedence, which is different from other editors like neovim where
precedence, which is different from other editors like Neovim where
the last matching query supersedes the ones before it. See
[this issue][neovim-query-precedence] for an example.
@@ -83,8 +39,7 @@ the last matching query supersedes the ones before it. See
- If a parser is segfaulting or you want to remove the parser, make sure to remove the compiled parser in `runtime/grammar/<name>.so`
- The indents query is `indents.toml`, *not* `indents.scm`. See [this](https://github.com/helix-editor/helix/issues/114) issue for more information.
[treesitter-language-injection]: https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection
[languages.toml]: https://github.com/helix-editor/helix/blob/master/languages.toml
[language configuration section]: ../languages.md
[neovim-query-precedence]: https://github.com/helix-editor/helix/pull/1170#issuecomment-997294090
[install-lsp-wiki]: https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers
[lang-support]: ../lang-support.md

93
book/src/guides/indent.md Normal file
View File

@@ -0,0 +1,93 @@
# Adding Indent Queries
Helix uses tree-sitter to correctly indent new lines. This requires
a tree-sitter grammar and an `indent.scm` query file placed in
`runtime/queries/{language}/indents.scm`. The indentation for a line
is calculated by traversing the syntax tree from the lowest node at the
beginning of the new line. Each of these nodes contributes to the total
indent when it is captured by the query (in what way depends on the name
of the capture).
Note that it matters where these added indents begin. For example,
multiple indent level increases that start on the same line only increase
the total indent level by 1.
## Scopes
Added indents don't always apply to the whole node. For example, in most
cases when a node should be indented, we actually only want everything
except for its first line to be indented. For this, there are several
scopes (more scopes may be added in the future if required):
- `all`:
This scope applies to the whole captured node. This is only different from
`tail` when the captured node is the first node on its line.
- `tail`:
This scope applies to everything except for the first line of the
captured node.
Every capture type has a default scope which should do the right thing
in most situations. When a different scope is required, this can be
changed by using a `#set!` declaration anywhere in the pattern:
```scm
(assignment_expression
right: (_) @indent
(#set! "scope" "all"))
```
## Capture Types
- `@indent` (default scope `tail`):
Increase the indent level by 1. Multiple occurrences in the same line
don't stack. If there is at least one `@indent` and one `@outdent`
capture on the same line, the indent level isn't changed at all.
- `@outdent` (default scope `all`):
Decrease the indent level by 1. The same rules as for `@indent` apply.
- `@extend`:
Extend the range of this node to the end of the line and to lines that
are indented more than the line that this node starts on. This is useful
for languages like Python, where for the purpose of indentation some nodes
(like functions or classes) should also contain indented lines that follow them.
- `@extend.prevent-once`:
Prevents the first extension of an ancestor of this node. For example, in Python
a return expression always ends the block that it is in. Note that this only stops the
extension of the next `@extend` capture. If multiple ancestors are captured,
only the extension of the innermost one is prevented. All other ancestors are unaffected
(regardless of whether the innermost ancestor would actually have been extended).
## Predicates
In some cases, an S-expression cannot express exactly what pattern should be matched.
For that, tree-sitter allows for predicates to appear anywhere within a pattern,
similar to how `#set!` declarations work:
```scm
(some_kind
(child_kind) @indent
(#predicate? arg1 arg2 ...)
)
```
The number of arguments depends on the predicate that's used.
Each argument is either a capture (`@name`) or a string (`"some string"`).
The following predicates are supported by tree-sitter:
- `#eq?`/`#not-eq?`:
The first argument (a capture) must/must not be equal to the second argument
(a capture or a string).
- `#match?`/`#not-match?`:
The first argument (a capture) must/must not match the regex given in the
second argument (a string).
Additionally, we support some custom predicates for indent queries:
- `#not-kind-eq?`:
The kind of the first argument (a capture) must not be equal to the second
argument (a string).
- `#same-line?`/`#not-same-line?`:
The captures given by the 2 arguments must/must not start on the same line.

View File

@@ -20,6 +20,8 @@ The following [captures][tree-sitter-captures] are recognized:
| `function.around` |
| `class.inside` |
| `class.around` |
| `test.inside` |
| `test.around` |
| `parameter.inside` |
| `comment.inside` |
| `comment.around` |

View File

@@ -1 +0,0 @@
# Hooks

View File

@@ -6,10 +6,9 @@ We provide pre-built binaries on the [GitHub Releases page](https://github.com/h
## OSX
A Homebrew tap is available:
Helix is available in homebrew-core:
```
brew tap helix-editor/helix
brew install helix
```
@@ -22,8 +21,12 @@ the project root. The flake can also be used to spin up a reproducible developme
shell for working on Helix with `nix develop`.
Flake outputs are cached for each push to master using
[Cachix](https://www.cachix.org/). With Cachix
[installed](https://docs.cachix.org/installation), `cachix use helix` will
[Cachix](https://www.cachix.org/). The flake is configured to
automatically make use of this cache assuming the user accepts
the new settings on first use.
If you are using a version of Nix without flakes enabled you can
[install Cachix cli](https://docs.cachix.org/installation); `cachix use helix` will
configure Nix to use cached outputs when possible.
### Arch Linux
@@ -41,6 +44,47 @@ sudo dnf copr enable varlad/helix
sudo dnf install helix
```
### Void Linux
```
sudo xbps-install helix
```
## Windows
Helix can be installed using [Scoop](https://scoop.sh/), [Chocolatey](https://chocolatey.org/)
or [MSYS2](https://msys2.org/).
**Scoop:**
```
scoop install helix
```
**Chocolatey:**
```
choco install helix
```
**MSYS2:**
```
pacman -S mingw-w64-i686-helix
```
or
```
pacman -S mingw-w64-x86_64-helix
```
or
```
pacman -S mingw-w64-ucrt-x86_64-helix
```
## Build from source
```
@@ -49,14 +93,75 @@ cd helix
cargo install --path helix-term
```
This will install the `hx` binary to `$HOME/.cargo/bin`.
This will install the `hx` binary to `$HOME/.cargo/bin` and build tree-sitter grammars in `./runtime/grammars`.
Helix also needs it's runtime files so make sure to copy/symlink the `runtime/` directory into the
config directory (for example `~/.config/helix/runtime` on Linux/macOS). This location can be overriden
Helix also needs its runtime files so make sure to copy/symlink the `runtime/` directory into the
config directory (for example `~/.config/helix/runtime` on Linux/macOS). This location can be overridden
via the `HELIX_RUNTIME` environment variable.
## Building tree-sitter grammars
| OS | Command |
| -------------------- | ------------------------------------------------ |
| Windows (Cmd) | `xcopy /e /i runtime %AppData%\helix\runtime` |
| Windows (PowerShell) | `xcopy /e /i runtime $Env:AppData\helix\runtime` |
| Linux / macOS | `ln -s $PWD/runtime ~/.config/helix/runtime` |
Starting with Windows Vista you can also create symbolic links on Windows. Note that this requires
elevated privileges - i.e. PowerShell or Cmd must be run as administrator.
**PowerShell:**
```powershell
New-Item -ItemType SymbolicLink -Target "runtime" -Path "$Env:AppData\helix\runtime"
```
**Cmd:**
```cmd
cd %appdata%\helix
mklink /D runtime "<helix-repo>\runtime"
```
The runtime location can be overridden via the `HELIX_RUNTIME` environment variable.
> NOTE: if `HELIX_RUNTIME` is set prior to calling `cargo install --path helix-term`,
> tree-sitter grammars will be built in `$HELIX_RUNTIME/grammars`.
If you plan on keeping the repo locally, an alternative to copying/symlinking
runtime files is to set `HELIX_RUNTIME=/path/to/helix/runtime`
(`HELIX_RUNTIME=$PWD/runtime` if you're in the helix repo directory).
To use Helix in desktop environments that supports [XDG desktop menu](https://specifications.freedesktop.org/menu-spec/menu-spec-latest.html), including Gnome and KDE, copy the provided `.desktop` file to the correct folder:
```bash
cp contrib/Helix.desktop ~/.local/share/applications
```
To use another terminal than the default, you will need to modify the `.desktop` file. For example, to use `kitty`:
```bash
sed -i "s|Exec=hx %F|Exec=kitty hx %F|g" ~/.local/share/applications/Helix.desktop
sed -i "s|Terminal=true|Terminal=false|g" ~/.local/share/applications/Helix.desktop
```
Please note: there is no icon for Helix yet, so the system default will be used.
## Finishing up the installation
To make sure everything is set up as expected you should finally run the helix healthcheck via
```
hx --health
```
For more information on the information displayed in the health check results refer to [Healthcheck](https://github.com/helix-editor/helix/wiki/Healthcheck).
### Building tree-sitter grammars
Tree-sitter grammars must 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).
with `hx --grammar build` (requires a C++ compiler).
### Installing language servers
Language servers can optionally be installed if you want their features (auto-complete, diagnostics etc.).
Follow the [instructions on the wiki page](https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers) to add your language servers of choice.

View File

@@ -1,13 +1,33 @@
# Keymap
- Mappings marked (**LSP**) require an active language server for the file.
- Mappings marked (**TS**) require a tree-sitter grammar for the filetype.
- [Normal mode](#normal-mode)
- [Movement](#movement)
- [Changes](#changes)
- [Shell](#shell)
- [Selection manipulation](#selection-manipulation)
- [Search](#search)
- [Minor modes](#minor-modes)
- [View mode](#view-mode)
- [Goto mode](#goto-mode)
- [Match mode](#match-mode)
- [Window mode](#window-mode)
- [Space mode](#space-mode)
- [Popup](#popup)
- [Unimpaired](#unimpaired)
- [Insert Mode](#insert-mode)
- [Select / extend mode](#select--extend-mode)
- [Picker](#picker)
- [Prompt](#prompt)
> 💡 Mappings marked (**LSP**) require an active language server for the file.
> 💡 Mappings marked (**TS**) require a tree-sitter grammar for the filetype.
## Normal mode
### Movement
> NOTE: Unlike vim, `f`, `F`, `t` and `T` are not confined to the current line.
> NOTE: Unlike Vim, `f`, `F`, `t` and `T` are not confined to the current line.
| Key | Description | Command |
| ----- | ----------- | ------- |
@@ -48,11 +68,11 @@
| `` Alt-` `` | Set the selected text to upper case | `switch_to_uppercase` |
| `i` | Insert before selection | `insert_mode` |
| `a` | Insert after selection (append) | `append_mode` |
| `I` | Insert at the start of the line | `prepend_to_line` |
| `A` | Insert at the end of the line | `append_to_line` |
| `I` | Insert at the start of the line | `insert_at_line_start` |
| `A` | Insert at the end of the line | `insert_at_line_end` |
| `o` | Open new line below selection | `open_below` |
| `O` | Open new line above selection | `open_above` |
| `.` | Repeat last change | N/A |
| `.` | Repeat last insert | N/A |
| `u` | Undo change | `undo` |
| `U` | Redo change | `redo` |
| `Alt-u` | Move backward in history | `earlier` |
@@ -105,16 +125,18 @@
| `Alt-(` | Rotate selection contents backward | `rotate_selection_contents_backward` |
| `Alt-)` | Rotate selection contents forward | `rotate_selection_contents_forward` |
| `%` | Select entire file | `select_all` |
| `x` | Select current line, if already selected, extend to next line | `extend_line` |
| `x` | Select current line, if already selected, extend to next line | `extend_line_below` |
| `X` | Extend selection to line bounds (line-wise selection) | `extend_to_line_bounds` |
| `Alt-x` | Shrink selection to line bounds (line-wise selection) | `shrink_to_line_bounds` |
| `J` | Join lines inside selection | `join_selections` |
| `Alt-J` | Join lines inside selection and select space | `join_selections_space` |
| `K` | Keep selections matching the regex | `keep_selections` |
| `Alt-K` | Remove selections matching the regex | `remove_selections` |
| `Ctrl-c` | Comment/uncomment the selections | `toggle_comments` |
| `Alt-k`, `Alt-up` | Expand selection to parent syntax node (**TS**) | `expand_selection` |
| `Alt-j`, `Alt-down` | Shrink syntax tree object selection (**TS**) | `shrink_selection` |
| `Alt-h`, `Alt-left` | Select previous sibling node in syntax tree (**TS**) | `select_prev_sibling` |
| `Alt-l`, `Alt-right` | Select next sibling node in syntax tree (**TS**) | `select_next_sibling` |
| `Alt-o`, `Alt-up` | Expand selection to parent syntax node (**TS**) | `expand_selection` |
| `Alt-i`, `Alt-down` | Shrink syntax tree object selection (**TS**) | `shrink_selection` |
| `Alt-p`, `Alt-left` | Select previous sibling node in syntax tree (**TS**) | `select_prev_sibling` |
| `Alt-n`, `Alt-right` | Select next sibling node in syntax tree (**TS**) | `select_next_sibling` |
### Search
@@ -145,10 +167,13 @@ These sub-modes are accessible from normal mode and typically switch back to nor
#### View mode
Accessed by typing `z` in [normal mode](#normal-mode).
View mode is intended for scrolling and manipulating the view without changing
the selection. The "sticky" variant of this mode is persistent; use the Escape
key to return to normal mode after usage (useful when you're simply looking
over text and not actively editing it).
the selection. The "sticky" variant of this mode (accessed by typing `Z` in
normal mode) is persistent; use the Escape key to return to normal mode after
usage (useful when you're simply looking over text and not actively editing
it).
| Key | Description | Command |
@@ -166,6 +191,8 @@ over text and not actively editing it).
#### Goto mode
Accessed by typing `g` in [normal mode](#normal-mode).
Jumps to various locations.
| Key | Description | Command |
@@ -191,9 +218,10 @@ Jumps to various locations.
#### Match mode
Enter this mode using `m` from normal mode. See the relavant section
in [Usage](./usage.md) for an explanation about [surround](./usage.md#surround)
and [textobject](./usage.md#textobject) usage.
Accessed by typing `m` in [normal mode](#normal-mode).
See the relevant section in [Usage](./usage.md) for an explanation about
[surround](./usage.md#surround) and [textobject](./usage.md#textobjects) usage.
| Key | Description | Command |
| ----- | ----------- | ------- |
@@ -208,7 +236,9 @@ TODO: Mappings for selecting syntax nodes (a superset of `[`).
#### Window mode
This layer is similar to vim keybindings as kakoune does not support window.
Accessed by typing `Ctrl-w` in [normal mode](#normal-mode).
This layer is similar to Vim keybindings as Kakoune does not support window.
| Key | Description | Command |
| ----- | ------------- | ------- |
@@ -223,19 +253,28 @@ This layer is similar to vim keybindings as kakoune does not support window.
| `l`, `Ctrl-l`, `Right` | Move to right split | `jump_view_right` |
| `q`, `Ctrl-q` | Close current window | `wclose` |
| `o`, `Ctrl-o` | Only keep the current window, closing all the others | `wonly` |
| `H` | Swap window to the left | `swap_view_left` |
| `J` | Swap window downwards | `swap_view_down` |
| `K` | Swap window upwards | `swap_view_up` |
| `L` | Swap window to the right | `swap_view_right` |
#### Space mode
This layer is a kludge of mappings, mostly pickers.
Accessed by typing `Space` in [normal mode](#normal-mode).
This layer is a kludge of mappings, mostly pickers.
| Key | Description | Command |
| ----- | ----------- | ------- |
| `f` | Open file picker | `file_picker` |
| `F` | Open file picker at current working directory | `file_picker_in_current_directory` |
| `b` | Open buffer picker | `buffer_picker` |
| `j` | Open jumplist picker | `jumplist_picker` |
| `k` | Show documentation for item under cursor in a [popup](#popup) (**LSP**) | `hover` |
| `s` | Open document symbol picker (**LSP**) | `symbol_picker` |
| `S` | Open workspace symbol picker (**LSP**) | `workspace_symbol_picker` |
| `d` | Open document diagnostics picker (**LSP**) | `diagnostics_picker` |
| `D` | Open workspace diagnostics picker (**LSP**) | `workspace_diagnostics_picker` |
| `r` | Rename symbol (**LSP**) | `rename_symbol` |
| `a` | Apply code action (**LSP**) | `code_action` |
| `'` | Open last fuzzy picker | `last_picker` |
@@ -248,7 +287,7 @@ This layer is a kludge of mappings, mostly pickers.
| `/` | Global search in workspace folder | `global_search` |
| `?` | Open command palette | `command_palette` |
> TIP: Global search displays results in a fuzzy picker, use `space + '` to bring it back up after opening a file.
> TIP: Global search displays results in a fuzzy picker, use `Space + '` to bring it back up after opening a file.
##### Popup
@@ -258,7 +297,7 @@ Displays documentation for item under cursor.
| ---- | ----------- |
| `Ctrl-u` | Scroll up |
| `Ctrl-d` | Scroll down |
#### Unimpaired
Mappings in the style of [vim-unimpaired](https://github.com/tpope/vim-unimpaired).
@@ -271,46 +310,74 @@ Mappings in the style of [vim-unimpaired](https://github.com/tpope/vim-unimpaire
| `]D` | Go to last diagnostic in document (**LSP**) | `goto_last_diag` |
| `]f` | Go to next function (**TS**) | `goto_next_function` |
| `[f` | Go to previous function (**TS**) | `goto_prev_function` |
| `]c` | Go to next class (**TS**) | `goto_next_class` |
| `[c` | Go to previous class (**TS**) | `goto_prev_class` |
| `]t` | Go to next type definition (**TS**) | `goto_next_class` |
| `[t` | Go to previous type definition (**TS**) | `goto_prev_class` |
| `]a` | Go to next argument/parameter (**TS**) | `goto_next_parameter` |
| `[a` | Go to previous argument/parameter (**TS**) | `goto_prev_parameter` |
| `]o` | Go to next comment (**TS**) | `goto_next_comment` |
| `[o` | Go to previous comment (**TS**) | `goto_prev_comment` |
| `[space` | Add newline above | `add_newline_above` |
| `]space` | Add newline below | `add_newline_below` |
| `]c` | Go to next comment (**TS**) | `goto_next_comment` |
| `[c` | Go to previous comment (**TS**) | `goto_prev_comment` |
| `]T` | Go to next test (**TS**) | `goto_next_test` |
| `]T` | Go to previous test (**TS**) | `goto_prev_test` |
| `]p` | Go to next paragraph | `goto_next_paragraph` |
| `[p` | Go to previous paragraph | `goto_prev_paragraph` |
| `]g` | Go to next change | `goto_next_change` |
| `[g` | Go to previous change | `goto_prev_change` |
| `]G` | Go to first change | `goto_first_change` |
| `[G` | Go to last change | `goto_last_change` |
| `[Space` | Add newline above | `add_newline_above` |
| `]Space` | Add newline below | `add_newline_below` |
## Insert Mode
## Insert mode
We support many readline/emacs style bindings in insert mode for
convenience. These can be helpful for making simple modifications
without escaping to normal mode, but beware that you will not have an
undo-able "save point" until you return to normal mode.
Insert mode bindings are somewhat minimal by default. Helix is designed to
be a modal editor, and this is reflected in the user experience and internal
mechanics. For example, changes to the text are only saved for undos when
escaping from insert mode to normal mode. For this reason, new users are
strongly encouraged to learn the modal editing paradigm to get the smoothest
experience.
| Key | Description | Command |
| ----- | ----------- | ------- |
| `Escape` | Switch to normal mode | `normal_mode` |
| `Ctrl-x` | Autocomplete | `completion` |
| `Ctrl-r` | Insert a register content | `insert_register` |
| `Ctrl-w`, `Alt-Backspace` | Delete previous word | `delete_word_backward` |
| `Alt-d` | Delete next word | `delete_word_forward` |
| `Alt-b`, `Alt-Left` | Backward a word | `move_prev_word_end` |
| `Ctrl-b`, `Left` | Backward a char | `move_char_left` |
| `Alt-f`, `Alt-Right` | Forward a word | `move_next_word_start` |
| `Ctrl-f`, `Right` | Forward a char | `move_char_right` |
| `Ctrl-e`, `End` | Move to line end | `goto_line_end_newline` |
| `Ctrl-a`, `Home` | Move to line start | `goto_line_start` |
| `Ctrl-u` | Delete to start of line | `kill_to_line_start` |
| `Ctrl-k` | Delete to end of line | `kill_to_line_end` |
| `Ctrl-j`, `Enter` | Insert new line | `insert_newline` |
| `Backspace`, `Ctrl-h` | Delete previous char | `delete_char_backward` |
| `Delete`, `Ctrl-d` | Delete previous char | `delete_char_forward` |
| `Ctrl-p`, `Up` | Move to previous line | `move_line_up` |
| `Ctrl-n`, `Down` | Move to next line | `move_line_down` |
| `PageUp` | Move one page up | `page_up` |
| `PageDown` | Move one page down | `page_down` |
| `Alt->` | Go to end of buffer | `goto_file_end` |
| `Alt-<` | Go to start of buffer | `goto_file_start` |
| Key | Description | Command |
| ----- | ----------- | ------- |
| `Escape` | Switch to normal mode | `normal_mode` |
| `Ctrl-s` | Commit undo checkpoint | `commit_undo_checkpoint` |
| `Ctrl-x` | Autocomplete | `completion` |
| `Ctrl-r` | Insert a register content | `insert_register` |
| `Ctrl-w`, `Alt-Backspace` | Delete previous word | `delete_word_backward` |
| `Alt-d`, `Alt-Delete` | Delete next word | `delete_word_forward` |
| `Ctrl-u` | Delete to start of line | `kill_to_line_start` |
| `Ctrl-k` | Delete to end of line | `kill_to_line_end` |
| `Ctrl-h`, `Backspace` | Delete previous char | `delete_char_backward` |
| `Ctrl-d`, `Delete` | Delete next char | `delete_char_forward` |
| `Ctrl-j`, `Enter` | Insert new line | `insert_newline` |
These keys are not recommended, but are included for new users less familiar
with modal editors.
| Key | Description | Command |
| ----- | ----------- | ------- |
| `Up` | Move to previous line | `move_line_up` |
| `Down` | Move to next line | `move_line_down` |
| `Left` | Backward a char | `move_char_left` |
| `Right` | Forward a char | `move_char_right` |
| `PageUp` | Move one page up | `page_up` |
| `PageDown` | Move one page down | `page_down` |
| `Home` | Move to line start | `goto_line_start` |
| `End` | Move to line end | `goto_line_end_newline` |
If you want to disable them in insert mode as you become more comfortable with modal editing, you can use
the following in your `config.toml`:
```toml
[keys.insert]
up = "no_op"
down = "no_op"
left = "no_op"
right = "no_op"
pageup = "no_op"
pagedown = "no_op"
home = "no_op"
end = "no_op"
```
## Select / extend mode
@@ -325,47 +392,47 @@ mode before pressing `n` or `N` makes it possible to keep the current
selection. Toggling it on and off during your iterative searching allows
you to selectively add search terms to your selections.
# Picker
## Picker
Keys to use within picker. Remapping currently not supported.
| Key | Description |
| ----- | ------------- |
| `Up`, `Ctrl-k`, `Ctrl-p` | Previous entry |
| `PageUp`, `Ctrl-b` | Page up |
| `Down`, `Ctrl-j`, `Ctrl-n` | Next entry |
| `PageDown`, `Ctrl-f` | Page down |
| `Shift-Tab`, `Up`, `Ctrl-p` | Previous entry |
| `Tab`, `Down`, `Ctrl-n` | Next entry |
| `PageUp`, `Ctrl-u` | Page up |
| `PageDown`, `Ctrl-d` | Page down |
| `Home` | Go to first entry |
| `End` | Go to last entry |
| `Ctrl-space` | Filter options |
| `Enter` | Open selected |
| `Ctrl-s` | Open horizontally |
| `Ctrl-v` | Open vertically |
| `Ctrl-t` | Toggle preview |
| `Escape`, `Ctrl-c` | Close picker |
# Prompt
## Prompt
Keys to use within prompt, Remapping currently not supported.
| Key | Description |
| ----- | ------------- |
| `Escape`, `Ctrl-c` | Close prompt |
| `Alt-b`, `Alt-Left` | Backward a word |
| `Ctrl-b`, `Left` | Backward a char |
| `Alt-f`, `Alt-Right` | Forward a word |
| `Ctrl-f`, `Right` | Forward a char |
| `Ctrl-e`, `End` | Move prompt end |
| `Ctrl-a`, `Home` | Move prompt start |
| `Ctrl-w` | Delete previous word |
| `Alt-d` | Delete next word |
| `Ctrl-u` | Delete to start of line |
| `Ctrl-k` | Delete to end of line |
| `backspace`, `Ctrl-h` | Delete previous char |
| `delete`, `Ctrl-d` | Delete next char |
| `Ctrl-s` | Insert a word under doc cursor, may be changed to Ctrl-r Ctrl-w later |
| `Ctrl-p`, `Up` | Select previous history |
| `Ctrl-n`, `Down` | Select next history |
| `Tab` | Select next completion item |
| `BackTab` | Select previous completion item |
| `Enter` | Open selected |
| Key | Description |
| ----- | ------------- |
| `Escape`, `Ctrl-c` | Close prompt |
| `Alt-b`, `Ctrl-Left` | Backward a word |
| `Ctrl-b`, `Left` | Backward a char |
| `Alt-f`, `Ctrl-Right` | Forward a word |
| `Ctrl-f`, `Right` | Forward a char |
| `Ctrl-e`, `End` | Move prompt end |
| `Ctrl-a`, `Home` | Move prompt start |
| `Ctrl-w`, `Alt-Backspace`, `Ctrl-Backspace` | Delete previous word |
| `Alt-d`, `Alt-Delete`, `Ctrl-Delete` | Delete next word |
| `Ctrl-u` | Delete to start of line |
| `Ctrl-k` | Delete to end of line |
| `Backspace`, `Ctrl-h` | Delete previous char |
| `Delete`, `Ctrl-d` | Delete next char |
| `Ctrl-s` | Insert a word under doc cursor, may be changed to Ctrl-r Ctrl-w later |
| `Ctrl-p`, `Up` | Select previous history |
| `Ctrl-n`, `Down` | Select next history |
| `Ctrl-r` | Insert the content of the register selected by following input char |
| `Tab` | Select next completion item |
| `BackTab` | Select previous completion item |
| `Enter` | Open selected |

View File

@@ -1,10 +1,16 @@
# Language Support
For more information like arguments passed to default LSP server,
extensions assosciated with a filetype, custom LSP settings, filetype
specific indent settings, etc see the default
[`languages.toml`][languages.toml] file.
The following languages and Language Servers are supported. In order to use
Language Server features, you must first [install][lsp-install-wiki] the
appropriate Language Server.
Check the language support in your installed helix version with `hx --health`.
Also see the [Language Configuration][lang-config] docs and the [Adding
Languages][adding-languages] guide for more language configuration information.
{{#include ./generated/lang-support.md}}
[languages.toml]: https://github.com/helix-editor/helix/blob/master/languages.toml
[lsp-install-wiki]: https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers
[lang-config]: ./languages.md
[adding-languages]: ./guides/adding_languages.md

View File

@@ -1,8 +1,17 @@
# Languages
Language-specific settings and settings for particular language servers can be configured in a `languages.toml` file placed in your [configuration directory](./configuration.md). Helix actually uses two `languages.toml` files, the [first one](https://github.com/helix-editor/helix/blob/master/languages.toml) is in the main helix repository; it contains the default settings for each language and is included in the helix binary at compile time. Users who want to see the available settings and options can either reference the helix repo's `languages.toml` file, or consult the table in the [adding languages](./guides/adding_languages.md) section.
Language-specific settings and settings for language servers are configured
in `languages.toml` files.
Changes made to the `languages.toml` file in a user's [configuration directory](./configuration.md) are merged with helix's defaults on start-up, such that a user's settings will take precedence over defaults in the event of a collision. For example, the default `languages.toml` sets rust's `auto-format` to `true`. If a user wants to disable auto-format, they can change the `languages.toml` in their [configuration directory](./configuration.md) to make the rust entry read like the example below; the new key/value pair `auto-format = false` will override the default when the two sets of settings are merged on start-up:
## `languages.toml` files
There are three possible `languages.toml` files. The first is compiled into
Helix and lives in the [Helix repository](https://github.com/helix-editor/helix/blob/master/languages.toml).
This provides the default configurations for languages and language servers.
You may define a `languages.toml` in your [configuration directory](./configuration.md)
which overrides values from the built-in language configuration. For example
to disable auto-LSP-formatting in Rust:
```toml
# in <config_dir>/helix/languages.toml
@@ -12,23 +21,130 @@ name = "rust"
auto-format = false
```
## Tree-sitter grammars
Language configuration may also be overridden local to a project by creating
a `languages.toml` file under a `.helix` directory. Its settings will be merged
with the language configuration in the configuration directory and the built-in
configuration.
Tree-sitter grammars can also be configured in `languages.toml`:
## Language configuration
Each language is configured by adding a `[[language]]` section to a
`languages.toml` file. For example:
```toml
# in <config_dir>/helix/languages.toml
[[grammar]]
name = "rust"
source = { git = "https://github.com/tree-sitter/tree-sitter-rust", rev = "a250c4582510ff34767ec3b7dcdd3c24e8c8aa68" }
[[grammar]]
name = "c"
source = { path = "/path/to/tree-sitter-c" }
[[language]]
name = "mylang"
scope = "source.mylang"
injection-regex = "^mylang$"
file-types = ["mylang", "myl"]
comment-token = "#"
indent = { tab-width = 2, unit = " " }
language-server = { command = "mylang-lsp", args = ["--stdio"], environment = { "ENV1" = "value1", "ENV2" = "value2" } }
formatter = { command = "mylang-formatter" , args = ["--stdin"] }
```
You may use a top-level `use-grammars` key to control which grammars are fetched and built.
These configuration keys are available:
| Key | Description |
| ---- | ----------- |
| `name` | The name of the language |
| `scope` | A string like `source.js` that identifies the language. Currently, we strive to match the scope names used by popular TextMate grammars and by the Linguist library. Usually `source.<name>` or `text.<name>` in case of markup languages |
| `injection-regex` | regex pattern that will be tested against a language name in order to determine whether this language should be used for a potential [language injection][treesitter-language-injection] site. |
| `file-types` | The filetypes of the language, for example `["yml", "yaml"]`. See the file-type detection section below. |
| `shebangs` | The interpreters from the shebang line, for example `["sh", "bash"]` |
| `roots` | A set of marker files to look for when trying to find the workspace root. For example `Cargo.lock`, `yarn.lock` |
| `auto-format` | Whether to autoformat this language when saving |
| `diagnostic-severity` | Minimal severity of diagnostic for it to be displayed. (Allowed values: `Error`, `Warning`, `Info`, `Hint`) |
| `comment-token` | The token to use as a comment-token |
| `indent` | The indent to use. Has sub keys `tab-width` and `unit` |
| `language-server` | The Language Server to run. See the Language Server configuration section below. |
| `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 |
| `max-line-length` | Maximum line length. Used for the `:reflow` command |
### File-type detection and the `file-types` key
Helix determines which language configuration to use with the `file-types` key
from the above section. `file-types` is a list of strings or tables, for
example:
```toml
file-types = ["Makefile", "toml", { suffix = ".git/config" }]
```
When determining a language configuration to use, Helix searches the file-types
with the following priorities:
1. Exact match: if the filename of a file is an exact match of a string in a
`file-types` list, that language wins. In the example above, `"Makefile"`
will match against `Makefile` files.
2. Extension: if there are no exact matches, any `file-types` string that
matches the file extension of a given file wins. In the example above, the
`"toml"` matches files like `Cargo.toml` or `languages.toml`.
3. Suffix: if there are still no matches, any values in `suffix` tables
are checked against the full path of the given file. In the example above,
the `{ suffix = ".git/config" }` would match against any `config` files
in `.git` directories. Note: `/` is used as the directory separator but is
replaced at runtime with the appropriate path separator for the operating
system, so this rule would match against `.git\config` files on Windows.
### Language Server configuration
The `language-server` field takes the following keys:
| Key | Description |
| --- | ----------- |
| `command` | The name of the language server binary to execute. Binaries must be in `$PATH` |
| `args` | A list of arguments to pass to the language server binary |
| `timeout` | The maximum time a request to the language server may take, in seconds. Defaults to `20` |
| `language-id` | The language name to pass to the language server. Some language servers support multiple languages and use this field to determine which one is being served in a buffer |
| `environment` | Any environment variables that will be used when starting the language server `{ "KEY1" = "Value1", "KEY2" = "Value2" }` |
The top-level `config` field is used to configure the LSP initialization options. A `format`
sub-table within `config` can be used to pass extra formatting options to
[Document Formatting Requests](https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-16.md#document-formatting-request--leftwards_arrow_with_hook).
For example with typescript:
```toml
[[language]]
name = "typescript"
auto-format = true
# pass format options according to https://github.com/typescript-language-server/typescript-language-server#workspacedidchangeconfiguration omitting the "[language].format." prefix.
config = { format = { "semicolons" = "insert", "insertSpaceBeforeFunctionParenthesis" = true } }
```
## Tree-sitter grammar configuration
The source for a language's tree-sitter grammar is specified in a `[[grammar]]`
section in `languages.toml`. For example:
```toml
[[grammar]]
name = "mylang"
source = { git = "https://github.com/example/mylang", rev = "a250c4582510ff34767ec3b7dcdd3c24e8c8aa68" }
```
Grammar configuration takes these keys:
| Key | Description |
| --- | ----------- |
| `name` | The name of the tree-sitter grammar |
| `source` | The method of fetching the grammar - a table with a schema defined below |
Where `source` is a table with either these keys when using a grammar from a
git repository:
| Key | Description |
| --- | ----------- |
| `git` | A git remote URL from which the grammar should be cloned |
| `rev` | The revision (commit hash or tag) which should be fetched |
| `subpath` | A path within the grammar directory which should be built. Some grammar repositories host multiple grammars (for example `tree-sitter-typescript` and `tree-sitter-ocaml`) in subdirectories. This key is used to point `hx --grammar build` to the correct path for compilation. When omitted, the root of repository is used |
### Choosing grammars
You may use a top-level `use-grammars` key to control which grammars are
fetched and built when using `hx --grammar fetch` and `hx --grammar build`.
```toml
# Note: this key must come **before** the [[language]] and [[grammar]] sections
@@ -38,3 +154,5 @@ use-grammars = { except = [ "yaml", "json" ] }
```
When omitted, all grammars are fetched and built.
[treesitter-language-injection]: https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection

View File

@@ -11,11 +11,11 @@ this:
```toml
# At most one section each of 'keys.normal', 'keys.insert' and 'keys.select'
[keys.normal]
C-s = ":w" # Maps the Control-s to the typable command :w which is an alias for :write (save file)
C-o = ":open ~/.config/helix/config.toml" # Maps the Control-o to opening of the helix config file
C-s = ":w" # Maps the Ctrl-s to the typable command :w which is an alias for :write (save file)
C-o = ":open ~/.config/helix/config.toml" # Maps the Ctrl-o to opening of the helix config file
a = "move_char_left" # Maps the 'a' key to the move_char_left command
w = "move_line_up" # Maps the 'w' key move_line_up
"C-S-esc" = "extend_line" # Maps Control-Shift-Escape to extend_line
"C-S-esc" = "extend_line" # Maps Ctrl-Shift-Escape to extend_line
g = { a = "code_action" } # Maps `ga` to show possible code actions
"ret" = ["open_below", "normal_mode"] # Maps the enter key to open_below then re-enter normal mode
@@ -25,7 +25,7 @@ j = { k = "normal_mode" } # Maps `jk` to exit insert mode
```
> NOTE: Typable commands can also be remapped, remember to keep the `:` prefix to indicate it's a typable command.
Control, Shift and Alt modifiers are encoded respectively with the prefixes
Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes
`C-`, `S-` and `A-`. Special keys are encoded as follows:
| Key name | Representation |
@@ -33,12 +33,7 @@ Control, Shift and Alt modifiers are encoded respectively with the prefixes
| Backspace | `"backspace"` |
| Space | `"space"` |
| Return/Enter | `"ret"` |
| < | `"lt"` |
| \> | `"gt"` |
| \+ | `"plus"` |
| \- | `"minus"` |
| ; | `"semicolon"` |
| % | `"percent"` |
| Left | `"left"` |
| Right | `"right"` |
| Up | `"up"` |

View File

@@ -13,10 +13,10 @@ The default theme.toml can be found [here](https://github.com/helix-editor/helix
Each line in the theme file is specified as below:
```toml
key = { fg = "#ffffff", bg = "#000000", modifiers = ["bold", "italic"] }
key = { fg = "#ffffff", bg = "#000000", underline = { color = "#ff0000", style = "curl"}, modifiers = ["bold", "italic"] }
```
where `key` represents what you want to style, `fg` specifies the foreground color, `bg` the background color, and `modifiers` is a list of style modifiers. `bg` and `modifiers` can be omitted to defer to the defaults.
where `key` represents what you want to style, `fg` specifies the foreground color, `bg` the background color, `underline` the underline `style`/`color`, and `modifiers` is a list of style modifiers. `bg`, `underline` and `modifiers` can be omitted to defer to the defaults.
To specify only the foreground color:
@@ -37,8 +37,8 @@ configuration values in your theme. To do this, add a table called
`palette` to your theme file:
```toml
ui.background = "white"
ui.text = "black"
"ui.background" = "white"
"ui.text" = "black"
[palette]
white = "#ffffff"
@@ -77,17 +77,50 @@ The following values may be used as modifiers.
Less common modifiers might not be supported by your terminal emulator.
| Modifier |
| --- |
| `bold` |
| `dim` |
| `italic` |
| `underlined` |
| `slow_blink` |
| `rapid_blink` |
| `reversed` |
| `hidden` |
| `crossed_out` |
> Note: The `underlined` modifier is deprecated and only available for backwards compatibility.
> Its behavior is equivalent to setting `underline.style="line"`.
### Underline Style
One of the following values may be used as a value for `underline.style`.
Some styles might not be supported by your terminal emulator.
| Modifier |
| --- |
| `bold` |
| `dim` |
| `italic` |
| `underlined` |
| `slow_blink` |
| `rapid_blink` |
| `reversed` |
| `hidden` |
| `crossed_out` |
| `line` |
| `curl` |
| `dashed` |
| `dotted` |
| `double_line` |
### Inheritance
Extend upon other themes by setting the `inherits` property to an existing theme.
```toml
inherits = "boo_berry"
# Override the theming for "keyword"s:
"keyword" = { fg = "gold" }
# Override colors in the palette:
[palette]
berry = "#2A2A4D"
```
### Scopes
@@ -103,6 +136,8 @@ We use a similar set of scopes as
[SublimeText](https://www.sublimetext.com/docs/scope_naming.html). See also
[TextMate](https://macromates.com/manual/en/language_grammars) scopes.
- `attribute` - Class attributes, html tag attributes
- `type` - Types
- `builtin` - Primitive types provided by the language (`int`, `usize`)
- `constructor`
@@ -133,13 +168,13 @@ We use a similar set of scopes as
- `parameter` - Function parameters
- `other`
- `member` - Fields of composite data types (e.g. structs, unions)
- `function` (TODO: ?)
- `label`
- `punctuation`
- `delimiter` - Commas, colons
- `bracket` - Parentheses, angle brackets, etc.
- `special` - String interpolation brackets.
- `keyword`
- `control`
@@ -151,6 +186,9 @@ We use a similar set of scopes as
- `operator` - `or`, `in`
- `directive` - Preprocessor directives (`#if` in C)
- `function` - `fn`, `func`
- `storage` - Keywords describing how things are stored
- `type` - The type of something, `class`, `function`, `var`, `let`, etc.
- `modifier` - Storage modifiers like `static`, `mut`, `const`, `ref`, etc.
- `operator` - `||`, `+=`, `>`
@@ -158,7 +196,7 @@ We use a similar set of scopes as
- `builtin`
- `method`
- `macro`
- `special` (preprocesor in C)
- `special` (preprocessor in C)
- `tag` - Tags (e.g. `<body>` in HTML)
@@ -205,32 +243,58 @@ These scopes are used for theming the editor interface.
- `hover` - for hover popup ui
| Key | Notes |
| --- | --- |
| `ui.background` | |
| `ui.cursor` | |
| `ui.cursor.insert` | |
| `ui.cursor.select` | |
| `ui.cursor.match` | Matching bracket etc. |
| `ui.cursor.primary` | Cursor with primary selection |
| `ui.linenr` | |
| `ui.linenr.selected` | |
| `ui.statusline` | Statusline |
| `ui.statusline.inactive` | Statusline (unfocused document) |
| `ui.popup` | |
| `ui.popup.info` | |
| `ui.window` | |
| `ui.help` | |
| `ui.text` | |
| `ui.text.focus` | |
| `ui.text.info` | |
| `ui.menu` | |
| `ui.menu.selected` | |
| `ui.selection` | For selections in the editing area |
| `ui.selection.primary` | |
| `warning` | Diagnostics warning (gutter) |
| `error` | Diagnostics error (gutter) |
| `info` | Diagnostics info (gutter) |
| `hint` | Diagnostics hint (gutter) |
| `diagnostic` | For text in editing area |
| Key | Notes |
| --- | --- |
| `ui.background` | |
| `ui.background.separator` | Picker separator below input line |
| `ui.cursor` | |
| `ui.cursor.insert` | |
| `ui.cursor.select` | |
| `ui.cursor.match` | Matching bracket etc. |
| `ui.cursor.primary` | Cursor with primary selection |
| `ui.gutter` | Gutter |
| `ui.gutter.selected` | Gutter for the line the cursor is on |
| `ui.linenr` | Line numbers |
| `ui.linenr.selected` | Line number for the line the cursor is on |
| `ui.statusline` | Statusline |
| `ui.statusline.inactive` | Statusline (unfocused document) |
| `ui.statusline.normal` | Statusline mode during normal mode ([only if `editor.color-modes` is enabled][editor-section]) |
| `ui.statusline.insert` | Statusline mode during insert mode ([only if `editor.color-modes` is enabled][editor-section]) |
| `ui.statusline.select` | Statusline mode during select mode ([only if `editor.color-modes` is enabled][editor-section]) |
| `ui.statusline.separator` | Separator character in statusline |
| `ui.popup` | Documentation popups (e.g Space + k) |
| `ui.popup.info` | Prompt for multiple key options |
| `ui.window` | Border lines separating splits |
| `ui.help` | Description box for commands |
| `ui.text` | Command prompts, popup text, etc. |
| `ui.text.focus` | |
| `ui.text.info` | The key: command text in `ui.popup.info` boxes |
| `ui.virtual.ruler` | Ruler columns (see the [`editor.rulers` config][editor-section]) |
| `ui.virtual.whitespace` | Visible whitespace characters |
| `ui.virtual.indent-guide` | Vertical indent width guides |
| `ui.menu` | Code and command completion menus |
| `ui.menu.selected` | Selected autocomplete item |
| `ui.menu.scroll` | `fg` sets thumb color, `bg` sets track color of scrollbar |
| `ui.selection` | For selections in the editing area |
| `ui.selection.primary` | |
| `ui.cursorline.primary` | The line of the primary cursor ([if cursorline is enabled][editor-section]) |
| `ui.cursorline.secondary` | The lines of any other cursors ([if cursorline is enabled][editor-section]) |
| `ui.cursorcolumn.primary` | The column of the primary cursor ([if cursorcolumn is enabled][editor-section]) |
| `ui.cursorcolumn.secondary` | The columns of any other cursors ([if cursorcolumn is enabled][editor-section]) |
| `warning` | Diagnostics warning (gutter) |
| `error` | Diagnostics error (gutter) |
| `info` | Diagnostics info (gutter) |
| `hint` | Diagnostics hint (gutter) |
| `diagnostic` | Diagnostics fallback style (editing area) |
| `diagnostic.hint` | Diagnostics hint (editing area) |
| `diagnostic.info` | Diagnostics info (editing area) |
| `diagnostic.warning` | Diagnostics warning (editing area) |
| `diagnostic.error` | Diagnostics error (editing area) |
You can check compliance to spec with
```shell
cargo xtask themelint onedark # replace onedark with <name>
```
[editor-section]: ./configuration.md#editor-section

View File

@@ -6,6 +6,7 @@ Docs for bleeding edge master can be found at
See the [usage] section for a quick overview of the editor, [keymap]
section for all available keybindings and the [configuration] section
for defining custom keybindings, setting themes, etc.
For everything else (e.g., how to install supported language servers), see the [Helix Wiki].
Refer the [FAQ] for common questions.
@@ -13,3 +14,4 @@ Refer the [FAQ] for common questions.
[usage]: ./usage.md
[keymap]: ./keymap.md
[configuration]: ./configuration.md
[Helix Wiki]: https://github.com/helix-editor/helix/wiki

View File

@@ -2,7 +2,7 @@
(Currently not fully documented, see the [keymappings](./keymap.md) list for more.)
See [tutor.txt](https://github.com/helix-editor/helix/blob/master/runtime/tutor.txt) (accessible via `hx --tutor` or `:tutor`) for a vimtutor-like introduction.
See [tutor](https://github.com/helix-editor/helix/blob/master/runtime/tutor) (accessible via `hx --tutor` or `:tutor`) for a vimtutor-like introduction.
## Registers
@@ -51,25 +51,99 @@ It can also act on multiple selections (yay!). For example, to change every occu
Multiple characters are currently not supported, but planned.
## Textobjects
## Syntax-tree Motions
Currently supported: `word`, `surround`, `function`, `class`, `parameter`.
`Alt-p`, `Alt-o`, `Alt-i`, and `Alt-n` (or `Alt` and arrow keys) move the primary
selection according to the selection's place in the syntax tree. Let's walk
through an example to get familiar with them. Many languages have a syntax like
so for function calls:
```
func(arg1, arg2, arg3)
```
A function call might be parsed by tree-sitter into a tree like the following.
```tsq
(call
function: (identifier) ; func
arguments:
(arguments ; (arg1, arg2, arg3)
(identifier) ; arg1
(identifier) ; arg2
(identifier))) ; arg3
```
Use `:tree-sitter-subtree` to view the syntax tree of the primary selection. In
a more intuitive tree format:
```
┌────┐
│call│
┌─────┴────┴─────┐
│ │
┌─────▼────┐ ┌────▼────┐
│identifier│ │arguments│
│ "func" │ ┌────┴───┬─────┴───┐
└──────────┘ │ │ │
│ │ │
┌─────────▼┐ ┌────▼─────┐ ┌▼─────────┐
│identifier│ │identifier│ │identifier│
│ "arg1" │ │ "arg2" │ │ "arg3" │
└──────────┘ └──────────┘ └──────────┘
```
Say we have a selection that wraps `arg1`. The selection is on the `arg1` leaf
in the tree above.
```
func([arg1], arg2, arg3)
```
Using `Alt-n` would select the next sibling in the syntax tree: `arg2`.
```
func(arg1, [arg2], arg3)
```
While `Alt-o` would expand the selection to the parent node. In the tree above we
can see that we would select the `arguments` node.
```
func[(arg1, arg2, arg3)]
```
There is also some nuanced behavior that prevents you from getting stuck on a
node with no sibling. If we have a selection on `arg1`, `Alt-p` would bring us
to the previous child node. Since `arg1` doesn't have a sibling to its left,
though, we climb the syntax tree and then take the previous selection. So
`Alt-p` will move the selection over to the "func" `identifier`.
```
[func](arg1, arg2, arg3)
```
## Textobjects
![textobject-demo](https://user-images.githubusercontent.com/23398472/124231131-81a4bb00-db2d-11eb-9d10-8e577ca7b177.gif)
![textobject-treesitter-demo](https://user-images.githubusercontent.com/23398472/132537398-2a2e0a54-582b-44ab-a77f-eb818942203d.gif)
- `ma` - Select around the object (`va` in vim, `<alt-a>` in kakoune)
- `mi` - Select inside the object (`vi` in vim, `<alt-i>` in kakoune)
- `ma` - Select around the object (`va` in Vim, `<alt-a>` in Kakoune)
- `mi` - Select inside the object (`vi` in Vim, `<alt-i>` in Kakoune)
| Key after `mi` or `ma` | Textobject selected |
| --- | --- |
| `w` | Word |
| `W` | WORD |
| `p` | Paragraph |
| `(`, `[`, `'`, etc | Specified surround pairs |
| `m` | Closest surround pair |
| `f` | Function |
| `c` | Class |
| `a` | Argument/parameter |
| `o` | Comment |
| `t` | Test |
| `g` | Change |
> NOTE: `f`, `c`, etc need a tree-sitter grammar active for the current
document and a special tree-sitter query file to work properly. [Only

View File

@@ -601,10 +601,10 @@ function playground_text(playground) {
});
})();
(function controllMenu() {
(function controlMenu() {
var menu = document.getElementById('menu-bar');
(function controllPosition() {
(function controlPosition() {
var scrollTop = document.scrollingElement.scrollTop;
var prevScrollTop = scrollTop;
var minMenuY = -menu.clientHeight - 50;
@@ -647,7 +647,7 @@ function playground_text(playground) {
prevScrollTop = scrollTop;
}, { passive: true });
})();
(function controllBorder() {
(function controlBorder() {
menu.classList.remove('bordered');
document.addEventListener('scroll', function () {
if (menu.offsetTop === 0) {

View File

@@ -390,7 +390,7 @@ ul#searchresults span.teaser em {
.chapter li {
display: flex;
color: var(--sidebar-non-existant);
color: var(--sidebar-non-existent);
}
.chapter li a {
display: block;

View File

@@ -16,7 +16,7 @@
--sidebar-bg: #14191f;
--sidebar-fg: #c8c9db;
--sidebar-non-existant: #5c6773;
--sidebar-non-existent: #5c6773;
--sidebar-active: #ffb454;
--sidebar-spacer: #2d334f;
@@ -56,7 +56,7 @@
--sidebar-bg: #292c2f;
--sidebar-fg: #a1adb8;
--sidebar-non-existant: #505254;
--sidebar-non-existent: #505254;
--sidebar-active: #3473ad;
--sidebar-spacer: #393939;
@@ -96,7 +96,7 @@
--sidebar-bg: #fafafa;
--sidebar-fg: hsl(0, 0%, 0%);
--sidebar-non-existant: #aaaaaa;
--sidebar-non-existent: #aaaaaa;
--sidebar-active: #1f1fff;
--sidebar-spacer: #f4f4f4;
@@ -136,7 +136,7 @@
--sidebar-bg: #282d3f;
--sidebar-fg: #c8c9db;
--sidebar-non-existant: #505274;
--sidebar-non-existent: #505274;
--sidebar-active: #2b79a2;
--sidebar-spacer: #2d334f;
@@ -176,7 +176,7 @@
--sidebar-bg: #3b2e2a;
--sidebar-fg: #c8c9db;
--sidebar-non-existant: #505254;
--sidebar-non-existent: #505254;
--sidebar-active: #e69f67;
--sidebar-spacer: #45373a;
@@ -217,7 +217,7 @@
--sidebar-bg: #292c2f;
--sidebar-fg: #a1adb8;
--sidebar-non-existant: #505254;
--sidebar-non-existent: #505254;
--sidebar-active: #3473ad;
--sidebar-spacer: #393939;
@@ -259,7 +259,7 @@
--sidebar-bg: #281733;
--sidebar-fg: #c8c9db;
--sidebar-non-existant: #505274;
--sidebar-non-existent: #505274;
--sidebar-active: #a4a0e8;
--sidebar-spacer: #2d334f;
@@ -304,7 +304,7 @@
--sidebar-bg: #281733;
--sidebar-fg: #c8c9db;
--sidebar-non-existant: #505274;
--sidebar-non-existent: #505274;
--sidebar-active: #a4a0e8;
--sidebar-spacer: #2d334f;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -1,22 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 199.7 184.2">
<style>
@media (prefers-color-scheme: dark) {
svg { fill: white; }
}
</style>
<path d="M189.5,36.8c0.2,2.8,0,5.1-0.6,6.8L153,162c-0.6,2.1-2,3.7-4.2,5c-2.2,1.2-4.4,1.9-6.7,1.9H31.4c-9.6,0-15.3-2.8-17.3-8.4
c-0.8-2.2-0.8-3.9,0.1-5.2c0.9-1.2,2.4-1.8,4.6-1.8H123c7.4,0,12.6-1.4,15.4-4.1s5.7-8.9,8.6-18.4l32.9-108.6
c1.8-5.9,1-11.1-2.2-15.6S169.9,0,164,0H72.7c-1,0-3.1,0.4-6.1,1.1l0.1-0.4C64.5,0.2,62.6,0,61,0.1s-3,0.5-4.3,1.4
c-1.3,0.9-2.4,1.8-3.2,2.8S52,6.5,51.2,8.1c-0.8,1.6-1.4,3-1.9,4.3s-1.1,2.7-1.8,4.2c-0.7,1.5-1.3,2.7-2,3.7c-0.5,0.6-1.2,1.5-2,2.5
s-1.6,2-2.2,2.8s-0.9,1.5-1.1,2.2c-0.2,0.7-0.1,1.8,0.2,3.2c0.3,1.4,0.4,2.4,0.4,3.1c-0.3,3-1.4,6.9-3.3,11.6
c-1.9,4.7-3.6,8.1-5.1,10.1c-0.3,0.4-1.2,1.3-2.6,2.7c-1.4,1.4-2.3,2.6-2.6,3.7c-0.3,0.4-0.3,1.5-0.1,3.4c0.3,1.8,0.4,3.1,0.3,3.8
c-0.3,2.7-1.3,6.3-3,10.8c-1.7,4.5-3.4,8.2-5,11c-0.2,0.5-0.9,1.4-2,2.8c-1.1,1.4-1.8,2.5-2,3.4c-0.2,0.6-0.1,1.8,0.1,3.4
c0.2,1.6,0.2,2.8-0.1,3.6c-0.6,3-1.8,6.7-3.6,11c-1.8,4.3-3.6,7.9-5.4,11c-0.5,0.8-1.1,1.7-2,2.8c-0.8,1.1-1.5,2-2,2.8
s-0.8,1.6-1,2.5c-0.1,0.5,0,1.3,0.4,2.3c0.3,1.1,0.4,1.9,0.4,2.6c-0.1,1.1-0.2,2.6-0.5,4.4c-0.2,1.8-0.4,2.9-0.4,3.2
c-1.8,4.8-1.7,9.9,0.2,15.2c2.2,6.2,6.2,11.5,11.9,15.8c5.7,4.3,11.7,6.4,17.8,6.4h110.7c5.2,0,10.1-1.7,14.7-5.2s7.7-7.8,9.2-12.9
l33-108.6c1.8-5.8,1-10.9-2.2-15.5C194.9,39.7,192.6,38,189.5,36.8z M59.6,122.8L73.8,80c0,0,7,0,10.8,0s28.8-1.7,25.4,17.5
c-3.4,19.2-18.8,25.2-36.8,25.4S59.6,122.8,59.6,122.8z M78.6,116.8c4.7-0.1,18.9-2.9,22.1-17.1S89.2,86.3,89.2,86.3l-8.9,0
l-10.2,30.5C70.2,116.9,74,116.9,78.6,116.8z M75.3,68.7L89,26.2h9.8l0.8,34l23.6-34h9.9l-13.6,42.5h-7.1l12.5-35.4l-24.5,35.4h-6.8
l-0.8-35L82,68.7H75.3z"/>
</svg>
<!-- Original image Copyright Dave Gandy — CC BY 4.0 License -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;" viewBox="663.38 37.57 575.35 903.75"> <g transform="matrix(1,0,0,1,-31352.7,-1817.25)"> <g transform="matrix(1,0,0,1,31062.7,-20.8972)"> <g transform="matrix(1,0,0,1,-130.173,0.00185558)"> <path d="M1083.58,1875.72L1635.06,2194.12C1649.8,2202.63 1658.88,2218.37 1658.88,2235.39C1658.88,2264.98 1658.88,2311.74 1658.88,2341.33C1658.88,2349.84 1656.61,2358.03 1652.5,2365.16C1652.5,2365.16 1214.7,2112.4 1107.2,2050.33C1092.58,2041.89 1083.58,2026.29 1083.58,2009.41C1083.58,1963.5 1083.58,1875.72 1083.58,1875.72Z" style="fill:#706bc8;"></path> </g> <g transform="matrix(1,0,0,1,-130.173,0.00185558)"> <path d="M1635.26,2604.84C1649.88,2613.28 1658.88,2628.87 1658.88,2645.75C1658.88,2691.67 1658.88,2779.44 1658.88,2779.44L1107.41,2461.05C1092.66,2452.53 1083.58,2436.8 1083.58,2419.78C1083.58,2390.19 1083.58,2343.42 1083.58,2313.84C1083.58,2305.32 1085.85,2297.13 1089.96,2290.01C1089.96,2290.01 1527.76,2542.77 1635.26,2604.84Z" style="fill:#55c5e4;"></path> </g> <g transform="matrix(1,0,0,1,216.062,984.098)"> <path d="M790.407,1432.56C785.214,1435.55 780.717,1439.9 777.509,1445.46C767.862,1462.16 773.473,1483.76 790.004,1493.59L789.998,1493.59L761.173,1476.95C746.427,1468.44 737.344,1452.71 737.344,1435.68C737.344,1406.09 737.344,1359.33 737.344,1329.74C737.344,1312.71 746.427,1296.98 761.173,1288.47L1259.59,1000.74L1259.83,1000.6C1264.92,997.617 1269.33,993.314 1272.48,987.844C1282.13,971.136 1276.52,949.544 1259.99,939.707L1260,939.707L1288.82,956.349C1303.57,964.862 1312.65,980.595 1312.65,997.622C1312.65,1027.21 1312.65,1073.97 1312.65,1103.56C1312.65,1120.59 1303.57,1136.32 1288.82,1144.83L1259.19,1161.94L1259.59,1161.68L790.407,1432.56Z" style="fill:#84ddea;"></path> </g> <g transform="matrix(1,0,0,1,216.062,984.098)"> <path d="M790.407,1686.24C785.214,1689.23 780.717,1693.58 777.509,1699.13C767.862,1715.84 773.473,1737.43 790.004,1747.27L789.998,1747.27L761.173,1730.63C746.427,1722.12 737.344,1706.38 737.344,1689.36C737.344,1659.77 737.344,1613.01 737.344,1583.42C737.344,1566.39 746.427,1550.66 761.173,1542.15L1259.59,1254.42L1259.83,1254.28C1264.92,1251.29 1269.33,1246.99 1272.48,1241.52C1282.13,1224.81 1276.52,1203.22 1259.99,1193.38L1260,1193.38L1288.82,1210.03C1303.57,1218.54 1312.65,1234.27 1312.65,1251.3C1312.65,1280.89 1312.65,1327.65 1312.65,1357.24C1312.65,1374.26 1303.57,1390 1288.82,1398.51L1259.19,1415.61L1259.59,1415.36L790.407,1686.24Z" style="fill:#997bc8;"></path></g></g></g> </svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

89
contrib/Helix.desktop Normal file
View File

@@ -0,0 +1,89 @@
[Desktop Entry]
Name=Helix
GenericName=Text Editor
GenericName[de]=Texteditor
GenericName[fr]=Éditeur de texte
GenericName[ru]=Текстовый редактор
GenericName[sr]=Едитор текст
GenericName[tr]=Metin Düzenleyici
Comment=Edit text files
Comment[af]=Redigeer tekslêers
Comment[am]=የጽሑፍ ፋይሎች ያስተካክሉ
Comment[ar]=حرّر ملفات نصية
Comment[az]=Mətn fayllarını redaktə edin
Comment[be]=Рэдагаваньне тэкставых файлаў
Comment[bg]=Редактиране на текстови файлове
Comment[bn]=টেক্স্ট ফাইল এডিট করুন
Comment[bs]=Izmijeni tekstualne datoteke
Comment[ca]=Edita fitxers de text
Comment[cs]=Úprava textových souborů
Comment[cy]=Golygu ffeiliau testun
Comment[da]=Redigér tekstfiler
Comment[de]=Textdateien bearbeiten
Comment[el]=Επεξεργασία αρχείων κειμένου
Comment[en_CA]=Edit text files
Comment[en_GB]=Edit text files
Comment[es]=Edita archivos de texto
Comment[et]=Redigeeri tekstifaile
Comment[eu]=Editatu testu-fitxategiak
Comment[fa]=ویرایش پرونده‌های متنی
Comment[fi]=Muokkaa tekstitiedostoja
Comment[fr]=Éditer des fichiers texte
Comment[ga]=Eagar comhad Téacs
Comment[gu]=લખાણ ફાઇલોમાં ફેરફાર કરો
Comment[he]=ערוך קבצי טקסט
Comment[hi]=पाठ फ़ाइलें संपादित करें
Comment[hr]=Uređivanje tekstualne datoteke
Comment[hu]=Szövegfájlok szerkesztése
Comment[id]=Edit file teks
Comment[it]=Modifica file di testo
Comment[ja]=テキストファイルを編集します
Comment[kn]=ಪಠ್ಯ ಕಡತಗಳನ್ನು ಸಂಪಾದಿಸು
Comment[ko]=텍스트 파일을 편집합니다
Comment[lt]=Redaguoti tekstines bylas
Comment[lv]=Rediģēt teksta failus
Comment[mk]=Уреди текстуални фајлови
Comment[ml]=വാചക രചനകള് തിരുത്തുക
Comment[mn]=Текст файл боловсруулах
Comment[mr]=गद्य फाइल संपादित करा
Comment[ms]=Edit fail teks
Comment[nb]=Rediger tekstfiler
Comment[ne]=पाठ फाइललाई संशोधन गर्नुहोस्
Comment[nl]=Tekstbestanden bewerken
Comment[nn]=Rediger tekstfiler
Comment[no]=Rediger tekstfiler
Comment[or]=ପାଠ୍ଯ ଫାଇଲଗୁଡ଼ିକୁ ସମ୍ପାଦନ କରନ୍ତୁ
Comment[pa]=ਪਾਠ ਫਾਇਲਾਂ ਸੰਪਾਦਨ
Comment[pl]=Edytor plików tekstowych
Comment[pt]=Editar ficheiros de texto
Comment[pt_BR]=Edite arquivos de texto
Comment[ro]=Editare fişiere text
Comment[ru]=Редактирование текстовых файлов
Comment[sk]=Úprava textových súborov
Comment[sl]=Urejanje datotek z besedili
Comment[sq]=Përpuno files teksti
Comment[sr]=Уређујте текст фајлове
Comment[sr@Latn]=Izmeni tekstualne datoteke
Comment[sv]=Redigera textfiler
Comment[ta]=உரை கோப்புகளை தொகுக்கவும்
Comment[th]=แก้ไขแฟ้มข้อความ
Comment[tk]=Metin faýllary editle
Comment[tr]=Metin dosyaları düzenleyin
Comment[uk]=Редактор текстових файлів
Comment[vi]=Soạn thảo tập tin văn bản
Comment[wa]=Asspougnî des fitchîs tecses
Comment[zh_CN]=编辑文本文件
Comment[zh_TW]=編輯文字檔
TryExec=hx
Exec=hx %F
Terminal=true
Type=Application
Keywords=Text;editor;
Keywords[fr]=Texte;éditeur;
Keywords[ru]=текст;текстовый редактор;
Keywords[sr]=Текст;едитор;
Keywords[tr]=Metin;düzenleyici;
Icon=helix
Categories=Utility;TextEditor;
StartupNotify=false
MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Bash completion script for Helix editor
_hx() {
# $1 command name
# $2 word being completed
# $3 word preceding
COMPREPLY=()
case "$3" in
-g | --grammar)
COMPREPLY=($(compgen -W "fetch build" -- $2))
;;
--health)
local languages=$(hx --health |tail -n '+7' |awk '{print $1}' |sed 's/\x1b\[[0-9;]*m//g')
COMPREPLY=($(compgen -W "$languages" -- $2))
;;
*)
COMPREPLY=($(compgen -fd -W "-h --help --tutor -V --version -v -vv -vvv --health -g --grammar --vsplit --hsplit -c --config --log" -- $2))
;;
esac
} && complete -o filenames -F _hx hx

55
contrib/completion/hx.elv Normal file
View File

@@ -0,0 +1,55 @@
# You can move it here ~/.config/elvish/lib/hx.elv
# Or add `eval (slurp < ~/$REPOS/helix/contrib/completion/hx.elv)`
# Be sure to replace `$REPOS` with something that makes sense for you!
### Renders a pretty completion candidate
var candidate = { | _stem _desc |
edit:complex-candidate $_stem &display=(styled $_stem bold)(styled " "$_desc dim)
}
### These commands will invalidate further input (i.e. not react to them)
var skips = [ "--tutor" "--help" "--version" "-V" "--health" ]
### Grammar commands
var grammar = [ "--grammar" "-g" ]
### Config commands
var config = [ "--config" "-c" ]
### Set an arg-completer for the `hx` binary
set edit:completion:arg-completer[hx] = {|@args|
var n = (count $args)
if (>= $n 3) {
# Stop completions if passed arg will take presedence
# and invalidate further input
if (has-value $skips $args[-2]) {
return
}
# If the previous arg == --grammar, then only suggest:
if (has-value $grammar $args[-2]) {
$candidate "fetch" "Fetch the tree-sitter grammars"
$candidate "build" "Build the tree-sitter grammars"
return
}
# When we have --config, we need a file
if (has-values $config $args[-2]) {
edit:complete-filename $args[-1] | each { |v| put $v[stem] }
return
}
# When we have --log, we need a file
if (has-values "log" $args[-2]) {
edit:complete-filename $args[-1] | each { |v| put $v[stem] }
return
}
}
edit:complete-filename $args[-1] | each { |v| put $v[stem]}
$candidate "--help" "(Prints help information)"
$candidate "--version" "(Prints version information)"
$candidate "--tutor" "(Loads the tutorial)"
$candidate "--health" "(Checks for errors in editor setup)"
$candidate "--grammar" "(Fetch or build the tree-sitter grammars)"
$candidate "--vsplit" "(Splits all given files vertically)"
$candidate "--hsplit" "(Splits all given files horizontally)"
$candidate "--config" "(Specifies a file to use for configuration)"
$candidate "--log" "(Specifies a file to write log data into)"
}

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env fish
# Fish completion script for Helix editor
set -l langs (hx --health |tail -n '+7' |awk '{print $1}' |sed 's/\x1b\[[0-9;]*m//g')
complete -c hx -s h -l help -d "Prints help information"
complete -c hx -l tutor -d "Loads the tutorial"
complete -c hx -l health -x -a "$langs" -d "Checks for errors in editor setup"
complete -c hx -s g -l grammar -x -a "fetch build" -d "Fetches or builds tree-sitter grammars"
complete -c hx -s v -o vv -o vvv -d "Increases logging verbosity"
complete -c hx -s V -l version -d "Prints version information"
complete -c hx -l vsplit -d "Splits all given files vertically into different windows"
complete -c hx -l hsplit -d "Splits all given files horizontally into different windows"
complete -c hx -s c -l config -r -d "Specifies a file to use for completion"
complete -c hx -l log -r -d "Specifies a file to write log data into"

34
contrib/completion/hx.zsh Normal file
View File

@@ -0,0 +1,34 @@
#compdef _hx hx
# Zsh completion script for Helix editor
_hx() {
_arguments -C \
"-h[Prints help information]" \
"--help[Prints help information]" \
"-v[Increase logging verbosity]" \
"-vv[Increase logging verbosity]" \
"-vvv[Increase logging verbosity]" \
"-V[Prints version information]" \
"--version[Prints version information]" \
"--tutor[Loads the tutorial]" \
"--health[Checks for errors in editor setup]:language:->health" \
"-g[Fetches or builds tree-sitter grammars]:action:->grammar" \
"--grammar[Fetches or builds tree-sitter grammars]:action:->grammar" \
"--vsplit[Splits all given files vertically into different windows]" \
"--hsplit[Splits all given files horizontally into different windows]" \
"-c[Specifies a file to use for configuration]" \
"--config[Specifies a file to use for configuration]" \
"--log[Specifies a file to write log data into]" \
"*:file:_files"
case "$state" in
health)
local languages=($(hx --health |tail -n '+7' |awk '{print $1}' |sed 's/\x1b\[[0-9;]*m//g'))
_values 'language' $languages
;;
grammar)
_values 'action' fetch build
;;
esac
}

BIN
contrib/helix.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

8
default.nix Normal file
View File

@@ -0,0 +1,8 @@
# Flake's default package for non-flake-enabled nix instances
let
compat = builtins.fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/b4a34015c698c7793d592d66adbab377907a2be8.tar.gz";
sha256 = "sha256:1qc703yg0babixi6wshn5wm2kgl5y1drcswgszh4xxzbrwkk9sv7";
};
in
(import compat {src = ./.;}).defaultNix.default

View File

@@ -30,8 +30,23 @@ inside the project. We use [xtask][xtask] as an ad-hoc task runner and
thus do not require any dependencies other than `cargo` (You don't have
to `cargo install` anything either).
# Integration tests
Integration tests for helix-term can be run with `cargo integration-test`. Code
contributors are strongly encouraged to write integration tests for their code.
Existing tests can be used as examples. Helpers can be found in
[helpers.rs][helpers.rs]. The log level can be set with the `HELIX_LOG_LEVEL`
environment variable, e.g. `HELIX_LOG_LEVEL=debug cargo integration-test`.
## Minimum Stable Rust Version (MSRV) Policy
Helix follows the MSRV of Firefox.
The current MSRV and future changes to the MSRV are listed in the [Firefox documentation].
[Firefox documentation]: https://firefox-source-docs.mozilla.org/writing-rust-code/update-policy.html
[good-first-issue]: https://github.com/helix-editor/helix/labels/E-easy
[log-file]: https://github.com/helix-editor/helix/wiki/FAQ#access-the-log-file
[architecture.md]: ./architecture.md
[docs]: https://docs.helix-editor.com/
[xtask]: https://github.com/matklad/cargo-xtask
[helpers.rs]: ../helix-term/tests/test/helpers.rs

View File

@@ -32,7 +32,7 @@ represented by a `Selection`. Each `Range` in the selection consists of a moving
a selection with a single range, with the head and the anchor in the same
position.
Ropes are modified by constructing an OT-like `Transaction`. It's represents
Ropes are modified by constructing an OT-like `Transaction`. It represents
a single coherent change to the document and can be applied to the rope.
A transaction can be inverted to produce an undo. Selections and marks can be
mapped over a transaction to translate to a position in the new text state after
@@ -42,7 +42,7 @@ applying the transaction.
> interface used to generate text edits.
`Syntax` is the interface used to interact with tree-sitter ASTs for syntax
highling and other features.
highlighting and other features.
## View

59
docs/releases.md Normal file
View File

@@ -0,0 +1,59 @@
## Checklist
Helix releases are versioned in the Calendar Versioning scheme:
`YY.0M(.MICRO)`, for example `22.05` for May of 2022. In these instructions
we'll use `<tag>` as a placeholder for the tag being published.
* Merge the changelog PR
* Tag and push
* `git tag -s -m "<tag>" -a <tag> && git push`
* Make sure to switch to master and pull first
* Edit the `VERSION` file and change the date to the next planned release
* Releases are planned to happen every two months, so `22.05` would change to `22.07`
* Wait for the Release CI to finish
* It will automatically turn the git tag into a GitHub release when it uploads artifacts
* Edit the new release
* Use `<tag>` as the title
* Link to the changelog and release notes
* Merge the release notes PR
* Download the macos and linux binaries and update the `sha256`s in the [homebrew formula]
* Use `sha256sum` on the downloaded `.tar.xz` files to determine the hash
* Link to the release notes in this-week-in-rust
* [Example PR](https://github.com/rust-lang/this-week-in-rust/pull/3300)
* Post to reddit
* [Example post](https://www.reddit.com/r/rust/comments/uzp5ze/helix_editor_2205_released/)
[homebrew formula]: https://github.com/Homebrew/homebrew-core/blob/master/Formula/helix.rb
## Changelog Curation
The changelog is currently created manually by reading through commits in the
log since the last release. GitHub's compare view is a nice way to approach
this. For example when creating the 22.07 release notes, this compare link
may be used
```
https://github.com/helix-editor/helix/compare/22.05...master
```
Either side of the triple-dot may be replaced with an exact revision, so if
you wish to incrementally compile the changelog, you can tackle a weeks worth
or so, record the revision where you stopped, and use that as a starting point
next week:
```
https://github.com/helix-editor/helix/compare/7706a4a0d8b67b943c31d0c5f7b00d357b5d838d...master
```
A work-in-progress commit for a changelog might look like
[this example](https://github.com/helix-editor/helix/commit/831adfd4c709ca16b248799bfef19698d5175e55).
Not every PR or commit needs a blurb in the changelog. Each release section
tends to have a blurb that links to a GitHub comparison between release
versions for convenience:
> As usual, the following is a summary of each of the changes since the last
> release. For the full log, check out the git log.
Typically, small changes like dependencies or documentation updates, refactors,
or meta changes like GitHub Actions work are left out.

108
flake.lock generated
View File

@@ -3,11 +3,11 @@
"crane": {
"flake": false,
"locked": {
"lastModified": 1644785799,
"narHash": "sha256-VpAJO1L0XeBvtCuNGK4IDKp6ENHIpTrlaZT7yfBCvwo=",
"lastModified": 1661875961,
"narHash": "sha256-f1h/2c6Teeu1ofAHWzrS8TwBPcnN+EEu+z1sRVmMQTk=",
"owner": "ipetkov",
"repo": "crane",
"rev": "fc7a94f841347c88f2cb44217b2a3faa93e2a0b2",
"rev": "d9f394e4e20e97c2a60c3ad82c2b6ef99be19e24",
"type": "github"
},
"original": {
@@ -17,19 +17,13 @@
}
},
"devshell": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": [
"nixCargoIntegration",
"nixpkgs"
]
},
"flake": false,
"locked": {
"lastModified": 1646667754,
"narHash": "sha256-LahZHvCC3UVzGQ55iWDRZkuDssXl1rYgqgScrPV9S38=",
"lastModified": 1667210711,
"narHash": "sha256-IoErjXZAkzYWHEpQqwu/DeRNJGFdR7X2OGbkhMqMrpw=",
"owner": "numtide",
"repo": "devshell",
"rev": "59fbe1dfc0de8c3332957c16998a7d16dff365d8",
"rev": "96a9dd12b8a447840cc246e17a47b81a4268bba7",
"type": "github"
},
"original": {
@@ -41,61 +35,60 @@
"dream2nix": {
"inputs": {
"alejandra": [
"nixCargoIntegration",
"nixpkgs"
"nci"
],
"all-cabal-json": [
"nci"
],
"crane": "crane",
"devshell": [
"nci",
"devshell"
],
"flake-utils-pre-commit": [
"nixCargoIntegration",
"nixpkgs"
"nci"
],
"ghc-utils": [
"nci"
],
"gomod2nix": [
"nixCargoIntegration",
"nixpkgs"
"nci"
],
"mach-nix": [
"nixCargoIntegration",
"nixpkgs"
"nci"
],
"nixpkgs": [
"nixCargoIntegration",
"nixpkgs"
],
"node2nix": [
"nixCargoIntegration",
"nci",
"nixpkgs"
],
"poetry2nix": [
"nixCargoIntegration",
"nixpkgs"
"nci"
],
"pre-commit-hooks": [
"nixCargoIntegration",
"nixpkgs"
"nci"
]
},
"locked": {
"lastModified": 1646710334,
"narHash": "sha256-eLBcDgcbOUfeH4k6SEW5a5v0PTp2KNCn+5ZXIoWGYww=",
"lastModified": 1668851003,
"narHash": "sha256-X7RCQQynbxStZR2m7HW38r/msMQwVl3afD6UXOCtvx4=",
"owner": "nix-community",
"repo": "dream2nix",
"rev": "5dcfbfd3b60ce0208b894c1bdea00e2bdf80ca6a",
"rev": "c77e8379d8fe01213ba072e40946cbfb7b58e628",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "main",
"repo": "dream2nix",
"type": "github"
}
},
"flake-utils": {
"locked": {
"lastModified": 1642700792,
"narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=",
"lastModified": 1659877975,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "846b2ae0fc4cc943637d3d1def4454213e203cba",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"type": "github"
},
"original": {
@@ -104,38 +97,23 @@
"type": "github"
}
},
"flake-utils_2": {
"locked": {
"lastModified": 1637014545,
"narHash": "sha256-26IZAc5yzlD9FlDT54io1oqG/bBoyka+FJk5guaX4x4=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "bba5dcc8e0b20ab664967ad83d24d64cb64ec4f4",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixCargoIntegration": {
"nci": {
"inputs": {
"devshell": "devshell",
"dream2nix": "dream2nix",
"nixpkgs": [
"nixpkgs"
],
"rustOverlay": [
"rust-overlay": [
"rust-overlay"
]
},
"locked": {
"lastModified": 1646766572,
"narHash": "sha256-DV3+zxvAIKsMHsHedJKYFsracvFyLKpFQqurUBR86oY=",
"lastModified": 1669011203,
"narHash": "sha256-Lymj4HktNEFmVXtwI0Os7srDXHZbZW0Nzw3/+5Hf8ko=",
"owner": "yusdacra",
"repo": "nix-cargo-integration",
"rev": "3a3f47f43ba486b7554164a698c8dfc5a38624ce",
"rev": "c5133b91fc1d549087c91228bd213f2518728a4b",
"type": "github"
},
"original": {
@@ -146,11 +124,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1646497237,
"narHash": "sha256-Ccpot1h/rV8MgcngDp5OrdmLTMaUTbStZTR5/sI7zW0=",
"lastModified": 1668905981,
"narHash": "sha256-RBQa/+9Uk1eFTqIOXBSBezlEbA3v5OkgP+qptQs1OxY=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "062a0c5437b68f950b081bbfc8a699d57a4ee026",
"rev": "690ffff026b4e635b46f69002c0f4e81c65dfc2e",
"type": "github"
},
"original": {
@@ -162,24 +140,24 @@
},
"root": {
"inputs": {
"nixCargoIntegration": "nixCargoIntegration",
"nci": "nci",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"flake-utils": "flake-utils_2",
"flake-utils": "flake-utils",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1646792695,
"narHash": "sha256-2drCXIKIQnJMlTZbcCfuHZAh+iPcdlRkCqtZnA6MHLY=",
"lastModified": 1668998422,
"narHash": "sha256-G/BklIplCHZEeDIabaaxqgITdIXtMolRGlwxn9jG2/Q=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "7f599870402c8d2a5806086c8ee0f2d92b175c54",
"rev": "68ab029c93f8f8eed4cf3ce9a89a9fd4504b2d6e",
"type": "github"
},
"original": {

203
flake.nix
View File

@@ -7,59 +7,174 @@
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
nixCargoIntegration = {
nci = {
url = "github:yusdacra/nix-cargo-integration";
inputs.nixpkgs.follows = "nixpkgs";
inputs.rustOverlay.follows = "rust-overlay";
inputs.rust-overlay.follows = "rust-overlay";
};
};
outputs = inputs@{ nixCargoIntegration, ... }:
nixCargoIntegration.lib.makeOutputs {
root = ./.;
renameOutputs = { "helix-term" = "helix"; };
# Set default app to hx (binary is from helix-term release build)
# Set default package to helix-term release build
defaultOutputs = {
app = "hx";
package = "helix";
outputs = {
self,
nixpkgs,
nci,
...
}: let
lib = nixpkgs.lib;
ncl = nci.lib.nci-lib;
mkRootPath = rel:
builtins.path {
path = "${toString ./.}/${rel}";
name = rel;
};
overrides = {
crateOverrides = common: _: {
helix-term = prev:
let
inherit (common) pkgs;
grammars = pkgs.callPackage ./grammars.nix { };
runtimeDir = pkgs.runCommand "helix-runtime" { } ''
mkdir -p $out
ln -s ${common.root}/runtime/* $out
rm -r $out/grammars
ln -s ${grammars} $out/grammars
'';
in
{
# disable fetching and building of tree-sitter grammars in the helix-term build.rs
HELIX_DISABLE_AUTO_GRAMMAR_BUILD = "1";
# link languages and theme toml files since helix-term expects them (for tests)
preConfigure = "ln -s ${common.root}/{languages.toml,theme.toml,base16_theme.toml} ..";
buildInputs = (prev.buildInputs or [ ]) ++ [ common.cCompiler.cc.lib ];
nativeBuildInputs = [ pkgs.makeWrapper ];
postFixup = ''
if [ -f "$out/bin/hx" ]; then
wrapProgram "$out/bin/hx" --set HELIX_RUNTIME "${runtimeDir}"
fi
'';
};
filteredSource = let
pathsToIgnore = [
".envrc"
".ignore"
".github"
"runtime"
"screenshot.png"
"book"
"contrib"
"docs"
"README.md"
"CHANGELOG.md"
"shell.nix"
"default.nix"
"grammars.nix"
"flake.nix"
"flake.lock"
];
ignorePaths = path: type: let
# split the nix store path into its components
components = lib.splitString "/" path;
# drop off the `/nix/hash-source` section from the path
relPathComponents = lib.drop 4 components;
# reassemble the path components
relPath = lib.concatStringsSep "/" relPathComponents;
in
lib.all (p: ! (lib.hasPrefix p relPath)) pathsToIgnore;
in
builtins.path {
name = "helix-source";
path = toString ./.;
# filter out unnecessary paths
filter = ignorePaths;
};
outputs = nci.lib.makeOutputs {
root = ./.;
config = common: {
outputs = {
# rename helix-term to helix since it's our main package
rename = {"helix-term" = "helix";};
# Set default app to hx (binary is from helix-term release build)
# Set default package to helix-term release build
defaults = {
app = "hx";
package = "helix";
};
};
shell = common: prev: {
packages = prev.packages ++ (with common.pkgs; [ lld_13 lldb cargo-tarpaulin cargo-flamegraph ]);
env = prev.env ++ [
{ name = "HELIX_RUNTIME"; eval = "$PWD/runtime"; }
{ name = "RUST_BACKTRACE"; value = "1"; }
{ name = "RUSTFLAGS"; value = "-C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment"; }
cCompiler.package = with common.pkgs;
if stdenv.isLinux
then gcc
else clang;
shell = {
packages = with common.pkgs;
[lld_13 cargo-flamegraph rust-analyzer]
++ (lib.optional (stdenv.isx86_64 && stdenv.isLinux) cargo-tarpaulin)
++ (lib.optional stdenv.isLinux lldb);
env = [
{
name = "HELIX_RUNTIME";
eval = "$PWD/runtime";
}
{
name = "RUST_BACKTRACE";
value = "1";
}
{
name = "RUSTFLAGS";
value =
if common.pkgs.stdenv.isLinux
then "-C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment"
else "";
}
];
};
};
pkgConfig = common: {
helix-term = {
# Wrap helix with runtime
wrapper = _: old: let
inherit (common) pkgs;
makeOverridableHelix = old: config: let
grammars = pkgs.callPackage ./grammars.nix config;
runtimeDir = pkgs.runCommand "helix-runtime" {} ''
mkdir -p $out
ln -s ${mkRootPath "runtime"}/* $out
rm -r $out/grammars
ln -s ${grammars} $out/grammars
'';
helix-wrapped =
common.internal.pkgsSet.utils.wrapDerivation old
{
nativeBuildInputs = [pkgs.makeWrapper];
makeWrapperArgs = config.makeWrapperArgs or [];
}
''
rm -rf $out/bin
mkdir -p $out/bin
ln -sf ${old}/bin/* $out/bin/
wrapProgram "$out/bin/hx" ''${makeWrapperArgs[@]} --set HELIX_RUNTIME "${runtimeDir}"
'';
in
helix-wrapped
// {override = makeOverridableHelix old;};
in
makeOverridableHelix old {};
overrides.fix-build.overrideAttrs = prev: {
src = filteredSource;
# disable fetching and building of tree-sitter grammars in the helix-term build.rs
HELIX_DISABLE_AUTO_GRAMMAR_BUILD = "1";
buildInputs = ncl.addBuildInputs prev [common.config.cCompiler.package.cc.lib];
# link languages and theme toml files since helix-term expects them (for tests)
preConfigure = ''
${prev.preConfigure or ""}
${
lib.concatMapStringsSep
"\n"
(path: "ln -sf ${mkRootPath path} ..")
["languages.toml" "theme.toml" "base16_theme.toml"]
}
'';
checkPhase = ":";
meta.mainProgram = "hx";
};
};
};
};
in
outputs
// {
packages =
lib.mapAttrs
(
system: packages:
packages
// {
helix-unwrapped = packages.helix.passthru.unwrapped;
helix-unwrapped-dev = packages.helix-dev.passthru.unwrapped;
}
)
outputs.packages;
};
nixConfig = {
extra-substituters = ["https://helix.cachix.org"];
extra-trusted-public-keys = ["helix.cachix.org-1:ejp9KQpR1FBI2onstMQ34yogDm4OgU2ru6lIwPvuCVs="];
};
}

View File

@@ -1,15 +1,25 @@
{ stdenv, lib, runCommand, yj }:
let
{
stdenv,
lib,
runCommandLocal,
runCommand,
yj,
includeGrammarIf ? _: true,
...
}: let
# HACK: nix < 2.6 has a bug in the toml parser, so we convert to JSON
# before parsing
languages-json = runCommand "languages-toml-to-json" { } ''
languages-json = runCommandLocal "languages-toml-to-json" {} ''
${yj}/bin/yj -t < ${./languages.toml} > $out
'';
languagesConfig =
builtins.fromJSON (builtins.readFile (builtins.toPath languages-json));
isGitGrammar = (grammar:
builtins.hasAttr "source" grammar && builtins.hasAttr "git" grammar.source
&& builtins.hasAttr "rev" grammar.source);
if lib.versionAtLeast builtins.nixVersion "2.6.0"
then builtins.fromTOML (builtins.readFile ./languages.toml)
else builtins.fromJSON (builtins.readFile (builtins.toPath languages-json));
isGitGrammar = grammar:
builtins.hasAttr "source" grammar
&& builtins.hasAttr "git" grammar.source
&& builtins.hasAttr "rev" grammar.source;
isGitHubGrammar = grammar: lib.hasPrefix "https://github.com" grammar.source.git;
toGitHubFetcher = url: let
match = builtins.match "https://github\.com/([^/]*)/([^/]*)/?" url;
@@ -18,33 +28,36 @@ let
repo = builtins.elemAt match 1;
};
gitGrammars = builtins.filter isGitGrammar languagesConfig.grammar;
buildGrammar = grammar:
let
gh = toGitHubFetcher grammar.source.git;
sourceGit = builtins.fetchTree {
type = "git";
url = grammar.source.git;
rev = grammar.source.rev;
ref = grammar.source.ref or "HEAD";
shallow = true;
};
sourceGitHub = builtins.fetchTree {
type = "github";
owner = gh.owner;
repo = gh.repo;
inherit (grammar.source) rev;
};
source = if isGitHubGrammar grammar then sourceGitHub else sourceGit;
in stdenv.mkDerivation rec {
buildGrammar = grammar: let
gh = toGitHubFetcher grammar.source.git;
sourceGit = builtins.fetchTree {
type = "git";
url = grammar.source.git;
rev = grammar.source.rev;
ref = grammar.source.ref or "HEAD";
shallow = true;
};
sourceGitHub = builtins.fetchTree {
type = "github";
owner = gh.owner;
repo = gh.repo;
inherit (grammar.source) rev;
};
source =
if isGitHubGrammar grammar
then sourceGitHub
else sourceGit;
in
stdenv.mkDerivation rec {
# see https://github.com/NixOS/nixpkgs/blob/fbdd1a7c0bc29af5325e0d7dd70e804a972eb465/pkgs/development/tools/parsing/tree-sitter/grammar.nix
pname = "helix-tree-sitter-${grammar.name}";
version = grammar.source.rev;
src = if builtins.hasAttr "subpath" grammar.source then
"${source}/${grammar.source.subpath}"
else
source;
src =
if builtins.hasAttr "subpath" grammar.source
then "${source}/${grammar.source.subpath}"
else source;
dontUnpack = true;
dontConfigure = true;
@@ -91,14 +104,18 @@ let
runHook postFixup
'';
};
builtGrammars = builtins.map (grammar: {
inherit (grammar) name;
artifact = buildGrammar grammar;
}) gitGrammars;
grammarLinks = builtins.map (grammar:
"ln -s ${grammar.artifact}/${grammar.name}.so $out/${grammar.name}.so")
grammarsToBuild = builtins.filter includeGrammarIf gitGrammars;
builtGrammars =
builtins.map (grammar: {
inherit (grammar) name;
artifact = buildGrammar grammar;
})
grammarsToBuild;
grammarLinks =
builtins.map (grammar: "ln -s ${grammar.artifact}/${grammar.name}.so $out/${grammar.name}.so")
builtGrammars;
in runCommand "consolidated-helix-grammars" { } ''
mkdir -p $out
${builtins.concatStringsSep "\n" grammarLinks}
''
in
runCommand "consolidated-helix-grammars" {} ''
mkdir -p $out
${builtins.concatStringsSep "\n" grammarLinks}
''

View File

@@ -12,35 +12,40 @@ include = ["src/**/*", "README.md"]
[features]
unicode-lines = ["ropey/unicode_lines"]
integration = []
[dependencies]
helix-loader = { version = "0.6", path = "../helix-loader" }
ropey = { version = "1.4", default-features = false }
smallvec = "1.8"
ropey = { version = "1.5.1-alpha", default-features = false, features = ["simd"] }
smallvec = "1.10"
smartstring = "1.0.1"
unicode-segmentation = "1.9"
unicode-segmentation = "1.10"
unicode-width = "0.1"
unicode-general-category = "0.5"
unicode-general-category = "0.6"
# slab = "0.4.2"
slotmap = "1.0"
tree-sitter = "0.20"
once_cell = "1.10"
once_cell = "1.16"
arc-swap = "1"
regex = "1"
bitflags = "1.3"
ahash = "0.8.2"
hashbrown = { version = "0.13.1", features = ["raw"] }
log = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
toml = "0.5"
similar = "2.1"
imara-diff = "0.1.0"
encoding_rs = "0.8"
chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }
etcetera = "0.3"
etcetera = "0.4"
textwrap = "0.16.0"
[dev-dependencies]
quickcheck = { version = "1", default-features = false }

View File

@@ -1,16 +1,12 @@
//! When typing the opening character of one of the possible pairs defined below,
//! this module provides the functionality to insert the paired closing character.
use crate::{
graphemes, movement::Direction, Range, Rope, RopeGraphemes, Selection, Tendril, Transaction,
};
use crate::{graphemes, movement::Direction, Range, Rope, Selection, Tendril, Transaction};
use std::collections::HashMap;
use log::debug;
use smallvec::SmallVec;
// Heavily based on https://github.com/codemirror/closebrackets/
pub const DEFAULT_PAIRS: &[(char, char)] = &[
('(', ')'),
('{', '}'),
@@ -125,7 +121,7 @@ impl Default for AutoPairs {
#[must_use]
pub fn hook(doc: &Rope, selection: &Selection, ch: char, pairs: &AutoPairs) -> Option<Transaction> {
debug!("autopairs hook selection: {:#?}", selection);
log::trace!("autopairs hook selection: {:#?}", selection);
if let Some(pair) = pairs.get(ch) {
if pair.same() {
@@ -149,22 +145,8 @@ fn prev_char(doc: &Rope, pos: usize) -> Option<char> {
doc.get_char(pos - 1)
}
fn is_single_grapheme(doc: &Rope, range: &Range) -> bool {
let mut graphemes = RopeGraphemes::new(doc.slice(range.from()..range.to()));
let first = graphemes.next();
let second = graphemes.next();
debug!("first: {:#?}, second: {:#?}", first, second);
first.is_some() && second.is_none()
}
/// calculate what the resulting range should be for an auto pair insertion
fn get_next_range(
doc: &Rope,
start_range: &Range,
offset: usize,
typed_char: char,
len_inserted: usize,
) -> Range {
fn get_next_range(doc: &Rope, start_range: &Range, offset: usize, len_inserted: usize) -> Range {
// When the character under the cursor changes due to complete pair
// insertion, we must look backward a grapheme and then add the length
// of the insertion to put the resulting cursor in the right place, e.g.
@@ -184,13 +166,13 @@ fn get_next_range(
// inserting at the very end of the document after the last newline
if start_range.head == doc.len_chars() && start_range.anchor == doc.len_chars() {
return Range::new(
start_range.anchor + offset + typed_char.len_utf8(),
start_range.head + offset + typed_char.len_utf8(),
start_range.anchor + offset + 1,
start_range.head + offset + 1,
);
}
let single_grapheme = is_single_grapheme(doc, start_range);
let doc_slice = doc.slice(..);
let single_grapheme = start_range.is_single_grapheme(doc_slice);
// just skip over graphemes
if len_inserted == 0 {
@@ -215,29 +197,28 @@ fn get_next_range(
// trivial case: only inserted a single-char opener, just move the selection
if len_inserted == 1 {
let end_anchor = if single_grapheme || start_range.direction() == Direction::Backward {
start_range.anchor + offset + typed_char.len_utf8()
start_range.anchor + offset + 1
} else {
start_range.anchor + offset
};
return Range::new(
end_anchor,
start_range.head + offset + typed_char.len_utf8(),
);
return Range::new(end_anchor, start_range.head + offset + 1);
}
// If the head = 0, then we must be in insert mode with a backward
// cursor, which implies the head will just move
let end_head = if start_range.head == 0 || start_range.direction() == Direction::Backward {
start_range.head + offset + typed_char.len_utf8()
start_range.head + offset + 1
} else {
// We must have a forward cursor, which means we must move to the
// other end of the grapheme to get to where the new characters
// are inserted, then move the head to where it should be
let prev_bound = graphemes::prev_grapheme_boundary(doc_slice, start_range.head);
debug!(
log::trace!(
"prev_bound: {}, offset: {}, len_inserted: {}",
prev_bound, offset, len_inserted
prev_bound,
offset,
len_inserted
);
prev_bound + offset + len_inserted
};
@@ -253,8 +234,7 @@ fn get_next_range(
(_, Direction::Forward) => {
if single_grapheme {
graphemes::prev_grapheme_boundary(doc.slice(..), start_range.head)
+ typed_char.len_utf8()
graphemes::prev_grapheme_boundary(doc.slice(..), start_range.head) + 1
// if we are appending, the anchor stays where it is; only offset
// for multiple range insertions
@@ -268,7 +248,9 @@ fn get_next_range(
// if we're backward, then the head is at the first char
// of the typed char, so we need to add the length of
// the closing char
graphemes::prev_grapheme_boundary(doc.slice(..), start_range.anchor) + len_inserted
graphemes::prev_grapheme_boundary(doc.slice(..), start_range.anchor)
+ len_inserted
+ offset
} else {
// when we are inserting in front of a selection, we need to move
// the anchor over by however many characters were inserted overall
@@ -289,9 +271,12 @@ fn handle_open(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
let next_char = doc.get_char(cursor);
let len_inserted;
// Since auto pairs are currently limited to single chars, we're either
// inserting exactly one or two chars. When arbitrary length pairs are
// added, these will need to be changed.
let change = match next_char {
Some(_) if !pair.should_close(doc, start_range) => {
len_inserted = pair.open.len_utf8();
len_inserted = 1;
let mut tendril = Tendril::new();
tendril.push(pair.open);
(cursor, cursor, Some(tendril))
@@ -299,12 +284,12 @@ fn handle_open(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
_ => {
// insert open & close
let pair_str = Tendril::from_iter([pair.open, pair.close]);
len_inserted = pair.open.len_utf8() + pair.close.len_utf8();
len_inserted = 2;
(cursor, cursor, Some(pair_str))
}
};
let next_range = get_next_range(doc, start_range, offs, pair.open, len_inserted);
let next_range = get_next_range(doc, start_range, offs, len_inserted);
end_ranges.push(next_range);
offs += len_inserted;
@@ -312,13 +297,12 @@ fn handle_open(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
});
let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index()));
debug!("auto pair transaction: {:#?}", t);
log::debug!("auto pair transaction: {:#?}", t);
t
}
fn handle_close(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
let mut end_ranges = SmallVec::with_capacity(selection.len());
let mut offs = 0;
let transaction = Transaction::change_by_selection(doc, selection, |start_range| {
@@ -330,13 +314,13 @@ fn handle_close(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
// return transaction that moves past close
(cursor, cursor, None) // no-op
} else {
len_inserted += pair.close.len_utf8();
len_inserted = 1;
let mut tendril = Tendril::new();
tendril.push(pair.close);
(cursor, cursor, Some(tendril))
};
let next_range = get_next_range(doc, start_range, offs, pair.close, len_inserted);
let next_range = get_next_range(doc, start_range, offs, len_inserted);
end_ranges.push(next_range);
offs += len_inserted;
@@ -344,7 +328,7 @@ fn handle_close(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
});
let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index()));
debug!("auto pair transaction: {:#?}", t);
log::debug!("auto pair transaction: {:#?}", t);
t
}
@@ -372,11 +356,11 @@ fn handle_same(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
pair_str.push(pair.close);
}
len_inserted += pair_str.len();
len_inserted += pair_str.chars().count();
(cursor, cursor, Some(pair_str))
};
let next_range = get_next_range(doc, start_range, offs, pair.open, len_inserted);
let next_range = get_next_range(doc, start_range, offs, len_inserted);
end_ranges.push(next_range);
offs += len_inserted;
@@ -384,554 +368,6 @@ fn handle_same(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
});
let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index()));
debug!("auto pair transaction: {:#?}", t);
log::debug!("auto pair transaction: {:#?}", t);
t
}
#[cfg(test)]
mod test {
use super::*;
use smallvec::smallvec;
const LINE_END: &str = crate::DEFAULT_LINE_ENDING.as_str();
fn differing_pairs() -> impl Iterator<Item = &'static (char, char)> {
DEFAULT_PAIRS.iter().filter(|(open, close)| open != close)
}
fn matching_pairs() -> impl Iterator<Item = &'static (char, char)> {
DEFAULT_PAIRS.iter().filter(|(open, close)| open == close)
}
fn test_hooks(
in_doc: &Rope,
in_sel: &Selection,
ch: char,
pairs: &[(char, char)],
expected_doc: &Rope,
expected_sel: &Selection,
) {
let pairs = AutoPairs::new(pairs.iter());
let trans = hook(in_doc, in_sel, ch, &pairs).unwrap();
let mut actual_doc = in_doc.clone();
assert!(trans.apply(&mut actual_doc));
assert_eq!(expected_doc, &actual_doc);
assert_eq!(expected_sel, trans.selection().unwrap());
}
fn test_hooks_with_pairs<I, F, R>(
in_doc: &Rope,
in_sel: &Selection,
test_pairs: I,
pairs: &[(char, char)],
get_expected_doc: F,
actual_sel: &Selection,
) where
I: IntoIterator<Item = &'static (char, char)>,
F: Fn(char, char) -> R,
R: Into<Rope>,
Rope: From<R>,
{
test_pairs.into_iter().for_each(|(open, close)| {
test_hooks(
in_doc,
in_sel,
*open,
pairs,
&Rope::from(get_expected_doc(*open, *close)),
actual_sel,
)
});
}
// [] indicates range
/// [] -> insert ( -> ([])
#[test]
fn test_insert_blank() {
test_hooks_with_pairs(
&Rope::from(LINE_END),
&Selection::single(1, 0),
DEFAULT_PAIRS,
DEFAULT_PAIRS,
|open, close| format!("{}{}{}", open, close, LINE_END),
&Selection::single(2, 1),
);
let empty_doc = Rope::from(format!("{line_end}{line_end}", line_end = LINE_END));
test_hooks_with_pairs(
&empty_doc,
&Selection::single(empty_doc.len_chars(), LINE_END.len()),
DEFAULT_PAIRS,
DEFAULT_PAIRS,
|open, close| {
format!(
"{line_end}{open}{close}{line_end}",
open = open,
close = close,
line_end = LINE_END
)
},
&Selection::single(LINE_END.len() + 2, LINE_END.len() + 1),
);
}
#[test]
fn test_insert_before_multi_code_point_graphemes() {
for (_, close) in differing_pairs() {
test_hooks(
&Rope::from(format!("hello 👨‍👩‍👧‍👦 goodbye{}", LINE_END)),
&Selection::single(13, 6),
*close,
DEFAULT_PAIRS,
&Rope::from(format!("hello {}👨‍👩‍👧‍👦 goodbye{}", close, LINE_END)),
&Selection::single(14, 7),
);
}
}
#[test]
fn test_insert_at_end_of_document() {
test_hooks_with_pairs(
&Rope::from(LINE_END),
&Selection::single(LINE_END.len(), LINE_END.len()),
DEFAULT_PAIRS,
DEFAULT_PAIRS,
|open, close| format!("{}{}{}", LINE_END, open, close),
&Selection::single(LINE_END.len() + 1, LINE_END.len() + 1),
);
test_hooks_with_pairs(
&Rope::from(format!("foo{}", LINE_END)),
&Selection::single(3 + LINE_END.len(), 3 + LINE_END.len()),
DEFAULT_PAIRS,
DEFAULT_PAIRS,
|open, close| format!("foo{}{}{}", LINE_END, open, close),
&Selection::single(LINE_END.len() + 4, LINE_END.len() + 4),
);
}
/// [] -> append ( -> ([])
#[test]
fn test_append_blank() {
test_hooks_with_pairs(
// this is what happens when you have a totally blank document and then append
&Rope::from(format!("{line_end}{line_end}", line_end = LINE_END)),
// before inserting the pair, the cursor covers all of both empty lines
&Selection::single(0, LINE_END.len() * 2),
DEFAULT_PAIRS,
DEFAULT_PAIRS,
|open, close| {
format!(
"{line_end}{open}{close}{line_end}",
line_end = LINE_END,
open = open,
close = close
)
},
// after inserting pair, the cursor covers the first new line and the open char
&Selection::single(0, LINE_END.len() + 2),
);
}
/// [] ([])
/// [] -> insert -> ([])
/// [] ([])
#[test]
fn test_insert_blank_multi_cursor() {
test_hooks_with_pairs(
&Rope::from("\n\n\n"),
&Selection::new(
smallvec!(Range::new(1, 0), Range::new(2, 1), Range::new(3, 2),),
0,
),
DEFAULT_PAIRS,
DEFAULT_PAIRS,
|open, close| {
format!(
"{open}{close}\n{open}{close}\n{open}{close}\n",
open = open,
close = close
)
},
&Selection::new(
smallvec!(Range::new(2, 1), Range::new(5, 4), Range::new(8, 7),),
0,
),
);
}
/// fo[o] -> append ( -> fo[o(])
#[test]
fn test_append() {
test_hooks_with_pairs(
&Rope::from("foo\n"),
&Selection::single(2, 4),
differing_pairs(),
DEFAULT_PAIRS,
|open, close| format!("foo{}{}\n", open, close),
&Selection::single(2, 5),
);
}
/// foo[] -> append to end of line ( -> foo([])
#[test]
fn test_append_single_cursor() {
test_hooks_with_pairs(
&Rope::from(format!("foo{}", LINE_END)),
&Selection::single(3, 3 + LINE_END.len()),
differing_pairs(),
DEFAULT_PAIRS,
|open, close| format!("foo{}{}{}", open, close, LINE_END),
&Selection::single(4, 5),
);
}
/// fo[o] fo[o(])
/// fo[o] -> append ( -> fo[o(])
/// fo[o] fo[o(])
#[test]
fn test_append_multi() {
test_hooks_with_pairs(
&Rope::from("foo\nfoo\nfoo\n"),
&Selection::new(
smallvec!(Range::new(2, 4), Range::new(6, 8), Range::new(10, 12)),
0,
),
differing_pairs(),
DEFAULT_PAIRS,
|open, close| {
format!(
"foo{open}{close}\nfoo{open}{close}\nfoo{open}{close}\n",
open = open,
close = close
)
},
&Selection::new(
smallvec!(Range::new(2, 5), Range::new(8, 11), Range::new(14, 17)),
0,
),
);
}
/// ([)] -> insert ) -> ()[]
#[test]
fn test_insert_close_inside_pair() {
for (open, close) in DEFAULT_PAIRS {
let doc = Rope::from(format!("{}{}{}", open, close, LINE_END));
test_hooks(
&doc,
&Selection::single(2, 1),
*close,
DEFAULT_PAIRS,
&doc,
&Selection::single(2 + LINE_END.len(), 2),
);
}
}
/// [(]) -> append ) -> [()]
#[test]
fn test_append_close_inside_pair() {
for (open, close) in DEFAULT_PAIRS {
let doc = Rope::from(format!("{}{}{}", open, close, LINE_END));
test_hooks(
&doc,
&Selection::single(0, 2),
*close,
DEFAULT_PAIRS,
&doc,
&Selection::single(0, 2 + LINE_END.len()),
);
}
}
/// ([]) ()[]
/// ([]) -> insert ) -> ()[]
/// ([]) ()[]
#[test]
fn test_insert_close_inside_pair_multi_cursor() {
let sel = Selection::new(
smallvec!(Range::new(2, 1), Range::new(5, 4), Range::new(8, 7),),
0,
);
let expected_sel = Selection::new(
smallvec!(Range::new(3, 2), Range::new(6, 5), Range::new(9, 8),),
0,
);
for (open, close) in DEFAULT_PAIRS {
let doc = Rope::from(format!(
"{open}{close}\n{open}{close}\n{open}{close}\n",
open = open,
close = close
));
test_hooks(&doc, &sel, *close, DEFAULT_PAIRS, &doc, &expected_sel);
}
}
/// [(]) [()]
/// [(]) -> append ) -> [()]
/// [(]) [()]
#[test]
fn test_append_close_inside_pair_multi_cursor() {
let sel = Selection::new(
smallvec!(Range::new(0, 2), Range::new(3, 5), Range::new(6, 8),),
0,
);
let expected_sel = Selection::new(
smallvec!(Range::new(0, 3), Range::new(3, 6), Range::new(6, 9),),
0,
);
for (open, close) in DEFAULT_PAIRS {
let doc = Rope::from(format!(
"{open}{close}\n{open}{close}\n{open}{close}\n",
open = open,
close = close
));
test_hooks(&doc, &sel, *close, DEFAULT_PAIRS, &doc, &expected_sel);
}
}
/// ([]) -> insert ( -> (([]))
#[test]
fn test_insert_open_inside_pair() {
let sel = Selection::single(2, 1);
let expected_sel = Selection::single(3, 2);
for (open, close) in differing_pairs() {
let doc = Rope::from(format!("{}{}", open, close));
let expected_doc = Rope::from(format!(
"{open}{open}{close}{close}",
open = open,
close = close
));
test_hooks(
&doc,
&sel,
*open,
DEFAULT_PAIRS,
&expected_doc,
&expected_sel,
);
}
}
/// [word(]) -> append ( -> [word((]))
#[test]
fn test_append_open_inside_pair() {
let sel = Selection::single(0, 6);
let expected_sel = Selection::single(0, 7);
for (open, close) in differing_pairs() {
let doc = Rope::from(format!("word{}{}", open, close));
let expected_doc = Rope::from(format!(
"word{open}{open}{close}{close}",
open = open,
close = close
));
test_hooks(
&doc,
&sel,
*open,
DEFAULT_PAIRS,
&expected_doc,
&expected_sel,
);
}
}
/// ([]) -> insert " -> ("[]")
#[test]
fn test_insert_nested_open_inside_pair() {
let sel = Selection::single(2, 1);
let expected_sel = Selection::single(3, 2);
for (outer_open, outer_close) in differing_pairs() {
let doc = Rope::from(format!("{}{}", outer_open, outer_close,));
for (inner_open, inner_close) in matching_pairs() {
let expected_doc = Rope::from(format!(
"{}{}{}{}",
outer_open, inner_open, inner_close, outer_close
));
test_hooks(
&doc,
&sel,
*inner_open,
DEFAULT_PAIRS,
&expected_doc,
&expected_sel,
);
}
}
}
/// [(]) -> append " -> [("]")
#[test]
fn test_append_nested_open_inside_pair() {
let sel = Selection::single(0, 2);
let expected_sel = Selection::single(0, 3);
for (outer_open, outer_close) in differing_pairs() {
let doc = Rope::from(format!("{}{}", outer_open, outer_close,));
for (inner_open, inner_close) in matching_pairs() {
let expected_doc = Rope::from(format!(
"{}{}{}{}",
outer_open, inner_open, inner_close, outer_close
));
test_hooks(
&doc,
&sel,
*inner_open,
DEFAULT_PAIRS,
&expected_doc,
&expected_sel,
);
}
}
}
/// []word -> insert ( -> ([]word
#[test]
fn test_insert_open_before_non_pair() {
test_hooks_with_pairs(
&Rope::from("word"),
&Selection::single(1, 0),
DEFAULT_PAIRS,
DEFAULT_PAIRS,
|open, _| format!("{}word", open),
&Selection::single(2, 1),
)
}
/// [wor]d -> insert ( -> ([wor]d
#[test]
fn test_insert_open_with_selection() {
test_hooks_with_pairs(
&Rope::from("word"),
&Selection::single(3, 0),
DEFAULT_PAIRS,
DEFAULT_PAIRS,
|open, _| format!("{}word", open),
&Selection::single(4, 1),
)
}
/// [wor]d -> append ) -> [wor)]d
#[test]
fn test_append_close_inside_non_pair_with_selection() {
let sel = Selection::single(0, 4);
let expected_sel = Selection::single(0, 5);
for (_, close) in DEFAULT_PAIRS {
let doc = Rope::from("word");
let expected_doc = Rope::from(format!("wor{}d", close));
test_hooks(
&doc,
&sel,
*close,
DEFAULT_PAIRS,
&expected_doc,
&expected_sel,
);
}
}
/// foo[ wor]d -> insert ( -> foo([) wor]d
#[test]
fn test_insert_open_trailing_word_with_selection() {
test_hooks_with_pairs(
&Rope::from("foo word"),
&Selection::single(7, 3),
differing_pairs(),
DEFAULT_PAIRS,
|open, close| format!("foo{}{} word", open, close),
&Selection::single(9, 4),
)
}
/// foo([) wor]d -> insert ) -> foo()[ wor]d
#[test]
fn test_insert_close_inside_pair_trailing_word_with_selection() {
for (open, close) in differing_pairs() {
test_hooks(
&Rope::from(format!("foo{}{} word{}", open, close, LINE_END)),
&Selection::single(9, 4),
*close,
DEFAULT_PAIRS,
&Rope::from(format!("foo{}{} word{}", open, close, LINE_END)),
&Selection::single(9, 5),
)
}
}
/// we want pairs that are *not* the same char to be inserted after
/// a non-pair char, for cases like functions, but for pairs that are
/// the same char, we want to *not* insert a pair to handle cases like "I'm"
///
/// word[] -> insert ( -> word([])
/// word[] -> insert ' -> word'[]
#[test]
fn test_insert_open_after_non_pair() {
let doc = Rope::from(format!("word{}", LINE_END));
let sel = Selection::single(5, 4);
let expected_sel = Selection::single(6, 5);
test_hooks_with_pairs(
&doc,
&sel,
differing_pairs(),
DEFAULT_PAIRS,
|open, close| format!("word{}{}{}", open, close, LINE_END),
&expected_sel,
);
test_hooks_with_pairs(
&doc,
&sel,
matching_pairs(),
DEFAULT_PAIRS,
|open, _| format!("word{}{}", open, LINE_END),
&expected_sel,
);
}
#[test]
fn test_configured_pairs() {
let test_pairs = &[('`', ':'), ('+', '-')];
test_hooks_with_pairs(
&Rope::from(LINE_END),
&Selection::single(1, 0),
test_pairs,
test_pairs,
|open, close| format!("{}{}{}", open, close, LINE_END),
&Selection::single(2, 1),
);
let doc = Rope::from(format!("foo`: word{}", LINE_END));
test_hooks(
&doc,
&Selection::single(9, 4),
':',
test_pairs,
&doc,
&Selection::single(9, 5),
)
}
}

View File

@@ -72,7 +72,7 @@ pub fn toggle_line_comments(doc: &Rope, selection: &Selection, token: Option<&st
let end = (end + 1).min(text.len_lines());
lines.extend(start..end);
min_next_line = end + 1;
min_next_line = end;
}
let (commented, to_change, min, margin) = find_line_comment(token, text, lines);
@@ -100,43 +100,41 @@ mod test {
#[test]
fn test_find_line_comment() {
use crate::State;
// four lines, two space indented, except for line 1 which is blank.
let doc = Rope::from(" 1\n\n 2\n 3");
let mut state = State::new(doc);
let mut doc = Rope::from(" 1\n\n 2\n 3");
// select whole document
state.selection = Selection::single(0, state.doc.len_chars() - 1);
let mut selection = Selection::single(0, doc.len_chars() - 1);
let text = state.doc.slice(..);
let text = doc.slice(..);
let res = find_line_comment("//", text, 0..3);
// (commented = true, to_change = [line 0, line 2], min = col 2, margin = 1)
assert_eq!(res, (false, vec![0, 2], 2, 1));
// comment
let transaction = toggle_line_comments(&state.doc, &state.selection, None);
transaction.apply(&mut state.doc);
state.selection = state.selection.map(transaction.changes());
let transaction = toggle_line_comments(&doc, &selection, None);
transaction.apply(&mut doc);
selection = selection.map(transaction.changes());
assert_eq!(state.doc, " // 1\n\n // 2\n // 3");
assert_eq!(doc, " // 1\n\n // 2\n // 3");
// uncomment
let transaction = toggle_line_comments(&state.doc, &state.selection, None);
transaction.apply(&mut state.doc);
state.selection = state.selection.map(transaction.changes());
assert_eq!(state.doc, " 1\n\n 2\n 3");
let transaction = toggle_line_comments(&doc, &selection, None);
transaction.apply(&mut doc);
selection = selection.map(transaction.changes());
assert_eq!(doc, " 1\n\n 2\n 3");
assert!(selection.len() == 1); // to ignore the selection unused warning
// 0 margin comments
state.doc = Rope::from(" //1\n\n //2\n //3");
doc = Rope::from(" //1\n\n //2\n //3");
// reset the selection.
state.selection = Selection::single(0, state.doc.len_chars() - 1);
selection = Selection::single(0, doc.len_chars() - 1);
let transaction = toggle_line_comments(&state.doc, &state.selection, None);
transaction.apply(&mut state.doc);
state.selection = state.selection.map(transaction.changes());
assert_eq!(state.doc, " 1\n\n 2\n 3");
let transaction = toggle_line_comments(&doc, &selection, None);
transaction.apply(&mut doc);
selection = selection.map(transaction.changes());
assert_eq!(doc, " 1\n\n 2\n 3");
assert!(selection.len() == 1); // to ignore the selection unused warning
// TODO: account for uncommenting with uneven comment indentation
}

View File

@@ -1,10 +1,10 @@
/// Syntax configuration loader based on built-in languages.toml.
pub fn default_syntax_loader() -> crate::syntax::Configuration {
helix_loader::default_lang_config()
helix_loader::config::default_lang_config()
.try_into()
.expect("Could not serialize built-in languages.toml")
}
/// Syntax configuration loader based on user configured languages.toml.
pub fn user_syntax_loader() -> Result<crate::syntax::Configuration, toml::de::Error> {
helix_loader::user_lang_config()?.try_into()
helix_loader::config::user_lang_config()?.try_into()
}

View File

@@ -23,6 +23,18 @@ pub struct Range {
pub end: usize,
}
#[derive(Debug, Eq, Hash, PartialEq, Clone, Deserialize, Serialize)]
pub enum NumberOrString {
Number(i32),
String(String),
}
#[derive(Debug, Clone)]
pub enum DiagnosticTag {
Unnecessary,
Deprecated,
}
/// Corresponds to [`lsp_types::Diagnostic`](https://docs.rs/lsp-types/0.91.0/lsp_types/struct.Diagnostic.html)
#[derive(Debug, Clone)]
pub struct Diagnostic {
@@ -30,4 +42,8 @@ pub struct Diagnostic {
pub line: usize,
pub message: String,
pub severity: Option<Severity>,
pub code: Option<NumberOrString>,
pub tags: Vec<DiagnosticTag>,
pub source: Option<String>,
pub data: Option<serde_json::Value>,
}

View File

@@ -1,58 +1,194 @@
use crate::{Rope, Transaction};
use std::ops::Range;
use std::time::Instant;
use imara_diff::intern::InternedInput;
use imara_diff::Algorithm;
use ropey::RopeSlice;
use crate::{ChangeSet, Rope, Tendril, Transaction};
/// A `imara_diff::Sink` that builds a `ChangeSet` for a character diff of a hunk
struct CharChangeSetBuilder<'a> {
res: &'a mut ChangeSet,
hunk: &'a InternedInput<char>,
pos: u32,
}
impl imara_diff::Sink for CharChangeSetBuilder<'_> {
type Out = ();
fn process_change(&mut self, before: Range<u32>, after: Range<u32>) {
self.res.retain((before.start - self.pos) as usize);
self.res.delete(before.len());
self.pos = before.end;
let res = self.hunk.after[after.start as usize..after.end as usize]
.iter()
.map(|&token| self.hunk.interner[token])
.collect();
self.res.insert(res);
}
fn finish(self) -> Self::Out {
self.res.retain(self.hunk.before.len() - self.pos as usize);
}
}
struct LineChangeSetBuilder<'a> {
res: ChangeSet,
after: RopeSlice<'a>,
file: &'a InternedInput<RopeSlice<'a>>,
current_hunk: InternedInput<char>,
pos: u32,
}
impl imara_diff::Sink for LineChangeSetBuilder<'_> {
type Out = ChangeSet;
fn process_change(&mut self, before: Range<u32>, after: Range<u32>) {
let len = self.file.before[self.pos as usize..before.start as usize]
.iter()
.map(|&it| self.file.interner[it].len_chars())
.sum();
self.res.retain(len);
self.pos = before.end;
// do not perform diffs on large hunks
let len_before = before.end - before.start;
let len_after = after.end - after.start;
// Pure insertions/removals do not require a character diff.
// Very large changes are ignored because their character diff is expensive to compute
// TODO adjust heuristic to detect large changes?
if len_before == 0
|| len_after == 0
|| len_after > 5 * len_before
|| 5 * len_after < len_before && len_before > 10
|| len_before + len_after > 200
{
let remove = self.file.before[before.start as usize..before.end as usize]
.iter()
.map(|&it| self.file.interner[it].len_chars())
.sum();
self.res.delete(remove);
let mut fragment = Tendril::new();
if len_after > 500 {
// copying a rope line by line is slower then copying the entire
// rope. Use to_string for very large changes instead..
if self.file.after.len() == after.end as usize {
if after.start == 0 {
fragment = self.after.to_string().into();
} else {
let start = self.after.line_to_char(after.start as usize);
fragment = self.after.slice(start..).to_string().into();
}
} else if after.start == 0 {
let end = self.after.line_to_char(after.end as usize);
fragment = self.after.slice(..end).to_string().into();
} else {
let start = self.after.line_to_char(after.start as usize);
let end = self.after.line_to_char(after.end as usize);
fragment = self.after.slice(start..end).to_string().into();
}
} else {
for &line in &self.file.after[after.start as usize..after.end as usize] {
for chunk in self.file.interner[line].chunks() {
fragment.push_str(chunk)
}
}
};
self.res.insert(fragment);
} else {
// for reasonably small hunks, generating a ChangeSet from char diff can save memory
// TODO use a tokenizer (word diff?) for improved performance
let hunk_before = self.file.before[before.start as usize..before.end as usize]
.iter()
.flat_map(|&it| self.file.interner[it].chars());
let hunk_after = self.file.after[after.start as usize..after.end as usize]
.iter()
.flat_map(|&it| self.file.interner[it].chars());
self.current_hunk.update_before(hunk_before);
self.current_hunk.update_after(hunk_after);
// the histogram heuristic does not work as well
// for characters because the same characters often reoccur
// use myer diff instead
imara_diff::diff(
Algorithm::Myers,
&self.current_hunk,
CharChangeSetBuilder {
res: &mut self.res,
hunk: &self.current_hunk,
pos: 0,
},
);
self.current_hunk.clear();
}
}
fn finish(mut self) -> Self::Out {
let len = self.file.before[self.pos as usize..]
.iter()
.map(|&it| self.file.interner[it].len_chars())
.sum();
self.res.retain(len);
self.res
}
}
struct RopeLines<'a>(RopeSlice<'a>);
impl<'a> imara_diff::intern::TokenSource for RopeLines<'a> {
type Token = RopeSlice<'a>;
type Tokenizer = ropey::iter::Lines<'a>;
fn tokenize(&self) -> Self::Tokenizer {
self.0.lines()
}
fn estimate_tokens(&self) -> u32 {
// we can provide a perfect estimate which is very nice for performance
self.0.len_lines() as u32
}
}
/// Compares `old` and `new` to generate a [`Transaction`] describing
/// the steps required to get from `old` to `new`.
pub fn compare_ropes(old: &Rope, new: &Rope) -> Transaction {
// `similar` only works on contiguous data, so a `Rope` has
// to be temporarily converted into a `String`.
let old_converted = old.to_string();
let new_converted = new.to_string();
pub fn compare_ropes(before: &Rope, after: &Rope) -> Transaction {
let start = Instant::now();
let res = ChangeSet::with_capacity(32);
let after = after.slice(..);
let file = InternedInput::new(RopeLines(before.slice(..)), RopeLines(after));
let builder = LineChangeSetBuilder {
res,
file: &file,
after,
pos: 0,
current_hunk: InternedInput::default(),
};
// A timeout is set so after 1 seconds, the algorithm will start
// approximating. This is especially important for big `Rope`s or
// `Rope`s that are extremely dissimilar to each other.
let mut config = similar::TextDiff::configure();
config.timeout(std::time::Duration::from_secs(1));
let res = imara_diff::diff(Algorithm::Histogram, &file, builder).into();
let diff = config.diff_chars(&old_converted, &new_converted);
// The current position of the change needs to be tracked to
// construct the `Change`s.
let mut pos = 0;
Transaction::change(
old,
diff.ops()
.iter()
.map(|op| op.as_tag_tuple())
.filter_map(|(tag, old_range, new_range)| {
// `old_pos..pos` is equivalent to `start..end` for where
// the change should be applied.
let old_pos = pos;
pos += old_range.end - old_range.start;
match tag {
// Semantically, inserts and replacements are the same thing.
similar::DiffTag::Insert | similar::DiffTag::Replace => {
// This is the text from the `new` rope that should be
// inserted into `old`.
let text: &str = {
let start = new.char_to_byte(new_range.start);
let end = new.char_to_byte(new_range.end);
&new_converted[start..end]
};
Some((old_pos, pos, Some(text.into())))
}
similar::DiffTag::Delete => Some((old_pos, pos, None)),
similar::DiffTag::Equal => None,
}
}),
)
log::debug!(
"rope diff took {}s",
Instant::now().duration_since(start).as_secs_f64()
);
res
}
#[cfg(test)]
mod tests {
use super::*;
fn test_identity(a: &str, b: &str) {
let mut old = Rope::from(a);
let new = Rope::from(b);
compare_ropes(&old, &new).apply(&mut old);
assert_eq!(old, new);
}
quickcheck::quickcheck! {
fn test_compare_ropes(a: String, b: String) -> bool {
let mut old = Rope::from(a);
@@ -61,4 +197,25 @@ mod tests {
old == new
}
}
#[test]
fn equal_files() {
test_identity("foo", "foo");
}
#[test]
fn trailing_newline() {
test_identity("foo\n", "foo");
test_identity("foo", "foo\n");
}
#[test]
fn new_file() {
test_identity("", "foo");
}
#[test]
fn deleted_file() {
test_identity("foo", "");
}
}

View File

@@ -14,7 +14,7 @@ pub fn grapheme_width(g: &str) -> usize {
// Point 1: theoretically, ascii control characters should have zero
// width, but in our case we actually want them to have width: if they
// show up in text, we want to treat them as textual elements that can
// be editied. So we can get away with making all ascii single width
// be edited. So we can get away with making all ascii single width
// here.
// Point 2: we're only examining the first codepoint here, which means
// we're ignoring graphemes formed with combining characters. However,

View File

@@ -1,9 +1,15 @@
use crate::{Assoc, ChangeSet, Range, Rope, State, Transaction};
use crate::{Assoc, ChangeSet, Range, Rope, Selection, Transaction};
use once_cell::sync::Lazy;
use regex::Regex;
use std::num::NonZeroUsize;
use std::time::{Duration, Instant};
#[derive(Debug, Clone)]
pub struct State {
pub doc: Rope,
pub selection: Selection,
}
/// Stores the history of changes to a buffer.
///
/// Currently the history is represented as a vector of revisions. The vector
@@ -22,10 +28,10 @@ use std::time::{Duration, Instant};
///
/// The current revision is the one currently displayed in the buffer.
///
/// Commiting a new revision to the history will update the last child of the
/// Committing a new revision to the history will update the last child of the
/// current revision, and push a new revision to the end of the vector.
///
/// Revisions are commited with a timestamp. :earlier and :later can be used
/// Revisions are committed with a timestamp. :earlier and :later can be used
/// to jump to the closest revision to a moment in time relative to the timestamp
/// of the current revision plus (:later) or minus (:earlier) the duration
/// given to the command. If a single integer is given, the editor will instead
@@ -33,7 +39,7 @@ use std::time::{Duration, Instant};
///
/// Limitations:
/// * Changes in selections currently don't commit history changes. The selection
/// will only be updated to the state after a commited buffer change.
/// will only be updated to the state after a committed buffer change.
/// * The vector of history revisions is currently unbounded. This might
/// cause the memory consumption to grow significantly large during long
/// editing sessions.
@@ -48,7 +54,7 @@ pub struct History {
}
/// A single point in history. See [History] for more information.
#[derive(Debug)]
#[derive(Debug, Clone)]
struct Revision {
parent: usize,
last_child: Option<NonZeroUsize>,
@@ -113,6 +119,21 @@ impl History {
self.current == 0
}
/// Returns the changes since the given revision composed into a transaction.
/// Returns None if there are no changes between the current and given revisions.
pub fn changes_since(&self, revision: usize) -> Option<Transaction> {
let lca = self.lowest_common_ancestor(revision, self.current);
let up = self.path_up(revision, lca);
let down = self.path_up(self.current, lca);
let up_txns = up
.iter()
.rev()
.map(|&n| self.revisions[n].inversion.clone());
let down_txns = down.iter().map(|&n| self.revisions[n].transaction.clone());
down_txns.chain(up_txns).reduce(|acc, tx| tx.compose(acc))
}
/// Undo the last edit.
pub fn undo(&mut self) -> Option<&Transaction> {
if self.at_root() {
@@ -177,7 +198,7 @@ impl History {
}
}
/// List of nodes on the way from `n` to 'a`. Doesn`t include `a`.
/// List of nodes on the way from `n` to 'a`. Doesn't include `a`.
/// Includes `n` unless `a == n`. `a` must be an ancestor of `n`.
fn path_up(&self, mut n: usize, a: usize) -> Vec<usize> {
let mut path = Vec::new();
@@ -282,13 +303,13 @@ impl History {
}
/// Whether to undo by a number of edits or a duration of time.
#[derive(Debug, PartialEq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum UndoKind {
Steps(usize),
TimePeriod(std::time::Duration),
}
/// A subset of sytemd.time time span syntax units.
/// A subset of systemd.time time span syntax units.
const TIME_UNITS: &[(&[&str], &str, u64)] = &[
(&["seconds", "second", "sec", "s"], "seconds", 1),
(&["minutes", "minute", "min", "m"], "minutes", 60),
@@ -366,12 +387,16 @@ impl std::str::FromStr for UndoKind {
#[cfg(test)]
mod test {
use super::*;
use crate::Selection;
#[test]
fn test_undo_redo() {
let mut history = History::default();
let doc = Rope::from("hello");
let mut state = State::new(doc);
let mut state = State {
doc,
selection: Selection::point(0),
};
let transaction1 =
Transaction::change(&state.doc, vec![(5, 5, Some(" world!".into()))].into_iter());
@@ -420,7 +445,10 @@ mod test {
fn test_earlier_later() {
let mut history = History::default();
let doc = Rope::from("a\n");
let mut state = State::new(doc);
let mut state = State {
doc,
selection: Selection::point(0),
};
fn undo(history: &mut History, state: &mut State) {
if let Some(transaction) = history.undo() {
@@ -546,8 +574,8 @@ mod test {
// Units are validated.
assert_eq!(
"1 millenium".parse::<UndoKind>(),
Err("incorrect time unit: millenium".to_string())
"1 millennium".parse::<UndoKind>(),
Err("incorrect time unit: millennium".to_string())
);
// Units can't be specified twice.

View File

@@ -5,6 +5,7 @@ use ropey::RopeSlice;
use std::borrow::Cow;
use std::cmp;
use std::fmt::Write;
use super::Increment;
use crate::{Range, Tendril};
@@ -73,12 +74,12 @@ impl DateTimeIncrementor {
(true, false) => {
let date = NaiveDate::parse_from_str(date_time, format.fmt).ok()?;
date.and_hms(0, 0, 0)
date.and_hms_opt(0, 0, 0).unwrap()
}
(false, true) => {
let time = NaiveTime::parse_from_str(date_time, format.fmt).ok()?;
NaiveDate::from_ymd(0, 1, 1).and_time(time)
NaiveDate::from_ymd_opt(0, 1, 1).unwrap().and_time(time)
}
(false, false) => return None,
};
@@ -162,7 +163,7 @@ impl Format {
fields.push(field);
max_len += field.max_len + remaining[..i].len();
regex += &remaining[..i];
regex += &format!("({})", field.regex);
write!(regex, "({})", field.regex).unwrap();
remaining = &after[spec_len..];
}
@@ -311,10 +312,10 @@ fn ndays_in_month(year: i32, month: u32) -> u32 {
} else {
(year, month + 1)
};
let d = NaiveDate::from_ymd(y, m, 1);
let d = NaiveDate::from_ymd_opt(y, m, 1).unwrap();
// ...is preceded by the last day of the original month.
d.pred().day()
d.pred_opt().unwrap().day()
}
fn add_months(date_time: NaiveDateTime, amount: i64) -> Option<NaiveDateTime> {
@@ -333,7 +334,7 @@ fn add_months(date_time: NaiveDateTime, amount: i64) -> Option<NaiveDateTime> {
let day = cmp::min(date_time.day(), ndays_in_month(year, month));
Some(NaiveDate::from_ymd(year, month, day).and_time(date_time.time()))
NaiveDate::from_ymd_opt(year, month, day).map(|date| date.and_time(date_time.time()))
}
fn add_years(date_time: NaiveDateTime, amount: i64) -> Option<NaiveDateTime> {
@@ -341,8 +342,8 @@ fn add_years(date_time: NaiveDateTime, amount: i64) -> Option<NaiveDateTime> {
let ndays = ndays_in_month(year, date_time.month());
if date_time.day() > ndays {
let d = NaiveDate::from_ymd(year, date_time.month(), ndays);
Some(d.succ().and_time(date_time.time()))
NaiveDate::from_ymd_opt(year, date_time.month(), ndays)
.and_then(|date| date.succ_opt().map(|date| date.and_time(date_time.time())))
} else {
date_time.with_year(year)
}

View File

@@ -110,8 +110,8 @@ impl<'a> Increment for NumberIncrementor<'a> {
let (lower_count, upper_count): (usize, usize) =
old_text.chars().skip(2).fold((0, 0), |(lower, upper), c| {
(
lower + c.is_ascii_lowercase().then(|| 1).unwrap_or(0),
upper + c.is_ascii_uppercase().then(|| 1).unwrap_or(0),
lower + usize::from(c.is_ascii_lowercase()),
upper + usize::from(c.is_ascii_uppercase()),
)
});
if upper_count > lower_count {
@@ -377,7 +377,7 @@ mod test {
}
#[test]
fn test_increment_basic_hexadedimal_numbers() {
fn test_increment_basic_hexadecimal_numbers() {
let tests = [
("0x0100", 1, "0x0101"),
("0x0100", -1, "0x00ff"),

View File

@@ -1,6 +1,10 @@
use std::collections::HashMap;
use tree_sitter::{Query, QueryCursor, QueryPredicateArg};
use crate::{
chars::{char_is_line_ending, char_is_whitespace},
syntax::{IndentQuery, LanguageConfiguration, Syntax},
syntax::{LanguageConfiguration, RopeProvider, Syntax},
tree_sitter::Node,
Rope, RopeSlice,
};
@@ -186,103 +190,544 @@ pub fn indent_level_for_line(line: RopeSlice, tab_width: usize) -> usize {
len / tab_width
}
/// Find the highest syntax node at position.
/// This is to identify the column where this node (e.g., an HTML closing tag) ends.
fn get_highest_syntax_node_at_bytepos(syntax: &Syntax, pos: usize) -> Option<Node> {
let tree = syntax.tree();
// named_descendant
let mut node = tree.root_node().descendant_for_byte_range(pos, pos)?;
while let Some(parent) = node.parent() {
if parent.start_byte() == node.start_byte() {
node = parent
} else {
break;
}
}
Some(node)
}
/// Calculate the indentation at a given treesitter node.
/// If newline is false, then any "indent" nodes on the line are ignored ("outdent" still applies).
/// This is because the indentation is only increased starting at the second line of the node.
fn calculate_indentation(
query: &IndentQuery,
node: Option<Node>,
line: usize,
newline: bool,
) -> usize {
let mut increment: isize = 0;
let mut node = match node {
Some(node) => node,
None => return 0,
};
let mut current_line = line;
let mut consider_indent = newline;
let mut increment_from_line: isize = 0;
/// Computes for node and all ancestors whether they are the first node on their line.
/// The first entry in the return value represents the root node, the last one the node itself
fn get_first_in_line(mut node: Node, new_line_byte_pos: Option<usize>) -> Vec<bool> {
let mut first_in_line = Vec::new();
loop {
let node_kind = node.kind();
let start = node.start_position().row;
if current_line != start {
// Indent/dedent by at most one per line:
// .map(|a| { <-- ({ is two scopes
// let len = 1; <-- indents one level
// }) <-- }) is two scopes
if consider_indent || increment_from_line < 0 {
increment += increment_from_line.signum();
}
increment_from_line = 0;
current_line = start;
consider_indent = true;
if let Some(prev) = node.prev_sibling() {
// If we insert a new line, the first node at/after the cursor is considered to be the first in its line
let first = prev.end_position().row != node.start_position().row
|| new_line_byte_pos.map_or(false, |byte_pos| {
node.start_byte() >= byte_pos && prev.start_byte() < byte_pos
});
first_in_line.push(Some(first));
} else {
// Nodes that have no previous siblings are first in their line if and only if their parent is
// (which we don't know yet)
first_in_line.push(None);
}
if query.outdent.contains(node_kind) {
increment_from_line -= 1;
}
if query.indent.contains(node_kind) {
increment_from_line += 1;
}
if let Some(parent) = node.parent() {
node = parent;
} else {
break;
}
}
if consider_indent || increment_from_line < 0 {
increment += increment_from_line.signum();
let mut result = Vec::with_capacity(first_in_line.len());
let mut parent_is_first = true; // The root node is by definition the first node in its line
for first in first_in_line.into_iter().rev() {
if let Some(first) = first {
result.push(first);
parent_is_first = first;
} else {
result.push(parent_is_first);
}
}
increment.max(0) as usize
result
}
// TODO: two usecases: if we are triggering this for a new, blank line:
// - it should return 0 when mass indenting stuff
// - it should look up the wrapper node and count it too when we press o/O
pub fn suggested_indent_for_pos(
/// The total indent for some line of code.
/// This is usually constructed in one of 2 ways:
/// - Successively add indent captures to get the (added) indent from a single line
/// - Successively add the indent results for each line
#[derive(Default)]
pub struct Indentation {
/// The total indent (the number of indent levels) is defined as max(0, indent-outdent).
/// The string that this results in depends on the indent style (spaces or tabs, etc.)
indent: usize,
outdent: usize,
}
impl Indentation {
/// Add some other [Indentation] to this.
/// The added indent should be the total added indent from one line
fn add_line(&mut self, added: &Indentation) {
if added.indent > 0 && added.outdent == 0 {
self.indent += 1;
} else if added.outdent > 0 && added.indent == 0 {
self.outdent += 1;
}
}
/// Add an indent capture to this indent.
/// All the captures that are added in this way should be on the same line.
fn add_capture(&mut self, added: IndentCaptureType) {
match added {
IndentCaptureType::Indent => {
self.indent = 1;
}
IndentCaptureType::Outdent => {
self.outdent = 1;
}
}
}
fn as_string(&self, indent_style: &IndentStyle) -> String {
let indent_level = if self.indent >= self.outdent {
self.indent - self.outdent
} else {
log::warn!("Encountered more outdent than indent nodes while calculating indentation: {} outdent, {} indent", self.outdent, self.indent);
0
};
indent_style.as_str().repeat(indent_level)
}
}
/// An indent definition which corresponds to a capture from the indent query
struct IndentCapture {
capture_type: IndentCaptureType,
scope: IndentScope,
}
#[derive(Clone, Copy)]
enum IndentCaptureType {
Indent,
Outdent,
}
impl IndentCaptureType {
fn default_scope(&self) -> IndentScope {
match self {
IndentCaptureType::Indent => IndentScope::Tail,
IndentCaptureType::Outdent => IndentScope::All,
}
}
}
/// This defines which part of a node an [IndentCapture] applies to.
/// Each [IndentCaptureType] has a default scope, but the scope can be changed
/// with `#set!` property declarations.
#[derive(Clone, Copy)]
enum IndentScope {
/// The indent applies to the whole node
All,
/// The indent applies to everything except for the first line of the node
Tail,
}
/// A capture from the indent query which does not define an indent but extends
/// the range of a node. This is used before the indent is calculated.
enum ExtendCapture {
Extend,
PreventOnce,
}
/// The result of running a tree-sitter indent query. This stores for
/// each node (identified by its ID) the relevant captures (already filtered
/// by predicates).
struct IndentQueryResult {
indent_captures: HashMap<usize, Vec<IndentCapture>>,
extend_captures: HashMap<usize, Vec<ExtendCapture>>,
}
fn query_indents(
query: &Query,
syntax: &Syntax,
cursor: &mut QueryCursor,
text: RopeSlice,
range: std::ops::Range<usize>,
// Position of the (optional) newly inserted line break.
// Given as (line, byte_pos)
new_line_break: Option<(usize, usize)>,
) -> IndentQueryResult {
let mut indent_captures: HashMap<usize, Vec<IndentCapture>> = HashMap::new();
let mut extend_captures: HashMap<usize, Vec<ExtendCapture>> = HashMap::new();
cursor.set_byte_range(range);
// Iterate over all captures from the query
for m in cursor.matches(query, syntax.tree().root_node(), RopeProvider(text)) {
// Skip matches where not all custom predicates are fulfilled
if !query.general_predicates(m.pattern_index).iter().all(|pred| {
match pred.operator.as_ref() {
"not-kind-eq?" => match (pred.args.get(0), pred.args.get(1)) {
(
Some(QueryPredicateArg::Capture(capture_idx)),
Some(QueryPredicateArg::String(kind)),
) => {
let node = m.nodes_for_capture_index(*capture_idx).next();
match node {
Some(node) => node.kind()!=kind.as_ref(),
_ => true,
}
}
_ => {
panic!("Invalid indent query: Arguments to \"not-kind-eq?\" must be a capture and a string");
}
},
"same-line?" | "not-same-line?" => {
match (pred.args.get(0), pred.args.get(1)) {
(
Some(QueryPredicateArg::Capture(capt1)),
Some(QueryPredicateArg::Capture(capt2))
) => {
let get_line_num = |node: Node| {
let mut node_line = node.start_position().row;
// Adjust for the new line that will be inserted
if let Some((line, byte)) = new_line_break {
if node_line==line && node.start_byte()>=byte {
node_line += 1;
}
}
node_line
};
let n1 = m.nodes_for_capture_index(*capt1).next();
let n2 = m.nodes_for_capture_index(*capt2).next();
match (n1, n2) {
(Some(n1), Some(n2)) => {
let same_line = get_line_num(n1)==get_line_num(n2);
same_line==(pred.operator.as_ref()=="same-line?")
}
_ => true,
}
}
_ => {
panic!("Invalid indent query: Arguments to \"{}\" must be 2 captures", pred.operator);
}
}
}
_ => {
panic!(
"Invalid indent query: Unknown predicate (\"{}\")",
pred.operator
);
}
}
}) {
continue;
}
for capture in m.captures {
let capture_name = query.capture_names()[capture.index as usize].as_str();
let capture_type = match capture_name {
"indent" => IndentCaptureType::Indent,
"outdent" => IndentCaptureType::Outdent,
"extend" => {
extend_captures
.entry(capture.node.id())
.or_insert_with(|| Vec::with_capacity(1))
.push(ExtendCapture::Extend);
continue;
}
"extend.prevent-once" => {
extend_captures
.entry(capture.node.id())
.or_insert_with(|| Vec::with_capacity(1))
.push(ExtendCapture::PreventOnce);
continue;
}
_ => {
// Ignore any unknown captures (these may be needed for predicates such as #match?)
continue;
}
};
let scope = capture_type.default_scope();
let mut indent_capture = IndentCapture {
capture_type,
scope,
};
// Apply additional settings for this capture
for property in query.property_settings(m.pattern_index) {
match property.key.as_ref() {
"scope" => {
indent_capture.scope = match property.value.as_deref() {
Some("all") => IndentScope::All,
Some("tail") => IndentScope::Tail,
Some(s) => {
panic!("Invalid indent query: Unknown value for \"scope\" property (\"{}\")", s);
}
None => {
panic!(
"Invalid indent query: Missing value for \"scope\" property"
);
}
}
}
_ => {
panic!(
"Invalid indent query: Unknown property \"{}\"",
property.key
);
}
}
}
indent_captures
.entry(capture.node.id())
// Most entries only need to contain a single IndentCapture
.or_insert_with(|| Vec::with_capacity(1))
.push(indent_capture);
}
}
IndentQueryResult {
indent_captures,
extend_captures,
}
}
/// Handle extend queries. deepest_preceding is the deepest descendant of node that directly precedes the cursor position.
/// Any ancestor of deepest_preceding which is also a descendant of node may be "extended". In that case, node will be updated,
/// so that the indent computation starts with the correct syntax node.
fn extend_nodes<'a>(
node: &mut Node<'a>,
mut deepest_preceding: Node<'a>,
extend_captures: &HashMap<usize, Vec<ExtendCapture>>,
text: RopeSlice,
line: usize,
tab_width: usize,
) {
let mut stop_extend = false;
while deepest_preceding != *node {
let mut extend_node = false;
// This will be set to true if this node is captured, regardless of whether
// it actually will be extended (e.g. because the cursor isn't indented
// more than the node).
let mut node_captured = false;
if let Some(captures) = extend_captures.get(&deepest_preceding.id()) {
for capture in captures {
match capture {
ExtendCapture::PreventOnce => {
stop_extend = true;
}
ExtendCapture::Extend => {
node_captured = true;
// We extend the node if
// - the cursor is on the same line as the end of the node OR
// - the line that the cursor is on is more indented than the
// first line of the node
if deepest_preceding.end_position().row == line {
extend_node = true;
} else {
let cursor_indent = indent_level_for_line(text.line(line), tab_width);
let node_indent = indent_level_for_line(
text.line(deepest_preceding.start_position().row),
tab_width,
);
if cursor_indent > node_indent {
extend_node = true;
}
}
}
}
}
}
// If we encountered some `StopExtend` capture before, we don't
// extend the node even if we otherwise would
if node_captured && stop_extend {
stop_extend = false;
} else if extend_node && !stop_extend {
*node = deepest_preceding;
break;
}
// If the tree contains a syntax error, `deepest_preceding` may not
// have a parent despite being a descendant of `node`.
deepest_preceding = match deepest_preceding.parent() {
Some(parent) => parent,
None => return,
}
}
}
/// Use the syntax tree to determine the indentation for a given position.
/// This can be used in 2 ways:
///
/// - To get the correct indentation for an existing line (new_line=false), not necessarily equal to the current indentation.
/// - In this case, pos should be inside the first tree-sitter node on that line.
/// In most cases, this can just be the first non-whitespace on that line.
/// - To get the indentation for a new line (new_line=true). This behaves like the first usecase if the part of the current line
/// after pos were moved to a new line.
///
/// The indentation is determined by traversing all the tree-sitter nodes containing the position.
/// Each of these nodes produces some [Indentation] for:
///
/// - The line of the (beginning of the) node. This is defined by the scope `all` if this is the first node on its line.
/// - The line after the node. This is defined by:
/// - The scope `tail`.
/// - The scope `all` if this node is not the first node on its line.
/// Intuitively, `all` applies to everything contained in this node while `tail` applies to everything except for the first line of the node.
/// The indents from different nodes for the same line are then combined.
/// The result [Indentation] is simply the sum of the [Indentation] for all lines.
///
/// Specifying which line exactly an [Indentation] applies to is important because indents on the same line combine differently than indents on different lines:
/// ```ignore
/// some_function(|| {
/// // Both the function parameters as well as the contained block should be indented.
/// // Because they are on the same line, this only yields one indent level
/// });
/// ```
///
/// ```ignore
/// some_function(
/// param1,
/// || {
/// // Here we get 2 indent levels because the 'parameters' and the 'block' node begin on different lines
/// },
/// );
/// ```
#[allow(clippy::too_many_arguments)]
pub fn treesitter_indent_for_pos(
query: &Query,
syntax: &Syntax,
indent_style: &IndentStyle,
tab_width: usize,
text: RopeSlice,
line: usize,
pos: usize,
new_line: bool,
) -> Option<String> {
let byte_pos = text.char_to_byte(pos);
// The innermost tree-sitter node which is considered for the indent
// computation. It may change if some predeceding node is extended
let mut node = syntax
.tree()
.root_node()
.descendant_for_byte_range(byte_pos, byte_pos)?;
let (query_result, deepest_preceding) = {
// The query range should intersect with all nodes directly preceding
// the position of the indent query in case one of them is extended.
let mut deepest_preceding = None; // The deepest node preceding the indent query position
let mut tree_cursor = node.walk();
for child in node.children(&mut tree_cursor) {
if child.byte_range().end <= byte_pos {
deepest_preceding = Some(child);
}
}
deepest_preceding = deepest_preceding.map(|mut prec| {
// Get the deepest directly preceding node
while prec.child_count() > 0 {
prec = prec.child(prec.child_count() - 1).unwrap();
}
prec
});
let query_range = deepest_preceding
.map(|prec| prec.byte_range().end - 1..byte_pos + 1)
.unwrap_or(byte_pos..byte_pos + 1);
crate::syntax::PARSER.with(|ts_parser| {
let mut ts_parser = ts_parser.borrow_mut();
let mut cursor = ts_parser.cursors.pop().unwrap_or_else(QueryCursor::new);
let query_result = query_indents(
query,
syntax,
&mut cursor,
text,
query_range,
new_line.then(|| (line, byte_pos)),
);
ts_parser.cursors.push(cursor);
(query_result, deepest_preceding)
})
};
let indent_captures = query_result.indent_captures;
let extend_captures = query_result.extend_captures;
// Check for extend captures, potentially changing the node that the indent calculation starts with
if let Some(deepest_preceding) = deepest_preceding {
extend_nodes(
&mut node,
deepest_preceding,
&extend_captures,
text,
line,
tab_width,
);
}
let mut first_in_line = get_first_in_line(node, new_line.then(|| byte_pos));
let mut result = Indentation::default();
// We always keep track of all the indent changes on one line, in order to only indent once
// even if there are multiple "indent" nodes on the same line
let mut indent_for_line = Indentation::default();
let mut indent_for_line_below = Indentation::default();
loop {
// This can safely be unwrapped because `first_in_line` contains
// one entry for each ancestor of the node (which is what we iterate over)
let is_first = *first_in_line.last().unwrap();
// Apply all indent definitions for this node
if let Some(definitions) = indent_captures.get(&node.id()) {
for definition in definitions {
match definition.scope {
IndentScope::All => {
if is_first {
indent_for_line.add_capture(definition.capture_type);
} else {
indent_for_line_below.add_capture(definition.capture_type);
}
}
IndentScope::Tail => {
indent_for_line_below.add_capture(definition.capture_type);
}
}
}
}
if let Some(parent) = node.parent() {
let mut node_line = node.start_position().row;
let mut parent_line = parent.start_position().row;
if node_line == line && new_line {
// Also consider the line that will be inserted
if node.start_byte() >= byte_pos {
node_line += 1;
}
if parent.start_byte() >= byte_pos {
parent_line += 1;
}
};
if node_line != parent_line {
if node_line < line + (new_line as usize) {
// Don't add indent for the line below the line of the query
result.add_line(&indent_for_line_below);
}
if node_line == parent_line + 1 {
indent_for_line_below = indent_for_line;
} else {
result.add_line(&indent_for_line);
indent_for_line_below = Indentation::default();
}
indent_for_line = Indentation::default();
}
node = parent;
first_in_line.pop();
} else {
// Only add the indentation for the line below if that line
// is not after the line that the indentation is calculated for.
if (node.start_position().row < line)
|| (new_line && node.start_position().row == line && node.start_byte() < byte_pos)
{
result.add_line(&indent_for_line_below);
}
result.add_line(&indent_for_line);
break;
}
}
Some(result.as_string(indent_style))
}
/// Returns the indentation for a new line.
/// This is done either using treesitter, or if that's not available by copying the indentation from the current line
#[allow(clippy::too_many_arguments)]
pub fn indent_for_newline(
language_config: Option<&LanguageConfiguration>,
syntax: Option<&Syntax>,
indent_style: &IndentStyle,
tab_width: usize,
text: RopeSlice,
pos: usize,
line: usize,
new_line: bool,
) -> Option<usize> {
line_before: usize,
line_before_end_pos: usize,
current_line: usize,
) -> String {
if let (Some(query), Some(syntax)) = (
language_config.and_then(|config| config.indent_query()),
syntax,
) {
let byte_start = text.char_to_byte(pos);
let node = get_highest_syntax_node_at_bytepos(syntax, byte_start);
// TODO: special case for comments
// TODO: if preserve_leading_whitespace
Some(calculate_indentation(query, node, line, new_line))
} else {
None
if let Some(indent) = treesitter_indent_for_pos(
query,
syntax,
indent_style,
tab_width,
text,
line_before,
line_before_end_pos,
true,
) {
return indent;
};
}
let indent_level = indent_level_for_line(text.line(current_line), tab_width);
indent_style.as_str().repeat(indent_level)
}
pub fn get_scopes(syntax: Option<&Syntax>, text: RopeSlice, pos: usize) -> Vec<&'static str> {
@@ -326,156 +771,4 @@ mod test {
let line = Rope::from("\t \tfn new"); // 1 tab, 4 spaces, tab
assert_eq!(indent_level_for_line(line.slice(..), tab_width), 3);
}
#[test]
fn test_suggested_indent_for_line() {
let doc = Rope::from(
"
use std::{
io::{self, stdout, Stdout, Write},
path::PathBuf,
sync::Arc,
time::Duration,
}
mod test {
fn hello_world() {
1 + 1;
let does_indentation_work = 1;
let test_function = function_with_param(this_param,
that_param
);
let test_function = function_with_param(
this_param,
that_param
);
let test_function = function_with_proper_indent(param1,
param2,
);
let selection = Selection::new(
changes
.clone()
.map(|(start, end, text): (usize, usize, Option<Tendril>)| {
let len = text.map(|text| text.len()).unwrap() - 1; // minus newline
let pos = start + len;
Range::new(pos, pos)
})
.collect(),
0,
);
return;
}
}
impl<A, D> MyTrait<A, D> for YourType
where
A: TraitB + TraitC,
D: TraitE + TraitF,
{
}
#[test]
//
match test {
Some(a) => 1,
None => {
unimplemented!()
}
}
std::panic::set_hook(Box::new(move |info| {
hook(info);
}));
{ { {
1
}}}
pub fn change<I>(document: &Document, changes: I) -> Self
where
I: IntoIterator<Item = Change> + ExactSizeIterator,
{
[
1,
2,
3,
];
(
1,
2
);
true
}
",
);
let doc = doc;
use crate::diagnostic::Severity;
use crate::syntax::{
Configuration, IndentationConfiguration, LanguageConfiguration, Loader,
};
use once_cell::sync::OnceCell;
let loader = Loader::new(Configuration {
language: vec![LanguageConfiguration {
scope: "source.rust".to_string(),
file_types: vec!["rs".to_string()],
shebangs: vec![],
language_id: "Rust".to_string(),
highlight_config: OnceCell::new(),
config: None,
//
injection_regex: None,
roots: vec![],
comment_token: None,
auto_format: false,
diagnostic_severity: Severity::Warning,
grammar: None,
language_server: None,
indent: Some(IndentationConfiguration {
tab_width: 4,
unit: String::from(" "),
}),
indent_query: OnceCell::new(),
textobject_query: OnceCell::new(),
debugger: None,
auto_pairs: None,
}],
});
// set runtime path so we can find the queries
let mut runtime = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
runtime.push("../runtime");
std::env::set_var("HELIX_RUNTIME", runtime.to_str().unwrap());
let language_config = loader.language_config_for_scope("source.rust").unwrap();
let highlight_config = language_config.highlight_config(&[]).unwrap();
let syntax = Syntax::new(&doc, highlight_config, std::sync::Arc::new(loader));
let text = doc.slice(..);
let tab_width = 4;
for i in 0..doc.len_lines() {
let line = text.line(i);
if let Some(pos) = crate::find_first_non_whitespace_char(line) {
let indent = indent_level_for_line(line, tab_width);
assert_eq!(
suggested_indent_for_pos(
Some(&language_config),
Some(&syntax),
text,
text.line_to_char(i) + pos,
i,
false
),
Some(indent),
"line {}: \"{}\"",
i,
line
);
}
}
}
}

View File

@@ -21,11 +21,12 @@ pub mod register;
pub mod search;
pub mod selection;
pub mod shellwords;
mod state;
pub mod surround;
pub mod syntax;
pub mod test;
pub mod textobject;
mod transaction;
pub mod wrap;
pub mod unicode {
pub use unicode_general_category as category;
@@ -41,10 +42,10 @@ pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option<usize> {
///
/// Order of detection:
/// * Top-most folder containing a root marker in current git repository
/// * Git repostory root if no marker detected
/// * 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]) -> Option<std::path::PathBuf> {
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 {
@@ -61,28 +62,28 @@ pub fn find_root(root: Option<&str>, root_markers: &[String]) -> Option<std::pat
let mut top_marker = None;
for ancestor in root.ancestors() {
for marker in root_markers {
if ancestor.join(marker).exists() {
top_marker = Some(ancestor);
break;
}
if root_markers
.iter()
.any(|marker| ancestor.join(marker).exists())
{
top_marker = Some(ancestor);
}
// don't go higher than repo
if ancestor.join(".git").is_dir() {
// Use workspace if detected from marker
return Some(top_marker.unwrap_or(ancestor).to_path_buf());
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;
}
}
// In absence of git repo, use workspace if detected
if top_marker.is_some() {
top_marker.map(|a| a.to_path_buf())
} else {
Some(current_dir)
}
// 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::{Rope, RopeBuilder, RopeSlice};
pub use ropey::{self, str_utils, Rope, RopeBuilder, RopeSlice};
// pub use tendril::StrTendril as Tendril;
pub use smartstring::SmartString;
@@ -93,13 +94,14 @@ pub type Tendril = SmartString<smartstring::LazyCompact>;
pub use {regex, tree_sitter};
pub use graphemes::RopeGraphemes;
pub use position::{coords_at_pos, pos_at_coords, visual_coords_at_pos, Position};
pub use position::{
coords_at_pos, pos_at_coords, pos_at_visual_coords, visual_coords_at_pos, Position,
};
pub use selection::{Range, Selection};
pub use smallvec::{smallvec, SmallVec};
pub use syntax::Syntax;
pub use diagnostic::Diagnostic;
pub use state::State;
pub use line_ending::{LineEnding, DEFAULT_LINE_ENDING};
pub use transaction::{Assoc, Change, ChangeSet, Operation, Transaction};

View File

@@ -6,7 +6,7 @@ pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::Crlf;
pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::LF;
/// Represents one of the valid Unicode line endings.
#[derive(PartialEq, Copy, Clone, Debug)]
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum LineEnding {
Crlf, // CarriageReturn followed by LineFeed
LF, // U+000A -- LineFeed
@@ -119,6 +119,11 @@ pub fn str_is_line_ending(s: &str) -> bool {
LineEnding::from_str(s).is_some()
}
#[inline]
pub fn rope_is_line_ending(r: RopeSlice) -> bool {
r.chunks().all(str_is_line_ending)
}
/// Attempts to detect what line ending the passed document uses.
pub fn auto_detect_line_ending(doc: &Rope) -> Option<LineEnding> {
// Return first matched line ending. Not all possible line endings
@@ -300,8 +305,17 @@ mod line_ending_tests {
fn line_end_char_index_rope_slice() {
let r = Rope::from_str("Hello\rworld\nhow\r\nare you?");
let s = &r.slice(..);
assert_eq!(line_end_char_index(s, 0), 11);
assert_eq!(line_end_char_index(s, 1), 15);
assert_eq!(line_end_char_index(s, 2), 25);
#[cfg(not(feature = "unicode-lines"))]
{
assert_eq!(line_end_char_index(s, 0), 11);
assert_eq!(line_end_char_index(s, 1), 15);
assert_eq!(line_end_char_index(s, 2), 25);
}
#[cfg(feature = "unicode-lines")]
{
assert_eq!(line_end_char_index(s, 0), 5);
assert_eq!(line_end_char_index(s, 1), 11);
assert_eq!(line_end_char_index(s, 2), 15);
}
}
}

View File

@@ -5,15 +5,15 @@ use tree_sitter::{Node, QueryCursor};
use crate::{
chars::{categorize_char, char_is_line_ending, CharCategory},
coords_at_pos,
graphemes::{
next_grapheme_boundary, nth_next_grapheme_boundary, nth_prev_grapheme_boundary,
prev_grapheme_boundary,
},
pos_at_coords,
line_ending::rope_is_line_ending,
pos_at_visual_coords,
syntax::LanguageConfiguration,
textobject::TextObject,
Position, Range, RopeSlice,
visual_coords_at_pos, Position, Range, RopeSlice,
};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -34,6 +34,7 @@ pub fn move_horizontally(
dir: Direction,
count: usize,
behaviour: Movement,
_: usize,
) -> Range {
let pos = range.cursor(slice);
@@ -53,15 +54,12 @@ pub fn move_vertically(
dir: Direction,
count: usize,
behaviour: Movement,
tab_width: usize,
) -> Range {
let pos = range.cursor(slice);
// Compute the current position's 2d coordinates.
// TODO: switch this to use `visual_coords_at_pos` rather than
// `coords_at_pos` as this will cause a jerky movement when the visual
// position does not match, like moving from a line with tabs/CJK to
// a line without
let Position { row, col } = coords_at_pos(slice, pos);
let Position { row, col } = visual_coords_at_pos(slice, pos, tab_width);
let horiz = range.horiz.unwrap_or(col as u32);
// Compute the new position.
@@ -70,7 +68,7 @@ pub fn move_vertically(
Direction::Backward => row.saturating_sub(count),
};
let new_col = col.max(horiz as usize);
let new_pos = pos_at_coords(slice, Position::new(new_row, new_col), true);
let new_pos = pos_at_visual_coords(slice, Position::new(new_row, new_col), tab_width);
// Special-case to avoid moving to the end of the last non-empty line.
if behaviour == Movement::Extend && slice.line(new_row).len_chars() == 0 {
@@ -149,6 +147,88 @@ fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTar
})
}
pub fn move_prev_paragraph(
slice: RopeSlice,
range: Range,
count: usize,
behavior: Movement,
) -> Range {
let mut line = range.cursor_line(slice);
let first_char = slice.line_to_char(line) == range.cursor(slice);
let prev_line_empty = rope_is_line_ending(slice.line(line.saturating_sub(1)));
let curr_line_empty = rope_is_line_ending(slice.line(line));
let prev_empty_to_line = prev_line_empty && !curr_line_empty;
// skip character before paragraph boundary
if prev_empty_to_line && !first_char {
line += 1;
}
let mut lines = slice.lines_at(line);
lines.reverse();
let mut lines = lines.map(rope_is_line_ending).peekable();
for _ in 0..count {
while lines.next_if(|&e| e).is_some() {
line -= 1;
}
while lines.next_if(|&e| !e).is_some() {
line -= 1;
}
}
let head = slice.line_to_char(line);
let anchor = if behavior == Movement::Move {
// exclude first character after paragraph boundary
if prev_empty_to_line && first_char {
range.cursor(slice)
} else {
range.head
}
} else {
range.put_cursor(slice, head, true).anchor
};
Range::new(anchor, head)
}
pub fn move_next_paragraph(
slice: RopeSlice,
range: Range,
count: usize,
behavior: Movement,
) -> Range {
let mut line = range.cursor_line(slice);
let last_char =
prev_grapheme_boundary(slice, slice.line_to_char(line + 1)) == range.cursor(slice);
let curr_line_empty = rope_is_line_ending(slice.line(line));
let next_line_empty =
rope_is_line_ending(slice.line(slice.len_lines().saturating_sub(1).min(line + 1)));
let curr_empty_to_line = curr_line_empty && !next_line_empty;
// skip character after paragraph boundary
if curr_empty_to_line && last_char {
line += 1;
}
let mut lines = slice.lines_at(line).map(rope_is_line_ending).peekable();
for _ in 0..count {
while lines.next_if(|&e| !e).is_some() {
line += 1;
}
while lines.next_if(|&e| e).is_some() {
line += 1;
}
}
let head = slice.line_to_char(line);
let anchor = if behavior == Movement::Move {
if curr_empty_to_line && last_char {
range.head
} else {
range.cursor(slice)
}
} else {
range.put_cursor(slice, head, true).anchor
};
Range::new(anchor, head)
}
// ---- util ------------
#[inline]
@@ -190,7 +270,7 @@ pub enum WordMotionTarget {
NextWordEnd,
PrevWordStart,
PrevWordEnd,
// A "Long word" (also known as a WORD in vim/kakoune) is strictly
// A "Long word" (also known as a WORD in Vim/Kakoune) is strictly
// delimited by whitespace, and can consist of punctuation as well
// as alphanumerics.
NextLongWordStart,
@@ -309,6 +389,8 @@ fn reached_target(target: WordMotionTarget, prev_ch: char, next_ch: char) -> boo
}
}
/// Finds the range of the next or previous textobject in the syntax sub-tree of `node`.
/// Returns the range in the forwards direction.
pub fn goto_treesitter_object(
slice: RopeSlice,
range: Range,
@@ -316,9 +398,9 @@ pub fn goto_treesitter_object(
dir: Direction,
slice_tree: Node,
lang_config: &LanguageConfiguration,
_count: usize,
count: usize,
) -> Range {
let get_range = move || -> Option<Range> {
let get_range = move |range: Range| -> Option<Range> {
let byte_pos = slice.char_to_byte(range.cursor(slice));
let cap_name = |t: TextObject| format!("{}.{}", object_name, t);
@@ -339,8 +421,8 @@ pub fn goto_treesitter_object(
.filter(|n| n.start_byte() > byte_pos)
.min_by_key(|n| n.start_byte())?,
Direction::Backward => nodes
.filter(|n| n.start_byte() < byte_pos)
.max_by_key(|n| n.start_byte())?,
.filter(|n| n.end_byte() < byte_pos)
.max_by_key(|n| n.end_byte())?,
};
let len = slice.len_bytes();
@@ -354,15 +436,17 @@ pub fn goto_treesitter_object(
let end_char = slice.byte_to_char(end_byte);
// head of range should be at beginning
Some(Range::new(end_char, start_char))
Some(Range::new(start_char, end_char))
};
get_range().unwrap_or(range)
(0..count).fold(range, |range, _| get_range(range).unwrap_or(range))
}
#[cfg(test)]
mod test {
use ropey::Rope;
use crate::{coords_at_pos, pos_at_coords};
use super::*;
const SINGLE_LINE_SAMPLE: &str = "This is a simple alphabetic line";
@@ -389,7 +473,7 @@ mod test {
assert_eq!(
coords_at_pos(
slice,
move_vertically(slice, range, Direction::Forward, 1, Movement::Move).head
move_vertically(slice, range, Direction::Forward, 1, Movement::Move, 4).head
),
(1, 3).into()
);
@@ -413,7 +497,7 @@ mod test {
];
for ((direction, amount), coordinates) in moves_and_expected_coordinates {
range = move_horizontally(slice, range, direction, amount, Movement::Move);
range = move_horizontally(slice, range, direction, amount, Movement::Move, 0);
assert_eq!(coords_at_pos(slice, range.head), coordinates.into())
}
}
@@ -439,7 +523,7 @@ mod test {
];
for ((direction, amount), coordinates) in moves_and_expected_coordinates {
range = move_horizontally(slice, range, direction, amount, Movement::Move);
range = move_horizontally(slice, range, direction, amount, Movement::Move, 0);
assert_eq!(coords_at_pos(slice, range.head), coordinates.into());
assert_eq!(range.head, range.anchor);
}
@@ -461,7 +545,7 @@ mod test {
];
for (direction, amount) in moves {
range = move_horizontally(slice, range, direction, amount, Movement::Extend);
range = move_horizontally(slice, range, direction, amount, Movement::Extend, 0);
assert_eq!(range.anchor, original_anchor);
}
}
@@ -485,7 +569,7 @@ mod test {
];
for ((direction, amount), coordinates) in moves_and_expected_coordinates {
range = move_vertically(slice, range, direction, amount, Movement::Move);
range = move_vertically(slice, range, direction, amount, Movement::Move, 4);
assert_eq!(coords_at_pos(slice, range.head), coordinates.into());
assert_eq!(range.head, range.anchor);
}
@@ -519,8 +603,8 @@ mod test {
for ((axis, direction, amount), coordinates) in moves_and_expected_coordinates {
range = match axis {
Axis::H => move_horizontally(slice, range, direction, amount, Movement::Move),
Axis::V => move_vertically(slice, range, direction, amount, Movement::Move),
Axis::H => move_horizontally(slice, range, direction, amount, Movement::Move, 0),
Axis::V => move_vertically(slice, range, direction, amount, Movement::Move, 4),
};
assert_eq!(coords_at_pos(slice, range.head), coordinates.into());
assert_eq!(range.head, range.anchor);
@@ -544,18 +628,18 @@ mod test {
let moves_and_expected_coordinates = [
// Places cursor at the fourth kana.
((Axis::H, Direction::Forward, 4), (0, 4)),
// Descent places cursor at the 4th character.
((Axis::V, Direction::Forward, 1usize), (1, 4)),
// Moving back 1 character.
((Axis::H, Direction::Backward, 1usize), (1, 3)),
// Descent places cursor at the 8th character.
((Axis::V, Direction::Forward, 1usize), (1, 8)),
// Moving back 2 characters.
((Axis::H, Direction::Backward, 2usize), (1, 6)),
// Jumping back up 1 line.
((Axis::V, Direction::Backward, 1usize), (0, 3)),
];
for ((axis, direction, amount), coordinates) in moves_and_expected_coordinates {
range = match axis {
Axis::H => move_horizontally(slice, range, direction, amount, Movement::Move),
Axis::V => move_vertically(slice, range, direction, amount, Movement::Move),
Axis::H => move_horizontally(slice, range, direction, amount, Movement::Move, 0),
Axis::V => move_vertically(slice, range, direction, amount, Movement::Move, 4),
};
assert_eq!(coords_at_pos(slice, range.head), coordinates.into());
assert_eq!(range.head, range.anchor);
@@ -1179,4 +1263,172 @@ mod test {
}
}
}
#[test]
fn test_behaviour_when_moving_to_prev_paragraph_single() {
let tests = [
("#[|]#", "#[|]#"),
("#[s|]#tart at\nfirst char\n", "#[|s]#tart at\nfirst char\n"),
("start at\nlast char#[\n|]#", "#[|start at\nlast char\n]#"),
(
"goto\nfirst\n\n#[p|]#aragraph",
"#[|goto\nfirst\n\n]#paragraph",
),
(
"goto\nfirst\n#[\n|]#paragraph",
"#[|goto\nfirst\n\n]#paragraph",
),
(
"goto\nsecond\n\np#[a|]#ragraph",
"goto\nsecond\n\n#[|pa]#ragraph",
),
(
"here\n\nhave\nmultiple\nparagraph\n\n\n\n\n#[|]#",
"here\n\n#[|have\nmultiple\nparagraph\n\n\n\n\n]#",
),
];
for (before, expected) in tests {
let (s, selection) = crate::test::print(before);
let text = Rope::from(s.as_str());
let selection =
selection.transform(|r| move_prev_paragraph(text.slice(..), r, 1, Movement::Move));
let actual = crate::test::plain(&s, selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
#[test]
fn test_behaviour_when_moving_to_prev_paragraph_double() {
let tests = [
(
"on#[e|]#\n\ntwo\n\nthree\n\n",
"#[|one]#\n\ntwo\n\nthree\n\n",
),
(
"one\n\ntwo\n\nth#[r|]#ee\n\n",
"one\n\n#[|two\n\nthr]#ee\n\n",
),
];
for (before, expected) in tests {
let (s, selection) = crate::test::print(before);
let text = Rope::from(s.as_str());
let selection =
selection.transform(|r| move_prev_paragraph(text.slice(..), r, 2, Movement::Move));
let actual = crate::test::plain(&s, selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
#[test]
fn test_behaviour_when_moving_to_prev_paragraph_extend() {
let tests = [
(
"one\n\n#[|two\n\n]#three\n\n",
"#[|one\n\ntwo\n\n]#three\n\n",
),
(
"#[|one\n\ntwo\n\n]#three\n\n",
"#[|one\n\ntwo\n\n]#three\n\n",
),
];
for (before, expected) in tests {
let (s, selection) = crate::test::print(before);
let text = Rope::from(s.as_str());
let selection = selection
.transform(|r| move_prev_paragraph(text.slice(..), r, 1, Movement::Extend));
let actual = crate::test::plain(&s, selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
#[test]
fn test_behaviour_when_moving_to_next_paragraph_single() {
let tests = [
("#[|]#", "#[|]#"),
("#[s|]#tart at\nfirst char\n", "#[start at\nfirst char\n|]#"),
("start at\nlast char#[\n|]#", "start at\nlast char#[\n|]#"),
(
"a\nb\n\n#[g|]#oto\nthird\n\nparagraph",
"a\nb\n\n#[goto\nthird\n\n|]#paragraph",
),
(
"a\nb\n#[\n|]#goto\nthird\n\nparagraph",
"a\nb\n\n#[goto\nthird\n\n|]#paragraph",
),
(
"a\nb#[\n|]#\ngoto\nsecond\n\nparagraph",
"a\nb#[\n\n|]#goto\nsecond\n\nparagraph",
),
(
"here\n\nhave\n#[m|]#ultiple\nparagraph\n\n\n\n\n",
"here\n\nhave\n#[multiple\nparagraph\n\n\n\n\n|]#",
),
(
"#[t|]#ext\n\n\nafter two blank lines\n\nmore text\n",
"#[text\n\n\n|]#after two blank lines\n\nmore text\n",
),
(
"#[text\n\n\n|]#after two blank lines\n\nmore text\n",
"text\n\n\n#[after two blank lines\n\n|]#more text\n",
),
];
for (before, expected) in tests {
let (s, selection) = crate::test::print(before);
let text = Rope::from(s.as_str());
let selection =
selection.transform(|r| move_next_paragraph(text.slice(..), r, 1, Movement::Move));
let actual = crate::test::plain(&s, selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
#[test]
fn test_behaviour_when_moving_to_next_paragraph_double() {
let tests = [
(
"one\n\ntwo\n\nth#[r|]#ee\n\n",
"one\n\ntwo\n\nth#[ree\n\n|]#",
),
(
"on#[e|]#\n\ntwo\n\nthree\n\n",
"on#[e\n\ntwo\n\n|]#three\n\n",
),
];
for (before, expected) in tests {
let (s, selection) = crate::test::print(before);
let text = Rope::from(s.as_str());
let selection =
selection.transform(|r| move_next_paragraph(text.slice(..), r, 2, Movement::Move));
let actual = crate::test::plain(&s, selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
#[test]
fn test_behaviour_when_moving_to_next_paragraph_extend() {
let tests = [
(
"one\n\n#[two\n\n|]#three\n\n",
"one\n\n#[two\n\nthree\n\n|]#",
),
(
"one\n\n#[two\n\nthree\n\n|]#",
"one\n\n#[two\n\nthree\n\n|]#",
),
];
for (before, expected) in tests {
let (s, selection) = crate::test::print(before);
let text = Rope::from(s.as_str());
let selection = selection
.transform(|r| move_next_paragraph(text.slice(..), r, 1, Movement::Extend));
let actual = crate::test::plain(&s, selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
}

View File

@@ -2,12 +2,11 @@ use crate::{Range, RopeSlice, Selection, Syntax};
use tree_sitter::Node;
pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection {
select_node_impl(syntax, text, selection, |descendant, from, to| {
if descendant.start_byte() == from && descendant.end_byte() == to {
descendant.parent()
} else {
Some(descendant)
select_node_impl(syntax, text, selection, |mut node, from, to| {
while node.start_byte() == from && node.end_byte() == to {
node = node.parent()?;
}
Some(node)
})
}

View File

@@ -5,16 +5,15 @@ use std::path::{Component, Path, PathBuf};
/// is available, otherwise returns the path unchanged.
pub fn fold_home_dir(path: &Path) -> PathBuf {
if let Ok(home) = home_dir() {
if path.starts_with(&home) {
// it's ok to unwrap, the path starts with home dir
return PathBuf::from("~").join(path.strip_prefix(&home).unwrap());
if let Ok(stripped) = path.strip_prefix(&home) {
return PathBuf::from("~").join(stripped);
}
}
path.to_path_buf()
}
/// Expands tilde `~` into users home directory if avilable, otherwise returns the path
/// Expands tilde `~` into users home directory if available, otherwise returns the path
/// unchanged. The tilde will only be expanded when present as the first component of the path
/// and only slash follows it.
pub fn expand_tilde(path: &Path) -> PathBuf {
@@ -91,3 +90,54 @@ pub fn get_relative_path(path: &Path) -> PathBuf {
};
fold_home_dir(path)
}
/// Returns a truncated filepath where the basepart of the path is reduced to the first
/// char of the folder and the whole filename appended.
///
/// Also strip the current working directory from the beginning of the path.
/// Note that this function does not check if the truncated path is unambiguous.
///
/// ```
/// use helix_core::path::get_truncated_path;
/// use std::path::Path;
///
/// assert_eq!(
/// get_truncated_path("/home/cnorris/documents/jokes.txt").as_path(),
/// Path::new("/h/c/d/jokes.txt")
/// );
/// assert_eq!(
/// get_truncated_path("jokes.txt").as_path(),
/// Path::new("jokes.txt")
/// );
/// assert_eq!(
/// get_truncated_path("/jokes.txt").as_path(),
/// Path::new("/jokes.txt")
/// );
/// assert_eq!(
/// get_truncated_path("/h/c/d/jokes.txt").as_path(),
/// Path::new("/h/c/d/jokes.txt")
/// );
/// assert_eq!(get_truncated_path("").as_path(), Path::new(""));
/// ```
///
pub fn get_truncated_path<P: AsRef<Path>>(path: P) -> PathBuf {
let cwd = std::env::current_dir().unwrap_or_default();
let path = path
.as_ref()
.strip_prefix(cwd)
.unwrap_or_else(|_| path.as_ref());
let file = path.file_name().unwrap_or_default();
let base = path.parent().unwrap_or_else(|| Path::new(""));
let mut ret = PathBuf::new();
for d in base {
ret.push(
d.to_string_lossy()
.chars()
.next()
.unwrap_or_default()
.to_string(),
);
}
ret.push(file);
ret
}

View File

@@ -109,9 +109,6 @@ pub fn visual_coords_at_pos(text: RopeSlice, pos: usize, tab_width: usize) -> Po
/// with left-side block-cursor positions, as this prevents the the block cursor
/// from jumping to the next line. Otherwise you typically want it to be `false`,
/// such as when dealing with raw anchor/head positions.
///
/// TODO: this should be changed to work in terms of visual row/column, not
/// graphemes.
pub fn pos_at_coords(text: RopeSlice, coords: Position, limit_before_line_ending: bool) -> usize {
let Position { mut row, col } = coords;
if limit_before_line_ending {
@@ -135,6 +132,43 @@ pub fn pos_at_coords(text: RopeSlice, coords: Position, limit_before_line_ending
line_start + col_char_offset
}
/// Convert visual (line, column) coordinates to a character index.
///
/// If the `line` coordinate is beyond the end of the file, the EOF
/// position will be returned.
///
/// If the `column` coordinate is past the end of the given line, the
/// line-end position (in this case, just before the line ending
/// character) will be returned.
pub fn pos_at_visual_coords(text: RopeSlice, coords: Position, tab_width: usize) -> usize {
let Position { mut row, col } = coords;
row = row.min(text.len_lines() - 1);
let line_start = text.line_to_char(row);
let line_end = line_end_char_index(&text, row);
let mut col_char_offset = 0;
let mut cols_remaining = col;
for grapheme in RopeGraphemes::new(text.slice(line_start..line_end)) {
let grapheme_width = if grapheme == "\t" {
tab_width - ((col - cols_remaining) % tab_width)
} else {
let grapheme = Cow::from(grapheme);
grapheme_width(&grapheme)
};
// If pos is in the middle of a wider grapheme (tab for example)
// return the starting offset.
if grapheme_width > cols_remaining {
break;
}
cols_remaining -= grapheme_width;
col_char_offset += grapheme.chars().count();
}
line_start + col_char_offset
}
#[cfg(test)]
mod test {
use super::*;
@@ -305,4 +339,70 @@ mod test {
assert_eq!(pos_at_coords(slice, (0, 10).into(), true), 0);
assert_eq!(pos_at_coords(slice, (10, 10).into(), true), 0);
}
#[test]
fn test_pos_at_visual_coords() {
let text = Rope::from("ḧëḷḷö\nẅöṛḷḋ");
let slice = text.slice(..);
assert_eq!(pos_at_visual_coords(slice, (0, 0).into(), 4), 0);
assert_eq!(pos_at_visual_coords(slice, (0, 5).into(), 4), 5); // position on \n
assert_eq!(pos_at_visual_coords(slice, (0, 6).into(), 4), 5); // position after \n
assert_eq!(pos_at_visual_coords(slice, (1, 0).into(), 4), 6); // position on w
assert_eq!(pos_at_visual_coords(slice, (1, 1).into(), 4), 7); // position on o
assert_eq!(pos_at_visual_coords(slice, (1, 4).into(), 4), 10); // position on d
// Test with wide characters.
let text = Rope::from("今日はいい\n");
let slice = text.slice(..);
assert_eq!(pos_at_visual_coords(slice, (0, 0).into(), 4), 0);
assert_eq!(pos_at_visual_coords(slice, (0, 1).into(), 4), 0);
assert_eq!(pos_at_visual_coords(slice, (0, 2).into(), 4), 1);
assert_eq!(pos_at_visual_coords(slice, (0, 3).into(), 4), 1);
assert_eq!(pos_at_visual_coords(slice, (0, 4).into(), 4), 2);
assert_eq!(pos_at_visual_coords(slice, (0, 5).into(), 4), 2);
assert_eq!(pos_at_visual_coords(slice, (0, 6).into(), 4), 3);
assert_eq!(pos_at_visual_coords(slice, (0, 7).into(), 4), 3);
assert_eq!(pos_at_visual_coords(slice, (0, 8).into(), 4), 4);
assert_eq!(pos_at_visual_coords(slice, (0, 9).into(), 4), 4);
// assert_eq!(pos_at_visual_coords(slice, (0, 10).into(), 4, false), 5);
// assert_eq!(pos_at_visual_coords(slice, (0, 10).into(), 4, true), 5);
assert_eq!(pos_at_visual_coords(slice, (1, 0).into(), 4), 6);
// Test with grapheme clusters.
let text = Rope::from("a̐éö̲\r\n");
let slice = text.slice(..);
assert_eq!(pos_at_visual_coords(slice, (0, 0).into(), 4), 0);
assert_eq!(pos_at_visual_coords(slice, (0, 1).into(), 4), 2);
assert_eq!(pos_at_visual_coords(slice, (0, 2).into(), 4), 4);
assert_eq!(pos_at_visual_coords(slice, (0, 3).into(), 4), 7); // \r\n is one char here
assert_eq!(pos_at_visual_coords(slice, (0, 4).into(), 4), 7);
assert_eq!(pos_at_visual_coords(slice, (1, 0).into(), 4), 9);
// Test with wide-character grapheme clusters.
let text = Rope::from("किमपि");
// 2 - 1 - 2 codepoints
// TODO: delete handling as per https://news.ycombinator.com/item?id=20058454
let slice = text.slice(..);
assert_eq!(pos_at_visual_coords(slice, (0, 0).into(), 4), 0);
assert_eq!(pos_at_visual_coords(slice, (0, 1).into(), 4), 0);
assert_eq!(pos_at_visual_coords(slice, (0, 2).into(), 4), 2);
assert_eq!(pos_at_visual_coords(slice, (0, 3).into(), 4), 3);
// Test with tabs.
let text = Rope::from("\tHello\n");
let slice = text.slice(..);
assert_eq!(pos_at_visual_coords(slice, (0, 0).into(), 4), 0);
assert_eq!(pos_at_visual_coords(slice, (0, 1).into(), 4), 0);
assert_eq!(pos_at_visual_coords(slice, (0, 2).into(), 4), 0);
assert_eq!(pos_at_visual_coords(slice, (0, 3).into(), 4), 0);
assert_eq!(pos_at_visual_coords(slice, (0, 4).into(), 4), 1);
assert_eq!(pos_at_visual_coords(slice, (0, 5).into(), 4), 2);
// Test out of bounds.
let text = Rope::new();
let slice = text.slice(..);
assert_eq!(pos_at_visual_coords(slice, (10, 0).into(), 4), 0);
assert_eq!(pos_at_visual_coords(slice, (0, 10).into(), 4), 0);
assert_eq!(pos_at_visual_coords(slice, (10, 10).into(), 4), 0);
}
}

View File

@@ -15,11 +15,7 @@ impl Register {
}
pub fn new_with_values(name: char, values: Vec<String>) -> Self {
if name == '_' {
Self::new(name)
} else {
Self { name, values }
}
Self { name, values }
}
pub const fn name(&self) -> char {
@@ -31,15 +27,11 @@ impl Register {
}
pub fn write(&mut self, values: Vec<String>) {
if self.name != '_' {
self.values = values;
}
self.values = values;
}
pub fn push(&mut self, value: String) {
if self.name != '_' {
self.values.push(value);
}
self.values.push(value);
}
}
@@ -54,19 +46,33 @@ impl Registers {
self.inner.get(&name)
}
pub fn get_mut(&mut self, name: char) -> &mut Register {
self.inner
.entry(name)
.or_insert_with(|| Register::new(name))
pub fn read(&self, name: char) -> Option<&[String]> {
self.get(name).map(|reg| reg.read())
}
pub fn write(&mut self, name: char, values: Vec<String>) {
self.inner
.insert(name, Register::new_with_values(name, values));
if name != '_' {
self.inner
.insert(name, Register::new_with_values(name, values));
}
}
pub fn read(&self, name: char) -> Option<&[String]> {
self.get(name).map(|reg| reg.read())
pub fn push(&mut self, name: char, value: String) {
if name != '_' {
if let Some(r) = self.inner.get_mut(&name) {
r.push(value);
} else {
self.write(name, vec![value]);
}
}
}
pub fn first(&self, name: char) -> Option<&String> {
self.read(name).and_then(|entries| entries.first())
}
pub fn last(&self, name: char) -> Option<&String> {
self.read(name).and_then(|entries| entries.last())
}
pub fn inner(&self) -> &HashMap<char, Register> {

View File

@@ -1,6 +1,28 @@
use crate::RopeSlice;
pub fn find_nth_next(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Option<usize> {
// TODO: switch to std::str::Pattern when it is stable.
pub trait CharMatcher {
fn char_match(&self, ch: char) -> bool;
}
impl CharMatcher for char {
fn char_match(&self, ch: char) -> bool {
*self == ch
}
}
impl<F: Fn(&char) -> bool> CharMatcher for F {
fn char_match(&self, ch: char) -> bool {
(*self)(&ch)
}
}
pub fn find_nth_next<M: CharMatcher>(
text: RopeSlice,
char_matcher: M,
mut pos: usize,
n: usize,
) -> Option<usize> {
if pos >= text.len_chars() || n == 0 {
return None;
}
@@ -13,7 +35,7 @@ pub fn find_nth_next(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Opt
pos += 1;
if c == ch {
if char_matcher.char_match(c) {
break;
}
}

View File

@@ -8,7 +8,7 @@ use crate::{
prev_grapheme_boundary,
},
movement::Direction,
Assoc, ChangeSet, RopeSlice,
Assoc, ChangeSet, RopeGraphemes, RopeSlice,
};
use smallvec::{smallvec, SmallVec};
use std::borrow::Cow;
@@ -122,7 +122,7 @@ impl Range {
}
}
// flips the direction of the selection
/// Flips the direction of the selection
pub fn flip(&self) -> Self {
Self {
anchor: self.head,
@@ -131,6 +131,16 @@ impl Range {
}
}
/// Returns the selection if it goes in the direction of `direction`,
/// flipping the selection otherwise.
pub fn with_direction(self, direction: Direction) -> Self {
if self.direction() == direction {
self
} else {
self.flip()
}
}
/// Check two ranges for overlap.
#[must_use]
pub fn overlaps(&self, other: &Self) -> bool {
@@ -222,9 +232,23 @@ impl Range {
// groupAt
/// Returns the text inside this range given the text of the whole buffer.
///
/// The returned `Cow` is a reference if the range of text is inside a single
/// chunk of the rope. Otherwise a copy of the text is returned. Consider
/// using `slice` instead if you do not need a `Cow` or `String` to avoid copying.
#[inline]
pub fn fragment<'a, 'b: 'a>(&'a self, text: RopeSlice<'b>) -> Cow<'b, str> {
text.slice(self.from()..self.to()).into()
self.slice(text).into()
}
/// Returns the text inside this range given the text of the whole buffer.
///
/// The returned value is a reference to the passed slice. This method never
/// copies any contents.
#[inline]
pub fn slice<'a, 'b: 'a>(&'a self, text: RopeSlice<'b>) -> RopeSlice<'b> {
text.slice(self.from()..self.to())
}
//--------------------------------
@@ -339,6 +363,14 @@ impl Range {
pub fn cursor_line(&self, text: RopeSlice) -> usize {
text.char_to_line(self.cursor(text))
}
/// Returns true if this Range covers a single grapheme in the given text
pub fn is_single_grapheme(&self, doc: RopeSlice) -> bool {
let mut graphemes = RopeGraphemes::new(doc.slice(self.from()..self.to()));
let first = graphemes.next();
let second = graphemes.next();
first.is_some() && second.is_none()
}
}
impl From<(usize, usize)> for Range {
@@ -540,6 +572,10 @@ impl Selection {
self.ranges.iter().map(move |range| range.fragment(text))
}
pub fn slices<'a>(&'a self, text: RopeSlice<'a>) -> impl Iterator<Item = RopeSlice> + 'a {
self.ranges.iter().map(move |range| range.slice(text))
}
#[inline(always)]
pub fn iter(&self) -> std::slice::Iter<'_, Range> {
self.ranges.iter()
@@ -633,7 +669,13 @@ pub fn select_on_matches(
let start = text.byte_to_char(start_byte + mat.start());
let end = text.byte_to_char(start_byte + mat.end());
result.push(Range::new(start, end));
let range = Range::new(start, end);
// Make sure the match is not right outside of the selection.
// These invalid matches can come from using RegEx anchors like `^`, `$`
if range != Range::point(sel.to()) {
result.push(range);
}
}
}
@@ -830,7 +872,7 @@ mod test {
}
#[test]
fn test_graphem_aligned() {
fn test_grapheme_aligned() {
let r = Rope::from_str("\r\nHi\r\n");
let s = r.slice(..);
@@ -903,6 +945,76 @@ mod test {
assert_eq!(Range::new(6, 5).min_width_1(s), Range::new(6, 5));
}
#[test]
fn test_select_on_matches() {
use crate::regex::{Regex, RegexBuilder};
let r = Rope::from_str("Nobody expects the Spanish inquisition");
let s = r.slice(..);
let selection = Selection::single(0, r.len_chars());
assert_eq!(
select_on_matches(s, &selection, &Regex::new(r"[A-Z][a-z]*").unwrap()),
Some(Selection::new(
smallvec![Range::new(0, 6), Range::new(19, 26)],
0
))
);
let r = Rope::from_str("This\nString\n\ncontains multiple\nlines");
let s = r.slice(..);
let start_of_line = RegexBuilder::new(r"^").multi_line(true).build().unwrap();
let end_of_line = RegexBuilder::new(r"$").multi_line(true).build().unwrap();
// line without ending
assert_eq!(
select_on_matches(s, &Selection::single(0, 4), &start_of_line),
Some(Selection::single(0, 0))
);
assert_eq!(
select_on_matches(s, &Selection::single(0, 4), &end_of_line),
None
);
// line with ending
assert_eq!(
select_on_matches(s, &Selection::single(0, 5), &start_of_line),
Some(Selection::single(0, 0))
);
assert_eq!(
select_on_matches(s, &Selection::single(0, 5), &end_of_line),
Some(Selection::single(4, 4))
);
// line with start of next line
assert_eq!(
select_on_matches(s, &Selection::single(0, 6), &start_of_line),
Some(Selection::new(
smallvec![Range::point(0), Range::point(5)],
0
))
);
assert_eq!(
select_on_matches(s, &Selection::single(0, 6), &end_of_line),
Some(Selection::single(4, 4))
);
// multiple lines
assert_eq!(
select_on_matches(
s,
&Selection::single(0, s.len_chars()),
&RegexBuilder::new(r"^[a-z ]*$")
.multi_line(true)
.build()
.unwrap()
),
Some(Selection::new(
smallvec![Range::point(12), Range::new(13, 30), Range::new(31, 36)],
0
))
);
}
#[test]
fn test_line_range() {
let r = Rope::from_str("\r\nHi\r\nthere!");

View File

@@ -1,97 +1,198 @@
use std::borrow::Cow;
/// Get the vec of escaped / quoted / doublequoted filenames from the input str
pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
enum State {
Normal,
NormalEscaped,
Quoted,
QuoteEscaped,
Dquoted,
DquoteEscaped,
}
use State::*;
let mut state = Normal;
let mut args: Vec<Cow<str>> = Vec::new();
let mut escaped = String::with_capacity(input.len());
let mut start = 0;
let mut end = 0;
for (i, c) in input.char_indices() {
state = match state {
Normal => match c {
'\\' => {
escaped.push_str(&input[start..i]);
start = i + 1;
NormalEscaped
}
'"' => {
end = i;
Dquoted
}
'\'' => {
end = i;
Quoted
}
c if c.is_ascii_whitespace() => {
end = i;
Normal
}
_ => Normal,
},
NormalEscaped => Normal,
Quoted => match c {
'\\' => {
escaped.push_str(&input[start..i]);
start = i + 1;
QuoteEscaped
}
'\'' => {
end = i;
Normal
}
_ => Quoted,
},
QuoteEscaped => Quoted,
Dquoted => match c {
'\\' => {
escaped.push_str(&input[start..i]);
start = i + 1;
DquoteEscaped
}
'"' => {
end = i;
Normal
}
_ => Dquoted,
},
DquoteEscaped => Dquoted,
};
if i >= input.len() - 1 && end == 0 {
end = i + 1;
}
if end > 0 {
let esc_trim = escaped.trim();
let inp = &input[start..end];
if !(esc_trim.is_empty() && inp.trim().is_empty()) {
if esc_trim.is_empty() {
args.push(inp.into());
} else {
args.push([escaped, inp.into()].concat().into());
escaped = "".to_string();
}
/// Auto escape for shellwords usage.
pub fn escape(input: Cow<str>) -> Cow<str> {
if !input.chars().any(|x| x.is_ascii_whitespace()) {
input
} else if cfg!(unix) {
Cow::Owned(input.chars().fold(String::new(), |mut buf, c| {
if c.is_ascii_whitespace() {
buf.push('\\');
}
start = i + 1;
end = 0;
buf.push(c);
buf
}))
} else {
Cow::Owned(format!("\"{}\"", input))
}
}
enum State {
OnWhitespace,
Unquoted,
UnquotedEscaped,
Quoted,
QuoteEscaped,
Dquoted,
DquoteEscaped,
}
pub struct Shellwords<'a> {
state: State,
/// Shellwords where whitespace and escapes has been resolved.
words: Vec<Cow<'a, str>>,
/// The parts of the input that are divided into shellwords. This can be
/// used to retrieve the original text for a given word by looking up the
/// same index in the Vec as the word in `words`.
parts: Vec<&'a str>,
}
impl<'a> From<&'a str> for Shellwords<'a> {
fn from(input: &'a str) -> Self {
use State::*;
let mut state = Unquoted;
let mut words = Vec::new();
let mut parts = Vec::new();
let mut escaped = String::with_capacity(input.len());
let mut part_start = 0;
let mut unescaped_start = 0;
let mut end = 0;
for (i, c) in input.char_indices() {
state = match state {
OnWhitespace => match c {
'"' => {
end = i;
Dquoted
}
'\'' => {
end = i;
Quoted
}
'\\' => {
if cfg!(unix) {
escaped.push_str(&input[unescaped_start..i]);
unescaped_start = i + 1;
UnquotedEscaped
} else {
OnWhitespace
}
}
c if c.is_ascii_whitespace() => {
end = i;
OnWhitespace
}
_ => Unquoted,
},
Unquoted => match c {
'\\' => {
if cfg!(unix) {
escaped.push_str(&input[unescaped_start..i]);
unescaped_start = i + 1;
UnquotedEscaped
} else {
Unquoted
}
}
c if c.is_ascii_whitespace() => {
end = i;
OnWhitespace
}
_ => Unquoted,
},
UnquotedEscaped => Unquoted,
Quoted => match c {
'\\' => {
if cfg!(unix) {
escaped.push_str(&input[unescaped_start..i]);
unescaped_start = i + 1;
QuoteEscaped
} else {
Quoted
}
}
'\'' => {
end = i;
OnWhitespace
}
_ => Quoted,
},
QuoteEscaped => Quoted,
Dquoted => match c {
'\\' => {
if cfg!(unix) {
escaped.push_str(&input[unescaped_start..i]);
unescaped_start = i + 1;
DquoteEscaped
} else {
Dquoted
}
}
'"' => {
end = i;
OnWhitespace
}
_ => Dquoted,
},
DquoteEscaped => Dquoted,
};
if i >= input.len() - 1 && end == 0 {
end = i + 1;
}
if end > 0 {
let esc_trim = escaped.trim();
let inp = &input[unescaped_start..end];
if !(esc_trim.is_empty() && inp.trim().is_empty()) {
if esc_trim.is_empty() {
words.push(inp.into());
parts.push(inp);
} else {
words.push([escaped, inp.into()].concat().into());
parts.push(&input[part_start..end]);
escaped = "".to_string();
}
}
unescaped_start = i + 1;
part_start = i + 1;
end = 0;
}
}
debug_assert!(words.len() == parts.len());
Self {
state,
words,
parts,
}
}
args
}
impl<'a> Shellwords<'a> {
/// Checks that the input ends with a whitespace character which is not escaped.
///
/// # Examples
///
/// ```rust
/// use helix_core::shellwords::Shellwords;
/// assert_eq!(Shellwords::from(" ").ends_with_whitespace(), true);
/// assert_eq!(Shellwords::from(":open ").ends_with_whitespace(), true);
/// assert_eq!(Shellwords::from(":open foo.txt ").ends_with_whitespace(), true);
/// assert_eq!(Shellwords::from(":open").ends_with_whitespace(), false);
/// #[cfg(unix)]
/// assert_eq!(Shellwords::from(":open a\\ ").ends_with_whitespace(), false);
/// #[cfg(unix)]
/// assert_eq!(Shellwords::from(":open a\\ b.txt").ends_with_whitespace(), false);
/// ```
pub fn ends_with_whitespace(&self) -> bool {
matches!(self.state, State::OnWhitespace)
}
/// Returns the list of shellwords calculated from the input string.
pub fn words(&self) -> &[Cow<'a, str>] {
&self.words
}
/// Returns a list of strings which correspond to [`Self::words`] but represent the original
/// text in the input string - including escape characters - without separating whitespace.
pub fn parts(&self) -> &[&'a str] {
&self.parts
}
}
#[cfg(test)]
@@ -99,9 +200,30 @@ mod test {
use super::*;
#[test]
#[cfg(windows)]
fn test_normal() {
let input = r#":o single_word twó wörds \three\ \"with\ escaping\\"#;
let result = shellwords(input);
let shellwords = Shellwords::from(input);
let result = shellwords.words().to_vec();
let expected = vec![
Cow::from(":o"),
Cow::from("single_word"),
Cow::from("twó"),
Cow::from("wörds"),
Cow::from("\\three\\"),
Cow::from("\\"),
Cow::from("with\\ escaping\\\\"),
];
// TODO test is_owned and is_borrowed, once they get stabilized.
assert_eq!(expected, result);
}
#[test]
#[cfg(unix)]
fn test_normal() {
let input = r#":o single_word twó wörds \three\ \"with\ escaping\\"#;
let shellwords = Shellwords::from(input);
let result = shellwords.words().to_vec();
let expected = vec![
Cow::from(":o"),
Cow::from("single_word"),
@@ -114,10 +236,12 @@ mod test {
}
#[test]
#[cfg(unix)]
fn test_quoted() {
let quoted =
r#":o 'single_word' 'twó wörds' '' ' ''\three\' \"with\ escaping\\' 'quote incomplete"#;
let result = shellwords(quoted);
let shellwords = Shellwords::from(quoted);
let result = shellwords.words().to_vec();
let expected = vec![
Cow::from(":o"),
Cow::from("single_word"),
@@ -129,9 +253,11 @@ mod test {
}
#[test]
#[cfg(unix)]
fn test_dquoted() {
let dquoted = r#":o "single_word" "twó wörds" "" " ""\three\' \"with\ escaping\\" "dquote incomplete"#;
let result = shellwords(dquoted);
let shellwords = Shellwords::from(dquoted);
let result = shellwords.words().to_vec();
let expected = vec![
Cow::from(":o"),
Cow::from("single_word"),
@@ -143,9 +269,11 @@ mod test {
}
#[test]
#[cfg(unix)]
fn test_mixed() {
let dquoted = r#":o single_word 'twó wörds' "\three\' \"with\ escaping\\""no space before"'and after' $#%^@ "%^&(%^" ')(*&^%''a\\\\\b' '"#;
let result = shellwords(dquoted);
let shellwords = Shellwords::from(dquoted);
let result = shellwords.words().to_vec();
let expected = vec![
Cow::from(":o"),
Cow::from("single_word"),
@@ -161,4 +289,48 @@ mod test {
];
assert_eq!(expected, result);
}
#[test]
fn test_lists() {
let input =
r#":set statusline.center ["file-type","file-encoding"] '["list", "in", "qoutes"]'"#;
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"]"#),
];
assert_eq!(expected, result);
}
#[test]
#[cfg(unix)]
fn test_escaping_unix() {
assert_eq!(escape("foobar".into()), Cow::Borrowed("foobar"));
assert_eq!(escape("foo bar".into()), Cow::Borrowed("foo\\ bar"));
assert_eq!(escape("foo\tbar".into()), Cow::Borrowed("foo\\\tbar"));
}
#[test]
#[cfg(windows)]
fn test_escaping_windows() {
assert_eq!(escape("foobar".into()), Cow::Borrowed("foobar"));
assert_eq!(escape("foo bar".into()), Cow::Borrowed("\"foo bar\""));
}
#[test]
#[cfg(unix)]
fn test_parts() {
assert_eq!(Shellwords::from(":o a").parts(), &[":o", "a"]);
assert_eq!(Shellwords::from(":o a\\ ").parts(), &[":o", "a\\ "]);
}
#[test]
#[cfg(windows)]
fn test_parts() {
assert_eq!(Shellwords::from(":o a").parts(), &[":o", "a"]);
assert_eq!(Shellwords::from(":o a\\ ").parts(), &[":o", "a\\"]);
}
}

View File

@@ -1,17 +0,0 @@
use crate::{Rope, Selection};
#[derive(Debug, Clone)]
pub struct State {
pub doc: Rope,
pub selection: Selection,
}
impl State {
#[must_use]
pub fn new(doc: Rope) -> Self {
Self {
doc,
selection: Selection::point(0),
}
}
}

View File

@@ -13,7 +13,7 @@ pub const PAIRS: &[(char, char)] = &[
('', ''),
];
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
PairNotFound,
CursorOverlap,
@@ -52,6 +52,45 @@ pub fn get_pair(ch: char) -> (char, char) {
.unwrap_or((ch, ch))
}
pub fn find_nth_closest_pairs_pos(
text: RopeSlice,
range: Range,
n: usize,
) -> Result<(usize, usize)> {
let is_open_pair = |ch| PAIRS.iter().any(|(open, _)| *open == ch);
let is_close_pair = |ch| PAIRS.iter().any(|(_, close)| *close == ch);
let mut stack = Vec::with_capacity(2);
let pos = range.cursor(text);
for ch in text.chars_at(pos) {
if is_open_pair(ch) {
// Track open pairs encountered so that we can step over
// the corresponding close pairs that will come up further
// down the loop. We want to find a lone close pair whose
// open pair is before the cursor position.
stack.push(ch);
continue;
} else if is_close_pair(ch) {
let (open, _) = get_pair(ch);
if stack.last() == Some(&open) {
stack.pop();
continue;
} else {
// In the ideal case the stack would be empty here and the
// current character would be the close pair that we are
// looking for. It could also be the case that the pairs
// are unbalanced and we encounter a close pair that doesn't
// close the last seen open pair. In either case use this
// char as the auto-detected closest pair.
return find_nth_pairs_pos(text, ch, range, n);
}
}
}
Err(Error::PairNotFound)
}
/// Find the position of surround pairs of `ch` which can be either a closing
/// or opening pair. `n` will skip n - 1 pairs (eg. n=2 will discard (only)
/// the first pair found and keep looking)
@@ -173,17 +212,22 @@ fn find_nth_close_pair(
/// Find position of surround characters around every cursor. Returns None
/// if any positions overlap. Note that the positions are in a flat Vec.
/// Use get_surround_pos().chunks(2) to get matching pairs of surround positions.
/// `ch` can be either closing or opening pair.
/// `ch` can be either closing or opening pair. If `ch` is None, surround pairs
/// are automatically detected around each cursor (note that this may result
/// in them selecting different surround characters for each selection).
pub fn get_surround_pos(
text: RopeSlice,
selection: &Selection,
ch: char,
ch: Option<char>,
skip: usize,
) -> Result<Vec<usize>> {
let mut change_pos = Vec::new();
for &range in selection {
let (open_pos, close_pos) = find_nth_pairs_pos(text, ch, range, skip)?;
let (open_pos, close_pos) = match ch {
Some(ch) => find_nth_pairs_pos(text, ch, range, skip)?,
None => find_nth_closest_pairs_pos(text, range, skip)?,
};
if change_pos.contains(&open_pos) || change_pos.contains(&close_pos) {
return Err(Error::CursorOverlap);
}
@@ -299,7 +343,7 @@ mod test {
// cursor on s[o]me, c[h]ars, newl[i]ne
assert_eq!(
get_surround_pos(slice, &selection, '(', 1)
get_surround_pos(slice, &selection, Some('('), 1)
.unwrap()
.as_slice(),
&[0, 5, 7, 13, 15, 23]
@@ -315,7 +359,7 @@ mod test {
Selection::new(SmallVec::from_slice(&[Range::point(2), Range::point(9)]), 0);
// cursor on s[o]me, c[h]ars
assert_eq!(
get_surround_pos(slice, &selection, '(', 1),
get_surround_pos(slice, &selection, Some('('), 1),
Err(Error::PairNotFound) // different surround chars
);
@@ -325,7 +369,7 @@ mod test {
);
// cursor on [x]x, newli[n]e
assert_eq!(
get_surround_pos(slice, &selection, '(', 1),
get_surround_pos(slice, &selection, Some('('), 1),
Err(Error::PairNotFound) // overlapping surround chars
);
@@ -333,7 +377,7 @@ mod test {
Selection::new(SmallVec::from_slice(&[Range::point(2), Range::point(3)]), 0);
// cursor on s[o][m]e
assert_eq!(
get_surround_pos(slice, &selection, '[', 1),
get_surround_pos(slice, &selection, Some('['), 1),
Err(Error::CursorOverlap)
);
}

File diff suppressed because it is too large Load Diff

265
helix-core/src/test.rs Normal file
View File

@@ -0,0 +1,265 @@
//! Test helpers.
use crate::{Range, Selection};
use smallvec::SmallVec;
use std::cmp::Reverse;
/// Convert annotated test string to test string and selection.
///
/// `#[|` for primary selection with head before anchor followed by `]#`.
/// `#(|` for secondary selection with head before anchor followed by `)#`.
/// `#[` for primary selection with head after anchor followed by `|]#`.
/// `#(` for secondary selection with head after anchor followed by `|)#`.
///
/// # Examples
///
/// ```
/// use helix_core::{Range, Selection, test::print};
/// use smallvec::smallvec;
///
/// assert_eq!(
/// print("#[a|]#b#(|c)#"),
/// ("abc".to_owned(), Selection::new(smallvec![Range::new(0, 1), Range::new(3, 2)], 0))
/// );
/// ```
///
/// # Panics
///
/// Panics when missing primary or appeared more than once.
/// Panics when missing head or anchor.
/// Panics when head come after head or anchor come after anchor.
pub fn print(s: &str) -> (String, Selection) {
let mut primary_idx = None;
let mut ranges = SmallVec::new();
let mut iter = s.chars().peekable();
let mut left = String::with_capacity(s.len());
'outer: while let Some(c) = iter.next() {
let start = left.chars().count();
if c != '#' {
left.push(c);
continue;
}
let (is_primary, close_pair) = match iter.next() {
Some('[') => (true, ']'),
Some('(') => (false, ')'),
Some(ch) => {
left.push('#');
left.push(ch);
continue;
}
None => break,
};
if is_primary && primary_idx.is_some() {
panic!("primary `#[` already appeared {:?} {:?}", left, s);
}
let head_at_beg = iter.next_if_eq(&'|').is_some();
while let Some(c) = iter.next() {
if !(c == close_pair && iter.peek() == Some(&'#')) {
left.push(c);
continue;
}
if !head_at_beg {
let prev = left.pop().unwrap();
if prev != '|' {
left.push(prev);
left.push(c);
continue;
}
}
iter.next(); // skip "#"
if is_primary {
primary_idx = Some(ranges.len());
}
let (anchor, head) = match head_at_beg {
true => (left.chars().count(), start),
false => (start, left.chars().count()),
};
ranges.push(Range::new(anchor, head));
continue 'outer;
}
if head_at_beg {
panic!("missing end `{}#` {:?} {:?}", close_pair, left, s);
} else {
panic!("missing end `|{}#` {:?} {:?}", close_pair, left, s);
}
}
let primary = match primary_idx {
Some(i) => i,
None => panic!("missing primary `#[|]#` {:?}", s),
};
let selection = Selection::new(ranges, primary);
(left, selection)
}
/// Convert test string and selection to annotated test string.
///
/// `#[|` for primary selection with head before anchor followed by `]#`.
/// `#(|` for secondary selection with head before anchor followed by `)#`.
/// `#[` for primary selection with head after anchor followed by `|]#`.
/// `#(` for secondary selection with head after anchor followed by `|)#`.
///
/// # Examples
///
/// ```
/// use helix_core::{Range, Selection, test::plain};
/// use smallvec::smallvec;
///
/// assert_eq!(
/// plain("abc", Selection::new(smallvec![Range::new(0, 1), Range::new(3, 2)], 0)),
/// "#[a|]#b#(|c)#".to_owned()
/// );
/// ```
pub fn plain(s: &str, selection: Selection) -> String {
let primary = selection.primary_index();
let mut out = String::with_capacity(s.len() + 5 * selection.len());
out.push_str(s);
let mut insertion: Vec<_> = selection
.iter()
.enumerate()
.flat_map(|(i, range)| {
// sort like this before reversed so anchor < head later
match (range.anchor < range.head, i == primary) {
(true, true) => [(range.anchor, "#["), (range.head, "|]#")],
(true, false) => [(range.anchor, "#("), (range.head, "|)#")],
(false, true) => [(range.anchor, "]#"), (range.head, "#[|")],
(false, false) => [(range.anchor, ")#"), (range.head, "#(|")],
}
})
.collect();
// insert in reverse order
insertion.sort_unstable_by_key(|k| Reverse(k.0));
for (i, s) in insertion {
out.insert_str(i, s);
}
out
}
#[cfg(test)]
#[allow(clippy::module_inception)]
mod test {
use super::*;
#[test]
fn print_single() {
assert_eq!(
(String::from("hello"), Selection::single(1, 0)),
print("#[|h]#ello")
);
assert_eq!(
(String::from("hello"), Selection::single(0, 1)),
print("#[h|]#ello")
);
assert_eq!(
(String::from("hello"), Selection::single(4, 0)),
print("#[|hell]#o")
);
assert_eq!(
(String::from("hello"), Selection::single(0, 4)),
print("#[hell|]#o")
);
assert_eq!(
(String::from("hello"), Selection::single(5, 0)),
print("#[|hello]#")
);
assert_eq!(
(String::from("hello"), Selection::single(0, 5)),
print("#[hello|]#")
);
}
#[test]
fn print_multi() {
assert_eq!(
(
String::from("hello"),
Selection::new(
SmallVec::from_slice(&[Range::new(1, 0), Range::new(5, 4)]),
0
)
),
print("#[|h]#ell#(|o)#")
);
assert_eq!(
(
String::from("hello"),
Selection::new(
SmallVec::from_slice(&[Range::new(0, 1), Range::new(4, 5)]),
0
)
),
print("#[h|]#ell#(o|)#")
);
assert_eq!(
(
String::from("hello"),
Selection::new(
SmallVec::from_slice(&[Range::new(2, 0), Range::new(5, 3)]),
0
)
),
print("#[|he]#l#(|lo)#")
);
assert_eq!(
(
String::from("hello\r\nhello\r\nhello\r\n"),
Selection::new(
SmallVec::from_slice(&[
Range::new(7, 5),
Range::new(21, 19),
Range::new(14, 12)
]),
0
)
),
print("hello#[|\r\n]#hello#(|\r\n)#hello#(|\r\n)#")
);
}
#[test]
fn print_multi_byte_code_point() {
assert_eq!(
(String::from("„“"), Selection::single(1, 0)),
print("#[|„]#“")
);
assert_eq!(
(String::from("„“"), Selection::single(2, 1)),
print("„#[|“]#")
);
assert_eq!(
(String::from("„“"), Selection::single(0, 1)),
print("#[„|]#“")
);
assert_eq!(
(String::from("„“"), Selection::single(1, 2)),
print("„#[“|]#")
);
assert_eq!(
(String::from("they said „hello“"), Selection::single(11, 10)),
print("they said #[|„]#hello“")
);
}
#[test]
fn print_multi_code_point_grapheme() {
assert_eq!(
(
String::from("hello 👨‍👩‍👧‍👦 goodbye"),
Selection::single(13, 6)
),
print("hello #[|👨‍👩‍👧‍👦]# goodbye")
);
}
}

View File

@@ -4,7 +4,8 @@ use ropey::RopeSlice;
use tree_sitter::{Node, QueryCursor};
use crate::chars::{categorize_char, char_is_whitespace, CharCategory};
use crate::graphemes::next_grapheme_boundary;
use crate::graphemes::{next_grapheme_boundary, prev_grapheme_boundary};
use crate::line_ending::rope_is_line_ending;
use crate::movement::Direction;
use crate::surround;
use crate::syntax::LanguageConfiguration;
@@ -111,14 +112,124 @@ pub fn textobject_word(
}
}
pub fn textobject_surround(
pub fn textobject_paragraph(
slice: RopeSlice,
range: Range,
textobject: TextObject,
count: usize,
) -> Range {
let mut line = range.cursor_line(slice);
let prev_line_empty = rope_is_line_ending(slice.line(line.saturating_sub(1)));
let curr_line_empty = rope_is_line_ending(slice.line(line));
let next_line_empty = rope_is_line_ending(slice.line(line.saturating_sub(1)));
let last_char =
prev_grapheme_boundary(slice, slice.line_to_char(line + 1)) == range.cursor(slice);
let prev_empty_to_line = prev_line_empty && !curr_line_empty;
let curr_empty_to_line = curr_line_empty && !next_line_empty;
// skip character before paragraph boundary
let mut line_back = line; // line but backwards
if prev_empty_to_line || curr_empty_to_line {
line_back += 1;
}
// do not include current paragraph on paragraph end (include next)
if !(curr_empty_to_line && last_char) {
let mut lines = slice.lines_at(line_back);
lines.reverse();
let mut lines = lines.map(rope_is_line_ending).peekable();
while lines.next_if(|&e| e).is_some() {
line_back -= 1;
}
while lines.next_if(|&e| !e).is_some() {
line_back -= 1;
}
}
// skip character after paragraph boundary
if curr_empty_to_line && last_char {
line += 1;
}
let mut lines = slice.lines_at(line).map(rope_is_line_ending).peekable();
let mut count_done = 0; // count how many non-whitespace paragraphs done
for _ in 0..count {
let mut done = false;
while lines.next_if(|&e| !e).is_some() {
line += 1;
done = true;
}
while lines.next_if(|&e| e).is_some() {
line += 1;
}
count_done += done as usize;
}
// search one paragraph backwards for last paragraph
// makes `map` at the end of the paragraph with trailing newlines useful
let last_paragraph = count_done != count && lines.peek().is_none();
if last_paragraph {
let mut lines = slice.lines_at(line_back);
lines.reverse();
let mut lines = lines.map(rope_is_line_ending).peekable();
while lines.next_if(|&e| e).is_some() {
line_back -= 1;
}
while lines.next_if(|&e| !e).is_some() {
line_back -= 1;
}
}
// handle last whitespaces part separately depending on textobject
match textobject {
TextObject::Around => {}
TextObject::Inside => {
// remove last whitespace paragraph
let mut lines = slice.lines_at(line);
lines.reverse();
let mut lines = lines.map(rope_is_line_ending).peekable();
while lines.next_if(|&e| e).is_some() {
line -= 1;
}
}
TextObject::Movement => unreachable!(),
}
let anchor = slice.line_to_char(line_back);
let head = slice.line_to_char(line);
Range::new(anchor, head)
}
pub fn textobject_pair_surround(
slice: RopeSlice,
range: Range,
textobject: TextObject,
ch: char,
count: usize,
) -> Range {
surround::find_nth_pairs_pos(slice, ch, range, count)
textobject_pair_surround_impl(slice, range, textobject, Some(ch), count)
}
pub fn textobject_pair_surround_closest(
slice: RopeSlice,
range: Range,
textobject: TextObject,
count: usize,
) -> Range {
textobject_pair_surround_impl(slice, range, textobject, None, count)
}
fn textobject_pair_surround_impl(
slice: RopeSlice,
range: Range,
textobject: TextObject,
ch: Option<char>,
count: usize,
) -> Range {
let pair_pos = match ch {
Some(ch) => surround::find_nth_pairs_pos(slice, ch, range, count),
// Automatically find the closest surround pairs
None => surround::find_nth_closest_pairs_pos(slice, range, count),
};
pair_pos
.map(|(anchor, head)| match textobject {
TextObject::Inside => Range::new(next_grapheme_boundary(slice, anchor), head),
TextObject::Around => Range::new(anchor, next_grapheme_boundary(slice, head)),
@@ -288,6 +399,91 @@ mod test {
}
}
#[test]
fn test_textobject_paragraph_inside_single() {
let tests = [
("#[|]#", "#[|]#"),
("firs#[t|]#\n\nparagraph\n\n", "#[first\n|]#\nparagraph\n\n"),
(
"second\n\npa#[r|]#agraph\n\n",
"second\n\n#[paragraph\n|]#\n",
),
("#[f|]#irst char\n\n", "#[first char\n|]#\n"),
("last char\n#[\n|]#", "#[last char\n|]#\n"),
(
"empty to line\n#[\n|]#paragraph boundary\n\n",
"empty to line\n\n#[paragraph boundary\n|]#\n",
),
(
"line to empty\n\n#[p|]#aragraph boundary\n\n",
"line to empty\n\n#[paragraph boundary\n|]#\n",
),
];
for (before, expected) in tests {
let (s, selection) = crate::test::print(before);
let text = Rope::from(s.as_str());
let selection = selection
.transform(|r| textobject_paragraph(text.slice(..), r, TextObject::Inside, 1));
let actual = crate::test::plain(&s, selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
#[test]
fn test_textobject_paragraph_inside_double() {
let tests = [
(
"last two\n\n#[p|]#aragraph\n\nwithout whitespaces\n\n",
"last two\n\n#[paragraph\n\nwithout whitespaces\n|]#\n",
),
(
"last two\n#[\n|]#paragraph\n\nwithout whitespaces\n\n",
"last two\n\n#[paragraph\n\nwithout whitespaces\n|]#\n",
),
];
for (before, expected) in tests {
let (s, selection) = crate::test::print(before);
let text = Rope::from(s.as_str());
let selection = selection
.transform(|r| textobject_paragraph(text.slice(..), r, TextObject::Inside, 2));
let actual = crate::test::plain(&s, selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
#[test]
fn test_textobject_paragraph_around_single() {
let tests = [
("#[|]#", "#[|]#"),
("firs#[t|]#\n\nparagraph\n\n", "#[first\n\n|]#paragraph\n\n"),
(
"second\n\npa#[r|]#agraph\n\n",
"second\n\n#[paragraph\n\n|]#",
),
("#[f|]#irst char\n\n", "#[first char\n\n|]#"),
("last char\n#[\n|]#", "#[last char\n\n|]#"),
(
"empty to line\n#[\n|]#paragraph boundary\n\n",
"empty to line\n\n#[paragraph boundary\n\n|]#",
),
(
"line to empty\n\n#[p|]#aragraph boundary\n\n",
"line to empty\n\n#[paragraph boundary\n\n|]#",
),
];
for (before, expected) in tests {
let (s, selection) = crate::test::print(before);
let text = Rope::from(s.as_str());
let selection = selection
.transform(|r| textobject_paragraph(text.slice(..), r, TextObject::Around, 1));
let actual = crate::test::plain(&s, selection);
assert_eq!(actual, expected, "\nbefore: `{:?}`", before);
}
}
#[test]
fn test_textobject_surround() {
// (text, [(cursor position, textobject, final range, surround char, count), ...])
@@ -366,7 +562,7 @@ mod test {
let slice = doc.slice(..);
for &case in scenario {
let (pos, objtype, expected_range, ch, count) = case;
let result = textobject_surround(slice, Range::point(pos), objtype, ch, count);
let result = textobject_pair_surround(slice, Range::point(pos), objtype, ch, count);
assert_eq!(
result,
expected_range.into(),

View File

@@ -56,7 +56,7 @@ impl ChangeSet {
}
// Changeset builder operations: delete/insert/retain
fn delete(&mut self, n: usize) {
pub(crate) fn delete(&mut self, n: usize) {
use Operation::*;
if n == 0 {
return;
@@ -71,7 +71,7 @@ impl ChangeSet {
}
}
fn insert(&mut self, fragment: Tendril) {
pub(crate) fn insert(&mut self, fragment: Tendril) {
use Operation::*;
if fragment.is_empty() {
@@ -93,7 +93,7 @@ impl ChangeSet {
self.changes.push(new_last);
}
fn retain(&mut self, n: usize) {
pub(crate) fn retain(&mut self, n: usize) {
use Operation::*;
if n == 0 {
return;
@@ -577,7 +577,7 @@ impl<'a> Iterator for ChangeIterator<'a> {
#[cfg(test)]
mod test {
use super::*;
use crate::State;
use crate::history::State;
#[test]
fn composition() {
@@ -704,7 +704,10 @@ mod test {
#[test]
fn optimized_composition() {
let mut state = State::new("".into());
let mut state = State {
doc: "".into(),
selection: Selection::point(0),
};
let t1 = Transaction::insert(&state.doc, &state.selection, Tendril::from("h"));
t1.apply(&mut state.doc);
state.selection = state.selection.clone().map(t1.changes());

7
helix-core/src/wrap.rs Normal file
View File

@@ -0,0 +1,7 @@
use smartstring::{LazyCompact, SmartString};
/// Given a slice of text, return the text re-wrapped to fit it
/// within the given width.
pub fn reflow_hard_wrap(text: &str, max_line_len: usize) -> SmartString<LazyCompact> {
textwrap::refill(text, max_line_len).into()
}

View File

@@ -0,0 +1 @@
../../../src/indent.rs

View File

@@ -0,0 +1,13 @@
# This languages.toml should contain definitions for all languages for which we have indent tests
[[language]]
name = "rust"
scope = "source.rust"
injection-regex = "rust"
file-types = ["rs"]
comment-token = "//"
roots = ["Cargo.toml", "Cargo.lock"]
indent = { tab-width = 4, unit = " " }
[[grammar]]
name = "rust"
source = { git = "https://github.com/tree-sitter/tree-sitter-rust", rev = "0431a2c60828731f27491ee9fdefe25e250ce9c9" }

View File

@@ -0,0 +1,105 @@
use std::{
io::{self, stdout, Stdout, Write},
path::PathBuf,
sync::Arc,
time::Duration,
};
mod test {
fn hello_world() {
1 + 1;
let does_indentation_work = 1;
let mut really_long_variable_name_using_up_the_line =
really_long_fn_that_should_definitely_go_on_the_next_line();
really_long_variable_name_using_up_the_line =
really_long_fn_that_should_definitely_go_on_the_next_line();
really_long_variable_name_using_up_the_line |=
really_long_fn_that_should_definitely_go_on_the_next_line();
let (
a_long_variable_name_in_this_tuple,
b_long_variable_name_in_this_tuple,
c_long_variable_name_in_this_tuple,
d_long_variable_name_in_this_tuple,
e_long_variable_name_in_this_tuple,
): (usize, usize, usize, usize, usize) =
if really_long_fn_that_should_definitely_go_on_the_next_line() {
(
03294239434,
1213412342314,
21231234134,
834534234549898789,
9879234234543853457,
)
} else {
(0, 1, 2, 3, 4)
};
let test_function = function_with_param(this_param,
that_param
);
let test_function = function_with_param(
this_param,
that_param
);
let test_function = function_with_proper_indent(param1,
param2,
);
let selection = Selection::new(
changes
.clone()
.map(|(start, end, text): (usize, usize, Option<Tendril>)| {
let len = text.map(|text| text.len()).unwrap() - 1; // minus newline
let pos = start + len;
Range::new(pos, pos)
})
.collect(),
0,
);
return;
}
}
impl<A, D> MyTrait<A, D> for YourType
where
A: TraitB + TraitC,
D: TraitE + TraitF,
{
}
#[test]
//
match test {
Some(a) => 1,
None => {
unimplemented!()
}
}
std::panic::set_hook(Box::new(move |info| {
hook(info);
}));
{ { {
1
}}}
pub fn change<I>(document: &Document, changes: I) -> Self
where
I: IntoIterator<Item = Change> + ExactSizeIterator,
{
[
1,
2,
3,
];
(
1,
2
);
true
}

View File

@@ -0,0 +1,69 @@
use helix_core::{
indent::{treesitter_indent_for_pos, IndentStyle},
syntax::Loader,
Syntax,
};
use std::path::PathBuf;
#[test]
fn test_treesitter_indent_rust() {
test_treesitter_indent("rust.rs", "source.rust");
}
#[test]
fn test_treesitter_indent_rust_2() {
test_treesitter_indent("indent.rs", "source.rust");
// TODO Use commands.rs as indentation test.
// Currently this fails because we can't align the parameters of a closure yet
// test_treesitter_indent("commands.rs", "source.rust");
}
fn test_treesitter_indent(file_name: &str, lang_scope: &str) {
let mut test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
test_dir.push("tests/data/indent");
let mut test_file = test_dir.clone();
test_file.push(file_name);
let test_file = std::fs::File::open(test_file).unwrap();
let doc = ropey::Rope::from_reader(test_file).unwrap();
let mut config_file = test_dir;
config_file.push("languages.toml");
let config = std::fs::read(config_file).unwrap();
let config = toml::from_slice(&config).unwrap();
let loader = Loader::new(config);
// set runtime path so we can find the queries
let mut runtime = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
runtime.push("../runtime");
std::env::set_var("HELIX_RUNTIME", runtime.to_str().unwrap());
let language_config = loader.language_config_for_scope(lang_scope).unwrap();
let highlight_config = language_config.highlight_config(&[]).unwrap();
let syntax = Syntax::new(&doc, highlight_config, std::sync::Arc::new(loader));
let indent_query = language_config.indent_query().unwrap();
let text = doc.slice(..);
for i in 0..doc.len_lines() {
let line = text.line(i);
if let Some(pos) = helix_core::find_first_non_whitespace_char(line) {
let suggested_indent = treesitter_indent_for_pos(
indent_query,
&syntax,
&IndentStyle::Spaces(4),
4,
text,
i,
text.line_to_char(i) + pos,
false,
)
.unwrap();
assert!(
line.get_slice(..pos).map_or(false, |s| s == suggested_indent),
"Wrong indentation on line {}:\n\"{}\" (original line)\n\"{}\" (suggested indentation)\n",
i+1,
line.slice(..line.len_chars()-1),
suggested_indent,
);
}
}
}

View File

@@ -34,7 +34,7 @@ pub struct Client {
pub caps: Option<DebuggerCapabilities>,
// thread_id -> frames
pub stack_frames: HashMap<ThreadId, Vec<StackFrame>>,
pub thread_states: HashMap<ThreadId, String>,
pub thread_states: ThreadStates,
pub thread_id: Option<ThreadId>,
/// Currently active frame for the current thread.
pub active_frame: Option<usize>,

View File

@@ -22,7 +22,7 @@ pub struct Request {
pub arguments: Option<Value>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
pub struct Response {
// seq is omitted as unused and is not sent by some implementations
pub request_seq: u64,

View File

@@ -14,238 +14,353 @@ impl std::fmt::Display for ThreadId {
}
}
pub type ThreadStates = HashMap<ThreadId, String>;
pub trait Request {
type Arguments: serde::de::DeserializeOwned + serde::Serialize;
type Result: serde::de::DeserializeOwned + serde::Serialize;
const COMMAND: &'static str;
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ColumnDescriptor {
pub attribute_name: String,
pub label: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<String>,
#[serde(rename = "type")]
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub ty: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub width: Option<usize>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ExceptionBreakpointsFilter {
pub filter: String,
pub label: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_condition: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub condition_description: Option<String>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DebuggerCapabilities {
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_configuration_done_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_function_breakpoints: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_conditional_breakpoints: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_hit_conditional_breakpoints: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_evaluate_for_hovers: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_step_back: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_set_variable: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_restart_frame: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_goto_targets_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_step_in_targets_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_completions_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_modules_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_restart_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_exception_options: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_value_formatting_options: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_exception_info_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub support_terminate_debuggee: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub support_suspend_debuggee: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_delayed_stack_trace_loading: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_loaded_sources_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_log_points: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_terminate_threads_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_set_expression: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_terminate_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_data_breakpoints: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_read_memory_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_write_memory_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_disassemble_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_cancel_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_breakpoint_locations_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_clipboard_context: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_stepping_granularity: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_instruction_breakpoints: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_exception_filter_options: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub exception_breakpoint_filters: Option<Vec<ExceptionBreakpointsFilter>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub completion_trigger_characters: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub additional_module_columns: Option<Vec<ColumnDescriptor>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supported_checksum_algorithms: Option<Vec<String>>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Checksum {
pub algorithm: String,
pub checksum: String,
}
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Source {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<PathBuf>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_reference: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub presentation_hint: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub origin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sources: Option<Vec<Source>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub adapter_data: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub checksums: Option<Vec<Checksum>>,
}
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SourceBreakpoint {
pub line: usize,
#[serde(skip_serializing_if = "Option::is_none")]
pub column: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub condition: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hit_condition: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub log_message: Option<String>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Breakpoint {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<usize>,
pub verified: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source: Option<Source>,
#[serde(skip_serializing_if = "Option::is_none")]
pub line: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub column: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_line: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_column: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub instruction_reference: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub offset: Option<usize>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StackFrameFormat {
#[serde(skip_serializing_if = "Option::is_none")]
pub parameters: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameter_types: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameter_names: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameter_values: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub line: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub module: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub include_all: Option<bool>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StackFrame {
pub id: usize,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub source: Option<Source>,
pub line: usize,
pub column: usize,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_line: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_column: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub can_restart: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub instruction_pointer_reference: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub module_id: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub presentation_hint: Option<String>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Thread {
pub id: ThreadId,
pub name: String,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Scope {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub presentation_hint: Option<String>,
pub variables_reference: usize,
#[serde(skip_serializing_if = "Option::is_none")]
pub named_variables: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub indexed_variables: Option<usize>,
pub expensive: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub source: Option<Source>,
#[serde(skip_serializing_if = "Option::is_none")]
pub line: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub column: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_line: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_column: Option<usize>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ValueFormat {
#[serde(skip_serializing_if = "Option::is_none")]
pub hex: Option<bool>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct VariablePresentationHint {
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attributes: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visibility: Option<String>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Variable {
pub name: String,
pub value: String,
#[serde(rename = "type")]
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub ty: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub presentation_hint: Option<VariablePresentationHint>,
#[serde(skip_serializing_if = "Option::is_none")]
pub evaluate_name: Option<String>,
pub variables_reference: usize,
#[serde(skip_serializing_if = "Option::is_none")]
pub named_variables: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub indexed_variables: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub memory_reference: Option<String>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Module {
pub id: String, // TODO: || number
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<PathBuf>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_optimized: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_user_code: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol_status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol_file_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub date_time_stamp: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub address_range: Option<String>,
}
pub mod requests {
use super::*;
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct InitializeArguments {
#[serde(rename = "clientID")]
#[serde(rename = "clientID", skip_serializing_if = "Option::is_none")]
pub client_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_name: Option<String>,
#[serde(rename = "adapterID")]
pub adapter_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub locale: Option<String>,
#[serde(rename = "linesStartAt1")]
#[serde(rename = "linesStartAt1", skip_serializing_if = "Option::is_none")]
pub lines_start_at_one: Option<bool>,
#[serde(rename = "columnsStartAt1")]
#[serde(rename = "columnsStartAt1", skip_serializing_if = "Option::is_none")]
pub columns_start_at_one: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub path_format: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_variable_type: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_variable_paging: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_run_in_terminal_request: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_memory_references: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_progress_reporting: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_invalidated_event: Option<bool>,
}
@@ -294,18 +409,21 @@ pub mod requests {
const COMMAND: &'static str = "configurationDone";
}
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SetBreakpointsArguments {
pub source: Source,
#[serde(skip_serializing_if = "Option::is_none")]
pub breakpoints: Option<Vec<SourceBreakpoint>>,
// lines is deprecated
#[serde(skip_serializing_if = "Option::is_none")]
pub source_modified: Option<bool>,
}
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SetBreakpointsResponse {
#[serde(skip_serializing_if = "Option::is_none")]
pub breakpoints: Option<Vec<Breakpoint>>,
}
@@ -318,15 +436,16 @@ pub mod requests {
const COMMAND: &'static str = "setBreakpoints";
}
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ContinueArguments {
pub thread_id: ThreadId,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ContinueResponse {
#[serde(skip_serializing_if = "Option::is_none")]
pub all_threads_continued: Option<bool>,
}
@@ -339,18 +458,22 @@ pub mod requests {
const COMMAND: &'static str = "continue";
}
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StackTraceArguments {
pub thread_id: ThreadId,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_frame: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub levels: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<StackFrameFormat>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StackTraceResponse {
#[serde(skip_serializing_if = "Option::is_none")]
pub total_frames: Option<usize>,
pub stack_frames: Vec<StackFrame>,
}
@@ -364,7 +487,7 @@ pub mod requests {
const COMMAND: &'static str = "stackTrace";
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ThreadsResponse {
pub threads: Vec<Thread>,
@@ -379,13 +502,13 @@ pub mod requests {
const COMMAND: &'static str = "threads";
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ScopesArguments {
pub frame_id: usize,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ScopesResponse {
pub scopes: Vec<Scope>,
@@ -400,17 +523,21 @@ pub mod requests {
const COMMAND: &'static str = "scopes";
}
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct VariablesArguments {
pub variables_reference: usize,
#[serde(skip_serializing_if = "Option::is_none")]
pub filter: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub count: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<ValueFormat>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct VariablesResponse {
pub variables: Vec<Variable>,
@@ -425,11 +552,13 @@ pub mod requests {
const COMMAND: &'static str = "variables";
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StepInArguments {
pub thread_id: ThreadId,
#[serde(skip_serializing_if = "Option::is_none")]
pub target_id: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub granularity: Option<String>,
}
@@ -442,10 +571,11 @@ pub mod requests {
const COMMAND: &'static str = "stepIn";
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StepOutArguments {
pub thread_id: ThreadId,
#[serde(skip_serializing_if = "Option::is_none")]
pub granularity: Option<String>,
}
@@ -458,10 +588,11 @@ pub mod requests {
const COMMAND: &'static str = "stepOut";
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NextArguments {
pub thread_id: ThreadId,
#[serde(skip_serializing_if = "Option::is_none")]
pub granularity: Option<String>,
}
@@ -474,7 +605,7 @@ pub mod requests {
const COMMAND: &'static str = "next";
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PauseArguments {
pub thread_id: ThreadId,
@@ -489,25 +620,32 @@ pub mod requests {
const COMMAND: &'static str = "pause";
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct EvaluateArguments {
pub expression: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub frame_id: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<ValueFormat>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct EvaluateResponse {
pub result: String,
#[serde(rename = "type")]
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub ty: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub presentation_hint: Option<VariablePresentationHint>,
pub variables_reference: usize,
#[serde(skip_serializing_if = "Option::is_none")]
pub named_variables: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub indexed_variables: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub memory_reference: Option<String>,
}
@@ -520,7 +658,7 @@ pub mod requests {
const COMMAND: &'static str = "evaluate";
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SetExceptionBreakpointsArguments {
pub filters: Vec<String>,
@@ -528,9 +666,10 @@ pub mod requests {
// pub exceptionOptions: Option<Vec<ExceptionOptions>>, // needs capability
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SetExceptionBreakpointsResponse {
#[serde(skip_serializing_if = "Option::is_none")]
pub breakpoints: Option<Vec<Breakpoint>>,
}
@@ -545,20 +684,25 @@ pub mod requests {
// Reverse Requests
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RunInTerminalResponse {
#[serde(skip_serializing_if = "Option::is_none")]
pub process_id: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub shell_process_id: Option<u32>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RunInTerminalArguments {
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
pub cwd: Option<String>,
pub cwd: String,
pub args: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub env: Option<HashMap<String, Option<String>>>,
}
@@ -582,7 +726,7 @@ pub mod events {
#[serde(tag = "event", content = "body")]
// seq is omitted as unused and is not sent by some implementations
pub enum Event {
Initialized,
Initialized(Option<DebuggerCapabilities>),
Stopped(Stopped),
Continued(Continued),
Exited(Exited),
@@ -601,95 +745,114 @@ pub mod events {
Memory(Memory),
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Stopped {
pub reason: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub thread_id: Option<ThreadId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub preserve_focus_hint: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub all_threads_stopped: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hit_breakpoint_ids: Option<Vec<usize>>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Continued {
pub thread_id: ThreadId,
#[serde(skip_serializing_if = "Option::is_none")]
pub all_threads_continued: Option<bool>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Exited {
pub exit_code: usize,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Terminated {
#[serde(skip_serializing_if = "Option::is_none")]
pub restart: Option<Value>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Thread {
pub reason: String,
pub thread_id: ThreadId,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Output {
pub output: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub category: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub line: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub column: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub variables_reference: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source: Option<Source>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<Value>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Breakpoint {
pub reason: String,
pub breakpoint: super::Breakpoint,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Module {
pub reason: String,
pub module: super::Module,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct LoadedSource {
pub reason: String,
pub source: super::Source,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Process {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub system_process_id: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_local_process: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_method: Option<String>, // TODO: use enum
#[serde(skip_serializing_if = "Option::is_none")]
pub pointer_size: Option<usize>,
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Capabilities {
pub capabilities: super::DebuggerCapabilities,
}
// #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
// #[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
// #[serde(rename_all = "camelCase")]
// pub struct Invalidated {
// pub areas: Vec<InvalidatedArea>,
@@ -697,7 +860,7 @@ pub mod events {
// pub stack_frame_id: Option<usize>,
// }
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Memory {
pub memory_reference: String,

View File

@@ -9,15 +9,24 @@ categories = ["editor"]
repository = "https://github.com/helix-editor/helix"
homepage = "https://helix-editor.com"
[[bin]]
name = "hx-loader"
path = "src/main.rs"
[dependencies]
anyhow = "1"
serde = { version = "1.0", features = ["derive"] }
toml = "0.5"
etcetera = "0.3"
etcetera = "0.4"
tree-sitter = "0.20"
libloading = "0.7"
once_cell = "1.9"
once_cell = "1.16"
log = "0.4"
# TODO: these two should be on !wasm32 only
# cloning/compiling tree-sitter grammars
cc = { version = "1" }
threadpool = { version = "1.0" }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
libloading = "0.7"

View File

@@ -1,6 +1,26 @@
use std::borrow::Cow;
use std::process::Command;
const VERSION: &str = include_str!("../VERSION");
fn main() {
let git_hash = Command::new("git")
.args(["rev-parse", "HEAD"])
.output()
.ok()
.filter(|output| output.status.success())
.and_then(|x| String::from_utf8(x.stdout).ok());
let version: Cow<_> = match git_hash {
Some(git_hash) => format!("{} ({})", VERSION, &git_hash[..8]).into(),
None => VERSION.into(),
};
println!(
"cargo:rustc-env=BUILD_TARGET={}",
std::env::var("TARGET").unwrap()
);
println!("cargo:rerun-if-changed=../VERSION");
println!("cargo:rustc-env=VERSION_AND_GIT_HASH={}", version);
}

View File

@@ -0,0 +1,42 @@
/// Default built-in languages.toml.
pub fn default_lang_config() -> toml::Value {
toml::from_slice(include_bytes!("../../languages.toml"))
.expect("Could not parse built-in languages.toml to valid toml")
}
/// User configured languages.toml file, merged with the default config.
pub fn user_lang_config() -> Result<toml::Value, toml::de::Error> {
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(&file)
.map(|config| toml::from_slice(&config))
.ok()
})
.collect::<Result<Vec<_>, _>>()?
.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)
});
Ok(config)
}

View File

@@ -1,5 +1,4 @@
use anyhow::{anyhow, Context, Result};
use libloading::{Library, Symbol};
use serde::{Deserialize, Serialize};
use std::fs;
use std::time::SystemTime;
@@ -17,6 +16,9 @@ const DYLIB_EXTENSION: &str = "so";
#[cfg(windows)]
const DYLIB_EXTENSION: &str = "dll";
#[cfg(target_arch = "wasm32")]
const DYLIB_EXTENSION: &str = "wasm";
#[derive(Debug, Serialize, Deserialize)]
struct Configuration {
#[serde(rename = "use-grammars")]
@@ -57,18 +59,24 @@ pub enum GrammarSource {
const BUILD_TARGET: &str = env!("BUILD_TARGET");
const REMOTE_NAME: &str = "origin";
#[cfg(target_arch = "wasm32")]
pub fn get_language(name: &str) -> Result<Language> {
let name = name.to_ascii_lowercase();
let mut library_path = crate::runtime_dir().join("grammars").join(&name);
unimplemented!()
}
#[cfg(not(target_arch = "wasm32"))]
pub fn get_language(name: &str) -> Result<Language> {
use libloading::{Library, Symbol};
let mut library_path = crate::runtime_dir().join("grammars").join(name);
library_path.set_extension(DYLIB_EXTENSION);
let library = unsafe { Library::new(&library_path) }
.with_context(|| format!("Error opening dynamic library {library_path:?}"))?;
.with_context(|| format!("Error opening dynamic library {:?}", library_path))?;
let language_fn_name = format!("tree_sitter_{}", name.replace('-', "_"));
let language = unsafe {
let language_fn: Symbol<unsafe extern "C" fn() -> Language> = library
.get(language_fn_name.as_bytes())
.with_context(|| format!("Failed to load symbol {language_fn_name}"))?;
.with_context(|| format!("Failed to load symbol {}", language_fn_name))?;
language_fn()
};
std::mem::forget(library);
@@ -80,11 +88,102 @@ pub fn fetch_grammars() -> Result<()> {
let mut grammars = get_grammar_configs()?;
grammars.retain(|grammar| !matches!(grammar.source, GrammarSource::Local { .. }));
run_parallel(grammars, fetch_grammar, "fetch")
println!("Fetching {} grammars", grammars.len());
let results = run_parallel(grammars, fetch_grammar);
let mut errors = Vec::new();
let mut git_updated = Vec::new();
let mut git_up_to_date = 0;
let mut non_git = Vec::new();
for 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),
}
}
non_git.sort_unstable();
git_updated.sort_unstable_by(|a, b| a.0.cmp(&b.0));
if git_up_to_date != 0 {
println!("{} up to date git grammars", git_up_to_date);
}
if !non_git.is_empty() {
println!("{} non git grammars", non_git.len());
println!("\t{:?}", non_git);
}
if !git_updated.is_empty() {
println!("{} updated grammars", git_updated.len());
// We checked the vec is not empty, unwrapping will not panic
let longest_id = git_updated.iter().map(|x| x.0.len()).max().unwrap();
for (id, rev) in git_updated {
println!(
"\t{id:width$} now on {rev}",
id = id,
width = longest_id,
rev = rev
);
}
}
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);
}
}
Ok(())
}
pub fn build_grammars() -> Result<()> {
run_parallel(get_grammar_configs()?, build_grammar, "build")
pub fn build_grammars(target: Option<String>) -> Result<()> {
let grammars = get_grammar_configs()?;
println!("Building {} grammars", grammars.len());
let results = run_parallel(grammars, move |grammar| {
build_grammar(grammar, target.as_deref())
});
let mut errors = Vec::new();
let mut already_built = 0;
let mut built = Vec::new();
for 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),
}
}
built.sort_unstable();
if already_built != 0 {
println!("{} grammars already built", already_built);
}
if !built.is_empty() {
println!("{} grammars built now", built.len());
println!("\t{:?}", built);
}
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);
}
}
Ok(())
}
// Returns the set of grammar configurations the user requests.
@@ -92,7 +191,7 @@ pub fn build_grammars() -> Result<()> {
// merged. The `grammar_selection` key of the config is then used to filter
// down all grammars into a subset of the user's choosing.
fn get_grammar_configs() -> Result<Vec<GrammarConfiguration>> {
let config: Configuration = crate::user_lang_config()
let config: Configuration = crate::config::user_lang_config()
.context("Could not parse languages.toml")?
.try_into()?;
@@ -113,37 +212,49 @@ fn get_grammar_configs() -> Result<Vec<GrammarConfiguration>> {
Ok(grammars)
}
fn run_parallel<F>(grammars: Vec<GrammarConfiguration>, job: F, action: &'static str) -> Result<()>
fn run_parallel<F, Res>(grammars: Vec<GrammarConfiguration>, job: F) -> Vec<Result<Res>>
where
F: Fn(GrammarConfiguration) -> Result<()> + std::marker::Send + 'static + Copy,
F: Fn(GrammarConfiguration) -> Result<Res> + Send + 'static + Clone,
Res: Send + 'static,
{
let pool = threadpool::Builder::new().build();
let (tx, rx) = channel();
for grammar in grammars {
let tx = tx.clone();
let job = job.clone();
pool.execute(move || {
tx.send(job(grammar)).unwrap();
// 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));
});
}
drop(tx);
// TODO: print all failures instead of the first one found.
rx.iter()
.find(|result| result.is_err())
.map(|err| err.with_context(|| format!("Failed to {action} some grammar(s)")))
.unwrap_or(Ok(()))
rx.iter().collect()
}
fn fetch_grammar(grammar: GrammarConfiguration) -> Result<()> {
enum FetchStatus {
GitUpToDate,
GitUpdated {
grammar_id: String,
revision: String,
},
NonGit {
grammar_id: String,
},
}
fn fetch_grammar(grammar: GrammarConfiguration) -> Result<FetchStatus> {
if let GrammarSource::Git {
remote, revision, ..
} = grammar.source
{
let grammar_dir = crate::runtime_dir()
.join("grammars/sources")
.join("grammars")
.join("sources")
.join(&grammar.grammar_id);
fs::create_dir_all(&grammar_dir).context(format!(
@@ -152,7 +263,7 @@ fn fetch_grammar(grammar: GrammarConfiguration) -> Result<()> {
))?;
// create the grammar dir contains a git directory
if !grammar_dir.join(".git").is_dir() {
if !grammar_dir.join(".git").exists() {
git(&grammar_dir, ["init"])?;
}
@@ -172,16 +283,18 @@ fn fetch_grammar(grammar: GrammarConfiguration) -> Result<()> {
)?;
git(&grammar_dir, ["checkout", &revision])?;
println!(
"Grammar '{}' checked out at '{}'.",
grammar.grammar_id, revision
);
Ok(FetchStatus::GitUpdated {
grammar_id: grammar.grammar_id,
revision,
})
} else {
println!("Grammar '{}' is already up to date.", grammar.grammar_id);
Ok(FetchStatus::GitUpToDate)
}
} else {
Ok(FetchStatus::NonGit {
grammar_id: grammar.grammar_id,
})
}
Ok(())
}
// Sets the remote for a repository to the given URL, creating the remote if
@@ -228,22 +341,32 @@ where
}
}
fn build_grammar(grammar: GrammarConfiguration) -> Result<()> {
enum BuildStatus {
AlreadyBuilt,
Built { grammar_id: String },
}
fn build_grammar(grammar: GrammarConfiguration, target: Option<&str>) -> Result<BuildStatus> {
let grammar_dir = if let GrammarSource::Local { path } = &grammar.source {
PathBuf::from(&path)
} else {
crate::runtime_dir()
.join("grammars/sources")
.join("grammars")
.join("sources")
.join(&grammar.grammar_id)
};
let grammar_dir_entries = grammar_dir.read_dir().with_context(|| {
format!("Failed to read directory {grammar_dir:?}. Did you use 'hx --grammar fetch'?")
format!(
"Failed to read directory {:?}. Did you use 'hx --grammar fetch'?",
grammar_dir
)
})?;
if grammar_dir_entries.count() == 0 {
return Err(anyhow!(
"Directory {grammar_dir:?} is empty. Did you use 'hx --grammar fetch'?"
"Directory {:?} is empty. Did you use 'hx --grammar fetch'?",
grammar_dir
));
};
@@ -256,10 +379,14 @@ fn build_grammar(grammar: GrammarConfiguration) -> Result<()> {
}
.join("src");
build_tree_sitter_library(&path, grammar)
build_tree_sitter_library(&path, grammar, target)
}
fn build_tree_sitter_library(src_path: &Path, grammar: GrammarConfiguration) -> Result<()> {
fn build_tree_sitter_library(
src_path: &Path,
grammar: GrammarConfiguration,
target: Option<&str>,
) -> Result<BuildStatus> {
let header_path = src_path;
let parser_path = src_path.join("parser.c");
let mut scanner_path = src_path.join("scanner.c");
@@ -282,29 +409,27 @@ fn build_tree_sitter_library(src_path: &Path, grammar: GrammarConfiguration) ->
.context("Failed to compare source and binary timestamps")?;
if !recompile {
println!("Grammar '{}' is already built.", grammar.grammar_id);
return Ok(());
return Ok(BuildStatus::AlreadyBuilt);
}
println!("Building grammar '{}'", grammar.grammar_id);
let mut config = cc::Build::new();
config
.cpp(true)
.opt_level(3)
.cargo_metadata(false)
.host(BUILD_TARGET)
.target(BUILD_TARGET);
.target(target.unwrap_or(BUILD_TARGET));
let compiler = config.get_compiler();
let mut command = Command::new(compiler.path());
command.current_dir(src_path);
for (key, value) in compiler.env() {
command.env(key, value);
}
command.args(compiler.args());
if cfg!(windows) {
if cfg!(all(windows, target_env = "msvc")) {
command
.args(&["/nologo", "/LD", "/I"])
.args(["/nologo", "/LD", "/I"])
.arg(header_path)
.arg("/Od")
.arg("/utf-8");
@@ -335,12 +460,17 @@ fn build_tree_sitter_library(src_path: &Path, grammar: GrammarConfiguration) ->
}
}
command.arg("-xc").arg(parser_path);
if cfg!(all(unix, not(target_os = "macos"))) {
if cfg!(all(
unix,
not(any(target_os = "macos", target_os = "illumos"))
)) {
command.arg("-Wl,-z,relro,-z,now");
}
}
let output = command.output().context("Failed to execute C compiler")?;
let output = command
.output()
.context("Failed to execute C/C++ compiler")?;
if !output.status.success() {
return Err(anyhow!(
"Parser compilation failed.\nStdout: {}\nStderr: {}",
@@ -349,7 +479,9 @@ fn build_tree_sitter_library(src_path: &Path, grammar: GrammarConfiguration) ->
));
}
Ok(())
Ok(BuildStatus::Built {
grammar_id: grammar.grammar_id,
})
}
fn needs_recompile(

View File

@@ -1,34 +1,58 @@
pub mod config;
pub mod grammar;
use etcetera::base_strategy::{choose_base_strategy, BaseStrategy};
use std::path::PathBuf;
pub static RUNTIME_DIR: once_cell::sync::Lazy<std::path::PathBuf> =
once_cell::sync::Lazy::new(runtime_dir);
pub const VERSION_AND_GIT_HASH: &str = env!("VERSION_AND_GIT_HASH");
pub fn runtime_dir() -> std::path::PathBuf {
pub static RUNTIME_DIR: once_cell::sync::Lazy<PathBuf> = once_cell::sync::Lazy::new(runtime_dir);
static CONFIG_FILE: once_cell::sync::OnceCell<PathBuf> = once_cell::sync::OnceCell::new();
pub fn initialize_config_file(specified_file: Option<PathBuf>) {
let config_file = specified_file.unwrap_or_else(|| {
let config_dir = config_dir();
if !config_dir.exists() {
std::fs::create_dir_all(&config_dir).ok();
}
config_dir.join("config.toml")
});
// We should only initialize this value once.
CONFIG_FILE.set(config_file).ok();
}
pub fn runtime_dir() -> PathBuf {
if let Ok(dir) = std::env::var("HELIX_RUNTIME") {
return dir.into();
}
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);
log::debug!("runtime dir: {}", path.to_string_lossy());
return path;
}
const RT_DIR: &str = "runtime";
let conf_dir = config_dir().join(RT_DIR);
if conf_dir.exists() {
return conf_dir;
}
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
return std::path::PathBuf::from(dir).parent().unwrap().join(RT_DIR);
}
// fallback to location of the executable being run
// canonicalize the path in case the executable is symlinked
std::env::current_exe()
.ok()
.and_then(|path| std::fs::canonicalize(path).ok())
.and_then(|path| path.parent().map(|path| path.to_path_buf().join(RT_DIR)))
.unwrap()
}
pub fn config_dir() -> std::path::PathBuf {
pub fn config_dir() -> PathBuf {
// TODO: allow env var override
let strategy = choose_base_strategy().expect("Unable to find the config directory!");
let mut path = strategy.config_dir();
@@ -36,7 +60,16 @@ pub fn config_dir() -> std::path::PathBuf {
path
}
pub fn cache_dir() -> std::path::PathBuf {
pub fn local_config_dirs() -> Vec<PathBuf> {
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!");
let mut path = strategy.cache_dir();
@@ -44,41 +77,51 @@ pub fn cache_dir() -> std::path::PathBuf {
path
}
pub fn config_file() -> std::path::PathBuf {
config_dir().join("config.toml")
pub fn config_file() -> PathBuf {
CONFIG_FILE
.get()
.map(|path| path.to_path_buf())
.unwrap_or_else(|| config_dir().join("config.toml"))
}
pub fn lang_config_file() -> std::path::PathBuf {
pub fn lang_config_file() -> PathBuf {
config_dir().join("languages.toml")
}
pub fn log_file() -> std::path::PathBuf {
pub fn log_file() -> PathBuf {
cache_dir().join("helix.log")
}
/// Default bultin-in languages.toml.
pub fn default_lang_config() -> toml::Value {
toml::from_slice(include_bytes!("../../languages.toml"))
.expect("Could not parse bultin-in languages.toml to valid toml")
}
pub fn find_local_config_dirs() -> Vec<PathBuf> {
let current_dir = std::env::current_dir().expect("unable to determine current directory");
let mut directories = Vec::new();
/// User configured languages.toml file, merged with the default config.
pub fn user_lang_config() -> Result<toml::Value, toml::de::Error> {
let def_lang_conf = default_lang_config();
let data = std::fs::read(crate::config_dir().join("languages.toml"));
let user_lang_conf = match data {
Ok(raw) => {
let value = toml::from_slice(&raw)?;
merge_toml_values(def_lang_conf, value)
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());
}
Err(_) => def_lang_conf,
};
Ok(user_lang_conf)
}
directories
}
// right overrides left
pub fn merge_toml_values(left: toml::Value, right: toml::Value) -> toml::Value {
/// Merge two TOML documents, merging values from `right` onto `left`
///
/// When an array exists in both `left` and `right`, `right`'s array is
/// used. When a table exists in both `left` and `right`, the merged table
/// consists of all keys in `left`'s table unioned with all keys in `right`
/// with the values of `right` being merged recursively onto values of
/// `left`.
///
/// `merge_toplevel_arrays` controls whether a top-level array in the TOML
/// document is merged instead of overridden. This is useful for TOML
/// documents that use a top-level array of values like the `languages.toml`,
/// where one usually wants to override or add to the array instead of
/// replacing it altogether.
pub fn merge_toml_values(left: toml::Value, right: toml::Value, merge_depth: usize) -> toml::Value {
use toml::Value;
fn get_name(v: &Value) -> Option<&str> {
@@ -87,32 +130,47 @@ pub fn merge_toml_values(left: toml::Value, right: toml::Value) -> toml::Value {
match (left, right) {
(Value::Array(mut left_items), Value::Array(right_items)) => {
left_items.reserve(right_items.len());
for rvalue in right_items {
let lvalue = get_name(&rvalue)
.and_then(|rname| left_items.iter().position(|v| get_name(v) == Some(rname)))
.map(|lpos| left_items.remove(lpos));
let mvalue = match lvalue {
Some(lvalue) => merge_toml_values(lvalue, rvalue),
None => rvalue,
};
left_items.push(mvalue);
// The top-level arrays should be merged but nested arrays should
// act as overrides. For the `languages.toml` config, this means
// that you can specify a sub-set of languages in an overriding
// `languages.toml` but that nested arrays like Language Server
// arguments are replaced instead of merged.
if merge_depth > 0 {
left_items.reserve(right_items.len());
for rvalue in right_items {
let lvalue = get_name(&rvalue)
.and_then(|rname| {
left_items.iter().position(|v| get_name(v) == Some(rname))
})
.map(|lpos| left_items.remove(lpos));
let mvalue = match lvalue {
Some(lvalue) => merge_toml_values(lvalue, rvalue, merge_depth - 1),
None => rvalue,
};
left_items.push(mvalue);
}
Value::Array(left_items)
} else {
Value::Array(right_items)
}
Value::Array(left_items)
}
(Value::Table(mut left_map), Value::Table(right_map)) => {
for (rname, rvalue) in right_map {
match left_map.remove(&rname) {
Some(lvalue) => {
let merged_value = merge_toml_values(lvalue, rvalue);
left_map.insert(rname, merged_value);
}
None => {
left_map.insert(rname, rvalue);
if merge_depth > 0 {
for (rname, rvalue) in right_map {
match left_map.remove(&rname) {
Some(lvalue) => {
let merged_value = merge_toml_values(lvalue, rvalue, merge_depth - 1);
left_map.insert(rname, merged_value);
}
None => {
left_map.insert(rname, rvalue);
}
}
}
Value::Table(left_map)
} else {
Value::Table(right_map)
}
Value::Table(left_map)
}
// Catch everything else we didn't handle, and use the right value
(_, value) => value,
@@ -122,23 +180,22 @@ pub fn merge_toml_values(left: toml::Value, right: toml::Value) -> toml::Value {
#[cfg(test)]
mod merge_toml_tests {
use super::merge_toml_values;
use toml::Value;
#[test]
fn language_tomls() {
use toml::Value;
const USER: &str = "
fn language_toml_map_merges() {
const USER: &str = r#"
[[language]]
name = \"nix\"
test = \"bbb\"
indent = { tab-width = 4, unit = \" \", test = \"aaa\" }
";
name = "nix"
test = "bbb"
indent = { tab-width = 4, unit = " ", test = "aaa" }
"#;
let base: Value = toml::from_slice(include_bytes!("../../languages.toml"))
.expect("Couldn't parse built-in languages config");
let user: Value = toml::from_str(USER).unwrap();
let merged = merge_toml_values(base, user);
let merged = merge_toml_values(base, user, 3);
let languages = merged.get("language").unwrap().as_array().unwrap();
let nix = languages
.iter()
@@ -158,4 +215,33 @@ mod merge_toml_tests {
// We didn't change comment-token so it should be same
assert_eq!(nix.get("comment-token").unwrap().as_str().unwrap(), "#");
}
#[test]
fn language_toml_nested_array_merges() {
const USER: &str = r#"
[[language]]
name = "typescript"
language-server = { command = "deno", args = ["lsp"] }
"#;
let base: Value = toml::from_slice(include_bytes!("../../languages.toml"))
.expect("Couldn't parse built-in languages config");
let user: Value = toml::from_str(USER).unwrap();
let merged = merge_toml_values(base, user, 3);
let languages = merged.get("language").unwrap().as_array().unwrap();
let ts = languages
.iter()
.find(|v| v.get("name").unwrap().as_str().unwrap() == "typescript")
.unwrap();
assert_eq!(
ts.get("language-server")
.unwrap()
.get("args")
.unwrap()
.as_array()
.unwrap(),
&vec![Value::String("lsp".into())]
)
}
}

9
helix-loader/src/main.rs Normal file
View File

@@ -0,0 +1,9 @@
use anyhow::Result;
use helix_loader::grammar::fetch_grammars;
// This binary is used in the Release CI as an optimization to cut down on
// compilation time. This is not meant to be run manually.
fn main() -> Result<()> {
fetch_grammars()
}

View File

@@ -13,16 +13,16 @@ homepage = "https://helix-editor.com"
[dependencies]
helix-core = { version = "0.6", path = "../helix-core" }
helix-loader = { version = "0.6", path = "../helix-loader" }
anyhow = "1.0"
futures-executor = "0.3"
futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
jsonrpc-core = { version = "18.0", default-features = false } # don't pull in all of futures
log = "0.4"
lsp-types = { version = "0.92", features = ["proposed"] }
lsp-types = { version = "0.93", features = ["proposed"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
tokio = { version = "1.17", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
tokio-stream = "0.1.8"
tokio = { version = "1.23", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
tokio-stream = "0.1.11"
which = "4.2"

View File

@@ -1,12 +1,15 @@
use crate::{
jsonrpc,
transport::{Payload, Transport},
Call, Error, OffsetEncoding, Result,
};
use helix_core::{find_root, ChangeSet, Rope};
use jsonrpc_core as jsonrpc;
use helix_loader::{self, VERSION_AND_GIT_HASH};
use lsp_types as lsp;
use serde::Deserialize;
use serde_json::Value;
use std::collections::HashMap;
use std::future::Future;
use std::process::Stdio;
use std::sync::{
@@ -31,22 +34,30 @@ pub struct Client {
pub(crate) capabilities: OnceCell<lsp::ServerCapabilities>,
offset_encoding: OffsetEncoding,
config: Option<Value>,
root_markers: Vec<String>,
root_path: std::path::PathBuf,
root_uri: Option<lsp::Url>,
workspace_folders: Vec<lsp::WorkspaceFolder>,
req_timeout: u64,
}
impl Client {
#[allow(clippy::type_complexity)]
#[allow(clippy::too_many_arguments)]
pub fn start(
cmd: &str,
args: &[String],
config: Option<Value>,
root_markers: Vec<String>,
server_environment: HashMap<String, String>,
root_markers: &[String],
id: usize,
req_timeout: u64,
doc_path: Option<&std::path::PathBuf>,
) -> Result<(Self, UnboundedReceiver<(usize, Call)>, Arc<Notify>)> {
// Resolve path to the binary
let cmd = which::which(cmd).map_err(|err| anyhow::anyhow!(err))?;
let process = Command::new(cmd)
.envs(server_environment)
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
@@ -65,6 +76,28 @@ 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())),
root_markers,
);
let root_uri = lsp::Url::from_file_path(root_path.clone()).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,
}]
})
.unwrap_or_default();
let client = Self {
id,
_process: process,
@@ -73,7 +106,11 @@ impl Client {
capabilities: OnceCell::new(),
offset_encoding: OffsetEncoding::Utf8,
config,
root_markers,
req_timeout,
root_path,
root_uri,
workspace_folders,
};
Ok((client, server_rx, initialize_notify))
@@ -117,6 +154,10 @@ impl Client {
self.config.as_ref()
}
pub fn workspace_folders(&self) -> &[lsp::WorkspaceFolder] {
&self.workspace_folders
}
/// Execute a RPC request on the language server.
async fn request<R: lsp::request::Request>(&self, params: R::Params) -> Result<R::Result>
where
@@ -139,6 +180,7 @@ impl Client {
{
let server_tx = self.server_tx.clone();
let id = self.next_request_id();
let timeout_secs = self.req_timeout;
async move {
use std::time::Duration;
@@ -162,8 +204,8 @@ impl Client {
})
.map_err(|e| Error::Other(e.into()))?;
// TODO: specifiable timeout, delay other calls until initialize success
timeout(Duration::from_secs(20), rx.recv())
// TODO: delay other calls until initialize success
timeout(Duration::from_secs(timeout_secs), rx.recv())
.await
.map_err(|_| Error::Timeout)? // return Timeout
.ok_or(Error::StreamClosed)?
@@ -234,20 +276,18 @@ impl Client {
// -------------------------------------------------------------------------------------------
pub(crate) async fn initialize(&self) -> Result<lsp::InitializeResult> {
// TODO: delay any requests that are triggered prior to initialize
let root = find_root(None, &self.root_markers)
.and_then(|root| lsp::Url::from_file_path(root).ok());
if self.config.is_some() {
log::info!("Using custom LSP config: {}", self.config.as_ref().unwrap());
if let Some(config) = &self.config {
log::info!("Using custom LSP config: {}", config);
}
#[allow(deprecated)]
let params = lsp::InitializeParams {
process_id: Some(std::process::id()),
// root_path is obsolete, use root_uri
root_path: None,
root_uri: root,
workspace_folders: Some(self.workspace_folders.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()),
root_uri: self.root_uri.clone(),
initialization_options: self.config.clone(),
capabilities: lsp::ClientCapabilities {
workspace: Some(lsp::WorkspaceClientCapabilities {
@@ -255,12 +295,29 @@ impl Client {
did_change_configuration: Some(lsp::DynamicRegistrationClientCapabilities {
dynamic_registration: Some(false),
}),
workspace_folders: Some(true),
apply_edit: Some(true),
symbol: Some(lsp::WorkspaceSymbolClientCapabilities {
dynamic_registration: Some(false),
..Default::default()
}),
execute_command: Some(lsp::DynamicRegistrationClientCapabilities {
dynamic_registration: Some(false),
}),
..Default::default()
}),
text_document: Some(lsp::TextDocumentClientCapabilities {
completion: Some(lsp::CompletionClientCapabilities {
completion_item: Some(lsp::CompletionItemCapability {
snippet_support: Some(false),
resolve_support: Some(lsp::CompletionItemCapabilityResolveSupport {
properties: vec![
String::from("documentation"),
String::from("detail"),
String::from("additionalTextEdits"),
],
}),
insert_replace_support: Some(true),
..Default::default()
}),
completion_item_kind: Some(lsp::CompletionItemKindCapability {
@@ -275,6 +332,16 @@ impl Client {
content_format: Some(vec![lsp::MarkupKind::Markdown]),
..Default::default()
}),
signature_help: Some(lsp::SignatureHelpClientCapabilities {
signature_information: Some(lsp::SignatureInformationSettings {
documentation_format: Some(vec![lsp::MarkupKind::Markdown]),
parameter_information: Some(lsp::ParameterInformationSettings {
label_offset_support: Some(true),
}),
active_parameter_support: Some(true),
}),
..Default::default()
}),
rename: Some(lsp::RenameClientCapabilities {
dynamic_registration: Some(false),
prepare_support: Some(false),
@@ -301,6 +368,9 @@ impl Client {
}),
..Default::default()
}),
publish_diagnostics: Some(lsp::PublishDiagnosticsClientCapabilities {
..Default::default()
}),
..Default::default()
}),
window: Some(lsp::WindowClientCapabilities {
@@ -310,8 +380,10 @@ impl Client {
..Default::default()
},
trace: None,
workspace_folders: None,
client_info: None,
client_info: Some(lsp::ClientInfo {
name: String::from("helix"),
version: Some(String::from(VERSION_AND_GIT_HASH)),
}),
locale: None, // TODO
};
@@ -480,16 +552,17 @@ impl Client {
new_text: &Rope,
changes: &ChangeSet,
) -> Option<impl Future<Output = Result<()>>> {
// figure out what kind of sync the server supports
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support document sync.
let sync_capabilities = match capabilities.text_document_sync {
Some(lsp::TextDocumentSyncCapability::Kind(kind))
| Some(lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions {
change: Some(kind),
..
})) => kind,
Some(
lsp::TextDocumentSyncCapability::Kind(kind)
| lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions {
change: Some(kind),
..
}),
) => kind,
// None | SyncOptions { changes: None }
_ => return None,
};
@@ -565,8 +638,12 @@ impl Client {
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
work_done_token: Option<lsp::ProgressToken>,
) -> impl Future<Output = Result<Value>> {
// ) -> Result<Vec<lsp::CompletionItem>> {
) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support completion.
capabilities.completion_provider.as_ref()?;
let params = lsp::CompletionParams {
text_document_position: lsp::TextDocumentPositionParams {
text_document,
@@ -581,15 +658,25 @@ impl Client {
// lsp::CompletionContext { trigger_kind: , trigger_character: Some(), }
};
self.call::<lsp::request::Completion>(params)
Some(self.call::<lsp::request::Completion>(params))
}
pub async fn resolve_completion_item(
pub fn resolve_completion_item(
&self,
completion_item: lsp::CompletionItem,
) -> Result<lsp::CompletionItem> {
self.request::<lsp::request::ResolveCompletionItem>(completion_item)
.await
) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support resolving completion items.
match capabilities.completion_provider {
Some(lsp::CompletionOptions {
resolve_provider: Some(true),
..
}) => (),
_ => return None,
}
Some(self.call::<lsp::request::ResolveCompletionItem>(completion_item))
}
pub fn text_document_signature_help(
@@ -597,7 +684,12 @@ impl Client {
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
work_done_token: Option<lsp::ProgressToken>,
) -> impl Future<Output = Result<Value>> {
) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support signature help.
capabilities.signature_help_provider.as_ref()?;
let params = lsp::SignatureHelpParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document,
@@ -608,7 +700,7 @@ impl Client {
// lsp::SignatureHelpContext
};
self.call::<lsp::request::SignatureHelpRequest>(params)
Some(self.call::<lsp::request::SignatureHelpRequest>(params))
}
pub fn text_document_hover(
@@ -616,7 +708,18 @@ impl Client {
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
work_done_token: Option<lsp::ProgressToken>,
) -> impl Future<Output = Result<Value>> {
) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support hover.
match capabilities.hover_provider {
Some(
lsp::HoverProviderCapability::Simple(true)
| lsp::HoverProviderCapability::Options(_),
) => (),
_ => return None,
}
let params = lsp::HoverParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document,
@@ -626,7 +729,7 @@ impl Client {
// lsp::SignatureHelpContext
};
self.call::<lsp::request::HoverRequest>(params)
Some(self.call::<lsp::request::HoverRequest>(params))
}
// formatting
@@ -639,13 +742,29 @@ impl Client {
) -> Option<impl Future<Output = Result<Vec<lsp::TextEdit>>>> {
let capabilities = self.capabilities.get().unwrap();
// check if we're able to format
// Return early if the server does not support formatting.
match capabilities.document_formatting_provider {
Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (),
// None | Some(false)
Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
_ => return None,
};
// TODO: return err::unavailable so we can fall back to tree sitter formatting
// merge FormattingOptions with 'config.format'
let config_format = self
.config
.as_ref()
.and_then(|cfg| cfg.get("format"))
.and_then(|fmt| HashMap::<String, lsp::FormattingProperty>::deserialize(fmt).ok());
let options = if let Some(mut properties) = config_format {
// passed in options take precedence over 'config.format'
properties.extend(options.properties);
lsp::FormattingOptions {
properties,
..options
}
} else {
options
};
let params = lsp::DocumentFormattingParams {
text_document,
@@ -662,22 +781,20 @@ impl Client {
})
}
pub async fn text_document_range_formatting(
pub fn text_document_range_formatting(
&self,
text_document: lsp::TextDocumentIdentifier,
range: lsp::Range,
options: lsp::FormattingOptions,
work_done_token: Option<lsp::ProgressToken>,
) -> anyhow::Result<Vec<lsp::TextEdit>> {
) -> Option<impl Future<Output = Result<Vec<lsp::TextEdit>>>> {
let capabilities = self.capabilities.get().unwrap();
// check if we're able to format
// Return early if the server does not support range formatting.
match capabilities.document_range_formatting_provider {
Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (),
// None | Some(false)
_ => return Ok(Vec::new()),
Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
_ => return None,
};
// TODO: return err::unavailable so we can fall back to tree sitter formatting
let params = lsp::DocumentRangeFormattingParams {
text_document,
@@ -686,11 +803,41 @@ impl Client {
work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
};
let response = self
.request::<lsp::request::RangeFormatting>(params)
.await?;
let request = self.call::<lsp::request::RangeFormatting>(params);
Ok(response.unwrap_or_default())
Some(async move {
let json = request.await?;
let response: Option<Vec<lsp::TextEdit>> = serde_json::from_value(json)?;
Ok(response.unwrap_or_default())
})
}
pub fn text_document_document_highlight(
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
work_done_token: Option<lsp::ProgressToken>,
) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support document highlight.
match capabilities.document_highlight_provider {
Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
_ => return None,
}
let params = lsp::DocumentHighlightParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document,
position,
},
work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
partial_result_params: lsp::PartialResultParams {
partial_result_token: None,
},
};
Some(self.call::<lsp::request::DocumentHighlightRequest>(params))
}
fn goto_request<
@@ -723,8 +870,20 @@ impl Client {
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
work_done_token: Option<lsp::ProgressToken>,
) -> impl Future<Output = Result<Value>> {
self.goto_request::<lsp::request::GotoDefinition>(text_document, position, work_done_token)
) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support goto-definition.
match capabilities.definition_provider {
Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
_ => return None,
}
Some(self.goto_request::<lsp::request::GotoDefinition>(
text_document,
position,
work_done_token,
))
}
pub fn goto_type_definition(
@@ -732,12 +891,23 @@ impl Client {
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
work_done_token: Option<lsp::ProgressToken>,
) -> impl Future<Output = Result<Value>> {
self.goto_request::<lsp::request::GotoTypeDefinition>(
) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support goto-type-definition.
match capabilities.type_definition_provider {
Some(
lsp::TypeDefinitionProviderCapability::Simple(true)
| lsp::TypeDefinitionProviderCapability::Options(_),
) => (),
_ => return None,
}
Some(self.goto_request::<lsp::request::GotoTypeDefinition>(
text_document,
position,
work_done_token,
)
))
}
pub fn goto_implementation(
@@ -745,12 +915,23 @@ impl Client {
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
work_done_token: Option<lsp::ProgressToken>,
) -> impl Future<Output = Result<Value>> {
self.goto_request::<lsp::request::GotoImplementation>(
) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support goto-definition.
match capabilities.implementation_provider {
Some(
lsp::ImplementationProviderCapability::Simple(true)
| lsp::ImplementationProviderCapability::Options(_),
) => (),
_ => return None,
}
Some(self.goto_request::<lsp::request::GotoImplementation>(
text_document,
position,
work_done_token,
)
))
}
pub fn goto_reference(
@@ -758,7 +939,15 @@ impl Client {
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
work_done_token: Option<lsp::ProgressToken>,
) -> impl Future<Output = Result<Value>> {
) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support goto-reference.
match capabilities.references_provider {
Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
_ => return None,
}
let params = lsp::ReferenceParams {
text_document_position: lsp::TextDocumentPositionParams {
text_document,
@@ -773,55 +962,92 @@ impl Client {
},
};
self.call::<lsp::request::References>(params)
Some(self.call::<lsp::request::References>(params))
}
pub fn document_symbols(
&self,
text_document: lsp::TextDocumentIdentifier,
) -> impl Future<Output = Result<Value>> {
) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support document symbols.
match capabilities.document_symbol_provider {
Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
_ => return None,
}
let params = lsp::DocumentSymbolParams {
text_document,
work_done_progress_params: lsp::WorkDoneProgressParams::default(),
partial_result_params: lsp::PartialResultParams::default(),
};
self.call::<lsp::request::DocumentSymbolRequest>(params)
Some(self.call::<lsp::request::DocumentSymbolRequest>(params))
}
// empty string to get all symbols
pub fn workspace_symbols(&self, query: String) -> impl Future<Output = Result<Value>> {
pub fn workspace_symbols(&self, query: String) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support workspace symbols.
match capabilities.workspace_symbol_provider {
Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
_ => return None,
}
let params = lsp::WorkspaceSymbolParams {
query,
work_done_progress_params: lsp::WorkDoneProgressParams::default(),
partial_result_params: lsp::PartialResultParams::default(),
};
self.call::<lsp::request::WorkspaceSymbol>(params)
Some(self.call::<lsp::request::WorkspaceSymbol>(params))
}
pub fn code_actions(
&self,
text_document: lsp::TextDocumentIdentifier,
range: lsp::Range,
) -> impl Future<Output = Result<Value>> {
context: lsp::CodeActionContext,
) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the server does not support code actions.
match capabilities.code_action_provider {
Some(
lsp::CodeActionProviderCapability::Simple(true)
| lsp::CodeActionProviderCapability::Options(_),
) => (),
_ => return None,
}
let params = lsp::CodeActionParams {
text_document,
range,
context: lsp::CodeActionContext::default(),
context,
work_done_progress_params: lsp::WorkDoneProgressParams::default(),
partial_result_params: lsp::PartialResultParams::default(),
};
self.call::<lsp::request::CodeActionRequest>(params)
Some(self.call::<lsp::request::CodeActionRequest>(params))
}
pub async fn rename_symbol(
pub fn rename_symbol(
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
new_name: String,
) -> anyhow::Result<lsp::WorkspaceEdit> {
) -> Option<impl Future<Output = Result<lsp::WorkspaceEdit>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the language server does not support renaming.
match capabilities.rename_provider {
Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (),
// None | Some(false)
_ => return None,
};
let params = lsp::RenameParams {
text_document_position: lsp::TextDocumentPositionParams {
text_document,
@@ -833,11 +1059,21 @@ impl Client {
},
};
let response = self.request::<lsp::request::Rename>(params).await?;
Ok(response.unwrap_or_default())
let request = self.call::<lsp::request::Rename>(params);
Some(async move {
let json = request.await?;
let response: Option<lsp::WorkspaceEdit> = serde_json::from_value(json)?;
Ok(response.unwrap_or_default())
})
}
pub fn command(&self, command: lsp::Command) -> impl Future<Output = Result<Value>> {
pub fn command(&self, command: lsp::Command) -> Option<impl Future<Output = Result<Value>>> {
let capabilities = self.capabilities.get().unwrap();
// Return early if the language server does not support executing commands.
capabilities.execute_command_provider.as_ref()?;
let params = lsp::ExecuteCommandParams {
command: command.command,
arguments: command.arguments.unwrap_or_default(),
@@ -846,6 +1082,6 @@ impl Client {
},
};
self.call::<lsp::request::ExecuteCommand>(params)
Some(self.call::<lsp::request::ExecuteCommand>(params))
}
}

Some files were not shown because too many files have changed in this diff Show More