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

pull/574/head
Dmitry Sharshakov 3 years ago
commit e315394631
No known key found for this signature in database
GPG Key ID: 471FD32E15FD8473

4
.gitmodules vendored

@ -102,3 +102,7 @@
path = helix-syntax/languages/tree-sitter-protobuf path = helix-syntax/languages/tree-sitter-protobuf
url = https://github.com/yusdacra/tree-sitter-protobuf.git url = https://github.com/yusdacra/tree-sitter-protobuf.git
shallow = true shallow = true
[submodule "helix-syntax/languages/tree-sitter-zig"]
path = helix-syntax/languages/tree-sitter-zig
url = https://github.com/maxxnino/tree-sitter-zig
shallow = true

@ -6,121 +6,121 @@
> NOTE: `f`, `F`, `t` and `T` are not confined to the current line. > NOTE: `f`, `F`, `t` and `T` are not confined to the current line.
| Key | Description | | Key | Description | Command |
| ----- | ----------- | | ----- | ----------- | ------- |
| `h`, `Left` | Move left | | `h`, `Left` | Move left | `move_char_left` |
| `j`, `Down` | Move down | | `j`, `Down` | Move down | `move_char_right` |
| `k`, `Up` | Move up | | `k`, `Up` | Move up | `move_line_up` |
| `l`, `Right` | Move right | | `l`, `Right` | Move right | `move_line_down` |
| `w` | Move next word start | | `w` | Move next word start | `move_next_word_start` |
| `b` | Move previous word start | | `b` | Move previous word start | `move_prev_word_start` |
| `e` | Move next word end | | `e` | Move next word end | `move_next_word_end` |
| `W` | Move next WORD start | | `W` | Move next WORD start | `move_next_long_word_start` |
| `B` | Move previous WORD start | | `B` | Move previous WORD start | `move_prev_long_word_start` |
| `E` | Move next WORD end | | `E` | Move next WORD end | `move_next_long_word_end` |
| `t` | Find 'till next char | | `t` | Find 'till next char | `find_till_char` |
| `f` | Find next char | | `f` | Find next char | `find_next_char` |
| `T` | Find 'till previous char | | `T` | Find 'till previous char | `till_prev_char` |
| `F` | Find previous char | | `F` | Find previous char | `find_prev_char` |
| `Home` | Move to the start of the line | | `Home` | Move to the start of the line | `goto_line_start` |
| `End` | Move to the end of the line | | `End` | Move to the end of the line | `goto_line_end` |
| `PageUp` | Move page up | | `PageUp` | Move page up | `page_up` |
| `PageDown` | Move page down | | `PageDown` | Move page down | `page_down` |
| `Ctrl-u` | Move half page up | | `Ctrl-u` | Move half page up | `half_page_up` |
| `Ctrl-d` | Move half page down | | `Ctrl-d` | Move half page down | `half_page_down` |
| `Ctrl-i` | Jump forward on the jumplist TODO: conflicts tab | | `Ctrl-i` | Jump forward on the jumplist TODO: conflicts tab | `jump_forward` |
| `Ctrl-o` | Jump backward on the jumplist | | `Ctrl-o` | Jump backward on the jumplist | `jump_backward` |
| `v` | Enter [select (extend) mode](#select--extend-mode) | | `v` | Enter [select (extend) mode](#select--extend-mode) | `select_mode` |
| `g` | Enter [goto mode](#goto-mode) | | `g` | Enter [goto mode](#goto-mode) | N/A |
| `m` | Enter [match mode](#match-mode) | | `m` | Enter [match mode](#match-mode) | N/A |
| `:` | Enter command mode | | `:` | Enter command mode | `command_mode` |
| `z` | Enter [view mode](#view-mode) | | `z` | Enter [view mode](#view-mode) | N/A |
| `Ctrl-w` | Enter [window mode](#window-mode) (maybe will be remove for spc w w later) | | `Ctrl-w` | Enter [window mode](#window-mode) (maybe will be remove for spc w w later) | N/A |
| `Space` | Enter [space mode](#space-mode) | | `Space` | Enter [space mode](#space-mode) | N/A |
| `K` | Show documentation for the item under the cursor | | `K` | Show documentation for the item under the cursor | `hover` |
### Changes ### Changes
| Key | Description | | Key | Description | Command |
| ----- | ----------- | | ----- | ----------- | ------- |
| `r` | Replace with a character | | `r` | Replace with a character | `replace` |
| `R` | Replace with yanked text | | `R` | Replace with yanked text | `replace_with_yanked` |
| `~` | Switch case of the selected text | | `~` | Switch case of the selected text | `switch_case` |
| `` ` `` | Set the selected text to lower case | | `` ` `` | Set the selected text to lower case | `switch_to_lowercase` |
| `` Alt-` `` | Set the selected text to upper case | | `` Alt-` `` | Set the selected text to upper case | `switch_to_uppercase` |
| `i` | Insert before selection | | `i` | Insert before selection | `insert_mode` |
| `a` | Insert after selection (append) | | `a` | Insert after selection (append) | `append_mode` |
| `I` | Insert at the start of the line | | `I` | Insert at the start of the line | `prepend_to_line` |
| `A` | Insert at the end of the line | | `A` | Insert at the end of the line | `append_to_line` |
| `o` | Open new line below selection | | `o` | Open new line below selection | `open_below` |
| `O` | Open new line above selection | | `O` | Open new line above selection | `open_above` |
| `u` | Undo change | | `u` | Undo change | `undo` |
| `U` | Redo change | | `U` | Redo change | `redo` |
| `y` | Yank selection | | `y` | Yank selection | `yank` |
| `p` | Paste after selection | | `p` | Paste after selection | `paste_after` |
| `P` | Paste before selection | | `P` | Paste before selection | `paste_before` |
| `"` `<reg>` | Select a register to yank to or paste from | | `"` `<reg>` | Select a register to yank to or paste from | `select_register` |
| `>` | Indent selection | | `>` | Indent selection | `indent` |
| `<` | Unindent selection | | `<` | Unindent selection | `unindent` |
| `=` | Format selection | | `=` | Format selection | `format_selections` |
| `d` | Delete selection | | `d` | Delete selection | `delete_selection` |
| `c` | Change selection (delete and enter insert mode) | | `c` | Change selection (delete and enter insert mode) | `change_selection` |
### Selection manipulation ### Selection manipulation
| Key | Description | | Key | Description | Command |
| ----- | ----------- | | ----- | ----------- | ------- |
| `s` | Select all regex matches inside selections | | `s` | Select all regex matches inside selections | `select_regex` |
| `S` | Split selection into subselections on regex matches | | `S` | Split selection into subselections on regex matches | `split_selection` |
| `Alt-s` | Split selection on newlines | | `Alt-s` | Split selection on newlines | `split_selection_on_newline` |
| `;` | Collapse selection onto a single cursor | | `;` | Collapse selection onto a single cursor | `collapse_selection` |
| `Alt-;` | Flip selection cursor and anchor | | `Alt-;` | Flip selection cursor and anchor | `flip_selections` |
| `C` | Copy selection onto the next line | | `C` | Copy selection onto the next line | `copy_selection_on_next_line` |
| `Alt-C` | Copy selection onto the previous line | | `Alt-C` | Copy selection onto the previous line | `copy_selection_on_prev_line` |
| `(` | Rotate main selection forward | | `(` | Rotate main selection forward | `rotate_selections_backward` |
| `)` | Rotate main selection backward | | `)` | Rotate main selection backward | `rotate_selections_forward` |
| `Alt-(` | Rotate selection contents forward | | `Alt-(` | Rotate selection contents forward | `rotate_selection_contents_backward` |
| `Alt-)` | Rotate selection contents backward | | `Alt-)` | Rotate selection contents backward | `rotate_selection_contents_forward` |
| `%` | Select entire file | | `%` | Select entire file | `select_all` |
| `x` | Select current line, if already selected, extend to next line | | `x` | Select current line, if already selected, extend to next line | `extend_line` |
| `X` | Extend selection to line bounds (line-wise selection) | | `X` | Extend selection to line bounds (line-wise selection) | `extend_to_line_bounds` |
| | Expand selection to parent syntax node TODO: pick a key | | | Expand selection to parent syntax node TODO: pick a key | `expand_selection` |
| `J` | Join lines inside selection | | `J` | Join lines inside selection | `join_selections` |
| `K` | Keep selections matching the regex TODO: overlapped by hover help | | `K` | Keep selections matching the regex TODO: overlapped by hover help | `keep_selections` |
| `Space` | Keep only the primary selection TODO: overlapped by space mode | | `Space` | Keep only the primary selection TODO: overlapped by space mode | `keep_primary_selection` |
| `Ctrl-c` | Comment/uncomment the selections | | `Ctrl-c` | Comment/uncomment the selections | `toggle_comments` |
### Insert Mode ### Insert Mode
| Key | Description | | Key | Description | Command |
| ----- | ----------- | | ----- | ----------- | ------- |
| `Escape` | Switch to normal mode | | `Escape` | Switch to normal mode | `normal_mode` |
| `Ctrl-x` | Autocomplete | | `Ctrl-x` | Autocomplete | `completion` |
| `Ctrl-w` | Delete previous word | | `Ctrl-w` | Delete previous word | `delete_word_backward` |
### Search ### Search
> TODO: The search implementation isn't ideal yet -- we don't support searching > TODO: The search implementation isn't ideal yet -- we don't support searching
in reverse, or searching via smartcase. in reverse, or searching via smartcase.
| Key | Description | | Key | Description | Command |
| ----- | ----------- | | ----- | ----------- | ------- |
| `/` | Search for regex pattern | | `/` | Search for regex pattern | `search` |
| `n` | Select next search match | | `n` | Select next search match | `search_next` |
| `N` | Add next search match to selection | | `N` | Add next search match to selection | `extend_search_next` |
| `*` | Use current selection as the search pattern | | `*` | Use current selection as the search pattern | `search_selection` |
### Diagnostics ### Diagnostics
> NOTE: `[` and `]` will likely contain more pair mappings in the style of > NOTE: `[` and `]` will likely contain more pair mappings in the style of
> [vim-unimpaired](https://github.com/tpope/vim-unimpaired) > [vim-unimpaired](https://github.com/tpope/vim-unimpaired)
| Key | Description | | Key | Description | Command |
| ----- | ----------- | | ----- | ----------- | ------- |
| `[d` | Go to previous diagnostic | | `[d` | Go to previous diagnostic | `goto_prev_diag` |
| `]d` | Go to next diagnostic | | `]d` | Go to next diagnostic | `goto_next_diag` |
| `[D` | Go to first diagnostic in document | | `[D` | Go to first diagnostic in document | `goto_first_diag` |
| `]D` | Go to last diagnostic in document | | `]D` | Go to last diagnostic in document | `goto_last_diag` |
## Select / extend mode ## Select / extend mode
@ -135,14 +135,14 @@ commands to extend the existing selection instead of replacing it.
View mode is intended for scrolling and manipulating the view without changing View mode is intended for scrolling and manipulating the view without changing
the selection. the selection.
| Key | Description | | Key | Description | Command |
| ----- | ----------- | | ----- | ----------- | ------- |
| `z` , `c` | Vertically center the line | | `z` , `c` | Vertically center the line | `align_view_center` |
| `t` | Align the line to the top of the screen | | `t` | Align the line to the top of the screen | `align_view_top` |
| `b` | Align the line to the bottom of the screen | | `b` | Align the line to the bottom of the screen | `align_view_bottom` |
| `m` | Align the line to the middle of the screen (horizontally) | | `m` | Align the line to the middle of the screen (horizontally) | `align_view_middle` |
| `j` | Scroll the view downwards | | `j` | Scroll the view downwards | `scroll_down` |
| `k` | Scroll the view upwards | | `k` | Scroll the view upwards | `scroll_up` |
## Goto mode ## Goto mode
@ -150,21 +150,21 @@ Jumps to various locations.
> NOTE: Some of these features are only available with the LSP present. > NOTE: Some of these features are only available with the LSP present.
| Key | Description | | Key | Description | Command |
| ----- | ----------- | | ----- | ----------- | ------- |
| `g` | Go to the start of the file | | `g` | Go to the start of the file | `goto_file_start` |
| `e` | Go to the end of the file | | `e` | Go to the end of the file | `goto_last_line` |
| `h` | Go to the start of the line | | `h` | Go to the start of the line | `goto_line_start` |
| `l` | Go to the end of the line | | `l` | Go to the end of the line | `goto_line_end` |
| `s` | Go to first non-whitespace character of the line | | `s` | Go to first non-whitespace character of the line | `goto_first_nonwhitespace` |
| `t` | Go to the top of the screen | | `t` | Go to the top of the screen | `goto_window_top` |
| `m` | Go to the middle of the screen | | `m` | Go to the middle of the screen | `goto_window_middle` |
| `b` | Go to the bottom of the screen | | `b` | Go to the bottom of the screen | `goto_window_bottom` |
| `d` | Go to definition | | `d` | Go to definition | `goto_definition` |
| `y` | Go to type definition | | `y` | Go to type definition | `goto_type_definition` |
| `r` | Go to references | | `r` | Go to references | `goto_reference` |
| `i` | Go to implementation | | `i` | Go to implementation | `goto_implementation` |
| `a` | Go to the last accessed/alternate file | | `a` | Go to the last accessed/alternate file | `goto_last_accessed_file` |
## Match mode ## Match mode
@ -172,14 +172,14 @@ Enter this mode using `m` from normal mode. See the relavant section
in [Usage](./usage.md) for an explanation about [surround](./usage.md#surround) in [Usage](./usage.md) for an explanation about [surround](./usage.md#surround)
and [textobject](./usage.md#textobject) usage. and [textobject](./usage.md#textobject) usage.
| Key | Description | | Key | Description | Command |
| ----- | ----------- | | ----- | ----------- | ------- |
| `m` | Goto matching bracket | | `m` | Goto matching bracket | `match_brackets` |
| `s` `<char>` | Surround current selection with `<char>` | | `s` `<char>` | Surround current selection with `<char>` | `surround_add` |
| `r` `<from><to>` | Replace surround character `<from>` with `<to>` | | `r` `<from><to>` | Replace surround character `<from>` with `<to>` | `surround_replace` |
| `d` `<char>` | Delete surround character `<char>` | | `d` `<char>` | Delete surround character `<char>` | `surround_delete` |
| `a` `<object>` | Select around textobject | | `a` `<object>` | Select around textobject | `select_textobject_around` |
| `i` `<object>` | Select inside textobject | | `i` `<object>` | Select inside textobject | `select_textobject_inner` |
## Object mode ## Object mode
@ -189,35 +189,35 @@ TODO: Mappings for selecting syntax nodes (a superset of `[`).
This layer is similar to vim keybindings as kakoune does not support window. This layer is similar to vim keybindings as kakoune does not support window.
| Key | Description | | Key | Description | Command |
| ----- | ------------- | | ----- | ------------- | ------- |
| `w`, `Ctrl-w` | Switch to next window | | `w`, `Ctrl-w` | Switch to next window | `rotate_view` |
| `v`, `Ctrl-v` | Vertical right split | | `v`, `Ctrl-v` | Vertical right split | `vsplit` |
| `h`, `Ctrl-h` | Horizontal bottom split | | `h`, `Ctrl-h` | Horizontal bottom split | `hsplit` |
| `q`, `Ctrl-q` | Close current window | | `q`, `Ctrl-q` | Close current window | `wclose` |
## Space mode ## Space mode
This layer is a kludge of mappings I had under leader key in neovim. This layer is a kludge of mappings I had under leader key in neovim.
| Key | Description | | Key | Description | Command |
| ----- | ----------- | | ----- | ----------- | ------- |
| `f` | Open file picker | | `f` | Open file picker | `file_picker` |
| `b` | Open buffer picker | | `b` | Open buffer picker | `buffer_picker` |
| `s` | Open symbol picker (current document) | | `s` | Open symbol picker (current document) | `symbol_picker` |
| `a` | Apply code action | | `a` | Apply code action | `code_action` |
| `'` | Open last fuzzy picker | | `'` | Open last fuzzy picker | `last_picker` |
| `w` | Enter [window mode](#window-mode) | | `w` | Enter [window mode](#window-mode) | N/A |
| `space` | Keep primary selection TODO: it's here because space mode replaced it | | `space` | Keep primary selection TODO: it's here because space mode replaced it | `keep_primary_selection` |
| `p` | Paste system clipboard after selections | | `p` | Paste system clipboard after selections | `paste_clipboard_after` |
| `P` | Paste system clipboard before selections | | `P` | Paste system clipboard before selections | `paste_clipboard_before` |
| `y` | Join and yank selections to clipboard | | `y` | Join and yank selections to clipboard | `yank_joined_to_clipboard` |
| `Y` | Yank main selection to clipboard | | `Y` | Yank main selection to clipboard | `yank_main_selection_to_clipboard` |
| `R` | Replace selections by clipboard contents | | `R` | Replace selections by clipboard contents | `replace_selections_with_clipboard` |
# Picker # Picker
Keys to use within picker. Keys to use within picker. Remapping currently not supported.
| Key | Description | | Key | Description |
| ----- | ------------- | | ----- | ------------- |

@ -91,6 +91,9 @@ Possible keys:
| `ui.help` | | | `ui.help` | |
| `ui.text` | | | `ui.text` | |
| `ui.text.focus` | | | `ui.text.focus` | |
| `ui.info` | |
| `ui.info.text` | |
| `ui.menu` | |
| `ui.menu.selected` | | | `ui.menu.selected` | |
| `ui.selection` | For selections in the editing area | | `ui.selection` | For selections in the editing area |
| `ui.selection.primary` | | | `ui.selection.primary` | |

@ -98,6 +98,89 @@ pub fn cache_dir() -> std::path::PathBuf {
path path
} }
// right overrides left
pub fn merge_toml_values(left: toml::Value, right: toml::Value) -> toml::Value {
use toml::Value;
fn get_name(v: &Value) -> Option<&str> {
v.get("name").and_then(Value::as_str)
}
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);
}
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);
}
}
}
Value::Table(left_map)
}
// Catch everything else we didn't handle, and use the right value
(_, value) => value,
}
}
#[cfg(test)]
mod merge_toml_tests {
use super::merge_toml_values;
#[test]
fn language_tomls() {
use toml::Value;
const USER: &str = "
[[language]]
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 langauges config");
let user: Value = toml::from_str(USER).unwrap();
let merged = merge_toml_values(base, user);
let languages = merged.get("language").unwrap().as_array().unwrap();
let nix = languages
.iter()
.find(|v| v.get("name").unwrap().as_str().unwrap() == "nix")
.unwrap();
let nix_indent = nix.get("indent").unwrap();
// We changed tab-width and unit in indent so check them if they are the new values
assert_eq!(
nix_indent.get("tab-width").unwrap().as_integer().unwrap(),
4
);
assert_eq!(nix_indent.get("unit").unwrap().as_str().unwrap(), " ");
// We added a new keys, so check them
assert_eq!(nix.get("test").unwrap().as_str().unwrap(), "bbb");
assert_eq!(nix_indent.get("test").unwrap().as_str().unwrap(), "aaa");
// We didn't change comment-token so it should be same
assert_eq!(nix.get("comment-token").unwrap().as_str().unwrap(), "#");
}
}
pub use etcetera::home_dir; pub use etcetera::home_dir;
use etcetera::base_strategy::{choose_base_strategy, BaseStrategy}; use etcetera::base_strategy::{choose_base_strategy, BaseStrategy};

@ -1,6 +1,5 @@
use crate::{Rope, Selection}; use crate::{Rope, Selection};
/// A state represents the current editor state of a single buffer.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct State { pub struct State {
pub doc: Rope, pub doc: Rope,
@ -15,27 +14,4 @@ impl State {
selection: Selection::point(0), selection: Selection::point(0),
} }
} }
// update/transact:
// update(desc) => transaction ? transaction.doc() for applied doc
// transaction.apply(doc)
// doc.transact(fn -> ... end)
// replaceSelection (transaction that replaces selection)
// changeByRange
// changes
// slice
//
// getters:
// tabSize
// indentUnit
// languageDataAt()
//
// config:
// indentation
// tabSize
// lineUnit
// syntax
// foldable
// changeFilter/transactionFilter
} }

@ -1831,15 +1831,14 @@ mod test {
#[test] #[test]
fn test_input_edits() { fn test_input_edits() {
use crate::State;
use tree_sitter::InputEdit; use tree_sitter::InputEdit;
let state = State::new("hello world!\ntest 123".into()); let doc = Rope::from("hello world!\ntest 123");
let transaction = Transaction::change( let transaction = Transaction::change(
&state.doc, &doc,
vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(), vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
); );
let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes()); let edits = LanguageLayer::generate_edits(doc.slice(..), transaction.changes());
// transaction.apply(&mut state); // transaction.apply(&mut state);
assert_eq!( assert_eq!(
@ -1865,13 +1864,13 @@ mod test {
); );
// Testing with the official example from tree-sitter // Testing with the official example from tree-sitter
let mut state = State::new("fn test() {}".into()); let mut doc = Rope::from("fn test() {}");
let transaction = let transaction =
Transaction::change(&state.doc, vec![(8, 8, Some("a: u32".into()))].into_iter()); Transaction::change(&doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes()); let edits = LanguageLayer::generate_edits(doc.slice(..), transaction.changes());
transaction.apply(&mut state.doc); transaction.apply(&mut doc);
assert_eq!(state.doc, "fn test(a: u32) {}"); assert_eq!(doc, "fn test(a: u32) {}");
assert_eq!( assert_eq!(
edits, edits,
&[InputEdit { &[InputEdit {

@ -125,7 +125,7 @@ impl ChangeSet {
/// In other words, If `this` goes `docA` → `docB` and `other` represents `docB` → `docC`, the /// In other words, If `this` goes `docA` → `docB` and `other` represents `docB` → `docC`, the
/// returned value will represent the change `docA` → `docC`. /// returned value will represent the change `docA` → `docC`.
pub fn compose(self, other: Self) -> Self { pub fn compose(self, other: Self) -> Self {
debug_assert!(self.len_after == other.len); assert!(self.len_after == other.len);
// composing fails in weird ways if one of the sets is empty // composing fails in weird ways if one of the sets is empty
// a: [] len: 0 len_after: 1 | b: [Insert(Tendril<UTF8>(inline: "\n")), Retain(1)] len 1 // a: [] len: 0 len_after: 1 | b: [Insert(Tendril<UTF8>(inline: "\n")), Retain(1)] len 1
@ -689,21 +689,21 @@ mod test {
#[test] #[test]
fn transaction_change() { fn transaction_change() {
let mut state = State::new("hello world!\ntest 123".into()); let mut doc = Rope::from("hello world!\ntest 123");
let transaction = Transaction::change( let transaction = Transaction::change(
&state.doc, &doc,
// (1, 1, None) is a useless 0-width delete // (1, 1, None) is a useless 0-width delete
vec![(1, 1, None), (6, 11, Some("void".into())), (12, 17, None)].into_iter(), vec![(1, 1, None), (6, 11, Some("void".into())), (12, 17, None)].into_iter(),
); );
transaction.apply(&mut state.doc); transaction.apply(&mut doc);
assert_eq!(state.doc, Rope::from_str("hello void! 123")); assert_eq!(doc, Rope::from_str("hello void! 123"));
} }
#[test] #[test]
fn changes_iter() { fn changes_iter() {
let state = State::new("hello world!\ntest 123".into()); let doc = Rope::from("hello world!\ntest 123");
let changes = vec![(6, 11, Some("void".into())), (12, 17, None)]; let changes = vec![(6, 11, Some("void".into())), (12, 17, None)];
let transaction = Transaction::change(&state.doc, changes.clone().into_iter()); let transaction = Transaction::change(&doc, changes.clone().into_iter());
assert_eq!(transaction.changes_iter().collect::<Vec<_>>(), changes); assert_eq!(transaction.changes_iter().collect::<Vec<_>>(), changes);
} }

@ -0,0 +1 @@
Subproject commit 049162bea8a44e1a4acd01b06e1c8672d9231a86

@ -1,4 +1,4 @@
use helix_core::{syntax, Range, Selection}; use helix_core::{merge_toml_values, syntax, Range, Selection};
use helix_dap::Payload; use helix_dap::Payload;
use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap}; use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
use helix_view::{theme, Editor}; use helix_view::{theme, Editor};
@ -66,11 +66,16 @@ impl Application {
let theme_loader = let theme_loader =
std::sync::Arc::new(theme::Loader::new(&conf_dir, &helix_core::runtime_dir())); std::sync::Arc::new(theme::Loader::new(&conf_dir, &helix_core::runtime_dir()));
// load $HOME/.config/helix/languages.toml, fallback to default config // load default and user config, and merge both
let lang_conf = std::fs::read(conf_dir.join("languages.toml")); let def_lang_conf: toml::Value = toml::from_slice(include_bytes!("../../languages.toml"))
let lang_conf = lang_conf .expect("Could not parse built-in languages.toml, something must be very wrong");
.as_deref() let user_lang_conf: Option<toml::Value> = std::fs::read(conf_dir.join("languages.toml"))
.unwrap_or(include_bytes!("../../languages.toml")); .ok()
.map(|raw| toml::from_slice(&raw).expect("Could not parse user languages.toml"));
let lang_conf = match user_lang_conf {
Some(value) => merge_toml_values(def_lang_conf, value),
None => def_lang_conf,
};
let theme = if let Some(theme) = &config.theme { let theme = if let Some(theme) = &config.theme {
match theme_loader.load(theme) { match theme_loader.load(theme) {
@ -84,7 +89,9 @@ impl Application {
theme_loader.default() theme_loader.default()
}; };
let syn_loader_conf = toml::from_slice(lang_conf).expect("Could not parse languages.toml"); let syn_loader_conf: helix_core::syntax::Configuration = lang_conf
.try_into()
.expect("Could not parse merged (built-in + user) languages.toml");
let syn_loader = std::sync::Arc::new(syntax::Loader::new(syn_loader_conf)); let syn_loader = std::sync::Arc::new(syntax::Loader::new(syn_loader_conf));
let mut editor = Editor::new( let mut editor = Editor::new(

@ -2369,7 +2369,7 @@ mod cmd {
}, },
TypableCommand { TypableCommand {
name: "vsplit", name: "vsplit",
alias: Some("vsp"), alias: Some("vs"),
doc: "Open the file in a vertical split.", doc: "Open the file in a vertical split.",
fun: vsplit, fun: vsplit,
completer: Some(completers::filename), completer: Some(completers::filename),

@ -541,6 +541,8 @@ impl Default for Keymaps {
"home" => goto_line_start, "home" => goto_line_start,
"end" => goto_line_end, "end" => goto_line_end,
"esc" => exit_select_mode, "esc" => exit_select_mode,
"v" => normal_mode,
})); }));
let insert = keymap!({ "Insert mode" let insert = keymap!({ "Insert mode"
"esc" => normal_mode, "esc" => normal_mode,

@ -508,7 +508,13 @@ impl EditorView {
} else { } else {
let line = match config.line_number { let line = match config.line_number {
LineNumber::Absolute => line + 1, LineNumber::Absolute => line + 1,
LineNumber::Relative => abs_diff(current_line, line), LineNumber::Relative => {
if current_line == line {
line + 1
} else {
abs_diff(current_line, line)
}
}
}; };
format!("{:>5}", line) format!("{:>5}", line)
}; };

@ -259,8 +259,11 @@ impl<T: Item + 'static> Component for Menu<T> {
// TODO: required size should re-trigger when we filter items so we can draw a smaller menu // TODO: required size should re-trigger when we filter items so we can draw a smaller menu
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) { fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
let style = cx.editor.theme.get("ui.text"); let theme = &cx.editor.theme;
let selected = cx.editor.theme.get("ui.menu.selected"); let style = theme
.try_get("ui.menu")
.unwrap_or_else(|| theme.get("ui.text"));
let selected = theme.get("ui.menu.selected");
let scroll = self.scroll; let scroll = self.scroll;

@ -228,7 +228,8 @@ pub mod completers {
let end = input.len()..; let end = input.len()..;
let mut files: Vec<_> = WalkBuilder::new(dir.clone()) let mut files: Vec<_> = WalkBuilder::new(&dir)
.hidden(false)
.max_depth(Some(1)) .max_depth(Some(1))
.build() .build()
.filter_map(|file| { .filter_map(|file| {

@ -400,18 +400,6 @@ impl Component for Prompt {
}))); })));
match event { match event {
// char or shift char
KeyEvent {
code: KeyCode::Char(c),
modifiers: KeyModifiers::NONE,
}
| KeyEvent {
code: KeyCode::Char(c),
modifiers: KeyModifiers::SHIFT,
} => {
self.insert_char(c);
(self.callback_fn)(cx, &self.line, PromptEvent::Update);
}
KeyEvent { KeyEvent {
code: KeyCode::Char('c'), code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL, modifiers: KeyModifiers::CONTROL,
@ -539,6 +527,14 @@ impl Component for Prompt {
code: KeyCode::Char('q'), code: KeyCode::Char('q'),
modifiers: KeyModifiers::CONTROL, modifiers: KeyModifiers::CONTROL,
} => self.exit_selection(), } => self.exit_selection(),
// any char event that's not combined with control or mapped to any other combo
KeyEvent {
code: KeyCode::Char(c),
modifiers,
} if !modifiers.contains(KeyModifiers::CONTROL) => {
self.insert_char(c);
(self.callback_fn)(cx, &self.line, PromptEvent::Update);
}
_ => (), _ => (),
}; };

@ -102,7 +102,7 @@ pub struct Document {
language_server: Option<Arc<helix_lsp::Client>>, language_server: Option<Arc<helix_lsp::Client>>,
} }
use std::fmt; use std::{fmt, mem};
impl fmt::Debug for Document { impl fmt::Debug for Document {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Document") f.debug_struct("Document")
@ -301,20 +301,13 @@ pub async fn to_writer<'a, W: tokio::io::AsyncWriteExt + Unpin + ?Sized>(
Ok(()) Ok(())
} }
/// Like std::mem::replace() except it allows the replacement value to be mapped from the fn take_with<T, F>(mut_ref: &mut T, f: F)
/// original value.
fn take_with<T, F>(mut_ref: &mut T, closure: F)
where where
T: Default,
F: FnOnce(T) -> T, F: FnOnce(T) -> T,
{ {
use std::{panic, ptr}; let t = mem::take(mut_ref);
let _ = mem::replace(mut_ref, f(t));
unsafe {
let old_t = ptr::read(mut_ref);
let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| closure(old_t)))
.unwrap_or_else(|_| ::std::process::abort());
ptr::write(mut_ref, new_t);
}
} }
use helix_lsp::lsp; use helix_lsp::lsp;

@ -15,10 +15,10 @@ pub struct KeyEvent {
} }
impl KeyEvent { impl KeyEvent {
/// If a character was pressed (without modifiers), return it. /// If a character was pressed, return it.
pub fn char(&self) -> Option<char> { pub fn char(&self) -> Option<char> {
match self.code { match self.code {
KeyCode::Char(ch) if self.modifiers.is_empty() => Some(ch), KeyCode::Char(ch) => Some(ch),
_ => None, _ => None,
} }
} }

@ -311,3 +311,15 @@ indent = { tab-width = 4, unit = " " }
# comment-token = "--" # comment-token = "--"
# #
# indent = { tab-width = 2, unit = " " } # indent = { tab-width = 2, unit = " " }
[[language]]
name = "zig"
scope = "source.zig"
injection-regex = "zig"
file-types = ["zig"]
roots = ["build.zig"]
auto-format = true
comment-token = "//"
language-server = { command = "zls" }
indent = { tab-width = 4, unit = " " }

@ -0,0 +1,198 @@
[
(container_doc_comment)
(doc_comment)
(line_comment)
] @comment
; field in top level decl, and in struct, union...
(ContainerField
(IDENTIFIER) @property
(SuffixExpr (IDENTIFIER) @type)?
)
; error.OutOfMemory;
(SuffixExpr
"error"
"."
(IDENTIFIER) @constant
)
; var x: IDENTIFIER
type: (SuffixExpr (IDENTIFIER) @type)
; IDENTIFIER{}
constructor: (SuffixExpr (IDENTIFIER) @constructor)
; fields
(FieldInit (IDENTIFIER) @property)
; foo.bar.baz.function() calls
(
(SuffixOp
(IDENTIFIER) @function
)
.
(FnCallArguments)
)
; function() calls
(
(
(IDENTIFIER) @function
)
.
(FnCallArguments)
)
; functionn decl
(FnProto
(IDENTIFIER) @function
(SuffixExpr (IDENTIFIER) @type)?
("!")? @function.macro
)
; function parameters and types
(ParamDecl
(IDENTIFIER) @variable.parameter
":"
[
(ParamType (SuffixExpr (IDENTIFIER) @type))
(ParamType)
]
)
; switch
(SwitchItem
(SuffixExpr
"."
.
(IDENTIFIER) @constant
)
)
(INTEGER) @number
(FLOAT) @number
[
(STRINGLITERAL)
(STRINGLITERALSINGLE)
] @string
(CHAR_LITERAL) @string
[
"allowzero"
"volatile"
"anytype"
"anyframe"
(BuildinTypeExpr)
] @type.builtin
(BreakLabel (IDENTIFIER) @label)
(BlockLabel (IDENTIFIER) @label)
[
"true"
"false"
"undefined"
"unreachable"
"null"
] @constant.builtin
[
"else"
"if"
"switch"
"for"
"while"
"return"
"break"
"continue"
"defer"
"errdefer"
"async"
"nosuspend"
"await"
"suspend"
"resume"
"try"
"catch"
] @keyword.control
[
"struct"
"enum"
"union"
"error"
"packed"
"opaque"
"test"
"usingnamespace"
"export"
"extern"
"const"
"var"
"comptime"
"threadlocal"
] @keyword
[
"pub"
"fn"
] @keyword.function
; PrecProc
[
"inline"
"noinline"
"asm"
"callconv"
"noalias"
] @attribute
[
(BUILTINIDENTIFIER)
"linksection"
"align"
] @function.builtin
[
(CompareOp)
(BitwiseOp)
(BitShiftOp)
(AdditionOp)
(MultiplyOp)
(PrefixOp)
"or"
"and"
"orelse"
"*"
"**"
"->"
"=>"
".?"
".*"
"="
] @operator
[
";"
"."
","
":"
] @punctuation.delimiter
[
".."
"..."
"["
"]"
"("
")"
"{"
"}"
(Payload "|")
(PtrPayload "|")
(PtrIndexPayload "|")
] @punctuation

@ -0,0 +1,12 @@
indent = [
"block",
"match_block",
"arguments",
"parameters"
]
outdent = [
"}",
"]",
")"
]
Loading…
Cancel
Save