on master help sign in
Merge remote-tracking branch 'origin/master' into debug
commite3153946311b189bd5e10e816acbdda508ded31c authorDmitry Sharshakov <d3dx12.xx@gmail.com> dateSat 28 Aug 2021, 14:59 (5 years ago) parent8df6739d6a9c2c
20 files changed+520−224
.gitmodules+4 book/src/keymap.md+146−146 book/src/themes.md+3 helix-core/src/lib.rs+83 helix-core/src/state.rs−24 helix-core/src/syntax.rs+8−9 helix-core/src/transaction.rs+7−7 helix-syntax/languages/tree-sitter-zig+1 helix-term/src/application.rs+14−7 helix-term/src/commands.rs+1−1 helix-term/src/keymap.rs+2 helix-term/src/ui/editor.rs+7−1 helix-term/src/ui/menu.rs+5−2 helix-term/src/ui/mod.rs+2−1 helix-term/src/ui/prompt.rs+8−12 helix-view/src/document.rs+5−12 helix-view/src/input.rs+2−2 languages.toml+12 runtime/queries/zig/highlights.scm+198 runtime/queries/zig/indents.toml+12
.gitmodules+4
@@ -102,3 +102,7 @@
102102 path = helix-syntax/languages/tree-sitter-protobuf
103103 url = https://github.com/yusdacra/tree-sitter-protobuf.git
104104 shallow = true
105+[submodule "helix-syntax/languages/tree-sitter-zig"]
106+ path = helix-syntax/languages/tree-sitter-zig
107+ url = https://github.com/maxxnino/tree-sitter-zig
108+ shallow = true
book/src/keymap.md+146−146
@@ -6,121 +6,121 @@
66
77> NOTE: `f`, `F`, `t` and `T` are not confined to the current line.
88
9−| Key | Description |
10−| ----- | ----------- |
11−| `h`, `Left` | Move left |
12−| `j`, `Down` | Move down |
13−| `k`, `Up` | Move up |
14−| `l`, `Right` | Move right |
15−| `w` | Move next word start |
16−| `b` | Move previous word start |
17−| `e` | Move next word end |
18−| `W` | Move next WORD start |
19−| `B` | Move previous WORD start |
20−| `E` | Move next WORD end |
21−| `t` | Find 'till next char |
22−| `f` | Find next char |
23−| `T` | Find 'till previous char |
24−| `F` | Find previous char |
25−| `Home` | Move to the start of the line |
26−| `End` | Move to the end of the line |
27−| `PageUp` | Move page up |
28−| `PageDown` | Move page down |
29−| `Ctrl-u` | Move half page up |
30−| `Ctrl-d` | Move half page down |
31−| `Ctrl-i` | Jump forward on the jumplist TODO: conflicts tab |
32−| `Ctrl-o` | Jump backward on the jumplist |
33−| `v` | Enter [select (extend) mode](#select--extend-mode) |
34−| `g` | Enter [goto mode](#goto-mode) |
35−| `m` | Enter [match mode](#match-mode) |
36−| `:` | Enter command mode |
37−| `z` | Enter [view mode](#view-mode) |
38−| `Ctrl-w` | Enter [window mode](#window-mode) (maybe will be remove for spc w w later) |
39−| `Space` | Enter [space mode](#space-mode) |
40−| `K` | Show documentation for the item under the cursor |
9+| Key | Description | Command |
10+| ----- | ----------- | ------- |
11+| `h`, `Left` | Move left | `move_char_left` |
12+| `j`, `Down` | Move down | `move_char_right` |
13+| `k`, `Up` | Move up | `move_line_up` |
14+| `l`, `Right` | Move right | `move_line_down` |
15+| `w` | Move next word start | `move_next_word_start` |
16+| `b` | Move previous word start | `move_prev_word_start` |
17+| `e` | Move next word end | `move_next_word_end` |
18+| `W` | Move next WORD start | `move_next_long_word_start` |
19+| `B` | Move previous WORD start | `move_prev_long_word_start` |
20+| `E` | Move next WORD end | `move_next_long_word_end` |
21+| `t` | Find 'till next char | `find_till_char` |
22+| `f` | Find next char | `find_next_char` |
23+| `T` | Find 'till previous char | `till_prev_char` |
24+| `F` | Find previous char | `find_prev_char` |
25+| `Home` | Move to the start of the line | `goto_line_start` |
26+| `End` | Move to the end of the line | `goto_line_end` |
27+| `PageUp` | Move page up | `page_up` |
28+| `PageDown` | Move page down | `page_down` |
29+| `Ctrl-u` | Move half page up | `half_page_up` |
30+| `Ctrl-d` | Move half page down | `half_page_down` |
31+| `Ctrl-i` | Jump forward on the jumplist TODO: conflicts tab | `jump_forward` |
32+| `Ctrl-o` | Jump backward on the jumplist | `jump_backward` |
33+| `v` | Enter [select (extend) mode](#select--extend-mode) | `select_mode` |
34+| `g` | Enter [goto mode](#goto-mode) | N/A |
35+| `m` | Enter [match mode](#match-mode) | N/A |
36+| `:` | Enter command mode | `command_mode` |
37+| `z` | Enter [view mode](#view-mode) | N/A |
38+| `Ctrl-w` | Enter [window mode](#window-mode) (maybe will be remove for spc w w later) | N/A |
39+| `Space` | Enter [space mode](#space-mode) | N/A |
40+| `K` | Show documentation for the item under the cursor | `hover` |
4141
4242### Changes
4343
44−| Key | Description |
45−| ----- | ----------- |
46−| `r` | Replace with a character |
47−| `R` | Replace with yanked text |
48−| `~` | Switch case of the selected text |
49−| `` ` `` | Set the selected text to lower case |
50−| `` Alt-` `` | Set the selected text to upper case |
51−| `i` | Insert before selection |
52−| `a` | Insert after selection (append) |
53−| `I` | Insert at the start of the line |
54−| `A` | Insert at the end of the line |
55−| `o` | Open new line below selection |
56−| `O` | Open new line above selection |
57−| `u` | Undo change |
58−| `U` | Redo change |
59−| `y` | Yank selection |
60−| `p` | Paste after selection |
61−| `P` | Paste before selection |
62−| `"` `<reg>` | Select a register to yank to or paste from |
63−| `>` | Indent selection |
64−| `<` | Unindent selection |
65−| `=` | Format selection |
66−| `d` | Delete selection |
67−| `c` | Change selection (delete and enter insert mode) |
44+| Key | Description | Command |
45+| ----- | ----------- | ------- |
46+| `r` | Replace with a character | `replace` |
47+| `R` | Replace with yanked text | `replace_with_yanked` |
48+| `~` | Switch case of the selected text | `switch_case` |
49+| `` ` `` | Set the selected text to lower case | `switch_to_lowercase` |
50+| `` Alt-` `` | Set the selected text to upper case | `switch_to_uppercase` |
51+| `i` | Insert before selection | `insert_mode` |
52+| `a` | Insert after selection (append) | `append_mode` |
53+| `I` | Insert at the start of the line | `prepend_to_line` |
54+| `A` | Insert at the end of the line | `append_to_line` |
55+| `o` | Open new line below selection | `open_below` |
56+| `O` | Open new line above selection | `open_above` |
57+| `u` | Undo change | `undo` |
58+| `U` | Redo change | `redo` |
59+| `y` | Yank selection | `yank` |
60+| `p` | Paste after selection | `paste_after` |
61+| `P` | Paste before selection | `paste_before` |
62+| `"` `<reg>` | Select a register to yank to or paste from | `select_register` |
63+| `>` | Indent selection | `indent` |
64+| `<` | Unindent selection | `unindent` |
65+| `=` | Format selection | `format_selections` |
66+| `d` | Delete selection | `delete_selection` |
67+| `c` | Change selection (delete and enter insert mode) | `change_selection` |
6868
6969### Selection manipulation
7070
71−| Key | Description |
72−| ----- | ----------- |
73−| `s` | Select all regex matches inside selections |
74−| `S` | Split selection into subselections on regex matches |
75−| `Alt-s` | Split selection on newlines |
76−| `;` | Collapse selection onto a single cursor |
77−| `Alt-;` | Flip selection cursor and anchor |
78−| `C` | Copy selection onto the next line |
79−| `Alt-C` | Copy selection onto the previous line |
80−| `(` | Rotate main selection forward |
81−| `)` | Rotate main selection backward |
82−| `Alt-(` | Rotate selection contents forward |
83−| `Alt-)` | Rotate selection contents backward |
84−| `%` | Select entire file |
85−| `x` | Select current line, if already selected, extend to next line |
86−| `X` | Extend selection to line bounds (line-wise selection) |
87−| | Expand selection to parent syntax node TODO: pick a key |
88−| `J` | Join lines inside selection |
89−| `K` | Keep selections matching the regex TODO: overlapped by hover help |
90−| `Space` | Keep only the primary selection TODO: overlapped by space mode |
91−| `Ctrl-c` | Comment/uncomment the selections |
71+| Key | Description | Command |
72+| ----- | ----------- | ------- |
73+| `s` | Select all regex matches inside selections | `select_regex` |
74+| `S` | Split selection into subselections on regex matches | `split_selection` |
75+| `Alt-s` | Split selection on newlines | `split_selection_on_newline` |
76+| `;` | Collapse selection onto a single cursor | `collapse_selection` |
77+| `Alt-;` | Flip selection cursor and anchor | `flip_selections` |
78+| `C` | Copy selection onto the next line | `copy_selection_on_next_line` |
79+| `Alt-C` | Copy selection onto the previous line | `copy_selection_on_prev_line` |
80+| `(` | Rotate main selection forward | `rotate_selections_backward` |
81+| `)` | Rotate main selection backward | `rotate_selections_forward` |
82+| `Alt-(` | Rotate selection contents forward | `rotate_selection_contents_backward` |
83+| `Alt-)` | Rotate selection contents backward | `rotate_selection_contents_forward` |
84+| `%` | Select entire file | `select_all` |
85+| `x` | Select current line, if already selected, extend to next line | `extend_line` |
86+| `X` | Extend selection to line bounds (line-wise selection) | `extend_to_line_bounds` |
87+| | Expand selection to parent syntax node TODO: pick a key | `expand_selection` |
88+| `J` | Join lines inside selection | `join_selections` |
89+| `K` | Keep selections matching the regex TODO: overlapped by hover help | `keep_selections` |
90+| `Space` | Keep only the primary selection TODO: overlapped by space mode | `keep_primary_selection` |
91+| `Ctrl-c` | Comment/uncomment the selections | `toggle_comments` |
9292
9393### Insert Mode
9494
95−| Key | Description |
96−| ----- | ----------- |
97−| `Escape` | Switch to normal mode |
98−| `Ctrl-x` | Autocomplete |
99−| `Ctrl-w` | Delete previous word |
95+| Key | Description | Command |
96+| ----- | ----------- | ------- |
97+| `Escape` | Switch to normal mode | `normal_mode` |
98+| `Ctrl-x` | Autocomplete | `completion` |
99+| `Ctrl-w` | Delete previous word | `delete_word_backward` |
100100
101101### Search
102102
103103> TODO: The search implementation isn't ideal yet -- we don't support searching
104104in reverse, or searching via smartcase.
105105
106−| Key | Description |
107−| ----- | ----------- |
108−| `/` | Search for regex pattern |
109−| `n` | Select next search match |
110−| `N` | Add next search match to selection |
111−| `*` | Use current selection as the search pattern |
106+| Key | Description | Command |
107+| ----- | ----------- | ------- |
108+| `/` | Search for regex pattern | `search` |
109+| `n` | Select next search match | `search_next` |
110+| `N` | Add next search match to selection | `extend_search_next` |
111+| `*` | Use current selection as the search pattern | `search_selection` |
112112
113113### Diagnostics
114114
115115> NOTE: `[` and `]` will likely contain more pair mappings in the style of
116116> [vim-unimpaired](https://github.com/tpope/vim-unimpaired)
117117
118−| Key | Description |
119−| ----- | ----------- |
120−| `[d` | Go to previous diagnostic |
121−| `]d` | Go to next diagnostic |
122−| `[D` | Go to first diagnostic in document |
123−| `]D` | Go to last diagnostic in document |
118+| Key | Description | Command |
119+| ----- | ----------- | ------- |
120+| `[d` | Go to previous diagnostic | `goto_prev_diag` |
121+| `]d` | Go to next diagnostic | `goto_next_diag` |
122+| `[D` | Go to first diagnostic in document | `goto_first_diag` |
123+| `]D` | Go to last diagnostic in document | `goto_last_diag` |
124124
125125## Select / extend mode
126126
@@ -135,14 +135,14 @@ commands to extend the existing selection instead of replacing it.
135135View mode is intended for scrolling and manipulating the view without changing
136136the selection.
137137
138−| Key | Description |
139−| ----- | ----------- |
140−| `z` , `c` | Vertically center the line |
141−| `t` | Align the line to the top of the screen |
142−| `b` | Align the line to the bottom of the screen |
143−| `m` | Align the line to the middle of the screen (horizontally) |
144−| `j` | Scroll the view downwards |
145−| `k` | Scroll the view upwards |
138+| Key | Description | Command |
139+| ----- | ----------- | ------- |
140+| `z` , `c` | Vertically center the line | `align_view_center` |
141+| `t` | Align the line to the top of the screen | `align_view_top` |
142+| `b` | Align the line to the bottom of the screen | `align_view_bottom` |
143+| `m` | Align the line to the middle of the screen (horizontally) | `align_view_middle` |
144+| `j` | Scroll the view downwards | `scroll_down` |
145+| `k` | Scroll the view upwards | `scroll_up` |
146146
147147## Goto mode
148148
@@ -150,21 +150,21 @@ Jumps to various locations.
150150
151151> NOTE: Some of these features are only available with the LSP present.
152152
153−| Key | Description |
154−| ----- | ----------- |
155−| `g` | Go to the start of the file |
156−| `e` | Go to the end of the file |
157−| `h` | Go to the start of the line |
158−| `l` | Go to the end of the line |
159−| `s` | Go to first non-whitespace character of the line |
160−| `t` | Go to the top of the screen |
161−| `m` | Go to the middle of the screen |
162−| `b` | Go to the bottom of the screen |
163−| `d` | Go to definition |
164−| `y` | Go to type definition |
165−| `r` | Go to references |
166−| `i` | Go to implementation |
167−| `a` | Go to the last accessed/alternate file |
153+| Key | Description | Command |
154+| ----- | ----------- | ------- |
155+| `g` | Go to the start of the file | `goto_file_start` |
156+| `e` | Go to the end of the file | `goto_last_line` |
157+| `h` | Go to the start of the line | `goto_line_start` |
158+| `l` | Go to the end of the line | `goto_line_end` |
159+| `s` | Go to first non-whitespace character of the line | `goto_first_nonwhitespace` |
160+| `t` | Go to the top of the screen | `goto_window_top` |
161+| `m` | Go to the middle of the screen | `goto_window_middle` |
162+| `b` | Go to the bottom of the screen | `goto_window_bottom` |
163+| `d` | Go to definition | `goto_definition` |
164+| `y` | Go to type definition | `goto_type_definition` |
165+| `r` | Go to references | `goto_reference` |
166+| `i` | Go to implementation | `goto_implementation` |
167+| `a` | Go to the last accessed/alternate file | `goto_last_accessed_file` |
168168
169169## Match mode
170170
@@ -172,14 +172,14 @@ Enter this mode using `m` from normal mode. See the relavant section
172172in [Usage](./usage.md) for an explanation about [surround](./usage.md#surround)
173173and [textobject](./usage.md#textobject) usage.
174174
175−| Key | Description |
176−| ----- | ----------- |
177−| `m` | Goto matching bracket |
178−| `s` `<char>` | Surround current selection with `<char>` |
179−| `r` `<from><to>` | Replace surround character `<from>` with `<to>` |
180−| `d` `<char>` | Delete surround character `<char>` |
181−| `a` `<object>` | Select around textobject |
182−| `i` `<object>` | Select inside textobject |
175+| Key | Description | Command |
176+| ----- | ----------- | ------- |
177+| `m` | Goto matching bracket | `match_brackets` |
178+| `s` `<char>` | Surround current selection with `<char>` | `surround_add` |
179+| `r` `<from><to>` | Replace surround character `<from>` with `<to>` | `surround_replace` |
180+| `d` `<char>` | Delete surround character `<char>` | `surround_delete` |
181+| `a` `<object>` | Select around textobject | `select_textobject_around` |
182+| `i` `<object>` | Select inside textobject | `select_textobject_inner` |
183183
184184## Object mode
185185
@@ -189,35 +189,35 @@ TODO: Mappings for selecting syntax nodes (a superset of `[`).
189189
190190This layer is similar to vim keybindings as kakoune does not support window.
191191
192−| Key | Description |
193−| ----- | ------------- |
194−| `w`, `Ctrl-w` | Switch to next window |
195−| `v`, `Ctrl-v` | Vertical right split |
196−| `h`, `Ctrl-h` | Horizontal bottom split |
197−| `q`, `Ctrl-q` | Close current window |
192+| Key | Description | Command |
193+| ----- | ------------- | ------- |
194+| `w`, `Ctrl-w` | Switch to next window | `rotate_view` |
195+| `v`, `Ctrl-v` | Vertical right split | `vsplit` |
196+| `h`, `Ctrl-h` | Horizontal bottom split | `hsplit` |
197+| `q`, `Ctrl-q` | Close current window | `wclose` |
198198
199199## Space mode
200200
201201This layer is a kludge of mappings I had under leader key in neovim.
202202
203−| Key | Description |
204−| ----- | ----------- |
205−| `f` | Open file picker |
206−| `b` | Open buffer picker |
207−| `s` | Open symbol picker (current document) |
208−| `a` | Apply code action |
209−| `'` | Open last fuzzy picker |
210−| `w` | Enter [window mode](#window-mode) |
211−| `space` | Keep primary selection TODO: it's here because space mode replaced it |
212−| `p` | Paste system clipboard after selections |
213−| `P` | Paste system clipboard before selections |
214−| `y` | Join and yank selections to clipboard |
215−| `Y` | Yank main selection to clipboard |
216−| `R` | Replace selections by clipboard contents |
203+| Key | Description | Command |
204+| ----- | ----------- | ------- |
205+| `f` | Open file picker | `file_picker` |
206+| `b` | Open buffer picker | `buffer_picker` |
207+| `s` | Open symbol picker (current document) | `symbol_picker` |
208+| `a` | Apply code action | `code_action` |
209+| `'` | Open last fuzzy picker | `last_picker` |
210+| `w` | Enter [window mode](#window-mode) | N/A |
211+| `space` | Keep primary selection TODO: it's here because space mode replaced it | `keep_primary_selection` |
212+| `p` | Paste system clipboard after selections | `paste_clipboard_after` |
213+| `P` | Paste system clipboard before selections | `paste_clipboard_before` |
214+| `y` | Join and yank selections to clipboard | `yank_joined_to_clipboard` |
215+| `Y` | Yank main selection to clipboard | `yank_main_selection_to_clipboard` |
216+| `R` | Replace selections by clipboard contents | `replace_selections_with_clipboard` |
217217
218218# Picker
219219
220−Keys to use within picker.
220+Keys to use within picker. Remapping currently not supported.
221221
222222| Key | Description |
223223| ----- | ------------- |
book/src/themes.md+3
@@ -91,6 +91,9 @@ Possible keys:
9191| `ui.help` | |
9292| `ui.text` | |
9393| `ui.text.focus` | |
94+| `ui.info` | |
95+| `ui.info.text` | |
96+| `ui.menu` | |
9497| `ui.menu.selected` | |
9598| `ui.selection` | For selections in the editing area |
9699| `ui.selection.primary` | |
helix-core/src/lib.rs+83
@@ -98,6 +98,89 @@ pub fn cache_dir() -> std::path::PathBuf {
9898 path
9999}
100100
101+// right overrides left
102+pub fn merge_toml_values(left: toml::Value, right: toml::Value) -> toml::Value {
103+ use toml::Value;
104+
105+ fn get_name(v: &Value) -> Option<&str> {
106+ v.get("name").and_then(Value::as_str)
107+ }
108+
109+ match (left, right) {
110+ (Value::Array(mut left_items), Value::Array(right_items)) => {
111+ left_items.reserve(right_items.len());
112+ for rvalue in right_items {
113+ let lvalue = get_name(&rvalue)
114+ .and_then(|rname| left_items.iter().position(|v| get_name(v) == Some(rname)))
115+ .map(|lpos| left_items.remove(lpos));
116+ let mvalue = match lvalue {
117+ Some(lvalue) => merge_toml_values(lvalue, rvalue),
118+ None => rvalue,
119+ };
120+ left_items.push(mvalue);
121+ }
122+ Value::Array(left_items)
123+ }
124+ (Value::Table(mut left_map), Value::Table(right_map)) => {
125+ for (rname, rvalue) in right_map {
126+ match left_map.remove(&rname) {
127+ Some(lvalue) => {
128+ let merged_value = merge_toml_values(lvalue, rvalue);
129+ left_map.insert(rname, merged_value);
130+ }
131+ None => {
132+ left_map.insert(rname, rvalue);
133+ }
134+ }
135+ }
136+ Value::Table(left_map)
137+ }
138+ // Catch everything else we didn't handle, and use the right value
139+ (_, value) => value,
140+ }
141+}
142+
143+#[cfg(test)]
144+mod merge_toml_tests {
145+ use super::merge_toml_values;
146+
147+ #[test]
148+ fn language_tomls() {
149+ use toml::Value;
150+
151+ const USER: &str = "
152+ [[language]]
153+ name = \"nix\"
154+ test = \"bbb\"
155+ indent = { tab-width = 4, unit = \" \", test = \"aaa\" }
156+ ";
157+
158+ let base: Value = toml::from_slice(include_bytes!("../../languages.toml"))
159+ .expect("Couldn't parse built-in langauges config");
160+ let user: Value = toml::from_str(USER).unwrap();
161+
162+ let merged = merge_toml_values(base, user);
163+ let languages = merged.get("language").unwrap().as_array().unwrap();
164+ let nix = languages
165+ .iter()
166+ .find(|v| v.get("name").unwrap().as_str().unwrap() == "nix")
167+ .unwrap();
168+ let nix_indent = nix.get("indent").unwrap();
169+
170+ // We changed tab-width and unit in indent so check them if they are the new values
171+ assert_eq!(
172+ nix_indent.get("tab-width").unwrap().as_integer().unwrap(),
173+ 4
174+ );
175+ assert_eq!(nix_indent.get("unit").unwrap().as_str().unwrap(), " ");
176+ // We added a new keys, so check them
177+ assert_eq!(nix.get("test").unwrap().as_str().unwrap(), "bbb");
178+ assert_eq!(nix_indent.get("test").unwrap().as_str().unwrap(), "aaa");
179+ // We didn't change comment-token so it should be same
180+ assert_eq!(nix.get("comment-token").unwrap().as_str().unwrap(), "#");
181+ }
182+}
183+
101184pub use etcetera::home_dir;
102185
103186use etcetera::base_strategy::{choose_base_strategy, BaseStrategy};
helix-core/src/state.rs−24
@@ -1,6 +1,5 @@
11use crate::{Rope, Selection};
22
3−/// A state represents the current editor state of a single buffer.
43#[derive(Debug, Clone)]
54pub struct State {
65 pub doc: Rope,
@@ -15,27 +14,4 @@ impl State {
1514 selection: Selection::point(0),
1615 }
1716 }
18−
19− // update/transact:
20− // update(desc) => transaction ? transaction.doc() for applied doc
21− // transaction.apply(doc)
22− // doc.transact(fn -> ... end)
23−
24− // replaceSelection (transaction that replaces selection)
25− // changeByRange
26− // changes
27− // slice
28− //
29− // getters:
30− // tabSize
31− // indentUnit
32− // languageDataAt()
33− //
34− // config:
35− // indentation
36− // tabSize
37− // lineUnit
38− // syntax
39− // foldable
40− // changeFilter/transactionFilter
4117}
helix-core/src/syntax.rs+8−9
@@ -1831,15 +1831,14 @@ mod test {
18311831
18321832 #[test]
18331833 fn test_input_edits() {
1834− use crate::State;
18351834 use tree_sitter::InputEdit;
18361835
1837− let state = State::new("hello world!\ntest 123".into());
1836+ let doc = Rope::from("hello world!\ntest 123");
18381837 let transaction = Transaction::change(
1839− &state.doc,
1838+ &doc,
18401839 vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
18411840 );
1842− let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
1841+ let edits = LanguageLayer::generate_edits(doc.slice(..), transaction.changes());
18431842 // transaction.apply(&mut state);
18441843
18451844 assert_eq!(
@@ -1865,13 +1864,13 @@ mod test {
18651864 );
18661865
18671866 // Testing with the official example from tree-sitter
1868− let mut state = State::new("fn test() {}".into());
1867+ let mut doc = Rope::from("fn test() {}");
18691868 let transaction =
1870− Transaction::change(&state.doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
1871− let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
1872− transaction.apply(&mut state.doc);
1869+ Transaction::change(&doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
1870+ let edits = LanguageLayer::generate_edits(doc.slice(..), transaction.changes());
1871+ transaction.apply(&mut doc);
18731872
1874− assert_eq!(state.doc, "fn test(a: u32) {}");
1873+ assert_eq!(doc, "fn test(a: u32) {}");
18751874 assert_eq!(
18761875 edits,
18771876 &[InputEdit {
helix-core/src/transaction.rs+7−7
@@ -125,7 +125,7 @@ impl ChangeSet {
125125 /// In other words, If `this` goes `docA` → `docB` and `other` represents `docB` → `docC`, the
126126 /// returned value will represent the change `docA` → `docC`.
127127 pub fn compose(self, other: Self) -> Self {
128− debug_assert!(self.len_after == other.len);
128+ assert!(self.len_after == other.len);
129129
130130 // composing fails in weird ways if one of the sets is empty
131131 // a: [] len: 0 len_after: 1 | b: [Insert(Tendril<UTF8>(inline: "\n")), Retain(1)] len 1
@@ -689,21 +689,21 @@ mod test {
689689
690690 #[test]
691691 fn transaction_change() {
692− let mut state = State::new("hello world!\ntest 123".into());
692+ let mut doc = Rope::from("hello world!\ntest 123");
693693 let transaction = Transaction::change(
694− &state.doc,
694+ &doc,
695695 // (1, 1, None) is a useless 0-width delete
696696 vec![(1, 1, None), (6, 11, Some("void".into())), (12, 17, None)].into_iter(),
697697 );
698− transaction.apply(&mut state.doc);
699− assert_eq!(state.doc, Rope::from_str("hello void! 123"));
698+ transaction.apply(&mut doc);
699+ assert_eq!(doc, Rope::from_str("hello void! 123"));
700700 }
701701
702702 #[test]
703703 fn changes_iter() {
704− let state = State::new("hello world!\ntest 123".into());
704+ let doc = Rope::from("hello world!\ntest 123");
705705 let changes = vec![(6, 11, Some("void".into())), (12, 17, None)];
706− let transaction = Transaction::change(&state.doc, changes.clone().into_iter());
706+ let transaction = Transaction::change(&doc, changes.clone().into_iter());
707707 assert_eq!(transaction.changes_iter().collect::<Vec<_>>(), changes);
708708 }
709709
helix-syntax/languages/tree-sitter-zignew file+1

Submodule changed.

helix-term/src/application.rs+14−7
@@ -1,4 +1,4 @@
1−use helix_core::{syntax, Range, Selection};
1+use helix_core::{merge_toml_values, syntax, Range, Selection};
22use helix_dap::Payload;
33use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
44use helix_view::{theme, Editor};
@@ -66,11 +66,16 @@ impl Application {
6666 let theme_loader =
6767 std::sync::Arc::new(theme::Loader::new(&conf_dir, &helix_core::runtime_dir()));
6868
69− // load $HOME/.config/helix/languages.toml, fallback to default config
70− let lang_conf = std::fs::read(conf_dir.join("languages.toml"));
71− let lang_conf = lang_conf
72− .as_deref()
73− .unwrap_or(include_bytes!("../../languages.toml"));
69+ // load default and user config, and merge both
70+ let def_lang_conf: toml::Value = toml::from_slice(include_bytes!("../../languages.toml"))
71+ .expect("Could not parse built-in languages.toml, something must be very wrong");
72+ let user_lang_conf: Option<toml::Value> = std::fs::read(conf_dir.join("languages.toml"))
73+ .ok()
74+ .map(|raw| toml::from_slice(&raw).expect("Could not parse user languages.toml"));
75+ let lang_conf = match user_lang_conf {
76+ Some(value) => merge_toml_values(def_lang_conf, value),
77+ None => def_lang_conf,
78+ };
7479
7580 let theme = if let Some(theme) = &config.theme {
7681 match theme_loader.load(theme) {
@@ -84,7 +89,9 @@ impl Application {
8489 theme_loader.default()
8590 };
8691
87− let syn_loader_conf = toml::from_slice(lang_conf).expect("Could not parse languages.toml");
92+ let syn_loader_conf: helix_core::syntax::Configuration = lang_conf
93+ .try_into()
94+ .expect("Could not parse merged (built-in + user) languages.toml");
8895 let syn_loader = std::sync::Arc::new(syntax::Loader::new(syn_loader_conf));
8996
9097 let mut editor = Editor::new(
helix-term/src/commands.rs+1−1
@@ -2369,7 +2369,7 @@ mod cmd {
23692369 },
23702370 TypableCommand {
23712371 name: "vsplit",
2372− alias: Some("vsp"),
2372+ alias: Some("vs"),
23732373 doc: "Open the file in a vertical split.",
23742374 fun: vsplit,
23752375 completer: Some(completers::filename),
helix-term/src/keymap.rs+2
@@ -541,6 +541,8 @@ impl Default for Keymaps {
541541 "home" => goto_line_start,
542542 "end" => goto_line_end,
543543 "esc" => exit_select_mode,
544+
545+ "v" => normal_mode,
544546 }));
545547 let insert = keymap!({ "Insert mode"
546548 "esc" => normal_mode,
helix-term/src/ui/editor.rs+7−1
@@ -508,7 +508,13 @@ impl EditorView {
508508 } else {
509509 let line = match config.line_number {
510510 LineNumber::Absolute => line + 1,
511− LineNumber::Relative => abs_diff(current_line, line),
511+ LineNumber::Relative => {
512+ if current_line == line {
513+ line + 1
514+ } else {
515+ abs_diff(current_line, line)
516+ }
517+ }
512518 };
513519 format!("{:>5}", line)
514520 };
helix-term/src/ui/menu.rs+5−2
@@ -259,8 +259,11 @@ impl<T: Item + 'static> Component for Menu<T> {
259259 // TODO: required size should re-trigger when we filter items so we can draw a smaller menu
260260
261261 fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
262− let style = cx.editor.theme.get("ui.text");
263− let selected = cx.editor.theme.get("ui.menu.selected");
262+ let theme = &cx.editor.theme;
263+ let style = theme
264+ .try_get("ui.menu")
265+ .unwrap_or_else(|| theme.get("ui.text"));
266+ let selected = theme.get("ui.menu.selected");
264267
265268 let scroll = self.scroll;
266269
helix-term/src/ui/mod.rs+2−1
@@ -228,7 +228,8 @@ pub mod completers {
228228
229229 let end = input.len()..;
230230
231− let mut files: Vec<_> = WalkBuilder::new(dir.clone())
231+ let mut files: Vec<_> = WalkBuilder::new(&dir)
232+ .hidden(false)
232233 .max_depth(Some(1))
233234 .build()
234235 .filter_map(|file| {
helix-term/src/ui/prompt.rs+8−12
@@ -400,18 +400,6 @@ impl Component for Prompt {
400400 })));
401401
402402 match event {
403− // char or shift char
404− KeyEvent {
405− code: KeyCode::Char(c),
406− modifiers: KeyModifiers::NONE,
407− }
408− | KeyEvent {
409− code: KeyCode::Char(c),
410− modifiers: KeyModifiers::SHIFT,
411− } => {
412− self.insert_char(c);
413− (self.callback_fn)(cx, &self.line, PromptEvent::Update);
414− }
415403 KeyEvent {
416404 code: KeyCode::Char('c'),
417405 modifiers: KeyModifiers::CONTROL,
@@ -539,6 +527,14 @@ impl Component for Prompt {
539527 code: KeyCode::Char('q'),
540528 modifiers: KeyModifiers::CONTROL,
541529 } => self.exit_selection(),
530+ // any char event that's not combined with control or mapped to any other combo
531+ KeyEvent {
532+ code: KeyCode::Char(c),
533+ modifiers,
534+ } if !modifiers.contains(KeyModifiers::CONTROL) => {
535+ self.insert_char(c);
536+ (self.callback_fn)(cx, &self.line, PromptEvent::Update);
537+ }
542538 _ => (),
543539 };
544540
helix-view/src/document.rs+5−12
@@ -102,7 +102,7 @@ pub struct Document {
102102 language_server: Option<Arc<helix_lsp::Client>>,
103103}
104104
105−use std::fmt;
105+use std::{fmt, mem};
106106impl fmt::Debug for Document {
107107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108108 f.debug_struct("Document")
@@ -301,20 +301,13 @@ pub async fn to_writer<'a, W: tokio::io::AsyncWriteExt + Unpin + ?Sized>(
301301 Ok(())
302302}
303303
304−/// Like std::mem::replace() except it allows the replacement value to be mapped from the
305−/// original value.
306−fn take_with<T, F>(mut_ref: &mut T, closure: F)
304+fn take_with<T, F>(mut_ref: &mut T, f: F)
307305where
306+ T: Default,
308307 F: FnOnce(T) -> T,
309308{
310− use std::{panic, ptr};
311−
312− unsafe {
313− let old_t = ptr::read(mut_ref);
314− let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| closure(old_t)))
315− .unwrap_or_else(|_| ::std::process::abort());
316− ptr::write(mut_ref, new_t);
317− }
309+ let t = mem::take(mut_ref);
310+ let _ = mem::replace(mut_ref, f(t));
318311}
319312
320313use helix_lsp::lsp;
helix-view/src/input.rs+2−2
@@ -15,10 +15,10 @@ pub struct KeyEvent {
1515}
1616
1717impl KeyEvent {
18− /// If a character was pressed (without modifiers), return it.
18+ /// If a character was pressed, return it.
1919 pub fn char(&self) -> Option<char> {
2020 match self.code {
21− KeyCode::Char(ch) if self.modifiers.is_empty() => Some(ch),
21+ KeyCode::Char(ch) => Some(ch),
2222 _ => None,
2323 }
2424 }
languages.toml+12
@@ -311,3 +311,15 @@ indent = { tab-width = 4, unit = " " }
311311# comment-token = "--"
312312#
313313# indent = { tab-width = 2, unit = " " }
314+
315+[[language]]
316+name = "zig"
317+scope = "source.zig"
318+injection-regex = "zig"
319+file-types = ["zig"]
320+roots = ["build.zig"]
321+auto-format = true
322+comment-token = "//"
323+
324+language-server = { command = "zls" }
325+indent = { tab-width = 4, unit = " " }
runtime/queries/zig/highlights.scmnew file+198
@@ -0,0 +1,198 @@
1+[
2+ (container_doc_comment)
3+ (doc_comment)
4+ (line_comment)
5+] @comment
6+
7+; field in top level decl, and in struct, union...
8+(ContainerField
9+ (IDENTIFIER) @property
10+ (SuffixExpr (IDENTIFIER) @type)?
11+)
12+
13+; error.OutOfMemory;
14+(SuffixExpr
15+ "error"
16+ "."
17+ (IDENTIFIER) @constant
18+)
19+
20+; var x: IDENTIFIER
21+type: (SuffixExpr (IDENTIFIER) @type)
22+
23+; IDENTIFIER{}
24+constructor: (SuffixExpr (IDENTIFIER) @constructor)
25+
26+; fields
27+(FieldInit (IDENTIFIER) @property)
28+
29+; foo.bar.baz.function() calls
30+(
31+ (SuffixOp
32+ (IDENTIFIER) @function
33+ )
34+ .
35+ (FnCallArguments)
36+)
37+
38+; function() calls
39+(
40+ (
41+ (IDENTIFIER) @function
42+ )
43+ .
44+ (FnCallArguments)
45+)
46+
47+; functionn decl
48+(FnProto
49+ (IDENTIFIER) @function
50+ (SuffixExpr (IDENTIFIER) @type)?
51+ ("!")? @function.macro
52+)
53+
54+; function parameters and types
55+(ParamDecl
56+ (IDENTIFIER) @variable.parameter
57+ ":"
58+ [
59+ (ParamType (SuffixExpr (IDENTIFIER) @type))
60+ (ParamType)
61+ ]
62+)
63+
64+; switch
65+(SwitchItem
66+ (SuffixExpr
67+ "."
68+ .
69+ (IDENTIFIER) @constant
70+ )
71+)
72+
73+(INTEGER) @number
74+
75+(FLOAT) @number
76+
77+[
78+ (STRINGLITERAL)
79+ (STRINGLITERALSINGLE)
80+] @string
81+
82+(CHAR_LITERAL) @string
83+
84+[
85+ "allowzero"
86+ "volatile"
87+ "anytype"
88+ "anyframe"
89+ (BuildinTypeExpr)
90+] @type.builtin
91+
92+(BreakLabel (IDENTIFIER) @label)
93+(BlockLabel (IDENTIFIER) @label)
94+
95+[
96+ "true"
97+ "false"
98+ "undefined"
99+ "unreachable"
100+ "null"
101+] @constant.builtin
102+
103+[
104+ "else"
105+ "if"
106+ "switch"
107+ "for"
108+ "while"
109+ "return"
110+ "break"
111+ "continue"
112+ "defer"
113+ "errdefer"
114+ "async"
115+ "nosuspend"
116+ "await"
117+ "suspend"
118+ "resume"
119+ "try"
120+ "catch"
121+] @keyword.control
122+
123+[
124+ "struct"
125+ "enum"
126+ "union"
127+ "error"
128+ "packed"
129+ "opaque"
130+ "test"
131+ "usingnamespace"
132+ "export"
133+ "extern"
134+ "const"
135+ "var"
136+ "comptime"
137+ "threadlocal"
138+] @keyword
139+
140+[
141+ "pub"
142+ "fn"
143+] @keyword.function
144+
145+; PrecProc
146+[
147+ "inline"
148+ "noinline"
149+ "asm"
150+ "callconv"
151+ "noalias"
152+] @attribute
153+
154+[
155+ (BUILTINIDENTIFIER)
156+ "linksection"
157+ "align"
158+] @function.builtin
159+
160+[
161+ (CompareOp)
162+ (BitwiseOp)
163+ (BitShiftOp)
164+ (AdditionOp)
165+ (MultiplyOp)
166+ (PrefixOp)
167+ "or"
168+ "and"
169+ "orelse"
170+ "*"
171+ "**"
172+ "->"
173+ "=>"
174+ ".?"
175+ ".*"
176+ "="
177+] @operator
178+
179+[
180+ ";"
181+ "."
182+ ","
183+ ":"
184+] @punctuation.delimiter
185+
186+[
187+ ".."
188+ "..."
189+ "["
190+ "]"
191+ "("
192+ ")"
193+ "{"
194+ "}"
195+ (Payload "|")
196+ (PtrPayload "|")
197+ (PtrIndexPayload "|")
198+] @punctuation
runtime/queries/zig/indents.tomlnew file+12
@@ -0,0 +1,12 @@
1+indent = [
2+ "block",
3+ "match_block",
4+ "arguments",
5+ "parameters"
6+]
7+
8+outdent = [
9+ "}",
10+ "]",
11+ ")"
12+]