on master help sign in
Merge remote-tracking branch 'origin/master' into debug
e315394Dmitry Sharshakov
.gitmodules+4
@@ -102,3 +102,7 @@
102 path = helix-syntax/languages/tree-sitter-protobuf
102 path = helix-syntax/languages/tree-sitter-protobuf
103 url = https://github.com/yusdacra/tree-sitter-protobuf.git
103 url = https://github.com/yusdacra/tree-sitter-protobuf.git
104 shallow = true
104 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 @@
6
6
7> NOTE: `f`, `F`, `t` and `T` are not confined to the current line.
7> NOTE: `f`, `F`, `t` and `T` are not confined to the current line.
8
8
9−| Key | Description |
9+| Key | Description | Command |
10−| ----- | ----------- |
10+| ----- | ----------- | ------- |
11−| `h`, `Left` | Move left |
11+| `h`, `Left` | Move left | `move_char_left` |
12−| `j`, `Down` | Move down |
12+| `j`, `Down` | Move down | `move_char_right` |
13−| `k`, `Up` | Move up |
13+| `k`, `Up` | Move up | `move_line_up` |
14−| `l`, `Right` | Move right |
14+| `l`, `Right` | Move right | `move_line_down` |
15−| `w` | Move next word start |
15+| `w` | Move next word start | `move_next_word_start` |
16−| `b` | Move previous word start |
16+| `b` | Move previous word start | `move_prev_word_start` |
17−| `e` | Move next word end |
17+| `e` | Move next word end | `move_next_word_end` |
18−| `W` | Move next WORD start |
18+| `W` | Move next WORD start | `move_next_long_word_start` |
19−| `B` | Move previous WORD start |
19+| `B` | Move previous WORD start | `move_prev_long_word_start` |
20−| `E` | Move next WORD end |
20+| `E` | Move next WORD end | `move_next_long_word_end` |
21−| `t` | Find 'till next char |
21+| `t` | Find 'till next char | `find_till_char` |
22−| `f` | Find next char |
22+| `f` | Find next char | `find_next_char` |
23−| `T` | Find 'till previous char |
23+| `T` | Find 'till previous char | `till_prev_char` |
24−| `F` | Find previous char |
24+| `F` | Find previous char | `find_prev_char` |
25−| `Home` | Move to the start of the line |
25+| `Home` | Move to the start of the line | `goto_line_start` |
26−| `End` | Move to the end of the line |
26+| `End` | Move to the end of the line | `goto_line_end` |
27−| `PageUp` | Move page up |
27+| `PageUp` | Move page up | `page_up` |
28−| `PageDown` | Move page down |
28+| `PageDown` | Move page down | `page_down` |
29−| `Ctrl-u` | Move half page up |
29+| `Ctrl-u` | Move half page up | `half_page_up` |
30−| `Ctrl-d` | Move half page down |
30+| `Ctrl-d` | Move half page down | `half_page_down` |
31−| `Ctrl-i` | Jump forward on the jumplist TODO: conflicts tab |
31+| `Ctrl-i` | Jump forward on the jumplist TODO: conflicts tab | `jump_forward` |
32−| `Ctrl-o` | Jump backward on the jumplist |
32+| `Ctrl-o` | Jump backward on the jumplist | `jump_backward` |
33−| `v` | Enter [select (extend) mode](#select--extend-mode) |
33+| `v` | Enter [select (extend) mode](#select--extend-mode) | `select_mode` |
34−| `g` | Enter [goto mode](#goto-mode) |
34+| `g` | Enter [goto mode](#goto-mode) | N/A |
35−| `m` | Enter [match mode](#match-mode) |
35+| `m` | Enter [match mode](#match-mode) | N/A |
36−| `:` | Enter command mode |
36+| `:` | Enter command mode | `command_mode` |
37−| `z` | Enter [view mode](#view-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) |
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) |
39+| `Space` | Enter [space mode](#space-mode) | N/A |
40−| `K` | Show documentation for the item under the cursor |
40+| `K` | Show documentation for the item under the cursor | `hover` |
41
41
42### Changes
42### Changes
43
43
44−| Key | Description |
44+| Key | Description | Command |
45−| ----- | ----------- |
45+| ----- | ----------- | ------- |
46−| `r` | Replace with a character |
46+| `r` | Replace with a character | `replace` |
47−| `R` | Replace with yanked text |
47+| `R` | Replace with yanked text | `replace_with_yanked` |
48−| `~` | Switch case of the selected text |
48+| `~` | Switch case of the selected text | `switch_case` |
49−| `` ` `` | Set the selected text to lower case |
49+| `` ` `` | Set the selected text to lower case | `switch_to_lowercase` |
50−| `` Alt-` `` | Set the selected text to upper case |
50+| `` Alt-` `` | Set the selected text to upper case | `switch_to_uppercase` |
51−| `i` | Insert before selection |
51+| `i` | Insert before selection | `insert_mode` |
52−| `a` | Insert after selection (append) |
52+| `a` | Insert after selection (append) | `append_mode` |
53−| `I` | Insert at the start of the line |
53+| `I` | Insert at the start of the line | `prepend_to_line` |
54−| `A` | Insert at the end of the line |
54+| `A` | Insert at the end of the line | `append_to_line` |
55−| `o` | Open new line below selection |
55+| `o` | Open new line below selection | `open_below` |
56−| `O` | Open new line above selection |
56+| `O` | Open new line above selection | `open_above` |
57−| `u` | Undo change |
57+| `u` | Undo change | `undo` |
58−| `U` | Redo change |
58+| `U` | Redo change | `redo` |
59−| `y` | Yank selection |
59+| `y` | Yank selection | `yank` |
60−| `p` | Paste after selection |
60+| `p` | Paste after selection | `paste_after` |
61−| `P` | Paste before selection |
61+| `P` | Paste before selection | `paste_before` |
62−| `"` `<reg>` | Select a register to yank to or paste from |
62+| `"` `<reg>` | Select a register to yank to or paste from | `select_register` |
63−| `>` | Indent selection |
63+| `>` | Indent selection | `indent` |
64−| `<` | Unindent selection |
64+| `<` | Unindent selection | `unindent` |
65−| `=` | Format selection |
65+| `=` | Format selection | `format_selections` |
66−| `d` | Delete selection |
66+| `d` | Delete selection | `delete_selection` |
67−| `c` | Change selection (delete and enter insert mode) |
67+| `c` | Change selection (delete and enter insert mode) | `change_selection` |
68
68
69### Selection manipulation
69### Selection manipulation
70
70
71−| Key | Description |
71+| Key | Description | Command |
72−| ----- | ----------- |
72+| ----- | ----------- | ------- |
73−| `s` | Select all regex matches inside selections |
73+| `s` | Select all regex matches inside selections | `select_regex` |
74−| `S` | Split selection into subselections on regex matches |
74+| `S` | Split selection into subselections on regex matches | `split_selection` |
75−| `Alt-s` | Split selection on newlines |
75+| `Alt-s` | Split selection on newlines | `split_selection_on_newline` |
76−| `;` | Collapse selection onto a single cursor |
76+| `;` | Collapse selection onto a single cursor | `collapse_selection` |
77−| `Alt-;` | Flip selection cursor and anchor |
77+| `Alt-;` | Flip selection cursor and anchor | `flip_selections` |
78−| `C` | Copy selection onto the next line |
78+| `C` | Copy selection onto the next line | `copy_selection_on_next_line` |
79−| `Alt-C` | Copy selection onto the previous line |
79+| `Alt-C` | Copy selection onto the previous line | `copy_selection_on_prev_line` |
80−| `(` | Rotate main selection forward |
80+| `(` | Rotate main selection forward | `rotate_selections_backward` |
81−| `)` | Rotate main selection backward |
81+| `)` | Rotate main selection backward | `rotate_selections_forward` |
82−| `Alt-(` | Rotate selection contents forward |
82+| `Alt-(` | Rotate selection contents forward | `rotate_selection_contents_backward` |
83−| `Alt-)` | Rotate selection contents backward |
83+| `Alt-)` | Rotate selection contents backward | `rotate_selection_contents_forward` |
84−| `%` | Select entire file |
84+| `%` | Select entire file | `select_all` |
85−| `x` | Select current line, if already selected, extend to next line |
85+| `x` | Select current line, if already selected, extend to next line | `extend_line` |
86−| `X` | Extend selection to line bounds (line-wise selection) |
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 |
87+| | Expand selection to parent syntax node TODO: pick a key | `expand_selection` |
88−| `J` | Join lines inside selection |
88+| `J` | Join lines inside selection | `join_selections` |
89−| `K` | Keep selections matching the regex TODO: overlapped by hover help |
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 |
90+| `Space` | Keep only the primary selection TODO: overlapped by space mode | `keep_primary_selection` |
91−| `Ctrl-c` | Comment/uncomment the selections |
91+| `Ctrl-c` | Comment/uncomment the selections | `toggle_comments` |
92
92
93### Insert Mode
93### Insert Mode
94
94
95−| Key | Description |
95+| Key | Description | Command |
96−| ----- | ----------- |
96+| ----- | ----------- | ------- |
97−| `Escape` | Switch to normal mode |
97+| `Escape` | Switch to normal mode | `normal_mode` |
98−| `Ctrl-x` | Autocomplete |
98+| `Ctrl-x` | Autocomplete | `completion` |
99−| `Ctrl-w` | Delete previous word |
99+| `Ctrl-w` | Delete previous word | `delete_word_backward` |
100
100
101### Search
101### Search
102
102
103> TODO: The search implementation isn't ideal yet -- we don't support searching
103> TODO: The search implementation isn't ideal yet -- we don't support searching
104in reverse, or searching via smartcase.
104in reverse, or searching via smartcase.
105
105
106−| Key | Description |
106+| Key | Description | Command |
107−| ----- | ----------- |
107+| ----- | ----------- | ------- |
108−| `/` | Search for regex pattern |
108+| `/` | Search for regex pattern | `search` |
109−| `n` | Select next search match |
109+| `n` | Select next search match | `search_next` |
110−| `N` | Add next search match to selection |
110+| `N` | Add next search match to selection | `extend_search_next` |
111−| `*` | Use current selection as the search pattern |
111+| `*` | Use current selection as the search pattern | `search_selection` |
112
112
113### Diagnostics
113### Diagnostics
114
114
115> NOTE: `[` and `]` will likely contain more pair mappings in the style of
115> NOTE: `[` and `]` will likely contain more pair mappings in the style of
116> [vim-unimpaired](https://github.com/tpope/vim-unimpaired)
116> [vim-unimpaired](https://github.com/tpope/vim-unimpaired)
117
117
118−| Key | Description |
118+| Key | Description | Command |
119−| ----- | ----------- |
119+| ----- | ----------- | ------- |
120−| `[d` | Go to previous diagnostic |
120+| `[d` | Go to previous diagnostic | `goto_prev_diag` |
121−| `]d` | Go to next diagnostic |
121+| `]d` | Go to next diagnostic | `goto_next_diag` |
122−| `[D` | Go to first diagnostic in document |
122+| `[D` | Go to first diagnostic in document | `goto_first_diag` |
123−| `]D` | Go to last diagnostic in document |
123+| `]D` | Go to last diagnostic in document | `goto_last_diag` |
124
124
125## Select / extend mode
125## Select / extend mode
126
126
@@ -135,14 +135,14 @@ commands to extend the existing selection instead of replacing it.
135View mode is intended for scrolling and manipulating the view without changing
135View mode is intended for scrolling and manipulating the view without changing
136the selection.
136the selection.
137
137
138−| Key | Description |
138+| Key | Description | Command |
139−| ----- | ----------- |
139+| ----- | ----------- | ------- |
140−| `z` , `c` | Vertically center the line |
140+| `z` , `c` | Vertically center the line | `align_view_center` |
141−| `t` | Align the line to the top of the screen |
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 |
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) |
143+| `m` | Align the line to the middle of the screen (horizontally) | `align_view_middle` |
144−| `j` | Scroll the view downwards |
144+| `j` | Scroll the view downwards | `scroll_down` |
145−| `k` | Scroll the view upwards |
145+| `k` | Scroll the view upwards | `scroll_up` |
146
146
147## Goto mode
147## Goto mode
148
148
@@ -150,21 +150,21 @@ Jumps to various locations.
150
150
151> NOTE: Some of these features are only available with the LSP present.
151> NOTE: Some of these features are only available with the LSP present.
152
152
153−| Key | Description |
153+| Key | Description | Command |
154−| ----- | ----------- |
154+| ----- | ----------- | ------- |
155−| `g` | Go to the start of the file |
155+| `g` | Go to the start of the file | `goto_file_start` |
156−| `e` | Go to the end of the file |
156+| `e` | Go to the end of the file | `goto_last_line` |
157−| `h` | Go to the start of the line |
157+| `h` | Go to the start of the line | `goto_line_start` |
158−| `l` | Go to the end of the line |
158+| `l` | Go to the end of the line | `goto_line_end` |
159−| `s` | Go to first non-whitespace character of the line |
159+| `s` | Go to first non-whitespace character of the line | `goto_first_nonwhitespace` |
160−| `t` | Go to the top of the screen |
160+| `t` | Go to the top of the screen | `goto_window_top` |
161−| `m` | Go to the middle of the screen |
161+| `m` | Go to the middle of the screen | `goto_window_middle` |
162−| `b` | Go to the bottom of the screen |
162+| `b` | Go to the bottom of the screen | `goto_window_bottom` |
163−| `d` | Go to definition |
163+| `d` | Go to definition | `goto_definition` |
164−| `y` | Go to type definition |
164+| `y` | Go to type definition | `goto_type_definition` |
165−| `r` | Go to references |
165+| `r` | Go to references | `goto_reference` |
166−| `i` | Go to implementation |
166+| `i` | Go to implementation | `goto_implementation` |
167−| `a` | Go to the last accessed/alternate file |
167+| `a` | Go to the last accessed/alternate file | `goto_last_accessed_file` |
168
168
169## Match mode
169## Match mode
170
170
@@ -172,14 +172,14 @@ Enter this mode using `m` from normal mode. See the relavant section
172in [Usage](./usage.md) for an explanation about [surround](./usage.md#surround)
172in [Usage](./usage.md) for an explanation about [surround](./usage.md#surround)
173and [textobject](./usage.md#textobject) usage.
173and [textobject](./usage.md#textobject) usage.
174
174
175−| Key | Description |
175+| Key | Description | Command |
176−| ----- | ----------- |
176+| ----- | ----------- | ------- |
177−| `m` | Goto matching bracket |
177+| `m` | Goto matching bracket | `match_brackets` |
178−| `s` `<char>` | Surround current selection with `<char>` |
178+| `s` `<char>` | Surround current selection with `<char>` | `surround_add` |
179−| `r` `<from><to>` | Replace surround character `<from>` with `<to>` |
179+| `r` `<from><to>` | Replace surround character `<from>` with `<to>` | `surround_replace` |
180−| `d` `<char>` | Delete surround character `<char>` |
180+| `d` `<char>` | Delete surround character `<char>` | `surround_delete` |
181−| `a` `<object>` | Select around textobject |
181+| `a` `<object>` | Select around textobject | `select_textobject_around` |
182−| `i` `<object>` | Select inside textobject |
182+| `i` `<object>` | Select inside textobject | `select_textobject_inner` |
183
183
184## Object mode
184## Object mode
185
185
@@ -189,35 +189,35 @@ TODO: Mappings for selecting syntax nodes (a superset of `[`).
189
189
190This layer is similar to vim keybindings as kakoune does not support window.
190This layer is similar to vim keybindings as kakoune does not support window.
191
191
192−| Key | Description |
192+| Key | Description | Command |
193−| ----- | ------------- |
193+| ----- | ------------- | ------- |
194−| `w`, `Ctrl-w` | Switch to next window |
194+| `w`, `Ctrl-w` | Switch to next window | `rotate_view` |
195−| `v`, `Ctrl-v` | Vertical right split |
195+| `v`, `Ctrl-v` | Vertical right split | `vsplit` |
196−| `h`, `Ctrl-h` | Horizontal bottom split |
196+| `h`, `Ctrl-h` | Horizontal bottom split | `hsplit` |
197−| `q`, `Ctrl-q` | Close current window |
197+| `q`, `Ctrl-q` | Close current window | `wclose` |
198
198
199## Space mode
199## Space mode
200
200
201This layer is a kludge of mappings I had under leader key in neovim.
201This layer is a kludge of mappings I had under leader key in neovim.
202
202
203−| Key | Description |
203+| Key | Description | Command |
204−| ----- | ----------- |
204+| ----- | ----------- | ------- |
205−| `f` | Open file picker |
205+| `f` | Open file picker | `file_picker` |
206−| `b` | Open buffer picker |
206+| `b` | Open buffer picker | `buffer_picker` |
207−| `s` | Open symbol picker (current document) |
207+| `s` | Open symbol picker (current document) | `symbol_picker` |
208−| `a` | Apply code action |
208+| `a` | Apply code action | `code_action` |
209−| `'` | Open last fuzzy picker |
209+| `'` | Open last fuzzy picker | `last_picker` |
210−| `w` | Enter [window mode](#window-mode) |
210+| `w` | Enter [window mode](#window-mode) | N/A |
211−| `space` | Keep primary selection TODO: it's here because space mode replaced it |
211+| `space` | Keep primary selection TODO: it's here because space mode replaced it | `keep_primary_selection` |
212−| `p` | Paste system clipboard after selections |
212+| `p` | Paste system clipboard after selections | `paste_clipboard_after` |
213−| `P` | Paste system clipboard before selections |
213+| `P` | Paste system clipboard before selections | `paste_clipboard_before` |
214−| `y` | Join and yank selections to clipboard |
214+| `y` | Join and yank selections to clipboard | `yank_joined_to_clipboard` |
215−| `Y` | Yank main selection to clipboard |
215+| `Y` | Yank main selection to clipboard | `yank_main_selection_to_clipboard` |
216−| `R` | Replace selections by clipboard contents |
216+| `R` | Replace selections by clipboard contents | `replace_selections_with_clipboard` |
217
217
218# Picker
218# Picker
219
219
220−Keys to use within picker.
220+Keys to use within picker. Remapping currently not supported.
221
221
222| Key | Description |
222| Key | Description |
223| ----- | ------------- |
223| ----- | ------------- |
book/src/themes.md+3
@@ -91,6 +91,9 @@ Possible keys:
91| `ui.help` | |
91| `ui.help` | |
92| `ui.text` | |
92| `ui.text` | |
93| `ui.text.focus` | |
93| `ui.text.focus` | |
94+| `ui.info` | |
95+| `ui.info.text` | |
96+| `ui.menu` | |
94| `ui.menu.selected` | |
97| `ui.menu.selected` | |
95| `ui.selection` | For selections in the editing area |
98| `ui.selection` | For selections in the editing area |
96| `ui.selection.primary` | |
99| `ui.selection.primary` | |
helix-core/src/lib.rs+83
@@ -98,6 +98,89 @@ pub fn cache_dir() -> std::path::PathBuf {
98 path
98 path
99}
99}
100
100
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+
101pub use etcetera::home_dir;
184pub use etcetera::home_dir;
102
185
103use etcetera::base_strategy::{choose_base_strategy, BaseStrategy};
186use etcetera::base_strategy::{choose_base_strategy, BaseStrategy};
helix-core/src/state.rs−24
@@ -1,6 +1,5 @@
1use crate::{Rope, Selection};
1use crate::{Rope, Selection};
2
2
3−/// A state represents the current editor state of a single buffer.
4#[derive(Debug, Clone)]
3#[derive(Debug, Clone)]
5pub struct State {
4pub struct State {
6 pub doc: Rope,
5 pub doc: Rope,
@@ -15,27 +14,4 @@ impl State {
15 selection: Selection::point(0),
14 selection: Selection::point(0),
16 }
15 }
17 }
16 }
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
41}
17}
helix-core/src/syntax.rs+8−9
@@ -1831,15 +1831,14 @@ mod test {
1831
1831
1832 #[test]
1832 #[test]
1833 fn test_input_edits() {
1833 fn test_input_edits() {
1834− use crate::State;
1835 use tree_sitter::InputEdit;
1834 use tree_sitter::InputEdit;
1836
1835
1837− let state = State::new("hello world!\ntest 123".into());
1836+ let doc = Rope::from("hello world!\ntest 123");
1838 let transaction = Transaction::change(
1837 let transaction = Transaction::change(
1839− &state.doc,
1838+ &doc,
1840 vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
1839 vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
1841 );
1840 );
1842− let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
1841+ let edits = LanguageLayer::generate_edits(doc.slice(..), transaction.changes());
1843 // transaction.apply(&mut state);
1842 // transaction.apply(&mut state);
1844
1843
1845 assert_eq!(
1844 assert_eq!(
@@ -1865,13 +1864,13 @@ mod test {
1865 );
1864 );
1866
1865
1867 // Testing with the official example from tree-sitter
1866 // 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() {}");
1869 let transaction =
1868 let transaction =
1870− Transaction::change(&state.doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
1869+ Transaction::change(&doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
1871− let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
1870+ let edits = LanguageLayer::generate_edits(doc.slice(..), transaction.changes());
1872− transaction.apply(&mut state.doc);
1871+ transaction.apply(&mut doc);
1873
1872
1874− assert_eq!(state.doc, "fn test(a: u32) {}");
1873+ assert_eq!(doc, "fn test(a: u32) {}");
1875 assert_eq!(
1874 assert_eq!(
1876 edits,
1875 edits,
1877 &[InputEdit {
1876 &[InputEdit {
helix-core/src/transaction.rs+7−7
@@ -125,7 +125,7 @@ impl ChangeSet {
125 /// In other words, If `this` goes `docA` → `docB` and `other` represents `docB` → `docC`, the
125 /// In other words, If `this` goes `docA` → `docB` and `other` represents `docB` → `docC`, the
126 /// returned value will represent the change `docA` → `docC`.
126 /// returned value will represent the change `docA` → `docC`.
127 pub fn compose(self, other: Self) -> Self {
127 pub fn compose(self, other: Self) -> Self {
128− debug_assert!(self.len_after == other.len);
128+ assert!(self.len_after == other.len);
129
129
130 // composing fails in weird ways if one of the sets is empty
130 // composing fails in weird ways if one of the sets is empty
131 // a: [] len: 0 len_after: 1 | b: [Insert(Tendril<UTF8>(inline: "\n")), Retain(1)] len 1
131 // a: [] len: 0 len_after: 1 | b: [Insert(Tendril<UTF8>(inline: "\n")), Retain(1)] len 1
@@ -689,21 +689,21 @@ mod test {
689
689
690 #[test]
690 #[test]
691 fn transaction_change() {
691 fn transaction_change() {
692− let mut state = State::new("hello world!\ntest 123".into());
692+ let mut doc = Rope::from("hello world!\ntest 123");
693 let transaction = Transaction::change(
693 let transaction = Transaction::change(
694− &state.doc,
694+ &doc,
695 // (1, 1, None) is a useless 0-width delete
695 // (1, 1, None) is a useless 0-width delete
696 vec![(1, 1, None), (6, 11, Some("void".into())), (12, 17, None)].into_iter(),
696 vec![(1, 1, None), (6, 11, Some("void".into())), (12, 17, None)].into_iter(),
697 );
697 );
698− transaction.apply(&mut state.doc);
698+ transaction.apply(&mut doc);
699− assert_eq!(state.doc, Rope::from_str("hello void! 123"));
699+ assert_eq!(doc, Rope::from_str("hello void! 123"));
700 }
700 }
701
701
702 #[test]
702 #[test]
703 fn changes_iter() {
703 fn changes_iter() {
704− let state = State::new("hello world!\ntest 123".into());
704+ let doc = Rope::from("hello world!\ntest 123");
705 let changes = vec![(6, 11, Some("void".into())), (12, 17, None)];
705 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());
707 assert_eq!(transaction.changes_iter().collect::<Vec<_>>(), changes);
707 assert_eq!(transaction.changes_iter().collect::<Vec<_>>(), changes);
708 }
708 }
709
709
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};
2use helix_dap::Payload;
2use helix_dap::Payload;
3use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
3use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
4use helix_view::{theme, Editor};
4use helix_view::{theme, Editor};
@@ -66,11 +66,16 @@ impl Application {
66 let theme_loader =
66 let theme_loader =
67 std::sync::Arc::new(theme::Loader::new(&conf_dir, &helix_core::runtime_dir()));
67 std::sync::Arc::new(theme::Loader::new(&conf_dir, &helix_core::runtime_dir()));
68
68
69− // load $HOME/.config/helix/languages.toml, fallback to default config
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");
70− let lang_conf = std::fs::read(conf_dir.join("languages.toml"));
72+ let user_lang_conf: Option<toml::Value> = std::fs::read(conf_dir.join("languages.toml"))
71− let lang_conf = lang_conf
73+ .ok()
72− .as_deref()
74+ .map(|raw| toml::from_slice(&raw).expect("Could not parse user languages.toml"));
73− .unwrap_or(include_bytes!("../../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+ };
74
79
75 let theme = if let Some(theme) = &config.theme {
80 let theme = if let Some(theme) = &config.theme {
76 match theme_loader.load(theme) {
81 match theme_loader.load(theme) {
@@ -84,7 +89,9 @@ impl Application {
84 theme_loader.default()
89 theme_loader.default()
85 };
90 };
86
91
92+ let syn_loader_conf: helix_core::syntax::Configuration = lang_conf
93+ .try_into()
87− let syn_loader_conf = toml::from_slice(lang_conf).expect("Could not parse languages.toml");
94+ .expect("Could not parse merged (built-in + user) languages.toml");
88 let syn_loader = std::sync::Arc::new(syntax::Loader::new(syn_loader_conf));
95 let syn_loader = std::sync::Arc::new(syntax::Loader::new(syn_loader_conf));
89
96
90 let mut editor = Editor::new(
97 let mut editor = Editor::new(
helix-term/src/commands.rs+1−1
@@ -2369,7 +2369,7 @@ mod cmd {
2369 },
2369 },
2370 TypableCommand {
2370 TypableCommand {
2371 name: "vsplit",
2371 name: "vsplit",
2372− alias: Some("vsp"),
2372+ alias: Some("vs"),
2373 doc: "Open the file in a vertical split.",
2373 doc: "Open the file in a vertical split.",
2374 fun: vsplit,
2374 fun: vsplit,
2375 completer: Some(completers::filename),
2375 completer: Some(completers::filename),
helix-term/src/keymap.rs+2
@@ -541,6 +541,8 @@ impl Default for Keymaps {
541 "home" => goto_line_start,
541 "home" => goto_line_start,
542 "end" => goto_line_end,
542 "end" => goto_line_end,
543 "esc" => exit_select_mode,
543 "esc" => exit_select_mode,
544+
545+ "v" => normal_mode,
544 }));
546 }));
545 let insert = keymap!({ "Insert mode"
547 let insert = keymap!({ "Insert mode"
546 "esc" => normal_mode,
548 "esc" => normal_mode,
helix-term/src/ui/editor.rs+7−1
@@ -508,7 +508,13 @@ impl EditorView {
508 } else {
508 } else {
509 let line = match config.line_number {
509 let line = match config.line_number {
510 LineNumber::Absolute => line + 1,
510 LineNumber::Absolute => line + 1,
511+ LineNumber::Relative => {
512+ if current_line == line {
513+ line + 1
514+ } else {
511− LineNumber::Relative => abs_diff(current_line, line),
515+ abs_diff(current_line, line)
516+ }
517+ }
512 };
518 };
513 format!("{:>5}", line)
519 format!("{:>5}", line)
514 };
520 };
helix-term/src/ui/menu.rs+5−2
@@ -259,8 +259,11 @@ impl<T: Item + 'static> Component for Menu<T> {
259 // TODO: required size should re-trigger when we filter items so we can draw a smaller menu
259 // TODO: required size should re-trigger when we filter items so we can draw a smaller menu
260
260
261 fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
261 fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
262+ let theme = &cx.editor.theme;
263+ let style = theme
264+ .try_get("ui.menu")
262− let style = cx.editor.theme.get("ui.text");
265+ .unwrap_or_else(|| theme.get("ui.text"));
263− let selected = cx.editor.theme.get("ui.menu.selected");
266+ let selected = theme.get("ui.menu.selected");
264
267
265 let scroll = self.scroll;
268 let scroll = self.scroll;
266
269
helix-term/src/ui/mod.rs+2−1
@@ -228,7 +228,8 @@ pub mod completers {
228
228
229 let end = input.len()..;
229 let end = input.len()..;
230
230
231− let mut files: Vec<_> = WalkBuilder::new(dir.clone())
231+ let mut files: Vec<_> = WalkBuilder::new(&dir)
232+ .hidden(false)
232 .max_depth(Some(1))
233 .max_depth(Some(1))
233 .build()
234 .build()
234 .filter_map(|file| {
235 .filter_map(|file| {
helix-term/src/ui/prompt.rs+8−12
@@ -400,18 +400,6 @@ impl Component for Prompt {
400 })));
400 })));
401
401
402 match event {
402 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− }
415 KeyEvent {
403 KeyEvent {
416 code: KeyCode::Char('c'),
404 code: KeyCode::Char('c'),
417 modifiers: KeyModifiers::CONTROL,
405 modifiers: KeyModifiers::CONTROL,
@@ -539,6 +527,14 @@ impl Component for Prompt {
539 code: KeyCode::Char('q'),
527 code: KeyCode::Char('q'),
540 modifiers: KeyModifiers::CONTROL,
528 modifiers: KeyModifiers::CONTROL,
541 } => self.exit_selection(),
529 } => 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+ }
542 _ => (),
538 _ => (),
543 };
539 };
544
540
helix-view/src/document.rs+5−12
@@ -102,7 +102,7 @@ pub struct Document {
102 language_server: Option<Arc<helix_lsp::Client>>,
102 language_server: Option<Arc<helix_lsp::Client>>,
103}
103}
104
104
105−use std::fmt;
105+use std::{fmt, mem};
106impl fmt::Debug for Document {
106impl fmt::Debug for Document {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 f.debug_struct("Document")
108 f.debug_struct("Document")
@@ -301,20 +301,13 @@ pub async fn to_writer<'a, W: tokio::io::AsyncWriteExt + Unpin + ?Sized>(
301 Ok(())
301 Ok(())
302}
302}
303
303
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)
307where
305where
306+ T: Default,
308 F: FnOnce(T) -> T,
307 F: FnOnce(T) -> T,
309{
308{
310− use std::{panic, ptr};
311−
312− unsafe {
313− let old_t = ptr::read(mut_ref);
309+ let t = mem::take(mut_ref);
314− let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| closure(old_t)))
310+ let _ = mem::replace(mut_ref, f(t));
315− .unwrap_or_else(|_| ::std::process::abort());
316− ptr::write(mut_ref, new_t);
317− }
318}
311}
319
312
320use helix_lsp::lsp;
313use helix_lsp::lsp;
helix-view/src/input.rs+2−2
@@ -15,10 +15,10 @@ pub struct KeyEvent {
15}
15}
16
16
17impl KeyEvent {
17impl KeyEvent {
18− /// If a character was pressed (without modifiers), return it.
18+ /// If a character was pressed, return it.
19 pub fn char(&self) -> Option<char> {
19 pub fn char(&self) -> Option<char> {
20 match self.code {
20 match self.code {
21− KeyCode::Char(ch) if self.modifiers.is_empty() => Some(ch),
21+ KeyCode::Char(ch) => Some(ch),
22 _ => None,
22 _ => None,
23 }
23 }
24 }
24 }
languages.toml+12
@@ -311,3 +311,15 @@ indent = { tab-width = 4, unit = " " }
311# comment-token = "--"
311# comment-token = "--"
312#
312#
313# indent = { tab-width = 2, unit = " " }
313# 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+]