diff --git a/.gitmodules b/.gitmodules index d5bd61c9e..422671b4e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -174,3 +174,7 @@ path = helix-syntax/languages/tree-sitter-git-commit url = https://github.com/the-mikedavis/tree-sitter-git-commit.git shallow = true +[submodule "helix-syntax/languages/tree-sitter-git-diff"] + path = helix-syntax/languages/tree-sitter-git-diff + url = https://github.com/the-mikedavis/tree-sitter-git-diff.git + shallow = true diff --git a/Cargo.lock b/Cargo.lock index 40afe4e50..83343fc48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.51" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" +checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3" [[package]] name = "arc-swap" @@ -78,9 +78,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chardetng" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83ee29c16b81c32fbc882ecc568305793338a8353952573db837f4f4a6cd5c2e" +checksum = "14b8f0b65b7b08ae3c8187e8d77174de20cb6777864c6b832d8ad365999cf1ea" dependencies = [ "cfg-if", "encoding_rs", diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 280944843..91575c629 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -12,6 +12,7 @@ | elixir | ✓ | | | `elixir-ls` | | fish | ✓ | ✓ | ✓ | | | git-commit | ✓ | | | | +| git-diff | ✓ | | | | | glsl | ✓ | | ✓ | | | go | ✓ | ✓ | ✓ | `gopls` | | html | ✓ | | | | @@ -21,7 +22,7 @@ | julia | ✓ | | | `julia` | | latex | ✓ | | | | | ledger | ✓ | | | | -| llvm | ✓ | | | | +| llvm | ✓ | ✓ | ✓ | | | lua | ✓ | | ✓ | | | markdown | ✓ | | | | | mint | | | | `mint` | diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index 884c98acf..06ea9d67b 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -122,6 +122,15 @@ impl Range { } } + // flips the direction of the selection + pub fn flip(&self) -> Self { + Self { + anchor: self.head, + head: self.anchor, + horiz: self.horiz, + } + } + /// Check two ranges for overlap. #[must_use] pub fn overlaps(&self, other: &Self) -> bool { diff --git a/helix-syntax/languages/tree-sitter-git-commit b/helix-syntax/languages/tree-sitter-git-commit index 5cd4776c8..066e395e1 160000 --- a/helix-syntax/languages/tree-sitter-git-commit +++ b/helix-syntax/languages/tree-sitter-git-commit @@ -1 +1 @@ -Subproject commit 5cd4776c86c82d9d6afdc8c73a47a08057aef618 +Subproject commit 066e395e1107df17183cf3ae4230f1a1406cc972 diff --git a/helix-syntax/languages/tree-sitter-git-diff b/helix-syntax/languages/tree-sitter-git-diff new file mode 160000 index 000000000..c12e6ecb5 --- /dev/null +++ b/helix-syntax/languages/tree-sitter-git-diff @@ -0,0 +1 @@ +Subproject commit c12e6ecb54485f764250556ffd7ccb18f8e2942b diff --git a/helix-syntax/languages/tree-sitter-llvm b/helix-syntax/languages/tree-sitter-llvm index d4f61bed8..3b213925b 160000 --- a/helix-syntax/languages/tree-sitter-llvm +++ b/helix-syntax/languages/tree-sitter-llvm @@ -1 +1 @@ -Subproject commit d4f61bed8ecb632addcd5e088c4f4cb9c1bf1c5b +Subproject commit 3b213925b9c4f42c1acfe2e10bfbb438d9c6834d diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c62f1da16..c841fcba1 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -26,6 +26,7 @@ use helix_view::{ }; use anyhow::{anyhow, bail, ensure, Context as _}; +use fuzzy_matcher::FuzzyMatcher; use helix_lsp::{ block_on, lsp, util::{lsp_pos_to_pos, lsp_range_to_range, pos_to_lsp_pos, range_to_lsp_range}, @@ -266,6 +267,7 @@ impl MappableCommand { change_selection_noyank, "Change selection (delete and enter insert mode, without yanking)", collapse_selection, "Collapse selection onto a single cursor", flip_selections, "Flip selection cursor and anchor", + ensure_selections_forward, "Ensure the selection is in forward direction", insert_mode, "Insert before selection", append_mode, "Insert after selection (append)", command_mode, "Enter command mode", @@ -1904,7 +1906,21 @@ fn flip_selections(cx: &mut Context) { let selection = doc .selection(view.id) .clone() - .transform(|range| Range::new(range.head, range.anchor)); + .transform(|range| range.flip()); + doc.set_selection(view.id, selection); +} + +fn ensure_selections_forward(cx: &mut Context) { + let (view, doc) = current!(cx.editor); + + let selection = doc + .selection(view.id) + .clone() + .transform(|r| match r.direction() { + Direction::Forward => r, + Direction::Backward => r.flip(), + }); + doc.set_selection(view.id, selection); } @@ -2791,18 +2807,18 @@ pub mod cmd { completer: Some(completers::filename), }, TypableCommand { - name: "buffer-close", - aliases: &["bc", "bclose"], - doc: "Close the current buffer.", - fun: buffer_close, - completer: None, // FIXME: buffer completer + name: "buffer-close", + aliases: &["bc", "bclose"], + doc: "Close the current buffer.", + fun: buffer_close, + completer: None, // FIXME: buffer completer }, TypableCommand { - name: "buffer-close!", - aliases: &["bc!", "bclose!"], - doc: "Close the current buffer forcefully (ignoring unsaved changes).", - fun: force_buffer_close, - completer: None, // FIXME: buffer completer + name: "buffer-close!", + aliases: &["bc!", "bclose!"], + doc: "Close the current buffer forcefully (ignoring unsaved changes).", + fun: force_buffer_close, + completer: None, // FIXME: buffer completer }, TypableCommand { name: "write", @@ -3103,6 +3119,9 @@ fn command_mode(cx: &mut Context) { ":".into(), Some(':'), |input: &str| { + static FUZZY_MATCHER: Lazy = + Lazy::new(fuzzy_matcher::skim::SkimMatcherV2::default); + // we use .this over split_whitespace() because we care about empty segments let parts = input.split(' ').collect::>(); @@ -3112,7 +3131,7 @@ fn command_mode(cx: &mut Context) { let end = 0..; cmd::TYPABLE_COMMAND_LIST .iter() - .filter(|command| command.name.contains(input)) + .filter(|command| FUZZY_MATCHER.fuzzy_match(command.name, input).is_some()) .map(|command| (end.clone(), Cow::Borrowed(command.name))) .collect() } else { @@ -3811,26 +3830,30 @@ fn normal_mode(cx: &mut Context) { } fn try_restore_indent(doc: &mut Document, view_id: ViewId) { - let doc_changes = doc.changes().changes(); - let text = doc.text().slice(..); - let pos = doc.selection(view_id).primary().cursor(text); - let mut can_restore_indent = false; - - // Removes trailing whitespace if insert mode is exited after starting a blank new line. use helix_core::chars::char_is_whitespace; use helix_core::Operation; - if let [Operation::Retain(move_pos), Operation::Insert(ref inserted_str), Operation::Retain(_)] = - doc_changes - { - if move_pos + inserted_str.len32() as usize == pos - && inserted_str.starts_with('\n') - && inserted_str.chars().skip(1).all(char_is_whitespace) + + fn inserted_a_new_blank_line(changes: &[Operation], pos: usize, line_end_pos: usize) -> bool { + if let [Operation::Retain(move_pos), Operation::Insert(ref inserted_str), Operation::Retain(_)] = + changes { - can_restore_indent = true; + move_pos + inserted_str.len32() as usize == pos + && inserted_str.starts_with('\n') + && inserted_str.chars().skip(1).all(char_is_whitespace) + && pos == line_end_pos // ensure no characters exists after current position + } else { + false } } - if can_restore_indent { + let doc_changes = doc.changes().changes(); + let text = doc.text().slice(..); + let range = doc.selection(view_id).primary(); + let pos = range.cursor(text); + let line_end_pos = line_end_char_index(&text, range.cursor_line(text)); + + if inserted_a_new_blank_line(doc_changes, pos, line_end_pos) { + // Removes tailing whitespaces. let transaction = Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| { let line_start_pos = text.line_to_char(range.cursor_line(text)); diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 08c8032bb..728332129 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -617,6 +617,8 @@ impl Default for Keymaps { "A-(" => rotate_selection_contents_backward, "A-)" => rotate_selection_contents_forward, + "A-:" => ensure_selections_forward, + "esc" => normal_mode, "C-b" | "pageup" => page_up, "C-f" | "pagedown" => page_down, diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index d3eebc630..adca5d9b4 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -356,7 +356,7 @@ pub mod completers { return None; } - //let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir()); + let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir()); let path = entry.path(); let mut path = if is_tilde { @@ -374,7 +374,12 @@ pub mod completers { path.push(""); } - let path = path.to_str().unwrap().to_owned(); + let path = if cfg!(windows) && is_dir { + // Convert Windows style path separator to Unix style + path.to_str().unwrap().replace("\\", "/") + } else { + path.to_str().unwrap().to_owned() + }; Some((end.clone(), Cow::from(path))) }) }) // TODO: unwrap or skip diff --git a/languages.toml b/languages.toml index 616ef234e..c3ae9f628 100644 --- a/languages.toml +++ b/languages.toml @@ -481,3 +481,12 @@ roots = [] file-types = ["COMMIT_EDITMSG"] comment-token = "#" indent = { tab-width = 2, unit = " " } + +[[language]] +name = "git-diff" +scope = "source.diff" +roots = [] +file-types = ["diff"] +injection-regex = "diff" +comment-token = "#" +indent = { tab-width = 2, unit = " " } diff --git a/runtime/queries/git-commit/highlights.scm b/runtime/queries/git-commit/highlights.scm index a74bb3817..ffcc31aef 100644 --- a/runtime/queries/git-commit/highlights.scm +++ b/runtime/queries/git-commit/highlights.scm @@ -13,7 +13,3 @@ [":" "->"] @punctuation.delimeter (comment) @comment - -; once we have diff injections, @comment should become @none -((comment (scissors)) - (message)+ @comment) diff --git a/runtime/queries/git-commit/injections.scm b/runtime/queries/git-commit/injections.scm index 2837a5865..bd96f1de3 100644 --- a/runtime/queries/git-commit/injections.scm +++ b/runtime/queries/git-commit/injections.scm @@ -1,12 +1,7 @@ -; once a diff grammar is available, we can inject diff highlighting into the -; trailer after scissors (git commit --verbose) -; see https://github.com/helix-editor/helix/pull/1338#issuecomment-1000013539 -; -; ((comment (scissors)) -; (message) @injection.content -; (#set! injection.language "diff")) - -; --- +((comment (scissors)) + (message) @injection.content + (#set! injection.include-children) + (#set! injection.language "diff")) ; once a rebase grammar is available, we can inject rebase highlighting into ; interactive rebase summary sections like so: diff --git a/runtime/queries/git-diff/highlights.scm b/runtime/queries/git-diff/highlights.scm new file mode 100644 index 000000000..1c1a8829f --- /dev/null +++ b/runtime/queries/git-diff/highlights.scm @@ -0,0 +1,6 @@ +[(addition) (new_file)] @diff.plus +[(deletion) (old_file)] @diff.minus + +(commit) @constant +(location) @attribute +(command) @markup.bold diff --git a/runtime/queries/llvm/highlights.scm b/runtime/queries/llvm/highlights.scm index 73afe85ed..cb705197e 100644 --- a/runtime/queries/llvm/highlights.scm +++ b/runtime/queries/llvm/highlights.scm @@ -1,14 +1,158 @@ (type) @type -(statement) @keyword.operator +(type_keyword) @type.builtin + +(type [ + (local_var) + (global_var) + ] @type) + +(argument) @variable.parameter + +(_ inst_name: _ @keyword.operator) + +[ + "catch" + "filter" +] @keyword.operator + +[ + "to" + "nuw" + "nsw" + "exact" + "unwind" + "from" + "cleanup" + "swifterror" + "volatile" + "inbounds" + "inrange" + (icmp_cond) + (fcmp_cond) + (fast_math) +] @keyword.control + +(_ callee: _ @function) +(function_header name: _ @function) + +[ + "declare" + "define" + (calling_conv) +] @keyword.function + +[ + "target" + "triple" + "datalayout" + "source_filename" + "addrspace" + "blockaddress" + "align" + "syncscope" + "within" + "uselistorder" + "uselistorder_bb" + "module" + "asm" + "sideeffect" + "alignstack" + "inteldialect" + "unwind" + "type" + "global" + "constant" + "externally_initialized" + "alias" + "ifunc" + "section" + "comdat" + "thread_local" + "localdynamic" + "initialexec" + "localexec" + "any" + "exactmatch" + "largest" + "nodeduplicate" + "samesize" + "distinct" + "attributes" + "vscale" + "no_cfi" + (linkage_aux) + (dso_local) + (visibility) + (dll_storage_class) + (unnamed_addr) + (attribute_name) +] @keyword + + +(function_header [ + (linkage) + (calling_conv) + (unnamed_addr) + ] @keyword.function) + +[ + (string) + (cstring) +] @string + (number) @constant.numeric.integer (comment) @comment -(string) @string (label) @label -(keyword) @keyword -"ret" @keyword.control.return -(boolean) @constant.builtin.boolean +(_ inst_name: "ret" @keyword.control.return) (float) @constant.numeric.float -(constant) @constant -(identifier) @variable -(symbol) @punctuation.delimiter -(bracket) @punctuation.bracket + +[ + (local_var) + (global_var) +] @variable + +[ + (struct_value) + (array_value) + (vector_value) +] @constructor + +[ + "(" + ")" + "[" + "]" + "{" + "}" + "<" + ">" + "<{" + "}>" +] @punctuation.bracket + +[ + "," + ":" +] @punctuation.delimiter + +[ + "=" + "|" + "x" + "..." +] @operator + +[ + "true" + "false" +] @constant.builtin.boolean + +[ + "undef" + "poison" + "null" + "none" + "zeroinitializer" +] @constant.builtin + +(ERROR) @error diff --git a/runtime/queries/llvm/indents.toml b/runtime/queries/llvm/indents.toml new file mode 100644 index 000000000..8cd603c8e --- /dev/null +++ b/runtime/queries/llvm/indents.toml @@ -0,0 +1,8 @@ +indent = [ + "function_body", + "instruction", +] + +outdent = [ + "}", +] diff --git a/runtime/queries/llvm/locals.scm b/runtime/queries/llvm/locals.scm new file mode 100644 index 000000000..1946c2871 --- /dev/null +++ b/runtime/queries/llvm/locals.scm @@ -0,0 +1,14 @@ +; Scopes + +(function_body) @local.scope + +; Definitions + +(argument + (value (var (local_var) @local.definition))) + +(instruction + (local_var) @local.definition) + +; References +(local_var) @local.reference diff --git a/runtime/queries/llvm/textobjects.scm b/runtime/queries/llvm/textobjects.scm new file mode 100644 index 000000000..3738a3bb9 --- /dev/null +++ b/runtime/queries/llvm/textobjects.scm @@ -0,0 +1,16 @@ +(define + body: (_) @function.inside) @function.around + +(struct_type + (struct_body) @class.inside) @class.around + +(packed_struct_type + (struct_body) @class.inside) @class.around + +(array_type + (array_vector_body) @class.inside) @class.around + +(vector_type + (array_vector_body) @class.inside) @class.around + +(argument) @parameter.inside