From 0e23e4f882ec840bed0e2c1ef3723deb7a258801 Mon Sep 17 00:00:00 2001 From: Lennard Hofmann Date: Sat, 19 Nov 2022 18:08:03 +0100 Subject: [PATCH 001/269] Make `r` and `f` work (#4817) Previously, commands such as `r` (replace with tab) or `t` (select till tab) had no effect. This is because `KeyCode::Tab` needs special treatment (like `KeyCode::Enter`). --- helix-term/src/commands.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index b00e02b9478b..1b0c557e6eb4 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1131,6 +1131,10 @@ where doc!(cx.editor).line_ending.as_str().chars().next().unwrap() } + KeyEvent { + code: KeyCode::Tab, .. + } => '\t', + KeyEvent { code: KeyCode::Char(ch), .. @@ -1277,6 +1281,9 @@ fn replace(cx: &mut Context) { code: KeyCode::Enter, .. } => Some(doc.line_ending.as_str()), + KeyEvent { + code: KeyCode::Tab, .. + } => Some("\t"), _ => None, }; From 46eb185d45c22f95de36b8467f323247cdb76fda Mon Sep 17 00:00:00 2001 From: Matthew Toohey Date: Sat, 19 Nov 2022 20:54:47 -0500 Subject: [PATCH 002/269] build(nix): update nci (#4823) --- flake.lock | 71 ++++++++++++++---------------------------------------- 1 file changed, 18 insertions(+), 53 deletions(-) diff --git a/flake.lock b/flake.lock index 74206d2b3dd9..99f92fc5adbd 100644 --- a/flake.lock +++ b/flake.lock @@ -1,22 +1,5 @@ { "nodes": { - "all-cabal-json": { - "flake": false, - "locked": { - "lastModified": 1665552503, - "narHash": "sha256-r14RmRSwzv5c+bWKUDaze6pXM7nOsiz1H8nvFHJvufc=", - "owner": "nix-community", - "repo": "all-cabal-json", - "rev": "d7c0434eebffb305071404edcf9d5cd99703878e", - "type": "github" - }, - "original": { - "owner": "nix-community", - "ref": "hackage", - "repo": "all-cabal-json", - "type": "github" - } - }, "crane": { "flake": false, "locked": { @@ -52,47 +35,45 @@ "dream2nix": { "inputs": { "alejandra": [ - "nci", - "nixpkgs" + "nci" + ], + "all-cabal-json": [ + "nci" ], - "all-cabal-json": "all-cabal-json", "crane": "crane", "devshell": [ "nci", "devshell" ], "flake-utils-pre-commit": [ - "nci", - "nixpkgs" + "nci" + ], + "ghc-utils": [ + "nci" ], - "ghc-utils": "ghc-utils", "gomod2nix": [ - "nci", - "nixpkgs" + "nci" ], "mach-nix": [ - "nci", - "nixpkgs" + "nci" ], "nixpkgs": [ "nci", "nixpkgs" ], "poetry2nix": [ - "nci", - "nixpkgs" + "nci" ], "pre-commit-hooks": [ - "nci", - "nixpkgs" + "nci" ] }, "locked": { - "lastModified": 1667429039, - "narHash": "sha256-Lu6da25JioHzerkLHAHSO9suCQFzJ/XBjkcGCIbasLM=", + "lastModified": 1668794409, + "narHash": "sha256-co+RtudWse5HozC69bbfvnAFkqocI/QesKpOBPv+J6A=", "owner": "nix-community", "repo": "dream2nix", - "rev": "5252794e58eedb02d607fa3187ffead7becc81b0", + "rev": "c17875d97f330ce1ed0c2e54ea964ce05e4c1d3c", "type": "github" }, "original": { @@ -116,22 +97,6 @@ "type": "github" } }, - "ghc-utils": { - "flake": false, - "locked": { - "lastModified": 1662774800, - "narHash": "sha256-1Rd2eohGUw/s1tfvkepeYpg8kCEXiIot0RijapUjAkE=", - "ref": "refs/heads/master", - "rev": "bb3a2d3dc52ff0253fb9c2812bd7aa2da03e0fea", - "revCount": 1072, - "type": "git", - "url": "https://gitlab.haskell.org/bgamari/ghc-utils" - }, - "original": { - "type": "git", - "url": "https://gitlab.haskell.org/bgamari/ghc-utils" - } - }, "nci": { "inputs": { "devshell": "devshell", @@ -144,11 +109,11 @@ ] }, "locked": { - "lastModified": 1667542401, - "narHash": "sha256-mdWjP5tjSf8n6FAtpSgL23kX4+eWBwLrSYo9iY3mA8Q=", + "lastModified": 1668871650, + "narHash": "sha256-jXNn1sTMDcJhx9L/tXejk00Lb+rHZzj1S0oxEB9omjw=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "cd5e5cbd81c80dc219455dd3b1e0ddb55fae51ec", + "rev": "0121135dcd9d9a9c6bf1e89194b49c84bf4627ef", "type": "github" }, "original": { From 8dac863a5b5b7fac08022a14f031fcf3c479a298 Mon Sep 17 00:00:00 2001 From: Filipe Azevedo Date: Sun, 20 Nov 2022 18:39:26 +0000 Subject: [PATCH 003/269] Add `:reload-all` command (#4663) --- book/src/generated/typable-cmd.md | 1 + helix-term/src/commands/typed.rs | 51 +++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index b7496d338c4e..6390ef858e7b 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -44,6 +44,7 @@ | `:show-directory`, `:pwd` | Show the current working directory. | | `:encoding` | Set encoding. Based on `https://encoding.spec.whatwg.org`. | | `:reload` | Discard changes and reload from the source file. | +| `:reload-all` | Discard changes and reload all documents from the source files. | | `:update` | Write changes only if the file has been modified. | | `:lsp-workspace-command` | Open workspace command picker | | `:lsp-restart` | Restarts the Language Server that is in use by the current doc | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 4bbb20824d50..b8f99ff369d2 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1034,6 +1034,50 @@ fn reload( }) } +fn reload_all( + cx: &mut compositor::Context, + _args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + + let scrolloff = cx.editor.config().scrolloff; + let view_id = view!(cx.editor).id; + + let docs_view_ids: Vec<(DocumentId, Vec)> = cx + .editor + .documents_mut() + .map(|doc| { + let mut view_ids: Vec<_> = doc.selections().keys().cloned().collect(); + + if view_ids.is_empty() { + doc.ensure_view_init(view_id); + view_ids.push(view_id); + }; + + (doc.id(), view_ids) + }) + .collect(); + + for (doc_id, view_ids) in docs_view_ids { + let doc = doc_mut!(cx.editor, &doc_id); + + // Every doc is guaranteed to have at least 1 view at this point. + let view = view_mut!(cx.editor, view_ids[0]); + doc.reload(view)?; + + for view_id in view_ids { + let view = view_mut!(cx.editor, view_id); + + view.ensure_cursor_in_view(doc, scrolloff); + } + } + + Ok(()) +} + /// Update the [`Document`] if it has been modified. fn update( cx: &mut compositor::Context, @@ -2051,6 +2095,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: reload, completer: None, }, + TypableCommand { + name: "reload-all", + aliases: &[], + doc: "Discard changes and reload all documents from the source files.", + fun: reload_all, + completer: None, + }, TypableCommand { name: "update", aliases: &[], From 117239ea4501bc655d3efd36252c41b42cb6f281 Mon Sep 17 00:00:00 2001 From: Chickenkeeper Date: Sun, 20 Nov 2022 18:51:58 +0000 Subject: [PATCH 004/269] Fix broken html doctype highlighting (#4829) --- runtime/queries/html/highlights.scm | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/queries/html/highlights.scm b/runtime/queries/html/highlights.scm index fff015b5c674..99f39c95bdc5 100644 --- a/runtime/queries/html/highlights.scm +++ b/runtime/queries/html/highlights.scm @@ -14,6 +14,7 @@ ">" "" + " Date: Mon, 21 Nov 2022 01:36:19 +0100 Subject: [PATCH 005/269] Implement simple indents.scm for Elixir (#4821) --- book/src/generated/lang-support.md | 2 +- runtime/queries/elixir/indents.scm | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/elixir/indents.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 9187fbfb1212..59b60851aac6 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -25,7 +25,7 @@ | edoc | ✓ | | | | | eex | ✓ | | | | | ejs | ✓ | | | | -| elixir | ✓ | ✓ | | `elixir-ls` | +| elixir | ✓ | ✓ | ✓ | `elixir-ls` | | elm | ✓ | | | `elm-language-server` | | elvish | ✓ | | | `elvish` | | env | ✓ | | | | diff --git a/runtime/queries/elixir/indents.scm b/runtime/queries/elixir/indents.scm new file mode 100644 index 000000000000..102b1aadfb9c --- /dev/null +++ b/runtime/queries/elixir/indents.scm @@ -0,0 +1,13 @@ +[ + (after_block) + (anonymous_function) + (catch_block) + (do_block) + (else_block) + (rescue_block) + (stab_clause) +] @indent + +[ + "end" +] @outdent From 2f9ca3840a478fc58f411b6a4bc67019829ff72f Mon Sep 17 00:00:00 2001 From: A-Walrus <58790821+A-Walrus@users.noreply.github.com> Date: Mon, 21 Nov 2022 03:58:35 +0200 Subject: [PATCH 006/269] Add preview for scratch buffers in buffer picker (#3454) --- helix-term/src/commands.rs | 6 +- helix-term/src/commands/dap.rs | 4 +- helix-term/src/commands/lsp.rs | 2 +- helix-term/src/ui/mod.rs | 2 +- helix-term/src/ui/picker.rs | 129 +++++++++++++++++++++------------ 5 files changed, 88 insertions(+), 55 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 1b0c557e6eb4..25f00f987b2a 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2005,7 +2005,7 @@ fn global_search(cx: &mut Context) { align_view(doc, view, Align::Center); }, |_editor, FileResult { path, line_num }| { - Some((path.clone(), Some((*line_num, *line_num)))) + Some((path.clone().into(), Some((*line_num, *line_num)))) }, ); compositor.push(Box::new(overlayed(picker))); @@ -2360,7 +2360,7 @@ fn buffer_picker(cx: &mut Context) { .selection(view_id) .primary() .cursor_line(doc.text().slice(..)); - Some((meta.path.clone()?, Some((line, line)))) + Some((meta.id.into(), Some((line, line)))) }, ); cx.push_layer(Box::new(overlayed(picker))); @@ -2441,7 +2441,7 @@ fn jumplist_picker(cx: &mut Context) { |editor, meta| { let doc = &editor.documents.get(&meta.id)?; let line = meta.selection.primary().cursor_line(doc.text().slice(..)); - Some((meta.path.clone()?, Some((line, line)))) + Some((meta.path.clone()?.into(), Some((line, line)))) }, ); cx.push_layer(Box::new(overlayed(picker))); diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index c27417e397b1..b182f28c4284 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -85,7 +85,7 @@ fn thread_picker( frame.line.saturating_sub(1), frame.end_line.unwrap_or(frame.line).saturating_sub(1), )); - Some((path, pos)) + Some((path.into(), pos)) }, ); compositor.push(Box::new(picker)); @@ -706,7 +706,7 @@ pub fn dap_switch_stack_frame(cx: &mut Context) { .and_then(|source| source.path.clone()) .map(|path| { ( - path, + path.into(), Some(( frame.line.saturating_sub(1), frame.end_line.unwrap_or(frame.line).saturating_sub(1), diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 33d33440cacd..dcabfab1d5f9 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -156,7 +156,7 @@ fn location_to_file_location(location: &lsp::Location) -> FileLocation { location.range.start.line as usize, location.range.end.line as usize, )); - (path, line) + (path.into(), line) } // TODO: share with symbol picker(symbol.location) diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index cca9e9bf0b68..3416b3194f16 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -230,7 +230,7 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi cx.editor.set_error(err); } }, - |_editor, path| Some((path.clone(), None)), + |_editor, path| Some((path.clone().into(), None)), ) } diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 5491192410d4..5e9ca3d887a5 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -12,18 +12,14 @@ use fuzzy_matcher::skim::SkimMatcherV2 as Matcher; use tui::widgets::Widget; use std::{cmp::Ordering, time::Instant}; -use std::{ - collections::HashMap, - io::Read, - path::{Path, PathBuf}, -}; +use std::{collections::HashMap, io::Read, path::PathBuf}; use crate::ui::{Prompt, PromptEvent}; use helix_core::{movement::Direction, Position}; use helix_view::{ editor::Action, graphics::{CursorKind, Margin, Modifier, Rect}, - Document, Editor, + Document, DocumentId, Editor, }; use super::menu::Item; @@ -32,8 +28,36 @@ pub const MIN_AREA_WIDTH_FOR_PREVIEW: u16 = 72; /// Biggest file size to preview in bytes pub const MAX_FILE_SIZE_FOR_PREVIEW: u64 = 10 * 1024 * 1024; +#[derive(PartialEq, Eq, Hash)] +pub enum PathOrId { + Id(DocumentId), + Path(PathBuf), +} + +impl PathOrId { + fn get_canonicalized(self) -> std::io::Result { + use PathOrId::*; + Ok(match self { + Path(path) => Path(helix_core::path::get_canonicalized_path(&path)?), + Id(id) => Id(id), + }) + } +} + +impl From for PathOrId { + fn from(v: PathBuf) -> Self { + Self::Path(v) + } +} + +impl From for PathOrId { + fn from(v: DocumentId) -> Self { + Self::Id(v) + } +} + /// File path and range of lines (used to align and highlight lines) -pub type FileLocation = (PathBuf, Option<(usize, usize)>); +pub type FileLocation = (PathOrId, Option<(usize, usize)>); pub struct FilePicker { picker: Picker, @@ -112,62 +136,71 @@ impl FilePicker { self.picker .selection() .and_then(|current| (self.file_fn)(editor, current)) - .and_then(|(path, line)| { - helix_core::path::get_canonicalized_path(&path) - .ok() - .zip(Some(line)) - }) + .and_then(|(path_or_id, line)| path_or_id.get_canonicalized().ok().zip(Some(line))) } /// Get (cached) preview for a given path. If a document corresponding /// to the path is already open in the editor, it is used instead. fn get_preview<'picker, 'editor>( &'picker mut self, - path: &Path, + path_or_id: PathOrId, editor: &'editor Editor, ) -> Preview<'picker, 'editor> { - if let Some(doc) = editor.document_by_path(path) { - return Preview::EditorDocument(doc); - } + match path_or_id { + PathOrId::Path(path) => { + let path = &path; + if let Some(doc) = editor.document_by_path(path) { + return Preview::EditorDocument(doc); + } - if self.preview_cache.contains_key(path) { - return Preview::Cached(&self.preview_cache[path]); - } + if self.preview_cache.contains_key(path) { + return Preview::Cached(&self.preview_cache[path]); + } - let data = std::fs::File::open(path).and_then(|file| { - let metadata = file.metadata()?; - // Read up to 1kb to detect the content type - let n = file.take(1024).read_to_end(&mut self.read_buffer)?; - let content_type = content_inspector::inspect(&self.read_buffer[..n]); - self.read_buffer.clear(); - Ok((metadata, content_type)) - }); - let preview = data - .map( - |(metadata, content_type)| match (metadata.len(), content_type) { - (_, content_inspector::ContentType::BINARY) => CachedPreview::Binary, - (size, _) if size > MAX_FILE_SIZE_FOR_PREVIEW => CachedPreview::LargeFile, - _ => { - // TODO: enable syntax highlighting; blocked by async rendering - Document::open(path, None, None) - .map(|doc| CachedPreview::Document(Box::new(doc))) - .unwrap_or(CachedPreview::NotFound) - } - }, - ) - .unwrap_or(CachedPreview::NotFound); - self.preview_cache.insert(path.to_owned(), preview); - Preview::Cached(&self.preview_cache[path]) + let data = std::fs::File::open(path).and_then(|file| { + let metadata = file.metadata()?; + // Read up to 1kb to detect the content type + let n = file.take(1024).read_to_end(&mut self.read_buffer)?; + let content_type = content_inspector::inspect(&self.read_buffer[..n]); + self.read_buffer.clear(); + Ok((metadata, content_type)) + }); + let preview = data + .map( + |(metadata, content_type)| match (metadata.len(), content_type) { + (_, content_inspector::ContentType::BINARY) => CachedPreview::Binary, + (size, _) if size > MAX_FILE_SIZE_FOR_PREVIEW => { + CachedPreview::LargeFile + } + _ => { + // TODO: enable syntax highlighting; blocked by async rendering + Document::open(path, None, None) + .map(|doc| CachedPreview::Document(Box::new(doc))) + .unwrap_or(CachedPreview::NotFound) + } + }, + ) + .unwrap_or(CachedPreview::NotFound); + self.preview_cache.insert(path.to_owned(), preview); + Preview::Cached(&self.preview_cache[path]) + } + PathOrId::Id(id) => { + let doc = editor.documents.get(&id).unwrap(); + Preview::EditorDocument(doc) + } + } } fn handle_idle_timeout(&mut self, cx: &mut Context) -> EventResult { // Try to find a document in the cache let doc = self .current_file(cx.editor) - .and_then(|(path, _range)| self.preview_cache.get_mut(&path)) - .and_then(|cache| match cache { - CachedPreview::Document(doc) => Some(doc), - _ => None, + .and_then(|(path, _range)| match path { + PathOrId::Id(doc_id) => Some(doc_mut!(cx.editor, &doc_id)), + PathOrId::Path(path) => match self.preview_cache.get_mut(&path) { + Some(CachedPreview::Document(doc)) => Some(doc), + _ => None, + }, }); // Then attempt to highlight it if it has no language set @@ -224,7 +257,7 @@ impl Component for FilePicker { block.render(preview_area, surface); if let Some((path, range)) = self.current_file(cx.editor) { - let preview = self.get_preview(&path, cx.editor); + let preview = self.get_preview(path, cx.editor); let doc = match preview.document() { Some(doc) => doc, None => { From bbde897ac39991620a9b6e9e5c742ab3b97b1fbe Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 20 Nov 2022 20:49:44 -0600 Subject: [PATCH 007/269] Select new pasted text in normal mode only (#4824) d6323b7cbc21a9d3ba29738c76581dad93f9f415 changed the behavior of paste to select the newly inserted text. This is preferrable in normal mode because it's useful to be able to act on the new text. This behavior is worse for insert or select mode though: * In insert mode, the cursor ends up on the last character of the newly selected text, so further typing inserts text before the last character. * In select mode, the current selection is replaced with the new text selection which doesn't extend the current selection. With this change, the selection is extended to include the new text. This aligns the behavior more closely with Kakoune, but it's coincidental instead of intentional: Kakoune doesn't implement bracketed paste (AFAIK) which causes this behavior in insert mode, and Kakoune doesn't have a select mode. --- helix-term/src/commands.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 25f00f987b2a..bf8229441a21 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3467,7 +3467,14 @@ enum Paste { Cursor, } -fn paste_impl(values: &[String], doc: &mut Document, view: &mut View, action: Paste, count: usize) { +fn paste_impl( + values: &[String], + doc: &mut Document, + view: &mut View, + action: Paste, + count: usize, + mode: Mode, +) { if values.is_empty() { return; } @@ -3499,7 +3506,7 @@ fn paste_impl(values: &[String], doc: &mut Document, view: &mut View, action: Pa let mut offset = 0; let mut ranges = SmallVec::with_capacity(selection.len()); - let transaction = Transaction::change_by_selection(text, selection, |range| { + let mut transaction = Transaction::change_by_selection(text, selection, |range| { let pos = match (action, linewise) { // paste linewise before (Paste::Before, true) => text.line_to_char(text.char_to_line(range.from())), @@ -3531,7 +3538,9 @@ fn paste_impl(values: &[String], doc: &mut Document, view: &mut View, action: Pa (pos, pos, value) }); - let transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); + if mode == Mode::Normal { + transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); + } apply_transaction(&transaction, doc, view); } @@ -3543,7 +3552,7 @@ pub(crate) fn paste_bracketed_value(cx: &mut Context, contents: String) { Mode::Normal => Paste::Before, }; let (view, doc) = current!(cx.editor); - paste_impl(&[contents], doc, view, paste, count); + paste_impl(&[contents], doc, view, paste, count, cx.editor.mode); } fn paste_clipboard_impl( @@ -3555,7 +3564,7 @@ fn paste_clipboard_impl( let (view, doc) = current!(editor); match editor.clipboard_provider.get_contents(clipboard_type) { Ok(contents) => { - paste_impl(&[contents], doc, view, action, count); + paste_impl(&[contents], doc, view, action, count, editor.mode); Ok(()) } Err(e) => Err(e.context("Couldn't get system clipboard contents")), @@ -3674,7 +3683,7 @@ fn paste(cx: &mut Context, pos: Paste) { let registers = &mut cx.editor.registers; if let Some(values) = registers.read(reg_name) { - paste_impl(values, doc, view, pos, count); + paste_impl(values, doc, view, pos, count, cx.editor.mode); } } From 0b2bb061b95b60c51f018f541e622b731ddd14ef Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 21 Nov 2022 03:13:59 -0600 Subject: [PATCH 008/269] Bump TREE_SITTER_MATCH_LIMIT to 256 (#4830) The limit of 64 breaks some highlighting in Erlang files with complicated record definitions. Bumping to 256 seems to work on all files I have seen. --- helix-core/src/syntax.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 93bd7fe908ce..b567a8ab7339 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -354,24 +354,25 @@ impl<'a> CapturedNode<'a> { } } -/// The number of matches a TS cursor can at once to avoid performance problems for medium to large files. -/// Set with `set_match_limit`. -/// Using such a limit means that we lose valid captures in, so there is fundamentally a tradeoff here. +/// The maximum number of in-progress matches a TS cursor can consider at once. +/// This is set to a constant in order to avoid performance problems for medium to large files. Set with `set_match_limit`. +/// Using such a limit means that we lose valid captures, so there is fundamentally a tradeoff here. /// /// /// Old tree sitter versions used a limit of 32 by default until this limit was removed in version `0.19.5` (must now be set manually). /// However, this causes performance issues for medium to large files. /// In helix, this problem caused treesitter motions to take multiple seconds to complete in medium-sized rust files (3k loc). +/// +/// /// Neovim also encountered this problem and reintroduced this limit after it was removed upstream /// (see and ). /// The number used here is fundamentally a tradeoff between breaking some obscure edge cases and performance. /// /// -/// A value of 64 was chosen because neovim uses that value. -/// Neovim chose this value somewhat arbitrarily () adjusting it whenever issues occur in practice. -/// However this value has been in use for a long time and due to the large userbase of neovim it is probably a good choice. -/// If this limit causes problems for a grammar in the future, it could be increased. -const TREE_SITTER_MATCH_LIMIT: u32 = 64; +/// Neovim chose 64 for this value somewhat arbitrarily (). +/// 64 is too low for some languages though. In particular, it breaks some highlighting for record fields in Erlang record definitions. +/// This number can be increased if new syntax highlight breakages are found, as long as the performance penalty is not too high. +const TREE_SITTER_MATCH_LIMIT: u32 = 256; impl TextObjectQuery { /// Run the query on the given node and return sub nodes which match given From 48e44720e4001e9d2feef7f4a24c1b10d43ad7df Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Mon, 21 Nov 2022 18:06:43 +0300 Subject: [PATCH 009/269] build(nix): don't run tests in builds since CI runs them already, update inputs (#4834) --- flake.lock | 24 ++++++++++++------------ flake.nix | 3 ++- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/flake.lock b/flake.lock index 99f92fc5adbd..f097519e34af 100644 --- a/flake.lock +++ b/flake.lock @@ -69,11 +69,11 @@ ] }, "locked": { - "lastModified": 1668794409, - "narHash": "sha256-co+RtudWse5HozC69bbfvnAFkqocI/QesKpOBPv+J6A=", + "lastModified": 1668851003, + "narHash": "sha256-X7RCQQynbxStZR2m7HW38r/msMQwVl3afD6UXOCtvx4=", "owner": "nix-community", "repo": "dream2nix", - "rev": "c17875d97f330ce1ed0c2e54ea964ce05e4c1d3c", + "rev": "c77e8379d8fe01213ba072e40946cbfb7b58e628", "type": "github" }, "original": { @@ -109,11 +109,11 @@ ] }, "locked": { - "lastModified": 1668871650, - "narHash": "sha256-jXNn1sTMDcJhx9L/tXejk00Lb+rHZzj1S0oxEB9omjw=", + "lastModified": 1669011203, + "narHash": "sha256-Lymj4HktNEFmVXtwI0Os7srDXHZbZW0Nzw3/+5Hf8ko=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "0121135dcd9d9a9c6bf1e89194b49c84bf4627ef", + "rev": "c5133b91fc1d549087c91228bd213f2518728a4b", "type": "github" }, "original": { @@ -124,11 +124,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1667482890, - "narHash": "sha256-pua0jp87iwN7NBY5/ypx0s9L9CG49Ju/NI4wGwurHc4=", + "lastModified": 1668905981, + "narHash": "sha256-RBQa/+9Uk1eFTqIOXBSBezlEbA3v5OkgP+qptQs1OxY=", "owner": "nixos", "repo": "nixpkgs", - "rev": "a2a777538d971c6b01c6e54af89ddd6567c055e8", + "rev": "690ffff026b4e635b46f69002c0f4e81c65dfc2e", "type": "github" }, "original": { @@ -153,11 +153,11 @@ ] }, "locked": { - "lastModified": 1667487142, - "narHash": "sha256-bVuzLs1ZVggJAbJmEDVO9G6p8BH3HRaolK70KXvnWnU=", + "lastModified": 1668998422, + "narHash": "sha256-G/BklIplCHZEeDIabaaxqgITdIXtMolRGlwxn9jG2/Q=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "cf668f737ac986c0a89e83b6b2e3c5ddbd8cf33b", + "rev": "68ab029c93f8f8eed4cf3ce9a89a9fd4504b2d6e", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index b1d3f01eb681..fe1c6b44bfc1 100644 --- a/flake.nix +++ b/flake.nix @@ -150,6 +150,7 @@ ["languages.toml" "theme.toml" "base16_theme.toml"] } ''; + checkPhase = ":"; meta.mainProgram = "hx"; }; @@ -166,7 +167,7 @@ packages // { helix-unwrapped = packages.helix.passthru.unwrapped; - helix-unwrapped-debug = packages.helix-debug.passthru.unwrapped; + helix-unwrapped-dev = packages.helix-dev.passthru.unwrapped; } ) outputs.packages; From 4ef6621c24833e24ab7361f121ba63729bd201cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 17:46:59 -0600 Subject: [PATCH 010/269] build(deps): bump serde_json from 1.0.87 to 1.0.88 (#4845) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.87 to 1.0.88. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.87...v1.0.88) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3a9673749ad6..57fdede85481 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -959,9 +959,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" +checksum = "8e8b3801309262e8184d9687fb697586833e939767aea0dda89f5a8e650e8bd7" dependencies = [ "itoa", "ryu", From 4443885b38936bc995421509bc25b01f7192a36b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 17:47:45 -0600 Subject: [PATCH 011/269] build(deps): bump cc from 1.0.76 to 1.0.77 (#4844) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.0.76 to 1.0.77. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Commits](https://github.com/rust-lang/cc-rs/compare/1.0.76...1.0.77) --- updated-dependencies: - dependency-name: cc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57fdede85481..5833714d640a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,9 +92,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cc" -version = "1.0.76" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" +checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" [[package]] name = "cfg-if" From 8102c3224f8cbf4a8e679377fef6ea98ed337cba Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 21 Nov 2022 19:54:50 -0600 Subject: [PATCH 012/269] Limit the number of items in the jumplist (#4750) Previously, jumplists could grow unchecked. Every transaction is applied to jumplist selections to ensure that they are up to date and within document bounds, so this would cause every edit to become more expensive as jumplist lengths increased throughout a session. Setting a maximum number of entries limits the cost. Vim and Neovim limit their jumplists: * https://github.com/vim/vim/blob/b298fe6cbae3b240b10dbd55d9c38d0cc8e033d3/src/structs.h#L141 * https://github.com/neovim/neovim/blob/e8cc489accc435076afb4fdf89778b64f0a48473/src/nvim/mark_defs.h#L57 Notably, Kakoune does not. In Kakoune, changes are applied to jumplist entries lazily as you hit ``/`` though, so Kakoune doesn't have the same growing cost concerns. Kakoune also does not have a concept of a View which limits the cost further. Vim and Neovim limit to 100. This seems unreasonably high to me so I've set this to 30 to start. We can increase if this is problematically low. --- helix-term/src/commands.rs | 1 - helix-view/src/view.rs | 26 ++++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index bf8229441a21..f384612bf3b5 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2427,7 +2427,6 @@ fn jumplist_picker(cx: &mut Context) { .views() .flat_map(|(view, _)| { view.jumps - .get() .iter() .map(|(doc_id, selection)| new_meta(view, *doc_id, selection.clone())) }) diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 6da4df1f0f03..8aa4760dcc69 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -3,29 +3,35 @@ use helix_core::{ pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection, Transaction, }; -use std::fmt; +use std::{collections::VecDeque, fmt}; + +const JUMP_LIST_CAPACITY: usize = 30; type Jump = (DocumentId, Selection); #[derive(Debug, Clone)] pub struct JumpList { - jumps: Vec, + jumps: VecDeque, current: usize, } impl JumpList { pub fn new(initial: Jump) -> Self { - Self { - jumps: vec![initial], - current: 0, - } + let mut jumps = VecDeque::with_capacity(JUMP_LIST_CAPACITY); + jumps.push_back(initial); + Self { jumps, current: 0 } } pub fn push(&mut self, jump: Jump) { self.jumps.truncate(self.current); // don't push duplicates - if self.jumps.last() != Some(&jump) { - self.jumps.push(jump); + if self.jumps.back() != Some(&jump) { + // If the jumplist is full, drop the oldest item. + while self.jumps.len() >= JUMP_LIST_CAPACITY { + self.jumps.pop_front(); + } + + self.jumps.push_back(jump); self.current = self.jumps.len(); } } @@ -57,8 +63,8 @@ impl JumpList { self.jumps.retain(|(other_id, _)| other_id != doc_id); } - pub fn get(&self) -> &[Jump] { - &self.jumps + pub fn iter(&self) -> impl Iterator { + self.jumps.iter() } /// Applies a [`Transaction`] of changes to the jumplist. From 1db01caec7c91e270a23fd4f85955bb235ffbcb7 Mon Sep 17 00:00:00 2001 From: Bob Date: Tue, 22 Nov 2022 09:55:46 +0800 Subject: [PATCH 013/269] remove duplicated shell calls (#3465) --- helix-term/src/commands.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index f384612bf3b5..5b44775b01af 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4803,15 +4803,24 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) { let mut ranges = SmallVec::with_capacity(selection.len()); let text = doc.text().slice(..); + let mut shell_output: Option = None; let mut offset = 0isize; - for range in selection.ranges() { - let fragment = range.slice(text); - let (output, success) = match shell_impl(shell, cmd, pipe.then(|| fragment.into())) { - Ok(result) => result, - Err(err) => { - cx.editor.set_error(err.to_string()); - return; + let (output, success) = if let Some(output) = shell_output.as_ref() { + (output.clone(), true) + } else { + let fragment = range.slice(text); + match shell_impl(shell, cmd, pipe.then(|| fragment.into())) { + Ok(result) => { + if !pipe { + shell_output = Some(result.0.clone()); + } + result + } + Err(err) => { + cx.editor.set_error(err.to_string()); + return; + } } }; From 9059c65a5385f6d3cc0bc7f6e3f835ae542635a5 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 21 Nov 2022 20:52:23 -0600 Subject: [PATCH 014/269] lsp: Check server provider capabilities (#3554) Language Servers may signal that they do not support a method in the initialization result (server capabilities). We can check these when making LSP requests and hint in the status line when a method is not supported by the server. This can also prevent crashes in servers which assume that clients do not send requests for methods which are disabled in the server capabilities. There is an existing pattern the LSP client module where a method returns `Option>>` with `None` signaling no support in the server. This change extends this pattern to the rest of the client functions. And we log an error to the statusline for manually triggered LSP calls which return `None`. --- helix-lsp/src/client.rs | 229 +++++++++++++++++++++++--------- helix-term/src/commands.rs | 29 ++-- helix-term/src/commands/lsp.rs | 115 +++++++++++++--- helix-term/src/ui/completion.rs | 17 +-- 4 files changed, 293 insertions(+), 97 deletions(-) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 424cbabfa202..2c2c7c88ec1d 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -4,7 +4,6 @@ use crate::{ Call, Error, OffsetEncoding, Result, }; -use anyhow::anyhow; use helix_core::{find_root, ChangeSet, Rope}; use lsp_types as lsp; use serde::Deserialize; @@ -546,16 +545,17 @@ impl Client { new_text: &Rope, changes: &ChangeSet, ) -> Option>> { - // figure out what kind of sync the server supports - let capabilities = self.capabilities.get().unwrap(); + // Return early if the server does not support document sync. let sync_capabilities = match capabilities.text_document_sync { - Some(lsp::TextDocumentSyncCapability::Kind(kind)) - | Some(lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions { - change: Some(kind), - .. - })) => kind, + Some( + lsp::TextDocumentSyncCapability::Kind(kind) + | lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions { + change: Some(kind), + .. + }), + ) => kind, // None | SyncOptions { changes: None } _ => return None, }; @@ -631,8 +631,12 @@ impl Client { text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option, - ) -> impl Future> { - // ) -> Result> { + ) -> Option>> { + let capabilities = self.capabilities.get().unwrap(); + + // Return early if the server does not support completion. + capabilities.completion_provider.as_ref()?; + let params = lsp::CompletionParams { text_document_position: lsp::TextDocumentPositionParams { text_document, @@ -647,14 +651,25 @@ impl Client { // lsp::CompletionContext { trigger_kind: , trigger_character: Some(), } }; - self.call::(params) + Some(self.call::(params)) } pub fn resolve_completion_item( &self, completion_item: lsp::CompletionItem, - ) -> impl Future> { - self.call::(completion_item) + ) -> Option>> { + let capabilities = self.capabilities.get().unwrap(); + + // Return early if the server does not support resolving completion items. + match capabilities.completion_provider { + Some(lsp::CompletionOptions { + resolve_provider: Some(true), + .. + }) => (), + _ => return None, + } + + Some(self.call::(completion_item)) } pub fn text_document_signature_help( @@ -665,7 +680,7 @@ impl Client { ) -> Option>> { let capabilities = self.capabilities.get().unwrap(); - // Return early if signature help is not supported + // Return early if the server does not support signature help. capabilities.signature_help_provider.as_ref()?; let params = lsp::SignatureHelpParams { @@ -686,7 +701,18 @@ impl Client { text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option, - ) -> impl Future> { + ) -> Option>> { + let capabilities = self.capabilities.get().unwrap(); + + // Return early if the server does not support hover. + match capabilities.hover_provider { + Some( + lsp::HoverProviderCapability::Simple(true) + | lsp::HoverProviderCapability::Options(_), + ) => (), + _ => return None, + } + let params = lsp::HoverParams { text_document_position_params: lsp::TextDocumentPositionParams { text_document, @@ -696,7 +722,7 @@ impl Client { // lsp::SignatureHelpContext }; - self.call::(params) + Some(self.call::(params)) } // formatting @@ -709,13 +735,11 @@ impl Client { ) -> Option>>> { let capabilities = self.capabilities.get().unwrap(); - // check if we're able to format + // Return early if the server does not support formatting. match capabilities.document_formatting_provider { - Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (), - // None | Some(false) + Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (), _ => return None, }; - // TODO: return err::unavailable so we can fall back to tree sitter formatting // merge FormattingOptions with 'config.format' let config_format = self @@ -750,22 +774,20 @@ impl Client { }) } - pub async fn text_document_range_formatting( + pub fn text_document_range_formatting( &self, text_document: lsp::TextDocumentIdentifier, range: lsp::Range, options: lsp::FormattingOptions, work_done_token: Option, - ) -> anyhow::Result> { + ) -> Option>>> { let capabilities = self.capabilities.get().unwrap(); - // check if we're able to format + // Return early if the server does not support range formatting. match capabilities.document_range_formatting_provider { - Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (), - // None | Some(false) - _ => return Ok(Vec::new()), + Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (), + _ => return None, }; - // TODO: return err::unavailable so we can fall back to tree sitter formatting let params = lsp::DocumentRangeFormattingParams { text_document, @@ -774,11 +796,13 @@ impl Client { work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token }, }; - let response = self - .request::(params) - .await?; + let request = self.call::(params); - Ok(response.unwrap_or_default()) + Some(async move { + let json = request.await?; + let response: Option> = serde_json::from_value(json)?; + Ok(response.unwrap_or_default()) + }) } pub fn text_document_document_highlight( @@ -786,7 +810,15 @@ impl Client { text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option, - ) -> impl Future> { + ) -> Option>> { + let capabilities = self.capabilities.get().unwrap(); + + // Return early if the server does not support document highlight. + match capabilities.document_highlight_provider { + Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (), + _ => return None, + } + let params = lsp::DocumentHighlightParams { text_document_position_params: lsp::TextDocumentPositionParams { text_document, @@ -798,7 +830,7 @@ impl Client { }, }; - self.call::(params) + Some(self.call::(params)) } fn goto_request< @@ -831,8 +863,20 @@ impl Client { text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option, - ) -> impl Future> { - self.goto_request::(text_document, position, work_done_token) + ) -> Option>> { + let capabilities = self.capabilities.get().unwrap(); + + // Return early if the server does not support goto-definition. + match capabilities.definition_provider { + Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (), + _ => return None, + } + + Some(self.goto_request::( + text_document, + position, + work_done_token, + )) } pub fn goto_type_definition( @@ -840,12 +884,23 @@ impl Client { text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option, - ) -> impl Future> { - self.goto_request::( + ) -> Option>> { + let capabilities = self.capabilities.get().unwrap(); + + // Return early if the server does not support goto-type-definition. + match capabilities.type_definition_provider { + Some( + lsp::TypeDefinitionProviderCapability::Simple(true) + | lsp::TypeDefinitionProviderCapability::Options(_), + ) => (), + _ => return None, + } + + Some(self.goto_request::( text_document, position, work_done_token, - ) + )) } pub fn goto_implementation( @@ -853,12 +908,23 @@ impl Client { text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option, - ) -> impl Future> { - self.goto_request::( + ) -> Option>> { + let capabilities = self.capabilities.get().unwrap(); + + // Return early if the server does not support goto-definition. + match capabilities.implementation_provider { + Some( + lsp::ImplementationProviderCapability::Simple(true) + | lsp::ImplementationProviderCapability::Options(_), + ) => (), + _ => return None, + } + + Some(self.goto_request::( text_document, position, work_done_token, - ) + )) } pub fn goto_reference( @@ -866,7 +932,15 @@ impl Client { text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option, - ) -> impl Future> { + ) -> Option>> { + let capabilities = self.capabilities.get().unwrap(); + + // Return early if the server does not support goto-reference. + match capabilities.references_provider { + Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (), + _ => return None, + } + let params = lsp::ReferenceParams { text_document_position: lsp::TextDocumentPositionParams { text_document, @@ -881,31 +955,47 @@ impl Client { }, }; - self.call::(params) + Some(self.call::(params)) } pub fn document_symbols( &self, text_document: lsp::TextDocumentIdentifier, - ) -> impl Future> { + ) -> Option>> { + let capabilities = self.capabilities.get().unwrap(); + + // Return early if the server does not support document symbols. + match capabilities.document_symbol_provider { + Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (), + _ => return None, + } + let params = lsp::DocumentSymbolParams { text_document, work_done_progress_params: lsp::WorkDoneProgressParams::default(), partial_result_params: lsp::PartialResultParams::default(), }; - self.call::(params) + Some(self.call::(params)) } // empty string to get all symbols - pub fn workspace_symbols(&self, query: String) -> impl Future> { + pub fn workspace_symbols(&self, query: String) -> Option>> { + let capabilities = self.capabilities.get().unwrap(); + + // Return early if the server does not support workspace symbols. + match capabilities.workspace_symbol_provider { + Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (), + _ => return None, + } + let params = lsp::WorkspaceSymbolParams { query, work_done_progress_params: lsp::WorkDoneProgressParams::default(), partial_result_params: lsp::PartialResultParams::default(), }; - self.call::(params) + Some(self.call::(params)) } pub fn code_actions( @@ -913,7 +1003,18 @@ impl Client { text_document: lsp::TextDocumentIdentifier, range: lsp::Range, context: lsp::CodeActionContext, - ) -> impl Future> { + ) -> Option>> { + let capabilities = self.capabilities.get().unwrap(); + + // Return early if the server does not support code actions. + match capabilities.code_action_provider { + Some( + lsp::CodeActionProviderCapability::Simple(true) + | lsp::CodeActionProviderCapability::Options(_), + ) => (), + _ => return None, + } + let params = lsp::CodeActionParams { text_document, range, @@ -922,26 +1023,22 @@ impl Client { partial_result_params: lsp::PartialResultParams::default(), }; - self.call::(params) + Some(self.call::(params)) } - pub async fn rename_symbol( + pub fn rename_symbol( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, new_name: String, - ) -> anyhow::Result { + ) -> Option>> { let capabilities = self.capabilities.get().unwrap(); - // check if we're able to rename + // Return early if the language server does not support renaming. match capabilities.rename_provider { Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (), // None | Some(false) - _ => { - log::warn!("rename_symbol failed: The server does not support rename"); - let err = "The server does not support rename"; - return Err(anyhow!(err)); - } + _ => return None, }; let params = lsp::RenameParams { @@ -955,11 +1052,21 @@ impl Client { }, }; - let response = self.request::(params).await?; - Ok(response.unwrap_or_default()) + let request = self.call::(params); + + Some(async move { + let json = request.await?; + let response: Option = serde_json::from_value(json)?; + Ok(response.unwrap_or_default()) + }) } - pub fn command(&self, command: lsp::Command) -> impl Future> { + pub fn command(&self, command: lsp::Command) -> Option>> { + let capabilities = self.capabilities.get().unwrap(); + + // Return early if the language server does not support executing commands. + capabilities.execute_command_provider.as_ref()?; + let params = lsp::ExecuteCommandParams { command: command.command, arguments: command.arguments.unwrap_or_default(), @@ -968,6 +1075,6 @@ impl Client { }, }; - self.call::(params) + Some(self.call::(params)) } } diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 5b44775b01af..8af5a7e3e400 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3801,15 +3801,21 @@ fn format_selections(cx: &mut Context) { let range = ranges[0]; - let edits = tokio::task::block_in_place(|| { - helix_lsp::block_on(language_server.text_document_range_formatting( - doc.identifier(), - range, - lsp::FormattingOptions::default(), - None, - )) - }) - .unwrap_or_default(); + let request = match language_server.text_document_range_formatting( + doc.identifier(), + range, + lsp::FormattingOptions::default(), + None, + ) { + Some(future) => future, + None => { + cx.editor + .set_error("Language server does not support range formatting"); + return; + } + }; + + let edits = tokio::task::block_in_place(|| helix_lsp::block_on(request)).unwrap_or_default(); let transaction = helix_lsp::util::generate_transaction_from_edits( doc.text(), @@ -3953,7 +3959,10 @@ pub fn completion(cx: &mut Context) { let pos = pos_to_lsp_pos(doc.text(), cursor, offset_encoding); - let future = language_server.completion(doc.identifier(), pos, None); + let future = match language_server.completion(doc.identifier(), pos, None) { + Some(future) => future, + None => return, + }; let trigger_offset = cursor; diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index dcabfab1d5f9..8faf1d087f92 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -333,7 +333,14 @@ pub fn symbol_picker(cx: &mut Context) { let current_url = doc.url(); let offset_encoding = language_server.offset_encoding(); - let future = language_server.document_symbols(doc.identifier()); + let future = match language_server.document_symbols(doc.identifier()) { + Some(future) => future, + None => { + cx.editor + .set_error("Language server does not support document symbols"); + return; + } + }; cx.callback( future, @@ -365,7 +372,14 @@ pub fn workspace_symbol_picker(cx: &mut Context) { let current_url = doc.url(); let language_server = language_server!(cx.editor, doc); let offset_encoding = language_server.offset_encoding(); - let future = language_server.workspace_symbols("".to_string()); + let future = match language_server.workspace_symbols("".to_string()) { + Some(future) => future, + None => { + cx.editor + .set_error("Language server does not support workspace symbols"); + return; + } + }; cx.callback( future, @@ -493,7 +507,7 @@ pub fn code_action(cx: &mut Context) { let range = range_to_lsp_range(doc.text(), selection_range, offset_encoding); - let future = language_server.code_actions( + let future = match language_server.code_actions( doc.identifier(), range, // Filter and convert overlapping diagnostics @@ -509,7 +523,14 @@ pub fn code_action(cx: &mut Context) { .collect(), only: None, }, - ); + ) { + Some(future) => future, + None => { + cx.editor + .set_error("Language server does not support code actions"); + return; + } + }; cx.callback( future, @@ -617,9 +638,16 @@ pub fn execute_lsp_command(editor: &mut Editor, cmd: lsp::Command) { // the command is executed on the server and communicated back // to the client asynchronously using workspace edits - let command_future = language_server.command(cmd); + let future = match language_server.command(cmd) { + Some(future) => future, + None => { + editor.set_error("Language server does not support executing commands"); + return; + } + }; + tokio::spawn(async move { - let res = command_future.await; + let res = future.await; if let Err(e) = res { log::error!("execute LSP command: {}", e); @@ -853,7 +881,14 @@ pub fn goto_definition(cx: &mut Context) { let pos = doc.position(view.id, offset_encoding); - let future = language_server.goto_definition(doc.identifier(), pos, None); + let future = match language_server.goto_definition(doc.identifier(), pos, None) { + Some(future) => future, + None => { + cx.editor + .set_error("Language server does not support goto-definition"); + return; + } + }; cx.callback( future, @@ -871,7 +906,14 @@ pub fn goto_type_definition(cx: &mut Context) { let pos = doc.position(view.id, offset_encoding); - let future = language_server.goto_type_definition(doc.identifier(), pos, None); + let future = match language_server.goto_type_definition(doc.identifier(), pos, None) { + Some(future) => future, + None => { + cx.editor + .set_error("Language server does not support goto-type-definition"); + return; + } + }; cx.callback( future, @@ -889,7 +931,14 @@ pub fn goto_implementation(cx: &mut Context) { let pos = doc.position(view.id, offset_encoding); - let future = language_server.goto_implementation(doc.identifier(), pos, None); + let future = match language_server.goto_implementation(doc.identifier(), pos, None) { + Some(future) => future, + None => { + cx.editor + .set_error("Language server does not support goto-implementation"); + return; + } + }; cx.callback( future, @@ -907,7 +956,14 @@ pub fn goto_reference(cx: &mut Context) { let pos = doc.position(view.id, offset_encoding); - let future = language_server.goto_reference(doc.identifier(), pos, None); + let future = match language_server.goto_reference(doc.identifier(), pos, None) { + Some(future) => future, + None => { + cx.editor + .set_error("Language server does not support goto-reference"); + return; + } + }; cx.callback( future, @@ -950,7 +1006,13 @@ pub fn signature_help_impl(cx: &mut Context, invoked: SignatureHelpInvoked) { let future = match language_server.text_document_signature_help(doc.identifier(), pos, None) { Some(f) => f, - None => return, + None => { + if was_manually_invoked { + cx.editor + .set_error("Language server does not support signature-help"); + } + return; + } }; cx.callback( @@ -1051,7 +1113,14 @@ pub fn hover(cx: &mut Context) { let pos = doc.position(view.id, offset_encoding); - let future = language_server.text_document_hover(doc.identifier(), pos, None); + let future = match language_server.text_document_hover(doc.identifier(), pos, None) { + Some(future) => future, + None => { + cx.editor + .set_error("Language server does not support hover"); + return; + } + }; cx.callback( future, @@ -1121,8 +1190,16 @@ pub fn rename_symbol(cx: &mut Context) { let pos = doc.position(view.id, offset_encoding); - let task = language_server.rename_symbol(doc.identifier(), pos, input.to_string()); - match block_on(task) { + let future = + match language_server.rename_symbol(doc.identifier(), pos, input.to_string()) { + Some(future) => future, + None => { + cx.editor + .set_error("Language server does not support symbol renaming"); + return; + } + }; + match block_on(future) { Ok(edits) => apply_workspace_edit(cx.editor, offset_encoding, &edits), Err(err) => cx.editor.set_error(err.to_string()), } @@ -1137,7 +1214,15 @@ pub fn select_references_to_symbol_under_cursor(cx: &mut Context) { let pos = doc.position(view.id, offset_encoding); - let future = language_server.text_document_document_highlight(doc.identifier(), pos, None); + let future = match language_server.text_document_document_highlight(doc.identifier(), pos, None) + { + Some(future) => future, + None => { + cx.editor + .set_error("Language server does not support document highlight"); + return; + } + }; cx.callback( future, diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index 4e6ee4246775..ebb4fb46ae66 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -245,21 +245,13 @@ impl Completion { completion_item: lsp::CompletionItem, ) -> Option { let language_server = doc.language_server()?; - let completion_resolve_provider = language_server - .capabilities() - .completion_provider - .as_ref()? - .resolve_provider; - if completion_resolve_provider != Some(true) { - return None; - } - let future = language_server.resolve_completion_item(completion_item); + let future = language_server.resolve_completion_item(completion_item)?; let response = helix_lsp::block_on(future); match response { Ok(value) => serde_json::from_value(value).ok(), Err(err) => { - log::error!("execute LSP command: {}", err); + log::error!("Failed to resolve completion item: {}", err); None } } @@ -330,7 +322,10 @@ impl Completion { }; // This method should not block the compositor so we handle the response asynchronously. - let future = language_server.resolve_completion_item(current_item.clone()); + let future = match language_server.resolve_completion_item(current_item.clone()) { + Some(future) => future, + None => return false, + }; cx.callback( future, From f538b697597dccdd2492606858f0976c7cf7e4d2 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Tue, 22 Nov 2022 03:54:22 +0100 Subject: [PATCH 015/269] significantly improve treesitter performance while editing large files (#4716) * significantly improve treesitter performance while editing large files * Apply stylistic suggestions from code review Co-authored-by: Michael Davis * use PartialEq and Hash instead of a freestanding function Co-authored-by: Michael Davis --- Cargo.lock | 27 ++++++++- helix-core/Cargo.toml | 2 + helix-core/src/syntax.rs | 117 ++++++++++++++++++++++++++------------- 3 files changed, 106 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5833714d640a..a2b2ffd8c514 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,18 @@ dependencies = [ "version_check", ] +[[package]] +name = "ahash" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.18" @@ -400,18 +412,29 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038" +dependencies = [ + "ahash 0.8.2", ] [[package]] name = "helix-core" version = "0.6.0" dependencies = [ + "ahash 0.8.2", "arc-swap", "bitflags", "chrono", "encoding_rs", "etcetera", + "hashbrown 0.13.1", "helix-loader", "log", "once_cell", @@ -1288,7 +1311,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137" dependencies = [ - "hashbrown", + "hashbrown 0.12.3", "regex", ] diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 45272f980058..eb886c90c217 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -30,6 +30,8 @@ once_cell = "1.16" arc-swap = "1" regex = "1" bitflags = "1.3" +ahash = "0.8.2" +hashbrown = { version = "0.13.1", features = ["raw"] } log = "0.4" serde = { version = "1.0", features = ["derive"] } diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index b567a8ab7339..8dc34a3e3631 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -7,8 +7,10 @@ use crate::{ Rope, RopeSlice, Tendril, }; +use ahash::RandomState; use arc_swap::{ArcSwap, Guard}; use bitflags::bitflags; +use hashbrown::raw::RawTable; use slotmap::{DefaultKey as LayerId, HopSlotMap}; use std::{ @@ -16,7 +18,8 @@ use std::{ cell::RefCell, collections::{HashMap, VecDeque}, fmt, - mem::replace, + hash::{Hash, Hasher}, + mem::{replace, transmute}, path::Path, str::FromStr, sync::Arc, @@ -770,30 +773,38 @@ impl Syntax { // Convert the changeset into tree sitter edits. let edits = generate_edits(old_source, changeset); + // This table allows inverse indexing of `layers`. + // That is by hashing a `Layer` you can find + // the `LayerId` of an existing equivalent `Layer` in `layers`. + // + // It is used to determine if a new layer exists for an injection + // or if an existing layer needs to be updated. + let mut layers_table = RawTable::with_capacity(self.layers.len()); + let layers_hasher = RandomState::new(); // Use the edits to update all layers markers - if !edits.is_empty() { - fn point_add(a: Point, b: Point) -> Point { - if b.row > 0 { - Point::new(a.row.saturating_add(b.row), b.column) - } else { - Point::new(0, a.column.saturating_add(b.column)) - } + fn point_add(a: Point, b: Point) -> Point { + if b.row > 0 { + Point::new(a.row.saturating_add(b.row), b.column) + } else { + Point::new(0, a.column.saturating_add(b.column)) } - fn point_sub(a: Point, b: Point) -> Point { - if a.row > b.row { - Point::new(a.row.saturating_sub(b.row), a.column) - } else { - Point::new(0, a.column.saturating_sub(b.column)) - } + } + fn point_sub(a: Point, b: Point) -> Point { + if a.row > b.row { + Point::new(a.row.saturating_sub(b.row), a.column) + } else { + Point::new(0, a.column.saturating_sub(b.column)) } + } - for layer in self.layers.values_mut() { - // The root layer always covers the whole range (0..usize::MAX) - if layer.depth == 0 { - layer.flags = LayerUpdateFlags::MODIFIED; - continue; - } + for (layer_id, layer) in self.layers.iter_mut() { + // The root layer always covers the whole range (0..usize::MAX) + if layer.depth == 0 { + layer.flags = LayerUpdateFlags::MODIFIED; + continue; + } + if !edits.is_empty() { for range in &mut layer.ranges { // Roughly based on https://github.com/tree-sitter/tree-sitter/blob/ddeaa0c7f534268b35b4f6cb39b52df082754413/lib/src/subtree.c#L691-L720 for edit in edits.iter().rev() { @@ -858,6 +869,12 @@ impl Syntax { } } } + + let hash = layers_hasher.hash_one(layer); + // Safety: insert_no_grow is unsafe because it assumes that the table + // has enough capacity to hold additional elements. + // This is always the case as we reserved enough capacity above. + unsafe { layers_table.insert_no_grow(hash, layer_id) }; } PARSER.with(|ts_parser| { @@ -982,27 +999,23 @@ impl Syntax { let depth = layer.depth + 1; // TODO: can't inline this since matches borrows self.layers for (config, ranges) in injections { - // Find an existing layer - let layer = self - .layers - .iter_mut() - .find(|(_, layer)| { - layer.depth == depth && // TODO: track parent id instead - layer.config.language == config.language && layer.ranges == ranges + let new_layer = LanguageLayer { + tree: None, + config, + depth, + ranges, + flags: LayerUpdateFlags::empty(), + }; + + // Find an identical existing layer + let layer = layers_table + .get(layers_hasher.hash_one(&new_layer), |&it| { + self.layers[it] == new_layer }) - .map(|(id, _layer)| id); + .copied(); // ...or insert a new one. - let layer_id = layer.unwrap_or_else(|| { - self.layers.insert(LanguageLayer { - tree: None, - config, - depth, - ranges, - // set the modified flag to ensure the layer is parsed - flags: LayerUpdateFlags::empty(), - }) - }); + let layer_id = layer.unwrap_or_else(|| self.layers.insert(new_layer)); queue.push_back(layer_id); } @@ -1139,6 +1152,34 @@ pub struct LanguageLayer { flags: LayerUpdateFlags, } +/// This PartialEq implementation only checks if that +/// two layers are theoretically identical (meaning they highlight the same text range with the same language). +/// It does not check whether the layers have the same internal treesitter +/// state. +impl PartialEq for LanguageLayer { + fn eq(&self, other: &Self) -> bool { + self.depth == other.depth + && self.config.language == other.config.language + && self.ranges == other.ranges + } +} + +/// Hash implementation belongs to PartialEq implementation above. +/// See its documentation for details. +impl Hash for LanguageLayer { + fn hash(&self, state: &mut H) { + self.depth.hash(state); + // The transmute is necessary here because tree_sitter::Language does not derive Hash at the moment. + // However it does use #[repr] transparent so the transmute here is safe + // as `Language` (which `Grammar` is an alias for) is just a newtype wrapper around a (thin) pointer. + // This is also compatible with the PartialEq implementation of language + // as that is just a pointer comparison. + let language: *const () = unsafe { transmute(self.config.language) }; + language.hash(state); + self.ranges.hash(state); + } +} + impl LanguageLayer { pub fn tree(&self) -> &Tree { // TODO: no unwrap From 33ae498e9f23f8f39a41abf8d79c09fc6964c2ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Tue, 22 Nov 2022 18:05:29 +0900 Subject: [PATCH 016/269] ci: Remove a bunch of actions-rs/cargo uses --- .github/workflows/build.yml | 38 ++++++++--------------------------- .github/workflows/release.yml | 5 +---- 2 files changed, 9 insertions(+), 34 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 157343618bf4..e6b319f973e6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,9 +31,7 @@ jobs: - uses: Swatinem/rust-cache@v1 - name: Run cargo check - uses: actions-rs/cargo@v1 - with: - command: check + run: cargo check test: name: Test Suite @@ -61,15 +59,10 @@ jobs: restore-keys: ${{ runner.os }}-stable-v${{ env.CACHE_VERSION }}-tree-sitter-grammars- - name: Run cargo test - uses: actions-rs/cargo@v1 - with: - command: test - args: --workspace + run: cargo test --workspace - name: Run cargo integration-test - uses: actions-rs/cargo@v1 - with: - command: integration-test + run: cargo integration-test strategy: matrix: @@ -92,22 +85,13 @@ jobs: - uses: Swatinem/rust-cache@v1 - name: Run cargo fmt - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check + run: cargo fmt --all -- --check - name: Run cargo clippy - uses: actions-rs/cargo@v1 - with: - command: clippy - args: --workspace --all-targets -- -D warnings + run: cargo clippy --workspace --all-targets -- -D warnings - name: Run cargo doc - uses: actions-rs/cargo@v1 - with: - command: doc - args: --no-deps --workspace --document-private-items + run: cargo doc --no-deps --workspace --document-private-items env: RUSTDOCFLAGS: -D warnings @@ -127,10 +111,7 @@ jobs: - uses: Swatinem/rust-cache@v1 - name: Generate docs - uses: actions-rs/cargo@v1 - with: - command: xtask - args: docgen + run: cargo xtask docgen - name: Check uncommitted documentation changes run: | @@ -155,7 +136,4 @@ jobs: - uses: Swatinem/rust-cache@v1 - name: Generate docs - uses: actions-rs/cargo@v1 - with: - command: xtask - args: query-check + run: cargo xtask query-check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e7aca89bb72a..8e805de295d3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,10 +34,7 @@ jobs: - uses: Swatinem/rust-cache@v1 - name: Fetch tree-sitter grammars - uses: actions-rs/cargo@v1 - with: - command: run - args: --package=helix-loader --bin=hx-loader + run: cargo run --package=helix-loader --bin=hx-loader - name: Bundle grammars run: tar cJf grammars.tar.xz -C runtime/grammars/sources . From 6aa345a6ce905a0f65e3526f93c3a46a777eaa39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Tue, 22 Nov 2022 18:05:42 +0900 Subject: [PATCH 017/269] ci: Simplify tag name fetching (set-output is deprecated) --- .github/workflows/release.yml | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8e805de295d3..7e184ff68468 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -218,16 +218,6 @@ jobs: - uses: actions/download-artifact@v3 - - name: Calculate tag name - run: | - name=dev - if [[ $GITHUB_REF == refs/tags/* ]]; then - name=${GITHUB_REF:10} - fi - echo ::set-output name=val::$name - echo TAG=$name >> $GITHUB_ENV - id: tagname - - name: Build archive shell: bash run: | @@ -247,7 +237,7 @@ jobs: if [[ $platform =~ "windows" ]]; then exe=".exe" fi - pkgname=helix-$TAG-$platform + pkgname=helix-$GITHUB_REF_NAME-$platform mkdir $pkgname cp $source/LICENSE $source/README.md $pkgname mkdir $pkgname/contrib @@ -267,7 +257,7 @@ jobs: fi done - tar cJf dist/helix-$TAG-source.tar.xz -C $source . + tar cJf dist/helix-$GITHUB_REF_NAME-source.tar.xz -C $source . mv dist $source/ - name: Upload binaries to release @@ -277,7 +267,7 @@ jobs: repo_token: ${{ secrets.GITHUB_TOKEN }} file: dist/* file_glob: true - tag: ${{ steps.tagname.outputs.val }} + tag: ${{ github.ref_name }} overwrite: true - name: Upload binaries as artifact From 5ad3befe9a802fc1b219355fb2cfd495aa5964d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Nov 2022 18:15:36 +0900 Subject: [PATCH 018/269] build(deps): bump Swatinem/rust-cache from 1 to 2 (#4843) Bumps [Swatinem/rust-cache](https://github.com/Swatinem/rust-cache) from 1 to 2. - [Release notes](https://github.com/Swatinem/rust-cache/releases) - [Changelog](https://github.com/Swatinem/rust-cache/blob/master/CHANGELOG.md) - [Commits](https://github.com/Swatinem/rust-cache/compare/v1...v2) --- updated-dependencies: - dependency-name: Swatinem/rust-cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 10 +++++----- .github/workflows/release.yml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e6b319f973e6..526c7b3c0055 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,7 +28,7 @@ jobs: profile: minimal override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Run cargo check run: cargo check @@ -49,7 +49,7 @@ jobs: profile: minimal override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Cache test tree-sitter grammar uses: actions/cache@v3 @@ -82,7 +82,7 @@ jobs: override: true components: rustfmt, clippy - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Run cargo fmt run: cargo fmt --all -- --check @@ -108,7 +108,7 @@ jobs: profile: minimal override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Generate docs run: cargo xtask docgen @@ -133,7 +133,7 @@ jobs: profile: minimal override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Generate docs run: cargo xtask query-check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7e184ff68468..c242f089464b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: profile: minimal override: true - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 - name: Fetch tree-sitter grammars run: cargo run --package=helix-loader --bin=hx-loader From 642a961c032b2a7e7fa67bfc3da54588d0ae8c5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Nov 2022 13:24:37 -0600 Subject: [PATCH 019/269] build(deps): bump tokio from 1.21.2 to 1.22.0 (#4846) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.21.2 to 1.22.0. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.21.2...tokio-1.22.0) --- updated-dependencies: - dependency-name: tokio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- helix-lsp/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a2b2ffd8c514..616c5317f359 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1219,9 +1219,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.21.2" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" dependencies = [ "autocfg", "bytes", diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index ad432d96f064..41884e73a249 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -22,6 +22,6 @@ lsp-types = { version = "0.93", features = ["proposed"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" -tokio = { version = "1.21", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } +tokio = { version = "1.22", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } tokio-stream = "0.1.11" which = "4.2" From 42e37a571e75aaf4feb1717dfebe8cf215e535dd Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 22 Nov 2022 21:28:49 -0600 Subject: [PATCH 020/269] Apply transactions to all views (#4733) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add a test case for updating jumplists across windows * Apply transactions to all views on history changes This ensures that jumplist selections follow changes in documents, even when there are multiple views (for example a split where both windows edit the same document). * Leave TODOs for cleaning up View::apply * Use Iterator::reduce to compose history transactions Co-authored-by: Blaž Hrastnik Co-authored-by: Blaž Hrastnik --- helix-core/src/history.rs | 18 +++++++++++++++++- helix-term/src/ui/editor.rs | 26 +++++++++++++++++++++++--- helix-term/tests/test/splits.rs | 26 ++++++++++++++++++++++++++ helix-view/src/lib.rs | 8 +++----- helix-view/src/macros.rs | 2 +- helix-view/src/view.rs | 1 + 6 files changed, 71 insertions(+), 10 deletions(-) diff --git a/helix-core/src/history.rs b/helix-core/src/history.rs index 51174c02475e..697f29b4ec98 100644 --- a/helix-core/src/history.rs +++ b/helix-core/src/history.rs @@ -54,7 +54,7 @@ pub struct History { } /// A single point in history. See [History] for more information. -#[derive(Debug)] +#[derive(Debug, Clone)] struct Revision { parent: usize, last_child: Option, @@ -119,6 +119,22 @@ impl History { self.current == 0 } + /// Returns the changes since the given revision composed into a transaction. + /// Returns None if there are no changes between the current and given revisions. + pub fn changes_since(&self, revision: usize) -> Option { + if self.at_root() || self.current >= revision { + return None; + } + + // The bounds are checked in the if condition above: + // `revision` is known to be `< self.current`. + self.revisions[revision..self.current] + .iter() + .map(|revision| &revision.transaction) + .cloned() + .reduce(|acc, transaction| acc.compose(transaction)) + } + /// Undo the last edit. pub fn undo(&mut self) -> Option<&Transaction> { if self.at_root() { diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 6c8ee2d95e9c..44f89b77ed15 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -1337,7 +1337,9 @@ impl Component for EditorView { cx.editor.status_msg = None; let mode = cx.editor.mode(); - let (view, _) = current!(cx.editor); + let (view, doc) = current!(cx.editor); + let original_doc_id = doc.id(); + let original_doc_revision = doc.get_current_revision(); let focus = view.id; if let Some(on_next_key) = self.on_next_key.take() { @@ -1413,13 +1415,31 @@ impl Component for EditorView { let view = view_mut!(cx.editor, focus); let doc = doc_mut!(cx.editor, &view.doc); - view.ensure_cursor_in_view(doc, config.scrolloff); - // Store a history state if not in insert mode. This also takes care of // committing changes when leaving insert mode. if mode != Mode::Insert { doc.append_changes_to_history(view.id); } + + // If the current document has been changed, apply the changes to all views. + // This ensures that selections in jumplists follow changes. + if doc.id() == original_doc_id + && doc.get_current_revision() > original_doc_revision + { + if let Some(transaction) = + doc.history.get_mut().changes_since(original_doc_revision) + { + let doc = doc!(cx.editor, &original_doc_id); + for (view, _focused) in cx.editor.tree.views_mut() { + view.apply(&transaction, doc); + } + } + } + + let view = view_mut!(cx.editor, focus); + let doc = doc_mut!(cx.editor, &view.doc); + + view.ensure_cursor_in_view(doc, config.scrolloff); } EventResult::Consumed(callback) diff --git a/helix-term/tests/test/splits.rs b/helix-term/tests/test/splits.rs index 5807413a267e..a51de365850e 100644 --- a/helix-term/tests/test/splits.rs +++ b/helix-term/tests/test/splits.rs @@ -127,3 +127,29 @@ async fn test_split_write_quit_same_file() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test(flavor = "multi_thread")] +async fn test_changes_in_splits_apply_to_all_views() -> anyhow::Result<()> { + // See . + // Transactions must be applied to any view that has the changed document open. + // This sequence would panic since the jumplist entry would be modified in one + // window but not the other. Attempting to update the changelist in the other + // window would cause a panic since it would point outside of the document. + + // The key sequence here: + // * v Create a vertical split of the current buffer. + // Both views look at the same doc. + // * [ Add a line ending to the beginning of the document. + // The cursor is now at line 2 in window 2. + // * Save that selection to the jumplist in window 2. + // * w Switch to window 1. + // * kd Delete line 1 in window 1. + // * q Close window 1, focusing window 2. + // * d Delete line 1 in window 2. + // + // This panicked in the past because the jumplist entry on line 2 of window 2 + // was not updated and after the `kd` step, pointed outside of the document. + test(("#[|]#", "v[wkdqd", "#[|]#")).await?; + + Ok(()) +} diff --git a/helix-view/src/lib.rs b/helix-view/src/lib.rs index 4c32b356b9ea..9cf36ae0505c 100644 --- a/helix-view/src/lib.rs +++ b/helix-view/src/lib.rs @@ -71,12 +71,10 @@ pub fn align_view(doc: &Document, view: &mut View, align: Align) { pub fn apply_transaction( transaction: &helix_core::Transaction, doc: &mut Document, - view: &mut View, + view: &View, ) -> bool { - // This is a short function but it's easy to call `Document::apply` - // without calling `View::apply` or in the wrong order. The transaction - // must be applied to the document before the view. - doc.apply(transaction, view.id) && view.apply(transaction, doc) + // TODO remove this helper function. Just call Document::apply everywhere directly. + doc.apply(transaction, view.id) } pub use document::Document; diff --git a/helix-view/src/macros.rs b/helix-view/src/macros.rs index 53ab434622d4..ee9cd4111795 100644 --- a/helix-view/src/macros.rs +++ b/helix-view/src/macros.rs @@ -67,7 +67,7 @@ macro_rules! view { #[macro_export] macro_rules! doc { ($editor:expr, $id:expr) => {{ - $editor.documents[$id] + &$editor.documents[$id] }}; ($editor:expr) => {{ $crate::current_ref!($editor).1 diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 8aa4760dcc69..c917a1abc054 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -351,6 +351,7 @@ impl View { /// which applies a transaction to the [`Document`] and view together. pub fn apply(&mut self, transaction: &Transaction, doc: &Document) -> bool { self.jumps.apply(transaction, doc); + // TODO: remove the boolean return. This is unused. true } } From 26ec1cf39a3c5f548f199918b0a84d614a5c6be7 Mon Sep 17 00:00:00 2001 From: alois31 <36605164+alois31@users.noreply.github.com> Date: Wed, 23 Nov 2022 04:49:02 +0100 Subject: [PATCH 021/269] Add QML language support (#4842) Fixes https://github.com/helix-editor/helix/issues/2771 --- book/src/generated/lang-support.md | 1 + languages.toml | 13 +++++ runtime/queries/qml/highlights.scm | 90 ++++++++++++++++++++++++++++++ runtime/queries/qml/indents.scm | 6 ++ runtime/queries/qml/injections.scm | 16 ++++++ 5 files changed, 126 insertions(+) create mode 100644 runtime/queries/qml/highlights.scm create mode 100644 runtime/queries/qml/indents.scm create mode 100644 runtime/queries/qml/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 59b60851aac6..ac95503697cd 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -93,6 +93,7 @@ | protobuf | ✓ | | ✓ | | | purescript | ✓ | | | `purescript-language-server` | | python | ✓ | ✓ | ✓ | `pylsp` | +| qml | ✓ | | ✓ | `qmlls` | | r | ✓ | | | `R` | | racket | | | | `racket` | | regex | ✓ | | | | diff --git a/languages.toml b/languages.toml index 47d77feed888..1e7dcbf79efa 100644 --- a/languages.toml +++ b/languages.toml @@ -1980,3 +1980,16 @@ language-server = { command = "bicep-langserver" } [[grammar]] name = "bicep" source = { git = "https://github.com/the-mikedavis/tree-sitter-bicep", rev = "d8e097fcfa143854861ef737161163a09cc2916b" } + +[[language]] +name = "qml" +scope = "source.qml" +file-types = ["qml"] +roots = [] +language-server = { command = "qmlls" } +indent = { tab-width = 4, unit = " " } +grammar = "qmljs" + +[[grammar]] +name = "qmljs" +source = { git = "https://github.com/yuja/tree-sitter-qmljs", rev = "0b2b25bcaa7d4925d5f0dda16f6a99c588a437f1" } diff --git a/runtime/queries/qml/highlights.scm b/runtime/queries/qml/highlights.scm new file mode 100644 index 000000000000..11178fcdb722 --- /dev/null +++ b/runtime/queries/qml/highlights.scm @@ -0,0 +1,90 @@ +(comment) @comment + +(ui_import + source: _ @namespace + version: _? @constant + alias: _? @namespace) + +(ui_pragma + name: (identifier) @attribute + value: (identifier)? @constant) + +(ui_annotation + "@" @punctuation + type_name: _ @type) + +;;; Declarations + +(enum_declaration + name: (identifier) @type) + +(enum_assignment + name: (identifier) @constant + value: _ @constant) + +(enum_body + name: (identifier) @constant) + +(ui_inline_component + name: (identifier) @type) + +(ui_object_definition + type_name: _ @type) + +(ui_object_definition_binding + type_name: _ @type + name: _ @variable.other.member) + +(ui_property + type: _ @type + name: (identifier) @variable.other.member) + +(ui_signal + name: (identifier) @function) + +(ui_signal_parameter + name: (identifier) @variable.parameter + type: _ @type) + +(ui_signal_parameter + type: _ @type + name: (identifier) @variable.parameter);;; Properties and bindings + +;;; Bindings + +(ui_binding + name: _ @variable.other.member) + +;;; Other + +[ + "(" + ")" + "{" + "}" +] @punctuation.bracket + +(ui_list_property_type [ + "<" + ">" +] @punctuation.bracket) + +[ + "," + "." + ":" +] @punctuation.delimiter + +[ + "as" + "component" + "default" + "enum" + "import" + "on" + "pragma" + "property" + "readonly" + "required" + "signal" +] @keyword diff --git a/runtime/queries/qml/indents.scm b/runtime/queries/qml/indents.scm new file mode 100644 index 000000000000..07492283721a --- /dev/null +++ b/runtime/queries/qml/indents.scm @@ -0,0 +1,6 @@ +[ + (enum_body) + (ui_object_initializer) +] @indent + +"}" @outdent diff --git a/runtime/queries/qml/injections.scm b/runtime/queries/qml/injections.scm new file mode 100644 index 000000000000..1ce987d35080 --- /dev/null +++ b/runtime/queries/qml/injections.scm @@ -0,0 +1,16 @@ +((comment) @injection.content + (#set! injection.language "comment")) + +([ + (empty_statement) + (expression_statement) + (function_declaration) + (generator_function_declaration) + (statement_block) + (switch_statement) + (try_statement) + (variable_declaration) + (with_statement) + ] @injection.content + (#set! injection.include-children) + (#set! injection.language "javascript")) From 590a628460c8fa8a4e101541d67289fa2fac95b5 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 23 Nov 2022 05:51:17 +0200 Subject: [PATCH 022/269] tutor: Add missing quotes (#4832) --- runtime/tutor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/tutor b/runtime/tutor index eb1d9885350e..957af64035f4 100644 --- a/runtime/tutor +++ b/runtime/tutor @@ -845,11 +845,11 @@ lines. Type q to repeat the macro from register @ (the default). 1. Move the cursor to the first line marked '-->' below. - Ensure your cursor is on the > of the arrow. + Ensure your cursor is on the '>' of the arrow. 2. Type Q to start recording. 3. Edit the line to look like the bottom one. 4. Exit insert and Type Q again to stop recording. - 5. Move to the line below and put your cursor on the > again. + 5. Move to the line below and put your cursor on '>' again. 6. Type q to repeat the macro. --> ... sentence doesn't have it's first and last ... . From 94eb3de7767c5d16344bec9634028f346cd867bb Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 23 Nov 2022 08:57:09 -0600 Subject: [PATCH 023/269] Add test case that panics on undo This case panics since undo/redo call View::apply and here, the edit that moves the jumplist selection out-of-bounds is not yet applied when View::apply is called in undo/redo. View::apply should only be called by the EditorView now. --- helix-term/tests/test/commands.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index 114bf22211a5..27dbd9d7c3c5 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -283,3 +283,19 @@ async fn test_multi_selection_shell_commands() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test(flavor = "multi_thread")] +async fn test_undo_redo() -> anyhow::Result<()> { + // A jumplist selection is passed through an edit and then an undo and then a redo. + // + // * [ Add a newline at line start. We're now on line 2. + // * Save the selection on line 2 in the jumplist. + // * kd Delete line 1. The jumplist selection should be adjusted to the new line 1. + // * uU Undo and redo the `kd` edit. + // * Jump back in the jumplist. This would panic if the jumplist were not being + // updated correctly. + // * Jump forward to line 1. + test(("#[|]#", "[kduU", "#[|]#")).await?; + + Ok(()) +} From fd00f3a70eb626242bb2fcc9bddf2c4d94580a9a Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 23 Nov 2022 08:57:03 -0600 Subject: [PATCH 024/269] Don't apply transactions to Views in undo/redo View::apply should only be called by EditorView after 42e37a571e75aaf4feb1717dfebe8cf215e535dd. This change removes the duplicate calls within undo/redo which could cause a panic. --- helix-term/src/commands.rs | 8 ++++---- helix-term/src/commands/typed.rs | 4 ++-- helix-view/src/document.rs | 24 ++++++++++++------------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 8af5a7e3e400..4eb9742ff70e 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3302,7 +3302,7 @@ fn undo(cx: &mut Context) { let count = cx.count(); let (view, doc) = current!(cx.editor); for _ in 0..count { - if !doc.undo(view) { + if !doc.undo(view.id) { cx.editor.set_status("Already at oldest change"); break; } @@ -3313,7 +3313,7 @@ fn redo(cx: &mut Context) { let count = cx.count(); let (view, doc) = current!(cx.editor); for _ in 0..count { - if !doc.redo(view) { + if !doc.redo(view.id) { cx.editor.set_status("Already at newest change"); break; } @@ -3325,7 +3325,7 @@ fn earlier(cx: &mut Context) { let (view, doc) = current!(cx.editor); for _ in 0..count { // rather than doing in batch we do this so get error halfway - if !doc.earlier(view, UndoKind::Steps(1)) { + if !doc.earlier(view.id, UndoKind::Steps(1)) { cx.editor.set_status("Already at oldest change"); break; } @@ -3337,7 +3337,7 @@ fn later(cx: &mut Context) { let (view, doc) = current!(cx.editor); for _ in 0..count { // rather than doing in batch we do this so get error halfway - if !doc.later(view, UndoKind::Steps(1)) { + if !doc.later(view.id, UndoKind::Steps(1)) { cx.editor.set_status("Already at newest change"); break; } diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index b8f99ff369d2..475f14d1de3c 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -481,7 +481,7 @@ fn earlier( let uk = args.join(" ").parse::().map_err(|s| anyhow!(s))?; let (view, doc) = current!(cx.editor); - let success = doc.earlier(view, uk); + let success = doc.earlier(view.id, uk); if !success { cx.editor.set_status("Already at oldest change"); } @@ -500,7 +500,7 @@ fn later( let uk = args.join(" ").parse::().map_err(|s| anyhow!(s))?; let (view, doc) = current!(cx.editor); - let success = doc.later(view, uk); + let success = doc.later(view.id, uk); if !success { cx.editor.set_status("Already at newest change"); } diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 087085283391..0eb54f25fa6e 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -857,11 +857,11 @@ impl Document { success } - fn undo_redo_impl(&mut self, view: &mut View, undo: bool) -> bool { + fn undo_redo_impl(&mut self, view_id: ViewId, undo: bool) -> bool { let mut history = self.history.take(); let txn = if undo { history.undo() } else { history.redo() }; let success = if let Some(txn) = txn { - self.apply_impl(txn, view.id) && view.apply(txn, self) + self.apply_impl(txn, view_id) } else { false }; @@ -875,13 +875,13 @@ impl Document { } /// Undo the last modification to the [`Document`]. Returns whether the undo was successful. - pub fn undo(&mut self, view: &mut View) -> bool { - self.undo_redo_impl(view, true) + pub fn undo(&mut self, view_id: ViewId) -> bool { + self.undo_redo_impl(view_id, true) } /// Redo the last modification to the [`Document`]. Returns whether the redo was successful. - pub fn redo(&mut self, view: &mut View) -> bool { - self.undo_redo_impl(view, false) + pub fn redo(&mut self, view_id: ViewId) -> bool { + self.undo_redo_impl(view_id, false) } pub fn savepoint(&mut self) { @@ -894,7 +894,7 @@ impl Document { } } - fn earlier_later_impl(&mut self, view: &mut View, uk: UndoKind, earlier: bool) -> bool { + fn earlier_later_impl(&mut self, view_id: ViewId, uk: UndoKind, earlier: bool) -> bool { let txns = if earlier { self.history.get_mut().earlier(uk) } else { @@ -902,7 +902,7 @@ impl Document { }; let mut success = false; for txn in txns { - if self.apply_impl(&txn, view.id) && view.apply(&txn, self) { + if self.apply_impl(&txn, view_id) { success = true; } } @@ -914,13 +914,13 @@ impl Document { } /// Undo modifications to the [`Document`] according to `uk`. - pub fn earlier(&mut self, view: &mut View, uk: UndoKind) -> bool { - self.earlier_later_impl(view, uk, true) + pub fn earlier(&mut self, view_id: ViewId, uk: UndoKind) -> bool { + self.earlier_later_impl(view_id, uk, true) } /// Redo modifications to the [`Document`] according to `uk`. - pub fn later(&mut self, view: &mut View, uk: UndoKind) -> bool { - self.earlier_later_impl(view, uk, false) + pub fn later(&mut self, view_id: ViewId, uk: UndoKind) -> bool { + self.earlier_later_impl(view_id, uk, false) } /// Commit pending changes to history From 4a103db6228ba54e0f36bbebb95d25867458f473 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 23 Nov 2022 09:35:07 -0600 Subject: [PATCH 025/269] Apply inversions to Views on undo/redo When using undo/redo, the history revision can be decremented. In that case we should apply the inversions since the given revision in History::changes_since. This prevents panics with jumplist operations when a session uses undo/redo to move the jumplist selection outside of the document. --- helix-core/src/history.rs | 24 ++++++++++++++---------- helix-term/src/ui/editor.rs | 2 +- helix-term/tests/test/commands.rs | 9 +++++++++ 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/helix-core/src/history.rs b/helix-core/src/history.rs index 697f29b4ec98..5f9fa71e4b9b 100644 --- a/helix-core/src/history.rs +++ b/helix-core/src/history.rs @@ -122,17 +122,21 @@ impl History { /// Returns the changes since the given revision composed into a transaction. /// Returns None if there are no changes between the current and given revisions. pub fn changes_since(&self, revision: usize) -> Option { - if self.at_root() || self.current >= revision { - return None; - } + use std::cmp::Ordering::*; - // The bounds are checked in the if condition above: - // `revision` is known to be `< self.current`. - self.revisions[revision..self.current] - .iter() - .map(|revision| &revision.transaction) - .cloned() - .reduce(|acc, transaction| acc.compose(transaction)) + match revision.cmp(&self.current) { + Equal => None, + Greater => self.revisions[self.current + 1..=revision] + .iter() + .map(|revision| &revision.inversion) + .cloned() + .reduce(|acc, inversion| acc.compose(inversion)), + Less => self.revisions[revision + 1..=self.current] + .iter() + .map(|revision| &revision.transaction) + .cloned() + .reduce(|acc, transaction| acc.compose(transaction)), + } } /// Undo the last edit. diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 44f89b77ed15..737125031e99 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -1424,7 +1424,7 @@ impl Component for EditorView { // If the current document has been changed, apply the changes to all views. // This ensures that selections in jumplists follow changes. if doc.id() == original_doc_id - && doc.get_current_revision() > original_doc_revision + && doc.get_current_revision() != original_doc_revision { if let Some(transaction) = doc.history.get_mut().changes_since(original_doc_revision) diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index 27dbd9d7c3c5..012957045587 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -286,6 +286,15 @@ async fn test_multi_selection_shell_commands() -> anyhow::Result<()> { #[tokio::test(flavor = "multi_thread")] async fn test_undo_redo() -> anyhow::Result<()> { + // A jumplist selection is created at a point which is undone. + // + // * 2[ Add two newlines at line start. We're now on line 3. + // * Save the selection on line 3 in the jumplist. + // * u Undo the two newlines. We're now on line 1. + // * Jump forward an back again in the jumplist. This would panic + // if the jumplist were not being updated correctly. + test(("#[|]#", "2[u", "#[|]#")).await?; + // A jumplist selection is passed through an edit and then an undo and then a redo. // // * [ Add a newline at line start. We're now on line 2. From a3f321a531554b51160f3fe7e6da1c269030f3b6 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 23 Nov 2022 13:02:00 -0600 Subject: [PATCH 026/269] Follow parent links when calculating changes since a revision The 'revisions' field on History can't be treated as linear: each Revision in the revisions Vec has a parent link and an optional child link. We can follow those to unroll the recent history. --- helix-core/src/history.rs | 31 +++++++++++++++++++++---------- helix-term/tests/test/commands.rs | 3 +++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/helix-core/src/history.rs b/helix-core/src/history.rs index 5f9fa71e4b9b..825092423e00 100644 --- a/helix-core/src/history.rs +++ b/helix-core/src/history.rs @@ -126,16 +126,27 @@ impl History { match revision.cmp(&self.current) { Equal => None, - Greater => self.revisions[self.current + 1..=revision] - .iter() - .map(|revision| &revision.inversion) - .cloned() - .reduce(|acc, inversion| acc.compose(inversion)), - Less => self.revisions[revision + 1..=self.current] - .iter() - .map(|revision| &revision.transaction) - .cloned() - .reduce(|acc, transaction| acc.compose(transaction)), + Less => { + let mut child = self.revisions[revision].last_child?.get(); + let mut transaction = self.revisions[child].transaction.clone(); + while child != self.current { + child = self.revisions[child].last_child?.get(); + transaction = transaction.compose(self.revisions[child].transaction.clone()); + } + Some(transaction) + } + Greater => { + let mut inversion = self.revisions[revision].inversion.clone(); + let mut parent = self.revisions[revision].parent; + while parent != self.current { + parent = self.revisions[parent].parent; + if parent == 0 { + return None; + } + inversion = inversion.compose(self.revisions[parent].inversion.clone()); + } + Some(inversion) + } } } diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index 012957045587..95bd95b73a7e 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -306,5 +306,8 @@ async fn test_undo_redo() -> anyhow::Result<()> { // * Jump forward to line 1. test(("#[|]#", "[kduU", "#[|]#")).await?; + // In this case we 'redo' manually to ensure that the transactions are composing correctly. + test(("#[|]#", "[u[u", "#[|]#")).await?; + Ok(()) } From 452f7d071ceb57aad9da36473e6d2a0f0bedb462 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 22 Oct 2022 12:51:20 -0500 Subject: [PATCH 027/269] Improve Edoc highlighting within Erlang This highlights edoc within Erlang comments. The trick was to have the Erlang grammar consume newlines and then give them to EDoc in the injection to use so that line-wise elements could be parsed accurately. --- languages.toml | 4 ++-- runtime/queries/edoc/highlights.scm | 2 ++ runtime/queries/edoc/injections.scm | 4 ++-- runtime/queries/erlang/highlights.scm | 10 ++++++---- runtime/queries/erlang/injections.scm | 9 +++++++-- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/languages.toml b/languages.toml index 1e7dcbf79efa..9007cc657c29 100644 --- a/languages.toml +++ b/languages.toml @@ -1184,7 +1184,7 @@ language-server = { command = "erlang_ls" } [[grammar]] name = "erlang" -source = { git = "https://github.com/the-mikedavis/tree-sitter-erlang", rev = "0e7d677d11a7379686c53c616825714ccb728059" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-erlang", rev = "ce0ed253d72c199ab93caba7542b6f62075339c4" } [[language]] name = "kotlin" @@ -1574,7 +1574,7 @@ indent = { tab-width = 4, unit = " " } [[grammar]] name = "edoc" -source = { git = "https://github.com/the-mikedavis/tree-sitter-edoc", rev = "1691ec0aa7ad1ed9fa295590545f27e570d12d60" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-edoc", rev = "74774af7b45dd9cefbf9510328fc6ff2374afc50" } [[language]] name = "jsdoc" diff --git a/runtime/queries/edoc/highlights.scm b/runtime/queries/edoc/highlights.scm index 4267cb9e0b1f..5bab7992888e 100644 --- a/runtime/queries/edoc/highlights.scm +++ b/runtime/queries/edoc/highlights.scm @@ -48,3 +48,5 @@ (language_identifier) (quote_content) ] @markup.raw.block + +(parameter) @variable.parameter diff --git a/runtime/queries/edoc/injections.scm b/runtime/queries/edoc/injections.scm index 9630995b69cc..28c44b9f457e 100644 --- a/runtime/queries/edoc/injections.scm +++ b/runtime/queries/edoc/injections.scm @@ -16,5 +16,5 @@ (tag) @_tag (argument) @injection.content) (#eq? @_tag "@type") - (#set injection.language "erlang") - (#set injection.include-children)) + (#set! injection.language "erlang") + (#set! injection.include-children)) diff --git a/runtime/queries/erlang/highlights.scm b/runtime/queries/erlang/highlights.scm index 58c8fb8af99c..050fb613c3a0 100644 --- a/runtime/queries/erlang/highlights.scm +++ b/runtime/queries/erlang/highlights.scm @@ -94,10 +94,6 @@ (unary_operator operator: _ @operator) ["/" ":" "->"] @operator -(tripledot) @comment.discard - -(comment) @comment - ; Macros (macro "?"+ @constant @@ -112,8 +108,14 @@ ((variable) @comment.discard (#match? @comment.discard "^_")) +(tripledot) @comment.discard + +[(comment) (line_comment) (shebang)] @comment + ; Basic types (variable) @variable +((atom) @constant.builtin.boolean + (#match? @constant.builtin.boolean "^(true|false)$")) (atom) @string.special.symbol (string) @string (character) @constant.character diff --git a/runtime/queries/erlang/injections.scm b/runtime/queries/erlang/injections.scm index 07858185ed77..11cbd01e3c0b 100644 --- a/runtime/queries/erlang/injections.scm +++ b/runtime/queries/erlang/injections.scm @@ -1,2 +1,7 @@ -((comment_content) @injection.content - (#set! injection.language "edoc")) +((line_comment (comment_content) @injection.content) + (#set! injection.language "edoc") + (#set! injection.include-children) + (#set! injection.combined)) + +((comment (comment_content) @injection.content) + (#set! injection.language "comment")) From 5a1bed2b708f6874daa9f04b26b14b3106d2e447 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 2 Nov 2022 09:38:36 -0500 Subject: [PATCH 028/269] Add parameter highlights to Erlang This doesn't work robustly (within pattern matches). Only regular bindings are highlighted as parameters. In order to highlight all parameters even in matches, we would need an arbitrary nesting operator in queries which doesn't exist yet in tree-sitter. --- runtime/queries/erlang/highlights.scm | 34 ++++++++++++++++++++++++--- runtime/queries/erlang/locals.scm | 30 +++++++++++++++++++++++ 2 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 runtime/queries/erlang/locals.scm diff --git a/runtime/queries/erlang/highlights.scm b/runtime/queries/erlang/highlights.scm index 050fb613c3a0..3f4ef4cb00de 100644 --- a/runtime/queries/erlang/highlights.scm +++ b/runtime/queries/erlang/highlights.scm @@ -65,6 +65,37 @@ (function_capture module: (atom) @namespace) (function_capture function: (atom) @function) +; Ignored variables +((variable) @comment.discard + (#match? @comment.discard "^_")) + +; Parameters +; specs +((attribute + name: (atom) @keyword + (stab_clause + pattern: (arguments (variable) @variable.parameter) + body: (variable)? @variable.parameter)) + (#match? @keyword "(spec|callback)")) +; functions +(function_clause pattern: (arguments (variable) @variable.parameter)) +; anonymous functions +(stab_clause pattern: (arguments (variable) @variable.parameter)) +; parametric types +((attribute + name: (atom) @keyword + (arguments + (binary_operator + left: (call (arguments (variable) @variable.parameter)) + operator: "::"))) + (#match? @keyword "(type|opaque)")) +; macros +((attribute + name: (atom) @keyword + (arguments + (call (arguments (variable) @variable.parameter)))) + (#eq? @keyword "define")) + ; Records (record_content (binary_operator @@ -105,9 +136,6 @@ name: (_) @keyword.directive) ; Comments -((variable) @comment.discard - (#match? @comment.discard "^_")) - (tripledot) @comment.discard [(comment) (line_comment) (shebang)] @comment diff --git a/runtime/queries/erlang/locals.scm b/runtime/queries/erlang/locals.scm new file mode 100644 index 000000000000..7379926b07e0 --- /dev/null +++ b/runtime/queries/erlang/locals.scm @@ -0,0 +1,30 @@ +; Specs and Callbacks +(attribute + (stab_clause + pattern: (arguments (variable) @local.definition) + ; If a spec uses a variable as the return type (and later a `when` clause to type it): + body: (variable)? @local.definition)) @local.scope + +; parametric `-type`s +((attribute + name: (atom) @_type + (arguments + (binary_operator + left: (call (arguments (variable) @local.definition)) + operator: "::") @local.scope)) + (#match? @_type "(type|opaque)")) + +; macros +((attribute + name: (atom) @_define + (arguments + (call (arguments (variable) @local.definition)))) @local.scope + (#eq? @_define "define")) + +; `fun`s +(anonymous_function (stab_clause pattern: (arguments (variable) @local.definition))) @local.scope + +; Ordinary functions +(function_clause pattern: (arguments (variable) @local.definition)) @local.scope + +(variable) @local.reference From cbc72e84d7a4c2a1ed5ec81bced3d280c69b4649 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 22 Nov 2022 21:28:17 -0600 Subject: [PATCH 029/269] Update tree-sitter-heex tree-sitter-heex split out the ending_expression_value from the partial_expression value which can help with indentation. --- languages.toml | 2 +- runtime/queries/heex/injections.scm | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/languages.toml b/languages.toml index 9007cc657c29..f6a238f43432 100644 --- a/languages.toml +++ b/languages.toml @@ -1360,7 +1360,7 @@ config = { elixirLS.dialyzerEnabled = false } [[grammar]] name = "heex" -source = { git = "https://github.com/phoenixframework/tree-sitter-heex", rev = "881f1c805f51485a26ecd7865d15c9ef8d606a78" } +source = { git = "https://github.com/phoenixframework/tree-sitter-heex", rev = "2e1348c3cf2c9323e87c2744796cf3f3868aa82a" } [[language]] name = "sql" diff --git a/runtime/queries/heex/injections.scm b/runtime/queries/heex/injections.scm index d97e4b3ef4c0..159b6f0e11bf 100644 --- a/runtime/queries/heex/injections.scm +++ b/runtime/queries/heex/injections.scm @@ -6,7 +6,11 @@ ; <%= if true do %> ;

hello, tree-sitter!

; <% end %> -((directive (partial_expression_value) @injection.content) +((directive + [ + (partial_expression_value) + (ending_expression_value) + ] @injection.content) (#set! injection.language "elixir") (#set! injection.include-children) (#set! injection.combined)) From ee06d4d337af7a46de294d88c00104b2ae836455 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 23 Nov 2022 16:27:26 -0600 Subject: [PATCH 030/269] Update tree-sitter-gleam This update includes a handful of fixes, a new binary concatenation operator (already highlighted by the `binary_operator` rule), and a new `use` language construct. The nodes are backwards compatible but this update introduces two new nodes for highlighting: `use` and `<-`. --- languages.toml | 2 +- runtime/queries/gleam/highlights.scm | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index f6a238f43432..0d90c3f741ca 100644 --- a/languages.toml +++ b/languages.toml @@ -1263,7 +1263,7 @@ language-server = { command = "gleam", args = ["lsp"] } [[grammar]] name = "gleam" -source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "d7861b2a4b4d594c58bb4f1be5f1f4ee4c67e5c3" } +source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "d6cbdf3477fcdb0b4d811518a356f9b5cd1795ed" } [[language]] name = "ron" diff --git a/runtime/queries/gleam/highlights.scm b/runtime/queries/gleam/highlights.scm index 8cff6b51d57f..34b3ce65cde5 100644 --- a/runtime/queries/gleam/highlights.scm +++ b/runtime/queries/gleam/highlights.scm @@ -80,6 +80,7 @@ "todo" "try" "type" + "use" ] @keyword ; Punctuation @@ -103,4 +104,5 @@ "->" ".." "-" + "<-" ] @punctuation.delimiter From 1d21683321b9f94161be14b4ec5b506ed1669c7f Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Thu, 24 Nov 2022 10:07:19 +0800 Subject: [PATCH 031/269] Exit select mode on surround commands (#4858) --- helix-term/src/commands.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 4eb9742ff70e..659d353e7a9e 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4582,6 +4582,7 @@ fn surround_add(cx: &mut Context) { let transaction = Transaction::change(doc.text(), changes.into_iter()) .with_selection(Selection::new(ranges, selection.primary_index())); apply_transaction(&transaction, doc, view); + exit_select_mode(cx); }) } @@ -4621,6 +4622,7 @@ fn surround_replace(cx: &mut Context) { }), ); apply_transaction(&transaction, doc, view); + exit_select_mode(cx); }); }) } @@ -4648,6 +4650,7 @@ fn surround_delete(cx: &mut Context) { let transaction = Transaction::change(doc.text(), change_pos.into_iter().map(|p| (p, p + 1, None))); apply_transaction(&transaction, doc, view); + exit_select_mode(cx); }) } From e6dad960cf77a3a0fae92ee216d31c9dae59b0ec Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 23 Nov 2022 20:07:42 -0600 Subject: [PATCH 032/269] Drain pending requests on language server termination (#4852) This prevents a freeze while shutting down when using `efm-langserver`. `efm-langserver` exits immediately after seeing a shutdown request, without responding to the request. We block awaiting the reply to the shutdown request which will never come, so we time out. This change responds to any pending requests with `Err` saying that the stream has been closed. --- helix-lsp/src/transport.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/helix-lsp/src/transport.rs b/helix-lsp/src/transport.rs index 68b3d15e64e4..3e3e06eec4c5 100644 --- a/helix-lsp/src/transport.rs +++ b/helix-lsp/src/transport.rs @@ -251,6 +251,16 @@ impl Transport { }; } Err(Error::StreamClosed) => { + // Close any outstanding requests. + for (id, tx) in transport.pending_requests.lock().await.drain() { + match tx.send(Err(Error::StreamClosed)).await { + Ok(_) => (), + Err(_) => { + error!("Could not close request on a closed channel (id={:?})", id) + } + } + } + // Hack: inject a terminated notification so we trigger code that needs to happen after exit use lsp_types::notification::Notification as _; let notification = From 2271c3aed9ccbecefa7b109f060bf5ab77c7c104 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Thu, 24 Nov 2022 20:40:48 -0600 Subject: [PATCH 033/269] Clear line on `` when line is all whitespace (#4854) This matches the insert-mode behavior for Vim and Kakoune: if the current line is empty except for whitespace, `` should insert a line ending at the beginning of the line, moving any indentation to the next line. --- helix-term/src/commands.rs | 89 +++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 659d353e7a9e..5c6807f0f9ae 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3085,40 +3085,59 @@ pub mod insert { let curr = contents.get_char(pos).unwrap_or(' '); let current_line = text.char_to_line(pos); - let indent = indent::indent_for_newline( - doc.language_config(), - doc.syntax(), - &doc.indent_style, - doc.tab_width(), - text, - current_line, - pos, - current_line, - ); - let mut text = String::new(); - // If we are between pairs (such as brackets), we want to - // insert an additional line which is indented one level - // more and place the cursor there - let on_auto_pair = doc - .auto_pairs(cx.editor) - .and_then(|pairs| pairs.get(prev)) - .and_then(|pair| if pair.close == curr { Some(pair) } else { None }) - .is_some(); - - let local_offs = if on_auto_pair { - let inner_indent = indent.clone() + doc.indent_style.as_str(); - text.reserve_exact(2 + indent.len() + inner_indent.len()); - text.push_str(doc.line_ending.as_str()); - text.push_str(&inner_indent); - let local_offs = text.chars().count(); - text.push_str(doc.line_ending.as_str()); - text.push_str(&indent); - local_offs + let line_is_only_whitespace = text + .line(current_line) + .chars() + .all(|char| char.is_ascii_whitespace()); + + let mut new_text = String::new(); + + // If the current line is all whitespace, insert a line ending at the beginning of + // the current line. This makes the current line empty and the new line contain the + // indentation of the old line. + let (from, to, local_offs) = if line_is_only_whitespace { + let line_start = text.line_to_char(current_line); + new_text.push_str(doc.line_ending.as_str()); + + (line_start, line_start, new_text.chars().count()) } else { - text.reserve_exact(1 + indent.len()); - text.push_str(doc.line_ending.as_str()); - text.push_str(&indent); - text.chars().count() + let indent = indent::indent_for_newline( + doc.language_config(), + doc.syntax(), + &doc.indent_style, + doc.tab_width(), + text, + current_line, + pos, + current_line, + ); + + // If we are between pairs (such as brackets), we want to + // insert an additional line which is indented one level + // more and place the cursor there + let on_auto_pair = doc + .auto_pairs(cx.editor) + .and_then(|pairs| pairs.get(prev)) + .and_then(|pair| if pair.close == curr { Some(pair) } else { None }) + .is_some(); + + let local_offs = if on_auto_pair { + let inner_indent = indent.clone() + doc.indent_style.as_str(); + new_text.reserve_exact(2 + indent.len() + inner_indent.len()); + new_text.push_str(doc.line_ending.as_str()); + new_text.push_str(&inner_indent); + let local_offs = new_text.chars().count(); + new_text.push_str(doc.line_ending.as_str()); + new_text.push_str(&indent); + local_offs + } else { + new_text.reserve_exact(1 + indent.len()); + new_text.push_str(doc.line_ending.as_str()); + new_text.push_str(&indent); + new_text.chars().count() + }; + + (pos, pos, local_offs) }; let new_range = if doc.restore_cursor { @@ -3139,9 +3158,9 @@ pub mod insert { // range.replace(|range| range.is_empty(), head); -> fn extend if cond true, new head pos // can be used with cx.mode to do replace or extend on most changes ranges.push(new_range); - global_offs += text.chars().count(); + global_offs += new_text.chars().count(); - (pos, pos, Some(text.into())) + (from, to, Some(new_text.into())) }); transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); From 6cdc5673721a69d2eb6de17a5c229f3151f0dfad Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sat, 26 Nov 2022 02:41:37 +0100 Subject: [PATCH 034/269] add theme nightfox (#4769) This theme is an adaptation of github.com/EdenEast/nightfox.nvim --- runtime/themes/nightfox.toml | 182 +++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 runtime/themes/nightfox.toml diff --git a/runtime/themes/nightfox.toml b/runtime/themes/nightfox.toml new file mode 100644 index 000000000000..131cab190870 --- /dev/null +++ b/runtime/themes/nightfox.toml @@ -0,0 +1,182 @@ +# Author: github.com/jhscheer +# +# This theme is an adaptation of +# github.com/EdenEast/nightfox.nvim + + +# INTERFACE +# These scopes are used for theming the editor interface. + +"ui.background" = { bg = "bg1" } # Default background color. +"ui.window" = { fg = "bg0" } # Window border between splits. +"ui.gutter" = { fg = "fg3" } # Left gutter for diagnostics and breakpoints. + +"ui.text" = { fg = "fg1" } # Default text color. +"ui.text.focus" = { bg = "sel1", fg = "fg1" } # Selection highlight in buffer-picker or file-picker. +"ui.text.info" = { fg = "fg2", bg = "sel0" } # Info popup contents (space mode menu). + +"ui.cursor" = { bg = "fg3", fg = "bg1" } # Fallback cursor colour, non-primary cursors when there are multiple (shift-c). +"ui.cursor.primary" = { bg = "fg1", fg = "bg1" } # The primary cursor when there are multiple (shift-c). +"ui.cursor.match" = { fg = "yellow", modifiers = ["bold"] } # The matching parentheses of that under the cursor. + +"ui.selection" = { bg = "bg3" } # All currently selected text. +"ui.selection.primary" = { bg = "bg4" } # The primary selection when there are multiple. +"ui.cursorline.primary" = { bg = "bg3" } # The line of the primary cursor (if cursorline is enabled) +# "ui.cursorline.secondary" = { } # The lines of any other cursors (if cursorline is enabled) +# "ui.cursorcolumn.primary" = { } # The column of the primary cursor (if cursorcolumn is enabled) +# "ui.cursorcolumn.secondary" = { } # The columns of any other cursors (if cursorcolumn is enabled) + +"ui.linenr" = { fg = "fg3" } # Line numbers. +"ui.linenr.selected" = { fg = "yellow", modifiers = ["bold"] } # Current line number. + +# "ui.virtual" = { } # Namespace for additions to the editing area. +"ui.virtual.ruler" = { bg = "bg3" } # Vertical rulers (colored columns in editing area). +"ui.virtual.whitespace" = { fg = "bg3" } # Whitespace markers in editing area. +"ui.virtual.indent-guide" = { fg = "black" } # Vertical indent width guides + +"ui.statusline" = { fg = "fg2", bg = "bg0" } # Status line. +"ui.statusline.inactive" = { fg = "fg3", bg = "bg0" } # Status line in unfocused windows. +"ui.statusline.normal" = { bg = "blue", fg = "bg0", modifiers = ["bold"] } # Statusline mode during normal mode (only if editor.color-modes is enabled) +"ui.statusline.insert" = { bg = "green", fg = "bg0", modifiers = ["bold"] } # Statusline mode during insert mode (only if editor.color-modes is enabled) +"ui.statusline.select" = { bg = "magenta", fg = "bg0", modifiers = ["bold"] } # Statusline mode during select mode (only if editor.color-modes is enabled) + +"ui.help" = { bg = "sel0", fg = "fg1" } # Description box for commands. + +"ui.menu" = { bg = "sel0", fg = "fg1" } # Code and command completion menus. +"ui.menu.selected" = { bg = "fg3" } # Selected autocomplete item. +"ui.menu.scroll" = { fg = "fg3" } # fg sets thumb color, bg sets track color of scrollbar. + +"ui.popup" = { bg = "bg0", fg = "fg1" } # Documentation popups (space-k). +"ui.popup.info" = { bg = "sel0", fg = "fg1" } # Info popups box (space mode menu). + +"markup.raw" = { fg = "magenta" } # Code block in Markdown. +"markup.raw.inline" = { fg = "orange" } # `Inline code block` in Markdown. +"markup.heading" = { fg = "yellow", modifiers = ["bold"] } +"markup.list" = { fg = "magenta", modifiers = ["bold"] } +"markup.bold" = { fg = "orange", modifiers = ["bold"] } +"markup.italic" = { fg = "pink" } +"markup.link" = { fg = "yellow-bright", modifiers = ["bold"] } +"markup.quote" = { fg = "blue" } + + +# DIAGNOSTICS +"warning" = { fg ="yellow", bg = "bg1" } # Diagnostics warning (gutter) +"error" = { fg = "red", bg = "bg1" } # Diagnostics error (gutter) +"info" = { fg = "blue", bg = "bg1" } # Diagnostics info (gutter) +"hint" = { fg = "green", bg = "bg1" } # Diagnostics hint (gutter) +"diagnostic" = { modifiers = ["underlined"] } # Diagnostics fallback style (editing area) +"diagnostic.error" = { fg = "red" } # Diagnostics error (editing area) +"diagnostic.warning" = { fg = "yellow" } # Diagnostics warning (editing area) +"diagnostic.info" = { fg = "blue" } # Diagnostics info (editing area) +"diagnostic.hint" = { fg = "green" } # Diagnostics hint (editing area) + + +# SYNTAX HIGHLIGHTING +# These keys match tree-sitter scopes. + +"special" = { fg = "fg2" } # Special symbols e.g `?` in Rust, `...` in Hare. +"attribute" = { fg = "yellow" } # Class attributes, html tag attributes. + +"type" = { fg = "yellow" } # Variable type, like integer or string, including program defined classes, structs etc.. +"type.builtin" = { fg = "cyan-bright" } # Primitive types of the language (string, int, float). +"type.enum.variant" = { fg = "orange-bright" } + +"constructor" = { fg = "magenta" } # Constructor method for a class or struct. + +"constant" = { fg = "orange-bright" } # Constant value +"constant.builtin" = { fg = "orange-bright" } # Special constants like `true`, `false`, `none`, etc. +"constant.builtin.boolean" = { fg = "orange" } # True or False. +"constant.character" = { fg = "green" } # Constant of character type. +"constant.character.escape" = { fg = "yellow-bright", modifiers = ["bold"] } # escape codes like \n. +"constant.numeric" = { fg = "orange" } # constant integer or float value. + +"string" = { fg = "green" } # String literal. +"string.regexp" = { fg = "yellow-bright" } # Regular expression literal. +"string.special" = { fg = "yellow-bright", modifiers = ["bold"] } # Strings containing a path, URL, etc. +"string.special.url" = { fg = "cyan", modifiers = ["bold"] } # String containing a web URL. + +"comment" = { fg = "comment" } # This is a comment. +"comment.block.documentation" = { fg = "comment", modifiers = ["bold"] } # Doc comments, e.g '///' in rust. + +"variable" = { fg = "white" } # Variable names. +"variable.builtin" = { fg = "red" } # Language reserved variables: `this`, `self`, `super`, etc. +"variable.parameter" = { fg = "cyan-bright" } # Function parameters. +"variable.other.member" = { fg = "fg2" } # Fields of composite data types (e.g. structs, unions). + +"label" = { fg = "magenta-bright" } # lifetimes - Loop labels, among other things. + +"punctuation" = { fg = "fg2" } # Any punctuation symbol. +# "punctuation.delimiter" = { fg = "fg2" } # Commas, colons or other delimiter depending on the language. +# "punctuation.bracket" = { fg = "fg2" } # Parentheses, angle brackets, etc. +# "punctuation.special" = { fg = "fg2" } # String interpolation brackets + +"keyword" = { fg = "magenta" } # Language reserved keywords. +"keyword.control" = { fg = "pink" } # Control keywords. +"keyword.control.conditional" = { fg = "magenta-bright" } # `if`, `else`, `elif`. +"keyword.control.repeat" = { fg = "magenta-bright" } # `for`, `while`, `loop`. +"keyword.control.import" = { fg = "pink-bright" } # `import`, `export` `use`. +"keyword.control.return" = { fg = "magenta" } # `return` in most languages. +"keyword.control.exception" = { fg = "magenta" } # `try`, `catch`, `raise`/`throw` and related. +"keyword.operator" = { fg = "fg2", modifiers = ["bold"] } # 'or', 'and', 'in'. +"keyword.directive" = { fg = "pink-bright" } # Preprocessor directives (#if in C...). +"keyword.function" = { fg = "red" } # The keyword to define a funtion: 'def', 'fun', 'fn'. +"keyword.storage" = { fg = "magenta" } # Keywords describing how things are stored +"keyword.storage.type" = { fg = "magenta" } # The type of something, class, function, var, let, etc. +"keyword.storage.modifier" = { fg = "yellow" } # Storage modifiers like static, mut, const, ref, etc. + +"operator" = { fg = "fg2" } # Logical, mathematical, and other operators. + +"function" = { fg = "blue-bright" } +"function.builtin" = { fg = "red" } +"function.macro" = { fg = "red" } +# "function.special" = { fg = "blue-bright" } # Preprocessor function in C. +# "function.method" = { fg = "blue-bright" } # Class / Struct methods. + +"tag" = { fg = "blue-bright" } # As in for html, css tags. + +"namespace" = { fg = "cyan-bright" } # Namespace or module identifier. + + +# Diff ============================== +# Version control changes. + +"diff.plus" = "green-dim" # Additions. +"diff.minus" = "red-dim" # Deletions. +"diff.delta" = "blue-dim" # Modifications. +"diff.delta.moved" = "cyan-dim" # Renamed or moved files. + +# color palette +[palette] +black = "#393b44" +red = "#c94f6d" +red-dim = "#2f2837" +green = "#81b29a" +green-dim = "#26343c" +yellow = "#dbc074" +yellow-bright = "#e0c989" +blue = "#719cd6" +blue-bright = "#86abdc" +blue-dim = "#2f2837" +magenta = "#9d79d6" +magenta-bright = "#baa1e2" +cyan = "#63cdcf" +cyan-bright = "#7ad4d6" +cyan-dim = "#253f4a" +white = "#dfdfe0" +orange = "#f4a261" +orange-bright = "#f6b079" +pink = "#d67ad2" +pink-bright = "#dc8ed9" +comment = "#738091" +# spec +bg0 = "#131a24" # Dark bg (status line and float) +bg1 = "#192330" # Default bg +bg2 = "#212e3f" # Lighter bg (colorcolm folds) +bg3 = "#29394f" # Lighter bg (cursor line) +bg4 = "#39506d" # Conceal, border fg +fg0 = "#d6d6d7" # Lighter fg +fg1 = "#cdcecf" # Default fg +fg2 = "#aeafb0" # Darker fg (status line) +fg3 = "#71839b" # Darker fg (line numbers, fold colums) +sel0 = "#2b3b51" # Popup bg, visual selection bg +sel1 = "#3c5372" # Popup sel bg, search bg From f2a55331d01be76765b8b20d64dbc55e75be55ee Mon Sep 17 00:00:00 2001 From: Chickenkeeper Date: Sat, 26 Nov 2022 01:43:41 +0000 Subject: [PATCH 035/269] Bump tree-sitter-html version (#4881) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 0d90c3f741ca..8c3f19e433cf 100644 --- a/languages.toml +++ b/languages.toml @@ -454,7 +454,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "html" -source = { git = "https://github.com/tree-sitter/tree-sitter-html", rev = "d93af487cc75120c89257195e6be46c999c6ba18" } +source = { git = "https://github.com/tree-sitter/tree-sitter-html", rev = "29f53d8f4f2335e61bf6418ab8958dac3282077a" } [[language]] name = "python" From 4e52d4d6f456e082f29f585c7a03a3ef1cbf156e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Dzivjak?= Date: Sat, 26 Nov 2022 02:52:34 +0100 Subject: [PATCH 036/269] feat(themes): improve fleetish (#4813) Small adjustements to the fleetish theme to improve readability in certain cases. Specifically: - use darker background for menues as it (purely subjectively) loooks better - use different color for `constant.buildin.boolean` and `keyword` to make statements such as `return true` read better - use different colors for different markup link parts - destructure the config where appliable --- runtime/themes/fleetish.toml | 165 ++++++++++++++++++----------------- 1 file changed, 86 insertions(+), 79 deletions(-) diff --git a/runtime/themes/fleetish.toml b/runtime/themes/fleetish.toml index 74340cae8de3..159daf8785d0 100644 --- a/runtime/themes/fleetish.toml +++ b/runtime/themes/fleetish.toml @@ -1,101 +1,116 @@ # Author: Kristoffer Flottorp # A take on the JetBrains Fleet theme sprinkled with some creative freedom -"type" = { fg = "yellow" } # .builtin -"constructor" = { fg = "yellow" } -"constant" = { fg = "cyan" } +"type" = "light_blue" +"type.builtin" = "orange" +"constructor" = "yellow" +"constant" = "cyan" # "constant.builtin" = {} # .boolean -"constant.builtin.boolean" = { fg = "cyan" } # .boolean -# "constant.character" = {} #.escape -"constant.numeric" = { fg = "yellow" } # .integer / .float -"string" = { fg = "pink" } # .regexp -# "string.special" = {} #.path / .url / .symbol -"string.special" = { modifiers = ["underlined"] } #.path / .url / .symbol -"comment" = { fg = "dark_gray" } # .line +"constant.builtin.boolean" = "yellow" +"constant.character" = "yellow" +"constant.characted.escape" = "light" +"constant.numeric" = "yellow" +"string" = "pink" +"string.regexp" = "light" +"string.special" = { fg = "yellow", modifiers = ["underlined"] } #.path / .url / .symbol +"comment" = "light_gray" # .line # "comment.block" = {} # .documentation -"variable" = { fg = "light" } # .builtin / .parameter +"variable" = "light" # .builtin +"variable.parameter" = "light" # "variable.other" = {} # .member -"variable.other.member" = { fg = "purple" } -"label" = { fg = "yellow" } -# "punctuation" = {} # .delimiter / .bracket -"keyword" = { fg = "cyan" } # .operator / .directive / .function -# "keyword.control" = { fg = "orange" } # .conditional / .repeat / .import / .return / .exception -"operator" = { fg = "light" } -"function" = { fg = "blue" } # .builtin / .method / .macro / .special -"function.macro" = { fg = "green" } -"function.special" = { fg = "green" } -"tag" = { fg = "green"} -"special" = { fg = "green" } -"namespace" = { fg = "light" } -"markup" = { fg = "purple" } # .bold / .italic / .quote -"markup.heading" = { fg = "light" } # .marker / .1 / .2 / .3 / .4 / .5 / .6 -"markup.heading.1" = { fg = "yellow" } -"markup.heading.2" = { fg = "green" } -"markup.heading.3" = { fg = "pink" } -"markup.heading.4" = { fg = "purple" } -"markup.heading.5" = { fg = "cyan" } -"markup.heading.6" = { fg = "blue" } -"markup.list" = { fg = "cyan" } # .unnumbered / .numbered -"markup.link" = { fg = "green" } # .url / .label / .text -"markup.raw" = { fg = "pink" } # .inline / .block -# "diff" = {} # .plus / .minus -"diff.plus" = { fg = "cyan" } -"diff.minus" = { fg = "yellow" } -"diff.delta" = { fg = "purple" } # .moved +"variable.other.member" = "yellow" +"label" = "yellow" +"punctuation" = "light" # .delimiter / .bracket +"keyword" = "cyan" # .operator / .directive / .function +"keyword.control" = "yellow" # .conditional / .repeat / .import / .return / .exception +"operator" = "light" +"function" = "yellow" +"function.macro" = "green" +"function.builtin" = "green" +"function.special" = "green" +"function.method" = "light" +"tag" = "green" +"special" = "green" +"namespace" = "light" # used in theming # "markup.normal" = {} # .completion / .hover -# "markup.heading" = {} # .completion / .hover # "markup.raw.inline" = {} # .completion / .hover +"markup" = "purple" # .quote +"markup.bold" = { fg = "purple", modifiers = ["bold"] } +"markup.italic" = { fg = "purple", modifiers = ["italic"] } +"markup.heading" = "light" # .marker +"markup.heading.1" = "yellow" +"markup.heading.2" = "green" +"markup.heading.3" = "pink" +"markup.heading.4" = "purple" +"markup.heading.5" = "cyan" +"markup.heading.6" = "light_blue" +"markup.list" = "cyan" # .unnumbered / .numbered +"markup.link" = "green" +"markup.link.url" = "pink" +"markup.link.text" = "cyan" +"markup.link.label" = "yellow" +"markup.raw" = "pink" # .inline +"markup.raw.block" = "orange" + +"diff.plus" = "cyan" +"diff.minus" = "yellow" +"diff.delta" = "purple" # ui specific -"ui.background" = { bg = "darkest" } # .separator +"ui.background" = { bg = "#0d0d0d" } # .separator "ui.cursor" = { bg = "dark_gray", modifiers = ["reversed"] } # .insert / .select / .match / .primary "ui.cursor.match" = { fg = "light", bg = "blue_accent" } # .insert / .select / .match / .primary "ui.cursorline" = { bg = "darker" } -"ui.linenr" = { fg = "dark_gray" } # .selected +"ui.linenr" = "dark_gray" "ui.linenr.selected" = { fg = "light_gray", bg = "darker" } "ui.statusline" = { fg = "light", bg = "darker" } # .inactive / .normal / .insert / .select -"ui.statusline.inactive" = { fg = "dark", bg = "darker" } # .inactive / .normal / .insert / .select -"ui.statusline.normal" = { fg = "lightest", bg = "darker"} # .inactive / .normal / .insert / .select -"ui.statusline.insert" = { fg = "lightest", bg = "blue_accent" } # .inactive / .normal / .insert / .select -"ui.statusline.select" = { fg = "lightest", bg = "orange_accent" } # .inactive / .normal / .insert / .select -"ui.popup" = { fg = "light", bg = "dark" } # .info +"ui.statusline.inactive" = { fg = "dark", bg = "darker" } +"ui.statusline.normal" = { fg = "lightest", bg = "darker"} +"ui.statusline.insert" = { fg = "lightest", bg = "blue_accent" } +"ui.statusline.select" = { fg = "lightest", bg = "orange_accent" } +"ui.popup" = { fg = "light", bg = "darkest" } # .info "ui.window" = { fg = "dark", bg = "darkest" } -"ui.help" = { fg = "light", bg = "dark" } -"ui.text" = { fg = "light" } # .focus / .info -"ui.virtual" = { fg = "dark" } # .ruler / .whitespace +"ui.help" = { fg = "light", bg = "darkest" } +"ui.text" = "light" # .focus / .info +"ui.virtual" = "dark" # .whitespace "ui.virtual.ruler" = { bg = "darker"} -"ui.menu" = { fg = "light", bg = "dark" } # .selected +"ui.menu" = { fg = "light", bg = "darker" } # .selected "ui.menu.selected" = { fg = "lightest", bg = "blue_accent" } # .selected "ui.selection" = { bg = "darker" } # .primary "ui.selection.primary" = { bg = "select" } # .primary -"hint" = { fg = "blue_accent"} -"info" = { fg = "yellow_accent" } -"warning" = { fg = "orange_accent" } -"error" = { fg = "diff_red_accent" } -"diagnostic". underline = { style = "curl" } +"hint" = "blue" +"info" = "yellow_accent" +"warning" = "orange_accent" +"error" = "red" +"diagnostic" = { modifiers = [] } +"diagnostic.hint" = { underline = { color = "light", style = "curl" } } +"diagnostic.info" = { underline = { color = "blue", style = "curl" } } +"diagnostic.warning" = { underline = { color = "yellow", style = "curl" } } +"diagnostic.error" = { underline = { color = "red", style = "curl" } } [palette] -darkest = "#0F0F0F" -darker = "#222222" -dark = "#383838" -select = "#102F5B" +darkest = "#1e1e1e" +darker = "#262626" +dark = "#898989" +select = "#102f5b" -light = "#F0F0F0" -lightest = "#FFFFFF" +light = "#d6d6dd" +lightest = "#ffffff" -dark_gray = "#5B5B5B" -light_gray = "#757575" -purple = "#AC9CF9" -blue = "#52A7F6" #"#94C1FA" -pink = "#D898D8" -green = "#AFCB85" -cyan = "#78D0BD" -orange = "#ECA775" -yellow = "#E5C995" +dark_gray = "#535353" +light_gray = "#6d6d6d" +purple = "#a390f0" +light_blue = "#7dbeff" +blue = "#52a7f6" +pink = "#d898d8" +green = "#afcb85" +cyan = "#78d0bd" +orange = "#efb080" +yellow = "#e5c995" +red = "#f44747" -purple_accent = "#6363EE" blue_accent = "#2197F3" pink_accent = "#E44C7A" green_accent = "#00AF99" @@ -104,11 +119,3 @@ yellow_accent = "#DEA407" # variables intended for future updates checkmark = "#44B254" - -diff_blue_accent = "#0079FF" -diff_blue_bg = "#072037" -diff_blue_fg = "#0079FF" - -diff_red_accent = "#EE113C" -diff_red_bg = "#390B14" -diff_red_fg = "#EC123B" From 8529d756fad2eeea543b487e1ff5253857bc2e16 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 25 Nov 2022 20:52:22 -0600 Subject: [PATCH 037/269] Remove selections for closed views on all documents (#4888) Previously we removed selections for a closed view on only the currently focused document. A view might have selections in other documents though, so the view needs to be removed from all documents. --- helix-view/src/editor.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 23e0a4976a53..6eaa89aac814 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1116,9 +1116,10 @@ impl Editor { } pub fn close(&mut self, id: ViewId) { - let (_view, doc) = current!(self); - // remove selection - doc.remove_view(id); + // Remove selections for the closed view on all documents. + for doc in self.documents_mut() { + doc.remove_view(id); + } self.tree.remove(id); self._refresh(); } From fc811726e0e74dd6597f1ebbbd095901b8a78a3e Mon Sep 17 00:00:00 2001 From: Lennard Hofmann Date: Sat, 26 Nov 2022 17:17:10 +0100 Subject: [PATCH 038/269] Update tree-sitter-java and add Java textobjects (#4886) --- book/src/generated/lang-support.md | 2 +- languages.toml | 2 +- runtime/queries/java/highlights.scm | 19 +++++++++++++-- runtime/queries/java/injections.scm | 2 +- runtime/queries/java/textobjects.scm | 35 ++++++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 runtime/queries/java/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index ac95503697cd..487057e61f3b 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -56,7 +56,7 @@ | idris | | | | `idris2-lsp` | | iex | ✓ | | | | | ini | ✓ | | | | -| java | ✓ | | | `jdtls` | +| java | ✓ | ✓ | | `jdtls` | | javascript | ✓ | ✓ | ✓ | `typescript-language-server` | | jsdoc | ✓ | | | | | json | ✓ | | ✓ | `vscode-json-language-server` | diff --git a/languages.toml b/languages.toml index 8c3f19e433cf..d616ce9eec81 100644 --- a/languages.toml +++ b/languages.toml @@ -617,7 +617,7 @@ indent = { tab-width = 4, unit = " " } [[grammar]] name = "java" -source = { git = "https://github.com/tree-sitter/tree-sitter-java", rev = "bd6186c24d5eb13b4623efac9d944dcc095c0dad" } +source = { git = "https://github.com/tree-sitter/tree-sitter-java", rev = "09d650def6cdf7f479f4b78f595e9ef5b58ce31e" } [[language]] name = "ledger" diff --git a/runtime/queries/java/highlights.scm b/runtime/queries/java/highlights.scm index 77902fce3221..f049b8d252b2 100644 --- a/runtime/queries/java/highlights.scm +++ b/runtime/queries/java/highlights.scm @@ -21,6 +21,8 @@ name: (identifier) @type) (class_declaration name: (identifier) @type) +(record_declaration + name: (identifier) @type) (enum_declaration name: (identifier) @type) @@ -33,6 +35,8 @@ (constructor_declaration name: (identifier) @type) +(compact_constructor_declaration + name: (identifier) @type) (type_identifier) @type @@ -59,6 +63,7 @@ (hex_integer_literal) (decimal_integer_literal) (octal_integer_literal) + (binary_integer_literal) ] @constant.numeric.integer [ @@ -67,7 +72,11 @@ ] @constant.numeric.float (character_literal) @constant.character -(string_literal) @string + +[ + (string_literal) + (text_block) +] @string [ (true) @@ -75,7 +84,8 @@ (null_literal) ] @constant.builtin -(comment) @comment +(line_comment) @comment +(block_comment) @comment ; Keywords @@ -104,15 +114,19 @@ "module" "native" "new" + "non-sealed" "open" "opens" "package" + "permits" "private" "protected" "provides" "public" "requires" + "record" "return" + "sealed" "static" "strictfp" "switch" @@ -127,4 +141,5 @@ "volatile" "while" "with" + "yield" ] @keyword diff --git a/runtime/queries/java/injections.scm b/runtime/queries/java/injections.scm index 321c90add371..e4509a5fd317 100644 --- a/runtime/queries/java/injections.scm +++ b/runtime/queries/java/injections.scm @@ -1,2 +1,2 @@ -((comment) @injection.content +([(line_comment) (block_comment)] @injection.content (#set! injection.language "comment")) diff --git a/runtime/queries/java/textobjects.scm b/runtime/queries/java/textobjects.scm new file mode 100644 index 000000000000..a932c7934553 --- /dev/null +++ b/runtime/queries/java/textobjects.scm @@ -0,0 +1,35 @@ +(method_declaration + body: (_) @function.inside) @function.around + +(interface_declaration + body: (_) @class.inside) @class.around + +(class_declaration + body: (_) @class.inside) @class.around + +(record_declaration + body: (_) @class.inside) @class.around + +(enum_declaration + body: (_) @class.inside) @class.around + +(formal_parameters + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +(type_parameters + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +(type_arguments + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +(argument_list + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +[ + (line_comment) + (block_comment) +] @comment.inside + +(line_comment)+ @comment.around + +(block_comment) @comment.around From f0f295a6679655dccfab0c1e0e9bb4a87e351db5 Mon Sep 17 00:00:00 2001 From: Filipe Azevedo Date: Sat, 26 Nov 2022 20:40:43 +0000 Subject: [PATCH 039/269] reload-all: Only update viewport when view focuses on the doc (#4901) --- helix-term/src/commands/typed.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 475f14d1de3c..351692fd24df 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1070,8 +1070,9 @@ fn reload_all( for view_id in view_ids { let view = view_mut!(cx.editor, view_id); - - view.ensure_cursor_in_view(doc, scrolloff); + if view.doc.eq(&doc_id) { + view.ensure_cursor_in_view(doc, scrolloff); + } } } From 583c2a5456263865c8aaf8b260909bfe431db549 Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Sun, 27 Nov 2022 08:36:52 -0700 Subject: [PATCH 040/269] Fix Go variable indentation (#4906) --- runtime/queries/go/indents.scm | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/queries/go/indents.scm b/runtime/queries/go/indents.scm index d75417d97a39..8bfc7c3fe14a 100644 --- a/runtime/queries/go/indents.scm +++ b/runtime/queries/go/indents.scm @@ -16,6 +16,7 @@ (block) (type_switch_statement) (expression_switch_statement) + (var_declaration) ] @indent [ From bf908cc4a11b7567800b2e3d5b48b5b29a330911 Mon Sep 17 00:00:00 2001 From: Chickenkeeper Date: Mon, 28 Nov 2022 01:11:12 +0000 Subject: [PATCH 041/269] Update CSS syntax highlighting (#4882) --- languages.toml | 2 +- runtime/queries/css/highlights.scm | 115 +++++++++++++++++------------ 2 files changed, 69 insertions(+), 48 deletions(-) diff --git a/languages.toml b/languages.toml index d616ce9eec81..756315cd6924 100644 --- a/languages.toml +++ b/languages.toml @@ -426,7 +426,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "css" -source = { git = "https://github.com/tree-sitter/tree-sitter-css", rev = "94e10230939e702b4fa3fa2cb5c3bc7173b95d07" } +source = { git = "https://github.com/tree-sitter/tree-sitter-css", rev = "769203d0f9abe1a9a691ac2b9fe4bb4397a73c51" } [[language]] name = "scss" diff --git a/runtime/queries/css/highlights.scm b/runtime/queries/css/highlights.scm index 4dfc0c66d390..b5262e8f6182 100644 --- a/runtime/queries/css/highlights.scm +++ b/runtime/queries/css/highlights.scm @@ -1,64 +1,85 @@ (comment) @comment -(tag_name) @tag -(nesting_selector) @tag -(universal_selector) @tag +[ + (tag_name) + (nesting_selector) + (universal_selector) +] @tag -"~" @operator -">" @operator -"+" @operator -"-" @operator -"*" @operator -"/" @operator -"=" @operator -"^=" @operator -"|=" @operator -"~=" @operator -"$=" @operator -"*=" @operator +[ + "~" + ">" + "+" + "-" + "*" + "/" + "=" + "^=" + "|=" + "~=" + "$=" + "*=" +] @operator -"and" @operator -"or" @operator -"not" @operator -"only" @operator - -(attribute_selector (plain_value) @string) -(pseudo_element_selector (tag_name) @attribute) -(pseudo_class_selector (class_name) @attribute) - -(class_name) @variable.other.member -(id_name) @variable.other.member -(namespace_name) @variable.other.member -(property_name) @variable.other.member -(feature_name) @variable.other.member - -(attribute_name) @attribute - -(function_name) @function +[ + "and" + "not" + "only" + "or" +] @keyword.operator ((property_name) @variable (#match? @variable "^--")) ((plain_value) @variable (#match? @variable "^--")) -"@media" @keyword -"@import" @keyword -"@charset" @keyword -"@namespace" @keyword -"@supports" @keyword -"@keyframes" @keyword -(at_keyword) @keyword -(to) @keyword -(from) @keyword -(important) @keyword +(attribute_name) @attribute +(class_name) @label +(feature_name) @variable.other.member +(function_name) @function +(id_name) @label +(namespace_name) @namespace +(property_name) @variable.other.member + +[ + "@charset" + "@import" + "@keyframes" + "@media" + "@namespace" + "@supports" + (at_keyword) + (from) + (important) + (to) +] @keyword + +[ + "#" + "." +] @punctuation (string_value) @string +((color_value) "#") @string.special (color_value) @string.special (integer_value) @constant.numeric.integer (float_value) @constant.numeric.float -(unit) @type -"#" @punctuation.delimiter -"," @punctuation.delimiter -":" @punctuation.delimiter +[ + ")" + "(" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +[ + "," + ";" + ":" + "::" +] @punctuation.delimiter + +(plain_value) @constant From a549328ef29b9f0911b04e9517bf55962d32dea2 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Mon, 28 Nov 2022 02:51:26 +0100 Subject: [PATCH 042/269] bump ropey to 1.5.1-alpha --- Cargo.lock | 4 ++-- helix-core/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 616c5317f359..1d0ee4df978c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -931,9 +931,9 @@ dependencies = [ [[package]] name = "ropey" -version = "1.5.0" +version = "1.5.1-alpha" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd22239fafefc42138ca5da064f3c17726a80d2379d817a3521240e78dd0064" +checksum = "917e62c0dee8926492dd13164b3cefaad2b0e03ab49f48c0d41635797a7409b3" dependencies = [ "smallvec", "str_indices", diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index eb886c90c217..09665b9160cf 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -17,7 +17,7 @@ integration = [] [dependencies] helix-loader = { version = "0.6", path = "../helix-loader" } -ropey = { version = "1.5", default-features = false, features = ["simd"] } +ropey = { version = "1.5.1-alpha", default-features = false, features = ["simd"] } smallvec = "1.10" smartstring = "1.0.1" unicode-segmentation = "1.10" From da355a3231174ac019b43a31958b73e818e6463f Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Mon, 28 Nov 2022 03:20:54 +0100 Subject: [PATCH 043/269] Significantly improve performance of `:reload` (#4457) * bump ropey to 1.5.1-alpha * significantly improve performance of :reload --- Cargo.lock | 259 ++++++++++++++++++++++++---------- helix-core/Cargo.toml | 2 +- helix-core/src/diff.rs | 248 ++++++++++++++++++++++++++------ helix-core/src/transaction.rs | 6 +- 4 files changed, 389 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d0ee4df978c..05a0396fafdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,9 +27,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -80,9 +80,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.0" +version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "bytecount" @@ -92,9 +92,9 @@ checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" [[package]] name = "bytes" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" [[package]] name = "cassowary" @@ -148,6 +148,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "content_inspector" version = "0.2.4" @@ -165,12 +175,11 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "crossbeam-utils" -version = "0.8.11" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -199,6 +208,50 @@ dependencies = [ "winapi", ] +[[package]] +name = "cxx" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -345,9 +398,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "libc", @@ -436,6 +489,7 @@ dependencies = [ "etcetera", "hashbrown 0.13.1", "helix-loader", + "imara-diff", "log", "once_cell", "quickcheck", @@ -443,7 +497,6 @@ dependencies = [ "ropey", "serde", "serde_json", - "similar", "slotmap", "smallvec", "smartstring", @@ -594,18 +647,28 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.47" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c495f162af0bf17656d0014a0eded5f3cd2f365fdd204548c2869db89359dc7" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" dependencies = [ "android_system_properties", "core-foundation-sys", + "iana-time-zone-haiku", "js-sys", - "once_cell", "wasm-bindgen", "winapi", ] +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "idna" version = "0.3.0" @@ -634,6 +697,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "imara-diff" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e98c1d0ad70fc91b8b9654b1f33db55e59579d3b3de2bffdced0fdb810570cb8" +dependencies = [ + "ahash 0.8.2", + "hashbrown 0.12.3", +] + [[package]] name = "indoc" version = "1.0.7" @@ -651,15 +724,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "js-sys" -version = "0.3.59" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] @@ -672,9 +745,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.132" +version = "0.2.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" [[package]] name = "libloading" @@ -686,11 +759,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + [[package]] name = "lock_api" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", @@ -726,18 +808,18 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498" +checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" dependencies = [ "libc", ] [[package]] name = "mio" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", @@ -766,9 +848,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" dependencies = [ "hermit-abi", "libc", @@ -792,9 +874,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" dependencies = [ "cfg-if", "libc", @@ -823,9 +905,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -870,9 +952,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] @@ -916,9 +998,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" -version = "0.6.27" +version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "remove_dir_all" @@ -960,20 +1042,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + [[package]] name = "serde" -version = "1.0.147" +version = "1.0.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c" dependencies = [ "proc-macro2", "quote", @@ -982,9 +1070,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8b3801309262e8184d9687fb697586833e939767aea0dda89f5a8e650e8bd7" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" dependencies = [ "itoa", "ryu", @@ -1044,12 +1132,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "similar" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" - [[package]] name = "slab" version = "0.4.7" @@ -1121,9 +1203,9 @@ checksum = "9d9199fa80c817e074620be84374a520062ebac833f358d74b37060ce4a0f2c0" [[package]] name = "syn" -version = "1.0.99" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce" dependencies = [ "proc-macro2", "quote", @@ -1144,6 +1226,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + [[package]] name = "termini" version = "0.1.4" @@ -1301,9 +1392,9 @@ checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "unicode-linebreak" @@ -1317,9 +1408,9 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] @@ -1373,9 +1464,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1383,9 +1474,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", "log", @@ -1398,9 +1489,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1408,9 +1499,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", @@ -1421,9 +1512,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "which" @@ -1469,46 +1560,60 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ + "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", + "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + [[package]] name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" [[package]] name = "windows_i686_gnu" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" [[package]] name = "windows_i686_msvc" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" [[package]] name = "windows_x86_64_msvc" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" [[package]] name = "xtask" diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 09665b9160cf..31b6546f052f 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -38,7 +38,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" toml = "0.5" -similar = "2.2" +imara-diff = "0.1.0" encoding_rs = "0.8" diff --git a/helix-core/src/diff.rs b/helix-core/src/diff.rs index 6960c679c4ac..c754da30f4ae 100644 --- a/helix-core/src/diff.rs +++ b/helix-core/src/diff.rs @@ -1,58 +1,195 @@ -use crate::{Rope, Transaction}; +use std::ops::Range; +use std::time::Instant; -/// Compares `old` and `new` to generate a [`Transaction`] describing -/// the steps required to get from `old` to `new`. -pub fn compare_ropes(old: &Rope, new: &Rope) -> Transaction { - // `similar` only works on contiguous data, so a `Rope` has - // to be temporarily converted into a `String`. - let old_converted = old.to_string(); - let new_converted = new.to_string(); - - // A timeout is set so after 1 seconds, the algorithm will start - // approximating. This is especially important for big `Rope`s or - // `Rope`s that are extremely dissimilar to each other. - let mut config = similar::TextDiff::configure(); - config.timeout(std::time::Duration::from_secs(1)); - - let diff = config.diff_chars(&old_converted, &new_converted); - - // The current position of the change needs to be tracked to - // construct the `Change`s. - let mut pos = 0; - Transaction::change( - old, - diff.ops() +use imara_diff::intern::InternedInput; +use imara_diff::Algorithm; +use ropey::RopeSlice; + +use crate::{ChangeSet, Rope, Tendril, Transaction}; + +/// A `imara_diff::Sink` that builds a `ChangeSet` for a character diff of a hunk +struct CharChangeSetBuilder<'a> { + res: &'a mut ChangeSet, + hunk: &'a InternedInput, + pos: u32, +} + +impl imara_diff::Sink for CharChangeSetBuilder<'_> { + type Out = (); + fn process_change(&mut self, before: Range, after: Range) { + self.res.retain((before.start - self.pos) as usize); + self.res.delete(before.len()); + self.pos = before.end; + + let res = self.hunk.after[after.start as usize..after.end as usize] + .iter() + .map(|&token| self.hunk.interner[token]) + .collect(); + + self.res.insert(res); + } + + fn finish(self) -> Self::Out { + self.res.retain(self.hunk.before.len() - self.pos as usize); + } +} + +struct LineChangeSetBuilder<'a> { + res: ChangeSet, + after: RopeSlice<'a>, + file: &'a InternedInput>, + current_hunk: InternedInput, + pos: u32, +} + +impl imara_diff::Sink for LineChangeSetBuilder<'_> { + type Out = ChangeSet; + + fn process_change(&mut self, before: Range, after: Range) { + let len = self.file.before[self.pos as usize..before.start as usize] .iter() - .map(|op| op.as_tag_tuple()) - .filter_map(|(tag, old_range, new_range)| { - // `old_pos..pos` is equivalent to `start..end` for where - // the change should be applied. - let old_pos = pos; - pos += old_range.end - old_range.start; - - match tag { - // Semantically, inserts and replacements are the same thing. - similar::DiffTag::Insert | similar::DiffTag::Replace => { - // This is the text from the `new` rope that should be - // inserted into `old`. - let text: &str = { - let start = new.char_to_byte(new_range.start); - let end = new.char_to_byte(new_range.end); - &new_converted[start..end] - }; - Some((old_pos, pos, Some(text.into()))) + .map(|&it| self.file.interner[it].len_chars()) + .sum(); + self.res.retain(len); + self.pos = before.end; + + // do not perform diffs on large hunks + let len_before = before.end - before.start; + let len_after = after.end - after.start; + + // Pure insertions/removals do not require a character diff. + // Very large changes are ignored because their character diff is expensive to compute + // TODO adjust heuristic to detect large changes? + if len_before == 0 + || len_after == 0 + || len_after > 5 * len_before + || 5 * len_after < len_before && len_before > 10 + || len_before + len_after > 200 + { + let remove = self.file.before[before.start as usize..before.end as usize] + .iter() + .map(|&it| self.file.interner[it].len_chars()) + .sum(); + self.res.delete(remove); + let mut fragment = Tendril::new(); + if len_after > 500 { + // copying a rope line by line is slower then copying the entire + // rope. Use to_string for very large changes instead.. + if self.file.after.len() == after.end as usize { + if after.start == 0 { + fragment = self.after.to_string().into(); + } else { + let start = self.after.line_to_char(after.start as usize); + fragment = self.after.slice(start..).to_string().into(); } - similar::DiffTag::Delete => Some((old_pos, pos, None)), - similar::DiffTag::Equal => None, + } else if after.start == 0 { + let end = self.after.line_to_char(after.end as usize); + fragment = self.after.slice(..end).to_string().into(); + } else { + let start = self.after.line_to_char(after.start as usize); + let end = self.after.line_to_char(after.end as usize); + fragment = self.after.slice(start..end).to_string().into(); } - }), - ) + } else { + for &line in &self.file.after[after.start as usize..after.end as usize] { + for chunk in self.file.interner[line].chunks() { + fragment.push_str(chunk) + } + } + }; + self.res.insert(fragment); + } else { + // for reasonably small hunks, generating a ChangeSet from char diff can save memory + // TODO use a tokenizer (word diff?) for improved performance + let hunk_before = self.file.before[before.start as usize..before.end as usize] + .iter() + .flat_map(|&it| self.file.interner[it].chars()); + let hunk_after = self.file.after[after.start as usize..after.end as usize] + .iter() + .flat_map(|&it| self.file.interner[it].chars()); + self.current_hunk.update_before(hunk_before); + self.current_hunk.update_after(hunk_after); + + // the histogram heuristic does not work as well + // for characters because the same characters often reoccur + // use myer diff instead + imara_diff::diff( + Algorithm::Myers, + &self.current_hunk, + CharChangeSetBuilder { + res: &mut self.res, + hunk: &self.current_hunk, + pos: 0, + }, + ); + + self.current_hunk.clear(); + } + } + + fn finish(mut self) -> Self::Out { + let len = self.file.before[self.pos as usize..] + .iter() + .map(|&it| self.file.interner[it].len_chars()) + .sum(); + + self.res.retain(len); + self.res + } +} + +struct RopeLines<'a>(RopeSlice<'a>); + +impl<'a> imara_diff::intern::TokenSource for RopeLines<'a> { + type Token = RopeSlice<'a>; + // TODO: improve performance of lines iterator (https://github.com/cessen/ropey/issues/25) + type Tokenizer = ropey::iter::Lines<'a>; + + fn tokenize(&self) -> Self::Tokenizer { + self.0.lines() + } + + fn estimate_tokens(&self) -> u32 { + // we can provide a perfect estimate which is very nice for performance + self.0.len_lines() as u32 + } +} + +/// Compares `old` and `new` to generate a [`Transaction`] describing +/// the steps required to get from `old` to `new`. +pub fn compare_ropes(before: &Rope, after: &Rope) -> Transaction { + let start = Instant::now(); + let res = ChangeSet::with_capacity(32); + let after = after.slice(..); + let file = InternedInput::new(RopeLines(before.slice(..)), RopeLines(after)); + let builder = LineChangeSetBuilder { + res, + file: &file, + after, + pos: 0, + current_hunk: InternedInput::default(), + }; + + let res = imara_diff::diff(Algorithm::Histogram, &file, builder).into(); + + log::debug!( + "rope diff took {}s", + Instant::now().duration_since(start).as_secs_f64() + ); + res } #[cfg(test)] mod tests { use super::*; + fn test_identity(a: &str, b: &str) { + let mut old = Rope::from(a); + let new = Rope::from(b); + compare_ropes(&old, &new).apply(&mut old); + assert_eq!(old, new); + } + quickcheck::quickcheck! { fn test_compare_ropes(a: String, b: String) -> bool { let mut old = Rope::from(a); @@ -61,4 +198,25 @@ mod tests { old == new } } + + #[test] + fn equal_files() { + test_identity("foo", "foo"); + } + + #[test] + fn trailing_newline() { + test_identity("foo\n", "foo"); + test_identity("foo", "foo\n"); + } + + #[test] + fn new_file() { + test_identity("", "foo"); + } + + #[test] + fn deleted_file() { + test_identity("foo", ""); + } } diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index 3fb394138a1e..482fd6d97e5e 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -56,7 +56,7 @@ impl ChangeSet { } // Changeset builder operations: delete/insert/retain - fn delete(&mut self, n: usize) { + pub(crate) fn delete(&mut self, n: usize) { use Operation::*; if n == 0 { return; @@ -71,7 +71,7 @@ impl ChangeSet { } } - fn insert(&mut self, fragment: Tendril) { + pub(crate) fn insert(&mut self, fragment: Tendril) { use Operation::*; if fragment.is_empty() { @@ -93,7 +93,7 @@ impl ChangeSet { self.changes.push(new_last); } - fn retain(&mut self, n: usize) { + pub(crate) fn retain(&mut self, n: usize) { use Operation::*; if n == 0 { return; From 5c213f7de4df551284cf46631508b1b0d5244a5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20B=C3=BCnnig?= Date: Mon, 28 Nov 2022 16:19:16 +0100 Subject: [PATCH 044/269] fix(grammar): Add `block_comment` and `comment_environment` injection for latex comments (#4922) --- runtime/queries/latex/injections.scm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime/queries/latex/injections.scm b/runtime/queries/latex/injections.scm index d3fdb0ca7178..101374686d05 100644 --- a/runtime/queries/latex/injections.scm +++ b/runtime/queries/latex/injections.scm @@ -1,2 +1,6 @@ -((line_comment) @injection.content - (#set! injection.language "comment")) +([ + (comment) + (line_comment) + (block_comment) + (comment_environment) + ] @injection.content (#set! injection.language "comment")) From 04df9e444523ced5d3bedbe34e2f622d675cccb2 Mon Sep 17 00:00:00 2001 From: Kirawi <67773714+kirawi@users.noreply.github.com> Date: Mon, 28 Nov 2022 20:07:47 -0500 Subject: [PATCH 045/269] delete outdated reference to cessen/ropey#25 (#4928) --- helix-core/src/diff.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/helix-core/src/diff.rs b/helix-core/src/diff.rs index c754da30f4ae..a5d6d72298be 100644 --- a/helix-core/src/diff.rs +++ b/helix-core/src/diff.rs @@ -142,7 +142,6 @@ struct RopeLines<'a>(RopeSlice<'a>); impl<'a> imara_diff::intern::TokenSource for RopeLines<'a> { type Token = RopeSlice<'a>; - // TODO: improve performance of lines iterator (https://github.com/cessen/ropey/issues/25) type Tokenizer = ropey::iter::Lines<'a>; fn tokenize(&self) -> Self::Tokenizer { From df5457a6e71b58a39e198642efd7be0c4963153d Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 27 Nov 2022 10:33:51 -0600 Subject: [PATCH 046/269] Remove eager application of transactions to all views --- helix-term/src/ui/editor.rs | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 737125031e99..6c8ee2d95e9c 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -1337,9 +1337,7 @@ impl Component for EditorView { cx.editor.status_msg = None; let mode = cx.editor.mode(); - let (view, doc) = current!(cx.editor); - let original_doc_id = doc.id(); - let original_doc_revision = doc.get_current_revision(); + let (view, _) = current!(cx.editor); let focus = view.id; if let Some(on_next_key) = self.on_next_key.take() { @@ -1415,31 +1413,13 @@ impl Component for EditorView { let view = view_mut!(cx.editor, focus); let doc = doc_mut!(cx.editor, &view.doc); + view.ensure_cursor_in_view(doc, config.scrolloff); + // Store a history state if not in insert mode. This also takes care of // committing changes when leaving insert mode. if mode != Mode::Insert { doc.append_changes_to_history(view.id); } - - // If the current document has been changed, apply the changes to all views. - // This ensures that selections in jumplists follow changes. - if doc.id() == original_doc_id - && doc.get_current_revision() != original_doc_revision - { - if let Some(transaction) = - doc.history.get_mut().changes_since(original_doc_revision) - { - let doc = doc!(cx.editor, &original_doc_id); - for (view, _focused) in cx.editor.tree.views_mut() { - view.apply(&transaction, doc); - } - } - } - - let view = view_mut!(cx.editor, focus); - let doc = doc_mut!(cx.editor, &view.doc); - - view.ensure_cursor_in_view(doc, config.scrolloff); } EventResult::Consumed(callback) From 4d1f5389f99013be99b9498fd3fee78eec6217f3 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 27 Nov 2022 10:46:42 -0600 Subject: [PATCH 047/269] Revert "Don't apply transactions to Views in undo/redo" This reverts commit fd00f3a70eb626242bb2fcc9bddf2c4d94580a9a. --- helix-term/src/commands.rs | 8 ++++---- helix-term/src/commands/typed.rs | 4 ++-- helix-view/src/document.rs | 24 ++++++++++++------------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 5c6807f0f9ae..0817ca739657 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3321,7 +3321,7 @@ fn undo(cx: &mut Context) { let count = cx.count(); let (view, doc) = current!(cx.editor); for _ in 0..count { - if !doc.undo(view.id) { + if !doc.undo(view) { cx.editor.set_status("Already at oldest change"); break; } @@ -3332,7 +3332,7 @@ fn redo(cx: &mut Context) { let count = cx.count(); let (view, doc) = current!(cx.editor); for _ in 0..count { - if !doc.redo(view.id) { + if !doc.redo(view) { cx.editor.set_status("Already at newest change"); break; } @@ -3344,7 +3344,7 @@ fn earlier(cx: &mut Context) { let (view, doc) = current!(cx.editor); for _ in 0..count { // rather than doing in batch we do this so get error halfway - if !doc.earlier(view.id, UndoKind::Steps(1)) { + if !doc.earlier(view, UndoKind::Steps(1)) { cx.editor.set_status("Already at oldest change"); break; } @@ -3356,7 +3356,7 @@ fn later(cx: &mut Context) { let (view, doc) = current!(cx.editor); for _ in 0..count { // rather than doing in batch we do this so get error halfway - if !doc.later(view.id, UndoKind::Steps(1)) { + if !doc.later(view, UndoKind::Steps(1)) { cx.editor.set_status("Already at newest change"); break; } diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 351692fd24df..89c310fa28e4 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -481,7 +481,7 @@ fn earlier( let uk = args.join(" ").parse::().map_err(|s| anyhow!(s))?; let (view, doc) = current!(cx.editor); - let success = doc.earlier(view.id, uk); + let success = doc.earlier(view, uk); if !success { cx.editor.set_status("Already at oldest change"); } @@ -500,7 +500,7 @@ fn later( let uk = args.join(" ").parse::().map_err(|s| anyhow!(s))?; let (view, doc) = current!(cx.editor); - let success = doc.later(view.id, uk); + let success = doc.later(view, uk); if !success { cx.editor.set_status("Already at newest change"); } diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 0eb54f25fa6e..087085283391 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -857,11 +857,11 @@ impl Document { success } - fn undo_redo_impl(&mut self, view_id: ViewId, undo: bool) -> bool { + fn undo_redo_impl(&mut self, view: &mut View, undo: bool) -> bool { let mut history = self.history.take(); let txn = if undo { history.undo() } else { history.redo() }; let success = if let Some(txn) = txn { - self.apply_impl(txn, view_id) + self.apply_impl(txn, view.id) && view.apply(txn, self) } else { false }; @@ -875,13 +875,13 @@ impl Document { } /// Undo the last modification to the [`Document`]. Returns whether the undo was successful. - pub fn undo(&mut self, view_id: ViewId) -> bool { - self.undo_redo_impl(view_id, true) + pub fn undo(&mut self, view: &mut View) -> bool { + self.undo_redo_impl(view, true) } /// Redo the last modification to the [`Document`]. Returns whether the redo was successful. - pub fn redo(&mut self, view_id: ViewId) -> bool { - self.undo_redo_impl(view_id, false) + pub fn redo(&mut self, view: &mut View) -> bool { + self.undo_redo_impl(view, false) } pub fn savepoint(&mut self) { @@ -894,7 +894,7 @@ impl Document { } } - fn earlier_later_impl(&mut self, view_id: ViewId, uk: UndoKind, earlier: bool) -> bool { + fn earlier_later_impl(&mut self, view: &mut View, uk: UndoKind, earlier: bool) -> bool { let txns = if earlier { self.history.get_mut().earlier(uk) } else { @@ -902,7 +902,7 @@ impl Document { }; let mut success = false; for txn in txns { - if self.apply_impl(&txn, view_id) { + if self.apply_impl(&txn, view.id) && view.apply(&txn, self) { success = true; } } @@ -914,13 +914,13 @@ impl Document { } /// Undo modifications to the [`Document`] according to `uk`. - pub fn earlier(&mut self, view_id: ViewId, uk: UndoKind) -> bool { - self.earlier_later_impl(view_id, uk, true) + pub fn earlier(&mut self, view: &mut View, uk: UndoKind) -> bool { + self.earlier_later_impl(view, uk, true) } /// Redo modifications to the [`Document`] according to `uk`. - pub fn later(&mut self, view_id: ViewId, uk: UndoKind) -> bool { - self.earlier_later_impl(view_id, uk, false) + pub fn later(&mut self, view: &mut View, uk: UndoKind) -> bool { + self.earlier_later_impl(view, uk, false) } /// Commit pending changes to history From 056a19a003a290b7914c7b442ebd640b93eaba0c Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 27 Nov 2022 10:45:17 -0600 Subject: [PATCH 048/269] Sync changes between doc and view on switch --- helix-view/src/editor.rs | 7 ++++++- helix-view/src/view.rs | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 6eaa89aac814..e54c7497f2a7 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -959,7 +959,8 @@ impl Editor { fn _refresh(&mut self) { let config = self.config(); for (view, _) in self.tree.views_mut() { - let doc = &self.documents[&view.doc]; + let doc = doc_mut!(self, &view.doc); + view.sync_changes(doc); view.ensure_cursor_in_view(doc, config.scrolloff) } } @@ -971,6 +972,7 @@ impl Editor { let doc = doc_mut!(self, &doc_id); doc.ensure_view_init(view.id); + view.sync_changes(doc); align_view(doc, view, Align::Center); } @@ -1239,6 +1241,9 @@ impl Editor { // within view if prev_id != view_id { self.mode = Mode::Normal; + let view = view_mut!(self, view_id); + let doc = doc_mut!(self, &view.doc); + view.sync_changes(doc); self.ensure_cursor_in_view(view_id); } } diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index c917a1abc054..845a545862d6 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -3,7 +3,10 @@ use helix_core::{ pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection, Transaction, }; -use std::{collections::VecDeque, fmt}; +use std::{ + collections::{HashMap, VecDeque}, + fmt, +}; const JUMP_LIST_CAPACITY: usize = 30; @@ -102,6 +105,11 @@ pub struct View { pub object_selections: Vec, /// GutterTypes used to fetch Gutter (constructor) and width for rendering gutters: Vec, + /// A mapping between documents and the last history revision the view was updated at. + /// Changes between documents and views are synced lazily when switching windows. This + /// mapping keeps track of the last applied history revision so that only new changes + /// are applied. + doc_revisions: HashMap, } impl fmt::Debug for View { @@ -126,6 +134,7 @@ impl View { last_modified_docs: [None, None], object_selections: Vec::new(), gutters: gutter_types, + doc_revisions: HashMap::new(), } } @@ -349,10 +358,33 @@ impl View { /// Applies a [`Transaction`] to the view. /// Instead of calling this function directly, use [crate::apply_transaction] /// which applies a transaction to the [`Document`] and view together. - pub fn apply(&mut self, transaction: &Transaction, doc: &Document) -> bool { + pub fn apply(&mut self, transaction: &Transaction, doc: &mut Document) { self.jumps.apply(transaction, doc); - // TODO: remove the boolean return. This is unused. - true + self.doc_revisions + .insert(doc.id(), doc.get_current_revision()); + } + + pub fn sync_changes(&mut self, doc: &mut Document) { + let latest_revision = doc.get_current_revision(); + let current_revision = *self + .doc_revisions + .entry(doc.id()) + .or_insert(latest_revision); + + if current_revision == latest_revision { + return; + } + + log::debug!( + "Syncing view {:?} between {} and {}", + self.id, + current_revision, + latest_revision + ); + + if let Some(transaction) = doc.history.get_mut().changes_since(current_revision) { + self.apply(&transaction, doc); + } } } From 53c28556436ffcf8ad5a68c40b53d9aa11669510 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 27 Nov 2022 12:47:51 -0600 Subject: [PATCH 049/269] Remove calls to View::apply in undo/redo/earlier/later --- helix-view/src/document.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 087085283391..4b264b132004 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -861,7 +861,7 @@ impl Document { let mut history = self.history.take(); let txn = if undo { history.undo() } else { history.redo() }; let success = if let Some(txn) = txn { - self.apply_impl(txn, view.id) && view.apply(txn, self) + self.apply_impl(txn, view.id) } else { false }; @@ -902,7 +902,7 @@ impl Document { }; let mut success = false; for txn in txns { - if self.apply_impl(&txn, view.id) && view.apply(&txn, self) { + if self.apply_impl(&txn, view.id) { success = true; } } From 2709ce33324cf6d4612c61609f336cf5937b6cac Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 27 Nov 2022 12:48:14 -0600 Subject: [PATCH 050/269] Sync changes with view in undo/redo/earlier/later --- helix-view/src/document.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 4b264b132004..1750355357da 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -870,6 +870,8 @@ impl Document { if success { // reset changeset to fix len self.changes = ChangeSet::new(self.text()); + // Sync with changes with the jumplist selections. + view.sync_changes(self); } success } @@ -909,6 +911,8 @@ impl Document { if success { // reset changeset to fix len self.changes = ChangeSet::new(self.text()); + // Sync with changes with the jumplist selections. + view.sync_changes(self); } success } From 9a9e462183cb60bff6450f17173e6b18eadbbfb2 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 27 Nov 2022 12:47:26 -0600 Subject: [PATCH 051/269] Call View::apply within Document::append_changes_to_history --- helix-term/src/commands.rs | 8 ++++---- helix-term/src/commands/lsp.rs | 5 +++-- helix-term/src/commands/typed.rs | 8 ++++---- helix-term/src/ui/editor.rs | 4 ++-- helix-view/src/document.rs | 9 ++++++--- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 0817ca739657..a6f88362c8f6 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2564,7 +2564,7 @@ async fn make_format_callback( if let Ok(format) = format { if doc.version() == doc_version { apply_transaction(&format, doc, view); - doc.append_changes_to_history(view.id); + doc.append_changes_to_history(view); doc.detect_indent_and_line_ending(); view.ensure_cursor_in_view(doc, scrolloff); } else { @@ -3365,7 +3365,7 @@ fn later(cx: &mut Context) { fn commit_undo_checkpoint(cx: &mut Context) { let (view, doc) = current!(cx.editor); - doc.append_changes_to_history(view.id); + doc.append_changes_to_history(view); } // Yank / Paste @@ -3677,7 +3677,7 @@ fn replace_selections_with_clipboard_impl( }); apply_transaction(&transaction, doc, view); - doc.append_changes_to_history(view.id); + doc.append_changes_to_history(view); } Err(e) => return Err(e.context("Couldn't get system clipboard contents")), } @@ -4884,7 +4884,7 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) { let transaction = Transaction::change(doc.text(), changes.into_iter()) .with_selection(Selection::new(ranges, selection.primary_index())); apply_transaction(&transaction, doc, view); - doc.append_changes_to_history(view.id); + doc.append_changes_to_history(view); } // after replace cursor may be out of bounds, do this to diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 8faf1d087f92..1f80de5f8d4e 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -760,8 +760,9 @@ pub fn apply_workspace_edit( text_edits, offset_encoding, ); - apply_transaction(&transaction, doc, view_mut!(editor, view_id)); - doc.append_changes_to_history(view_id); + let view = view_mut!(editor, view_id); + apply_transaction(&transaction, doc, view); + doc.append_changes_to_history(view); }; if let Some(ref changes) = workspace_edit.changes { diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 89c310fa28e4..2fa903a7e605 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -464,7 +464,7 @@ fn set_line_ending( }), ); apply_transaction(&transaction, doc, view); - doc.append_changes_to_history(view.id); + doc.append_changes_to_history(view); Ok(()) } @@ -909,7 +909,7 @@ fn replace_selections_with_clipboard_impl( }); apply_transaction(&transaction, doc, view); - doc.append_changes_to_history(view.id); + doc.append_changes_to_history(view); Ok(()) } Err(e) => Err(e.context("Couldn't get system clipboard contents")), @@ -1573,7 +1573,7 @@ fn sort_impl( ); apply_transaction(&transaction, doc, view); - doc.append_changes_to_history(view.id); + doc.append_changes_to_history(view); Ok(()) } @@ -1617,7 +1617,7 @@ fn reflow( }); apply_transaction(&transaction, doc, view); - doc.append_changes_to_history(view.id); + doc.append_changes_to_history(view); view.ensure_cursor_in_view(doc, scrolloff); Ok(()) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 6c8ee2d95e9c..7bda74d283eb 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -1319,7 +1319,7 @@ impl Component for EditorView { // Store a history state if not in insert mode. Otherwise wait till we exit insert // to include any edits to the paste in the history state. if mode != Mode::Insert { - doc.append_changes_to_history(view.id); + doc.append_changes_to_history(view); } EventResult::Consumed(None) @@ -1418,7 +1418,7 @@ impl Component for EditorView { // Store a history state if not in insert mode. This also takes care of // committing changes when leaving insert mode. if mode != Mode::Insert { - doc.append_changes_to_history(view.id); + doc.append_changes_to_history(view); } } diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 1750355357da..ad47f838fa90 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -641,7 +641,7 @@ impl Document { // of the encoding. let transaction = helix_core::diff::compare_ropes(self.text(), &rope); apply_transaction(&transaction, self, view); - self.append_changes_to_history(view.id); + self.append_changes_to_history(view); self.reset_modified(); self.detect_indent_and_line_ending(); @@ -928,7 +928,7 @@ impl Document { } /// Commit pending changes to history - pub fn append_changes_to_history(&mut self, view_id: ViewId) { + pub fn append_changes_to_history(&mut self, view: &mut View) { if self.changes.is_empty() { return; } @@ -938,7 +938,7 @@ impl Document { // Instead of doing this messy merge we could always commit, and based on transaction // annotations either add a new layer or compose into the previous one. let transaction = - Transaction::from(changes).with_selection(self.selection(view_id).clone()); + Transaction::from(changes).with_selection(self.selection(view.id).clone()); // HAXX: we need to reconstruct the state as it was before the changes.. let old_state = self.old_state.take().expect("no old_state available"); @@ -946,6 +946,9 @@ impl Document { let mut history = self.history.take(); history.commit_revision(&transaction, &old_state); self.history.set(history); + + // Update jumplist entries in the view. + view.apply(&transaction, self); } pub fn id(&self) -> DocumentId { From 9387dfafedfc7051e7682cfdbec09b5b91c76918 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 27 Nov 2022 12:46:36 -0600 Subject: [PATCH 052/269] Use lowest common ancestor search in History::changes_since --- helix-core/src/history.rs | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/helix-core/src/history.rs b/helix-core/src/history.rs index 825092423e00..b99e969f93ba 100644 --- a/helix-core/src/history.rs +++ b/helix-core/src/history.rs @@ -122,32 +122,16 @@ impl History { /// Returns the changes since the given revision composed into a transaction. /// Returns None if there are no changes between the current and given revisions. pub fn changes_since(&self, revision: usize) -> Option { - use std::cmp::Ordering::*; + let lca = self.lowest_common_ancestor(revision, self.current); + let up = self.path_up(revision, lca); + let down = self.path_up(self.current, lca); + let up_txns = up + .iter() + .rev() + .map(|&n| self.revisions[n].inversion.clone()); + let down_txns = down.iter().map(|&n| self.revisions[n].transaction.clone()); - match revision.cmp(&self.current) { - Equal => None, - Less => { - let mut child = self.revisions[revision].last_child?.get(); - let mut transaction = self.revisions[child].transaction.clone(); - while child != self.current { - child = self.revisions[child].last_child?.get(); - transaction = transaction.compose(self.revisions[child].transaction.clone()); - } - Some(transaction) - } - Greater => { - let mut inversion = self.revisions[revision].inversion.clone(); - let mut parent = self.revisions[revision].parent; - while parent != self.current { - parent = self.revisions[parent].parent; - if parent == 0 { - return None; - } - inversion = inversion.compose(self.revisions[parent].inversion.clone()); - } - Some(inversion) - } - } + up_txns.chain(down_txns).reduce(|acc, tx| tx.compose(acc)) } /// Undo the last edit. From 4802f26a232b2eed5f4af05a540a4735edd199ee Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 27 Nov 2022 13:47:52 -0600 Subject: [PATCH 053/269] Add a test case for undo/redo across splits --- helix-term/tests/test/splits.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/helix-term/tests/test/splits.rs b/helix-term/tests/test/splits.rs index a51de365850e..a34a24b7cbdf 100644 --- a/helix-term/tests/test/splits.rs +++ b/helix-term/tests/test/splits.rs @@ -151,5 +151,15 @@ async fn test_changes_in_splits_apply_to_all_views() -> anyhow::Result<()> { // was not updated and after the `kd` step, pointed outside of the document. test(("#[|]#", "v[wkdqd", "#[|]#")).await?; + // Transactions are applied to the views for windows lazily when they are focused. + // This case panics if the transactions and inversions are not applied in the + // correct order as we switch between windows. + test(( + "#[|]#", + "[[[vuuuwUUUquuu", + "#[|]#", + )) + .await?; + Ok(()) } From 260341ed801a894141db2fd4e66c7159d06b665e Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 28 Nov 2022 09:36:41 -0600 Subject: [PATCH 054/269] Sync all document changes on view focus --- helix-view/src/editor.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index e54c7497f2a7..5a1ac6b1fe1d 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1241,10 +1241,13 @@ impl Editor { // within view if prev_id != view_id { self.mode = Mode::Normal; - let view = view_mut!(self, view_id); - let doc = doc_mut!(self, &view.doc); - view.sync_changes(doc); self.ensure_cursor_in_view(view_id); + + // Update jumplist selections with new document changes. + for (view, _focused) in self.tree.views_mut() { + let doc = doc_mut!(self, &view.doc); + view.sync_changes(doc); + } } } From 607c74efde40812caa6379a05fcb28f259ea2c8e Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 29 Nov 2022 10:15:55 -0600 Subject: [PATCH 055/269] Handle disambiguated keycodes (#4887) Media keys are sent despite `DISAMBIGUATE_ESCAPE_CODES` being unset. Previously we panicked on these. This change translates the disambiguated keys from crossterm so that they do not cause a panic. --- helix-view/src/input.rs | 142 ++++++++++++++++++++++++- helix-view/src/keyboard.rs | 205 +++++++++++++++++++++++++++++++++++-- 2 files changed, 335 insertions(+), 12 deletions(-) diff --git a/helix-view/src/input.rs b/helix-view/src/input.rs index 30fa72c49653..bda0520e0b51 100644 --- a/helix-view/src/input.rs +++ b/helix-view/src/input.rs @@ -4,7 +4,7 @@ use helix_core::unicode::{segmentation::UnicodeSegmentation, width::UnicodeWidth use serde::de::{self, Deserialize, Deserializer}; use std::fmt; -pub use crate::keyboard::{KeyCode, KeyModifiers}; +pub use crate::keyboard::{KeyCode, KeyModifiers, MediaKeyCode, ModifierKeyCode}; #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Hash)] pub enum Event { @@ -119,6 +119,40 @@ pub(crate) mod keys { pub(crate) const MINUS: &str = "minus"; pub(crate) const LESS_THAN: &str = "lt"; pub(crate) const GREATER_THAN: &str = "gt"; + pub(crate) const CAPS_LOCK: &str = "capslock"; + pub(crate) const SCROLL_LOCK: &str = "scrolllock"; + pub(crate) const NUM_LOCK: &str = "numlock"; + pub(crate) const PRINT_SCREEN: &str = "printscreen"; + pub(crate) const PAUSE: &str = "pause"; + pub(crate) const MENU: &str = "menu"; + pub(crate) const KEYPAD_BEGIN: &str = "keypadbegin"; + pub(crate) const PLAY: &str = "play"; + pub(crate) const PAUSE_MEDIA: &str = "pausemedia"; + pub(crate) const PLAY_PAUSE: &str = "playpause"; + pub(crate) const REVERSE: &str = "reverse"; + pub(crate) const STOP: &str = "stop"; + pub(crate) const FAST_FORWARD: &str = "fastforward"; + pub(crate) const REWIND: &str = "rewind"; + pub(crate) const TRACK_NEXT: &str = "tracknext"; + pub(crate) const TRACK_PREVIOUS: &str = "trackprevious"; + pub(crate) const RECORD: &str = "record"; + pub(crate) const LOWER_VOLUME: &str = "lowervolume"; + pub(crate) const RAISE_VOLUME: &str = "raisevolume"; + pub(crate) const MUTE_VOLUME: &str = "mutevolume"; + pub(crate) const LEFT_SHIFT: &str = "leftshift"; + pub(crate) const LEFT_CONTROL: &str = "leftcontrol"; + pub(crate) const LEFT_ALT: &str = "leftalt"; + pub(crate) const LEFT_SUPER: &str = "leftsuper"; + pub(crate) const LEFT_HYPER: &str = "lefthyper"; + pub(crate) const LEFT_META: &str = "leftmeta"; + pub(crate) const RIGHT_SHIFT: &str = "rightshift"; + pub(crate) const RIGHT_CONTROL: &str = "rightcontrol"; + pub(crate) const RIGHT_ALT: &str = "rightalt"; + pub(crate) const RIGHT_SUPER: &str = "rightsuper"; + pub(crate) const RIGHT_HYPER: &str = "righthyper"; + pub(crate) const RIGHT_META: &str = "rightmeta"; + pub(crate) const ISO_LEVEL_3_SHIFT: &str = "isolevel3shift"; + pub(crate) const ISO_LEVEL_5_SHIFT: &str = "isolevel5shift"; } impl fmt::Display for KeyEvent { @@ -163,6 +197,44 @@ impl fmt::Display for KeyEvent { KeyCode::Char('>') => f.write_str(keys::GREATER_THAN)?, KeyCode::F(i) => f.write_fmt(format_args!("F{}", i))?, KeyCode::Char(c) => f.write_fmt(format_args!("{}", c))?, + KeyCode::CapsLock => f.write_str(keys::CAPS_LOCK)?, + KeyCode::ScrollLock => f.write_str(keys::SCROLL_LOCK)?, + KeyCode::NumLock => f.write_str(keys::NUM_LOCK)?, + KeyCode::PrintScreen => f.write_str(keys::PRINT_SCREEN)?, + KeyCode::Pause => f.write_str(keys::PAUSE)?, + KeyCode::Menu => f.write_str(keys::MENU)?, + KeyCode::KeypadBegin => f.write_str(keys::KEYPAD_BEGIN)?, + KeyCode::Media(MediaKeyCode::Play) => f.write_str(keys::PLAY)?, + KeyCode::Media(MediaKeyCode::Pause) => f.write_str(keys::PAUSE_MEDIA)?, + KeyCode::Media(MediaKeyCode::PlayPause) => f.write_str(keys::PLAY_PAUSE)?, + KeyCode::Media(MediaKeyCode::Stop) => f.write_str(keys::STOP)?, + KeyCode::Media(MediaKeyCode::Reverse) => f.write_str(keys::REVERSE)?, + KeyCode::Media(MediaKeyCode::FastForward) => f.write_str(keys::FAST_FORWARD)?, + KeyCode::Media(MediaKeyCode::Rewind) => f.write_str(keys::REWIND)?, + KeyCode::Media(MediaKeyCode::TrackNext) => f.write_str(keys::TRACK_NEXT)?, + KeyCode::Media(MediaKeyCode::TrackPrevious) => f.write_str(keys::TRACK_PREVIOUS)?, + KeyCode::Media(MediaKeyCode::Record) => f.write_str(keys::RECORD)?, + KeyCode::Media(MediaKeyCode::LowerVolume) => f.write_str(keys::LOWER_VOLUME)?, + KeyCode::Media(MediaKeyCode::RaiseVolume) => f.write_str(keys::RAISE_VOLUME)?, + KeyCode::Media(MediaKeyCode::MuteVolume) => f.write_str(keys::MUTE_VOLUME)?, + KeyCode::Modifier(ModifierKeyCode::LeftShift) => f.write_str(keys::LEFT_SHIFT)?, + KeyCode::Modifier(ModifierKeyCode::LeftControl) => f.write_str(keys::LEFT_CONTROL)?, + KeyCode::Modifier(ModifierKeyCode::LeftAlt) => f.write_str(keys::LEFT_ALT)?, + KeyCode::Modifier(ModifierKeyCode::LeftSuper) => f.write_str(keys::LEFT_SUPER)?, + KeyCode::Modifier(ModifierKeyCode::LeftHyper) => f.write_str(keys::LEFT_HYPER)?, + KeyCode::Modifier(ModifierKeyCode::LeftMeta) => f.write_str(keys::LEFT_META)?, + KeyCode::Modifier(ModifierKeyCode::RightShift) => f.write_str(keys::RIGHT_SHIFT)?, + KeyCode::Modifier(ModifierKeyCode::RightControl) => f.write_str(keys::RIGHT_CONTROL)?, + KeyCode::Modifier(ModifierKeyCode::RightAlt) => f.write_str(keys::RIGHT_ALT)?, + KeyCode::Modifier(ModifierKeyCode::RightSuper) => f.write_str(keys::RIGHT_SUPER)?, + KeyCode::Modifier(ModifierKeyCode::RightHyper) => f.write_str(keys::RIGHT_HYPER)?, + KeyCode::Modifier(ModifierKeyCode::RightMeta) => f.write_str(keys::RIGHT_META)?, + KeyCode::Modifier(ModifierKeyCode::IsoLevel3Shift) => { + f.write_str(keys::ISO_LEVEL_3_SHIFT)? + } + KeyCode::Modifier(ModifierKeyCode::IsoLevel5Shift) => { + f.write_str(keys::ISO_LEVEL_5_SHIFT)? + } }; Ok(()) } @@ -192,6 +264,40 @@ impl UnicodeWidthStr for KeyEvent { KeyCode::F(1..=9) => 2, KeyCode::F(_) => 3, KeyCode::Char(c) => c.width().unwrap_or(0), + KeyCode::CapsLock => keys::CAPS_LOCK.len(), + KeyCode::ScrollLock => keys::SCROLL_LOCK.len(), + KeyCode::NumLock => keys::NUM_LOCK.len(), + KeyCode::PrintScreen => keys::PRINT_SCREEN.len(), + KeyCode::Pause => keys::PAUSE.len(), + KeyCode::Menu => keys::MENU.len(), + KeyCode::KeypadBegin => keys::KEYPAD_BEGIN.len(), + KeyCode::Media(MediaKeyCode::Play) => keys::PLAY.len(), + KeyCode::Media(MediaKeyCode::Pause) => keys::PAUSE_MEDIA.len(), + KeyCode::Media(MediaKeyCode::PlayPause) => keys::PLAY_PAUSE.len(), + KeyCode::Media(MediaKeyCode::Stop) => keys::STOP.len(), + KeyCode::Media(MediaKeyCode::Reverse) => keys::REVERSE.len(), + KeyCode::Media(MediaKeyCode::FastForward) => keys::FAST_FORWARD.len(), + KeyCode::Media(MediaKeyCode::Rewind) => keys::REWIND.len(), + KeyCode::Media(MediaKeyCode::TrackNext) => keys::TRACK_NEXT.len(), + KeyCode::Media(MediaKeyCode::TrackPrevious) => keys::TRACK_PREVIOUS.len(), + KeyCode::Media(MediaKeyCode::Record) => keys::RECORD.len(), + KeyCode::Media(MediaKeyCode::LowerVolume) => keys::LOWER_VOLUME.len(), + KeyCode::Media(MediaKeyCode::RaiseVolume) => keys::RAISE_VOLUME.len(), + KeyCode::Media(MediaKeyCode::MuteVolume) => keys::MUTE_VOLUME.len(), + KeyCode::Modifier(ModifierKeyCode::LeftShift) => keys::LEFT_SHIFT.len(), + KeyCode::Modifier(ModifierKeyCode::LeftControl) => keys::LEFT_CONTROL.len(), + KeyCode::Modifier(ModifierKeyCode::LeftAlt) => keys::LEFT_ALT.len(), + KeyCode::Modifier(ModifierKeyCode::LeftSuper) => keys::LEFT_SUPER.len(), + KeyCode::Modifier(ModifierKeyCode::LeftHyper) => keys::LEFT_HYPER.len(), + KeyCode::Modifier(ModifierKeyCode::LeftMeta) => keys::LEFT_META.len(), + KeyCode::Modifier(ModifierKeyCode::RightShift) => keys::RIGHT_SHIFT.len(), + KeyCode::Modifier(ModifierKeyCode::RightControl) => keys::RIGHT_CONTROL.len(), + KeyCode::Modifier(ModifierKeyCode::RightAlt) => keys::RIGHT_ALT.len(), + KeyCode::Modifier(ModifierKeyCode::RightSuper) => keys::RIGHT_SUPER.len(), + KeyCode::Modifier(ModifierKeyCode::RightHyper) => keys::RIGHT_HYPER.len(), + KeyCode::Modifier(ModifierKeyCode::RightMeta) => keys::RIGHT_META.len(), + KeyCode::Modifier(ModifierKeyCode::IsoLevel3Shift) => keys::ISO_LEVEL_3_SHIFT.len(), + KeyCode::Modifier(ModifierKeyCode::IsoLevel5Shift) => keys::ISO_LEVEL_5_SHIFT.len(), }; if self.modifiers.contains(KeyModifiers::SHIFT) { width += 2; @@ -235,6 +341,40 @@ impl std::str::FromStr for KeyEvent { keys::MINUS => KeyCode::Char('-'), keys::LESS_THAN => KeyCode::Char('<'), keys::GREATER_THAN => KeyCode::Char('>'), + keys::CAPS_LOCK => KeyCode::CapsLock, + keys::SCROLL_LOCK => KeyCode::ScrollLock, + keys::NUM_LOCK => KeyCode::NumLock, + keys::PRINT_SCREEN => KeyCode::PrintScreen, + keys::PAUSE => KeyCode::Pause, + keys::MENU => KeyCode::Menu, + keys::KEYPAD_BEGIN => KeyCode::KeypadBegin, + keys::PLAY => KeyCode::Media(MediaKeyCode::Play), + keys::PAUSE_MEDIA => KeyCode::Media(MediaKeyCode::Pause), + keys::PLAY_PAUSE => KeyCode::Media(MediaKeyCode::PlayPause), + keys::STOP => KeyCode::Media(MediaKeyCode::Stop), + keys::REVERSE => KeyCode::Media(MediaKeyCode::Reverse), + keys::FAST_FORWARD => KeyCode::Media(MediaKeyCode::FastForward), + keys::REWIND => KeyCode::Media(MediaKeyCode::Rewind), + keys::TRACK_NEXT => KeyCode::Media(MediaKeyCode::TrackNext), + keys::TRACK_PREVIOUS => KeyCode::Media(MediaKeyCode::TrackPrevious), + keys::RECORD => KeyCode::Media(MediaKeyCode::Record), + keys::LOWER_VOLUME => KeyCode::Media(MediaKeyCode::LowerVolume), + keys::RAISE_VOLUME => KeyCode::Media(MediaKeyCode::RaiseVolume), + keys::MUTE_VOLUME => KeyCode::Media(MediaKeyCode::MuteVolume), + keys::LEFT_SHIFT => KeyCode::Modifier(ModifierKeyCode::LeftShift), + keys::LEFT_CONTROL => KeyCode::Modifier(ModifierKeyCode::LeftControl), + keys::LEFT_ALT => KeyCode::Modifier(ModifierKeyCode::LeftAlt), + keys::LEFT_SUPER => KeyCode::Modifier(ModifierKeyCode::LeftSuper), + keys::LEFT_HYPER => KeyCode::Modifier(ModifierKeyCode::LeftHyper), + keys::LEFT_META => KeyCode::Modifier(ModifierKeyCode::LeftMeta), + keys::RIGHT_SHIFT => KeyCode::Modifier(ModifierKeyCode::RightShift), + keys::RIGHT_CONTROL => KeyCode::Modifier(ModifierKeyCode::RightControl), + keys::RIGHT_ALT => KeyCode::Modifier(ModifierKeyCode::RightAlt), + keys::RIGHT_SUPER => KeyCode::Modifier(ModifierKeyCode::RightSuper), + keys::RIGHT_HYPER => KeyCode::Modifier(ModifierKeyCode::RightHyper), + keys::RIGHT_META => KeyCode::Modifier(ModifierKeyCode::RightMeta), + keys::ISO_LEVEL_3_SHIFT => KeyCode::Modifier(ModifierKeyCode::IsoLevel3Shift), + keys::ISO_LEVEL_5_SHIFT => KeyCode::Modifier(ModifierKeyCode::IsoLevel5Shift), single if single.chars().count() == 1 => KeyCode::Char(single.chars().next().unwrap()), function if function.len() > 1 && function.starts_with('F') => { let function: String = function.chars().skip(1).collect(); diff --git a/helix-view/src/keyboard.rs b/helix-view/src/keyboard.rs index 84cfebf160d7..cf673e113ce2 100644 --- a/helix-view/src/keyboard.rs +++ b/helix-view/src/keyboard.rs @@ -53,6 +53,164 @@ impl From for KeyModifiers { } } +/// Represents a media key (as part of [`KeyCode::Media`]). +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)] +pub enum MediaKeyCode { + /// Play media key. + Play, + /// Pause media key. + Pause, + /// Play/Pause media key. + PlayPause, + /// Reverse media key. + Reverse, + /// Stop media key. + Stop, + /// Fast-forward media key. + FastForward, + /// Rewind media key. + Rewind, + /// Next-track media key. + TrackNext, + /// Previous-track media key. + TrackPrevious, + /// Record media key. + Record, + /// Lower-volume media key. + LowerVolume, + /// Raise-volume media key. + RaiseVolume, + /// Mute media key. + MuteVolume, +} + +#[cfg(feature = "term")] +impl From for crossterm::event::MediaKeyCode { + fn from(media_key_code: MediaKeyCode) -> Self { + use crossterm::event::MediaKeyCode as CMediaKeyCode; + + match media_key_code { + MediaKeyCode::Play => CMediaKeyCode::Play, + MediaKeyCode::Pause => CMediaKeyCode::Pause, + MediaKeyCode::PlayPause => CMediaKeyCode::PlayPause, + MediaKeyCode::Reverse => CMediaKeyCode::Reverse, + MediaKeyCode::Stop => CMediaKeyCode::Stop, + MediaKeyCode::FastForward => CMediaKeyCode::FastForward, + MediaKeyCode::Rewind => CMediaKeyCode::Rewind, + MediaKeyCode::TrackNext => CMediaKeyCode::TrackNext, + MediaKeyCode::TrackPrevious => CMediaKeyCode::TrackPrevious, + MediaKeyCode::Record => CMediaKeyCode::Record, + MediaKeyCode::LowerVolume => CMediaKeyCode::LowerVolume, + MediaKeyCode::RaiseVolume => CMediaKeyCode::RaiseVolume, + MediaKeyCode::MuteVolume => CMediaKeyCode::MuteVolume, + } + } +} + +#[cfg(feature = "term")] +impl From for MediaKeyCode { + fn from(val: crossterm::event::MediaKeyCode) -> Self { + use crossterm::event::MediaKeyCode as CMediaKeyCode; + + match val { + CMediaKeyCode::Play => MediaKeyCode::Play, + CMediaKeyCode::Pause => MediaKeyCode::Pause, + CMediaKeyCode::PlayPause => MediaKeyCode::PlayPause, + CMediaKeyCode::Reverse => MediaKeyCode::Reverse, + CMediaKeyCode::Stop => MediaKeyCode::Stop, + CMediaKeyCode::FastForward => MediaKeyCode::FastForward, + CMediaKeyCode::Rewind => MediaKeyCode::Rewind, + CMediaKeyCode::TrackNext => MediaKeyCode::TrackNext, + CMediaKeyCode::TrackPrevious => MediaKeyCode::TrackPrevious, + CMediaKeyCode::Record => MediaKeyCode::Record, + CMediaKeyCode::LowerVolume => MediaKeyCode::LowerVolume, + CMediaKeyCode::RaiseVolume => MediaKeyCode::RaiseVolume, + CMediaKeyCode::MuteVolume => MediaKeyCode::MuteVolume, + } + } +} + +/// Represents a media key (as part of [`KeyCode::Modifier`]). +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)] +pub enum ModifierKeyCode { + /// Left Shift key. + LeftShift, + /// Left Control key. + LeftControl, + /// Left Alt key. + LeftAlt, + /// Left Super key. + LeftSuper, + /// Left Hyper key. + LeftHyper, + /// Left Meta key. + LeftMeta, + /// Right Shift key. + RightShift, + /// Right Control key. + RightControl, + /// Right Alt key. + RightAlt, + /// Right Super key. + RightSuper, + /// Right Hyper key. + RightHyper, + /// Right Meta key. + RightMeta, + /// Iso Level3 Shift key. + IsoLevel3Shift, + /// Iso Level5 Shift key. + IsoLevel5Shift, +} + +#[cfg(feature = "term")] +impl From for crossterm::event::ModifierKeyCode { + fn from(modifier_key_code: ModifierKeyCode) -> Self { + use crossterm::event::ModifierKeyCode as CModifierKeyCode; + + match modifier_key_code { + ModifierKeyCode::LeftShift => CModifierKeyCode::LeftShift, + ModifierKeyCode::LeftControl => CModifierKeyCode::LeftControl, + ModifierKeyCode::LeftAlt => CModifierKeyCode::LeftAlt, + ModifierKeyCode::LeftSuper => CModifierKeyCode::LeftSuper, + ModifierKeyCode::LeftHyper => CModifierKeyCode::LeftHyper, + ModifierKeyCode::LeftMeta => CModifierKeyCode::LeftMeta, + ModifierKeyCode::RightShift => CModifierKeyCode::RightShift, + ModifierKeyCode::RightControl => CModifierKeyCode::RightControl, + ModifierKeyCode::RightAlt => CModifierKeyCode::RightAlt, + ModifierKeyCode::RightSuper => CModifierKeyCode::RightSuper, + ModifierKeyCode::RightHyper => CModifierKeyCode::RightHyper, + ModifierKeyCode::RightMeta => CModifierKeyCode::RightMeta, + ModifierKeyCode::IsoLevel3Shift => CModifierKeyCode::IsoLevel3Shift, + ModifierKeyCode::IsoLevel5Shift => CModifierKeyCode::IsoLevel5Shift, + } + } +} + +#[cfg(feature = "term")] +impl From for ModifierKeyCode { + fn from(val: crossterm::event::ModifierKeyCode) -> Self { + use crossterm::event::ModifierKeyCode as CModifierKeyCode; + + match val { + CModifierKeyCode::LeftShift => ModifierKeyCode::LeftShift, + CModifierKeyCode::LeftControl => ModifierKeyCode::LeftControl, + CModifierKeyCode::LeftAlt => ModifierKeyCode::LeftAlt, + CModifierKeyCode::LeftSuper => ModifierKeyCode::LeftSuper, + CModifierKeyCode::LeftHyper => ModifierKeyCode::LeftHyper, + CModifierKeyCode::LeftMeta => ModifierKeyCode::LeftMeta, + CModifierKeyCode::RightShift => ModifierKeyCode::RightShift, + CModifierKeyCode::RightControl => ModifierKeyCode::RightControl, + CModifierKeyCode::RightAlt => ModifierKeyCode::RightAlt, + CModifierKeyCode::RightSuper => ModifierKeyCode::RightSuper, + CModifierKeyCode::RightHyper => ModifierKeyCode::RightHyper, + CModifierKeyCode::RightMeta => ModifierKeyCode::RightMeta, + CModifierKeyCode::IsoLevel3Shift => ModifierKeyCode::IsoLevel3Shift, + CModifierKeyCode::IsoLevel5Shift => ModifierKeyCode::IsoLevel5Shift, + } + } +} + /// Represents a key. #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)] pub enum KeyCode { @@ -94,6 +252,24 @@ pub enum KeyCode { Null, /// Escape key. Esc, + /// CapsLock key. + CapsLock, + /// ScrollLock key. + ScrollLock, + /// NumLock key. + NumLock, + /// PrintScreen key. + PrintScreen, + /// Pause key. + Pause, + /// Menu key. + Menu, + /// KeypadBegin key. + KeypadBegin, + /// A media key. + Media(MediaKeyCode), + /// A modifier key. + Modifier(ModifierKeyCode), } #[cfg(feature = "term")] @@ -119,6 +295,15 @@ impl From for crossterm::event::KeyCode { KeyCode::Char(character) => CKeyCode::Char(character), KeyCode::Null => CKeyCode::Null, KeyCode::Esc => CKeyCode::Esc, + KeyCode::CapsLock => CKeyCode::CapsLock, + KeyCode::ScrollLock => CKeyCode::ScrollLock, + KeyCode::NumLock => CKeyCode::NumLock, + KeyCode::PrintScreen => CKeyCode::PrintScreen, + KeyCode::Pause => CKeyCode::Pause, + KeyCode::Menu => CKeyCode::Menu, + KeyCode::KeypadBegin => CKeyCode::KeypadBegin, + KeyCode::Media(media_key_code) => CKeyCode::Media(media_key_code.into()), + KeyCode::Modifier(modifier_key_code) => CKeyCode::Modifier(modifier_key_code.into()), } } } @@ -147,17 +332,15 @@ impl From for KeyCode { CKeyCode::Char(character) => KeyCode::Char(character), CKeyCode::Null => KeyCode::Null, CKeyCode::Esc => KeyCode::Esc, - CKeyCode::CapsLock - | CKeyCode::ScrollLock - | CKeyCode::NumLock - | CKeyCode::PrintScreen - | CKeyCode::Pause - | CKeyCode::Menu - | CKeyCode::KeypadBegin - | CKeyCode::Media(_) - | CKeyCode::Modifier(_) => unreachable!( - "Shouldn't get this key without enabling DISAMBIGUATE_ESCAPE_CODES in crossterm" - ), + CKeyCode::CapsLock => KeyCode::CapsLock, + CKeyCode::ScrollLock => KeyCode::ScrollLock, + CKeyCode::NumLock => KeyCode::NumLock, + CKeyCode::PrintScreen => KeyCode::PrintScreen, + CKeyCode::Pause => KeyCode::Pause, + CKeyCode::Menu => KeyCode::Menu, + CKeyCode::KeypadBegin => KeyCode::KeypadBegin, + CKeyCode::Media(media_key_code) => KeyCode::Media(media_key_code.into()), + CKeyCode::Modifier(modifier_key_code) => KeyCode::Modifier(modifier_key_code.into()), } } } From 664d08e70d02a3e3917ddc69e66b5fc826a0caf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1?= Date: Tue, 29 Nov 2022 23:30:06 +0000 Subject: [PATCH 056/269] Fix ayu theme cursor issue (#4764) --- runtime/themes/ayu_dark.toml | 3 +-- runtime/themes/ayu_light.toml | 3 +-- runtime/themes/ayu_mirage.toml | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/runtime/themes/ayu_dark.toml b/runtime/themes/ayu_dark.toml index 3b989f828d1c..b297a3abdde8 100644 --- a/runtime/themes/ayu_dark.toml +++ b/runtime/themes/ayu_dark.toml @@ -10,7 +10,6 @@ "string.regexp" = "orange" "string.special" = "yellow" "comment" = { fg = "gray", modifiers = ["italic"] } -"comment.block.documentation" = { fg = "blue", modifiers = ["italic"] } "variable" = "foreground" "label" = "orange" "punctuation" = "foreground" @@ -34,7 +33,7 @@ # Interface "ui.background"= { bg = "background" } -"ui.cursor" = { modifiers = ["reversed"] } +"ui.cursor" = { fg = "dark_gray", bg = "orange" } "ui.cursor.match" = "orange" "ui.linenr" = "dark_gray" "ui.linenr.selected" = "gray" diff --git a/runtime/themes/ayu_light.toml b/runtime/themes/ayu_light.toml index 6a801951f8e3..ab0283fb6ec3 100644 --- a/runtime/themes/ayu_light.toml +++ b/runtime/themes/ayu_light.toml @@ -10,7 +10,6 @@ "string.regexp" = "orange" "string.special" = "yellow" "comment" = { fg = "gray", modifiers = ["italic"] } -"comment.block.documentation" = { fg = "blue", modifiers = ["italic"] } "variable" = "foreground" "label" = "orange" "punctuation" = "foreground" @@ -34,7 +33,7 @@ # Interface "ui.background"= { bg = "background" } -"ui.cursor" = { modifiers = ["reversed"] } +"ui.cursor" = { fg = "dark_gray", bg = "orange" } "ui.cursor.match" = "orange" "ui.linenr" = "dark_gray" "ui.linenr.selected" = "gray" diff --git a/runtime/themes/ayu_mirage.toml b/runtime/themes/ayu_mirage.toml index b1abd9a3c27d..d6af12fa76f8 100644 --- a/runtime/themes/ayu_mirage.toml +++ b/runtime/themes/ayu_mirage.toml @@ -10,7 +10,6 @@ "string.regexp" = "orange" "string.special" = "yellow" "comment" = { fg = "gray", modifiers = ["italic"] } -"comment.block.documentation" = { fg = "blue", modifiers = ["italic"] } "variable" = "foreground" "label" = "orange" "punctuation" = "foreground" @@ -34,7 +33,7 @@ # Interface "ui.background"= { bg = "background" } -"ui.cursor" = { modifiers = ["reversed"] } +"ui.cursor" = { fg = "dark_gray", bg = "orange" } "ui.cursor.match" = "orange" "ui.linenr" = "dark_gray" "ui.linenr.selected" = "gray" From 67415e096ea70173d30550803559eb2347ed04d6 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 30 Nov 2022 08:27:08 -0600 Subject: [PATCH 057/269] Fix file-types declaration for racket (#4915) Both the racket and scheme entries used the rkt file-extension. This commit removes that entry for scheme and so that the racket entry takes precedence. We explicitly point to the scheme grammar now and setup queries that inherit from scheme. This should enable using the racket language server configuration. --- book/src/generated/lang-support.md | 2 +- languages.toml | 3 ++- runtime/queries/racket/highlights.scm | 1 + runtime/queries/racket/injections.scm | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 runtime/queries/racket/highlights.scm create mode 100644 runtime/queries/racket/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 487057e61f3b..b1fde0016abb 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -95,7 +95,7 @@ | python | ✓ | ✓ | ✓ | `pylsp` | | qml | ✓ | | ✓ | `qmlls` | | r | ✓ | | | `R` | -| racket | | | | `racket` | +| racket | ✓ | | | `racket` | | regex | ✓ | | | | | rescript | ✓ | ✓ | | `rescript-language-server` | | rmarkdown | ✓ | | ✓ | `R` | diff --git a/languages.toml b/languages.toml index 756315cd6924..4eb8a4dab1d5 100644 --- a/languages.toml +++ b/languages.toml @@ -880,6 +880,7 @@ file-types = ["rkt"] shebangs = ["racket"] comment-token = ";" language-server = { command = "racket", args = ["-l", "racket-langserver"] } +grammar = "scheme" [[language]] name = "comment" @@ -1526,7 +1527,7 @@ source = { git = "https://github.com/metio/tree-sitter-ssh-client-config", rev = name = "scheme" scope = "source.scheme" injection-regex = "scheme" -file-types = ["ss", "rkt"] # "scm", +file-types = ["ss"] # "scm", roots = [] comment-token = ";" indent = { tab-width = 2, unit = " " } diff --git a/runtime/queries/racket/highlights.scm b/runtime/queries/racket/highlights.scm new file mode 100644 index 000000000000..e11eb7881081 --- /dev/null +++ b/runtime/queries/racket/highlights.scm @@ -0,0 +1 @@ +; inherits: scheme diff --git a/runtime/queries/racket/injections.scm b/runtime/queries/racket/injections.scm new file mode 100644 index 000000000000..e11eb7881081 --- /dev/null +++ b/runtime/queries/racket/injections.scm @@ -0,0 +1 @@ +; inherits: scheme From 5a3ff742218aac32c3af08993f0edb623631fc72 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Thu, 1 Dec 2022 09:35:23 +0100 Subject: [PATCH 058/269] Show (git) diff signs in gutter (#3890) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Show (git) diff signs in gutter (#3890) Avoid string allocation when git diffing Incrementally diff using changesets refactor diffs to be provider indepndent and improve git implementation remove dependency on zlib-ng switch to asynchronus diffing with similar Update helix-vcs/Cargo.toml fix toml formatting Co-authored-by: Ivan Tham fix typo in documentation use ropey reexpors from helix-core fix crash when creating new file remove useless use if io::Cursor fix spelling mistakes implement suggested improvement to repository loading improve git test isolation remove lefover comments Co-authored-by: univerz fixed spelling mistake minor cosmetic changes fix: set self.differ to None if decoding the diff_base fails fixup formatting Co-authored-by: Ivan Tham reload diff_base when file is reloaded from disk switch to imara-diff Fixup formatting Co-authored-by: Blaž Hrastnik Redraw buffer whenever a diff is updated. Only store hunks instead of changes for individual lines to easily allow jumping between them Update to latest gitoxide version Change default diff gutter position Only update gutter after timeout * update diff gutter synchronously, with a timeout * Apply suggestions from code review Co-authored-by: Blaž Hrastnik Co-authored-by: Michael Davis * address review comments and ensure lock is always aquired * remove configuration for redraw timeout Co-authored-by: Blaž Hrastnik Co-authored-by: Michael Davis --- Cargo.lock | 878 +++++++++++++++++++++++++++++- Cargo.toml | 1 + book/src/configuration.md | 2 +- helix-core/src/lib.rs | 2 +- helix-term/Cargo.toml | 3 + helix-term/src/application.rs | 50 +- helix-term/src/commands/typed.rs | 11 +- helix-term/src/ui/editor.rs | 2 +- helix-vcs/Cargo.toml | 28 + helix-vcs/src/diff.rs | 198 +++++++ helix-vcs/src/diff/line_cache.rs | 130 +++++ helix-vcs/src/diff/worker.rs | 207 +++++++ helix-vcs/src/diff/worker/test.rs | 149 +++++ helix-vcs/src/git.rs | 80 +++ helix-vcs/src/git/test.rs | 121 ++++ helix-vcs/src/lib.rs | 51 ++ helix-view/Cargo.toml | 2 + helix-view/src/document.rs | 52 +- helix-view/src/editor.rs | 75 ++- helix-view/src/gutter.rs | 55 +- helix-view/src/view.rs | 15 +- 21 files changed, 2036 insertions(+), 76 deletions(-) create mode 100644 helix-vcs/Cargo.toml create mode 100644 helix-vcs/src/diff.rs create mode 100644 helix-vcs/src/diff/line_cache.rs create mode 100644 helix-vcs/src/diff/worker.rs create mode 100644 helix-vcs/src/diff/worker/test.rs create mode 100644 helix-vcs/src/git.rs create mode 100644 helix-vcs/src/git/test.rs create mode 100644 helix-vcs/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 05a0396fafdc..2e0211972bb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "ahash" version = "0.7.6" @@ -55,6 +61,15 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "983cd8b9d4b02a6dc6ffa557262eb5858a27a0038ffffe21a0f133eaa819a164" +[[package]] +name = "atoi" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c57d12312ff59c811c0643f4d80830505833c9ffaebd193d819392b265be8e" +dependencies = [ + "num-traits", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -78,12 +93,43 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "bstr" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd" +dependencies = [ + "memchr", + "once_cell", + "regex-automata", + "serde", +] + +[[package]] +name = "btoi" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97c0869a9faa81f8bbf8102371105d6d0a7b79167a04c340b04ab16892246a11" +dependencies = [ + "num-traits", +] + [[package]] name = "bumpalo" version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +[[package]] +name = "byte-unit" +version = "4.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581ad4b3d627b0c09a0ccb2912148f839acaca0b93cf54cbe42b6c674e86079c" +dependencies = [ + "serde", + "utf8-width", +] + [[package]] name = "bytecount" version = "0.6.3" @@ -96,12 +142,27 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +[[package]] +name = "bytesize" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c58ec36aac5066d5ca17df51b3e70279f5670a72102f5752cb7e7c856adfc70" + [[package]] name = "cassowary" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" +[[package]] +name = "castaway" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc" +dependencies = [ + "rustversion", +] + [[package]] name = "cc" version = "1.0.77" @@ -148,6 +209,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "clru" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "218d6bd3dde8e442a975fa1cd233c0e5fded7596bccfe39f58eca98d22421e0a" + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -158,6 +225,17 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "compact_str" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5138945395949e7dfba09646dc9e766b548ff48e23deb5246890e6b64ae9e1b9" +dependencies = [ + "castaway", + "itoa", + "ryu", +] + [[package]] name = "content_inspector" version = "0.2.4" @@ -173,6 +251,15 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-utils" version = "0.8.14" @@ -252,6 +339,28 @@ dependencies = [ "syn", ] +[[package]] +name = "dashmap" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +dependencies = [ + "cfg-if", + "hashbrown 0.12.3", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -262,6 +371,17 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -336,6 +456,28 @@ dependencies = [ "log", ] +[[package]] +name = "filetime" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys", +] + +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -407,6 +549,498 @@ dependencies = [ "wasi", ] +[[package]] +name = "git-actor" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d4ce09c0a6c71c044700e5932877667f427f007b77e6c39ab49aebc4719e25" +dependencies = [ + "bstr 1.0.1", + "btoi", + "git-date", + "itoa", + "nom", + "quick-error", +] + +[[package]] +name = "git-attributes" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c62e66a042c6b39c6dbfa3be37d134900d99ff9c54bbe489ed560a573895d5d" +dependencies = [ + "bstr 1.0.1", + "compact_str", + "git-features", + "git-glob", + "git-path", + "git-quote", + "thiserror", + "unicode-bom", +] + +[[package]] +name = "git-bitmap" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327098a7ad27ae298d7e71602dbd4375cc828d755d10a720e4be0be1b4ec38f0" +dependencies = [ + "quick-error", +] + +[[package]] +name = "git-chunk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07b2bc1635b660ad6e30379a84a4946590a3c124b747107c2cca1d9dbb98f588" +dependencies = [ + "thiserror", +] + +[[package]] +name = "git-command" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e4b01997b6551554fdac6f02277d0d04c3e869daa649bedd06d38c86f11dc42" +dependencies = [ + "bstr 1.0.1", +] + +[[package]] +name = "git-config" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd8603e953bd4c9bf310e74e43697400f5542f1cc75fad46fbd7427135a9534f" +dependencies = [ + "bstr 1.0.1", + "git-config-value", + "git-features", + "git-glob", + "git-path", + "git-ref", + "git-sec", + "memchr", + "nom", + "once_cell", + "smallvec", + "thiserror", + "unicode-bom", +] + +[[package]] +name = "git-config-value" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f276bfe5806b414915112f1eec0f006206cdf5b8cc9bbb44ef7e52286dc3eb" +dependencies = [ + "bitflags", + "bstr 1.0.1", + "git-path", + "libc", + "thiserror", +] + +[[package]] +name = "git-credentials" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f540186ea56fd075ba2b923180ebf4318e66ceaeac0a2a518e75dab8517d339" +dependencies = [ + "bstr 1.0.1", + "git-command", + "git-config-value", + "git-path", + "git-prompt", + "git-sec", + "git-url", + "thiserror", +] + +[[package]] +name = "git-date" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37881e9725df41e15d16216d3a0cee251fd8a39d425f75b389112df5c7f20f3d" +dependencies = [ + "bstr 1.0.1", + "itoa", + "thiserror", + "time", +] + +[[package]] +name = "git-diff" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a88666a0ae4365b55a0cbf2efde68d2a4cff0747894ad229403bd60b0b2abc5" +dependencies = [ + "git-hash", + "git-object", + "imara-diff", + "thiserror", +] + +[[package]] +name = "git-discover" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881e4136d5599cfdb79d8ef60d650823d1a563589fa493d8e4961e64d78a79f2" +dependencies = [ + "bstr 1.0.1", + "git-hash", + "git-path", + "git-ref", + "git-sec", + "thiserror", +] + +[[package]] +name = "git-features" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be88ae837674c71b30c6517c6f5f1335f8135bb8a9ffef20000d211933bed08" +dependencies = [ + "crc32fast", + "flate2", + "git-hash", + "libc", + "once_cell", + "prodash", + "quick-error", + "sha1_smol", + "walkdir", +] + +[[package]] +name = "git-glob" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d756430237112f8c89049236f60fdcdb0005127b1f7e531d40984e4fe7daa90" +dependencies = [ + "bitflags", + "bstr 1.0.1", +] + +[[package]] +name = "git-hash" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d46e6c2d1e8da4438a87bf516a6761b300964a353541fea61e96b3c7b34554" +dependencies = [ + "hex", + "thiserror", +] + +[[package]] +name = "git-index" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "821583c2d12b1e864694eb0bf1cca10ff6a3f45966f5f834e0f921b496dbe7cb" +dependencies = [ + "atoi", + "bitflags", + "bstr 1.0.1", + "filetime", + "git-bitmap", + "git-features", + "git-hash", + "git-lock", + "git-object", + "git-traverse", + "itoa", + "memmap2", + "smallvec", + "thiserror", +] + +[[package]] +name = "git-lock" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0fe10bf961f62b1335b4c07785e64fb4d86c5ed367dc7cd9360f13c3eb7c78" +dependencies = [ + "fastrand", + "git-tempfile", + "quick-error", +] + +[[package]] +name = "git-mailmap" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb3f85ce84b2328aeb3124a809f7b3a63e59c4d63c227dba7a9cdf6fca6c0987" +dependencies = [ + "bstr 1.0.1", + "git-actor", + "quick-error", +] + +[[package]] +name = "git-object" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9469a8c00d8bb500ee76a12e455bb174b4ddf71674713335dd1a84313723f7b3" +dependencies = [ + "bstr 1.0.1", + "btoi", + "git-actor", + "git-features", + "git-hash", + "git-validate", + "hex", + "itoa", + "nom", + "smallvec", + "thiserror", +] + +[[package]] +name = "git-odb" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaaea7031ac7d8dfee232a16d7114395d118226214fb03fe4e15d1f4d62a88a6" +dependencies = [ + "arc-swap", + "git-features", + "git-hash", + "git-object", + "git-pack", + "git-path", + "git-quote", + "parking_lot", + "tempfile", + "thiserror", +] + +[[package]] +name = "git-pack" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc4386dff835ffdc3697c3558111f708fd7b7695c42a4347f2d211cf3246c8e1" +dependencies = [ + "bytesize", + "clru", + "dashmap", + "git-chunk", + "git-diff", + "git-features", + "git-hash", + "git-object", + "git-path", + "git-tempfile", + "git-traverse", + "hash_hasher", + "memmap2", + "parking_lot", + "smallvec", + "thiserror", +] + +[[package]] +name = "git-path" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "425dc1022690be13e6c5bde4b7e04d9504d323605ec314cd367cebf38a812572" +dependencies = [ + "bstr 1.0.1", + "thiserror", +] + +[[package]] +name = "git-prompt" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa6947935c0671342277bc883ff0687978477b570c1ffe2200b9ba5ac8afdd9f" +dependencies = [ + "git-command", + "git-config-value", + "nix", + "parking_lot", + "thiserror", +] + +[[package]] +name = "git-quote" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea17931d07cbe447f371bbdf45ff03c30ea86db43788166655a5302df87ecfc" +dependencies = [ + "bstr 1.0.1", + "btoi", + "quick-error", +] + +[[package]] +name = "git-ref" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "638c9e454bacb2965a43f05b4a383c8f66dc64f3a770bd0324b221c2a20e121d" +dependencies = [ + "git-actor", + "git-features", + "git-hash", + "git-lock", + "git-object", + "git-path", + "git-tempfile", + "git-validate", + "memmap2", + "nom", + "thiserror", +] + +[[package]] +name = "git-refspec" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9497af773538ae8cfda053ff7dd0a9e6c28d333ba653040f54b8b4ee32f14187" +dependencies = [ + "bstr 1.0.1", + "git-hash", + "git-revision", + "git-validate", + "smallvec", + "thiserror", +] + +[[package]] +name = "git-repository" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeb43e59612e493af6a433bf0a960de0042c8aa6f4e4c4cb414f03b97e296b82" +dependencies = [ + "byte-unit", + "clru", + "git-actor", + "git-attributes", + "git-config", + "git-credentials", + "git-date", + "git-diff", + "git-discover", + "git-features", + "git-glob", + "git-hash", + "git-index", + "git-lock", + "git-mailmap", + "git-object", + "git-odb", + "git-pack", + "git-path", + "git-prompt", + "git-ref", + "git-refspec", + "git-revision", + "git-sec", + "git-tempfile", + "git-traverse", + "git-url", + "git-validate", + "git-worktree", + "log", + "once_cell", + "signal-hook", + "smallvec", + "thiserror", + "unicode-normalization", +] + +[[package]] +name = "git-revision" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efd31c63c3745b5dba5ec7109eec41a9c717f4e1e797fe0ef93098f33f31b25" +dependencies = [ + "bstr 1.0.1", + "git-date", + "git-hash", + "git-object", + "hash_hasher", + "thiserror", +] + +[[package]] +name = "git-sec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c79769f6546814d0774db7295c768441016b7e40bdd414fa8dfae2c616a1892" +dependencies = [ + "bitflags", + "dirs", + "git-path", + "libc", + "windows", +] + +[[package]] +name = "git-tempfile" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d23bc6129de3cbd81e6c9d0d685b5540c6b41bd9fa0cc38f381bc300743d708" +dependencies = [ + "dashmap", + "libc", + "once_cell", + "signal-hook", + "signal-hook-registry", + "tempfile", +] + +[[package]] +name = "git-traverse" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0c4dd773c69f294f43ace8373d48eb770129791f104c6857fa8cac0505af89" +dependencies = [ + "git-hash", + "git-object", + "hash_hasher", + "thiserror", +] + +[[package]] +name = "git-url" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b7f8323196840e7932f5b60e1d9c1d6c140fd806bc512f8beedc3f990a1f81" +dependencies = [ + "bstr 1.0.1", + "git-features", + "git-path", + "home", + "thiserror", + "url", +] + +[[package]] +name = "git-validate" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5439d6aa0de838dfadd74a71e97a9e23ebc719fd11a9ab6788b835b112c8c3d" +dependencies = [ + "bstr 1.0.1", + "thiserror", +] + +[[package]] +name = "git-worktree" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45bcc69c36a29cfa283710b7901877ab251d658935f5a41ed824416af500e0ed" +dependencies = [ + "bstr 1.0.1", + "git-attributes", + "git-features", + "git-glob", + "git-hash", + "git-index", + "git-object", + "git-path", + "io-close", + "thiserror", +] + [[package]] name = "globset" version = "0.4.9" @@ -414,7 +1048,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" dependencies = [ "aho-corasick", - "bstr", + "bstr 0.2.17", "fnv", "log", "regex", @@ -436,7 +1070,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1345f8d33c89f2d5b081f2f2a41175adef9fd0bed2fea6a26c96c2deb027e58e" dependencies = [ "aho-corasick", - "bstr", + "bstr 0.2.17", "grep-matcher", "log", "regex", @@ -450,7 +1084,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48852bd08f9b4eb3040ecb6d2f4ade224afe880a9a0909c5563cc59fa67932cc" dependencies = [ - "bstr", + "bstr 0.2.17", "bytecount", "encoding_rs", "encoding_rs_io", @@ -459,6 +1093,12 @@ dependencies = [ "memmap2", ] +[[package]] +name = "hash_hasher" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74721d007512d0cb3338cd20f0654ac913920061a4c4d0d8708edb3f2a698c0c" + [[package]] name = "hashbrown" version = "0.12.3" @@ -576,6 +1216,7 @@ dependencies = [ "helix-loader", "helix-lsp", "helix-tui", + "helix-vcs", "helix-view", "ignore", "indoc", @@ -608,6 +1249,19 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "helix-vcs" +version = "0.6.0" +dependencies = [ + "git-repository", + "helix-core", + "imara-diff", + "log", + "parking_lot", + "tempfile", + "tokio", +] + [[package]] name = "helix-view" version = "0.6.0" @@ -624,6 +1278,7 @@ dependencies = [ "helix-loader", "helix-lsp", "helix-tui", + "helix-vcs", "log", "once_cell", "serde", @@ -645,6 +1300,27 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "home" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408" +dependencies = [ + "winapi", +] + +[[package]] +name = "human_format" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86cce260d758a9aa3d7c4b99d55c815a540f8a37514ba6046ab6be402a157cb0" + [[package]] name = "iana-time-zone" version = "0.1.53" @@ -722,6 +1398,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "io-close" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cadcf447f06744f8ce713d2d6239bb5bde2c357a452397a9ed90c625da390bc" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "itoa" version = "1.0.4" @@ -815,6 +1501,21 @@ dependencies = [ "libc", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.5" @@ -827,6 +1528,28 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "nix" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" +dependencies = [ + "autocfg", + "bitflags", + "cfg-if", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -856,6 +1579,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + [[package]] name = "once_cell" version = "1.16.0" @@ -912,6 +1644,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prodash" +version = "21.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e13d7bd38cdab08b3a8b780cedcc54238c84fdca4084eb188807b308bcf11e6" +dependencies = [ + "bytesize", + "human_format", +] + [[package]] name = "pulldown-cmark" version = "0.9.2" @@ -923,6 +1665,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quickcheck" version = "1.0.3" @@ -1021,6 +1769,12 @@ dependencies = [ "str_indices", ] +[[package]] +name = "rustversion" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" + [[package]] name = "ryu" version = "1.0.11" @@ -1090,6 +1844,12 @@ dependencies = [ "syn", ] +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + [[package]] name = "signal-hook" version = "0.3.14" @@ -1293,6 +2053,35 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "time" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +dependencies = [ + "itoa", + "libc", + "num_threads", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +dependencies = [ + "time-core", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -1384,6 +2173,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +[[package]] +name = "unicode-bom" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63ec69f541d875b783ca40184d655f2927c95f0bffd486faa83cd3ac3529ec32" + [[package]] name = "unicode-general-category" version = "0.6.0" @@ -1439,6 +2234,12 @@ dependencies = [ "serde", ] +[[package]] +name = "utf8-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" + [[package]] name = "version_check" version = "0.9.4" @@ -1558,57 +2359,114 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e30acc718a52fb130fec72b1cb5f55ffeeec9253e1b785e94db222178a6acaa1" +dependencies = [ + "windows_aarch64_gnullvm 0.40.0", + "windows_aarch64_msvc 0.40.0", + "windows_i686_gnu 0.40.0", + "windows_i686_msvc 0.40.0", + "windows_x86_64_gnu 0.40.0", + "windows_x86_64_gnullvm 0.40.0", + "windows_x86_64_msvc 0.40.0", +] + [[package]] name = "windows-sys" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.0", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm 0.42.0", + "windows_x86_64_msvc 0.42.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3caa4a1a16561b714323ca6b0817403738583033a6a92e04c5d10d4ba37ca10" + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +[[package]] +name = "windows_aarch64_msvc" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328973c62dfcc50fb1aaa8e7100676e0b642fe56bac6bafff3327902db843ab4" + [[package]] name = "windows_aarch64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +[[package]] +name = "windows_i686_gnu" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa5b09fad70f0df85dea2ac2a525537e415e2bf63ee31cf9b8e263645ee9f3c1" + [[package]] name = "windows_i686_gnu" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +[[package]] +name = "windows_i686_msvc" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1ad4031c1a98491fa195d8d43d7489cb749f135f2e5c4eed58da094bd0d876" + [[package]] name = "windows_i686_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +[[package]] +name = "windows_x86_64_gnu" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520ff37edd72da8064b49d2281182898e17f0688ae9f4070bca27e4b5c162ac7" + [[package]] name = "windows_x86_64_gnu" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046e5b82215102c44fd75f488f1b9158973d02aa34d06ed85c23d6f5520a2853" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +[[package]] +name = "windows_x86_64_msvc" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0c9c6df55dd1bfa76e131cef44bdd8ec9c819ef3611f04dfe453fd5bfeda28" + [[package]] name = "windows_x86_64_msvc" version = "0.42.0" diff --git a/Cargo.toml b/Cargo.toml index 9e985ddcd1c4..ecf6848e04a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "helix-lsp", "helix-dap", "helix-loader", + "helix-vcs", "xtask", ] diff --git a/book/src/configuration.md b/book/src/configuration.md index e4854cda1a70..0890d28328ca 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -46,7 +46,7 @@ on unix operating systems. | `line-number` | Line number display: `absolute` simply shows each line's number, while `relative` shows the distance from the current line. When unfocused or in insert mode, `relative` will still show absolute line numbers. | `absolute` | | `cursorline` | Highlight all lines with a cursor. | `false` | | `cursorcolumn` | Highlight all columns with a cursor. | `false` | -| `gutters` | Gutters to display: Available are `diagnostics` and `line-numbers` and `spacer`, note that `diagnostics` also includes other features like breakpoints, 1-width padding will be inserted if gutters is non-empty | `["diagnostics", "spacer", "line-numbers"]` | +| `gutters` | Gutters to display: Available are `diagnostics` and `diff` and `line-numbers` and `spacer`, note that `diagnostics` also includes other features like breakpoints, 1-width padding will be inserted if gutters is non-empty | `["diagnostics", "spacer", "line-numbers", "spacer", "diff"]` | | `auto-completion` | Enable automatic pop up of auto-completion. | `true` | | `auto-format` | Enable automatic formatting on save. | `true` | | `auto-save` | Enable automatic saving on focus moving away from Helix. Requires [focus event support](https://github.com/helix-editor/helix/wiki/Terminal-Support) from your terminal. | `false` | diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 5f60c04890de..0e76ebbbefca 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -83,7 +83,7 @@ pub fn find_root(root: Option<&str>, root_markers: &[String]) -> std::path::Path top_marker.map_or(current_dir, |a| a.to_path_buf()) } -pub use ropey::{str_utils, Rope, RopeBuilder, RopeSlice}; +pub use ropey::{self, str_utils, Rope, RopeBuilder, RopeSlice}; // pub use tendril::StrTendril as Tendril; pub use smartstring::SmartString; diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 485cabe90819..30bfc7ea38a3 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -17,8 +17,10 @@ build = true app = true [features] +default = ["git"] unicode-lines = ["helix-core/unicode-lines"] integration = [] +git = ["helix-vcs/git"] [[bin]] name = "hx" @@ -29,6 +31,7 @@ helix-core = { version = "0.6", path = "../helix-core" } helix-view = { version = "0.6", path = "../helix-view" } helix-lsp = { version = "0.6", path = "../helix-lsp" } helix-dap = { version = "0.6", path = "../helix-dap" } +helix-vcs = { version = "0.6", path = "../helix-vcs" } helix-loader = { version = "0.6", path = "../helix-loader" } anyhow = "1" diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 99d3af182edf..dc12ba3cddf5 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -274,16 +274,27 @@ impl Application { } #[cfg(feature = "integration")] - fn render(&mut self) {} + async fn render(&mut self) {} #[cfg(not(feature = "integration"))] - fn render(&mut self) { + async fn render(&mut self) { let mut cx = crate::compositor::Context { editor: &mut self.editor, jobs: &mut self.jobs, scroll: None, }; + // Acquire mutable access to the redraw_handle lock + // to ensure that there are no tasks running that want to block rendering + drop(cx.editor.redraw_handle.1.write().await); + cx.editor.needs_redraw = false; + { + // exhaust any leftover redraw notifications + let notify = cx.editor.redraw_handle.0.notified(); + tokio::pin!(notify); + notify.enable(); + } + let area = self .terminal .autoresize() @@ -304,7 +315,7 @@ impl Application { where S: Stream> + Unpin, { - self.render(); + self.render().await; self.last_render = Instant::now(); loop { @@ -329,18 +340,18 @@ impl Application { biased; Some(event) = input_stream.next() => { - self.handle_terminal_events(event); + self.handle_terminal_events(event).await; } Some(signal) = self.signals.next() => { self.handle_signals(signal).await; } Some(callback) = self.jobs.futures.next() => { self.jobs.handle_callback(&mut self.editor, &mut self.compositor, callback); - self.render(); + self.render().await; } Some(callback) = self.jobs.wait_futures.next() => { self.jobs.handle_callback(&mut self.editor, &mut self.compositor, callback); - self.render(); + self.render().await; } event = self.editor.wait_event() => { let _idle_handled = self.handle_editor_event(event).await; @@ -445,25 +456,25 @@ impl Application { self.compositor.resize(area); self.terminal.clear().expect("couldn't clear terminal"); - self.render(); + self.render().await; } signal::SIGUSR1 => { self.refresh_config(); - self.render(); + self.render().await; } _ => unreachable!(), } } - pub fn handle_idle_timeout(&mut self) { + pub async fn handle_idle_timeout(&mut self) { let mut cx = crate::compositor::Context { editor: &mut self.editor, jobs: &mut self.jobs, scroll: None, }; let should_render = self.compositor.handle_event(&Event::IdleTimeout, &mut cx); - if should_render { - self.render(); + if should_render || self.editor.needs_redraw { + self.render().await; } } @@ -536,11 +547,11 @@ impl Application { match event { EditorEvent::DocumentSaved(event) => { self.handle_document_write(event); - self.render(); + self.render().await; } EditorEvent::ConfigEvent(event) => { self.handle_config_events(event); - self.render(); + self.render().await; } EditorEvent::LanguageServerMessage((id, call)) => { self.handle_language_server_message(call, id).await; @@ -548,19 +559,19 @@ impl Application { let last = self.editor.language_servers.incoming.is_empty(); if last || self.last_render.elapsed() > LSP_DEADLINE { - self.render(); + self.render().await; self.last_render = Instant::now(); } } EditorEvent::DebuggerEvent(payload) => { let needs_render = self.editor.handle_debugger_message(payload).await; if needs_render { - self.render(); + self.render().await; } } EditorEvent::IdleTimer => { self.editor.clear_idle_timer(); - self.handle_idle_timeout(); + self.handle_idle_timeout().await; #[cfg(feature = "integration")] { @@ -572,7 +583,10 @@ impl Application { false } - pub fn handle_terminal_events(&mut self, event: Result) { + pub async fn handle_terminal_events( + &mut self, + event: Result, + ) { let mut cx = crate::compositor::Context { editor: &mut self.editor, jobs: &mut self.jobs, @@ -596,7 +610,7 @@ impl Application { }; if should_redraw && !self.editor.should_close() { - self.render(); + self.render().await; } } diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 2fa903a7e605..9f848efd9da6 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1028,10 +1028,12 @@ fn reload( } let scrolloff = cx.editor.config().scrolloff; + let redraw_handle = cx.editor.redraw_handle.clone(); let (view, doc) = current!(cx.editor); - doc.reload(view).map(|_| { - view.ensure_cursor_in_view(doc, scrolloff); - }) + doc.reload(view, &cx.editor.diff_providers, redraw_handle) + .map(|_| { + view.ensure_cursor_in_view(doc, scrolloff); + }) } fn reload_all( @@ -1066,7 +1068,8 @@ fn reload_all( // Every doc is guaranteed to have at least 1 view at this point. let view = view_mut!(cx.editor, view_ids[0]); - doc.reload(view)?; + let redraw_handle = cx.editor.redraw_handle.clone(); + doc.reload(view, &cx.editor.diff_providers, redraw_handle)?; for view_id in view_ids { let view = view_mut!(cx.editor, view_id); diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 7bda74d283eb..32c8fe91af93 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -730,7 +730,7 @@ impl EditorView { let mut text = String::with_capacity(8); for gutter_type in view.gutters() { - let gutter = gutter_type.style(editor, doc, view, theme, is_focused); + let mut gutter = gutter_type.style(editor, doc, view, theme, is_focused); let width = gutter_type.width(view, doc); text.reserve(width); // ensure there's enough space for the gutter for (i, line) in (view.offset.row..(last_line + 1)).enumerate() { diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml new file mode 100644 index 000000000000..c114666d26d5 --- /dev/null +++ b/helix-vcs/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "helix-vcs" +version = "0.6.0" +authors = ["Blaž Hrastnik "] +edition = "2021" +license = "MPL-2.0" +categories = ["editor"] +repository = "https://github.com/helix-editor/helix" +homepage = "https://helix-editor.com" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +helix-core = { version = "0.6", path = "../helix-core" } + +tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "parking_lot", "macros"] } +parking_lot = "0.12" + +git-repository = { version = "0.26", default-features = false , optional = true } +imara-diff = "0.1.5" + +log = "0.4" + +[features] +git = ["git-repository"] + +[dev-dependencies] +tempfile = "3.3" \ No newline at end of file diff --git a/helix-vcs/src/diff.rs b/helix-vcs/src/diff.rs new file mode 100644 index 000000000000..b1acd1f29937 --- /dev/null +++ b/helix-vcs/src/diff.rs @@ -0,0 +1,198 @@ +use std::ops::Range; +use std::sync::Arc; + +use helix_core::Rope; +use imara_diff::Algorithm; +use parking_lot::{Mutex, MutexGuard}; +use tokio::sync::mpsc::{unbounded_channel, UnboundedSender}; +use tokio::sync::{Notify, OwnedRwLockReadGuard, RwLock}; +use tokio::task::JoinHandle; +use tokio::time::Instant; + +use crate::diff::worker::DiffWorker; + +mod line_cache; +mod worker; + +type RedrawHandle = (Arc, Arc>); + +/// A rendering lock passed to the differ the prevents redraws from occurring +struct RenderLock { + pub lock: OwnedRwLockReadGuard<()>, + pub timeout: Option, +} + +struct Event { + text: Rope, + is_base: bool, + render_lock: Option, +} + +#[derive(Clone, Debug)] +pub struct DiffHandle { + channel: UnboundedSender, + render_lock: Arc>, + hunks: Arc>>, + inverted: bool, +} + +impl DiffHandle { + pub fn new(diff_base: Rope, doc: Rope, redraw_handle: RedrawHandle) -> DiffHandle { + DiffHandle::new_with_handle(diff_base, doc, redraw_handle).0 + } + + fn new_with_handle( + diff_base: Rope, + doc: Rope, + redraw_handle: RedrawHandle, + ) -> (DiffHandle, JoinHandle<()>) { + let (sender, receiver) = unbounded_channel(); + let hunks: Arc>> = Arc::default(); + let worker = DiffWorker { + channel: receiver, + hunks: hunks.clone(), + new_hunks: Vec::default(), + redraw_notify: redraw_handle.0, + diff_finished_notify: Arc::default(), + }; + let handle = tokio::spawn(worker.run(diff_base, doc)); + let differ = DiffHandle { + channel: sender, + hunks, + inverted: false, + render_lock: redraw_handle.1, + }; + (differ, handle) + } + + pub fn invert(&mut self) { + self.inverted = !self.inverted; + } + + pub fn hunks(&self) -> FileHunks { + FileHunks { + hunks: self.hunks.lock(), + inverted: self.inverted, + } + } + + /// Updates the document associated with this redraw handle + /// This function is only intended to be called from within the rendering loop + /// if called from elsewhere it may fail to acquire the render lock and panic + pub fn update_document(&self, doc: Rope, block: bool) -> bool { + // unwrap is ok here because the rendering lock is + // only exclusively locked during redraw. + // This function is only intended to be called + // from the core rendering loop where no redraw can happen in parallel + let lock = self.render_lock.clone().try_read_owned().unwrap(); + let timeout = if block { + None + } else { + Some(Instant::now() + tokio::time::Duration::from_millis(SYNC_DIFF_TIMEOUT)) + }; + self.update_document_impl(doc, self.inverted, Some(RenderLock { lock, timeout })) + } + + pub fn update_diff_base(&self, diff_base: Rope) -> bool { + self.update_document_impl(diff_base, !self.inverted, None) + } + + fn update_document_impl( + &self, + text: Rope, + is_base: bool, + render_lock: Option, + ) -> bool { + let event = Event { + text, + is_base, + render_lock, + }; + self.channel.send(event).is_ok() + } +} + +/// synchronous debounce value should be low +/// so we can update synchronously most of the time +const DIFF_DEBOUNCE_TIME_SYNC: u64 = 1; +/// maximum time that rendering should be blocked until the diff finishes +const SYNC_DIFF_TIMEOUT: u64 = 12; +const DIFF_DEBOUNCE_TIME_ASYNC: u64 = 96; +const ALGORITHM: Algorithm = Algorithm::Histogram; +const MAX_DIFF_LINES: usize = 64 * u16::MAX as usize; +// cap average line length to 128 for files with MAX_DIFF_LINES +const MAX_DIFF_BYTES: usize = MAX_DIFF_LINES * 128; + +/// A single change in a file potentially spanning multiple lines +/// Hunks produced by the differs are always ordered by their position +/// in the file and non-overlapping. +/// Specifically for any two hunks `x` and `y` the following properties hold: +/// +/// ``` no_compile +/// assert!(x.before.end <= y.before.start); +/// assert!(x.after.end <= y.after.start); +/// ``` +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct Hunk { + pub before: Range, + pub after: Range, +} + +impl Hunk { + /// Can be used instead of `Option::None` for better performance + /// because lines larger then `i32::MAX` are not supported by `imara-diff` anyways. + /// Has some nice properties where it usually is not necessary to check for `None` separately: + /// Empty ranges fail contains checks and also fails smaller then checks. + pub const NONE: Hunk = Hunk { + before: u32::MAX..u32::MAX, + after: u32::MAX..u32::MAX, + }; + + /// Inverts a change so that `before` + pub fn invert(&self) -> Hunk { + Hunk { + before: self.after.clone(), + after: self.before.clone(), + } + } + + pub fn is_pure_insertion(&self) -> bool { + self.before.is_empty() + } + + pub fn is_pure_removal(&self) -> bool { + self.after.is_empty() + } +} + +/// A list of changes in a file sorted in ascending +/// non-overlapping order +#[derive(Debug)] +pub struct FileHunks<'a> { + hunks: MutexGuard<'a, Vec>, + inverted: bool, +} + +impl FileHunks<'_> { + pub fn is_inverted(&self) -> bool { + self.inverted + } + + /// Returns the `Hunk` for the `n`th change in this file. + /// if there is no `n`th change `Hunk::NONE` is returned instead. + pub fn nth_hunk(&self, n: u32) -> Hunk { + match self.hunks.get(n as usize) { + Some(hunk) if self.inverted => hunk.invert(), + Some(hunk) => hunk.clone(), + None => Hunk::NONE, + } + } + + pub fn len(&self) -> u32 { + self.hunks.len() as u32 + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} diff --git a/helix-vcs/src/diff/line_cache.rs b/helix-vcs/src/diff/line_cache.rs new file mode 100644 index 000000000000..c3ee5daa3e79 --- /dev/null +++ b/helix-vcs/src/diff/line_cache.rs @@ -0,0 +1,130 @@ +//! This modules encapsulates a tiny bit of unsafe code that +//! makes diffing significantly faster and more ergonomic to implement. +//! This code is necessary because diffing requires quick random +//! access to the lines of the text that is being diffed. +//! +//! Therefore it is best to collect the `Rope::lines` iterator into a vec +//! first because access to the vec is `O(1)` where `Rope::line` is `O(log N)`. +//! However this process can allocate a (potentially quite large) vector. +//! +//! To avoid reallocation for every diff, the vector is reused. +//! However the RopeSlice references the original rope and therefore forms a self-referential data structure. +//! A transmute is used to change the lifetime of the slice to static to circumvent that project. +use std::mem::transmute; + +use helix_core::{Rope, RopeSlice}; +use imara_diff::intern::{InternedInput, Interner}; + +use super::{MAX_DIFF_BYTES, MAX_DIFF_LINES}; + +/// A cache that stores the `lines` of a rope as a vector. +/// It allows safely reusing the allocation of the vec when updating the rope +pub(crate) struct InternedRopeLines { + diff_base: Rope, + doc: Rope, + num_tokens_diff_base: u32, + interned: InternedInput>, +} + +impl InternedRopeLines { + pub fn new(diff_base: Rope, doc: Rope) -> InternedRopeLines { + let mut res = InternedRopeLines { + interned: InternedInput { + before: Vec::with_capacity(diff_base.len_lines()), + after: Vec::with_capacity(doc.len_lines()), + interner: Interner::new(diff_base.len_lines() + doc.len_lines()), + }, + diff_base, + doc, + // will be populated by update_diff_base_impl + num_tokens_diff_base: 0, + }; + res.update_diff_base_impl(); + res + } + + /// Updates the `diff_base` and optionally the document if `doc` is not None + pub fn update_diff_base(&mut self, diff_base: Rope, doc: Option) { + self.interned.clear(); + self.diff_base = diff_base; + if let Some(doc) = doc { + self.doc = doc + } + if !self.is_too_large() { + self.update_diff_base_impl(); + } + } + + /// Updates the `doc` without reinterning the `diff_base`, this function + /// is therefore significantly faster than `update_diff_base` when only the document changes. + pub fn update_doc(&mut self, doc: Rope) { + // Safety: we clear any tokens that were added after + // the interning of `self.diff_base` finished so + // all lines that refer to `self.doc` have been purged. + + self.interned + .interner + .erase_tokens_after(self.num_tokens_diff_base.into()); + + self.doc = doc; + if self.is_too_large() { + self.interned.after.clear(); + } else { + self.update_doc_impl(); + } + } + + fn update_diff_base_impl(&mut self) { + // Safety: This transmute is safe because it only transmutes a lifetime, which has no effect. + // The backing storage for the RopeSlices referred to by the lifetime is stored in `self.diff_base`. + // Therefore as long as `self.diff_base` is not dropped/replaced this memory remains valid. + // `self.diff_base` is only changed in `self.update_diff_base`, which clears the interner. + // When the interned lines are exposed to consumer in `self.diff_input`, the lifetime is bounded to a reference to self. + // That means that on calls to update there exist no references to `self.interned`. + let before = self + .diff_base + .lines() + .map(|line: RopeSlice| -> RopeSlice<'static> { unsafe { transmute(line) } }); + self.interned.update_before(before); + self.num_tokens_diff_base = self.interned.interner.num_tokens(); + // the has to be interned again because the interner was fully cleared + self.update_doc_impl() + } + + fn update_doc_impl(&mut self) { + // Safety: This transmute is save because it only transmutes a lifetime, which has no effect. + // The backing storage for the RopeSlices referred to by the lifetime is stored in `self.doc`. + // Therefore as long as `self.doc` is not dropped/replaced this memory remains valid. + // `self.doc` is only changed in `self.update_doc`, which clears the interner. + // When the interned lines are exposed to consumer in `self.diff_input`, the lifetime is bounded to a reference to self. + // That means that on calls to update there exist no references to `self.interned`. + let after = self + .doc + .lines() + .map(|line: RopeSlice| -> RopeSlice<'static> { unsafe { transmute(line) } }); + self.interned.update_after(after); + } + + fn is_too_large(&self) -> bool { + // bound both lines and bytes to avoid huge files with few (but huge) lines + // or huge file with tiny lines. While this makes no difference to + // diff itself (the diff performance only depends on the number of tokens) + // the interning runtime depends mostly on filesize and is actually dominant + // for large files + self.doc.len_lines() > MAX_DIFF_LINES + || self.diff_base.len_lines() > MAX_DIFF_LINES + || self.doc.len_bytes() > MAX_DIFF_BYTES + || self.diff_base.len_bytes() > MAX_DIFF_BYTES + } + + /// Returns the `InternedInput` for performing the diff. + /// If `diff_base` or `doc` is so large that performing a diff could slow the editor + /// this function returns `None`. + pub fn interned_lines(&self) -> Option<&InternedInput> { + if self.is_too_large() { + None + } else { + Some(&self.interned) + } + } +} diff --git a/helix-vcs/src/diff/worker.rs b/helix-vcs/src/diff/worker.rs new file mode 100644 index 000000000000..b8659c9b3bc2 --- /dev/null +++ b/helix-vcs/src/diff/worker.rs @@ -0,0 +1,207 @@ +use std::mem::swap; +use std::ops::Range; +use std::sync::Arc; + +use helix_core::{Rope, RopeSlice}; +use imara_diff::intern::InternedInput; +use parking_lot::Mutex; +use tokio::sync::mpsc::UnboundedReceiver; +use tokio::sync::Notify; +use tokio::time::{timeout, timeout_at, Duration}; + +use crate::diff::{ + Event, RenderLock, ALGORITHM, DIFF_DEBOUNCE_TIME_ASYNC, DIFF_DEBOUNCE_TIME_SYNC, +}; + +use super::line_cache::InternedRopeLines; +use super::Hunk; + +#[cfg(test)] +mod test; + +pub(super) struct DiffWorker { + pub channel: UnboundedReceiver, + pub hunks: Arc>>, + pub new_hunks: Vec, + pub redraw_notify: Arc, + pub diff_finished_notify: Arc, +} + +impl DiffWorker { + async fn accumulate_events(&mut self, event: Event) -> (Option, Option) { + let mut accumulator = EventAccumulator::new(); + accumulator.handle_event(event).await; + accumulator + .accumulate_debounced_events( + &mut self.channel, + self.redraw_notify.clone(), + self.diff_finished_notify.clone(), + ) + .await; + (accumulator.doc, accumulator.diff_base) + } + + pub async fn run(mut self, diff_base: Rope, doc: Rope) { + let mut interner = InternedRopeLines::new(diff_base, doc); + if let Some(lines) = interner.interned_lines() { + self.perform_diff(lines); + } + self.apply_hunks(); + while let Some(event) = self.channel.recv().await { + let (doc, diff_base) = self.accumulate_events(event).await; + + let process_accumulated_events = || { + if let Some(new_base) = diff_base { + interner.update_diff_base(new_base, doc) + } else { + interner.update_doc(doc.unwrap()) + } + + if let Some(lines) = interner.interned_lines() { + self.perform_diff(lines) + } + }; + + // Calculating diffs is computationally expensive and should + // not run inside an async function to avoid blocking other futures. + // Note: tokio::task::block_in_place does not work during tests + #[cfg(test)] + process_accumulated_events(); + #[cfg(not(test))] + tokio::task::block_in_place(process_accumulated_events); + + self.apply_hunks(); + } + } + + /// update the hunks (used by the gutter) by replacing it with `self.new_hunks`. + /// `self.new_hunks` is always empty after this function runs. + /// To improve performance this function tries to reuse the allocation of the old diff previously stored in `self.line_diffs` + fn apply_hunks(&mut self) { + swap(&mut *self.hunks.lock(), &mut self.new_hunks); + self.diff_finished_notify.notify_waiters(); + self.new_hunks.clear(); + } + + fn perform_diff(&mut self, input: &InternedInput) { + imara_diff::diff(ALGORITHM, input, |before: Range, after: Range| { + self.new_hunks.push(Hunk { before, after }) + }) + } +} + +struct EventAccumulator { + diff_base: Option, + doc: Option, + render_lock: Option, +} + +impl<'a> EventAccumulator { + fn new() -> EventAccumulator { + EventAccumulator { + diff_base: None, + doc: None, + render_lock: None, + } + } + + async fn handle_event(&mut self, event: Event) { + let dst = if event.is_base { + &mut self.diff_base + } else { + &mut self.doc + }; + + *dst = Some(event.text); + + // always prefer the most synchronous requested render mode + if let Some(render_lock) = event.render_lock { + match &mut self.render_lock { + Some(RenderLock { timeout, .. }) => { + // A timeout of `None` means that the render should + // always wait for the diff to complete (so no timeout) + // remove the existing timeout, otherwise keep the previous timeout + // because it will be shorter then the current timeout + if render_lock.timeout.is_none() { + timeout.take(); + } + } + None => self.render_lock = Some(render_lock), + } + } + } + + async fn accumulate_debounced_events( + &mut self, + channel: &mut UnboundedReceiver, + redraw_notify: Arc, + diff_finished_notify: Arc, + ) { + let async_debounce = Duration::from_millis(DIFF_DEBOUNCE_TIME_ASYNC); + let sync_debounce = Duration::from_millis(DIFF_DEBOUNCE_TIME_SYNC); + loop { + // if we are not blocking rendering use a much longer timeout + let debounce = if self.render_lock.is_none() { + async_debounce + } else { + sync_debounce + }; + + if let Ok(Some(event)) = timeout(debounce, channel.recv()).await { + self.handle_event(event).await; + } else { + break; + } + } + + // setup task to trigger the rendering + match self.render_lock.take() { + // diff is performed outside of the rendering loop + // request a redraw after the diff is done + None => { + tokio::spawn(async move { + diff_finished_notify.notified().await; + redraw_notify.notify_one(); + }); + } + // diff is performed inside the rendering loop + // block redraw until the diff is done or the timeout is expired + Some(RenderLock { + lock, + timeout: Some(timeout), + }) => { + tokio::spawn(async move { + let res = { + // Acquire a lock on the redraw handle. + // The lock will block the rendering from occurring while held. + // The rendering waits for the diff if it doesn't time out + timeout_at(timeout, diff_finished_notify.notified()).await + }; + // we either reached the timeout or the diff is finished, release the render lock + drop(lock); + if res.is_ok() { + // Diff finished in time we are done. + return; + } + // Diff failed to complete in time log the event + // and wait until the diff occurs to trigger an async redraw + log::warn!("Diff computation timed out, update of diffs might appear delayed"); + diff_finished_notify.notified().await; + redraw_notify.notify_one(); + }); + } + // a blocking diff is performed inside the rendering loop + // block redraw until the diff is done + Some(RenderLock { + lock, + timeout: None, + }) => { + tokio::spawn(async move { + diff_finished_notify.notified().await; + // diff is done release the lock + drop(lock) + }); + } + }; + } +} diff --git a/helix-vcs/src/diff/worker/test.rs b/helix-vcs/src/diff/worker/test.rs new file mode 100644 index 000000000000..1444242651c8 --- /dev/null +++ b/helix-vcs/src/diff/worker/test.rs @@ -0,0 +1,149 @@ +use helix_core::Rope; +use tokio::task::JoinHandle; + +use crate::diff::{DiffHandle, Hunk}; + +impl DiffHandle { + fn new_test(diff_base: &str, doc: &str) -> (DiffHandle, JoinHandle<()>) { + DiffHandle::new_with_handle( + Rope::from_str(diff_base), + Rope::from_str(doc), + Default::default(), + ) + } + async fn into_diff(self, handle: JoinHandle<()>) -> Vec { + let hunks = self.hunks; + // dropping the channel terminates the task + drop(self.channel); + handle.await.unwrap(); + let hunks = hunks.lock(); + Vec::clone(&*hunks) + } +} + +#[tokio::test] +async fn append_line() { + let (differ, handle) = DiffHandle::new_test("foo\n", "foo\nbar\n"); + let line_diffs = differ.into_diff(handle).await; + assert_eq!( + &line_diffs, + &[Hunk { + before: 1..1, + after: 1..2 + }] + ) +} + +#[tokio::test] +async fn prepend_line() { + let (differ, handle) = DiffHandle::new_test("foo\n", "bar\nfoo\n"); + let line_diffs = differ.into_diff(handle).await; + assert_eq!( + &line_diffs, + &[Hunk { + before: 0..0, + after: 0..1 + }] + ) +} + +#[tokio::test] +async fn modify() { + let (differ, handle) = DiffHandle::new_test("foo\nbar\n", "foo bar\nbar\n"); + let line_diffs = differ.into_diff(handle).await; + assert_eq!( + &line_diffs, + &[Hunk { + before: 0..1, + after: 0..1 + }] + ) +} + +#[tokio::test] +async fn delete_line() { + let (differ, handle) = DiffHandle::new_test("foo\nfoo bar\nbar\n", "foo\nbar\n"); + let line_diffs = differ.into_diff(handle).await; + assert_eq!( + &line_diffs, + &[Hunk { + before: 1..2, + after: 1..1 + }] + ) +} + +#[tokio::test] +async fn delete_line_and_modify() { + let (differ, handle) = DiffHandle::new_test("foo\nbar\ntest\nfoo", "foo\ntest\nfoo bar"); + let line_diffs = differ.into_diff(handle).await; + assert_eq!( + &line_diffs, + &[ + Hunk { + before: 1..2, + after: 1..1 + }, + Hunk { + before: 3..4, + after: 2..3 + }, + ] + ) +} + +#[tokio::test] +async fn add_use() { + let (differ, handle) = DiffHandle::new_test( + "use ropey::Rope;\nuse tokio::task::JoinHandle;\n", + "use ropey::Rope;\nuse ropey::RopeSlice;\nuse tokio::task::JoinHandle;\n", + ); + let line_diffs = differ.into_diff(handle).await; + assert_eq!( + &line_diffs, + &[Hunk { + before: 1..1, + after: 1..2 + },] + ) +} + +#[tokio::test] +async fn update_document() { + let (differ, handle) = DiffHandle::new_test("foo\nbar\ntest\nfoo", "foo\nbar\ntest\nfoo"); + differ.update_document(Rope::from_str("foo\ntest\nfoo bar"), false); + let line_diffs = differ.into_diff(handle).await; + assert_eq!( + &line_diffs, + &[ + Hunk { + before: 1..2, + after: 1..1 + }, + Hunk { + before: 3..4, + after: 2..3 + }, + ] + ) +} + +#[tokio::test] +async fn update_base() { + let (differ, handle) = DiffHandle::new_test("foo\ntest\nfoo bar", "foo\ntest\nfoo bar"); + differ.update_diff_base(Rope::from_str("foo\nbar\ntest\nfoo")); + let line_diffs = differ.into_diff(handle).await; + assert_eq!( + &line_diffs, + &[ + Hunk { + before: 1..2, + after: 1..1 + }, + Hunk { + before: 3..4, + after: 2..3 + }, + ] + ) +} diff --git a/helix-vcs/src/git.rs b/helix-vcs/src/git.rs new file mode 100644 index 000000000000..82b2b5587fc4 --- /dev/null +++ b/helix-vcs/src/git.rs @@ -0,0 +1,80 @@ +use std::path::Path; + +use git::objs::tree::EntryMode; +use git::sec::trust::DefaultForLevel; +use git::{Commit, ObjectId, Repository, ThreadSafeRepository}; +use git_repository as git; + +use crate::DiffProvider; + +#[cfg(test)] +mod test; + +pub struct Git; + +impl Git { + fn open_repo(path: &Path, ceiling_dir: Option<&Path>) -> Option { + // custom open options + let mut git_open_opts_map = git::sec::trust::Mapping::::default(); + + // don't use the global git configs (not needed) + let config = git::permissions::Config { + system: false, + git: false, + user: false, + env: true, + includes: true, + git_binary: false, + }; + // change options for config permissions without touching anything else + git_open_opts_map.reduced = git_open_opts_map.reduced.permissions(git::Permissions { + config, + ..git::Permissions::default_for_level(git::sec::Trust::Reduced) + }); + git_open_opts_map.full = git_open_opts_map.full.permissions(git::Permissions { + config, + ..git::Permissions::default_for_level(git::sec::Trust::Full) + }); + + let mut open_options = git::discover::upwards::Options::default(); + if let Some(ceiling_dir) = ceiling_dir { + open_options.ceiling_dirs = vec![ceiling_dir.to_owned()]; + } + + ThreadSafeRepository::discover_with_environment_overrides_opts( + path, + open_options, + git_open_opts_map, + ) + .ok() + } +} + +impl DiffProvider for Git { + fn get_diff_base(&self, file: &Path) -> Option> { + debug_assert!(!file.exists() || file.is_file()); + debug_assert!(file.is_absolute()); + + // TODO cache repository lookup + let repo = Git::open_repo(file.parent()?, None)?.to_thread_local(); + let head = repo.head_commit().ok()?; + let file_oid = find_file_in_commit(&repo, &head, file)?; + + let file_object = repo.find_object(file_oid).ok()?; + Some(file_object.detach().data) + } +} + +/// Finds the object that contains the contents of a file at a specific commit. +fn find_file_in_commit(repo: &Repository, commit: &Commit, file: &Path) -> Option { + let repo_dir = repo.work_dir()?; + let rel_path = file.strip_prefix(repo_dir).ok()?; + let tree = commit.tree().ok()?; + let tree_entry = tree.lookup_entry_by_path(rel_path).ok()??; + match tree_entry.mode() { + // not a file, everything is new, do not show diff + EntryMode::Tree | EntryMode::Commit | EntryMode::Link => None, + // found a file + EntryMode::Blob | EntryMode::BlobExecutable => Some(tree_entry.object_id()), + } +} diff --git a/helix-vcs/src/git/test.rs b/helix-vcs/src/git/test.rs new file mode 100644 index 000000000000..d6e9af08868a --- /dev/null +++ b/helix-vcs/src/git/test.rs @@ -0,0 +1,121 @@ +use std::{fs::File, io::Write, path::Path, process::Command}; + +use tempfile::TempDir; + +use crate::{DiffProvider, Git}; + +fn exec_git_cmd(args: &str, git_dir: &Path) { + let res = Command::new("git") + .arg("-C") + .arg(git_dir) // execute the git command in this directory + .args(args.split_whitespace()) + .env_remove("GIT_DIR") + .env_remove("GIT_ASKPASS") + .env_remove("SSH_ASKPASS") + .env("GIT_TERMINAL_PROMPT", "false") + .env("GIT_AUTHOR_DATE", "2000-01-01 00:00:00 +0000") + .env("GIT_AUTHOR_EMAIL", "author@example.com") + .env("GIT_AUTHOR_NAME", "author") + .env("GIT_COMMITTER_DATE", "2000-01-02 00:00:00 +0000") + .env("GIT_COMMITTER_EMAIL", "committer@example.com") + .env("GIT_COMMITTER_NAME", "committer") + .env("GIT_CONFIG_COUNT", "2") + .env("GIT_CONFIG_KEY_0", "commit.gpgsign") + .env("GIT_CONFIG_VALUE_0", "false") + .env("GIT_CONFIG_KEY_1", "init.defaultBranch") + .env("GIT_CONFIG_VALUE_1", "main") + .output() + .unwrap_or_else(|_| panic!("`git {args}` failed")); + if !res.status.success() { + println!("{}", String::from_utf8_lossy(&res.stdout)); + eprintln!("{}", String::from_utf8_lossy(&res.stderr)); + panic!("`git {args}` failed (see output above)") + } +} + +fn create_commit(repo: &Path, add_modified: bool) { + if add_modified { + exec_git_cmd("add -A", repo); + } + exec_git_cmd("commit -m message", repo); +} + +fn empty_git_repo() -> TempDir { + let tmp = tempfile::tempdir().expect("create temp dir for git testing"); + exec_git_cmd("init", tmp.path()); + exec_git_cmd("config user.email test@helix.org", tmp.path()); + exec_git_cmd("config user.name helix-test", tmp.path()); + tmp +} + +#[test] +fn missing_file() { + let temp_git = empty_git_repo(); + let file = temp_git.path().join("file.txt"); + File::create(&file).unwrap().write_all(b"foo").unwrap(); + + assert_eq!(Git.get_diff_base(&file), None); +} + +#[test] +fn unmodified_file() { + let temp_git = empty_git_repo(); + let file = temp_git.path().join("file.txt"); + let contents = b"foo".as_slice(); + File::create(&file).unwrap().write_all(contents).unwrap(); + create_commit(temp_git.path(), true); + assert_eq!(Git.get_diff_base(&file), Some(Vec::from(contents))); +} + +#[test] +fn modified_file() { + let temp_git = empty_git_repo(); + let file = temp_git.path().join("file.txt"); + let contents = b"foo".as_slice(); + File::create(&file).unwrap().write_all(contents).unwrap(); + create_commit(temp_git.path(), true); + File::create(&file).unwrap().write_all(b"bar").unwrap(); + + assert_eq!(Git.get_diff_base(&file), Some(Vec::from(contents))); +} + +/// Test that `get_file_head` does not return content for a directory. +/// This is important to correctly cover cases where a directory is removed and replaced by a file. +/// If the contents of the directory object were returned a diff between a path and the directory children would be produced. +#[test] +fn directory() { + let temp_git = empty_git_repo(); + let dir = temp_git.path().join("file.txt"); + std::fs::create_dir(&dir).expect(""); + let file = dir.join("file.txt"); + let contents = b"foo".as_slice(); + File::create(&file).unwrap().write_all(contents).unwrap(); + + create_commit(temp_git.path(), true); + + std::fs::remove_dir_all(&dir).unwrap(); + File::create(&dir).unwrap().write_all(b"bar").unwrap(); + assert_eq!(Git.get_diff_base(&dir), None); +} + +/// Test that `get_file_head` does not return content for a symlink. +/// This is important to correctly cover cases where a symlink is removed and replaced by a file. +/// If the contents of the symlink object were returned a diff between a path and the actual file would be produced (bad ui). +#[cfg(any(unix, windows))] +#[test] +fn symlink() { + #[cfg(unix)] + use std::os::unix::fs::symlink; + #[cfg(not(unix))] + use std::os::windows::fs::symlink_file as symlink; + let temp_git = empty_git_repo(); + let file = temp_git.path().join("file.txt"); + let contents = b"foo".as_slice(); + File::create(&file).unwrap().write_all(contents).unwrap(); + let file_link = temp_git.path().join("file_link.txt"); + symlink("file.txt", &file_link).unwrap(); + + create_commit(temp_git.path(), true); + assert_eq!(Git.get_diff_base(&file_link), None); + assert_eq!(Git.get_diff_base(&file), Some(Vec::from(contents))); +} diff --git a/helix-vcs/src/lib.rs b/helix-vcs/src/lib.rs new file mode 100644 index 000000000000..97320d32518f --- /dev/null +++ b/helix-vcs/src/lib.rs @@ -0,0 +1,51 @@ +use std::path::Path; + +#[cfg(feature = "git")] +pub use git::Git; +#[cfg(not(feature = "git"))] +pub use Dummy as Git; + +#[cfg(feature = "git")] +mod git; + +mod diff; + +pub use diff::{DiffHandle, Hunk}; + +pub trait DiffProvider { + /// Returns the data that a diff should be computed against + /// if this provider is used. + /// The data is returned as raw byte without any decoding or encoding performed + /// to ensure all file encodings are handled correctly. + fn get_diff_base(&self, file: &Path) -> Option>; +} + +#[doc(hidden)] +pub struct Dummy; +impl DiffProvider for Dummy { + fn get_diff_base(&self, _file: &Path) -> Option> { + None + } +} + +pub struct DiffProviderRegistry { + providers: Vec>, +} + +impl DiffProviderRegistry { + pub fn get_diff_base(&self, file: &Path) -> Option> { + self.providers + .iter() + .find_map(|provider| provider.get_diff_base(file)) + } +} + +impl Default for DiffProviderRegistry { + fn default() -> Self { + // currently only git is supported + // TODO make this configurable when more providers are added + let git: Box = Box::new(Git); + let providers = vec![git]; + DiffProviderRegistry { providers } + } +} diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index a2a88001bffd..13d5da0e583c 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -21,6 +21,7 @@ helix-loader = { version = "0.6", path = "../helix-loader" } helix-lsp = { version = "0.6", path = "../helix-lsp" } helix-dap = { version = "0.6", path = "../helix-dap" } crossterm = { version = "0.25", optional = true } +helix-vcs = { version = "0.6", path = "../helix-vcs" } # Conversion traits once_cell = "1.16" @@ -43,6 +44,7 @@ log = "~0.4" which = "4.2" + [target.'cfg(windows)'.dependencies] clipboard-win = { version = "4.4", features = ["std"] } diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index ad47f838fa90..856e5628ab42 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -3,6 +3,8 @@ use futures_util::future::BoxFuture; use futures_util::FutureExt; use helix_core::auto_pairs::AutoPairs; use helix_core::Range; +use helix_vcs::{DiffHandle, DiffProviderRegistry}; + use serde::de::{self, Deserialize, Deserializer}; use serde::Serialize; use std::borrow::Cow; @@ -24,6 +26,7 @@ use helix_core::{ DEFAULT_LINE_ENDING, }; +use crate::editor::RedrawHandle; use crate::{apply_transaction, DocumentId, Editor, View, ViewId}; /// 8kB of buffer space for encoding and decoding `Rope`s. @@ -133,6 +136,8 @@ pub struct Document { diagnostics: Vec, language_server: Option>, + + diff_handle: Option, } use std::{fmt, mem}; @@ -371,6 +376,7 @@ impl Document { last_saved_revision: 0, modified_since_accessed: false, language_server: None, + diff_handle: None, } } @@ -624,16 +630,20 @@ impl Document { } /// Reload the document from its path. - pub fn reload(&mut self, view: &mut View) -> Result<(), Error> { + pub fn reload( + &mut self, + view: &mut View, + provider_registry: &DiffProviderRegistry, + redraw_handle: RedrawHandle, + ) -> Result<(), Error> { let encoding = &self.encoding; - let path = self.path().filter(|path| path.exists()); - - // If there is no path or the path no longer exists. - if path.is_none() { - bail!("can't find file to reload from"); - } + let path = self + .path() + .filter(|path| path.exists()) + .ok_or_else(|| anyhow!("can't find file to reload from"))? + .to_owned(); - let mut file = std::fs::File::open(path.unwrap())?; + let mut file = std::fs::File::open(&path)?; let (rope, ..) = from_reader(&mut file, Some(encoding))?; // Calculate the difference between the buffer and source text, and apply it. @@ -646,6 +656,11 @@ impl Document { self.detect_indent_and_line_ending(); + match provider_registry.get_diff_base(&path) { + Some(diff_base) => self.set_diff_base(diff_base, redraw_handle), + None => self.diff_handle = None, + } + Ok(()) } @@ -787,6 +802,10 @@ impl Document { if !transaction.changes().is_empty() { self.version += 1; + // start computing the diff in parallel + if let Some(diff_handle) = &self.diff_handle { + diff_handle.update_document(self.text.clone(), false); + } // generate revert to savepoint if self.savepoint.is_some() { @@ -1046,6 +1065,23 @@ impl Document { server.is_initialized().then(|| server) } + pub fn diff_handle(&self) -> Option<&DiffHandle> { + self.diff_handle.as_ref() + } + + /// Intialize/updates the differ for this document with a new base. + pub fn set_diff_base(&mut self, diff_base: Vec, redraw_handle: RedrawHandle) { + if let Ok((diff_base, _)) = from_reader(&mut diff_base.as_slice(), Some(self.encoding)) { + if let Some(differ) = &self.diff_handle { + differ.update_diff_base(diff_base); + return; + } + self.diff_handle = Some(DiffHandle::new(diff_base, self.text.clone(), redraw_handle)) + } else { + self.diff_handle = None; + } + } + #[inline] /// Tree-sitter AST tree pub fn syntax(&self) -> Option<&Syntax> { diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 5a1ac6b1fe1d..973cf82ea109 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -9,6 +9,7 @@ use crate::{ tree::{self, Tree}, Align, Document, DocumentId, View, ViewId, }; +use helix_vcs::DiffProviderRegistry; use futures_util::stream::select_all::SelectAll; use futures_util::{future, StreamExt}; @@ -26,7 +27,10 @@ use std::{ }; use tokio::{ - sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, + sync::{ + mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, + Notify, RwLock, + }, time::{sleep, Duration, Instant, Sleep}, }; @@ -454,6 +458,8 @@ pub enum GutterType { LineNumbers, /// Show one blank space Spacer, + /// Highlight local changes + Diff, } impl std::str::FromStr for GutterType { @@ -464,6 +470,7 @@ impl std::str::FromStr for GutterType { "diagnostics" => Ok(Self::Diagnostics), "spacer" => Ok(Self::Spacer), "line-numbers" => Ok(Self::LineNumbers), + "diff" => Ok(Self::Diff), _ => anyhow::bail!("Gutter type can only be `diagnostics` or `line-numbers`."), } } @@ -600,6 +607,8 @@ impl Default for Config { GutterType::Diagnostics, GutterType::Spacer, GutterType::LineNumbers, + GutterType::Spacer, + GutterType::Diff, ], middle_click_paste: true, auto_pairs: AutoPairConfig::default(), @@ -681,6 +690,7 @@ pub struct Editor { pub macro_replaying: Vec, pub language_servers: helix_lsp::Registry, pub diagnostics: BTreeMap>, + pub diff_providers: DiffProviderRegistry, pub debugger: Option, pub debugger_events: SelectAll>, @@ -711,8 +721,15 @@ pub struct Editor { pub exit_code: i32, pub config_events: (UnboundedSender, UnboundedReceiver), + /// Allows asynchronous tasks to control the rendering + /// The `Notify` allows asynchronous tasks to request the editor to perform a redraw + /// The `RwLock` blocks the editor from performing the render until an exclusive lock can be aquired + pub redraw_handle: RedrawHandle, + pub needs_redraw: bool, } +pub type RedrawHandle = (Arc, Arc>); + #[derive(Debug)] pub enum EditorEvent { DocumentSaved(DocumentSavedEventResult), @@ -785,6 +802,7 @@ impl Editor { theme: theme_loader.default(), language_servers: helix_lsp::Registry::new(), diagnostics: BTreeMap::new(), + diff_providers: DiffProviderRegistry::default(), debugger: None, debugger_events: SelectAll::new(), breakpoints: HashMap::new(), @@ -803,6 +821,8 @@ impl Editor { auto_pairs, exit_code: 0, config_events: unbounded_channel(), + redraw_handle: Default::default(), + needs_redraw: false, } } @@ -1109,7 +1129,9 @@ impl Editor { let mut doc = Document::open(&path, None, Some(self.syn_loader.clone()))?; let _ = Self::launch_language_server(&mut self.language_servers, &mut doc); - + if let Some(diff_base) = self.diff_providers.get_diff_base(&path) { + doc.set_diff_base(diff_base, self.redraw_handle.clone()); + } self.new_document(doc) }; @@ -1348,24 +1370,39 @@ impl Editor { } pub async fn wait_event(&mut self) -> EditorEvent { - tokio::select! { - biased; + // the loop only runs once or twice and would be better implemented with a recursion + const generic + // however due to limitations with async functions that can not be implemented right now + loop { + tokio::select! { + biased; + + Some(event) = self.save_queue.next() => { + self.write_count -= 1; + return EditorEvent::DocumentSaved(event) + } + Some(config_event) = self.config_events.1.recv() => { + return EditorEvent::ConfigEvent(config_event) + } + Some(message) = self.language_servers.incoming.next() => { + return EditorEvent::LanguageServerMessage(message) + } + Some(event) = self.debugger_events.next() => { + return EditorEvent::DebuggerEvent(event) + } - Some(event) = self.save_queue.next() => { - self.write_count -= 1; - EditorEvent::DocumentSaved(event) - } - Some(config_event) = self.config_events.1.recv() => { - EditorEvent::ConfigEvent(config_event) - } - Some(message) = self.language_servers.incoming.next() => { - EditorEvent::LanguageServerMessage(message) - } - Some(event) = self.debugger_events.next() => { - EditorEvent::DebuggerEvent(event) - } - _ = &mut self.idle_timer => { - EditorEvent::IdleTimer + _ = self.redraw_handle.0.notified() => { + if !self.needs_redraw{ + self.needs_redraw = true; + let timeout = Instant::now() + Duration::from_millis(96); + if timeout < self.idle_timer.deadline(){ + self.idle_timer.as_mut().reset(timeout) + } + } + } + + _ = &mut self.idle_timer => { + return EditorEvent::IdleTimer + } } } } diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 61a1779186c3..377518fb5379 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -12,7 +12,7 @@ fn count_digits(n: usize) -> usize { std::iter::successors(Some(n), |&n| (n >= 10).then(|| n / 10)).count() } -pub type GutterFn<'doc> = Box Option - - - + \ No newline at end of file From 39ce82b7a59de8adcb1626151b1ce8fe7b7a4a8e Mon Sep 17 00:00:00 2001 From: lesleyrs <19632758+lesleyrs@users.noreply.github.com> Date: Fri, 2 Dec 2022 15:02:29 +0100 Subject: [PATCH 070/269] Add Ctrl-i alias for Windows (#4961) --- helix-term/src/keymap/default.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index 118764d97585..c0d17a87e065 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -198,7 +198,7 @@ pub fn default() -> HashMap { // z family for save/restore/combine from/to sels from register - "tab" => jump_forward, // tab == + "C-i" | "tab" => jump_forward, // tab == "C-o" => jump_backward, "C-s" => save_selection, From d0bc38d6fa60e36ef317e8bbbaa11aeb30470ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Dzivjak?= Date: Fri, 2 Dec 2022 15:06:35 +0100 Subject: [PATCH 071/269] feat(lang): bump tree-sitter-go (#4969) Update tree-sitter-go to latest with updated support for generics. See: https://github.com/tree-sitter/tree-sitter-go/compare/0fa917a7022d1cd2e9b779a6a8fc5dc7fad69c75..05900faa3cdb5d2d8c8bd5e77ee698487e0a8611 for full diff. --- languages.toml | 2 +- runtime/queries/go/indents.scm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/languages.toml b/languages.toml index 4eb8a4dab1d5..9664d93a654b 100644 --- a/languages.toml +++ b/languages.toml @@ -301,7 +301,7 @@ args = { mode = "local", processId = "{0}" } [[grammar]] name = "go" -source = { git = "https://github.com/tree-sitter/tree-sitter-go", rev = "0fa917a7022d1cd2e9b779a6a8fc5dc7fad69c75" } +source = { git = "https://github.com/tree-sitter/tree-sitter-go", rev = "05900faa3cdb5d2d8c8bd5e77ee698487e0a8611" } [[language]] name = "gomod" diff --git a/runtime/queries/go/indents.scm b/runtime/queries/go/indents.scm index 8bfc7c3fe14a..f72ec9e827b0 100644 --- a/runtime/queries/go/indents.scm +++ b/runtime/queries/go/indents.scm @@ -5,7 +5,7 @@ (type_spec) (func_literal) (literal_value) - (element) + (literal_element) (keyed_element) (expression_case) (default_case) From 59b886cf5e89dadfd73d93b638b2c552ce5537f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?alex=20=E5=AD=99=E6=AC=A3=E4=B9=90?= Date: Fri, 2 Dec 2022 22:24:00 +0800 Subject: [PATCH 072/269] nightfox theme: Use brighter colors for diff scopes (#4966) --- runtime/themes/nightfox.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime/themes/nightfox.toml b/runtime/themes/nightfox.toml index 131cab190870..c4cbbce0f726 100644 --- a/runtime/themes/nightfox.toml +++ b/runtime/themes/nightfox.toml @@ -140,10 +140,10 @@ # Diff ============================== # Version control changes. -"diff.plus" = "green-dim" # Additions. -"diff.minus" = "red-dim" # Deletions. -"diff.delta" = "blue-dim" # Modifications. -"diff.delta.moved" = "cyan-dim" # Renamed or moved files. +"diff.plus" = "green" # Additions. +"diff.minus" = "red" # Deletions. +"diff.delta" = "blue" # Modifications. +"diff.delta.moved" = "cyan" # Renamed or moved files. # color palette [palette] From b677c6a019f893c7ed8b9b84d136c50e5445315a Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Sat, 3 Dec 2022 03:05:15 +0100 Subject: [PATCH 073/269] Add logo with text included (#4973) --- README.md | 10 +++-- logo_dark.svg | 115 +++++++++++++++++++++++++++++++++++++++++++++++++ logo_light.svg | 115 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+), 3 deletions(-) create mode 100644 logo_dark.svg create mode 100644 logo_light.svg diff --git a/README.md b/README.md index 3555b53916a4..b06e8222702c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@
-Logo - -# Helix +

+ + + + Helix + +

[![Build status](https://github.com/helix-editor/helix/actions/workflows/build.yml/badge.svg)](https://github.com/helix-editor/helix/actions) [![GitHub Release](https://img.shields.io/github/v/release/helix-editor/helix)](https://github.com/helix-editor/helix/releases/latest) diff --git a/logo_dark.svg b/logo_dark.svg new file mode 100644 index 000000000000..f6e94f1b4c39 --- /dev/null +++ b/logo_dark.svg @@ -0,0 +1,115 @@ + + diff --git a/logo_light.svg b/logo_light.svg new file mode 100644 index 000000000000..cdd5ddb8b0a6 --- /dev/null +++ b/logo_light.svg @@ -0,0 +1,115 @@ + + From 224a024d3997035d04bf7b2f7424a472ff9936b8 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Fri, 2 Dec 2022 18:26:01 -0800 Subject: [PATCH 074/269] Update zenburn theme for git gutters (#4977) --- runtime/themes/zenburn.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime/themes/zenburn.toml b/runtime/themes/zenburn.toml index affb9f56deda..63f4ac72251e 100644 --- a/runtime/themes/zenburn.toml +++ b/runtime/themes/zenburn.toml @@ -37,9 +37,9 @@ "ui.virtual.indent-guide" = "#4f4f4f" -"diff.plus" = {fg = "#709080", bg = "#313c36", modifiers = ["bold"] } -"diff.delta" = "#333333" -"diff.minus" = {fg = "#333333", bg = "#464646"} +"diff.plus" = {fg = "#709080"} +"diff.delta" = {fg = "#464646"} +"diff.minus" = {fg = "#cc9393"} "diagnostic" = {bg = "statusbg"} "diagnostic.error" = { fg = "errorfg", bg = "errorbg"} From dc00291b4888f7ffad43fd544259227d0dbbf6fb Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 3 Dec 2022 03:26:10 +0100 Subject: [PATCH 075/269] Update Doom Acario for git gutters (#4979) Edited the diff.delta from green to blue. --- runtime/themes/doom_acario_dark.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/doom_acario_dark.toml b/runtime/themes/doom_acario_dark.toml index c38c93eed5b2..95dc78e0dbb6 100644 --- a/runtime/themes/doom_acario_dark.toml +++ b/runtime/themes/doom_acario_dark.toml @@ -41,7 +41,7 @@ 'diff.plus' = { fg = 'green' } 'diff.minus' = { fg = 'red' } -'diff.delta' = { fg = 'green' } +'diff.delta' = { fg = 'blue' } 'ui.background'= { bg = 'bg' } 'ui.cursor' = { bg = 'orange', fg = 'bg-alt' } From bcdb475b71b0fbabce57344ac8d2575c23b1bbe0 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 2 Dec 2022 21:09:08 -0600 Subject: [PATCH 076/269] Fix transaction composition order in History::changes_since (#4981) * Add a undo/redo split test case for crossing branches * history: Switch up/down transaction chaining order The old code tends to work in practice because, usually, either up_txns or down_txns are empty. When both have contents though, we can run into a panic trying to compose them all since they will disagree on the length of the text. This fixes the panic test case in the parent commit. --- helix-core/src/history.rs | 2 +- helix-term/tests/test/splits.rs | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/helix-core/src/history.rs b/helix-core/src/history.rs index b99e969f93ba..1aac38d934c7 100644 --- a/helix-core/src/history.rs +++ b/helix-core/src/history.rs @@ -131,7 +131,7 @@ impl History { .map(|&n| self.revisions[n].inversion.clone()); let down_txns = down.iter().map(|&n| self.revisions[n].transaction.clone()); - up_txns.chain(down_txns).reduce(|acc, tx| tx.compose(acc)) + down_txns.chain(up_txns).reduce(|acc, tx| tx.compose(acc)) } /// Undo the last edit. diff --git a/helix-term/tests/test/splits.rs b/helix-term/tests/test/splits.rs index a34a24b7cbdf..96ced21a57cd 100644 --- a/helix-term/tests/test/splits.rs +++ b/helix-term/tests/test/splits.rs @@ -161,5 +161,30 @@ async fn test_changes_in_splits_apply_to_all_views() -> anyhow::Result<()> { )) .await?; + // See . + // This sequence undoes part of the history and then adds new changes, creating a + // new branch in the history tree. `View::sync_changes` applies transactions down + // and up to the lowest common ancestor in the path between old and new revision + // numbers. If we apply these up/down transactions in the wrong order, this case + // panics. + // The key sequence: + // * 3[ Create three empty lines so we are at the end of the document. + // * v Create a split and save that point at the end of the document + // in the jumplist. + // * w Switch back to the first window. + // * uu Undo twice (not three times which would bring us back to the + // root of the tree). + // * 3[ Create three empty lines. Now the end of the document is past + // where it was on step 1. + // * q Close window 1, focusing window 2 and causing a sync. This step + // panics if we don't apply in the right order. + // * %d Clean up the buffer. + test(( + "#[|]#", + "3[vwuu3[q%d", + "#[|]#", + )) + .await?; + Ok(()) } From 2123e91e56caccf60b9285f30bc2f2f12952520a Mon Sep 17 00:00:00 2001 From: Aleksey Kuznetsov Date: Sat, 3 Dec 2022 19:24:43 +0500 Subject: [PATCH 077/269] Enable auto format for css and scss files (#4987) provideFormatter enables capability in LS and auto-format performs format on save --- languages.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/languages.toml b/languages.toml index 9664d93a654b..d214a082fcc3 100644 --- a/languages.toml +++ b/languages.toml @@ -422,6 +422,8 @@ injection-regex = "css" file-types = ["css", "scss"] roots = [] language-server = { command = "vscode-css-language-server", args = ["--stdio"] } +auto-format = true +config = { "provideFormatter" = true } indent = { tab-width = 2, unit = " " } [[grammar]] @@ -435,6 +437,8 @@ injection-regex = "scss" file-types = ["scss"] roots = [] language-server = { command = "vscode-css-language-server", args = ["--stdio"] } +auto-format = true +config = { "provideFormatter" = true } indent = { tab-width = 2, unit = " " } [[grammar]] From 326a0dab069b65463db90e2647287c1e5b6b66aa Mon Sep 17 00:00:00 2001 From: Jens Getreu Date: Sun, 4 Dec 2022 03:03:42 +0100 Subject: [PATCH 078/269] Autumn theme: adjust some gray colors (#4996) --- runtime/themes/autumn.toml | 12 ++++++------ runtime/themes/autumn_night.toml | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/runtime/themes/autumn.toml b/runtime/themes/autumn.toml index b13aeef2bd8d..fe80261af294 100644 --- a/runtime/themes/autumn.toml +++ b/runtime/themes/autumn.toml @@ -10,13 +10,13 @@ "ui.background" = { bg = "my_gray0" } "ui.menu" = { fg = "my_white", bg = "my_gray2" } "ui.menu.selected" = { fg = "my_gray2", bg = "my_gray5" } -"ui.linenr" = { fg = "my_gray4", bg = "my_gray2" } +"ui.linenr" = { fg = "my_gray3", bg = "my_gray0" } "ui.popup" = { bg = "my_gray2" } -"ui.window" = { fg = "my_gray4", bg = "my_gray2" } -"ui.linenr.selected" = { fg = "my_gray6", bg = "my_gray1"} +"ui.window" = { fg = "my_gray3", bg = "my_gray2" } +"ui.linenr.selected" = { fg = "my_gray6", bg = "my_gray0"} "ui.selection" = { bg = "my_gray3" } "comment" = { fg = "my_gray4", modifiers = ["italic"] } -"ui.cursorline" = { bg = "my_gray2" } +"ui.cursorline" = { bg = "my_gray3" } "ui.statusline" = { fg = "my_gray6", bg = "my_gray2" } "ui.statusline.inactive" = { fg = 'my_gray4', bg = 'my_gray2' } "ui.statusline.insert" = {fg = "my_black", bg = "my_gray5", modifiers = ["bold"]} @@ -62,7 +62,7 @@ "diff.minus" = "my_red" "diagnostic" = { modifiers = ["underlined"] } -"ui.gutter" = { bg = "my_gray2" } +"ui.gutter" = { bg = "my_gray0" } "hint" = "my_gray5" "debug" = "my_yellow2" "info" = "my_yellow2" @@ -77,7 +77,7 @@ my_gray2 = "#323232" # Lighter Background (Used for status bars, line numbe my_gray3 = "#505050" # Selection Background my_gray4 = "#7c7c7c" # Comments, Invisibles, Line Highlighting my_gray5 = "#a8a8a8" # Dark Foreground (Used for status bars) -my_gray6 = "#c0c0c0" # Light Foreground (Not often used) +my_gray6 = "#c8c8c8" # Light Foreground (Not often used) my_gray7 = "#e8e8e8" # Light Background (Not often used) my_white = "#F3F2CC" # Default Foreground, Caret, Delimiters, Operators my_white2 = "#F3F2CC" # Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted diff --git a/runtime/themes/autumn_night.toml b/runtime/themes/autumn_night.toml index 2f398dc96468..d01f5356931e 100644 --- a/runtime/themes/autumn_night.toml +++ b/runtime/themes/autumn_night.toml @@ -10,13 +10,13 @@ "ui.background" = { bg = "my_gray0" } "ui.menu" = { fg = "my_white", bg = "my_gray2" } "ui.menu.selected" = { fg = "my_gray2", bg = "my_gray5" } -"ui.linenr" = { fg = "my_gray4", bg = "my_gray2" } +"ui.linenr" = { fg = "my_gray3", bg = "my_gray0" } "ui.popup" = { bg = "my_gray2" } -"ui.window" = { fg = "my_gray4", bg = "my_gray2" } -"ui.linenr.selected" = { fg = "my_gray6", bg = "my_gray1"} +"ui.window" = { fg = "my_gray3", bg = "my_gray2" } +"ui.linenr.selected" = { fg = "my_gray6", bg = "my_gray0"} "ui.selection" = { bg = "my_gray3" } "comment" = { fg = "my_gray4", modifiers = ["italic"] } -"ui.cursorline" = { bg = "my_gray2" } +"ui.cursorline" = { bg = "my_gray3" } "ui.statusline" = { fg = "my_gray6", bg = "my_gray2" } "ui.statusline.inactive" = { fg = 'my_gray4', bg = 'my_gray2' } "ui.statusline.insert" = {fg = "my_black", bg = "my_gray5", modifiers = ["bold"]} @@ -62,7 +62,7 @@ "diff.minus" = "my_red" "diagnostic" = { modifiers = ["underlined"] } -"ui.gutter" = { bg = "my_gray2" } +"ui.gutter" = { bg = "my_gray0" } "hint" = "my_gray5" "debug" = "my_yellow2" "info" = "my_yellow2" @@ -77,7 +77,7 @@ my_gray2 = "#1a1a1a" # Lighter Background (Used for status bars, line numbe my_gray3 = "#323232" # Selection Background my_gray4 = "#7c7c7c" # Comments, Invisibles, Line Highlighting my_gray5 = "#aaaaaa" # Dark Foreground (Used for status bars) -my_gray6 = "#c0c0c0" # Light Foreground (Not often used) +my_gray6 = "#c4c4c4" # Light Foreground (Not often used) my_gray7 = "#e8e8e8" # Light Background (Not often used) my_white = "#F3F2CC" # Default Foreground, Caret, Delimiters, Operators my_white2 = "#F3F2CC" # Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted From e9d0645f66c6254e82c2b50000eb5660c128f26b Mon Sep 17 00:00:00 2001 From: PORTALSURFER <41680373+PORTALSURFER@users.noreply.github.com> Date: Sun, 4 Dec 2022 03:06:40 +0100 Subject: [PATCH 079/269] Adjusted hex themes for new gutter diff colors (#4990) * added 2 themes * diff feature fixes adjusted the skin to better work with the new diff coloring features propagates to child skins like - hex_toxic * fine tuning so it all is a bit softer * fine tuning to be softer * added new version, lavender --- runtime/themes/hex_lavender.toml | 31 ++++++++++++++++++++++++++++++ runtime/themes/hex_steel.toml | 33 ++++++++++++++++++-------------- runtime/themes/hex_toxic.toml | 10 +++++----- 3 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 runtime/themes/hex_lavender.toml diff --git a/runtime/themes/hex_lavender.toml b/runtime/themes/hex_lavender.toml new file mode 100644 index 000000000000..974c486ce06e --- /dev/null +++ b/runtime/themes/hex_lavender.toml @@ -0,0 +1,31 @@ +inherits = "hex_steel" + +[palette] +t1 = "#0e0e0d" +t2 = "#121311" +t3 = "#2b3444" # +t4 = "#61586f" +t5 = "#686e73" +t6 = "#878480" +t7 = "#897dca" +t8 = "#7b89a3" +t9 = "#bcb6ba" +t10 = "#9db2b8" +t11 = "#a0c7cf" + +highlight = "#ff2e5f" +highlight_two = "#0affa9" +highlight_three = "#29bbff" + +black = "#000000" + +selection = "#290019" + +comment = "#9aacfe" +comment_doc = "#0affa9" + +error = "#ff0900" +warning = "#ffbf00" +display = "#57ff89" +info = "#dad7d5" +# diff --git a/runtime/themes/hex_steel.toml b/runtime/themes/hex_steel.toml index 06e91d01374e..7a2183f8f8aa 100644 --- a/runtime/themes/hex_steel.toml +++ b/runtime/themes/hex_steel.toml @@ -1,5 +1,5 @@ -"comment" = { fg = "highlight_three" } -"comment.block.documentation" = { bg = "t4", modifiers = ["italic"] } +"comment" = { fg = "comment" } +"comment.block.documentation" = { bg = "comment_doc", modifiers = ["italic"] } "constant" = { fg = "t11" } "function" = { fg = "t10" } @@ -20,18 +20,19 @@ "variable" = { fg = "t4" } "label" = { fg = "t4" } -"diff.plus" = { fg = "t4" } -"diff.delta" = { fg = "t4" } -"diff.minus" = { fg = "t4" } +"diff.plus" = { fg = "diff_plus" } +"diff.delta" = { fg = "diff_delta" } +"diff.delta.moved" = { fg = "diff_delta_moved" } +"diff.minus" = { fg = "diff_minus" } "ui.cursor.insert" = { fg = "t2", bg = "highlight" } "ui.cursor.select" = { fg = "t2", bg = "highlight_two" } "ui.cursor" = { fg = "t1", bg = "highlight_three" } -"ui.cursor.match" = { fg = "highlight", bg = "t1", modifiers = ["bold"] } +"ui.cursor.match" = { fg = "highlight", bg = "selection", modifiers = ["bold"] } -"ui.linenr" = { fg = "t3", bg = "t1" } -"ui.linenr.selected" = { fg = "highlight_three", bg = "t1" } -"ui.gutter" = { bg = "t1" } +"ui.linenr" = { fg = "t3", bg = "t2" } +"ui.linenr.selected" = { fg = "highlight_three", bg = "t2" } +"ui.gutter" = { bg = "t2" } "ui.background" = { fg = "t4", bg = "t2" } "ui.background.separator" = { fg = "t3" } @@ -76,8 +77,8 @@ "markup.raw" = { fg = "t4" } [palette] -t1 = "#0f0b0b" -t2 = "#161010" +t1 = "#0e0e0d" +t2 = "#1d1e1b" t3 = "#5b5555" t4 = "#656869" t5 = "#727b7c" @@ -95,11 +96,15 @@ highlight_three = "#d4d987" selection = "#032d4a" black = "#000000" - -comment = "#396884" +comment = "#d4d987" comment_doc = "#234048" error = "#ff0900" warning = "#ffbf00" -display = "#57ff89" +display = "#42baff" info = "#dad7d5" + +diff_minus = "#ff0900" +diff_delta = "#0078bd" +diff_plus = "#87a800" +diff_delta_moved = "#0048bd" diff --git a/runtime/themes/hex_toxic.toml b/runtime/themes/hex_toxic.toml index 3cd878bef7ea..33bfa6e5fa2f 100644 --- a/runtime/themes/hex_toxic.toml +++ b/runtime/themes/hex_toxic.toml @@ -2,7 +2,7 @@ inherits = "hex_steel" [palette] t1 = "#101719" -t2 = "#152432" +t2 = "#1b2a32" t3 = "#4b5968" t4 = "#8792ab" t5 = "#6f91bc" @@ -13,15 +13,15 @@ t9 = "#b3ccd0" t10 = "#b0d4d8" t11 = "#ffbf52" -highlight = "#ff2e5f" +highlight = "#ff0a50" highlight_two = "#0affa9" -highlight_three = "#d7ff52" +highlight_three = "#f8ed8b" black = "#000000" -selection = "#290019" +selection = "#382e1e" -comment = "#396884" +comment = "#61bdd1" comment_doc = "#234048" error = "#ff0900" From c13c6d56b6eb0e117cb92ba4011155b519befde6 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 3 Dec 2022 20:07:17 -0600 Subject: [PATCH 080/269] Use logo for contrib icon (#4982) --- contrib/helix.png | Bin 1838 -> 15785 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/contrib/helix.png b/contrib/helix.png index bef00b98418a3fefcf56a5d45fafb1403e26e996..a9b699a4606926465926e8020eb5ce94cffb2ddb 100644 GIT binary patch literal 15785 zcmZ{L1yEd1@aEfH+}&M*6C^+g?hrhUa5P*h)xEOyd{eZY2 z*+{8M0YGgW=7R+?;y0a@;yYCU@O=RQ&=3H)Lp*}+0Kg|60N67JfH!FXKkkPj zcrgmDdHD!EhqV?pdf;@Q)GXxXxSswPNaMRrC_PkGWPR%!3H;#0NW**}*`x{;FMB(u z>~=aa@cMayrJ(U8eSYbV9T=d4pTghaJ8Nyem-35xXZY2oKZ%J`QPH-D1w)d98U7t@ zMCU*q#;BD}fV7%r$I)!NSExCk8jmL|W&jwHqp3iSu!FmWh*4<2>5z$jP&N6zp`ONi!tTKt&Pg&@eb2-7S!8}E8i5kg}f5aqt51<4pR{j!k`O&SPr~T-N z_Q#O5%h%fVql&TfzKxUo?m1u#lXo&~8k-k``k%tIkOH_0lws>0l4u5DhxbwH7EA#N+xHd)bKp*KOkJU%ji7RFg z!DO0m(!GiF;A6Q{{FBVgw5CQu`~8+ASzsw0AHIoptv`7V?GQu~P2(*Jiz;TOk&2_& zMykMQfLoAtRCeQ!vJq7obbk3+-G<+gY$DA7+;0cN8StI;HWTyM@HO_`{wDQOhKo!x z7(aE;)6u=n+o6R;!%fUf^09sh#)S{GHOx2PHBf72E_`PKj|q;$OXQkmWUEkPDdO?5 zTvvV6c^L77X54Qrf+dlpz~;PTXvR@B#yS#liYP>9K3mnh!b_42z+s^T4|=nWy6H>g zun%vgk(wYF|Efc>;$|!1}b*r+@}mi5DO_khBXp{WU!-0`3^EkFo#=)Ce3c2D5Amu zWdHdLrKPWv=CYwnDr>+JD~%-AqA6)1#FmCu@G$HR5 zE(^4vKvX1eLRp&t7K1*t6q9-J(O=)oT~%WUBV%r>k79N?U@C< z2nDC#;rNl?RN6FC{O!TAgY#T|9r*d$&dAh*6$RAm^Re*y{0s!QE670?$Wdm?(H)4R zhkHpL>0C&gLznaP)zf$n-MHU8cOiTNQ03zse2@EwaOJ$&Kl_naika#g@8u2wXvb6> z;6yqi+N_T(mLpb5<#C@|&-&~<9>dDM)qeLzDi=eN9!ny`f$Sd%PS<8=?^nc7a*0k{ z;4ZT7YYS-E$8aacn+m>?|D!4KUBlFzpDAzN+k6A3vjB8a!S1g7FXp6?@0U4P4GBQu zv2Rx#z}MeqFHPjiWzX~Iv4i*1Qho^?kZg6<5wCB%`j}9K3{JwoA9_a-IrHgoD!l>A zsS|5(4St7zDy_nbf5SK|r{!>Rh8*ClH6Bx1pWfstqB~ytfqn)OuvrTyhIjt!KrIB= zN@!0RPl3oUxFDg(K^JIXPuWYT>g_L;GHj8U+x;fq>*PvSlEUAtSOe8rkcH6sn|&Pz z282Kq)`@|6#pwo)dBS$)c8^B-t8?VxZWIz@FUtwR{;zwfP4RDw;OuJ@?Ux{7)fI*n z{qTMM2l$STJt^ZIgcN)ok{^Id_D;7{LB@J3R6uFgO(gw#SkNy~S_gCrOGFMp=0uJy zOyv$x6op!D^Q=&;yjn2~{oFTZTQN_o_=R4=P?X!AGAd=SVP0Qrn)W@*H%_E2MV;&* zmI16dPGQE`|EZ&=k&{@l^A#PFdEb>iYepTTlgI&| z&S@p0%Ezf>&fxc?UvZfNsIY#4kED8{puvqU++E5BAJmL~UktVL2bv#c9HxyWZWFqYX_i^=C3VFEwFR(6&Cm|D<NP7T4o_Y7n0Wp0JG1%ZaP*2wM_OjH8+Vp{SYvQ7gPjff5}d zJKgYm3LGcvq?GWH$hAFu0pv%)93$OP&2!#8sgl*qX@5W0Cs6IQUY2T)kCo#KeDQ|; zBxt52-M@~Q>u)Ad1`VQs7+&-)0<8s&C5lR*TqNg#8nn$|Owu@HMl5P?EdCNvsoEyy z@&G&1bF;;_c&sn1fjjW_YRB~mY*llf%*&Du*ko%uE-8xxcgD@-FqFJ>%|Y|}lV#{G z%(HOr85E+DT^s458X#(azm(#$-)O~Wq1?>E7NQ=sgu~hW+d*Xq$?|iEpw*pyFGe%< ziO6i=b0gCAU?4^_Ni$_W%_kwLs(72fQ&B5#j`VKJLEYU5vro5QiqN#iA1ec zw&upVK3adlj+~42Bvi%)BtJUykENZk6Yh?$}ca zJn0mUHf1Q?=iQCoeE0BYRlejBi2%eZ&z;jq0g@&T!aEgH>lJ`Kh>C4*?c;z~EX?!S zucP91h>@7%EdCY*I?3`~_c?vT86s>u@;!}6$l>fpsKD{BSS-fo{KyhnyGUDB;&kl%KWdQm{ ze_`q}c61pUUZGx?uQ;xN*V;kE$eC`7p3Z{Z4*AmZ7)k1HsI*q;F&MsTmgh>QMeG}l zB??(uaR6@1es=trByp=H)4Ab)!LV(Rqs%XLw^g{b`DcW`4_|HWE&p8cQGD!WwfGzv z-UiZ2Pgx7u>NI>{cQ#65>Vg7yrSeynp^O7bLcISvBymc;S|JAeo|c3eU!YwVFihv&{!*n`26i%cpWMJ@o_4pyWt%!NTlFHn{wo=YuzI|R8` zitu7>cR3x%*ch4n5>+DlcJ9NF@20nP43g@mLPYt?*O;l=Nn_(*W<^+4cX^ZFFB!p- zGAxg|#wT+JwO9H_Ml%TV!anp`xWjeJlRWA3G!0o(!L(TMYMZS z5=`qf)a{>Fo9a+s6MOT-(jcPBdyD=b6wx}`y*gA3jBc$9W+f%Z9vtR$0&O8*aW9$u zZOOlWeZTt5A2^Ur)t-VTiThz{VgL^*sz}&{RdwFVZ3(`6@uTVo7v=(Ge8EQATRsI{ z^WnDltDRz<8k6U+?#(X)E_j-CsAKX0zC95Kjx(|B@86LayR;8A!>FFWL?N%o1+ks8 ziZ#AWF2T;fnCTc=3$&qteU|-Z{_&JbBiS3EHXlZgOFXTZ$0My72Hg0!OYo+LUhNg5 z70D-S-mP|g3rl5kdwRNc33-;Bb&_db6H`JPD^GjlL%hixW(=&w4#>;=LeXmMy?u(u zLQI3QuLt?pqf3!{Cku`f+R`UBR*v;n84kRN<&TlMeR6}*cI6-`B2i7kvaFDi7Y|e# zBn|#9$_`n}e^}hLnVD&Kg1;*oKMHW6@)v9^g$Mdw+ILBQdAQ69mx#O1fjMI@Op#Mc z&y;!F{@(pWE>75!S(m71!iPGW_lL$Y^pD-SmA|9!wrh^*Uf+p4&M#6C@|Q)dxQbrd zETy%Ft6IWl!V8qbCrn-GJL;|a^G&c`+e;c$Q73vt6YuXf1{AG1Eym^=jlTr@Vc(#* zDwaIpBa6}t6!iApeo0~oK22DPeia|e4E%7QNW6xYve}s z9)7d+4HZqR$fc24D^bu=z3UJ+3;b>F;RBa-OZs)|>*f92x%=}F!CFu=ax<|7BZe-L zI%F%FhN8jAv406Z?R{X?bem~JH67Kv&bx@ z0;rlk3(igGcM3-qz#ACuh>b^+OyIHFv)7C-tCn|67L@Ym%0B@@lhcqiS_A*M(A3wB+0r5qwxDBoCx zTZ&YgL?h1Uhuq<9L5M~}w;ZWE7Ho$fdx zSLYWuK_{f~`NXPjF#gPCr?E4JBR;HJ167W-bgWX!P-=(Aa|t^=jj2nqs!y3KGT z_Qj4KyLS#j*heO3XLu?s$G~WA_Qxw8^u{gQCkN_Vff(CS&s&pn$>mpA9G}nC4K}Ou z&w~4*t#8H7awM(HZ?A9%)|DIMdk!MVEB3?mJtfbh&0~6 zBj@1!a;7EE=y)m#mOvc8RFYaRU8qy_2gP`u^2(dxU^vY9>fcSIm8e+tCBe>PO85twF1Y)@#!XY>d2B06~sgiqzYC47{w z-zgTg5@N5XGrWOp_=8?!OQ8*jSfGFpCAH)Jm}uWT-ckmt!RGjJxAk^9gMO#wbtl&r z7FTeskQaEDN+fN-go@&S8vhy=w>Cy>bso`sGfpR5EOPe| zHsRkm>r695tCEW+U)^5zn`jy>@P4Iij6tj%?ACI8^@{Dk`X^%<47g7x4)|Gq`$Hl|{0C7!+$9tW@vn zIOYwDMII!VJN0T@(vRvtZ9H|Tr#s_wJ?LU-qgvb6+)t zn6*^SBtgxgX~_z~*9xM|6vrWL)@L%(tk>cAl?p>UZFx%v17I z#iK%@G~!e-%#;hzYkxp_VSRNttOXmiTO0O>E7@^bEU?sjO735bDff)QXxe6uyjYCY z*pqsWCWJOR-d(=(tpt9V7)4=fOA+H*1flUmpK)0u<~qm{P@j-EZT(!g%ezJ&X4i&% z(B#BSS*(pSTsmLfoT_b0(D`Nqzx;ouTy)WdW|P!L`ksm7b0c+tsfZfn30`ywyiT-*cy$+BS!l;Qz#%Om6;{7>9q_{zB4cr2FN$6@In{ zrkE*EHtp1>1p_KT_-s0pe;9rt^~WdeHh%G4X@WOg!hBldTqc`*v_-i;=Ta7$m{cAt zHBwBBz#dHhPJ+#liovwu-8)}XUU%|sib9*6XFef|83J1!EyOx1ohXzJRN>b=xIf1 z_}_@=iJE<0e+_VF7|N8cpjU5U@`+@Rx5CKb+dB;Sg7>|*?S2=_0lS)D*U60OQ&CzS zD*(12*q3S=9b_0H}nAix7AuXVCYS+d^ zQ0#veFB{J45!n*u(m%M{{nK({QSlAG$iN~LhB_&ro{rVFEg3!PU6t)+P4U1q>cTH( zX@TIciK7Z~;?NKOV$?(bvDGn_G7Nyrp$@eVG%|_il5qVV1hGtYLVL3tLkOe^G=vrZ z&`6nf>aUkTmpNaS9*DK{ccb>Zw_f60RwW6Xk7xo)`2r6GwdsjOC4Sg|^uAK3){ zEm!p5x=0i30dIPWzFh2INL>A+G~UiaWJ=H=xcL4`GTbC_t*#bbC9~>$Dfp$fZrAgP zt+^+EdhgI2pIQz}p$s{3Dk#o$1`mf8sIJr}K3Ec<#xOhFu8+6)!L9F4k4L)YSnvs& z6&mT0XpkP+t5DY6mR2oH_gcfUWk$aC1?Kf$t+%fI6w*Lu3$Y!(C*Z-|p=~hXrH>Lx zF{0b)i437=@!VRj+*?X#o__hU1o>adR6L5bt>lfsFr=BWN9hOA`=S{4%XcnnCSwLE_k9I__ zv{VhJEl&6Mc2i+5uhI?MaL5ZZGo)}#q7sYmso+zwe5hgnV0oKQBdo!C8X7&I&}V(g z+{WMPhWR|@ezz&K_J*6~&m%Wo z3Jsh?Bza5n5mxlEMR7dgnwk{|L?K}~v#B6?D>%VuxwCwOTc-Y6*!~{S_qD^miOVMu zio=vI3YjV{?oIY4Nn*(kNZWq;p*Ws$&*g{`fV1#EVHztESyYExM6?CF!~b@u zLPuNMI|QQuL-Flc-1=~sI=x-XTxIV&01L0%f{EC_asuK7na<$3PP*hXw3G&O91hPP zzjdw*fcm9%6=T?r(qUH@63fI%d9W+}n;Z-;0)QL&x5&PqEA;?TFsH^vfK=VoHw~Q% zjQXher!QOl1a7mSnks@29%GKM9Ly|SDuM?8_H=y=X!G;#VQcqGkWk(NcNle9kd#lE zIyna_sRDX$OsYgoEwY}qIg!p?xGROT$6YOx$bAB0R(3Y~XpG#1@1rUk9HM!XaGZ*dKALWdC-(tEp7g!;PEk2x(%$hpv6#szKUJ4W9}!ul=UzK4gJv zn!8NSnf{0u@5!CcYR^X4V}qP7HSW={gTS$`XVDjMS_V;;qWbF(9QS0N>rgsGTD%P@ zmR^^jl<##vNMd(ny~iS5y?abX@bukJ2$|+VP#{1Oeik2zWI9|l^te&FW}q%K>XQ~7 zh<9s_+fSzb=~ahHzkmr>Z2drpAOhl_o)A?D512@bfrAK0RwA!S1~LpEvIlrNJ&Ye5tLKt$H@2Lf#s*g#w{hyQ5LY=rHy=aW^vu6RA}m1=rNrpsxrDWuLDyi?L! zbgY(_x~!n98DS?cQ~k8Y@Bz1m;G%`)V9F*|DEM@et5*C?cvLKFtcd+k7KJoX@L1M} zvfT@R&ahoLDc$#8Z8Vu8wkk}vD$jv*a24Snu+C#*_(mLmFdmE=JB5~7iz?Gk`9t-K z3%?qReZeRCqVx+N_%uCR_uLox6&=b3Vrm4CKiU*tK^e0SKOjKX>FeS7e1S*-puoSf zspmnYHBKDS#z^%l_=#`K5quYAnInddX#?+X6=kHn&)(T7d?xq?C1tkXzf7PSKjo~= ztQZNpk+&|pqZQC|3AtmuCKs|=CCYnEflfq@QND-SQp8lu!B+fXAPi;2)I9(ATox}c z9~-oKMh}V4|2uFyIXN7^VAa;LSRz4>ZCBJrr?8%LL#UKd*};hMN%yCNd03vA&neZv z#xMV6@^tjALukR*hoCX zA%}0$GI51CQDlvUp3KCQ2O=H#Cfzviz_zZ1#b()-dqz*4DrHFgR6gfUI+9OfrS9)v ziObZ0dpAdRrXS|fLGSWiDR`)-qxpRqqjCeoPkP>|Q=F4@oELg~mLTSX5HHU>+2nT$ z_3xA{N>#rwn~fWm<-ujFg*hRUnfJtMfgTXM#I;yn8OGXAr&$>(|NQ8+Mb*jT233sH zorgdj{w@|Q8i(@>{61Qdyl!F;MWhudo-yP6U6!?xmZFyFvSG0(LG!y6ZJjDe`-sdQ zgwl1ZkTQPE>Qaw4LNkP>tonW_ z@)toDvTl0)F?ziRLC-gLV2L1gk&QH(6#eRWlF^)>vO`4iv>6z~SHTlh@bAulleh#uyNQf_?e`+ZZ~bG{dS z=N=f2i+)HoYjGQ8kG=#_O>F;0m->N8w*!+l?wxQ|;m6QW-JHHp`XD)JjIxQkX@# z;Yl=ewYb*y^+D+J+cgj{3-7yatxtiEPg%8B^+Uu_sGm_->-U3U`VJli80|KI$1*xv>u2iZ5_RgkN~frRbi4KG6JBneL#d$(H}W#$Td?LEiBFi#E$i=+k3TuUgnmDCPD}Q z(Yl}FOq4%_{e}3n;kZe`4w>H#mnD}MePkE^5YF{Fn+p$Lw$9!*1@Pg$%AO@>F3sqj4adG}^o;=sTX7&JVVuKh>9n1$)UhoNLaz0$0 za=Ny&bI8sdcKa2*G8@(l^iY{-BxbH9f~NdxYbcwDbe(xJHA}63wc+@eJAim_gHuLO zh}TjEVja`9l*{rX;y3({X1h|f5BAc+!cX&nKfl-Zu@K<`Oh>w$QY*&?W5WcQPJ1R> zhqI6Lyc|l(it04-uAu`K(E5=K(Z8n#?gGTv;h(78S%FmAKzJ_agCN03#>t!s@?Gkk zfx}OQMakbya!|j#_n3W~cTL4Bx^Di=mNd zs=JrQuAk~|=HGIPL4(;vGcZWX7mmqwBV5l!+68IZVI+SHIx&(2P_UL~2FFxYliv3r zzzXe4P?YwiC*z0Kf>N@#o<~~?a=8eKc?SQ_yjrq*?(#6cwKVs{pQ7jo=?ybNE2Npf zRCRXhGX??=)ItVy*-cmh?GgCZ0`D}paYr`>#%Aiz)Jj>)Y8lXF2&R-S zBqaz6s}GDnIG|;%?ZCF_)Q$=#(68jY{4LOtFx1SD(N3zDT3@kDJ+@dsuPsS*H$hx# zxD3w|%1|P9tUH;HMYe}J5VxzxzcA#Wt2O3%IfQsYYrCKyHLX<~LnRBC#%^x~7>D5e?Yat@u?+O7h0qgz+uJB(XTan8BUe`HecN0wI`H5niNA zmW)?T8x`A)V@QG9&0oNl$z;)~+==TLQ7)s|3r1s4u>xTLpY%CnwPdsp+X;iA;Y zV+ym{eYzz(%e`0Xm;WESD*gJ);Eq9$5Pq|2Tz0QlpMIm2oP~jPss;GGl?iwK5NV3U z66n6hk#y;F3ZoHj?s@f5w!qz@Qe2zPOaD`B42(^?d~xNLI$7}?%uiGMmt6xC=NWs^ zo%!H&$HB4Rs?jrJiUwBk2($Vx->_-JP^YBHgF&yNM&Q#DL-TpW^kIQAsW?O<|JP$+ zr^)YC1Cfk_B)?JxuZuaO5f9ulrw{KDOcVYUzyaHj%?MoM|MNQ_T0Vn~KA5yP{o!#P zfrRw_uDi@X`&w{7Mz}78EtK1lClgeC?sY=Xp_)$qxl^w@kGb`VMO=+YBox;W<^?Z0 z=7taF;{9&&G{bU=Wn0cfxb^n0rtbHn-kz8}9AY`kBpNvcjY6}9Fgv(x-ttpGX9cf$ zZx~9LV?e!%Q2uXG)CFiAmIW!736&%FN;hpx)Lf&fYIRGD#1-_T#s~gVI@Z!}c#p50 zotFk+fpfGPFpp8b_fZ`GxLnW*IzpOH-<-H7WljvfsdYA`XHERPl9c^=yc{VnSxKE; zq&^dmx7maK4rH??8f0bo&kNOggzuvXVirIYwru|g)!!=N%tCOdt&Jf?9h%+6*z`Mmmfs$(CN%SkvT$t;O`GDg(8TW#=rWj^}F#H_Fq!QwYQX4 z$j6Z}r!E&+%+ROhoUFTzc9WZ~u_s@~4^QWF(L)O!k%TeRFsP^-{N1F8K9cuP_KeKD zstYPUYyXod|6gouNJAQIubf)7xvn7VBL!4A6l4{#U!1KE6_dmG(2kPwt+-g&wrIq;nMEk2U5yDHb%3S{H$0+M3_UM zKyCff6VgJ8Qr5f*vQ)=^9?Z3*(4th)NP&J;jK)32Eq=6RlzzN_T`Y?+tVHj^DrMfz zzAnqU8@^a7E?)elwxTvh`L1{)wCy*3G?|)j&zlt0nPa5p5F9)QQ1jFHfa2%KvVymv z;lIG##n_Yn=q|;_M-)42580^JXzgk-=OV-9aDq@XjI*!;GECUZ1%VIV6OEUwmRtY= z>8}{e4NFz^9-goai8_7DSC3R>9QjVID=)rSgiyW)ZiO+;u)vZcA0?%Y{%_btT}2Q> zBzOh`zBVgBrl}!Hd`sfWe6;X#)dVlpF=Ak!ad^g9M@{RenImEez52&T#x!=pp4%n| zf!Fv+e^vF)Ll7iHn|H$MUtb{IAe}g@tdt(Ie~`__Y|k4X98T&E#}9)qLNdg zl*9pyH6|cJii~@kpU0)|3v1dDeLAP#vPy-b4(~R@609}nwJTmF-#bzmj3P{L$U2gH z^q7_Y1g%DLHBfG-F$*XZp)feTy+%}0JBDxa8t5M}va_vdf9-pI87@ulG{aLCWD_SA zj{W6|tzWeR(ghL6Sa{*e-;LgAjx2eX!gHDsgRm+}%UL{G6M ze{5JhuT=^>L0-=)XXZkL63(Uzhe>G{CBp|I-G-jvt@z3y+f|J$vl-(=!`c*_m zTFe{4B=VRGo*b7h0d>DDJ);Z}P>s-z@+=cwNq%)6-v&gcw)WJ@x5yXwn{mX)U-lM} zH$ZHR%fo-+mw6=+OwA`wX>k|77vgp3Z-?~*7NDh0oa~lAQOBg2Pf2PZ(nLW?7XJo6 z=7=59O~q9)O+QgQ<|tz5UHXW~J8Qfye$_C4>9tV*B?8w8k+&^i7{wgK`==ER>7%gN zhGYHr-p=!WWm>lktu3c^z=e>+6Sywg$yasRRGs845SYpqjpGH=Y>3+x;LB*JnEvVc zb=~pkw!|ywVengxh|BZF&e!tEWY+jLL}r_UV{0FN5MzL zgAujH59{k`0e$G zy~)JYe>Lnxqz&*m4Yj^OYes2PSazB9^ zj1!hD)P$NqEFO|(9a(4O{xZ#A3fZ@>-6!`o=ckK$&&Zq*bdjr7TUFd#idq5s4fSxh z#`jaKlsxNd>s5Gr2aw-( zs~u&GozE%10ON6yl!8bsFTKd@-U)RgNkGp7UEj4X9sE)dqPN%NMT=zkg02F7A|xZY z?CXyvg;8p@QzuXZ>@+W0gRM(0s8m&v=-x~L%B}PinCfR6dFQOs<|ne#d3l+dagJlA@0g|!l7w^MRoW+aVjG2DmpQ!7qTN> z2Y-Z1JNV3y1x-yX4(T=hnRLM=q@BS?7qyo%o?W2}sdwWiTq3;uLcnhd>WG>V(If;r zj^J*;WEuEK4vIh>qh>u};!#R=*Y<&j8$INk?Tq)~);w%Tang!_b(ph64Bzd(T5jHhn>@z4 zZZT%oVB~=Ca6LqMAUCfx2rf}c2t6VEcZzqZtpW;UWJkBQqLgvHKPhU`W+9vkKRcFB zK!1*w>Jn8tvVwB0&#qgpB042>qiMVJa{Pj&1%bbK-WscHZZutT&D_ehemowGk5G<1 zf#)EWGi^I1zb0+VTRGBN)c*SHU(sA1(Pn9*X-4Y_nF?_jQ z#jDoeb+?{7d>W`wMQ&K&7Y}g9_$me+U3Y=MN_q);=8&e*oUqm84uBHV3P)R8g_)o1 zrjmnp_Gx^vM=A9&4kG9J8MgVsR@kmJy0T8nUlgUG5F5<@;ydUi8W(S)#dsTGVWZP? zxGM{k-9`*i?*SmH-(KMxp#MS=SL6G%d$@z^m!EeB=eENt6f9;$oThN2fVRRMir|SE z(lIs~p_p4ValKqE1Qz73TeP`hbzM*rs06F%3)dGs*a-Ua0}1`QUqV+is?-6Z?<+!Z zAZS!xnATg`p9stUxg$r(T|InxZTSmv?hOw|KlT8_w}r)8)Df=c8guR{UZw8LXe4<# zCs_pqb?o1U^h-LO)fHEIsb`D%&yg0gN4HY4YW^TWYa=`qopjD2o8*%Ei5*kh+F825zmm`=G=s^US z`FRu4(-jD>h|B8bj~jYEJe3|sqk-C*J>RQILz@uUGgx)`-cL9qLqB^YQW)me6=iN8m~nxadBs!xHD;GS|S{(OC4b|ME||$F*0RXk_(O<&4%04 z_2+HEz`zPBk*tVv!2)*gAYy%FQHURjo*7SA?+B+o0SJmH^fJCX3T7affj9gUxu0^= zoY%eh;S0(AY>v4}u3S1Evhz`ghG>Jzc>gSCTDkno*!<)zn>io58R&^qF^?6+;%xH% zxG(kO#dWr5v`D|MMWw}T8avW##?=FD`8;hi%`_Tw{@_j}4P1WZLsD);jgqD|5+Q41 zCxSeHSZsz^pt<(NyZJpxnOUli8Lxea%@ONw;2@bx7jY`}oK1VnO;tmmW z=DbwdEfTpm=^IAZ@jJ@L{zim{4Mla0(Nu#Jugibx^So{=!LtFO=t$rRea!Wa{mHjSd2Vc@PhJlj^)^_hE43#916>L@56VvIM(pEc zLCr&(K&_iB$yvYkXf%=f7s2688B~x7eU*B`hiaIiNvI?iOvd+}fIBUh=|Z+|d_81yU7n7jvEKz*=LoeUnlQK%aelxB!4luD$K5~HQa9srm4eMW&w4a7bAbinj!0sJOpY7`G{e=c+HBQx3*RbrI>1H*VilUv z)g(7u_Y!6S$QRbYpZ+EvD|PExB}RkW+Esmy4G83f;>9Q7s)HN7A7a0hcK`&VltjFZ zqF)I*n*TE*l=m*K`_^P3SR#MDB8w-hRe}#o6GX{+5>l3fn-${#Cm2aF>Qm!HUU_g( z>sBu6O5>~nZU$Q0+DwyqiYGJLW3AV}xKHPPStFN|t;4u3-IFyZIk_%9+_yt02b{%R zmKsXtAeXuIiMlADsH^%_|G36CwP?0dA?_#J+oO=0ab9^Nr;Z#D?J)Lr487OWK;`!D zfH6uud#M4+uhm02^XAf|$nLMlqT~&;=!Yw#ygfHPCCgFBXZlD}Av;a5f3QtSEktE= z_6!Cv_O6Bzip`9c3f6+AE}zx?&C>y3xiNDaAvmtn&Fp^o#``*)C#9k8uHpj+$bM{Hl2>5HQp zxrFZf#udFPL0MWPq8)&qBWcrZQ`C#$8l(9k-w=+<-IPtb+G6Bdgw6=Mssg%duR}Ji z6wLANY$@XBe&pWK?`*^5+RjZiy649jk${!%TPwwgE@q5G$gP+wiF2MD`e108U=jT5 zh<$;e&?;ac=={1VmNvSK*=R8Tq(IIFAaqmc`B~}|4H2uOaz8zo{1&Z{N6!#c7L6iC z=#7&gQ938dwDKuXbaGPcjB!WD&qs&L=Qks?xjjf6QCPYQuU$0n_DI@KjibfCRQT)c z8;x4?lGGT%k#A)~%gnj*T68C#(7fezP(#a5E(-+t^Anr>56pFA%cU`c+{_%rPB4ud zR=r@@n)CV<7mA2ukwN9^47n(7)-3eh5=k|JJdp`Z+6Q(O4>M>-qHaiJGCM_p;HFTA zC$V$IEEhZn5h@G%{y-d{)%GVytfC3ta#!>xk&;%QWZ%@xOc|5oq~(vMn+aw8rVx$f zEg#R;9N8lgpG1Akj1DFAeP!l%fz65htq)gw=cTi|H@mAg%VYX`Tsr!EvY+k?cqwt^ z;3Rkv<{{W12otjkWEwZu&#Ht(m#&Eby_UCIe}$n=beKA~qE&x-8xb~&@WhHcmlafceG&fhh5GS$ zV}T(QPo$%a&6u``ldn|__|T9L65VLZh=#e0cT`~9?|XW%b0~!&hN>??1i-{}&@+7c zr3SJ5ZapvxBhg}5o7UAZxsgp{=K4nw3CEC-rqz!1FCVvW*rRP&k0Ef%{Ov&6REZig zp>*~ugm&>K+zUSAt^onR&}4}v1|gy@=q2lQ=z*y3Bi!Vj5TiqPGM~L+{|L3jX9AwS zx#A2n!;2C2%la(wW+978v9vx1aRiy!Lr&l0y@iMM8>^4jhzr2S!^g+P%g4pTug&}F z&8t^$`1lcV*&807m>jD=|CfLhqU!R4&;MWGp=Ta(;u&E5KRtNZIa#}VSU9=0ff85vgq}f`VA4A9@001~furR&K zN7A9gVf;upy3r2+U{U}cZ%e@AQFp>aeFK7g0N`wHTrS3fZhWf8bM%Uts{A+9*PQZ; zE~1hVW2zG6xZfqOM`*SD5H8kLRME&H2X=L3_f#dOH`E@lC8PGhuS-nolDraEQ@t_u z`;vOl)j>`uB4i zcN4NaF8H1AR2Cc3rZ=YPr&j6(CvF*qB}w`e>^+ShqY8^*!`%ZmzY%t7HyB$e`S zC|s_#ewZxrtq;RVto4+CgsT;kHaKZ}A2zX_$m`k&so``->!?TwwtAdeyd@1^hh!Gd z#Ud|R&p}yO0q2-0&ldtZWz_M>>p$R2Q!tI%sp5J;w{<|kCMD=YEwfUExz)**iL*Zm zpM_uo2N~Dd=r~|x%yAQjMnf+n^4r(Hudjb(a51AR8-g)e;Z+OtTxZ z_;8;aL?3TdQ~=Q*WlpfNb-sUG3ILA42&N_u(UadwUfq=^NT+xfiNC->O@hP7A1vI4 z1IdO_xvLuMOs;xvZkVz`l-SXTJoML;cXbjsMIGj+)0SHX)?dp(X7IZMTMkyiPT+yj zLEH>IyO2Nr-}3CX?#d>PjWlXfl6)0M{dvLD#vTgSU;6CU)2TVDK%#!r=h-MKIf_5G zD<2kIXx+~O`dC;{QC)FRaj*)7e~v3(On7q|ODq<)Jt89u!jP7-S6VgB|G;}k=joQd zsuY4WALI6Ns&HI+Dp(k9eB-LPH_R4F}&$b0%{=JeCHW7G^e2-_t#z8+IlOBEhPICUYs zuJB4!cv8&$5TV0o3-yxCA)tT{lIiv5Zv3S08qCBAXjmDV9rD{jYIddfyWj6eXnA*p znvq-|tyWghClcsYvy-)7dNTsFB)$Hq!e)FA(q^x^A1NN-#yH=vn4g$++Q~fa+wny8 zPH^w%DTLOY_Rt!Gzxt#=(azgHJ8sTyaA=(cgL=c>JL7E#6aca1u1>>(97#nrp3AQ9 zr1@oXp!LsR&YnY3lXOR5#f-rLc zY79Wp;1<2lb@OaVO(wD=WZzpMAIpG~0KQdHiiAIOO&&IWn&pzI;V60R zEHthOId<-^l{KT&-pb_F48*h1CrGNIy=ze}V0fVUv=sW+S!}qARY{3d-Gut6b@gs` z{oU|e^@a~SlrRJ1_I|E`<4EDM$4T8&ftGSEp^TRe!xM9?VvFS>*O^Kxx<;H4nLV;fue-%O2prY(QXmq|3V>56$A zPlS-YwM}%C0TFFv&16*)l>H`FgwJ^Vl~@=P)9fO0F6T?z-?MGgnf2NY!{yi6zfz5N2gUuSP!qeFbaqsHlcPZ=vtvNMz{H2bwR#F=9jdqavm# zjywH8S>mU*_JUED+k|<)W(L$TK9HOV6YWQfjrfmJ7U|NS%Z&tne~ Xz Date: Sun, 4 Dec 2022 16:45:31 +0100 Subject: [PATCH 081/269] Add support for single-line comments to scss (#5003) --- runtime/queries/scss/highlights.scm | 2 +- runtime/queries/scss/injections.scm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/queries/scss/highlights.scm b/runtime/queries/scss/highlights.scm index 89cce49442c2..8ba00a881c33 100644 --- a/runtime/queries/scss/highlights.scm +++ b/runtime/queries/scss/highlights.scm @@ -1,4 +1,4 @@ -(comment) @comment +[(comment) (single_line_comment)] @comment "~" @operator ">" @operator diff --git a/runtime/queries/scss/injections.scm b/runtime/queries/scss/injections.scm index 321c90add371..350ea9e78a76 100644 --- a/runtime/queries/scss/injections.scm +++ b/runtime/queries/scss/injections.scm @@ -1,2 +1,2 @@ -((comment) @injection.content +([(comment) (single_line_comment)] @injection.content (#set! injection.language "comment")) From 417676953bce6a4be91f4b8da35ed0e361b585ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 5 Dec 2022 14:40:41 +0900 Subject: [PATCH 082/269] Add basic support for common lisp --- languages.toml | 15 +++++++++++++-- runtime/queries/common-lisp/highlights.scm | 1 + runtime/queries/common-lisp/injections.scm | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 runtime/queries/common-lisp/highlights.scm create mode 100644 runtime/queries/common-lisp/injections.scm diff --git a/languages.toml b/languages.toml index d214a082fcc3..325a39dfc4c6 100644 --- a/languages.toml +++ b/languages.toml @@ -878,14 +878,25 @@ source = { git = "https://github.com/ganezdragon/tree-sitter-perl", rev = "0ac2c [[language]] name = "racket" -scope = "source.rkt" +scope = "source.racket" roots = [] -file-types = ["rkt"] +file-types = ["rkt", "rktd", "rktl", "scrbl"] shebangs = ["racket"] comment-token = ";" language-server = { command = "racket", args = ["-l", "racket-langserver"] } grammar = "scheme" +[[language]] +name = "common-lisp" +scope = "source.lisp" +roots = [] +file-types = ["lisp", "asd", "cl", "l", "lsp", "ny"," podsl", "sexp"] +shebangs = ["lisp", "sbcl", "ccl", "clisp", "ecl"] +comment-token = ";" +indent = { tab-width = 2, unit = " " } +language-server = { command = "cl-lsp", args = [ "stdio" ] } +grammar = "scheme" + [[language]] name = "comment" scope = "scope.comment" diff --git a/runtime/queries/common-lisp/highlights.scm b/runtime/queries/common-lisp/highlights.scm new file mode 100644 index 000000000000..e11eb7881081 --- /dev/null +++ b/runtime/queries/common-lisp/highlights.scm @@ -0,0 +1 @@ +; inherits: scheme diff --git a/runtime/queries/common-lisp/injections.scm b/runtime/queries/common-lisp/injections.scm new file mode 100644 index 000000000000..e11eb7881081 --- /dev/null +++ b/runtime/queries/common-lisp/injections.scm @@ -0,0 +1 @@ +; inherits: scheme From 03ca18b377c1dfd78e8ff6bfac6d418de237923b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 5 Dec 2022 15:02:13 +0900 Subject: [PATCH 083/269] Update language support docs --- book/src/generated/lang-support.md | 1 + 1 file changed, 1 insertion(+) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index b1fde0016abb..ccfd18c00fca 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -12,6 +12,7 @@ | clojure | ✓ | | | `clojure-lsp` | | cmake | ✓ | ✓ | ✓ | `cmake-language-server` | | comment | ✓ | | | | +| common-lisp | ✓ | | | `cl-lsp` | | cpon | ✓ | | ✓ | | | cpp | ✓ | ✓ | ✓ | `clangd` | | css | ✓ | | | `vscode-css-language-server` | From 1e31bc3f77040d4a3663b8b6bf72d8d3a632b88a Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Mon, 5 Dec 2022 14:18:42 +0100 Subject: [PATCH 084/269] Reduce log message about diff timeout from warn to info (#5012) --- helix-vcs/src/diff/worker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-vcs/src/diff/worker.rs b/helix-vcs/src/diff/worker.rs index b8659c9b3bc2..f4bb4dbfb07c 100644 --- a/helix-vcs/src/diff/worker.rs +++ b/helix-vcs/src/diff/worker.rs @@ -185,7 +185,7 @@ impl<'a> EventAccumulator { } // Diff failed to complete in time log the event // and wait until the diff occurs to trigger an async redraw - log::warn!("Diff computation timed out, update of diffs might appear delayed"); + log::info!("Diff computation timed out, update of diffs might appear delayed"); diff_finished_notify.notified().await; redraw_notify.notify_one(); }); From b0f20f13e3a606cba35cc70144f045a22b5b38bc Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Mon, 5 Dec 2022 14:46:59 +0100 Subject: [PATCH 085/269] fix git diff when core.autocrlf is enabled (#4995) --- helix-vcs/src/git.rs | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/helix-vcs/src/git.rs b/helix-vcs/src/git.rs index 82b2b5587fc4..432159b6cdb8 100644 --- a/helix-vcs/src/git.rs +++ b/helix-vcs/src/git.rs @@ -17,14 +17,17 @@ impl Git { // custom open options let mut git_open_opts_map = git::sec::trust::Mapping::::default(); - // don't use the global git configs (not needed) + // On windows various configuration options are bundled as part of the installations + // This path depends on the install location of git and therefore requires some overhead to lookup + // This is basically only used on windows and has some overhead hence it's disabled on other platforms. + // `gitoxide` doesn't use this as default let config = git::permissions::Config { - system: false, - git: false, - user: false, + system: true, + git: true, + user: true, env: true, includes: true, - git_binary: false, + git_binary: cfg!(windows), }; // change options for config permissions without touching anything else git_open_opts_map.reduced = git_open_opts_map.reduced.permissions(git::Permissions { @@ -61,7 +64,29 @@ impl DiffProvider for Git { let file_oid = find_file_in_commit(&repo, &head, file)?; let file_object = repo.find_object(file_oid).ok()?; - Some(file_object.detach().data) + let mut data = file_object.detach().data; + // convert LF to CRLF if configured to avoid showing every line as changed + if repo + .config_snapshot() + .boolean("core.autocrlf") + .unwrap_or(false) + { + let mut normalized_file = Vec::with_capacity(data.len()); + let mut at_cr = false; + for &byte in &data { + if byte == b'\n' { + // if this is a LF instead of a CRLF (last byte was not a CR) + // insert a new CR to generate a CRLF + if !at_cr { + normalized_file.push(b'\r'); + } + } + at_cr = byte == b'\r'; + normalized_file.push(byte) + } + data = normalized_file + } + Some(data) } } From f712d316e5d210e95f9d297651f1d753646c26d2 Mon Sep 17 00:00:00 2001 From: two-six Date: Mon, 5 Dec 2022 14:48:20 +0100 Subject: [PATCH 086/269] Update Acme and Nord Light for git gutters (#4999) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update acme.toml * Update nord_light.toml * Update runtime/themes/nord_light.toml Co-authored-by: Blaž Hrastnik * Update acme.toml Co-authored-by: Blaž Hrastnik --- runtime/themes/acme.toml | 3 +++ runtime/themes/nord_light.toml | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/runtime/themes/acme.toml b/runtime/themes/acme.toml index d3be695cb944..696a4a9b2633 100644 --- a/runtime/themes/acme.toml +++ b/runtime/themes/acme.toml @@ -22,6 +22,9 @@ "diagnostic.hint" = {bg="white", modifiers=["bold"]} "ui.bufferline" = { fg = "indent", bg = "acme_bar_bg" } "ui.bufferline.active" = { fg = "black", bg = "acme_bg" } +"diff.plus" = {fg = "green"} +"diff.delta" = {fg = "acme_bar_bg"} +"diff.minus" = {fg = "red"} [palette] white = "#ffffff" diff --git a/runtime/themes/nord_light.toml b/runtime/themes/nord_light.toml index 5270fe34ea39..eb947d034fc3 100644 --- a/runtime/themes/nord_light.toml +++ b/runtime/themes/nord_light.toml @@ -58,6 +58,10 @@ "markup.link.text" = {fg="nord12"} "markup.quote" = {fg="nord3", modifiers=["italic"]} +"diff.plus" = {fg = "nord14"} +"diff.delta" = {fg = "nord13"} +"diff.minus" = {fg = "nord11"} + [palette] nord0 = "#2E3440" From 5781aa026417bc6539b80b451da4a99a7057bbe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Dzivjak?= Date: Mon, 5 Dec 2022 16:16:25 +0100 Subject: [PATCH 087/269] feat(highlights): go builtin funcs and types (#5010) Add highlight scopes for golang built-in functions and types. Based on https://pkg.go.dev/builtin. --- runtime/queries/go/highlights.scm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/runtime/queries/go/highlights.scm b/runtime/queries/go/highlights.scm index 4ff8675b1d5f..927bd95b06a7 100644 --- a/runtime/queries/go/highlights.scm +++ b/runtime/queries/go/highlights.scm @@ -1,5 +1,9 @@ ; Function calls +(call_expression + function: (identifier) @function.builtin + (match? @function.builtin "^(append|cap|close|complex|copy|delete|imag|len|make|new|panic|print|println|real|recover)$")) + (call_expression function: (identifier) @function) @@ -24,6 +28,9 @@ (parameter_declaration (identifier) @variable.parameter) (variadic_parameter_declaration (identifier) @variable.parameter) +((type_identifier) @type.builtin + (match? @type.builtin "^(any|bool|byte|comparable|complex128|complex64|error|float32|float64|int|int16|int32|int64|int8|rune|string|uint|uint16|uint32|uint64|uint8|uintptr)$")) + (type_identifier) @type (field_identifier) @variable.other.member (identifier) @variable From 5691ada822a7c6e27f8890ee25f52a9262caddd2 Mon Sep 17 00:00:00 2001 From: VuiMuich Date: Mon, 5 Dec 2022 23:28:20 +0100 Subject: [PATCH 088/269] Change diff colors for serika themes (#5015) --- runtime/themes/serika-dark.toml | 2 +- runtime/themes/serika-light.toml | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/runtime/themes/serika-dark.toml b/runtime/themes/serika-dark.toml index 88e4cf6d5e82..2b4000ac215f 100644 --- a/runtime/themes/serika-dark.toml +++ b/runtime/themes/serika-dark.toml @@ -61,7 +61,7 @@ "diff.plus" = { fg = "green" } "diff.delta" = { fg = "orange" } -"diff.minus" = { fg = "red" } +"diff.minus" = { fg = "nasty-red" } "markup.heading" = { fg = "purple", modifiers = ["bold"] } "markup.list" = "cyan" diff --git a/runtime/themes/serika-light.toml b/runtime/themes/serika-light.toml index a00274bb9f60..ad830d92c148 100644 --- a/runtime/themes/serika-light.toml +++ b/runtime/themes/serika-light.toml @@ -59,9 +59,9 @@ "error" = "nasty-red" "diagnostic" = { fg = "nasty-red", modifiers = ["underlined"] } -"diff.plus" = { fg = "green" } -"diff.delta" = { fg = "orange" } -"diff.minus" = { fg = "red" } +"diff.plus" = { fg = "bg_green" +"diff.delta" = { fg = "bg_blue" } +"diff.minus" = { fg = "nasty-red" } "markup.heading" = { fg = "purple", modifiers = ["bold"] } "markup.list" = "cyan" @@ -72,7 +72,6 @@ "markup.quote" = { fg = "yellow", modifiers = ["italic"] } "markup.raw" = { fg = "fg" } - [palette] bg0 = "#e1e1e3" From 7210c58a51a16c0ae3c9d77211ed1a25e039bd9e Mon Sep 17 00:00:00 2001 From: nosa <96927121+n0s4@users.noreply.github.com> Date: Tue, 6 Dec 2022 01:13:41 +0000 Subject: [PATCH 089/269] Change default TS object bindings (#3782) * Change default TS object bindings Changes 'match inside/around' bindings for: - type definition from `c` to `t` - comments from `o` to `c` - tests from `t` to `T` Also changes those for the `]` / `[` bindings. * Update docs for changed keybinds Co-authored-by: Michael Davis --- book/src/keymap.md | 14 +++++++------- helix-term/src/commands.rs | 16 ++++++++-------- helix-term/src/keymap/default.rs | 12 ++++++------ 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index 6523b09fb88c..c3c09f4ca3b9 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -297,7 +297,7 @@ Displays documentation for item under cursor. | ---- | ----------- | | `Ctrl-u` | Scroll up | | `Ctrl-d` | Scroll down | - + #### Unimpaired Mappings in the style of [vim-unimpaired](https://github.com/tpope/vim-unimpaired). @@ -310,14 +310,14 @@ Mappings in the style of [vim-unimpaired](https://github.com/tpope/vim-unimpaire | `]D` | Go to last diagnostic in document (**LSP**) | `goto_last_diag` | | `]f` | Go to next function (**TS**) | `goto_next_function` | | `[f` | Go to previous function (**TS**) | `goto_prev_function` | -| `]c` | Go to next class (**TS**) | `goto_next_class` | -| `[c` | Go to previous class (**TS**) | `goto_prev_class` | +| `]t` | Go to next type definition (**TS**) | `goto_next_class` | +| `[t` | Go to previous type definition (**TS**) | `goto_prev_class` | | `]a` | Go to next argument/parameter (**TS**) | `goto_next_parameter` | | `[a` | Go to previous argument/parameter (**TS**) | `goto_prev_parameter` | -| `]o` | Go to next comment (**TS**) | `goto_next_comment` | -| `[o` | Go to previous comment (**TS**) | `goto_prev_comment` | -| `]t` | Go to next test (**TS**) | `goto_next_test` | -| `]t` | Go to previous test (**TS**) | `goto_prev_test` | +| `]c` | Go to next comment (**TS**) | `goto_next_comment` | +| `[c` | Go to previous comment (**TS**) | `goto_prev_comment` | +| `]T` | Go to next test (**TS**) | `goto_next_test` | +| `]T` | Go to previous test (**TS**) | `goto_prev_test` | | `]p` | Go to next paragraph | `goto_next_paragraph` | | `[p` | Go to previous paragraph | `goto_prev_paragraph` | | `[Space` | Add newline above | `add_newline_above` | diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 4cd271194959..31a2f58274d1 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -402,8 +402,8 @@ impl MappableCommand { select_textobject_inner, "Select inside object", goto_next_function, "Goto next function", goto_prev_function, "Goto previous function", - goto_next_class, "Goto next class", - goto_prev_class, "Goto previous class", + goto_next_class, "Goto next type definition", + goto_prev_class, "Goto previous type definition", goto_next_parameter, "Goto next parameter", goto_prev_parameter, "Goto previous parameter", goto_next_comment, "Goto next comment", @@ -4520,11 +4520,11 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) { match ch { 'w' => textobject::textobject_word(text, range, objtype, count, false), 'W' => textobject::textobject_word(text, range, objtype, count, true), - 'c' => textobject_treesitter("class", range), + 't' => textobject_treesitter("class", range), 'f' => textobject_treesitter("function", range), 'a' => textobject_treesitter("parameter", range), - 'o' => textobject_treesitter("comment", range), - 't' => textobject_treesitter("test", range), + 'c' => textobject_treesitter("comment", range), + 'T' => textobject_treesitter("test", range), 'p' => textobject::textobject_paragraph(text, range, objtype, count), 'm' => textobject::textobject_pair_surround_closest( text, range, objtype, count, @@ -4552,11 +4552,11 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) { ("w", "Word"), ("W", "WORD"), ("p", "Paragraph"), - ("c", "Class (tree-sitter)"), + ("t", "Type definition (tree-sitter)"), ("f", "Function (tree-sitter)"), ("a", "Argument/parameter (tree-sitter)"), - ("o", "Comment (tree-sitter)"), - ("t", "Test (tree-sitter)"), + ("c", "Comment (tree-sitter)"), + ("T", "Test (tree-sitter)"), ("m", "Closest surrounding pair to cursor"), (" ", "... or any character acting as a pair"), ]; diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index c0d17a87e065..b6d9ea1088c2 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -101,10 +101,10 @@ pub fn default() -> HashMap { "d" => goto_prev_diag, "D" => goto_first_diag, "f" => goto_prev_function, - "c" => goto_prev_class, + "t" => goto_prev_class, "a" => goto_prev_parameter, - "o" => goto_prev_comment, - "t" => goto_prev_test, + "c" => goto_prev_comment, + "T" => goto_prev_test, "p" => goto_prev_paragraph, "space" => add_newline_above, }, @@ -112,10 +112,10 @@ pub fn default() -> HashMap { "d" => goto_next_diag, "D" => goto_last_diag, "f" => goto_next_function, - "c" => goto_next_class, + "t" => goto_next_class, "a" => goto_next_parameter, - "o" => goto_next_comment, - "t" => goto_next_test, + "c" => goto_next_comment, + "T" => goto_next_test, "p" => goto_next_paragraph, "space" => add_newline_below, }, From 2077f5e26a4cdaadde4b505fc64eadb9e6849c0d Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 5 Dec 2022 19:29:40 -0600 Subject: [PATCH 090/269] Apply completion edits to all cursors (#4496) Completion edits - either basic `insert_text` strings or structured `text_edit`s - are assumed by the LSP spec to apply to the current cursor (or at least the trigger point). We can use the range (if any) and text given by the Language Server to create a transaction that changes all ranges in the current selection though, allowing auto- complete to affect multiple cursors. --- helix-lsp/src/lib.rs | 38 ++++++++++++++++++++++++++++++++- helix-term/src/ui/completion.rs | 31 +++++++++++++++++++++------ 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index abc930f85bd6..f714395f28f5 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -57,7 +57,7 @@ pub enum OffsetEncoding { pub mod util { use super::*; - use helix_core::{diagnostic::NumberOrString, Range, Rope, Transaction}; + use helix_core::{diagnostic::NumberOrString, Range, Rope, Selection, Tendril, Transaction}; /// Converts a diagnostic in the document to [`lsp::Diagnostic`]. /// @@ -196,6 +196,42 @@ pub mod util { Some(Range::new(start, end)) } + /// Creates a [Transaction] from the [lsp::TextEdit] in a completion response. + /// The transaction applies the edit to all cursors. + pub fn generate_transaction_from_completion_edit( + doc: &Rope, + selection: &Selection, + edit: lsp::TextEdit, + offset_encoding: OffsetEncoding, + ) -> Transaction { + let replacement: Option = if edit.new_text.is_empty() { + None + } else { + Some(edit.new_text.into()) + }; + + let text = doc.slice(..); + let primary_cursor = selection.primary().cursor(text); + + let start_offset = match lsp_pos_to_pos(doc, edit.range.start, offset_encoding) { + Some(start) => start as i128 - primary_cursor as i128, + None => return Transaction::new(doc), + }; + let end_offset = match lsp_pos_to_pos(doc, edit.range.end, offset_encoding) { + Some(end) => end as i128 - primary_cursor as i128, + None => return Transaction::new(doc), + }; + + Transaction::change_by_selection(doc, selection, |range| { + let cursor = range.cursor(text); + ( + (cursor as i128 + start_offset) as usize, + (cursor as i128 + end_offset) as usize, + replacement.clone(), + ) + }) + } + pub fn generate_transaction_from_edits( doc: &Rope, mut edits: Vec, diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index ebb4fb46ae66..c54990e8ec75 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -1,5 +1,5 @@ use crate::compositor::{Component, Context, Event, EventResult}; -use helix_view::{apply_transaction, editor::CompleteAction}; +use helix_view::{apply_transaction, editor::CompleteAction, ViewId}; use tui::buffer::Buffer as Surface; use tui::text::Spans; @@ -107,6 +107,7 @@ impl Completion { let menu = Menu::new(items, (), move |editor: &mut Editor, item, event| { fn item_to_transaction( doc: &Document, + view_id: ViewId, item: &CompletionItem, offset_encoding: helix_lsp::OffsetEncoding, start_offset: usize, @@ -121,9 +122,10 @@ impl Completion { } }; - util::generate_transaction_from_edits( + util::generate_transaction_from_completion_edit( doc.text(), - vec![edit], + doc.selection(view_id), + edit, offset_encoding, // TODO: should probably transcode in Client ) } else { @@ -132,10 +134,23 @@ impl Completion { // in these cases we need to check for a common prefix and remove it let prefix = Cow::from(doc.text().slice(start_offset..trigger_offset)); let text = text.trim_start_matches::<&str>(&prefix); - Transaction::change( - doc.text(), - vec![(trigger_offset, trigger_offset, Some(text.into()))].into_iter(), - ) + + // TODO: this needs to be true for the numbers to work out correctly + // in the closure below. It's passed in to a callback as this same + // formula, but can the value change between the LSP request and + // response? If it does, can we recover? + debug_assert!( + doc.selection(view_id) + .primary() + .cursor(doc.text().slice(..)) + == trigger_offset + ); + + Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| { + let cursor = range.cursor(doc.text().slice(..)); + + (cursor, cursor, Some(text.into())) + }) }; transaction @@ -164,6 +179,7 @@ impl Completion { let transaction = item_to_transaction( doc, + view.id, item, offset_encoding, start_offset, @@ -185,6 +201,7 @@ impl Completion { let transaction = item_to_transaction( doc, + view.id, item, offset_encoding, start_offset, From dbed90c5a65f435c7886f27b17cbad9cd8492355 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Dec 2022 10:30:04 +0900 Subject: [PATCH 091/269] build(deps): bump git-repository from 0.26.0 to 0.29.0 (#5016) Bumps [git-repository](https://github.com/Byron/gitoxide) from 0.26.0 to 0.29.0. - [Release notes](https://github.com/Byron/gitoxide/releases) - [Changelog](https://github.com/Byron/gitoxide/blob/main/CHANGELOG.md) - [Commits](https://github.com/Byron/gitoxide/compare/git-repository-v0.26.0...git-repository-v0.29.0) --- updated-dependencies: - dependency-name: git-repository dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 132 +++++++++++++++++++++---------------------- helix-vcs/Cargo.toml | 2 +- 2 files changed, 67 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e0211972bb6..a3746f569abd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -551,9 +551,9 @@ dependencies = [ [[package]] name = "git-actor" -version = "0.13.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d4ce09c0a6c71c044700e5932877667f427f007b77e6c39ab49aebc4719e25" +checksum = "ac9fb99c934ed45a62d9ae1e7b21949f2d869d1b82a07dcbf16ed61daa665870" dependencies = [ "bstr 1.0.1", "btoi", @@ -565,9 +565,9 @@ dependencies = [ [[package]] name = "git-attributes" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c62e66a042c6b39c6dbfa3be37d134900d99ff9c54bbe489ed560a573895d5d" +checksum = "82e98446a2bf0eb5c8f29fa828d6529510a6fadeb59ce14ca98e58fa7e1e0199" dependencies = [ "bstr 1.0.1", "compact_str", @@ -581,36 +581,36 @@ dependencies = [ [[package]] name = "git-bitmap" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327098a7ad27ae298d7e71602dbd4375cc828d755d10a720e4be0be1b4ec38f0" +checksum = "44304093ac66a0ada1b243c15c3a503a165a1d0f50bec748f4e5a9b84a0d0722" dependencies = [ "quick-error", ] [[package]] name = "git-chunk" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b2bc1635b660ad6e30379a84a4946590a3c124b747107c2cca1d9dbb98f588" +checksum = "3090baa2f4a3fe488a9b3e31090b83259aaf930bf0634af34c18117274f8f1a8" dependencies = [ "thiserror", ] [[package]] name = "git-command" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e4b01997b6551554fdac6f02277d0d04c3e869daa649bedd06d38c86f11dc42" +checksum = "a6b98a6312fef79b326c0a6e15d576c2bd30f7f9d0b7964998d166049e0d7b9e" dependencies = [ "bstr 1.0.1", ] [[package]] name = "git-config" -version = "0.10.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd8603e953bd4c9bf310e74e43697400f5542f1cc75fad46fbd7427135a9534f" +checksum = "bd1d13179bcf3dd68e83404f91a8d01c618f54eb97ef36c68ee5e6f30183a681" dependencies = [ "bstr 1.0.1", "git-config-value", @@ -629,9 +629,9 @@ dependencies = [ [[package]] name = "git-config-value" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f276bfe5806b414915112f1eec0f006206cdf5b8cc9bbb44ef7e52286dc3eb" +checksum = "64561e9700f1fc737fa3c1c4ea55293be70dba98e45c54cf3715cb180f37a566" dependencies = [ "bitflags", "bstr 1.0.1", @@ -642,9 +642,9 @@ dependencies = [ [[package]] name = "git-credentials" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f540186ea56fd075ba2b923180ebf4318e66ceaeac0a2a518e75dab8517d339" +checksum = "621dd60288ae7b8f80bb0704f46d4d2b76fc1ec980a7804e48b02d94a927e331" dependencies = [ "bstr 1.0.1", "git-command", @@ -658,9 +658,9 @@ dependencies = [ [[package]] name = "git-date" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37881e9725df41e15d16216d3a0cee251fd8a39d425f75b389112df5c7f20f3d" +checksum = "e33db9f4462b565a33507aee113f3383bf16b988d2c573f07691e34302b7aa0a" dependencies = [ "bstr 1.0.1", "itoa", @@ -670,9 +670,9 @@ dependencies = [ [[package]] name = "git-diff" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a88666a0ae4365b55a0cbf2efde68d2a4cff0747894ad229403bd60b0b2abc5" +checksum = "82f77407381267be95f1b26acfb32007258af342ee61729bb4271b1869bf5bb2" dependencies = [ "git-hash", "git-object", @@ -682,9 +682,9 @@ dependencies = [ [[package]] name = "git-discover" -version = "0.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881e4136d5599cfdb79d8ef60d650823d1a563589fa493d8e4961e64d78a79f2" +checksum = "2c2cfd1272824b126c6997ef479a71288d00fae14dc5144dfc48658f4dd24fbe" dependencies = [ "bstr 1.0.1", "git-hash", @@ -696,9 +696,9 @@ dependencies = [ [[package]] name = "git-features" -version = "0.23.1" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be88ae837674c71b30c6517c6f5f1335f8135bb8a9ffef20000d211933bed08" +checksum = "d7bdbe755d2129bc609437b6b18af1116f146128dda6070c15c0aa50201ac17c" dependencies = [ "crc32fast", "flate2", @@ -713,9 +713,9 @@ dependencies = [ [[package]] name = "git-glob" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d756430237112f8c89049236f60fdcdb0005127b1f7e531d40984e4fe7daa90" +checksum = "ef858611602fce54b51e45671ca72f07fe6a3c0e24a0539c66b75dfd4d84bd77" dependencies = [ "bitflags", "bstr 1.0.1", @@ -723,9 +723,9 @@ dependencies = [ [[package]] name = "git-hash" -version = "0.9.11" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d46e6c2d1e8da4438a87bf516a6761b300964a353541fea61e96b3c7b34554" +checksum = "1532d82bf830532f8d545c5b7b568e311e3593f16cf7ee9dd0ce03c74b12b99d" dependencies = [ "hex", "thiserror", @@ -733,9 +733,9 @@ dependencies = [ [[package]] name = "git-index" -version = "0.7.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "821583c2d12b1e864694eb0bf1cca10ff6a3f45966f5f834e0f921b496dbe7cb" +checksum = "a87c32d2e012ee316d4037b2151e5893599379ff1fc2c6adb36d2d4d1c461e2c" dependencies = [ "atoi", "bitflags", @@ -755,9 +755,9 @@ dependencies = [ [[package]] name = "git-lock" -version = "2.2.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0fe10bf961f62b1335b4c07785e64fb4d86c5ed367dc7cd9360f13c3eb7c78" +checksum = "89e4f05b8a68c3a5dd83a6651c76be384e910fe283072184fdab9d77f87ccec2" dependencies = [ "fastrand", "git-tempfile", @@ -766,9 +766,9 @@ dependencies = [ [[package]] name = "git-mailmap" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb3f85ce84b2328aeb3124a809f7b3a63e59c4d63c227dba7a9cdf6fca6c0987" +checksum = "480eecdfaf1bfd05973678520d182dc07afa25b133db18c52575fb65b782b7ba" dependencies = [ "bstr 1.0.1", "git-actor", @@ -777,9 +777,9 @@ dependencies = [ [[package]] name = "git-object" -version = "0.22.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9469a8c00d8bb500ee76a12e455bb174b4ddf71674713335dd1a84313723f7b3" +checksum = "ce0f14f9cd8f0782e843898a2fb7b0c2f5a6e37bd4cdff4409bb8ec698597dad" dependencies = [ "bstr 1.0.1", "btoi", @@ -796,9 +796,9 @@ dependencies = [ [[package]] name = "git-odb" -version = "0.35.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaaea7031ac7d8dfee232a16d7114395d118226214fb03fe4e15d1f4d62a88a6" +checksum = "13493da6cf0326454215414d29f933a1e26bdba3b9b60ad8cdcbe06f0639584b" dependencies = [ "arc-swap", "git-features", @@ -814,9 +814,9 @@ dependencies = [ [[package]] name = "git-pack" -version = "0.25.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc4386dff835ffdc3697c3558111f708fd7b7695c42a4347f2d211cf3246c8e1" +checksum = "fa8391cbf293f0f8ffbb5e324f25741f5e1e2d35fb87b89ab222a025661e0454" dependencies = [ "bytesize", "clru", @@ -838,9 +838,9 @@ dependencies = [ [[package]] name = "git-path" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "425dc1022690be13e6c5bde4b7e04d9504d323605ec314cd367cebf38a812572" +checksum = "5f60cbc13bc0fdd95df5f4b80437197e2853116792894b1bf38d1a6b4a64f8c9" dependencies = [ "bstr 1.0.1", "thiserror", @@ -848,9 +848,9 @@ dependencies = [ [[package]] name = "git-prompt" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa6947935c0671342277bc883ff0687978477b570c1ffe2200b9ba5ac8afdd9f" +checksum = "21c6aaeb3f0f8de91f5e0eb950282c6508e05babcedef768db5a6f085d6e5242" dependencies = [ "git-command", "git-config-value", @@ -861,9 +861,9 @@ dependencies = [ [[package]] name = "git-quote" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea17931d07cbe447f371bbdf45ff03c30ea86db43788166655a5302df87ecfc" +checksum = "1dd11f4e7f251ab297545faa4c5a4517f4985a43b9c16bf96fa49107f58e837f" dependencies = [ "bstr 1.0.1", "btoi", @@ -872,9 +872,9 @@ dependencies = [ [[package]] name = "git-ref" -version = "0.18.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "638c9e454bacb2965a43f05b4a383c8f66dc64f3a770bd0324b221c2a20e121d" +checksum = "22484043921e699edc170415789f1b882c8f3546e1fbbc447a0043ef07e088c4" dependencies = [ "git-actor", "git-features", @@ -891,9 +891,9 @@ dependencies = [ [[package]] name = "git-refspec" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9497af773538ae8cfda053ff7dd0a9e6c28d333ba653040f54b8b4ee32f14187" +checksum = "ac2e8f36e7d5d48903b60051dfb75aedfc4ea9ba66bdffa7a9081e8d276b0107" dependencies = [ "bstr 1.0.1", "git-hash", @@ -905,9 +905,9 @@ dependencies = [ [[package]] name = "git-repository" -version = "0.26.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb43e59612e493af6a433bf0a960de0042c8aa6f4e4c4cb414f03b97e296b82" +checksum = "a89cec253dd3fba44694f7468d907506a52d0055850ecd7d84f4bac07f00e73f" dependencies = [ "byte-unit", "clru", @@ -948,9 +948,9 @@ dependencies = [ [[package]] name = "git-revision" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efd31c63c3745b5dba5ec7109eec41a9c717f4e1e797fe0ef93098f33f31b25" +checksum = "e629289b0d7f7f2f2e46248527f5cac838e6a7cb9507eab06fc8473082db6cb6" dependencies = [ "bstr 1.0.1", "git-date", @@ -962,9 +962,9 @@ dependencies = [ [[package]] name = "git-sec" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c79769f6546814d0774db7295c768441016b7e40bdd414fa8dfae2c616a1892" +checksum = "1ecb370efde58da72827909292284b5c5b885e0621a342515a36976b0b3bf660" dependencies = [ "bitflags", "dirs", @@ -975,9 +975,9 @@ dependencies = [ [[package]] name = "git-tempfile" -version = "2.0.6" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d23bc6129de3cbd81e6c9d0d685b5540c6b41bd9fa0cc38f381bc300743d708" +checksum = "a6bb4dee86c8cae5a078cfaac3b004ef99c31548ed86218f23a7ff9b4b74f3be" dependencies = [ "dashmap", "libc", @@ -989,9 +989,9 @@ dependencies = [ [[package]] name = "git-traverse" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d0c4dd773c69f294f43ace8373d48eb770129791f104c6857fa8cac0505af89" +checksum = "2d2746935c92d252e24f9d345e0a981510596faceb7edae821b9e4c8c35c285b" dependencies = [ "git-hash", "git-object", @@ -1001,9 +1001,9 @@ dependencies = [ [[package]] name = "git-url" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b7f8323196840e7932f5b60e1d9c1d6c140fd806bc512f8beedc3f990a1f81" +checksum = "7dbd91c55b1b03a833ff8278776fed272918cd61cd48efe9a97ad1fea7ef93ec" dependencies = [ "bstr 1.0.1", "git-features", @@ -1015,9 +1015,9 @@ dependencies = [ [[package]] name = "git-validate" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5439d6aa0de838dfadd74a71e97a9e23ebc719fd11a9ab6788b835b112c8c3d" +checksum = "cdf83bae632fc064ca938ebfb987364d9083b7f98b1476805f0a2d5eebb48686" dependencies = [ "bstr 1.0.1", "thiserror", @@ -1025,9 +1025,9 @@ dependencies = [ [[package]] name = "git-worktree" -version = "0.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45bcc69c36a29cfa283710b7901877ab251d658935f5a41ed824416af500e0ed" +checksum = "2eae0e0b1050208e611d5fac0d8366b29ef3f83849767ff9c4bcf570f0d5dc2b" dependencies = [ "bstr 1.0.1", "git-attributes", diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml index c114666d26d5..e54cf828f51b 100644 --- a/helix-vcs/Cargo.toml +++ b/helix-vcs/Cargo.toml @@ -16,7 +16,7 @@ helix-core = { version = "0.6", path = "../helix-core" } tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "parking_lot", "macros"] } parking_lot = "0.12" -git-repository = { version = "0.26", default-features = false , optional = true } +git-repository = { version = "0.29", default-features = false , optional = true } imara-diff = "0.1.5" log = "0.4" From 952f292d252bdc135f10b1ffa52734d5242d2c60 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Dec 2022 10:30:11 +0900 Subject: [PATCH 092/269] build(deps): bump serde from 1.0.148 to 1.0.149 (#5017) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.148 to 1.0.149. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.148...v1.0.149) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3746f569abd..014834e43349 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1804,18 +1804,18 @@ checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" [[package]] name = "serde" -version = "1.0.148" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc" +checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.148" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c" +checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4" dependencies = [ "proc-macro2", "quote", From 453a75a3739338348024b6c676231aef9ef6cb7b Mon Sep 17 00:00:00 2001 From: Narazaki Shuji Date: Tue, 6 Dec 2022 11:16:08 +0900 Subject: [PATCH 093/269] fix: align view after jumplist_picker (#3743) * Add `View::ensure_cursor_in_view_center` to adjust view after searching and jumping Also `offset_coodrs_to_in_view` was refactored to reduce duplicated position calculations. * Fix a wrong offset calculation in `offset_coords_to_in_view_center` It ignored `scrolloff` if `centering` is false. --- helix-term/src/commands.rs | 15 +++---- helix-view/src/view.rs | 89 +++++++++++++++++++++++++------------- 2 files changed, 67 insertions(+), 37 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 31a2f58274d1..263890269c41 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1667,12 +1667,7 @@ fn search_impl( }; doc.set_selection(view.id, selection); - // TODO: is_cursor_in_view does the same calculation as ensure_cursor_in_view - if view.is_cursor_in_view(doc, 0) { - view.ensure_cursor_in_view(doc, scrolloff); - } else { - align_view(doc, view, Align::Center) - } + view.ensure_cursor_in_view_center(doc, scrolloff); }; } @@ -2434,8 +2429,10 @@ fn jumplist_picker(cx: &mut Context) { (), |cx, meta, action| { cx.editor.switch(meta.id, action); + let config = cx.editor.config(); let (view, doc) = current!(cx.editor); doc.set_selection(view.id, meta.selection.clone()); + view.ensure_cursor_in_view_center(doc, config.scrolloff); }, |editor, meta| { let doc = &editor.documents.get(&meta.id)?; @@ -4205,6 +4202,7 @@ fn match_brackets(cx: &mut Context) { fn jump_forward(cx: &mut Context) { let count = cx.count(); + let config = cx.editor.config(); let view = view_mut!(cx.editor); let doc_id = view.doc; @@ -4218,12 +4216,13 @@ fn jump_forward(cx: &mut Context) { } doc.set_selection(view.id, selection); - align_view(doc, view, Align::Center); + view.ensure_cursor_in_view_center(doc, config.scrolloff); }; } fn jump_backward(cx: &mut Context) { let count = cx.count(); + let config = cx.editor.config(); let (view, doc) = current!(cx.editor); let doc_id = doc.id(); @@ -4237,7 +4236,7 @@ fn jump_backward(cx: &mut Context) { } doc.set_selection(view.id, selection); - align_view(doc, view, Align::Center); + view.ensure_cursor_in_view_center(doc, config.scrolloff); }; } diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index ecc8e8beaa7b..c09d502dcaca 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -1,4 +1,4 @@ -use crate::{editor::GutterType, graphics::Rect, Document, DocumentId, ViewId}; +use crate::{align_view, editor::GutterType, graphics::Rect, Align, Document, DocumentId, ViewId}; use helix_core::{ pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection, Transaction, }; @@ -169,6 +169,15 @@ impl View { &self, doc: &Document, scrolloff: usize, + ) -> Option<(usize, usize)> { + self.offset_coords_to_in_view_center(doc, scrolloff, false) + } + + pub fn offset_coords_to_in_view_center( + &self, + doc: &Document, + scrolloff: usize, + centering: bool, ) -> Option<(usize, usize)> { let cursor = doc .selection(self.id) @@ -180,47 +189,69 @@ impl View { let inner_area = self.inner_area(doc); let last_line = (self.offset.row + inner_area.height as usize).saturating_sub(1); - - // - 1 so we have at least one gap in the middle. - // a height of 6 with padding of 3 on each side will keep shifting the view back and forth - // as we type - let scrolloff = scrolloff.min(inner_area.height.saturating_sub(1) as usize / 2); - let last_col = self.offset.col + inner_area.width.saturating_sub(1) as usize; - let row = if line > last_line.saturating_sub(scrolloff) { - // scroll down - self.offset.row + line - (last_line.saturating_sub(scrolloff)) - } else if line < self.offset.row + scrolloff { - // scroll up - line.saturating_sub(scrolloff) - } else { - self.offset.row + let new_offset = |scrolloff: usize| { + // - 1 so we have at least one gap in the middle. + // a height of 6 with padding of 3 on each side will keep shifting the view back and forth + // as we type + let scrolloff = scrolloff.min(inner_area.height.saturating_sub(1) as usize / 2); + + let row = if line > last_line.saturating_sub(scrolloff) { + // scroll down + self.offset.row + line - (last_line.saturating_sub(scrolloff)) + } else if line < self.offset.row + scrolloff { + // scroll up + line.saturating_sub(scrolloff) + } else { + self.offset.row + }; + + let col = if col > last_col.saturating_sub(scrolloff) { + // scroll right + self.offset.col + col - (last_col.saturating_sub(scrolloff)) + } else if col < self.offset.col + scrolloff { + // scroll left + col.saturating_sub(scrolloff) + } else { + self.offset.col + }; + (row, col) }; - - let col = if col > last_col.saturating_sub(scrolloff) { - // scroll right - self.offset.col + col - (last_col.saturating_sub(scrolloff)) - } else if col < self.offset.col + scrolloff { - // scroll left - col.saturating_sub(scrolloff) + let current_offset = (self.offset.row, self.offset.col); + if centering { + // return None if cursor is out of view + let offset = new_offset(0); + (offset == current_offset).then(|| { + if scrolloff == 0 { + offset + } else { + new_offset(scrolloff) + } + }) } else { - self.offset.col - }; - if row == self.offset.row && col == self.offset.col { - None - } else { - Some((row, col)) + // return None if cursor is in (view - scrolloff) + let offset = new_offset(scrolloff); + (offset != current_offset).then(|| offset) // TODO: use 'then_some' when 1.62 <= MSRV } } pub fn ensure_cursor_in_view(&mut self, doc: &Document, scrolloff: usize) { - if let Some((row, col)) = self.offset_coords_to_in_view(doc, scrolloff) { + if let Some((row, col)) = self.offset_coords_to_in_view_center(doc, scrolloff, false) { self.offset.row = row; self.offset.col = col; } } + pub fn ensure_cursor_in_view_center(&mut self, doc: &Document, scrolloff: usize) { + if let Some((row, col)) = self.offset_coords_to_in_view_center(doc, scrolloff, true) { + self.offset.row = row; + self.offset.col = col; + } else { + align_view(doc, self, Align::Center); + } + } + pub fn is_cursor_in_view(&mut self, doc: &Document, scrolloff: usize) -> bool { self.offset_coords_to_in_view(doc, scrolloff).is_none() } From af532147c97987d6170dc06a52aa3434ebf1b9d4 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Tue, 6 Dec 2022 15:18:33 +0100 Subject: [PATCH 094/269] Add command/keybinding to jump between hunks (#4650) * add command and keybding to jump to next/prev hunk * add textobject for change * Update helix-vcs/src/diff.rs Co-authored-by: Michael Davis * select entire hunk instead of first char * fix selection range Co-authored-by: Michael Davis --- book/src/keymap.md | 4 + book/src/usage.md | 1 + helix-term/src/commands.rs | 121 +++++++++++++++++++++++++++++++ helix-term/src/keymap/default.rs | 4 + helix-vcs/src/diff.rs | 81 +++++++++++++++++++++ 5 files changed, 211 insertions(+) diff --git a/book/src/keymap.md b/book/src/keymap.md index c3c09f4ca3b9..139e8fddf613 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -320,6 +320,10 @@ Mappings in the style of [vim-unimpaired](https://github.com/tpope/vim-unimpaire | `]T` | Go to previous test (**TS**) | `goto_prev_test` | | `]p` | Go to next paragraph | `goto_next_paragraph` | | `[p` | Go to previous paragraph | `goto_prev_paragraph` | +| `]g` | Go to next change | `goto_next_change` | +| `[g` | Go to previous change | `goto_prev_change` | +| `]G` | Go to first change | `goto_first_change` | +| `[G` | Go to last change | `goto_last_change` | | `[Space` | Add newline above | `add_newline_above` | | `]Space` | Add newline below | `add_newline_below` | diff --git a/book/src/usage.md b/book/src/usage.md index 646bf926d536..a6eb9ec1d4f1 100644 --- a/book/src/usage.md +++ b/book/src/usage.md @@ -143,6 +143,7 @@ though, we climb the syntax tree and then take the previous selection. So | `a` | Argument/parameter | | `o` | Comment | | `t` | Test | +| `g` | Change | > NOTE: `f`, `c`, etc need a tree-sitter grammar active for the current document and a special tree-sitter query file to work properly. [Only diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 263890269c41..1843e7a2be4e 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3,6 +3,7 @@ pub(crate) mod lsp; pub(crate) mod typed; pub use dap::*; +use helix_vcs::Hunk; pub use lsp::*; use tui::text::Spans; pub use typed::*; @@ -308,6 +309,10 @@ impl MappableCommand { goto_last_diag, "Goto last diagnostic", goto_next_diag, "Goto next diagnostic", goto_prev_diag, "Goto previous diagnostic", + goto_next_change, "Goto next change", + goto_prev_change, "Goto previous change", + goto_first_change, "Goto first change", + goto_last_change, "Goto last change", goto_line_start, "Goto line start", goto_line_end, "Goto line end", goto_next_buffer, "Goto next buffer", @@ -2912,6 +2917,100 @@ fn goto_prev_diag(cx: &mut Context) { goto_pos(editor, pos); } +fn goto_first_change(cx: &mut Context) { + goto_first_change_impl(cx, false); +} + +fn goto_last_change(cx: &mut Context) { + goto_first_change_impl(cx, true); +} + +fn goto_first_change_impl(cx: &mut Context, reverse: bool) { + let editor = &mut cx.editor; + let (_, doc) = current!(editor); + if let Some(handle) = doc.diff_handle() { + let hunk = { + let hunks = handle.hunks(); + let idx = if reverse { + hunks.len().saturating_sub(1) + } else { + 0 + }; + hunks.nth_hunk(idx) + }; + if hunk != Hunk::NONE { + let pos = doc.text().line_to_char(hunk.after.start as usize); + goto_pos(editor, pos) + } + } +} + +fn goto_next_change(cx: &mut Context) { + goto_next_change_impl(cx, Direction::Forward) +} + +fn goto_prev_change(cx: &mut Context) { + goto_next_change_impl(cx, Direction::Backward) +} + +fn goto_next_change_impl(cx: &mut Context, direction: Direction) { + let count = cx.count() as u32 - 1; + let motion = move |editor: &mut Editor| { + let (view, doc) = current!(editor); + let doc_text = doc.text().slice(..); + let diff_handle = if let Some(diff_handle) = doc.diff_handle() { + diff_handle + } else { + editor.set_status("Diff is not available in current buffer"); + return; + }; + + let selection = doc.selection(view.id).clone().transform(|range| { + let cursor_line = range.cursor_line(doc_text) as u32; + + let hunks = diff_handle.hunks(); + let hunk_idx = match direction { + Direction::Forward => hunks + .next_hunk(cursor_line) + .map(|idx| (idx + count).min(hunks.len() - 1)), + Direction::Backward => hunks + .prev_hunk(cursor_line) + .map(|idx| idx.saturating_sub(count)), + }; + // TODO refactor with let..else once MSRV reaches 1.65 + let hunk_idx = if let Some(hunk_idx) = hunk_idx { + hunk_idx + } else { + return range; + }; + let hunk = hunks.nth_hunk(hunk_idx); + + let hunk_start = doc_text.line_to_char(hunk.after.start as usize); + let hunk_end = if hunk.after.is_empty() { + hunk_start + 1 + } else { + doc_text.line_to_char(hunk.after.end as usize) + }; + let new_range = Range::new(hunk_start, hunk_end); + if editor.mode == Mode::Select { + let head = if new_range.head < range.anchor { + new_range.anchor + } else { + new_range.head + }; + + Range::new(range.anchor, head) + } else { + new_range.with_direction(direction) + } + }); + + doc.set_selection(view.id, selection) + }; + motion(cx.editor); + cx.editor.last_motion = Some(Motion(Box::new(motion))); +} + pub mod insert { use super::*; pub type Hook = fn(&Rope, &Selection, char) -> Option; @@ -4515,6 +4614,27 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) { ) }; + if ch == 'g' && doc.diff_handle().is_none() { + editor.set_status("Diff is not available in current buffer"); + return; + } + + let textobject_change = |range: Range| -> Range { + let diff_handle = doc.diff_handle().unwrap(); + let hunks = diff_handle.hunks(); + let line = range.cursor_line(text); + let hunk_idx = if let Some(hunk_idx) = hunks.hunk_at(line as u32, false) { + hunk_idx + } else { + return range; + }; + let hunk = hunks.nth_hunk(hunk_idx).after; + + let start = text.line_to_char(hunk.start as usize); + let end = text.line_to_char(hunk.end as usize); + Range::new(start, end).with_direction(range.direction()) + }; + let selection = doc.selection(view.id).clone().transform(|range| { match ch { 'w' => textobject::textobject_word(text, range, objtype, count, false), @@ -4528,6 +4648,7 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) { 'm' => textobject::textobject_pair_surround_closest( text, range, objtype, count, ), + 'g' => textobject_change(range), // TODO: cancel new ranges if inconsistent surround matches across lines ch if !ch.is_ascii_alphanumeric() => { textobject::textobject_pair_surround(text, range, objtype, ch, count) diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index b6d9ea1088c2..ebcd125aa129 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -100,6 +100,8 @@ pub fn default() -> HashMap { "[" => { "Left bracket" "d" => goto_prev_diag, "D" => goto_first_diag, + "g" => goto_prev_change, + "G" => goto_first_change, "f" => goto_prev_function, "t" => goto_prev_class, "a" => goto_prev_parameter, @@ -111,6 +113,8 @@ pub fn default() -> HashMap { "]" => { "Right bracket" "d" => goto_next_diag, "D" => goto_last_diag, + "g" => goto_next_change, + "G" => goto_last_change, "f" => goto_next_function, "t" => goto_next_class, "a" => goto_next_parameter, diff --git a/helix-vcs/src/diff.rs b/helix-vcs/src/diff.rs index b1acd1f29937..9c6a362f7db8 100644 --- a/helix-vcs/src/diff.rs +++ b/helix-vcs/src/diff.rs @@ -195,4 +195,85 @@ impl FileHunks<'_> { pub fn is_empty(&self) -> bool { self.len() == 0 } + + pub fn next_hunk(&self, line: u32) -> Option { + let hunk_range = if self.inverted { + |hunk: &Hunk| hunk.before.clone() + } else { + |hunk: &Hunk| hunk.after.clone() + }; + + let res = self + .hunks + .binary_search_by_key(&line, |hunk| hunk_range(hunk).start); + + match res { + // Search found a hunk that starts exactly at this line, return the next hunk if it exists. + Ok(pos) if pos + 1 == self.hunks.len() => None, + Ok(pos) => Some(pos as u32 + 1), + + // No hunk starts exactly at this line, so the search returns + // the position where a hunk starting at this line should be inserted. + // That position is exactly the position of the next hunk or the end + // of the list if no such hunk exists + Err(pos) if pos == self.hunks.len() => None, + Err(pos) => Some(pos as u32), + } + } + + pub fn prev_hunk(&self, line: u32) -> Option { + let hunk_range = if self.inverted { + |hunk: &Hunk| hunk.before.clone() + } else { + |hunk: &Hunk| hunk.after.clone() + }; + let res = self + .hunks + .binary_search_by_key(&line, |hunk| hunk_range(hunk).end); + + match res { + // Search found a hunk that ends exactly at this line (so it does not include the current line). + // We can usually just return that hunk, however a special case for empty hunk is necessary + // which represents a pure removal. + // Removals are technically empty but are still shown as single line hunks + // and as such we must jump to the previous hunk (if it exists) if we are already inside the removal + Ok(pos) if !hunk_range(&self.hunks[pos]).is_empty() => Some(pos as u32), + + // No hunk ends exactly at this line, so the search returns + // the position where a hunk ending at this line should be inserted. + // That position before this one is exactly the position of the previous hunk + Err(0) | Ok(0) => None, + Err(pos) | Ok(pos) => Some(pos as u32 - 1), + } + } + + pub fn hunk_at(&self, line: u32, include_removal: bool) -> Option { + let hunk_range = if self.inverted { + |hunk: &Hunk| hunk.before.clone() + } else { + |hunk: &Hunk| hunk.after.clone() + }; + + let res = self + .hunks + .binary_search_by_key(&line, |hunk| hunk_range(hunk).start); + + match res { + // Search found a hunk that starts exactly at this line, return it + Ok(pos) => Some(pos as u32), + + // No hunk starts exactly at this line, so the search returns + // the position where a hunk starting at this line should be inserted. + // The previous hunk contains this hunk if it exists and doesn't end before this line + Err(0) => None, + Err(pos) => { + let hunk = hunk_range(&self.hunks[pos - 1]); + if hunk.end > line || include_removal && hunk.start == line && hunk.is_empty() { + Some(pos as u32 - 1) + } else { + None + } + } + } + } } From e9d43c284bb717e3de5aec7312d985a088ede7ea Mon Sep 17 00:00:00 2001 From: Kristoffer Flottorp <2630397+krfl@users.noreply.github.com> Date: Wed, 7 Dec 2022 02:08:34 +0100 Subject: [PATCH 095/269] Fleetish theme renamed to fleet dark and adjusted to match official theme. (#4997) * remove fleetish.toml * add fleet_dark.toml * adjust colors for tags and markup lists * Add type.enum.variant * correct color for focused elements * adjust builtins and keywords Co-authored-by: krfl --- .../themes/{fleetish.toml => fleet_dark.toml} | 93 ++++++++++--------- 1 file changed, 51 insertions(+), 42 deletions(-) rename runtime/themes/{fleetish.toml => fleet_dark.toml} (52%) diff --git a/runtime/themes/fleetish.toml b/runtime/themes/fleet_dark.toml similarity index 52% rename from runtime/themes/fleetish.toml rename to runtime/themes/fleet_dark.toml index 159daf8785d0..f885e4eb6542 100644 --- a/runtime/themes/fleetish.toml +++ b/runtime/themes/fleet_dark.toml @@ -1,8 +1,13 @@ -# Author: Kristoffer Flottorp -# A take on the JetBrains Fleet theme sprinkled with some creative freedom +# Fleet Dark +# A take on the JetBrains Fleet theme. Feel free to contribute +# Original author: @krfl +# Contributors: +# @matoous + +"attribute" = "green" "type" = "light_blue" -"type.builtin" = "orange" +"type.enum.variant" = "purple" "constructor" = "yellow" "constant" = "cyan" # "constant.builtin" = {} # .boolean @@ -16,55 +21,55 @@ "comment" = "light_gray" # .line # "comment.block" = {} # .documentation "variable" = "light" # .builtin +"variable.builtin" = { fg = "red", modifiers = ["underlined"] } "variable.parameter" = "light" # "variable.other" = {} # .member -"variable.other.member" = "yellow" +"variable.other.member" = "purple" "label" = "yellow" "punctuation" = "light" # .delimiter / .bracket "keyword" = "cyan" # .operator / .directive / .function -"keyword.control" = "yellow" # .conditional / .repeat / .import / .return / .exception +# "keyword.control" = "cyan" # .conditional / .repeat / .import / .return / .exception +"keyword.control.exception" = "purple" "operator" = "light" "function" = "yellow" "function.macro" = "green" "function.builtin" = "green" "function.special" = "green" "function.method" = "light" -"tag" = "green" +#"function.declaration.method" = { fg = "lightest", modifiers = ["bold"] } #depends on #4892 +"tag" = "light_blue" "special" = "green" "namespace" = "light" # used in theming +# "markup" = {} # .normal / .quote / .raw # "markup.normal" = {} # .completion / .hover -# "markup.raw.inline" = {} # .completion / .hover -"markup" = "purple" # .quote -"markup.bold" = { fg = "purple", modifiers = ["bold"] } -"markup.italic" = { fg = "purple", modifiers = ["italic"] } -"markup.heading" = "light" # .marker -"markup.heading.1" = "yellow" -"markup.heading.2" = "green" -"markup.heading.3" = "pink" -"markup.heading.4" = "purple" -"markup.heading.5" = "cyan" -"markup.heading.6" = "light_blue" -"markup.list" = "cyan" # .unnumbered / .numbered -"markup.link" = "green" -"markup.link.url" = "pink" +"markup.bold" = { fg = "lightest", modifiers = ["bold"] } +"markup.italic" = { modifiers = ["italic"] } +"markup.heading" = { fg = "cyan", modifiers = ["bold"] } # .marker / .1 / .2 / .3 / .4 / .5 / .6 +"markup.list" = "pink" # .unnumbered / .numbered +"markup.list.numbered" = "cyan" +"markup.list.unnumbered" = "cyan" +# "markup.link" = "green" +"markup.link.url" = { fg = "pink", modifiers = ['italic', 'underlined'] } "markup.link.text" = "cyan" -"markup.link.label" = "yellow" -"markup.raw" = "pink" # .inline -"markup.raw.block" = "orange" +"markup.link.label" = "purple" +"markup.quote" = "pink" +"markup.raw" = "pink" +"markup.raw.inline" = "cyan" # .completion / .hover +"markup.raw.block" = "pink" -"diff.plus" = "cyan" -"diff.minus" = "yellow" -"diff.delta" = "purple" +"diff.plus" = "diff_plus" +"diff.minus" = "red_accent" +"diff.delta" = "blue_accent" # ui specific -"ui.background" = { bg = "#0d0d0d" } # .separator +"ui.background" = { bg = "background" } # .separator "ui.cursor" = { bg = "dark_gray", modifiers = ["reversed"] } # .insert / .select / .match / .primary -"ui.cursor.match" = { fg = "light", bg = "blue_accent" } # .insert / .select / .match / .primary +"ui.cursor.match" = { fg = "light", bg = "selection" } # .insert / .select / .match / .primary "ui.cursorline" = { bg = "darker" } "ui.linenr" = "dark_gray" -"ui.linenr.selected" = { fg = "light_gray", bg = "darker" } +"ui.linenr.selected" = { fg = "light", bg = "darker" } "ui.statusline" = { fg = "light", bg = "darker" } # .inactive / .normal / .insert / .select "ui.statusline.inactive" = { fg = "dark", bg = "darker" } "ui.statusline.normal" = { fg = "lightest", bg = "darker"} @@ -74,27 +79,28 @@ "ui.window" = { fg = "dark", bg = "darkest" } "ui.help" = { fg = "light", bg = "darkest" } "ui.text" = "light" # .focus / .info +"ui.text.focus" = { fg = "lightest", bg = "focus" } "ui.virtual" = "dark" # .whitespace "ui.virtual.ruler" = { bg = "darker"} -"ui.menu" = { fg = "light", bg = "darker" } # .selected -"ui.menu.selected" = { fg = "lightest", bg = "blue_accent" } # .selected +"ui.menu" = { fg = "light", bg = "darkest" } # .selected +"ui.menu.selected" = { fg = "lightest", bg = "focus" } # .selected "ui.selection" = { bg = "darker" } # .primary -"ui.selection.primary" = { bg = "select" } # .primary +"ui.selection.primary" = { bg = "selection" } "hint" = "blue" "info" = "yellow_accent" "warning" = "orange_accent" -"error" = "red" +"error" = "red_error" "diagnostic" = { modifiers = [] } -"diagnostic.hint" = { underline = { color = "light", style = "curl" } } -"diagnostic.info" = { underline = { color = "blue", style = "curl" } } -"diagnostic.warning" = { underline = { color = "yellow", style = "curl" } } -"diagnostic.error" = { underline = { color = "red", style = "curl" } } +"diagnostic.hint" = { underline = { color = "light", style = "line" } } +"diagnostic.info" = { underline = { color = "blue_accent", style = "line" } } +"diagnostic.warning" = { underline = { color = "yellow_accent", style = "line" } } +"diagnostic.error" = { underline = { color = "red_error", style = "line" } } [palette] +background = "#181818" darkest = "#1e1e1e" -darker = "#262626" +darker = "#292929" dark = "#898989" -select = "#102f5b" light = "#d6d6dd" lightest = "#ffffff" @@ -109,13 +115,16 @@ green = "#afcb85" cyan = "#78d0bd" orange = "#efb080" yellow = "#e5c995" -red = "#f44747" +red = "#CC7C8A" blue_accent = "#2197F3" pink_accent = "#E44C7A" green_accent = "#00AF99" orange_accent = "#EE7F25" yellow_accent = "#DEA407" +red_accent = "#F44747" -# variables intended for future updates -checkmark = "#44B254" +red_error = "#EB5F6A" +selection = "#1F3661" +diff_plus = "#5A9F81" +focus = "#204474" From d3f670c0e2d8800bfeacb76a5b96753ac6529170 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Wed, 7 Dec 2022 10:11:45 +0800 Subject: [PATCH 096/269] Use OSC 52 for tmux copy (#5027) --- helix-view/src/clipboard.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-view/src/clipboard.rs b/helix-view/src/clipboard.rs index 19fade69c7b6..4f83fb4dc693 100644 --- a/helix-view/src/clipboard.rs +++ b/helix-view/src/clipboard.rs @@ -136,7 +136,7 @@ pub fn get_clipboard_provider() -> Box { } else if env_var_is_set("TMUX") && binary_exists("tmux") { command_provider! { paste => "tmux", "save-buffer", "-"; - copy => "tmux", "load-buffer", "-"; + copy => "tmux", "load-buffer", "-w", "-"; } } else { Box::new(provider::FallbackProvider::new()) From 96ff64a84a4948b0aa85a453276cb0091fb9c792 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 6 Dec 2022 20:54:50 -0600 Subject: [PATCH 097/269] Add changelog notes for 22.12 (#4822) * Add changelog notes for 22.12 * Bump VERSION to 22.12 --- CHANGELOG.md | 286 +++++++++++++++++++++++++++++++++++++++++++++++++++ VERSION | 2 +- 2 files changed, 287 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56d85751b940..dc91c9ff33a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,289 @@ +# 22.12 (2022-12-06) + +This is a great big release filled with changes from a 99 contributors. A big _thank you_ to you all! + +As usual, the following is a summary of each of the changes since the last release. +For the full log, check out the [git log](https://github.com/helix-editor/helix/compare/22.08.1..22.12). + +Breaking changes: + +- Remove readline-like navigation bindings from the default insert mode keymap ([e12690e](https://github.com/helix-editor/helix/commit/e12690e), [#3811](https://github.com/helix-editor/helix/pull/3811), [#3827](https://github.com/helix-editor/helix/pull/3827), [#3915](https://github.com/helix-editor/helix/pull/3915), [#4088](https://github.com/helix-editor/helix/pull/4088)) +- Rename `append_to_line` as `insert_at_line_end` and `prepend_to_line` as `insert_at_line_start` ([#3753](https://github.com/helix-editor/helix/pull/3753)) +- Swap diagnostic picker and debug mode bindings in the space keymap ([#4229](https://github.com/helix-editor/helix/pull/4229)) +- Select newly inserted text on paste or from shell commands ([#4458](https://github.com/helix-editor/helix/pull/4458), [#4608](https://github.com/helix-editor/helix/pull/4608), [#4619](https://github.com/helix-editor/helix/pull/4619), [#4824](https://github.com/helix-editor/helix/pull/4824)) +- Select newly inserted surrounding characters on `ms` ([#4752](https://github.com/helix-editor/helix/pull/4752)) +- Exit select-mode after executing `replace_*` commands ([#4554](https://github.com/helix-editor/helix/pull/4554)) +- Exit select-mode after executing surround commands ([#4858](https://github.com/helix-editor/helix/pull/4858)) +- Change tree-sitter text-object keys ([#3782](https://github.com/helix-editor/helix/pull/3782)) +- Rename `fleetish` theme to `fleet_dark` ([#4997](https://github.com/helix-editor/helix/pull/4997)) + +Features: + +- Bufferline ([#2759](https://github.com/helix-editor/helix/pull/2759)) +- Support underline styles and colors ([#4061](https://github.com/helix-editor/helix/pull/4061), [98c121c](https://github.com/helix-editor/helix/commit/98c121c)) +- Inheritance for themes ([#3067](https://github.com/helix-editor/helix/pull/3067), [#4096](https://github.com/helix-editor/helix/pull/4096)) +- Cursorcolumn ([#4084](https://github.com/helix-editor/helix/pull/4084)) +- Overhauled system for writing files and quiting ([#2267](https://github.com/helix-editor/helix/pull/2267), [#4397](https://github.com/helix-editor/helix/pull/4397)) +- Autosave when terminal loses focus ([#3178](https://github.com/helix-editor/helix/pull/3178)) +- Use OSC52 as a fallback for the system clipboard ([#3220](https://github.com/helix-editor/helix/pull/3220)) +- Show git diffs in the gutter ([#3890](https://github.com/helix-editor/helix/pull/3890), [#5012](https://github.com/helix-editor/helix/pull/5012), [#4995](https://github.com/helix-editor/helix/pull/4995)) +- Add a logo ([dc1ec56](https://github.com/helix-editor/helix/commit/dc1ec56)) +- Multi-cursor completion ([#4496](https://github.com/helix-editor/helix/pull/4496)) + +Commands: + +- `file_picker_in_current_directory` (`F`) ([#3701](https://github.com/helix-editor/helix/pull/3701)) +- `:lsp-restart` to restart the current document's language server ([#3435](https://github.com/helix-editor/helix/pull/3435), [#3972](https://github.com/helix-editor/helix/pull/3972)) +- `join_selections_space` (`A-j`) which joins selections and selects the joining whitespace ([#3549](https://github.com/helix-editor/helix/pull/3549)) +- `:update` to write the current file if it is modified ([#4426](https://github.com/helix-editor/helix/pull/4426)) +- `:lsp-workspace-command` for picking LSP commands to execute ([#3140](https://github.com/helix-editor/helix/pull/3140)) +- `extend_prev_word_end` - the extend variant for `move_prev_word_end` ([7468fa2](https://github.com/helix-editor/helix/commit/7468fa2)) +- `make_search_word_bounded` which adds regex word boundaries to the current search register value ([#4322](https://github.com/helix-editor/helix/pull/4322)) +- `:reload-all` - `:reload` for all open buffers ([#4663](https://github.com/helix-editor/helix/pull/4663), [#4901](https://github.com/helix-editor/helix/pull/4901)) +- `goto_next_change` (`]g`), `goto_prev_change` (`[g`), `goto_first_change` (`[G`), `goto_last_change` (`]G`) textobjects for jumping between VCS changes ([#4650](https://github.com/helix-editor/helix/pull/4650)) + +Usability improvements and fixes: + +- Don't log 'LSP not defined' errors in the logfile ([1caba2d](https://github.com/helix-editor/helix/commit/1caba2d)) +- Look for the external formatter program before invoking it ([#3670](https://github.com/helix-editor/helix/pull/3670)) +- Don't send LSP didOpen events for documents without URLs ([44b4479](https://github.com/helix-editor/helix/commit/44b4479)) +- Fix off-by-one in `extend_line_above` command ([#3689](https://github.com/helix-editor/helix/pull/3689)) +- Use the original scroll offset when opening a split ([1acdfaa](https://github.com/helix-editor/helix/commit/1acdfaa)) +- Handle auto-formatting failures and save the file anyway ([#3684](https://github.com/helix-editor/helix/pull/3684)) +- Ensure the cursor is in view after `:reflow` ([#3733](https://github.com/helix-editor/helix/pull/3733)) +- Add default rulers and reflow config for git commit messages ([#3738](https://github.com/helix-editor/helix/pull/3738)) +- Improve grammar fetching and building output ([#3773](https://github.com/helix-editor/helix/pull/3773)) +- Add a `text` language to language completion ([cc47d3f](https://github.com/helix-editor/helix/commit/cc47d3f)) +- Improve error handling for `:set-language` ([e8add6f](https://github.com/helix-editor/helix/commit/e8add6f)) +- Improve error handling for `:config-reload` ([#3668](https://github.com/helix-editor/helix/pull/3668)) +- Improve error handling when passing improper ranges to syntax highlighting ([#3826](https://github.com/helix-editor/helix/pull/3826)) +- Render `` tags as raw markup in markdown ([#3425](https://github.com/helix-editor/helix/pull/3425)) +- Remove border around the LSP code-actions popup ([#3444](https://github.com/helix-editor/helix/pull/3444)) +- Canonicalize the path to the runtime directory ([#3794](https://github.com/helix-editor/helix/pull/3794)) +- Add a `themelint` xtask for linting themes ([#3234](https://github.com/helix-editor/helix/pull/3234)) +- Re-sort LSP diagnostics after applying transactions ([#3895](https://github.com/helix-editor/helix/pull/3895), [#4319](https://github.com/helix-editor/helix/pull/4319)) +- Add a command-line flag to specify the log file ([#3807](https://github.com/helix-editor/helix/pull/3807)) +- Track source and tag information in LSP diagnostics ([#3898](https://github.com/helix-editor/helix/pull/3898), [1df32c9](https://github.com/helix-editor/helix/commit/1df32c9)) +- Fix theme returning to normal when exiting the `:theme` completion ([#3644](https://github.com/helix-editor/helix/pull/3644)) +- Improve error messages for invalid commands in the keymap ([#3931](https://github.com/helix-editor/helix/pull/3931)) +- Deduplicate regexs in `search_selection` command ([#3941](https://github.com/helix-editor/helix/pull/3941)) +- Split the finding of LSP root and config roots ([#3929](https://github.com/helix-editor/helix/pull/3929)) +- Ensure that the cursor is within view after auto-formatting ([#4047](https://github.com/helix-editor/helix/pull/4047)) +- Add pseudo-pending to commands with on-next-key callbacks ([#4062](https://github.com/helix-editor/helix/pull/4062), [#4077](https://github.com/helix-editor/helix/pull/4077)) +- Add live preview to `:goto` ([#2982](https://github.com/helix-editor/helix/pull/2982)) +- Show regex compilation failure in a popup ([#3049](https://github.com/helix-editor/helix/pull/3049)) +- Add 'cycled to end' and 'no more matches' for search ([#3176](https://github.com/helix-editor/helix/pull/3176), [#4101](https://github.com/helix-editor/helix/pull/4101)) +- Add extending behavior to tree-sitter textobjects ([#3266](https://github.com/helix-editor/helix/pull/3266)) +- Add `ui.gutter.selected` option for themes ([#3303](https://github.com/helix-editor/helix/pull/3303)) +- Make statusline mode names configurable ([#3311](https://github.com/helix-editor/helix/pull/3311)) +- Add a statusline element for total line count ([#3960](https://github.com/helix-editor/helix/pull/3960)) +- Add extending behavior to `goto_window_*` commands ([#3985](https://github.com/helix-editor/helix/pull/3985)) +- Fix a panic in signature help when the preview is too large ([#4030](https://github.com/helix-editor/helix/pull/4030)) +- Add command names to the command palette ([#4071](https://github.com/helix-editor/helix/pull/4071), [#4223](https://github.com/helix-editor/helix/pull/4223), [#4495](https://github.com/helix-editor/helix/pull/4495)) +- Find the LSP workspace root from the current document's path ([#3553](https://github.com/helix-editor/helix/pull/3553)) +- Add an option to skip indent-guide levels ([#3819](https://github.com/helix-editor/helix/pull/3819), [2c36e33](https://github.com/helix-editor/helix/commit/2c36e33)) +- Change focus to modified docs on quit ([#3872](https://github.com/helix-editor/helix/pull/3872)) +- Respond to `USR1` signal by reloading config ([#3952](https://github.com/helix-editor/helix/pull/3952)) +- Exit gracefully when the close operation fails ([#4081](https://github.com/helix-editor/helix/pull/4081)) +- Fix goto/view center mismatch ([#4135](https://github.com/helix-editor/helix/pull/4135)) +- Highlight the current file picker document on idle-timeout ([#3172](https://github.com/helix-editor/helix/pull/3172), [a85e386](https://github.com/helix-editor/helix/commit/a85e386)) +- Apply transactions to jumplist selections ([#4186](https://github.com/helix-editor/helix/pull/4186), [#4227](https://github.com/helix-editor/helix/pull/4227), [#4733](https://github.com/helix-editor/helix/pull/4733), [#4865](https://github.com/helix-editor/helix/pull/4865), [#4912](https://github.com/helix-editor/helix/pull/4912), [#4965](https://github.com/helix-editor/helix/pull/4965), [#4981](https://github.com/helix-editor/helix/pull/4981)) +- Use space as a separator for fuzzy matcher ([#3969](https://github.com/helix-editor/helix/pull/3969)) +- Overlay all diagnostics with highest severity on top ([#4113](https://github.com/helix-editor/helix/pull/4113)) +- Avoid re-parsing unmodified tree-sitter injections ([#4146](https://github.com/helix-editor/helix/pull/4146)) +- Add extending captures for indentation, re-enable python indentation ([#3382](https://github.com/helix-editor/helix/pull/3382), [3e84434](https://github.com/helix-editor/helix/commit/3e84434)) +- Only allow either `--vsplit` or `--hsplit` CLI flags at once ([#4202](https://github.com/helix-editor/helix/pull/4202)) +- Fix append cursor location when selection anchor is at the end of the document ([#4147](https://github.com/helix-editor/helix/pull/4147)) +- Improve selection yanking message ([#4275](https://github.com/helix-editor/helix/pull/4275)) +- Log failures to load tree-sitter grammars as errors ([#4315](https://github.com/helix-editor/helix/pull/4315)) +- Fix rendering of lines longer than 65,536 columns ([#4172](https://github.com/helix-editor/helix/pull/4172)) +- Skip searching `.git` in `global_search` ([#4334](https://github.com/helix-editor/helix/pull/4334)) +- Display tree-sitter scopes in a popup ([#4337](https://github.com/helix-editor/helix/pull/4337)) +- Fix deleting a word from the end of the buffer ([#4328](https://github.com/helix-editor/helix/pull/4328)) +- Pretty print the syntax tree in `:tree-sitter-subtree` ([#4295](https://github.com/helix-editor/helix/pull/4295), [#4606](https://github.com/helix-editor/helix/pull/4606)) +- Allow specifying suffixes for file-type detection ([#2455](https://github.com/helix-editor/helix/pull/2455), [#4414](https://github.com/helix-editor/helix/pull/4414)) +- Fix multi-byte auto-pairs ([#4024](https://github.com/helix-editor/helix/pull/4024)) +- Improve sort scoring for LSP code-actions and completions ([#4134](https://github.com/helix-editor/helix/pull/4134)) +- Fix the handling of quotes within shellwords ([#4098](https://github.com/helix-editor/helix/pull/4098)) +- Fix `delete_word_backward` and `delete_word_forward` on newlines ([#4392](https://github.com/helix-editor/helix/pull/4392)) +- Fix 'no entry found for key' crash on `:write-all` ([#4384](https://github.com/helix-editor/helix/pull/4384)) +- Remove lowercase requirement for tree-sitter grammars ([#4346](https://github.com/helix-editor/helix/pull/4346)) +- Resolve LSP completion items on idle-timeout ([#4406](https://github.com/helix-editor/helix/pull/4406), [#4797](https://github.com/helix-editor/helix/pull/4797)) +- Render diagnostics in the file picker preview ([#4324](https://github.com/helix-editor/helix/pull/4324)) +- Fix terminal freezing on `shell_insert_output` ([#4156](https://github.com/helix-editor/helix/pull/4156)) +- Allow use of the count in the repeat operator (`.`) ([#4450](https://github.com/helix-editor/helix/pull/4450)) +- Show the current theme name on `:theme` with no arguments ([#3740](https://github.com/helix-editor/helix/pull/3740)) +- Fix rendering in very large terminals ([#4318](https://github.com/helix-editor/helix/pull/4318)) +- Sort LSP preselected items to the top of the completion menu ([#4480](https://github.com/helix-editor/helix/pull/4480)) +- Trim braces and quotes from paths in goto-file ([#4370](https://github.com/helix-editor/helix/pull/4370)) +- Prevent automatic signature help outside of insert mode ([#4456](https://github.com/helix-editor/helix/pull/4456)) +- Fix freezes with external programs that process stdin and stdout concurrently ([#4180](https://github.com/helix-editor/helix/pull/4180)) +- Make `scroll` aware of tabs and wide characters ([#4519](https://github.com/helix-editor/helix/pull/4519)) +- Correctly handle escaping in `command_mode` completion ([#4316](https://github.com/helix-editor/helix/pull/4316), [#4587](https://github.com/helix-editor/helix/pull/4587), [#4632](https://github.com/helix-editor/helix/pull/4632)) +- Fix `delete_char_backward` for paired characters ([#4558](https://github.com/helix-editor/helix/pull/4558)) +- Fix crash from two windows editing the same document ([#4570](https://github.com/helix-editor/helix/pull/4570)) +- Fix pasting from the blackhole register ([#4497](https://github.com/helix-editor/helix/pull/4497)) +- Support LSP insertReplace completion items ([1312682](https://github.com/helix-editor/helix/commit/1312682)) +- Dynamically resize the line number gutter width ([#3469](https://github.com/helix-editor/helix/pull/3469)) +- Fix crash for unknown completion item kinds ([#4658](https://github.com/helix-editor/helix/pull/4658)) +- Re-enable `format_selections` for single selection ranges ([d4f5cab](https://github.com/helix-editor/helix/commit/d4f5cab)) +- Limit the number of in-progress tree-sitter query matches ([#4707](https://github.com/helix-editor/helix/pull/4707), [#4830](https://github.com/helix-editor/helix/pull/4830)) +- Use the special `#` register with `increment`/`decrement` to change by range number ([#4418](https://github.com/helix-editor/helix/pull/4418)) +- Add a statusline element to show number of selected chars ([#4682](https://github.com/helix-editor/helix/pull/4682)) +- Add a statusline element showing global LSP diagnostic warning and error counts ([#4569](https://github.com/helix-editor/helix/pull/4569)) +- Add a scrollbar to popups ([#4449](https://github.com/helix-editor/helix/pull/4449)) +- Prefer shorter matches in fuzzy matcher scoring ([#4698](https://github.com/helix-editor/helix/pull/4698)) +- Use key-sequence format for command palette keybinds ([#4712](https://github.com/helix-editor/helix/pull/4712)) +- Remove prefix filtering from autocompletion menu ([#4578](https://github.com/helix-editor/helix/pull/4578)) +- Focus on the parent buffer when closing a split ([#4766](https://github.com/helix-editor/helix/pull/4766)) +- Handle language server termination ([#4797](https://github.com/helix-editor/helix/pull/4797), [#4852](https://github.com/helix-editor/helix/pull/4852)) +- Allow `r`/`t`/`f` to work on tab characters ([#4817](https://github.com/helix-editor/helix/pull/4817)) +- Show a preview for scratch buffers in the buffer picker ([#3454](https://github.com/helix-editor/helix/pull/3454)) +- Set a limit of entries in the jumplist ([#4750](https://github.com/helix-editor/helix/pull/4750)) +- Re-use shell outputs when inserting or appending shell output ([#3465](https://github.com/helix-editor/helix/pull/3465)) +- Check LSP server provider capabilities ([#3554](https://github.com/helix-editor/helix/pull/3554)) +- Improve tree-sitter parsing performance on files with many language layers ([#4716](https://github.com/helix-editor/helix/pull/4716)) +- Move indentation to the next line when using `` on a line with only whitespace ([#4854](https://github.com/helix-editor/helix/pull/4854)) +- Remove selections for closed views from all documents ([#4888](https://github.com/helix-editor/helix/pull/4888)) +- Improve performance of the `:reload` command ([#4457](https://github.com/helix-editor/helix/pull/4457)) +- Properly handle media keys ([#4887](https://github.com/helix-editor/helix/pull/4887)) +- Support LSP diagnostic data field ([#4935](https://github.com/helix-editor/helix/pull/4935)) +- Handle C-i keycode as tab ([#4961](https://github.com/helix-editor/helix/pull/4961)) +- Fix view alignment for jumplist picker jumps ([#3743](https://github.com/helix-editor/helix/pull/3743)) +- Use OSC52 for tmux clipboard provider ([#5027](https://github.com/helix-editor/helix/pull/5027)) + +Themes: + +- Add `varua` ([#3610](https://github.com/helix-editor/helix/pull/3610), [#4964](https://github.com/helix-editor/helix/pull/4964)) +- Update `boo_berry` ([#3653](https://github.com/helix-editor/helix/pull/3653)) +- Add `rasmus` ([#3728](https://github.com/helix-editor/helix/pull/3728)) +- Add `papercolor_dark` ([#3742](https://github.com/helix-editor/helix/pull/3742)) +- Update `monokai_pro_spectrum` ([#3814](https://github.com/helix-editor/helix/pull/3814)) +- Update `nord` ([#3792](https://github.com/helix-editor/helix/pull/3792)) +- Update `fleetish` ([#3844](https://github.com/helix-editor/helix/pull/3844), [#4487](https://github.com/helix-editor/helix/pull/4487), [#4813](https://github.com/helix-editor/helix/pull/4813)) +- Update `flatwhite` ([#3843](https://github.com/helix-editor/helix/pull/3843)) +- Add `darcula` ([#3739](https://github.com/helix-editor/helix/pull/3739)) +- Update `papercolor` ([#3938](https://github.com/helix-editor/helix/pull/3938), [#4317](https://github.com/helix-editor/helix/pull/4317)) +- Add bufferline colors to multiple themes ([#3881](https://github.com/helix-editor/helix/pull/3881)) +- Add `gruvbox_dark_hard` ([#3948](https://github.com/helix-editor/helix/pull/3948)) +- Add `onedarker` ([#3980](https://github.com/helix-editor/helix/pull/3980), [#4060](https://github.com/helix-editor/helix/pull/4060)) +- Add `dark_high_contrast` ([#3312](https://github.com/helix-editor/helix/pull/3312)) +- Update `bogster` ([#4121](https://github.com/helix-editor/helix/pull/4121), [#4264](https://github.com/helix-editor/helix/pull/4264)) +- Update `sonokai` ([#4089](https://github.com/helix-editor/helix/pull/4089)) +- Update `ayu_*` themes ([#4140](https://github.com/helix-editor/helix/pull/4140), [#4109](https://github.com/helix-editor/helix/pull/4109), [#4662](https://github.com/helix-editor/helix/pull/4662), [#4764](https://github.com/helix-editor/helix/pull/4764)) +- Update `everforest` ([#3998](https://github.com/helix-editor/helix/pull/3998)) +- Update `monokai_pro_octagon` ([#4247](https://github.com/helix-editor/helix/pull/4247)) +- Add `heisenberg` ([#4209](https://github.com/helix-editor/helix/pull/4209)) +- Add `bogster_light` ([#4265](https://github.com/helix-editor/helix/pull/4265)) +- Update `pop-dark` ([#4323](https://github.com/helix-editor/helix/pull/4323)) +- Update `rose_pine` ([#4221](https://github.com/helix-editor/helix/pull/4221)) +- Add `kanagawa` ([#4300](https://github.com/helix-editor/helix/pull/4300)) +- Add `hex_steel`, `hex_toxic` and `hex_lavendar` ([#4367](https://github.com/helix-editor/helix/pull/4367), [#4990](https://github.com/helix-editor/helix/pull/4990)) +- Update `tokyonight` and `tokyonight_storm` ([#4415](https://github.com/helix-editor/helix/pull/4415)) +- Update `gruvbox` ([#4626](https://github.com/helix-editor/helix/pull/4626)) +- Update `dark_plus` ([#4661](https://github.com/helix-editor/helix/pull/4661), [#4678](https://github.com/helix-editor/helix/pull/4678)) +- Add `zenburn` ([#4613](https://github.com/helix-editor/helix/pull/4613), [#4977](https://github.com/helix-editor/helix/pull/4977)) +- Update `monokai_pro` ([#4789](https://github.com/helix-editor/helix/pull/4789)) +- Add `mellow` ([#4770](https://github.com/helix-editor/helix/pull/4770)) +- Add `nightfox` ([#4769](https://github.com/helix-editor/helix/pull/4769), [#4966](https://github.com/helix-editor/helix/pull/4966)) +- Update `doom_acario_dark` ([#4979](https://github.com/helix-editor/helix/pull/4979)) +- Update `autumn` ([#4996](https://github.com/helix-editor/helix/pull/4996)) +- Update `acme` ([#4999](https://github.com/helix-editor/helix/pull/4999)) +- Update `nord_light` ([#4999](https://github.com/helix-editor/helix/pull/4999)) +- Update `serika_*` ([#5015](https://github.com/helix-editor/helix/pull/5015)) + +LSP configurations: + +- Switch to `openscad-lsp` for OpenScad ([#3750](https://github.com/helix-editor/helix/pull/3750)) +- Support Jsonnet ([#3748](https://github.com/helix-editor/helix/pull/3748)) +- Support Markdown ([#3499](https://github.com/helix-editor/helix/pull/3499)) +- Support Bass ([#3771](https://github.com/helix-editor/helix/pull/3771)) +- Set roots configuration for Elixir and HEEx ([#3917](https://github.com/helix-editor/helix/pull/3917), [#3959](https://github.com/helix-editor/helix/pull/3959)) +- Support Purescript ([#4242](https://github.com/helix-editor/helix/pull/4242)) +- Set roots configuration for Julia ([#4361](https://github.com/helix-editor/helix/pull/4361)) +- Support D ([#4372](https://github.com/helix-editor/helix/pull/4372)) +- Increase default language server timeout for Julia ([#4575](https://github.com/helix-editor/helix/pull/4575)) +- Use ElixirLS for HEEx ([#4679](https://github.com/helix-editor/helix/pull/4679)) +- Support Bicep ([#4403](https://github.com/helix-editor/helix/pull/4403)) +- Switch to `nil` for Nix ([433ccef](https://github.com/helix-editor/helix/commit/433ccef)) +- Support QML ([#4842](https://github.com/helix-editor/helix/pull/4842)) +- Enable auto-format for CSS ([#4987](https://github.com/helix-editor/helix/pull/4987)) +- Support CommonLisp ([4176769](https://github.com/helix-editor/helix/commit/4176769)) + +New languages: + +- SML ([#3692](https://github.com/helix-editor/helix/pull/3692)) +- Jsonnet ([#3714](https://github.com/helix-editor/helix/pull/3714)) +- Godot resource ([#3759](https://github.com/helix-editor/helix/pull/3759)) +- Astro ([#3829](https://github.com/helix-editor/helix/pull/3829)) +- SSH config ([#2455](https://github.com/helix-editor/helix/pull/2455), [#4538](https://github.com/helix-editor/helix/pull/4538)) +- Bass ([#3771](https://github.com/helix-editor/helix/pull/3771)) +- WAT (WebAssembly text format) ([#4040](https://github.com/helix-editor/helix/pull/4040), [#4542](https://github.com/helix-editor/helix/pull/4542)) +- Purescript ([#4242](https://github.com/helix-editor/helix/pull/4242)) +- D ([#4372](https://github.com/helix-editor/helix/pull/4372), [#4562](https://github.com/helix-editor/helix/pull/4562)) +- VHS ([#4486](https://github.com/helix-editor/helix/pull/4486)) +- KDL ([#4481](https://github.com/helix-editor/helix/pull/4481)) +- XML ([#4518](https://github.com/helix-editor/helix/pull/4518)) +- WIT ([#4525](https://github.com/helix-editor/helix/pull/4525)) +- ENV ([#4536](https://github.com/helix-editor/helix/pull/4536)) +- INI ([#4538](https://github.com/helix-editor/helix/pull/4538)) +- Bicep ([#4403](https://github.com/helix-editor/helix/pull/4403), [#4751](https://github.com/helix-editor/helix/pull/4751)) +- QML ([#4842](https://github.com/helix-editor/helix/pull/4842)) +- CommonLisp ([4176769](https://github.com/helix-editor/helix/commit/4176769)) + +Updated languages and queries: + +- Zig ([#3621](https://github.com/helix-editor/helix/pull/3621), [#4745](https://github.com/helix-editor/helix/pull/4745)) +- Rust ([#3647](https://github.com/helix-editor/helix/pull/3647), [#3729](https://github.com/helix-editor/helix/pull/3729), [#3927](https://github.com/helix-editor/helix/pull/3927), [#4073](https://github.com/helix-editor/helix/pull/4073), [#4510](https://github.com/helix-editor/helix/pull/4510), [#4659](https://github.com/helix-editor/helix/pull/4659), [#4717](https://github.com/helix-editor/helix/pull/4717)) +- Solidity ([20ed8c2](https://github.com/helix-editor/helix/commit/20ed8c2)) +- Fish ([#3704](https://github.com/helix-editor/helix/pull/3704)) +- Elixir ([#3645](https://github.com/helix-editor/helix/pull/3645), [#4333](https://github.com/helix-editor/helix/pull/4333), [#4821](https://github.com/helix-editor/helix/pull/4821)) +- Diff ([#3708](https://github.com/helix-editor/helix/pull/3708)) +- Nix ([665e27f](https://github.com/helix-editor/helix/commit/665e27f), [1fe3273](https://github.com/helix-editor/helix/commit/1fe3273)) +- Markdown ([#3749](https://github.com/helix-editor/helix/pull/3749), [#4078](https://github.com/helix-editor/helix/pull/4078), [#4483](https://github.com/helix-editor/helix/pull/4483), [#4478](https://github.com/helix-editor/helix/pull/4478)) +- GDScript ([#3760](https://github.com/helix-editor/helix/pull/3760)) +- JSX and TSX ([#3853](https://github.com/helix-editor/helix/pull/3853), [#3973](https://github.com/helix-editor/helix/pull/3973)) +- Ruby ([#3976](https://github.com/helix-editor/helix/pull/3976), [#4601](https://github.com/helix-editor/helix/pull/4601)) +- R ([#4031](https://github.com/helix-editor/helix/pull/4031)) +- WGSL ([#3996](https://github.com/helix-editor/helix/pull/3996), [#4079](https://github.com/helix-editor/helix/pull/4079)) +- C# ([#4118](https://github.com/helix-editor/helix/pull/4118), [#4281](https://github.com/helix-editor/helix/pull/4281), [#4213](https://github.com/helix-editor/helix/pull/4213)) +- Twig ([#4176](https://github.com/helix-editor/helix/pull/4176)) +- Lua ([#3552](https://github.com/helix-editor/helix/pull/3552)) +- C/C++ ([#4079](https://github.com/helix-editor/helix/pull/4079), [#4278](https://github.com/helix-editor/helix/pull/4278), [#4282](https://github.com/helix-editor/helix/pull/4282)) +- Cairo ([17488f1](https://github.com/helix-editor/helix/commit/17488f1), [431f9c1](https://github.com/helix-editor/helix/commit/431f9c1), [09a6df1](https://github.com/helix-editor/helix/commit/09a6df1)) +- Rescript ([#4356](https://github.com/helix-editor/helix/pull/4356)) +- Zig ([#4409](https://github.com/helix-editor/helix/pull/4409)) +- Scala ([#4353](https://github.com/helix-editor/helix/pull/4353), [#4697](https://github.com/helix-editor/helix/pull/4697), [#4701](https://github.com/helix-editor/helix/pull/4701)) +- LaTeX ([#4528](https://github.com/helix-editor/helix/pull/4528), [#4922](https://github.com/helix-editor/helix/pull/4922)) +- SQL ([#4529](https://github.com/helix-editor/helix/pull/4529)) +- Python ([#4560](https://github.com/helix-editor/helix/pull/4560)) +- Bash/Zsh ([#4582](https://github.com/helix-editor/helix/pull/4582)) +- Nu ([#4583](https://github.com/helix-editor/helix/pull/4583)) +- Julia ([#4588](https://github.com/helix-editor/helix/pull/4588)) +- Typescript ([#4703](https://github.com/helix-editor/helix/pull/4703)) +- Meson ([#4572](https://github.com/helix-editor/helix/pull/4572)) +- Haskell ([#4800](https://github.com/helix-editor/helix/pull/4800)) +- CMake ([#4809](https://github.com/helix-editor/helix/pull/4809)) +- HTML ([#4829](https://github.com/helix-editor/helix/pull/4829), [#4881](https://github.com/helix-editor/helix/pull/4881)) +- Java ([#4886](https://github.com/helix-editor/helix/pull/4886)) +- Go ([#4906](https://github.com/helix-editor/helix/pull/4906), [#4969](https://github.com/helix-editor/helix/pull/4969), [#5010](https://github.com/helix-editor/helix/pull/5010)) +- CSS ([#4882](https://github.com/helix-editor/helix/pull/4882)) +- Racket ([#4915](https://github.com/helix-editor/helix/pull/4915)) +- SCSS ([#5003](https://github.com/helix-editor/helix/pull/5003)) + +Packaging: + +- Filter relevant source files in the Nix flake ([#3657](https://github.com/helix-editor/helix/pull/3657)) +- Build a binary for `aarch64-linux` in the release CI ([038a91d](https://github.com/helix-editor/helix/commit/038a91d)) +- Build an AppImage for `aarch64-linux` in the release CI ([b738031](https://github.com/helix-editor/helix/commit/b738031)) +- Enable CI builds for `riscv64-linux` ([#3685](https://github.com/helix-editor/helix/pull/3685)) +- Support preview releases in CI ([0090a2d](https://github.com/helix-editor/helix/commit/0090a2d)) +- Strip binaries built in CI ([#3780](https://github.com/helix-editor/helix/pull/3780)) +- Fix the development shell for the Nix Flake on `aarch64-darwin` ([#3810](https://github.com/helix-editor/helix/pull/3810)) +- Raise the MSRV and create an MSRV policy ([#3896](https://github.com/helix-editor/helix/pull/3896), [#3913](https://github.com/helix-editor/helix/pull/3913), [#3961](https://github.com/helix-editor/helix/pull/3961)) +- Fix Fish completions for `--config` and `--log` flags ([#3912](https://github.com/helix-editor/helix/pull/3912)) +- Use builtin filenames option in Bash completion ([#4648](https://github.com/helix-editor/helix/pull/4648)) + # 22.08.1 (2022-09-01) This is a patch release that fixes a panic caused by closing splits or buffers. ([#3633](https://github.com/helix-editor/helix/pull/3633)) diff --git a/VERSION b/VERSION index b9ed4c22ac55..e70b3aebd5b7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -22.08.1 \ No newline at end of file +22.12 \ No newline at end of file From 9d4236941d581a1a9ed017db294fd3413a670b84 Mon Sep 17 00:00:00 2001 From: Alexander Brevig Date: Wed, 7 Dec 2022 12:29:56 +0100 Subject: [PATCH 098/269] fix(theme): serika toml syntax valid (#5038) --- runtime/themes/serika-light.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/serika-light.toml b/runtime/themes/serika-light.toml index ad830d92c148..99d4b7f1bbbd 100644 --- a/runtime/themes/serika-light.toml +++ b/runtime/themes/serika-light.toml @@ -59,7 +59,7 @@ "error" = "nasty-red" "diagnostic" = { fg = "nasty-red", modifiers = ["underlined"] } -"diff.plus" = { fg = "bg_green" +"diff.plus" = { fg = "bg_green" } "diff.delta" = { fg = "bg_blue" } "diff.minus" = { fg = "nasty-red" } From a4de86e7afc0da3d847d467a21ff4fb67a51d620 Mon Sep 17 00:00:00 2001 From: Alexander Brevig Date: Wed, 7 Dec 2022 12:30:46 +0100 Subject: [PATCH 099/269] fix(theme): git gutter for flatwhite (#5036) --- runtime/themes/flatwhite.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime/themes/flatwhite.toml b/runtime/themes/flatwhite.toml index d4c837b6930a..2fdc66d0fea9 100644 --- a/runtime/themes/flatwhite.toml +++ b/runtime/themes/flatwhite.toml @@ -77,9 +77,9 @@ "ui.popup" = { fg = "base1", bg = "base6" } "ui.window" = { fg = "base1", bg = "base6" } -"diff.plus" = { bg = "diff_add" } -"diff.delta" = { bg = "diff_change" } -"diff.minus" = { bg = "diff_delete" } +"diff.plus" = { fg = "diff_add" } +"diff.delta" = { fg = "diff_change" } +"diff.minus" = { fg = "diff_delete" } [palette] base1 = "#605a52" From f8b75a245a390fc3772d59cafe04ccaaa53c9ca9 Mon Sep 17 00:00:00 2001 From: Jens Getreu Date: Thu, 8 Dec 2022 02:48:01 +0100 Subject: [PATCH 100/269] Autumn theme: use new features (#5051) Co-authored-by: Jens Getreu --- runtime/themes/autumn.toml | 3 +- runtime/themes/autumn_night.toml | 62 +------------------------------- 2 files changed, 3 insertions(+), 62 deletions(-) diff --git a/runtime/themes/autumn.toml b/runtime/themes/autumn.toml index fe80261af294..501675da16ba 100644 --- a/runtime/themes/autumn.toml +++ b/runtime/themes/autumn.toml @@ -58,10 +58,11 @@ "markup.raw" = "my_green" "diff.plus" = "my_green" -"diff.delta" = "my_white" +"diff.delta" = "my_gray4" "diff.minus" = "my_red" "diagnostic" = { modifiers = ["underlined"] } +"diagnostic.error" = { underline = { style = "curl", color = "my_red" } } "ui.gutter" = { bg = "my_gray0" } "hint" = "my_gray5" "debug" = "my_yellow2" diff --git a/runtime/themes/autumn_night.toml b/runtime/themes/autumn_night.toml index d01f5356931e..c26cc777e144 100644 --- a/runtime/themes/autumn_night.toml +++ b/runtime/themes/autumn_night.toml @@ -7,67 +7,7 @@ # Jens Getreu ported and optimised the color theme for the Helix editor. # Author: Jens Getreu -"ui.background" = { bg = "my_gray0" } -"ui.menu" = { fg = "my_white", bg = "my_gray2" } -"ui.menu.selected" = { fg = "my_gray2", bg = "my_gray5" } -"ui.linenr" = { fg = "my_gray3", bg = "my_gray0" } -"ui.popup" = { bg = "my_gray2" } -"ui.window" = { fg = "my_gray3", bg = "my_gray2" } -"ui.linenr.selected" = { fg = "my_gray6", bg = "my_gray0"} -"ui.selection" = { bg = "my_gray3" } -"comment" = { fg = "my_gray4", modifiers = ["italic"] } -"ui.cursorline" = { bg = "my_gray3" } -"ui.statusline" = { fg = "my_gray6", bg = "my_gray2" } -"ui.statusline.inactive" = { fg = 'my_gray4', bg = 'my_gray2' } -"ui.statusline.insert" = {fg = "my_black", bg = "my_gray5", modifiers = ["bold"]} -"ui.statusline.normal" = {fg = "my_gray6", bg = "my_gray2"} -"ui.statusline.select" = {fg = "my_gray6", bg = "my_black", modifiers = ["bold"]} -"ui.cursor" = { fg = "my_gray5", modifiers = ["reversed"] } -"ui.cursor.primary" = { fg = "my_white", modifiers = ["reversed"] } -"ui.cursorline.primary" = { bg = "my_black" } -"ui.cursorline.secondary" = { bg = "my_black" } -"ui.text" = "my_white" -"operator" = "my_white" -"ui.text.focus" = "my_white" -"variable" = "my_white3" -"constant.numeric" = "my_turquoise" -"constant" = "my_white3" -"attribute" = "my_turquoise" -"type" = { fg = "my_white3", modifiers = ["italic"] } -"ui.cursor.match" = { fg = "my_white3", modifiers = ["underlined"] } -"string" = "my_green" -"variable.other.member" = "my_brown" -"constant.character.escape" = "my_turquoise" -"function" = "my_yellow1" -"constructor" = "my_yellow1" -"special" = "my_yellow1" -"keyword" = "my_red" -"label" = "my_red" -"namespace" = "my_white3" -"ui.help" = { fg = "my_gray6", bg = "my_gray2" } -"ui.virtual.whitespace" = { fg = "my_gray5" } -"ui.virtual.ruler" = { bg = "my_gray1" } - -"markup.heading" = "my_yellow1" -"markup.list" = "my_white2" -"markup.bold" = { modifiers = ["bold"] } -"markup.italic" = { modifiers = ["italic"] } -"markup.link.url" = "my_turquoise2" -"markup.link.text" = "my_white2" -"markup.quote" = "my_brown" -"markup.raw" = "my_green" - -"diff.plus" = "my_green" -"diff.delta" = "my_white" -"diff.minus" = "my_red" - -"diagnostic" = { modifiers = ["underlined"] } -"ui.gutter" = { bg = "my_gray0" } -"hint" = "my_gray5" -"debug" = "my_yellow2" -"info" = "my_yellow2" -"warning" = "my_yellow2" -"error" = "my_red" +inherits = "autumn" [palette] my_black = "#111111" # Cursorline From 36eff1da8cdc4efc9cec362311718fa6a4c75563 Mon Sep 17 00:00:00 2001 From: LeoniePhiline <22329650+LeoniePhiline@users.noreply.github.com> Date: Fri, 9 Dec 2022 03:58:15 +0100 Subject: [PATCH 101/269] fix(tutor): Capitalize first letter of a sentence (#5075) --- runtime/tutor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tutor b/runtime/tutor index d977e078c78f..418c4195487e 100644 --- a/runtime/tutor +++ b/runtime/tutor @@ -96,7 +96,7 @@ _________________________________________________________________ 2. Move to a place in the line which is missing text and type i to enter Insert mode. Keys you type will now type text. 3. Enter the missing text. - 4. type Escape to exit Insert mode and return to Normal mode. + 4. Type Escape to exit Insert mode and return to Normal mode. 5. Repeat until the line matches the line below it. --> Th stce misg so. From d91464208958b6f44b431d244e0f369d7907ba59 Mon Sep 17 00:00:00 2001 From: cor Date: Fri, 9 Dec 2022 04:48:56 +0100 Subject: [PATCH 102/269] use curl underlines for gruvbox_dark_hard (#5066) --- runtime/themes/gruvbox_dark_hard.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime/themes/gruvbox_dark_hard.toml b/runtime/themes/gruvbox_dark_hard.toml index 708ca2b2c279..27d9ab9b36e8 100644 --- a/runtime/themes/gruvbox_dark_hard.toml +++ b/runtime/themes/gruvbox_dark_hard.toml @@ -39,6 +39,12 @@ "info" = { fg = "aqua1", bg = "bg1" } "hint" = { fg = "blue1", bg = "bg1" } +"diagnostic" = { modifiers = ["underlined"] } +"diagnostic.error" = { underline = { style = "curl", color = "red0" } } +"diagnostic.warning" = { underline = { style = "curl", color = "orange1" } } +"diagnostic.info" = { underline = { style = "curl", color = "aqua1" } } +"diagnostic.hint" = { underline = { style = "curl", color = "blue1" } } + "ui.background" = { bg = "bg0" } "ui.linenr" = { fg = "bg4" } "ui.linenr.selected" = { fg = "yellow1" } @@ -61,8 +67,6 @@ "ui.virtual.whitespace" = "bg2" "ui.virtual.ruler" = { bg = "bg1" } -"diagnostic" = { modifiers = ["underlined"] } - "markup.heading" = "aqua1" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } From 6798a6651f9d314eacefddfd051661b030ca9d78 Mon Sep 17 00:00:00 2001 From: ath3 <45574139+ath3@users.noreply.github.com> Date: Fri, 9 Dec 2022 04:55:15 +0100 Subject: [PATCH 103/269] Only write newlines in menu selection popup if the lsp returns detail (#4902) --- helix-term/src/ui/completion.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index c54990e8ec75..11d7886a37d6 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -411,7 +411,7 @@ impl Component for Completion { "```{}\n{}\n```\n{}", language, option.detail.as_deref().unwrap_or_default(), - contents.clone() + contents ), cx.editor.syn_loader.clone(), ) @@ -421,15 +421,14 @@ impl Component for Completion { value: contents, })) => { // TODO: set language based on doc scope - Markdown::new( - format!( - "```{}\n{}\n```\n{}", - language, - option.detail.as_deref().unwrap_or_default(), - contents.clone() - ), - cx.editor.syn_loader.clone(), - ) + if let Some(detail) = &option.detail.as_deref() { + Markdown::new( + format!("```{}\n{}\n```\n{}", language, detail, contents), + cx.editor.syn_loader.clone(), + ) + } else { + Markdown::new(contents.to_string(), cx.editor.syn_loader.clone()) + } } None if option.detail.is_some() => { // TODO: copied from above From 8abed3bd78200fc5f7e3890fd853c17ce518d157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Dzivjak?= Date: Fri, 9 Dec 2022 04:57:03 +0100 Subject: [PATCH 104/269] feat(lsp): pass client_info on initialization (#4904) Pass client name ('helix') and client version (version / git hash) to LSP server on initialization. --- Cargo.lock | 1 + helix-loader/build.rs | 20 ++++++++++++++++++++ helix-loader/src/lib.rs | 2 ++ helix-lsp/Cargo.toml | 1 + helix-lsp/src/client.rs | 6 +++++- helix-term/build.rs | 21 --------------------- helix-term/src/main.rs | 5 +++-- 7 files changed, 32 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 014834e43349..b204214fc42e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1187,6 +1187,7 @@ dependencies = [ "futures-executor", "futures-util", "helix-core", + "helix-loader", "log", "lsp-types", "serde", diff --git a/helix-loader/build.rs b/helix-loader/build.rs index e0ebd1c48f17..c4b89e6b93fe 100644 --- a/helix-loader/build.rs +++ b/helix-loader/build.rs @@ -1,6 +1,26 @@ +use std::borrow::Cow; +use std::process::Command; + +const VERSION: &str = include_str!("../VERSION"); + fn main() { + let git_hash = Command::new("git") + .args(["rev-parse", "HEAD"]) + .output() + .ok() + .filter(|output| output.status.success()) + .and_then(|x| String::from_utf8(x.stdout).ok()); + + let version: Cow<_> = match git_hash { + Some(git_hash) => format!("{} ({})", VERSION, &git_hash[..8]).into(), + None => VERSION.into(), + }; + println!( "cargo:rustc-env=BUILD_TARGET={}", std::env::var("TARGET").unwrap() ); + + println!("cargo:rerun-if-changed=../VERSION"); + println!("cargo:rustc-env=VERSION_AND_GIT_HASH={}", version); } diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index a02a59afc821..29a9f2e75a2b 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -4,6 +4,8 @@ pub mod grammar; use etcetera::base_strategy::{choose_base_strategy, BaseStrategy}; use std::path::PathBuf; +pub const VERSION_AND_GIT_HASH: &str = env!("VERSION_AND_GIT_HASH"); + pub static RUNTIME_DIR: once_cell::sync::Lazy = once_cell::sync::Lazy::new(runtime_dir); static CONFIG_FILE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index 41884e73a249..05c5467ea8ac 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -13,6 +13,7 @@ homepage = "https://helix-editor.com" [dependencies] helix-core = { version = "0.6", path = "../helix-core" } +helix-loader = { version = "0.6", path = "../helix-loader" } anyhow = "1.0" futures-executor = "0.3" diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 2c2c7c88ec1d..90fd2f21507c 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -5,6 +5,7 @@ use crate::{ }; use helix_core::{find_root, ChangeSet, Rope}; +use helix_loader::{self, VERSION_AND_GIT_HASH}; use lsp_types as lsp; use serde::Deserialize; use serde_json::Value; @@ -376,7 +377,10 @@ impl Client { ..Default::default() }, trace: None, - client_info: None, + client_info: Some(lsp::ClientInfo { + name: String::from("helix"), + version: Some(String::from(VERSION_AND_GIT_HASH)), + }), locale: None, // TODO }; diff --git a/helix-term/build.rs b/helix-term/build.rs index 719113ff2c37..b47dae8ef653 100644 --- a/helix-term/build.rs +++ b/helix-term/build.rs @@ -1,30 +1,9 @@ use helix_loader::grammar::{build_grammars, fetch_grammars}; -use std::borrow::Cow; -use std::process::Command; - -const VERSION: &str = include_str!("../VERSION"); fn main() { - let git_hash = Command::new("git") - .args(["rev-parse", "HEAD"]) - .output() - .ok() - .filter(|output| output.status.success()) - .and_then(|x| String::from_utf8(x.stdout).ok()); - - let version: Cow<_> = match git_hash { - Some(git_hash) => format!("{} ({})", VERSION, &git_hash[..8]).into(), - None => VERSION.into(), - }; - if std::env::var("HELIX_DISABLE_AUTO_GRAMMAR_BUILD").is_err() { fetch_grammars().expect("Failed to fetch tree-sitter grammars"); build_grammars(Some(std::env::var("TARGET").unwrap())) .expect("Failed to compile tree-sitter grammars"); } - - println!("cargo:rerun-if-changed=../runtime/grammars/"); - println!("cargo:rerun-if-changed=../VERSION"); - - println!("cargo:rustc-env=VERSION_AND_GIT_HASH={}", version); } diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index 96b695c6fcde..aac5c5379f37 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -1,5 +1,6 @@ use anyhow::{Context, Error, Result}; use crossterm::event::EventStream; +use helix_loader::VERSION_AND_GIT_HASH; use helix_term::application::Application; use helix_term::args::Args; use helix_term::config::Config; @@ -74,7 +75,7 @@ FLAGS: --hsplit Splits all given files horizontally into different windows ", env!("CARGO_PKG_NAME"), - env!("VERSION_AND_GIT_HASH"), + VERSION_AND_GIT_HASH, env!("CARGO_PKG_AUTHORS"), env!("CARGO_PKG_DESCRIPTION"), logpath.display(), @@ -89,7 +90,7 @@ FLAGS: } if args.display_version { - println!("helix {}", env!("VERSION_AND_GIT_HASH")); + println!("helix {}", VERSION_AND_GIT_HASH); std::process::exit(0); } From 2ea20a23e26a771e095972bdda673d491b4aacc5 Mon Sep 17 00:00:00 2001 From: Jummit Date: Fri, 9 Dec 2022 05:02:34 +0100 Subject: [PATCH 105/269] Fix LSP completions ignoring auto-completion option (#5042) --- helix-term/src/commands.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 1843e7a2be4e..2bac5be08e8d 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3049,6 +3049,11 @@ pub mod insert { } fn language_server_completion(cx: &mut Context, ch: char) { + let config = cx.editor.config(); + if !config.auto_completion { + return; + } + use helix_lsp::lsp; // if ch matches completion char, trigger completion let doc = doc_mut!(cx.editor); From 16e13b9789359282cb6c2681262f46fb1b70134b Mon Sep 17 00:00:00 2001 From: TotalKrill Date: Fri, 9 Dec 2022 05:09:23 +0100 Subject: [PATCH 106/269] allow specifying environment for language servers in language.toml (#4004) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stephen Wakely Co-authored-by: Stephen Wakely Co-authored-by: Blaž Hrastnik --- book/src/languages.md | 3 ++- helix-core/src/syntax.rs | 2 ++ helix-lsp/src/client.rs | 3 +++ helix-lsp/src/lib.rs | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/book/src/languages.md b/book/src/languages.md index 133e6447941c..e45ef910a8d4 100644 --- a/book/src/languages.md +++ b/book/src/languages.md @@ -39,7 +39,7 @@ injection-regex = "^mylang$" file-types = ["mylang", "myl"] comment-token = "#" indent = { tab-width = 2, unit = " " } -language-server = { command = "mylang-lsp", args = ["--stdio"] } +language-server = { command = "mylang-lsp", args = ["--stdio"], environment = { "ENV1" = "value1", "ENV2" = "value2" } } formatter = { command = "mylang-formatter" , args = ["--stdin"] } ``` @@ -99,6 +99,7 @@ The `language-server` field takes the following keys: | `args` | A list of arguments to pass to the language server binary | | `timeout` | The maximum time a request to the language server may take, in seconds. Defaults to `20` | | `language-id` | The language name to pass to the language server. Some language servers support multiple languages and use this field to determine which one is being served in a buffer | +| `environment` | Any environment variables that will be used when starting the language server `{ "KEY1" = "Value1", "KEY2" = "Value2" }` | The top-level `config` field is used to configure the LSP initialization options. A `format` sub-table within `config` can be used to pass extra formatting options to diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 8dc34a3e3631..41ab23e1343a 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -207,6 +207,8 @@ pub struct LanguageServerConfiguration { #[serde(default)] #[serde(skip_serializing_if = "Vec::is_empty")] pub args: Vec, + #[serde(default, skip_serializing_if = "HashMap::is_empty")] + pub environment: HashMap, #[serde(default = "default_timeout")] pub timeout: u64, pub language_id: Option, diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 90fd2f21507c..dd2581c6d916 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -42,10 +42,12 @@ pub struct Client { impl Client { #[allow(clippy::type_complexity)] + #[allow(clippy::too_many_arguments)] pub fn start( cmd: &str, args: &[String], config: Option, + server_environment: HashMap, root_markers: &[String], id: usize, req_timeout: u64, @@ -55,6 +57,7 @@ impl Client { let cmd = which::which(cmd).map_err(|err| anyhow::anyhow!(err))?; let process = Command::new(cmd) + .envs(server_environment) .args(args) .stdin(Stdio::piped()) .stdout(Stdio::piped()) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index f714395f28f5..8418896cbb73 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -550,6 +550,7 @@ fn start_client( &ls_config.command, &ls_config.args, config.config.clone(), + ls_config.environment.clone(), &config.roots, id, ls_config.timeout, From 37e7dd1df598312727aadb5c74919fd196fecffc Mon Sep 17 00:00:00 2001 From: two-six Date: Fri, 9 Dec 2022 05:11:25 +0100 Subject: [PATCH 107/269] Update `diagnostic.error` background for acme theme (#5019) --- runtime/themes/acme.toml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/runtime/themes/acme.toml b/runtime/themes/acme.toml index 696a4a9b2633..e1785f4a5fec 100644 --- a/runtime/themes/acme.toml +++ b/runtime/themes/acme.toml @@ -17,9 +17,9 @@ "ui.menu" = {fg="black", bg="acme_bg"} "ui.menu.selected" = {bg="selected"} "ui.window" = {bg="acme_bg"} -"diagnostic.error" = {bg="white", modifiers=["bold"]} -"diagnostic.warning" = {bg="white", modifiers=["bold"]} -"diagnostic.hint" = {bg="white", modifiers=["bold"]} +"diagnostic.error" = {bg="red", fg="white", modifiers=["bold"]} +"diagnostic.warning" = {bg="orange", fg="black", modifiers=["bold"]} +"diagnostic.hint" = {fg="gray", modifiers=["bold"]} "ui.bufferline" = { fg = "indent", bg = "acme_bar_bg" } "ui.bufferline.active" = { fg = "black", bg = "acme_bg" } "diff.plus" = {fg = "green"} @@ -37,3 +37,5 @@ cursor = "#444444" red = "#a0342f" green = "#065905" indent = "#aaaaaa" +orange = "#f0ad4e" +gray = "#777777" From d14de277092d7eab555ea2abc1435101d12e308c Mon Sep 17 00:00:00 2001 From: "Felipe S. S. Schneider" <37125+schneiderfelipe@users.noreply.github.com> Date: Fri, 9 Dec 2022 01:33:08 -0300 Subject: [PATCH 108/269] Add support for the BibTeX file format (#5064) --- book/src/generated/lang-support.md | 1 + languages.toml | 28 ++++++++++++++++ runtime/queries/bibtex/highlights.scm | 47 +++++++++++++++++++++++++++ runtime/queries/bibtex/locals.scm | 0 runtime/queries/bibtex/tags.scm | 0 5 files changed, 76 insertions(+) create mode 100644 runtime/queries/bibtex/highlights.scm create mode 100644 runtime/queries/bibtex/locals.scm create mode 100644 runtime/queries/bibtex/tags.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index ccfd18c00fca..28dafd7ada47 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -5,6 +5,7 @@ | bash | ✓ | | | `bash-language-server` | | bass | ✓ | | | `bass` | | beancount | ✓ | | | | +| bibtex | ✓ | | | `texlab` | | bicep | ✓ | | | `bicep-langserver` | | c | ✓ | ✓ | ✓ | `clangd` | | c-sharp | ✓ | ✓ | | `OmniSharp` | diff --git a/languages.toml b/languages.toml index 325a39dfc4c6..96d92ce84ab1 100644 --- a/languages.toml +++ b/languages.toml @@ -576,6 +576,34 @@ indent = { tab-width = 4, unit = "\t" } name = "latex" source = { git = "https://github.com/latex-lsp/tree-sitter-latex", rev = "8c75e93cd08ccb7ce1ccab22c1fbd6360e3bcea6" } +[[language]] +name = "bibtex" +scope = "source.bib" +injection-regex = "bib" +file-types = ["bib"] +roots = [] +comment-token = "%" +language-server = { command = "texlab" } +indent = { tab-width = 4, unit = "\t" } +auto-format = true + +[language.formatter] +command = 'bibtex-tidy' +args = [ + "-", + "--curly", + "--drop-all-caps", + "--remove-empty-fields", + "--sort-fields", + "--sort=year,author,id", + "--strip-enclosing-braces", + "--trailing-commas", +] + +[[grammar]] +name = "bibtex" +source = { git = "https://github.com/latex-lsp/tree-sitter-bibtex", rev = "ccfd77db0ed799b6c22c214fe9d2937f47bc8b34" } + [[language]] name = "lean" scope = "source.lean" diff --git a/runtime/queries/bibtex/highlights.scm b/runtime/queries/bibtex/highlights.scm new file mode 100644 index 000000000000..db1ab70c16f9 --- /dev/null +++ b/runtime/queries/bibtex/highlights.scm @@ -0,0 +1,47 @@ +[ + (string_type) + (preamble_type) + (entry_type) +] @keyword + +[ + (junk) + (comment) +] @comment + +[ + "=" + "#" +] @operator + +(command) @function.builtin + +(number) @constant.numeric + +(field + name: (identifier) @variable.builtin) + +(token + (identifier) @variable.parameter) + +[ + (brace_word) + (quote_word) +] @string + +[ + (key_brace) + (key_paren) +] @attribute + +(string + name: (identifier) @constant) + +[ + "{" + "}" + "(" + ")" +] @punctuation.bracket + +"," @punctuation.delimiter diff --git a/runtime/queries/bibtex/locals.scm b/runtime/queries/bibtex/locals.scm new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/runtime/queries/bibtex/tags.scm b/runtime/queries/bibtex/tags.scm new file mode 100644 index 000000000000..e69de29bb2d1 From f323ffabcc5846f647e3ba1d3d2ff5dec95257bd Mon Sep 17 00:00:00 2001 From: Danilo Spinella Date: Sat, 10 Dec 2022 01:40:27 +0100 Subject: [PATCH 109/269] Treat patches as diff files (#5085) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 96d92ce84ab1..06af52bd340e 100644 --- a/languages.toml +++ b/languages.toml @@ -1083,7 +1083,7 @@ source = { git = "https://github.com/the-mikedavis/tree-sitter-git-commit", rev name = "diff" scope = "source.diff" roots = [] -file-types = ["diff"] +file-types = ["diff", "patch"] injection-regex = "diff" comment-token = "#" indent = { tab-width = 2, unit = " " } From 0e8ea13696206aa8ad289d539a5df62f34a73dec Mon Sep 17 00:00:00 2001 From: Ollie Charles Date: Sat, 10 Dec 2022 20:03:18 +0000 Subject: [PATCH 110/269] Add Haskell text objects (#5061) --- book/src/generated/lang-support.md | 2 +- runtime/queries/haskell/textobjects.scm | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/haskell/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 28dafd7ada47..4dca810478db 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -51,7 +51,7 @@ | gowork | ✓ | | | `gopls` | | graphql | ✓ | | | | | hare | ✓ | | | | -| haskell | ✓ | | | `haskell-language-server-wrapper` | +| haskell | ✓ | ✓ | | `haskell-language-server-wrapper` | | hcl | ✓ | | ✓ | `terraform-ls` | | heex | ✓ | ✓ | | `elixir-ls` | | html | ✓ | | | `vscode-html-language-server` | diff --git a/runtime/queries/haskell/textobjects.scm b/runtime/queries/haskell/textobjects.scm new file mode 100644 index 000000000000..9870dc4a4128 --- /dev/null +++ b/runtime/queries/haskell/textobjects.scm @@ -0,0 +1,13 @@ +(comment) @comment.inside + +[ + (adt) + (decl_type) + (newtype) +] @class.around + +((signature)? (function rhs:(_) @function.inside)) @function.around +(exp_lambda) @function.around + +(adt (type_variable) @parameter.inside) +(patterns (_) @parameter.inside) From 70d78123b94d93c801171ac3dd29e2a493feee20 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Sun, 11 Dec 2022 11:20:34 +0100 Subject: [PATCH 111/269] properly handle detachted git worktrees (#5097) --- helix-core/src/lib.rs | 2 +- helix-loader/src/grammar.rs | 2 +- helix-loader/src/lib.rs | 2 +- helix-term/src/ui/mod.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 0e76ebbbefca..ee174e69d1cd 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -69,7 +69,7 @@ pub fn find_root(root: Option<&str>, root_markers: &[String]) -> std::path::Path top_marker = Some(ancestor); } - if ancestor.join(".git").is_dir() { + if ancestor.join(".git").exists() { // Top marker is repo root if not root marker was detected yet if top_marker.is_none() { top_marker = Some(ancestor); diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index 833616e046d9..2aa924755112 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -263,7 +263,7 @@ fn fetch_grammar(grammar: GrammarConfiguration) -> Result { ))?; // create the grammar dir contains a git directory - if !grammar_dir.join(".git").is_dir() { + if !grammar_dir.join(".git").exists() { git(&grammar_dir, ["init"])?; } diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index 29a9f2e75a2b..80d44a8264b8 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -97,7 +97,7 @@ pub fn find_local_config_dirs() -> Vec { let mut directories = Vec::new(); for ancestor in current_dir.ancestors() { - if ancestor.join(".git").is_dir() { + if ancestor.join(".git").exists() { directories.push(ancestor.to_path_buf()); // Don't go higher than repo if we're in one break; diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index f61c4c450c7d..107e48dd1ca3 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -207,7 +207,7 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi // Cap the number of files if we aren't in a git project, preventing // hangs when using the picker in your home directory - let files: Vec<_> = if root.join(".git").is_dir() { + let files: Vec<_> = if root.join(".git").exists() { files.collect() } else { // const MAX: usize = 8192; From cdc54f50a2ceb62c9f1c38b939ca988ff0e96855 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 11 Dec 2022 09:04:08 -0600 Subject: [PATCH 112/269] Reset mode when changing buffers (#5072) * Reset mode when changing buffers This is similar to the change in e4c9d4082a139aac3aea4506918171b96e81f5b9: reset the editor to normal mode when changing buffers. Usually the editor is already in normal mode but it's possible to setup insert-mode keybindings that change buffers. * Move normal mode entering code to Editor This should be called internally in the Editor when changing documents (Editor::switch) or changing focuses (Editor::focus). --- helix-term/src/commands.rs | 57 +------------------------------ helix-view/src/editor.rs | 70 +++++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 57 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 2bac5be08e8d..1310417e47be 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2672,62 +2672,7 @@ fn open_above(cx: &mut Context) { } fn normal_mode(cx: &mut Context) { - if cx.editor.mode == Mode::Normal { - return; - } - - cx.editor.mode = Mode::Normal; - let (view, doc) = current!(cx.editor); - - try_restore_indent(doc, view); - - // if leaving append mode, move cursor back by 1 - if doc.restore_cursor { - let text = doc.text().slice(..); - let selection = doc.selection(view.id).clone().transform(|range| { - Range::new( - range.from(), - graphemes::prev_grapheme_boundary(text, range.to()), - ) - }); - - doc.set_selection(view.id, selection); - doc.restore_cursor = false; - } -} - -fn try_restore_indent(doc: &mut Document, view: &mut View) { - use helix_core::chars::char_is_whitespace; - use helix_core::Operation; - - 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 - { - move_pos + inserted_str.len() == 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 - } - } - - 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)); - (line_start_pos, pos, None) - }); - apply_transaction(&transaction, doc, view); - } + cx.editor.enter_normal_mode(); } // Store a jump on the jumplist. diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 973cf82ea109..c13a66736948 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1005,6 +1005,8 @@ impl Editor { return; } + self.enter_normal_mode(); + match action { Action::Replace => { let (view, doc) = current_ref!(self); @@ -1025,6 +1027,9 @@ impl Editor { let (view, doc) = current!(self); let view_id = view.id; + // Append any outstanding changes to history in the old document. + doc.append_changes_to_history(view); + if remove_empty_scratch { // Copy `doc.id` into a variable before calling `self.documents.remove`, which requires a mutable // borrow, invalidating direct access to `doc.id`. @@ -1262,7 +1267,7 @@ impl Editor { // if leaving the view: mode should reset and the cursor should be // within view if prev_id != view_id { - self.mode = Mode::Normal; + self.enter_normal_mode(); self.ensure_cursor_in_view(view_id); // Update jumplist selections with new document changes. @@ -1427,4 +1432,67 @@ impl Editor { Ok(()) } + + /// Switches the editor into normal mode. + pub fn enter_normal_mode(&mut self) { + use helix_core::{graphemes, Range}; + + if self.mode == Mode::Normal { + return; + } + + self.mode = Mode::Normal; + let (view, doc) = current!(self); + + try_restore_indent(doc, view); + + // if leaving append mode, move cursor back by 1 + if doc.restore_cursor { + let text = doc.text().slice(..); + let selection = doc.selection(view.id).clone().transform(|range| { + Range::new( + range.from(), + graphemes::prev_grapheme_boundary(text, range.to()), + ) + }); + + doc.set_selection(view.id, selection); + doc.restore_cursor = false; + } + } +} + +fn try_restore_indent(doc: &mut Document, view: &mut View) { + use helix_core::{ + chars::char_is_whitespace, line_ending::line_end_char_index, Operation, Transaction, + }; + + 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 + { + move_pos + inserted_str.len() == 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 + } + } + + 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)); + (line_start_pos, pos, None) + }); + crate::apply_transaction(&transaction, doc, view); + } } From c5bfb792b2a26545f6515a1e7b62d4f37b10841e Mon Sep 17 00:00:00 2001 From: Slug <106496265+GreasySlug@users.noreply.github.com> Date: Mon, 12 Dec 2022 03:14:10 +0900 Subject: [PATCH 113/269] update(theme): adjust base16_transparent and dark_high_contrast (#5105) --- book/src/themes.md | 2 +- runtime/themes/base16_transparent.toml | 45 +++++++++++++------------ runtime/themes/dark_high_contrast.toml | 46 ++++++++++++++------------ 3 files changed, 48 insertions(+), 45 deletions(-) diff --git a/book/src/themes.md b/book/src/themes.md index 392b5f8c956a..322caea54b48 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -103,7 +103,7 @@ Some styles might not be supported by your terminal emulator. | `line` | | `curl` | | `dashed` | -| `dot` | +| `dotted` | | `double_line` | diff --git a/runtime/themes/base16_transparent.toml b/runtime/themes/base16_transparent.toml index 0c6d924f64cd..f8ee0890d082 100644 --- a/runtime/themes/base16_transparent.toml +++ b/runtime/themes/base16_transparent.toml @@ -1,27 +1,28 @@ # Author: GreasySlug <9619abgoni@gmail.com> +# This theme is base on base16_theme(Author: NNB ) "ui.background" = { fg = "white"} "ui.background.separator" = { fg = "gray" } -"ui.menu" = { fg = "gray" } +"ui.menu" = { fg = "white" } "ui.menu.selected" = { modifiers = ["reversed"] } "ui.menu.scroll" = { fg = "light-gray" } "ui.linenr" = { fg = "light-gray" } "ui.linenr.selected" = { fg = "white", modifiers = ["bold"] } "ui.popup" = { fg = "white" } "ui.window" = { fg = "white" } -"ui.selection" = { modifiers = [ "reversed"] } -"comment" = { fg = "gray", modifiers = ["italic"] } +"ui.selection" = { bg = "gray" } +"comment" = "light-gray" "ui.statusline" = { fg = "white" } "ui.statusline.inactive" = { fg = "gray" } -"ui.statusline.normal" = { fg = "blue", modifiers = ["reversed"] } -"ui.statusline.insert" = { fg = "green", modifiers = ["reversed"] } -"ui.statusline.select" = { fg = "magenta", modifiers = ["reversed"] } +"ui.statusline.normal" = { fg = "black", bg = "blue" } +"ui.statusline.insert" = { fg = "black", bg = "green" } +"ui.statusline.select" = { fg = "black", bg = "magenta" } "ui.help" = { fg = "light-gray" } "ui.cursor" = { modifiers = ["reversed"] } -"ui.cursor.match" = { fg = "light-yellow", modifiers = ["underlined"] } +"ui.cursor.match" = { fg = "light-yellow", underline = { color = "light-yellow", style = "line" } } "ui.cursor.primary" = { modifiers = ["reversed", "slow_blink"] } "ui.cursor.secondary" = { modifiers = ["reversed"] } -"ui.virtual.ruler" = { fg = "gray", modifiers = ["reversed"] } +"ui.virtual.ruler" = { bg = "gray" } "ui.virtual.whitespace" = "gray" "ui.virtual.indent-guide" = "gray" @@ -44,7 +45,7 @@ "markup.list" = "light-red" "markup.bold" = { fg = "light-yellow", modifiers = ["bold"] } "markup.italic" = { fg = "light-magenta", modifiers = ["italic"] } -"markup.link.url" = { fg = "yellow", modifiers = ["underlined"] } +"markup.link.url" = { fg = "yellow", underline = { color = "yellow", style = "line"} } "markup.link.text" = "light-red" "markup.quote" = "light-cyan" "markup.raw" = "green" @@ -53,19 +54,19 @@ "markup.select" = { fg = "magenta" } "diff.plus" = "light-green" -"diff.delta" = "yellow" +"diff.delta" = "light-blue" +"diff.delta.moved" = "blue" "diff.minus" = "light-red" -"ui.gutter" = "gray" -"info" = "light-blue" -"hint" = "gray" -"debug" = "gray" -"warning" = "yellow" -"error" = "light-red" +"ui.gutter" = "gray" +"info" = "light-blue" +"hint" = "light-gray" +"debug" = "light-gray" +"warning" = "light-yellow" +"error" = "light-red" -"diagnostic" = { modifiers = ["underlined"] } -"diagnostic.info" = { fg = "light-blue", modifiers = ["underlined"] } -"diagnostic.hint" = { fg = "gray", modifiers = ["underlined"] } -"diagnostic.debug" ={ fg ="gray", modifiers = ["underlined"] } -"diagnostic.warning" = { fg = "yellow", modifiers = ["underlined"] } -"diagnostic.error" = { fg ="light-red", modifiers = ["underlined"] } +"diagnostic.info" = { underline = { color = "light-blue", style = "dotted" } } +"diagnostic.hint" = { underline = { color = "light-gray", style = "double_line" } } +"diagnostic.debug" = { underline ={ color ="light-gray", style = "dashed" } } +"diagnostic.warning" = { underline = { color = "light-yellow", style = "curl" } } +"diagnostic.error" = { underline = { color ="light-red", style = "curl" } } diff --git a/runtime/themes/dark_high_contrast.toml b/runtime/themes/dark_high_contrast.toml index c65750f4ee01..1c911eb5fc94 100644 --- a/runtime/themes/dark_high_contrast.toml +++ b/runtime/themes/dark_high_contrast.toml @@ -9,29 +9,29 @@ "ui.text.focus" = { modifiers = ["reversed"] } # file picker selected "ui.virtual.whitespace" = "gray" -"ui.virtual.ruler" = { fg = "gray", bg = "white", modifiers = ["reversed"] } +"ui.virtual.ruler" = { fg = "white", bg = "gray" } "ui.virtual.indent-guide" = "white" "ui.statusline" = { fg = "white", bg = "deep_blue" } -"ui.statusline.inactive" = { fg = "gray" } +"ui.statusline.inactive" = { fg = "gray", bg = "deep_blue" } "ui.statusline.normal" = { fg = "black", bg = "aqua" } "ui.statusline.insert" = { fg = "black", bg = "orange" } "ui.statusline.select" = { fg = "black", bg = "purple" } -# "ui.statusline.separator" = { fg = "aqua", bg = "white" } +"ui.statusline.separator" = { fg = "aqua", bg = "white" } "ui.cursor" = { fg = "black", bg = "white" } "ui.cursor.insert" = { fg = "black", bg = "white" } "ui.cursor.select" = { fg = "black", bg = "white" } "ui.cursor.match" = { bg = "white", modifiers = ["dim"] } "ui.cursor.primary" = { fg = "black", bg = "white", modifiers = ["slow_blink"] } - "ui.cursor.secondary" = "white" -"ui.cursorline.primary" = { fg = "orange", modifiers = ["underlined"] } -"ui.cursorline.secondary" = { fg = "orange", modifiers = ["underlined"] } -"ui.selection" = { fg = "deep_blue", bg = "white" } +"ui.cursorline.primary" = { bg = "deep_blue", underline = { color = "orange", style = "double_line" } } +"ui.cursorline.secondary" = { bg = "dark_blue", underline = { color = "white", style = "line" } } +"ui.selection" = { fg = "dark_blue", bg = "white" } +"ui.selection.primary" = { fg = "deep_blue", bg = "white" } "ui.menu" = { fg = "white", bg = "deep_blue" } -"ui.menu.selected" = { fg = "orange", modifiers = ["underlined"] } +"ui.menu.selected" = { fg = "orange", underline = { style = "line" } } "ui.menu.scroll" = { fg = "aqua", bg = "black" } "ui.help" = { fg = "white", bg = "deep_blue" } @@ -39,15 +39,16 @@ "ui.popup.info" = { fg = "white", bg = "deep_blue" } "ui.gutter" = { bg = "black" } +"ui.gutter.selected" = { bg = "black" } "ui.linenr" = { fg = "white", bg = "black" } "ui.linenr.selected" = { fg = "orange", bg = "black", modifiers = ["bold"] } # Diagnostic -"diagnostic" = "white" -"diagnostic.info" = { bg = "white", modifiers = ["underlined"] } -"diagnostic.hint" = { fg = "yellow", modifiers = ["underlined"] } -"diagnostic.warning" = { fg = "orange", modifiers = ["underlined"] } -"diagnostic.error" = { fg = "red", modifiers = ["underlined"] } +"diagnostic" = { fg = "white" } +"diagnostic.info" = { underline = { color = "white", style = "dotted" } } +"diagnostic.hint" = { underline = { color = "yellow", style = "dashed" } } +"diagnostic.warning" = { underline = { color = "orange", style = "curl" } } +"diagnostic.error" = { underline = { color = "red", style = "curl" } } "info" = "white" "hint" = "yellow" "warning" = "orange" @@ -59,31 +60,31 @@ "diff.minus" = "pink" # Syntax high light -"type" = { fg = "emerald_green" } +"type" = "emerald_green" "type.buildin" = "emerald_green" -"comment" = { fg = "white" } +"comment" = "white" "operator" = "white" -"variable" = { fg = "aqua" } +"variable" = "aqua" "variable.other.member" = "brown" "constant" = "aqua" "constant.numeric" = "emerald_green" -"attributes" = { fg = "blue" } +"attributes" = "blue" "namespace" = "blue" "string" = "brown" -"string.special.url" = { fg = "brown", modifiers =["underlined"]} +"string.special.url" = "brown" "constant.character.escape" = "yellow" "constructor" = "aqua" -"keyword" = { fg = "blue", modifiers = ["underlined"] } +"keyword" = "blue" "keyword.control" = "purple" "function" = "yellow" "label" = "blue" # Markup -"markup.heading" = { fg = "yellow", modifiers = ["bold", "underlined"] } -"markup.list" = { fg = "pink" } +"markup.heading" = { fg = "yellow", modifiers = ["bold"], underline = { color = "yellow", style = "double_line"} } +"markup.list" = "pink" "markup.bold" = { fg = "emerald_green", modifiers = ["bold"] } "markup.italic" = { fg = "blue", modifiers = ["italic"] } -"markup.link.url" = { fg = "blue", modifiers = ["underlined"] } +"markup.link.url" = { fg = "blue", underline = { color = "blue", style = "line" } } "markup.link.text" = "pink" "markup.quote" = "yellow" "markup.raw" = "brown" @@ -94,6 +95,7 @@ gray = "#585858" white = "#ffffff" blue = "#66a4ff" deep_blue = "#142743" +dark_blue = "#0d1a2d" aqua = "#6fc3df" purple = "#c586c0" red = "#b65f5f" From a34ba071be0a48a35f36ada7759dee53d783e57b Mon Sep 17 00:00:00 2001 From: garlic0x1 <43155857+garlic0x1@users.noreply.github.com> Date: Sun, 11 Dec 2022 19:59:27 -0600 Subject: [PATCH 114/269] Fix commonlisp filetypes typo and auto-pairs (#5091) --- languages.toml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 06af52bd340e..dae675dfc14d 100644 --- a/languages.toml +++ b/languages.toml @@ -918,13 +918,19 @@ grammar = "scheme" name = "common-lisp" scope = "source.lisp" roots = [] -file-types = ["lisp", "asd", "cl", "l", "lsp", "ny"," podsl", "sexp"] +file-types = ["lisp", "asd", "cl", "l", "lsp", "ny", "podsl", "sexp"] shebangs = ["lisp", "sbcl", "ccl", "clisp", "ecl"] comment-token = ";" indent = { tab-width = 2, unit = " " } language-server = { command = "cl-lsp", args = [ "stdio" ] } grammar = "scheme" +[language.auto-pairs] +'(' = ')' +'{' = '}' +'[' = ']' +'"' = '"' + [[language]] name = "comment" scope = "scope.comment" From d5ab974d38fd5565a63c8d7c35967c77c0e434d0 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 12 Dec 2022 02:59:53 +0100 Subject: [PATCH 115/269] chore(book): link repository (#5101) --- book/book.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/book/book.toml b/book/book.toml index 2277a0bd9dc6..9835145cea3f 100644 --- a/book/book.toml +++ b/book/book.toml @@ -9,3 +9,4 @@ edit-url-template = "https://github.com/helix-editor/helix/tree/master/book/{pat cname = "docs.helix-editor.com" default-theme = "colibri" preferred-dark-theme = "colibri" +git-repository-url = "https://github.com/helix-editor/helix" From 0b960216433956503e9e6fe5220523eb1970eaee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schl=C3=B6gl?= Date: Mon, 12 Dec 2022 03:06:24 +0100 Subject: [PATCH 116/269] Add `:pipe-to` typable command that ignores shell output (#4931) --- book/src/generated/typable-cmd.md | 1 + helix-term/src/commands/typed.rs | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 6390ef858e7b..66e6ac039c26 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -71,4 +71,5 @@ | `:insert-output` | Run shell command, inserting output before each selection. | | `:append-output` | Run shell command, appending output after each selection. | | `:pipe` | Pipe each selection to the shell command. | +| `:pipe-to` | Pipe each selection to the shell command, ignoring output. | | `:run-shell-command`, `:sh` | Run a shell command | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 03fcaa553a53..2119a48d67a4 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1741,13 +1741,30 @@ fn insert_output( Ok(()) } +fn pipe_to( + cx: &mut compositor::Context, + args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + pipe_impl(cx, args, event, &ShellBehavior::Ignore) +} + fn pipe(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> anyhow::Result<()> { + pipe_impl(cx, args, event, &ShellBehavior::Replace) +} + +fn pipe_impl( + cx: &mut compositor::Context, + args: &[Cow], + event: PromptEvent, + behavior: &ShellBehavior, +) -> anyhow::Result<()> { if event != PromptEvent::Validate { return Ok(()); } ensure!(!args.is_empty(), "Shell command required"); - shell(cx, &args.join(" "), &ShellBehavior::Replace); + shell(cx, &args.join(" "), behavior); Ok(()) } @@ -2292,6 +2309,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: pipe, completer: None, }, + TypableCommand { + name: "pipe-to", + aliases: &[], + doc: "Pipe each selection to the shell command, ignoring output.", + fun: pipe_to, + completer: None, + }, TypableCommand { name: "run-shell-command", aliases: &["sh"], From bae890d8faa993333d81e662b6f0a6bc5e921a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 12 Dec 2022 17:49:57 +0900 Subject: [PATCH 117/269] Update tree-sitter-scheme --- languages.toml | 2 +- runtime/queries/rust/highlights.scm | 11 +++++- runtime/queries/scheme/highlights.scm | 55 +++++++++++++-------------- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/languages.toml b/languages.toml index dae675dfc14d..e6bc344ccfee 100644 --- a/languages.toml +++ b/languages.toml @@ -1583,7 +1583,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "scheme" -source = { git = "https://github.com/6cdh/tree-sitter-scheme", rev = "27fb77db05f890c2823b4bd751c6420378df146b" } +source = { git = "https://github.com/6cdh/tree-sitter-scheme", rev = "c0741320bfca6b7b5b7a13b5171275951e96a842" } [[language]] name = "v" diff --git a/runtime/queries/rust/highlights.scm b/runtime/queries/rust/highlights.scm index 5606e93d3007..d3c292708b63 100644 --- a/runtime/queries/rust/highlights.scm +++ b/runtime/queries/rust/highlights.scm @@ -5,8 +5,6 @@ ; overrides are unnecessary. ; ------- - - ; ------- ; Types ; ------- @@ -241,6 +239,14 @@ +(attribute + (identifier) @_macro + arguments: (token_tree (identifier) @constant.numeric.integer) + (#eq? @_macro "derive") +) +@special + + ; ------- ; Functions ; ------- @@ -271,6 +277,7 @@ ; --- ; Macros ; --- + (attribute (identifier) @function.macro) (attribute diff --git a/runtime/queries/scheme/highlights.scm b/runtime/queries/scheme/highlights.scm index 3b7a42755b1b..468193745d93 100644 --- a/runtime/queries/scheme/highlights.scm +++ b/runtime/queries/scheme/highlights.scm @@ -2,29 +2,40 @@ (character) @constant.character (boolean) @constant.builtin.boolean -[(string) - (character)] @string +(string) @string (escape_sequence) @constant.character.escape -[(comment) - (block_comment) - (directive)] @comment +(comment) @comment.line +(block_comment) @comment.block +(directive) @keyword.directive -[(boolean) - (character)] @constant +; operators -((symbol) @function.builtin - (#match? @function.builtin "^(eqv\\?|eq\\?|equal\\?)")) ; TODO +((symbol) @operator + (#match? @operator "^(\\+|-|\\*|/|=|>|<|>=|<=)$")) ; keywords -((symbol) @keyword.conditional - (#match? @keyword.conditional "^(if|cond|case|when|unless)$")) +(list + . + ((symbol) @keyword.conditional + (#match? @keyword.conditional "^(if|cond|case|when|unless)$" + ))) -((symbol) @keyword - (#match? @keyword - "^(define|lambda|begin|do|define-syntax|and|or|if|cond|case|when|unless|else|=>|let|let*|let-syntax|let-values|let*-values|letrec|letrec*|letrec-syntax|set!|syntax-rules|identifier-syntax|quote|unquote|quote-splicing|quasiquote|unquote-splicing|delay|assert|library|export|import|rename|only|except|prefix)$")) +(list + . + (symbol) @keyword + (#match? @keyword + "^(define-syntax|let\\*|lambda|λ|case|=>|quote-splicing|unquote-splicing|set!|let|letrec|letrec-syntax|let-values|let\\*-values|do|else|define|cond|syntax-rules|unquote|begin|quote|let-syntax|and|if|quasiquote|letrec|delay|or|when|unless|identifier-syntax|assert|library|export|import|rename|only|except|prefix)$" + )) + +(list + . + (symbol) @function.builtin + (#match? @function.builtin + "^(caar|cadr|call-with-input-file|call-with-output-file|cdar|cddr|list|open-input-file|open-output-file|with-input-from-file|with-output-to-file|\\*|\\+|-|/|<|<=|=|>|>=|abs|acos|angle|append|apply|asin|assoc|assq|assv|atan|boolean\\?|caaaar|caaadr|caaar|caadar|caaddr|caadr|cadaar|cadadr|cadar|caddar|cadddr|caddr|call-with-current-continuation|call-with-values|car|cdaaar|cdaadr|cdaar|cdadar|cdaddr|cdadr|cddaar|cddadr|cddar|cdddar|cddddr|cdddr|cdr|ceiling|char->integer|char-alphabetic\\?|char-ci<=\\?|char-ci<\\?|char-ci=\\?|char-ci>=\\?|char-ci>\\?|char-downcase|char-lower-case\\?|char-numeric\\?|char-ready\\?|char-upcase|char-upper-case\\?|char-whitespace\\?|char<=\\?|char<\\?|char=\\?|char>=\\?|char>\\?|char\\?|close-input-port|close-output-port|complex\\?|cons|cos|current-error-port|current-input-port|current-output-port|denominator|display|dynamic-wind|eof-object\\?|eq\\?|equal\\?|eqv\\?|eval|even\\?|exact->inexact|exact\\?|exp|expt|floor|flush-output|for-each|force|gcd|imag-part|inexact->exact|inexact\\?|input-port\\?|integer->char|integer\\?|interaction-environment|lcm|length|list->string|list->vector|list-ref|list-tail|list\\?|load|log|magnitude|make-polar|make-rectangular|make-string|make-vector|map|max|member|memq|memv|min|modulo|negative\\?|newline|not|null-environment|null\\?|number->string|number\\?|numerator|odd\\?|output-port\\?|pair\\?|peek-char|positive\\?|procedure\\?|quotient|rational\\?|rationalize|read|read-char|real-part|real\\?|remainder|reverse|round|scheme-report-environment|set-car!|set-cdr!|sin|sqrt|string|string->list|string->number|string->symbol|string-append|string-ci<=\\?|string-ci<\\?|string-ci=\\?|string-ci>=\\?|string-ci>\\?|string-copy|string-fill!|string-length|string-ref|string-set!|string<=\\?|string<\\?|string=\\?|string>=\\?|string>\\?|string\\?|substring|symbol->string|symbol\\?|tan|transcript-off|transcript-on|truncate|values|vector|vector->list|vector-fill!|vector-length|vector-ref|vector-set!|vector\\?|write|write-char|zero\\?)$" + )) ; special forms @@ -47,26 +58,16 @@ . (list (list - (symbol) @variable)) + (symbol) @variable.parameter)) (#match? @_f "^(let|let\\*|let-syntax|let-values|let\\*-values|letrec|letrec\\*|letrec-syntax)$")) -; operators - -(list - . - (symbol) @operator - (#match? @operator "^([+*/<>=-]|(<=)|(>=))$")) - ; quote -(abbreviation - "'" (symbol)) @constant - (list . (symbol) @_f - (#eq? @_f "quote")) @symbol + (#eq? @_f "quote")) @string.symbol ; library @@ -89,12 +90,10 @@ ((symbol) @variable.builtin (#eq? @variable.builtin "...")) -(symbol) @variable ((symbol) @variable.builtin (#eq? @variable.builtin ".")) (symbol) @variable - ["(" ")" "[" "]" "{" "}"] @punctuation.bracket From f995f2610b3ad3aa68cec42ea14ce067a1ed3655 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Dec 2022 17:20:26 -0600 Subject: [PATCH 118/269] build(deps): bump serde from 1.0.149 to 1.0.150 (#5138) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.149 to 1.0.150. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.149...v1.0.150) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b204214fc42e..040a039c4f2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1805,18 +1805,18 @@ checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" [[package]] name = "serde" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055" +checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4" +checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e" dependencies = [ "proc-macro2", "quote", From fa436fa680b5bcf6d46666a03ae23b94a74e0414 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Dec 2022 17:25:05 -0600 Subject: [PATCH 119/269] build(deps): bump tokio from 1.22.0 to 1.23.0 (#5137) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.22.0 to 1.23.0. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.22.0...tokio-1.23.0) --- updated-dependencies: - dependency-name: tokio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- helix-lsp/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 040a039c4f2b..6ae0a71f8c1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2100,9 +2100,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.22.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" +checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" dependencies = [ "autocfg", "bytes", @@ -2115,7 +2115,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "winapi", + "windows-sys", ] [[package]] diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index 05c5467ea8ac..d04edcd52288 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -23,6 +23,6 @@ lsp-types = { version = "0.93", features = ["proposed"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" -tokio = { version = "1.22", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } +tokio = { version = "1.23", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } tokio-stream = "0.1.11" which = "4.2" From 00092a29c4f8ca7402455a9a494147ee3521bd4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Tue, 13 Dec 2022 15:07:20 +0900 Subject: [PATCH 120/269] Use dtolnay/rust-toolchain in more places --- .github/workflows/build.yml | 9 ++------ .github/workflows/release.yml | 42 ++++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index deeff80e1059..3a4896f1ecf1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,10 +44,7 @@ jobs: uses: actions/checkout@v3 - name: Install stable toolchain - uses: helix-editor/rust-toolchain@v1 - with: - profile: minimal - override: true + uses: dtolnay/rust-toolchain@1.61 - uses: Swatinem/rust-cache@v2 @@ -76,10 +73,8 @@ jobs: uses: actions/checkout@v3 - name: Install stable toolchain - uses: helix-editor/rust-toolchain@v1 + uses: dtolnay/rust-toolchain@1.61 with: - profile: minimal - override: true components: rustfmt, clippy - uses: Swatinem/rust-cache@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c242f089464b..8c105bfcf317 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,10 +26,7 @@ jobs: uses: actions/checkout@v3 - name: Install stable toolchain - uses: helix-editor/rust-toolchain@v1 - with: - profile: minimal - override: true + uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 @@ -47,6 +44,16 @@ jobs: dist: name: Dist needs: [fetch-grammars] + env: + # For some builds, we use cross to test on 32-bit and big-endian + # systems. + CARGO: cargo + # When CARGO is set to CROSS, this is set to `--target matrix.target`. + TARGET_FLAGS: + # When CARGO is set to CROSS, TARGET_DIR includes matrix.target. + TARGET_DIR: ./target + # Emit backtraces on panics. + RUST_BACKTRACE: 1 runs-on: ${{ matrix.os }} strategy: fail-fast: false # don't fail other jobs if one fails @@ -107,12 +114,10 @@ jobs: tar xJf grammars/grammars.tar.xz -C runtime/grammars/sources - name: Install ${{ matrix.rust }} toolchain - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: - profile: minimal toolchain: ${{ matrix.rust }} target: ${{ matrix.target }} - override: true # Install a pre-release version of Cross # TODO: We need to pre-install Cross because we need cross-rs/cross#591 to @@ -120,15 +125,20 @@ jobs: # 0.3.0, which includes cross-rs/cross#591, is released. - name: Install Cross if: "matrix.cross" - run: cargo install cross --git https://github.com/cross-rs/cross.git --rev 47df5c76e7cba682823a0b6aa6d95c17b31ba63a + run: | + cargo install cross --git https://github.com/cross-rs/cross.git --rev 47df5c76e7cba682823a0b6aa6d95c17b31ba63a + echo "CARGO=cross" >> $GITHUB_ENV + # echo "TARGET_FLAGS=--target ${{ matrix.target }}" >> $GITHUB_ENV + # echo "TARGET_DIR=./target/${{ matrix.target }}" >> $GITHUB_ENV + + - name: Show command used for Cargo + run: | + echo "cargo command is: ${{ env.CARGO }}" + echo "target flag is: ${{ env.TARGET_FLAGS }}" - name: Run cargo test - uses: actions-rs/cargo@v1 if: "!matrix.skip_tests" - with: - use-cross: ${{ matrix.cross }} - command: test - args: --release --locked --target ${{ matrix.target }} --workspace + run: ${{ env.CARGO }} test --release --locked --target ${{ matrix.target }} --workspace - name: Set profile.release.strip = true shell: bash @@ -139,11 +149,7 @@ jobs: EOF - name: Build release binary - uses: actions-rs/cargo@v1 - with: - use-cross: ${{ matrix.cross }} - command: build - args: --release --locked --target ${{ matrix.target }} + run: ${{ env.CARGO }} build --release --locked --target ${{ matrix.target }} - name: Build AppImage shell: bash From e6fce860b10faab1cb50b7709a67ded113364392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Tue, 13 Dec 2022 15:08:24 +0900 Subject: [PATCH 121/269] Use latest github runner images --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8c105bfcf317..9518a5373ccb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -61,17 +61,17 @@ jobs: build: [x86_64-linux, x86_64-macos, x86_64-windows] #, x86_64-win-gnu, win32-msvc include: - build: x86_64-linux - os: ubuntu-20.04 + os: ubuntu-latest rust: stable target: x86_64-unknown-linux-gnu cross: false - build: aarch64-linux - os: ubuntu-20.04 + os: ubuntu-latest rust: stable target: aarch64-unknown-linux-gnu cross: true - build: riscv64-linux - os: ubuntu-20.04 + os: ubuntu-latest rust: stable target: riscv64gc-unknown-linux-gnu cross: true @@ -81,7 +81,7 @@ jobs: target: x86_64-apple-darwin cross: false - build: x86_64-windows - os: windows-2019 + os: windows-latest rust: stable target: x86_64-pc-windows-msvc cross: false From 0f2ae35a1336d5fef823127dc134ed5675e5b9cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Tue, 13 Dec 2022 15:14:40 +0900 Subject: [PATCH 122/269] ci: Merge two jobs --- .github/workflows/build.yml | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3a4896f1ecf1..0d6fcb3e8426 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -98,13 +98,13 @@ jobs: uses: actions/checkout@v3 - name: Install stable toolchain - uses: helix-editor/rust-toolchain@v1 - with: - profile: minimal - override: true + uses: dtolnay/rust-toolchain@1.61 - uses: Swatinem/rust-cache@v2 + - name: Validate queries + run: cargo xtask query-check + - name: Generate docs run: cargo xtask docgen @@ -115,20 +115,3 @@ jobs: || (echo "Run 'cargo xtask docgen', commit the changes and push again" \ && exit 1) - queries: - name: Tree-sitter queries - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - name: Install stable toolchain - uses: helix-editor/rust-toolchain@v1 - with: - profile: minimal - override: true - - - uses: Swatinem/rust-cache@v2 - - - name: Generate docs - run: cargo xtask query-check From 436296b76c671446aab8863b467155ff9e94d4fc Mon Sep 17 00:00:00 2001 From: Erasin Date: Wed, 14 Dec 2022 21:51:00 +0800 Subject: [PATCH 123/269] Add Mermaid.js for markdown support (#5147) --- book/src/generated/lang-support.md | 1 + languages.toml | 13 ++ runtime/queries/mermaid/highlights.scm | 187 +++++++++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 runtime/queries/mermaid/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 4dca810478db..fa7b6edd30f1 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -77,6 +77,7 @@ | make | ✓ | | | | | markdown | ✓ | | | `marksman` | | markdown.inline | ✓ | | | | +| mermaid | ✓ | | | | | meson | ✓ | | ✓ | | | mint | | | | `mint` | | nickel | ✓ | | ✓ | `nls` | diff --git a/languages.toml b/languages.toml index e6bc344ccfee..e28476d3118a 100644 --- a/languages.toml +++ b/languages.toml @@ -2043,3 +2043,16 @@ grammar = "qmljs" [[grammar]] name = "qmljs" source = { git = "https://github.com/yuja/tree-sitter-qmljs", rev = "0b2b25bcaa7d4925d5f0dda16f6a99c588a437f1" } + +[[language]] +name = "mermaid" +scope = "source.mermaid" +injection-regex = "mermaid" +file-types = ["mermaid"] +roots = [] +comment-token = "%%" +indent = { tab-width = 4, unit = " " } + +[[grammar]] +name = "mermaid" +source = { git = "https://github.com/monaqa/tree-sitter-mermaid", rev = "d787c66276e7e95899230539f556e8b83ee16f6d" } diff --git a/runtime/queries/mermaid/highlights.scm b/runtime/queries/mermaid/highlights.scm new file mode 100644 index 000000000000..b546d39f27ab --- /dev/null +++ b/runtime/queries/mermaid/highlights.scm @@ -0,0 +1,187 @@ +[ + "sequenceDiagram" + "classDiagram" + "classDiagram-v2" + "stateDiagram" + "stateDiagram-v2" + "gantt" + "pie" + "flowchart" + "erdiagram" + + "participant" + "as" + "activate" + "deactivate" + "note " + "over" + "link" + "links" + ; "left of" + ; "right of" + "properties" + "details" + "title" + "loop" + "rect" + "opt" + "alt" + "else" + "par" + "and" + "end" + (sequence_stmt_autonumber) + (note_placement_left) + (note_placement_right) + + "class" + + "state " + + "dateformat" + "inclusiveenddates" + "topaxis" + "axisformat" + "includes" + "excludes" + "todaymarker" + "title" + "section" + + "direction" + "subgraph" + + ] @keyword + +[ + (comment) + ] @comment + +(flow_vertex_id) @type +(flow_arrow_text) @label +(flow_text_literal) @string + +[ + ":" + (sequence_signal_plus_sign) + (sequence_signal_minus_sign) + + (class_visibility_public) + (class_visibility_private) + (class_visibility_protected) + (class_visibility_internal) + + (state_division) + ] @punctuation.delimiter + +[ + "(" + ")" + "{" + "}" + ] @punctuation.bracket + +[ + "-->" + (solid_arrow) + (dotted_arrow) + (solid_open_arrow) + (dotted_open_arrow) + (solid_cross) + (dotted_cross) + (solid_point) + (dotted_point) + ] @operator + +[ + (class_reltype_aggregation) + (class_reltype_extension) + (class_reltype_composition) + (class_reltype_dependency) + (class_linetype_solid) + (class_linetype_dotted) + "&" + ] @operator + +(sequence_actor) @variable +(sequence_text) @string + +(class_name) @type +(class_label) @string +(class_method_line) @function.method + +(state_name) @variable + +(gantt_section) @markup.heading +(gantt_task_text) @variable.builtin +(gantt_task_data) @string + +[ + (class_annotation_line) + (class_stmt_annotation) + (class_generics) + + (state_annotation_fork) + (state_annotation_join) + (state_annotation_choice) + ] @type + +(directive) @keyword.directive + +(pie_label) @string +(pie_value) @constant.numeric + +[ +(flowchart_direction_lr) +(flowchart_direction_rl) +(flowchart_direction_tb) +(flowchart_direction_bt) + ] @constant + +(flow_vertex_id) @variable + +[ + (flow_link_arrow) + (flow_link_arrow_start) + ] @operator + +(flow_link_arrowtext "|" @punctuation.bracket) + +(flow_vertex_square [ "[" "]" ] @punctuation.bracket ) +(flow_vertex_circle ["((" "))"] @punctuation.bracket ) +(flow_vertex_ellipse ["(-" "-)"] @punctuation.bracket ) +(flow_vertex_stadium ["([" "])"] @punctuation.bracket ) +(flow_vertex_subroutine ["[[" "]]"] @punctuation.bracket ) +(flow_vertex_rect ["[|" "|]"] @punctuation.bracket ) +(flow_vertex_cylinder ["[(" ")]"] @punctuation.bracket ) +(flow_vertex_round ["(" ")"] @punctuation.bracket ) +(flow_vertex_diamond ["{" "}"] @punctuation.bracket ) +(flow_vertex_hexagon ["{{" "}}"] @punctuation.bracket ) +(flow_vertex_odd [">" "]"] @punctuation.bracket ) +(flow_vertex_trapezoid ["[/" "\\]"] @punctuation.bracket ) +(flow_vertex_inv_trapezoid ["[\\" "/]"] @punctuation.bracket ) +(flow_vertex_leanright ["[/" "/]"] @punctuation.bracket ) +(flow_vertex_leanleft ["[\\" "\\]"] @punctuation.bracket ) + +(flow_stmt_subgraph ["[" "]"] @punctuation.bracket ) + +[ + (er_cardinarity_zero_or_one) + (er_cardinarity_zero_or_more) + (er_cardinarity_one_or_more) + (er_cardinarity_only_one) + (er_reltype_non_identifying) + (er_reltype_identifying) + ] @operator + +(er_entity_name) @variable + +(er_attribute_type) @type +(er_attribute_name) @variable + +[ + (er_attribute_key_type_pk) + (er_attribute_key_type_fk) + ] @keyword + +(er_attribute_comment) @string From 012fc12f97f4e8e0fc38af351388e41e8bc142d8 Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Wed, 14 Dec 2022 07:42:11 -0700 Subject: [PATCH 124/269] Add Bash indents (#5149) --- book/src/generated/lang-support.md | 2 +- runtime/queries/bash/indents.scm | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/bash/indents.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index fa7b6edd30f1..1400fa875795 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -2,7 +2,7 @@ | --- | --- | --- | --- | --- | | astro | ✓ | | | | | awk | ✓ | ✓ | | `awk-language-server` | -| bash | ✓ | | | `bash-language-server` | +| bash | ✓ | | ✓ | `bash-language-server` | | bass | ✓ | | | `bass` | | beancount | ✓ | | | | | bibtex | ✓ | | | `texlab` | diff --git a/runtime/queries/bash/indents.scm b/runtime/queries/bash/indents.scm new file mode 100644 index 000000000000..f2077037d2e9 --- /dev/null +++ b/runtime/queries/bash/indents.scm @@ -0,0 +1,11 @@ +[ + (function_definition) + (if_statement) + (for_statement) + (case_statement) + (pipeline) +] @indent + +[ + "}" +] @outdent From db939801ebf299f11a6a52bdff7a3c9bfb87fc34 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Thu, 15 Dec 2022 02:49:49 -0600 Subject: [PATCH 125/269] Improve error message handling for theme loading failures (#5073) The error messages for a theme that failed to be deserialized (or otherwise failed to load) were covered up by the context/with_context calls: * The log message for a bad theme configured in config.toml would only say "Failed to deserilaize theme" * Selecting a bad theme via :theme would show "Theme does not exist" With these changes, we let the TOML deserializer errors bubble up, so the error messages can now say the line number of a duplicated key - and that key's name - when a theme fails to load because of a duplicated key. Providing a theme which does not exist to :theme still gives a helpful error message: "No such file or directory." --- helix-term/src/commands/typed.rs | 2 +- helix-view/src/theme.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 2119a48d67a4..cb387fcb5b64 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -777,7 +777,7 @@ fn theme( .editor .theme_loader .load(theme_name) - .with_context(|| "Theme does not exist")?; + .map_err(|err| anyhow::anyhow!("Could not load theme: {}", err))?; if !(true_color || theme.is_16_color()) { bail!("Unsupported theme: theme requires true color support"); } diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index f1219ec5dc17..b2c8a79f76aa 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -136,8 +136,9 @@ impl Loader { // Loads the theme data as `toml::Value` first from the user_dir then in default_dir fn load_toml(&self, path: PathBuf) -> Result { let data = std::fs::read(&path)?; + let value = toml::from_slice(data.as_slice())?; - toml::from_slice(data.as_slice()).context("Failed to deserialize theme") + Ok(value) } // Returns the path to the theme with the name From c64debc7412c0769db8186694bd89f85ea057b1b Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Tue, 19 Jul 2022 21:28:14 +0530 Subject: [PATCH 126/269] Add force_score() for scoring picker items without optimizations --- helix-term/src/ui/picker.rs | 45 +++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 5e9ca3d887a5..8b5d20eca6b8 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -469,34 +469,41 @@ impl Picker { self.matches.sort_unstable(); } else { - let query = FuzzyQuery::new(pattern); - self.matches.clear(); - self.matches.extend( - self.options - .iter() - .enumerate() - .filter_map(|(index, option)| { - let text = option.filter_text(&self.editor_data); - - query - .fuzzy_match(&text, &self.matcher) - .map(|score| PickerMatch { - index, - score, - len: text.chars().count(), - }) - }), - ); - self.matches.sort_unstable(); + self.force_score(); } log::debug!("picker score {:?}", Instant::now().duration_since(now)); // reset cursor position self.cursor = 0; + let pattern = self.prompt.line(); self.previous_pattern.clone_from(pattern); } + pub fn force_score(&mut self) { + let pattern = self.prompt.line(); + + let query = FuzzyQuery::new(pattern); + self.matches.clear(); + self.matches.extend( + self.options + .iter() + .enumerate() + .filter_map(|(index, option)| { + let text = option.filter_text(&self.editor_data); + + query + .fuzzy_match(&text, &self.matcher) + .map(|score| PickerMatch { + index, + score, + len: text.chars().count(), + }) + }), + ); + self.matches.sort_unstable(); + } + /// Move the cursor by a number of lines, either down (`Forward`) or up (`Backward`) pub fn move_by(&mut self, amount: usize, direction: Direction) { let len = self.matches.len(); From 914d2944997e11cf76eeabfe43f9031aeb2b1721 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Tue, 19 Jul 2022 21:49:02 +0530 Subject: [PATCH 127/269] Add DynamicPicker for updating options on every key --- helix-term/src/ui/mod.rs | 2 +- helix-term/src/ui/overlay.rs | 4 ++ helix-term/src/ui/picker.rs | 74 +++++++++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 107e48dd1ca3..5b5924bff0e8 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -19,7 +19,7 @@ pub use completion::Completion; pub use editor::EditorView; pub use markdown::Markdown; pub use menu::Menu; -pub use picker::{FileLocation, FilePicker, Picker}; +pub use picker::{DynamicPicker, FileLocation, FilePicker, Picker}; pub use popup::Popup; pub use prompt::{Prompt, PromptEvent}; pub use spinner::{ProgressSpinners, Spinner}; diff --git a/helix-term/src/ui/overlay.rs b/helix-term/src/ui/overlay.rs index 0b8a93ae833d..5b2bc806093d 100644 --- a/helix-term/src/ui/overlay.rs +++ b/helix-term/src/ui/overlay.rs @@ -69,4 +69,8 @@ impl Component for Overlay { let dimensions = (self.calc_child_size)(area); self.content.cursor(dimensions, ctx) } + + fn id(&self) -> Option<&'static str> { + self.content.id() + } } diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 8b5d20eca6b8..821a282cf61f 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -3,6 +3,7 @@ use crate::{ ctrl, key, shift, ui::{self, fuzzy_match::FuzzyQuery, EditorView}, }; +use futures_util::future::BoxFuture; use tui::{ buffer::Buffer as Surface, widgets::{Block, BorderType, Borders}, @@ -22,7 +23,7 @@ use helix_view::{ Document, DocumentId, Editor, }; -use super::menu::Item; +use super::{menu::Item, overlay::Overlay}; pub const MIN_AREA_WIDTH_FOR_PREVIEW: u16 = 72; /// Biggest file size to preview in bytes @@ -751,3 +752,74 @@ impl Component for Picker { self.prompt.cursor(area, editor) } } + +/// Returns a new list of options to replace the contents of the picker +/// when called with the current picker query, +pub type DynQueryCallback = + Box BoxFuture<'static, anyhow::Result>>>; + +/// A picker that updates its contents via a callback whenever the +/// query string changes. Useful for live grep, workspace symbols, etc. +pub struct DynamicPicker { + file_picker: FilePicker, + query_callback: DynQueryCallback, +} + +impl DynamicPicker { + pub const ID: &'static str = "dynamic-picker"; + + pub fn new(file_picker: FilePicker, query_callback: DynQueryCallback) -> Self { + Self { + file_picker, + query_callback, + } + } +} + +impl Component for DynamicPicker { + fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) { + self.file_picker.render(area, surface, cx); + } + + fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult { + let prev_query = self.file_picker.picker.prompt.line().to_owned(); + let event_result = self.file_picker.handle_event(event, cx); + let current_query = self.file_picker.picker.prompt.line(); + + if *current_query == prev_query || matches!(event_result, EventResult::Ignored(_)) { + return event_result; + } + + let new_options = (self.query_callback)(current_query.to_owned(), cx.editor); + + cx.jobs.callback(async move { + let new_options = new_options.await?; + let callback = + crate::job::Callback::EditorCompositor(Box::new(move |_editor, compositor| { + // Wrapping of pickers in overlay is done outside the picker code, + // so this is fragile and will break if wrapped in some other widget. + let picker = match compositor.find_id::>>(Self::ID) { + Some(overlay) => &mut overlay.content.file_picker.picker, + None => return, + }; + picker.options = new_options; + picker.cursor = 0; + picker.force_score(); + })); + anyhow::Ok(callback) + }); + EventResult::Consumed(None) + } + + fn cursor(&self, area: Rect, ctx: &Editor) -> (Option, CursorKind) { + self.file_picker.cursor(area, ctx) + } + + fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> { + self.file_picker.required_size(viewport) + } + + fn id(&self) -> Option<&'static str> { + Some(Self::ID) + } +} From d1f717eb8d02205ce224292f157bfe1bddd1f6db Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Tue, 19 Jul 2022 22:15:03 +0530 Subject: [PATCH 128/269] Re-request workspace symbols on keypress in picker Most language servers limit the number of workspace symbols that are returned with an empty query even though all symbols are supposed to be returned, according to the spec (for perfomance reasons). This patch adds a workspace symbol picker based on a dynamic picker that allows re-requesting the symbols on every keypress (i.e. when the picker query text changes). The old behavior has been completely replaced, and I have only tested with rust-analyzer so far. --- helix-term/src/commands/lsp.rs | 50 ++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 810e3adf1115..8052dcac2f48 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -1,3 +1,4 @@ +use futures_util::FutureExt; use helix_lsp::{ block_on, lsp::{self, CodeAction, CodeActionOrCommand, DiagnosticSeverity, NumberOrString}, @@ -14,7 +15,8 @@ use helix_view::{apply_transaction, document::Mode, editor::Action, theme::Style use crate::{ compositor::{self, Compositor}, ui::{ - self, lsp::SignatureHelp, overlay::overlayed, FileLocation, FilePicker, Popup, PromptEvent, + self, lsp::SignatureHelp, overlay::overlayed, DynamicPicker, FileLocation, FilePicker, + Popup, PromptEvent, }, }; @@ -384,10 +386,48 @@ pub fn workspace_symbol_picker(cx: &mut Context) { cx.callback( future, move |_editor, compositor, response: Option>| { - if let Some(symbols) = response { - let picker = sym_picker(symbols, current_url, offset_encoding); - compositor.push(Box::new(overlayed(picker))) - } + let symbols = match response { + Some(s) => s, + None => return, + }; + let picker = sym_picker(symbols, current_url, offset_encoding); + let get_symbols = |query: String, editor: &mut Editor| { + let doc = doc!(editor); + let language_server = match doc.language_server() { + Some(s) => s, + None => { + // This should not generally happen since the picker will not + // even open in the first place if there is no server. + return async move { Err(anyhow::anyhow!("LSP not active")) }.boxed(); + } + }; + let symbol_request = match language_server.workspace_symbols(query) { + Some(future) => future, + None => { + // This should also not happen since the language server must have + // supported workspace symbols before to reach this block. + return async move { + Err(anyhow::anyhow!( + "Language server does not support workspace symbols" + )) + } + .boxed(); + } + }; + + let future = async move { + let json = symbol_request.await?; + let response: Option> = + serde_json::from_value(json)?; + + response.ok_or_else(|| { + anyhow::anyhow!("No response for workspace symbols from language server") + }) + }; + future.boxed() + }; + let dyn_picker = DynamicPicker::new(picker, Box::new(get_symbols)); + compositor.push(Box::new(overlayed(dyn_picker))) }, ) } From a7daa02346789e43af51db2b944b0dc516354a29 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 7 Dec 2022 16:27:31 -0600 Subject: [PATCH 129/269] DynamicPicker: Use idle-timeout as debounce This change uses the idle-timeout event to trigger fetching new results in the DynamicPicker, so idle-timeout becomes a sort of debounce. This prevents querying the language server overly aggressively. --- helix-term/src/ui/picker.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 821a282cf61f..35597843bbf3 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -763,6 +763,7 @@ pub type DynQueryCallback = pub struct DynamicPicker { file_picker: FilePicker, query_callback: DynQueryCallback, + query: String, } impl DynamicPicker { @@ -772,6 +773,7 @@ impl DynamicPicker { Self { file_picker, query_callback, + query: String::new(), } } } @@ -782,14 +784,15 @@ impl Component for DynamicPicker { } fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult { - let prev_query = self.file_picker.picker.prompt.line().to_owned(); let event_result = self.file_picker.handle_event(event, cx); let current_query = self.file_picker.picker.prompt.line(); - if *current_query == prev_query || matches!(event_result, EventResult::Ignored(_)) { + if !matches!(event, Event::IdleTimeout) || self.query == *current_query { return event_result; } + self.query.clone_from(current_query); + let new_options = (self.query_callback)(current_query.to_owned(), cx.editor); cx.jobs.callback(async move { From 35cf972ce459eda6ceffb7a7c256a4bc9f4e6e39 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 7 Dec 2022 16:24:32 -0600 Subject: [PATCH 130/269] DynamicPicker: Reset idle timeout on refresh If the new results shown by the picker select a file that hasn't been previewed before, the idle timeout would not trigger highlighting on that file. With this change, we reset the idle timeout and allow that file to be highlighted on the next idle timeout event. --- helix-term/src/ui/picker.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 35597843bbf3..2d471aae6e8e 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -798,7 +798,7 @@ impl Component for DynamicPicker { cx.jobs.callback(async move { let new_options = new_options.await?; let callback = - crate::job::Callback::EditorCompositor(Box::new(move |_editor, compositor| { + crate::job::Callback::EditorCompositor(Box::new(move |editor, compositor| { // Wrapping of pickers in overlay is done outside the picker code, // so this is fragile and will break if wrapped in some other widget. let picker = match compositor.find_id::>>(Self::ID) { @@ -808,6 +808,7 @@ impl Component for DynamicPicker { picker.options = new_options; picker.cursor = 0; picker.force_score(); + editor.reset_idle_timer(); })); anyhow::Ok(callback) }); From 2a60de74f9ccc935fa65031cfe30c62cf07bbbaf Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Thu, 8 Dec 2022 19:54:15 -0600 Subject: [PATCH 131/269] workspace symbols: Default to empty Vec on None A language server might send None as the response to workspace symbols. We should treat this as the empty Vec rather than the server sending an error status. This fixes the interaction with gopls which uses None to mean no matching symbols. --- helix-term/src/commands/lsp.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 8052dcac2f48..86b0c5fa7417 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -386,10 +386,7 @@ pub fn workspace_symbol_picker(cx: &mut Context) { cx.callback( future, move |_editor, compositor, response: Option>| { - let symbols = match response { - Some(s) => s, - None => return, - }; + let symbols = response.unwrap_or_default(); let picker = sym_picker(symbols, current_url, offset_encoding); let get_symbols = |query: String, editor: &mut Editor| { let doc = doc!(editor); @@ -420,9 +417,7 @@ pub fn workspace_symbol_picker(cx: &mut Context) { let response: Option> = serde_json::from_value(json)?; - response.ok_or_else(|| { - anyhow::anyhow!("No response for workspace symbols from language server") - }) + Ok(response.unwrap_or_default()) }; future.boxed() }; From 42ad1a9e043e2e0fb148924ff79b9abbe06907ae Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Thu, 15 Dec 2022 02:57:31 -0600 Subject: [PATCH 132/269] Select diagnostic range in goto_*_diag commands (#4713) This roughly matches the behavior of the diagnostic picker: when jumping to a diagnostic with `[d`/`]d`/`[D`/`]D`, the range of the diagnostic is selected instead of the start point. --- helix-term/src/commands.rs | 50 +++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 1310417e47be..0f04ecba6c31 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2789,35 +2789,28 @@ fn exit_select_mode(cx: &mut Context) { } } -fn goto_pos(editor: &mut Editor, pos: usize) { - let (view, doc) = current!(editor); - - push_jump(view, doc); - doc.set_selection(view.id, Selection::point(pos)); - align_view(doc, view, Align::Center); -} - fn goto_first_diag(cx: &mut Context) { - let doc = doc!(cx.editor); - let pos = match doc.diagnostics().first() { - Some(diag) => diag.range.start, + let (view, doc) = current!(cx.editor); + let selection = match doc.diagnostics().first() { + Some(diag) => Selection::single(diag.range.start, diag.range.end), None => return, }; - goto_pos(cx.editor, pos); + doc.set_selection(view.id, selection); + align_view(doc, view, Align::Center); } fn goto_last_diag(cx: &mut Context) { - let doc = doc!(cx.editor); - let pos = match doc.diagnostics().last() { - Some(diag) => diag.range.start, + let (view, doc) = current!(cx.editor); + let selection = match doc.diagnostics().last() { + Some(diag) => Selection::single(diag.range.start, diag.range.end), None => return, }; - goto_pos(cx.editor, pos); + doc.set_selection(view.id, selection); + align_view(doc, view, Align::Center); } fn goto_next_diag(cx: &mut Context) { - let editor = &mut cx.editor; - let (view, doc) = current!(editor); + let (view, doc) = current!(cx.editor); let cursor_pos = doc .selection(view.id) @@ -2830,17 +2823,16 @@ fn goto_next_diag(cx: &mut Context) { .find(|diag| diag.range.start > cursor_pos) .or_else(|| doc.diagnostics().first()); - let pos = match diag { - Some(diag) => diag.range.start, + let selection = match diag { + Some(diag) => Selection::single(diag.range.start, diag.range.end), None => return, }; - - goto_pos(editor, pos); + doc.set_selection(view.id, selection); + align_view(doc, view, Align::Center); } fn goto_prev_diag(cx: &mut Context) { - let editor = &mut cx.editor; - let (view, doc) = current!(editor); + let (view, doc) = current!(cx.editor); let cursor_pos = doc .selection(view.id) @@ -2854,12 +2846,14 @@ fn goto_prev_diag(cx: &mut Context) { .find(|diag| diag.range.start < cursor_pos) .or_else(|| doc.diagnostics().last()); - let pos = match diag { - Some(diag) => diag.range.start, + let selection = match diag { + // NOTE: the selection is reversed because we're jumping to the + // previous diagnostic. + Some(diag) => Selection::single(diag.range.end, diag.range.start), None => return, }; - - goto_pos(editor, pos); + doc.set_selection(view.id, selection); + align_view(doc, view, Align::Center); } fn goto_first_change(cx: &mut Context) { From f916915b53fa6fedd3f9106bcf58163083cc052e Mon Sep 17 00:00:00 2001 From: Roberto Vidal Date: Thu, 15 Dec 2022 09:59:34 +0100 Subject: [PATCH 133/269] add redraw command (#4354) * add redraw command * update docs * Update helix-term/src/commands/typed.rs Co-authored-by: Michael Davis * update docs Co-authored-by: Michael Davis --- book/src/generated/typable-cmd.md | 1 + helix-term/src/commands/typed.rs | 29 +++++++++++++++++++++++++++++ helix-term/src/compositor.rs | 4 ++++ 3 files changed, 34 insertions(+) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 66e6ac039c26..269d63e37ce5 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -73,3 +73,4 @@ | `:pipe` | Pipe each selection to the shell command. | | `:pipe-to` | Pipe each selection to the shell command, ignoring output. | | `:run-shell-command`, `:sh` | Run a shell command | +| `:redraw` | Clear and re-render the whole UI | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index cb387fcb5b64..90dde7e144e6 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1808,6 +1808,28 @@ fn run_shell_command( Ok(()) } +fn redraw( + cx: &mut compositor::Context, + _args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + + let callback = Box::pin(async move { + let call: job::Callback = Box::new(|_editor, compositor| { + compositor.clear().expect("unable to redraw"); + }); + + Ok(call) + }); + + cx.jobs.callback(callback); + + Ok(()) +} + pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "quit", @@ -2323,6 +2345,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: run_shell_command, completer: Some(completers::directory), }, + TypableCommand { + name: "redraw", + aliases: &[], + doc: "Clear and re-render the whole UI", + fun: redraw, + completer: None, + }, ]; pub static TYPABLE_COMMAND_MAP: Lazy> = diff --git a/helix-term/src/compositor.rs b/helix-term/src/compositor.rs index 9dad36209c62..18620b7bb29c 100644 --- a/helix-term/src/compositor.rs +++ b/helix-term/src/compositor.rs @@ -197,6 +197,10 @@ impl Compositor { .find(|component| component.id() == Some(id)) .and_then(|component| component.as_any_mut().downcast_mut()) } + + pub fn clear(&mut self) -> std::io::Result<()> { + self.terminal.clear() + } } // View casting, taken straight from Cursive From 5c4a9cba9a14ca10437e979c884d2ccba78ef1e7 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Thu, 15 Dec 2022 14:20:26 +0100 Subject: [PATCH 134/269] Restore deleted goto_pos function (#5164) --- helix-term/src/commands.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 0f04ecba6c31..6cf494646d85 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2789,6 +2789,14 @@ fn exit_select_mode(cx: &mut Context) { } } +fn goto_pos(editor: &mut Editor, pos: usize) { + let (view, doc) = current!(editor); + + push_jump(view, doc); + doc.set_selection(view.id, Selection::point(pos)); + align_view(doc, view, Align::Center); +} + fn goto_first_diag(cx: &mut Context) { let (view, doc) = current!(cx.editor); let selection = match doc.diagnostics().first() { From ec9aa6690244bccefac24037c9f7a659816bffdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Thu, 15 Dec 2022 22:23:06 +0900 Subject: [PATCH 135/269] Remove redraw to fix build --- book/src/generated/typable-cmd.md | 1 - helix-term/src/commands/typed.rs | 29 ----------------------------- helix-term/src/compositor.rs | 4 ---- 3 files changed, 34 deletions(-) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 269d63e37ce5..66e6ac039c26 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -73,4 +73,3 @@ | `:pipe` | Pipe each selection to the shell command. | | `:pipe-to` | Pipe each selection to the shell command, ignoring output. | | `:run-shell-command`, `:sh` | Run a shell command | -| `:redraw` | Clear and re-render the whole UI | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 90dde7e144e6..cb387fcb5b64 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1808,28 +1808,6 @@ fn run_shell_command( Ok(()) } -fn redraw( - cx: &mut compositor::Context, - _args: &[Cow], - event: PromptEvent, -) -> anyhow::Result<()> { - if event != PromptEvent::Validate { - return Ok(()); - } - - let callback = Box::pin(async move { - let call: job::Callback = Box::new(|_editor, compositor| { - compositor.clear().expect("unable to redraw"); - }); - - Ok(call) - }); - - cx.jobs.callback(callback); - - Ok(()) -} - pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "quit", @@ -2345,13 +2323,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: run_shell_command, completer: Some(completers::directory), }, - TypableCommand { - name: "redraw", - aliases: &[], - doc: "Clear and re-render the whole UI", - fun: redraw, - completer: None, - }, ]; pub static TYPABLE_COMMAND_MAP: Lazy> = diff --git a/helix-term/src/compositor.rs b/helix-term/src/compositor.rs index 18620b7bb29c..9dad36209c62 100644 --- a/helix-term/src/compositor.rs +++ b/helix-term/src/compositor.rs @@ -197,10 +197,6 @@ impl Compositor { .find(|component| component.id() == Some(id)) .and_then(|component| component.as_any_mut().downcast_mut()) } - - pub fn clear(&mut self) -> std::io::Result<()> { - self.terminal.clear() - } } // View casting, taken straight from Cursive From 3e6887648c386372839e29028a3459d4674ce68b Mon Sep 17 00:00:00 2001 From: alice Date: Fri, 16 Dec 2022 15:43:58 +0100 Subject: [PATCH 136/269] set 'c++' as a recognised extension for cpp (#5183) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index e28476d3118a..d03726e72a91 100644 --- a/languages.toml +++ b/languages.toml @@ -190,7 +190,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-c", rev = "7175a6dd name = "cpp" scope = "source.cpp" injection-regex = "cpp" -file-types = ["cc", "hh", "cpp", "hpp", "h", "ipp", "tpp", "cxx", "hxx", "ixx", "txx", "ino"] +file-types = ["cc", "hh", "c++", "cpp", "hpp", "h", "ipp", "tpp", "cxx", "hxx", "ixx", "txx", "ino"] roots = [] comment-token = "//" language-server = { command = "clangd" } From 9c9c775a27f23b2fa5c8c856af0b15671916efd6 Mon Sep 17 00:00:00 2001 From: Ifiok Jr Date: Sat, 17 Dec 2022 15:09:14 +0000 Subject: [PATCH 137/269] Fix a typo in the docs (#5191) --- book/src/keymap.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index 139e8fddf613..153294007ee6 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -317,7 +317,7 @@ Mappings in the style of [vim-unimpaired](https://github.com/tpope/vim-unimpaire | `]c` | Go to next comment (**TS**) | `goto_next_comment` | | `[c` | Go to previous comment (**TS**) | `goto_prev_comment` | | `]T` | Go to next test (**TS**) | `goto_next_test` | -| `]T` | Go to previous test (**TS**) | `goto_prev_test` | +| `[T` | Go to previous test (**TS**) | `goto_prev_test` | | `]p` | Go to next paragraph | `goto_next_paragraph` | | `[p` | Go to previous paragraph | `goto_prev_paragraph` | | `]g` | Go to next change | `goto_next_change` | From b12c65678aacc577b070c70307ef6fce528e4d85 Mon Sep 17 00:00:00 2001 From: Eric Thorburn <60004386+hyderix@users.noreply.github.com> Date: Sat, 17 Dec 2022 20:03:18 +0100 Subject: [PATCH 138/269] Print the binary required by the debug adapter (#5195) This commit addresses issue 5193, where the author requested that the name of the binary needed is printed along with the rest of the health information. This commit adds a format! macro which formats in the name of the binary and then it will be printed along with the rest of the debug information. The value in cmd is referenced to the call to which, and then consumed upon the call to format! --- helix-term/src/health.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helix-term/src/health.rs b/helix-term/src/health.rs index e8fbb84d0982..6558fe19fb4c 100644 --- a/helix-term/src/health.rs +++ b/helix-term/src/health.rs @@ -281,9 +281,9 @@ fn probe_protocol(protocol_name: &str, server_cmd: Option) -> std::io::R writeln!(stdout, "Configured {}: {}", protocol_name, cmd_name)?; if let Some(cmd) = server_cmd { - let path = match which::which(cmd) { + let path = match which::which(&cmd) { Ok(path) => path.display().to_string().green(), - Err(_) => "Not found in $PATH".to_string().red(), + Err(_) => format!("'{}' not found in $PATH", cmd).red(), }; writeln!(stdout, "Binary for {}: {}", protocol_name, path)?; } From e6a2df8c798537a7dc5aff264eeccc773525aa6c Mon Sep 17 00:00:00 2001 From: Alex Kladov Date: Sat, 17 Dec 2022 19:30:43 +0000 Subject: [PATCH 139/269] Better sorting in picker in case of ties (#5169) --- helix-term/src/ui/mod.rs | 3 ++- helix-term/src/ui/picker.rs | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 5b5924bff0e8..ade1d8cf4c7f 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -207,13 +207,14 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi // Cap the number of files if we aren't in a git project, preventing // hangs when using the picker in your home directory - let files: Vec<_> = if root.join(".git").exists() { + let mut files: Vec = if root.join(".git").exists() { files.collect() } else { // const MAX: usize = 8192; const MAX: usize = 100_000; files.take(MAX).collect() }; + files.sort(); log::debug!("file_picker init {:?}", Instant::now().duration_since(now)); diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 2d471aae6e8e..aad3f81ceac3 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -12,7 +12,10 @@ use tui::{ use fuzzy_matcher::skim::SkimMatcherV2 as Matcher; use tui::widgets::Widget; -use std::{cmp::Ordering, time::Instant}; +use std::{ + cmp::{self, Ordering}, + time::Instant, +}; use std::{collections::HashMap, io::Read, path::PathBuf}; use crate::ui::{Prompt, PromptEvent}; @@ -344,11 +347,17 @@ impl Component for FilePicker { #[derive(PartialEq, Eq, Debug)] struct PickerMatch { - index: usize, score: i64, + index: usize, len: usize, } +impl PickerMatch { + fn key(&self) -> impl Ord { + (cmp::Reverse(self.score), self.len, self.index) + } +} + impl PartialOrd for PickerMatch { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) @@ -357,10 +366,7 @@ impl PartialOrd for PickerMatch { impl Ord for PickerMatch { fn cmp(&self, other: &Self) -> Ordering { - self.score - .cmp(&other.score) - .reverse() - .then_with(|| self.len.cmp(&other.len)) + self.key().cmp(&other.key()) } } @@ -502,6 +508,7 @@ impl Picker { }) }), ); + self.matches.sort_unstable(); } From aecb524e503363c2eed2a5a72d8fd881aae18e4b Mon Sep 17 00:00:00 2001 From: Jonas Everaert <62475953+Jomy10@users.noreply.github.com> Date: Sat, 17 Dec 2022 20:34:00 +0100 Subject: [PATCH 140/269] Crystal language support (#4993) --- book/src/generated/lang-support.md | 1 + languages.toml | 12 +++++ runtime/queries/crystal/highlights.scm | 66 ++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 runtime/queries/crystal/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 1400fa875795..73e0bfcd5f6a 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -16,6 +16,7 @@ | common-lisp | ✓ | | | `cl-lsp` | | cpon | ✓ | | ✓ | | | cpp | ✓ | ✓ | ✓ | `clangd` | +| crystal | ✓ | | | | | css | ✓ | | | `vscode-css-language-server` | | cue | ✓ | | | `cuelsp` | | d | ✓ | ✓ | ✓ | `serve-d` | diff --git a/languages.toml b/languages.toml index d03726e72a91..42495e5c08da 100644 --- a/languages.toml +++ b/languages.toml @@ -223,6 +223,18 @@ args = { console = "internalConsole", attachCommands = [ "platform select remote name = "cpp" source = { git = "https://github.com/tree-sitter/tree-sitter-cpp", rev = "d5e90fba898f320db48d81ddedd78d52c67c1fed" } +[[language]] +name = "crystal" +scope = "source.cr" +file-types = ["cr"] +roots = ["shard.yml", "shard.lock"] +comment-token = "#" +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "crystal" +source = { git = "https://github.com/will/tree-sitter-crystal", rev = "15597b307b18028b04d288561f9c29794621562b" } + [[language]] name = "c-sharp" scope = "source.csharp" diff --git a/runtime/queries/crystal/highlights.scm b/runtime/queries/crystal/highlights.scm new file mode 100644 index 000000000000..33a53e7f94cb --- /dev/null +++ b/runtime/queries/crystal/highlights.scm @@ -0,0 +1,66 @@ +[ + "class" + "struct" + "module" + + "def" + "alias" + "do" + "end" + + "require" + "include" + "extend" +] @keyword + +[ + "[" "]" + "(" ")" + "{" "}" +] @punctuation.bracket + +(operator) @operator + +(comment) @comment + +; literals + +(nil) @constant.builtin +(bool) @constant.builtin.boolean + +(integer) @constant.numeric.integer +(float) @constant.numeric.float + +[ + (string) + (char) + (commandLiteral) +] @string + +(symbol) @string.special.symbol + +(regex) @string.special.regex + +; variables + +(local_variable) @variable + +[ + (instance_variable) + (class_variable) +] @variable.other.member + +(constant) @constant + +; type defintitions + +(type_identifier) @constructor + +; method definition/call +(identifier) @function.method + +; types +(generic_type) @type +(union_type) @type +(type_identifier) @type + From 042d03269ecbe68e0461548bcf6918324c967bbb Mon Sep 17 00:00:00 2001 From: g-s-k Date: Sat, 17 Dec 2022 20:44:08 +0100 Subject: [PATCH 141/269] Add support for MATLAB/Octave files (#5192) --- book/src/generated/lang-support.md | 1 + languages.toml | 13 ++++ runtime/queries/matlab/highlights.scm | 97 +++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 runtime/queries/matlab/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 73e0bfcd5f6a..1a3aed79b914 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -78,6 +78,7 @@ | make | ✓ | | | | | markdown | ✓ | | | `marksman` | | markdown.inline | ✓ | | | | +| matlab | ✓ | | | | | mermaid | ✓ | | | | | meson | ✓ | | ✓ | | | mint | | | | `mint` | diff --git a/languages.toml b/languages.toml index 42495e5c08da..8972a6e94389 100644 --- a/languages.toml +++ b/languages.toml @@ -2068,3 +2068,16 @@ indent = { tab-width = 4, unit = " " } [[grammar]] name = "mermaid" source = { git = "https://github.com/monaqa/tree-sitter-mermaid", rev = "d787c66276e7e95899230539f556e8b83ee16f6d" } + +[[language]] +name = "matlab" +scope = "source.m" +file-types = ["m"] +comment-token = "%" +shebangs = ["octave-cli", "matlab"] +roots = [] +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "matlab" +source = { git = "https://github.com/mstanciu552/tree-sitter-matlab", rev = "2d5d3d5193718a86477d4335aba5b34e79147326" } diff --git a/runtime/queries/matlab/highlights.scm b/runtime/queries/matlab/highlights.scm new file mode 100644 index 000000000000..c0e23e917541 --- /dev/null +++ b/runtime/queries/matlab/highlights.scm @@ -0,0 +1,97 @@ + ; highlights.scm + +function_keyword: (function_keyword) @keyword.function + +(function_definition +function_name: (identifier) @function +(end) @function) + +(parameter_list (identifier) @variable.parameter) + +[ + "if" + "elseif" + "else" + "switch" + "case" + "otherwise" +] @keyword.control.conditional + +(if_statement (end) @keyword.control.conditional) +(switch_statement (end) @keyword.control.conditional) + +["for" "while"] @keyword.control.repeat +(for_statement (end) @keyword.control.repeat) +(while_statement (end) @keyword.control.repeat) + +["try" "catch"] @keyword.control.exception +(try_statement (end) @keyword.control.exception) + +(function_definition end: (end) @keyword) + +["return" "break" "continue"] @keyword.return + +( +(identifier) @constant.builtin +(#any-of? @constant.builtin "true" "false") +) + +( + (identifier) @constant.builtin + (#eq? @constant.builtin "end") +) + +;; Punctuations + +[";" ","] @punctuation.special +(argument_list "," @punctuation.delimiter) +(vector_definition ["," ";"] @punctuation.delimiter) +(cell_definition ["," ";"] @punctuation.delimiter) +":" @punctuation.delimiter +(parameter_list "," @punctuation.delimiter) +(return_value "," @punctuation.delimiter) + +; ;; Brackets + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +;; Operators +"=" @operator +(operation [ ">" + "<" + "==" + "<=" + ">=" + "=<" + "=>" + "~=" + "*" + ".*" + "/" + "\\" + "./" + "^" + ".^" + "+"] @operator) + +;; boolean operator +[ + "&&" + "||" +] @operator + +;; Number +(number) @constant.numeric + +;; String +(string) @string + +;; Comment +(comment) @comment From 24cd7f6adf7a46b8386583b17f01839eb592a2eb Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Sat, 10 Dec 2022 09:56:12 +0000 Subject: [PATCH 142/269] Make prompt suggestions greyed out --- book/src/themes.md | 1 + helix-term/src/ui/prompt.rs | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/book/src/themes.md b/book/src/themes.md index 322caea54b48..0f94828ebb9d 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -268,6 +268,7 @@ These scopes are used for theming the editor interface. | `ui.help` | Description box for commands | | `ui.text` | Command prompts, popup text, etc. | | `ui.text.focus` | | +| `ui.text.inactive` | Same as `ui.text` but when the text is inactive (e.g. suggestions) | | `ui.text.info` | The key: command text in `ui.popup.info` boxes | | `ui.virtual.ruler` | Ruler columns (see the [`editor.rulers` config][editor-section]) | | `ui.virtual.whitespace` | Visible whitespace characters | diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index b19b9a9fce90..5fb6745a90e5 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -352,6 +352,7 @@ impl Prompt { let prompt_color = theme.get("ui.text"); let completion_color = theme.get("ui.menu"); let selected_color = theme.get("ui.menu.selected"); + let suggestion_color = theme.get("ui.text.inactive"); // completion let max_len = self @@ -450,21 +451,29 @@ impl Prompt { // render buffer text surface.set_string(area.x, area.y + line, &self.prompt, prompt_color); - let input: Cow = if self.line.is_empty() { + let (input, is_suggestion): (Cow, bool) = if self.line.is_empty() { // latest value in the register list - self.history_register + match self + .history_register .and_then(|reg| cx.editor.registers.last(reg)) .map(|entry| entry.into()) - .unwrap_or_else(|| Cow::from("")) + { + Some(value) => (value, true), + None => (Cow::from(""), false), + } } else { - self.line.as_str().into() + (self.line.as_str().into(), false) }; surface.set_string( area.x + self.prompt.len() as u16, area.y + line, &input, - prompt_color, + if is_suggestion { + suggestion_color + } else { + prompt_color + }, ); } } From ba3c24aa0268735ac57321442d458ab6a1ac662c Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Sat, 10 Dec 2022 09:56:37 +0000 Subject: [PATCH 143/269] Set ui.text.inactive for official themes --- base16_theme.toml | 1 + theme.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/base16_theme.toml b/base16_theme.toml index 63fc2f790e72..268a38df61bd 100644 --- a/base16_theme.toml +++ b/base16_theme.toml @@ -7,6 +7,7 @@ "ui.linenr.selected" = { fg = "white", bg = "black", modifiers = ["bold"] } "ui.selection" = { fg = "black", bg = "blue" } "ui.selection.primary" = { fg = "white", bg = "blue" } +"ui.text.inactive" = { fg = "gray" } "comment" = { fg = "gray" } "ui.statusline" = { fg = "black", bg = "white" } "ui.statusline.inactive" = { fg = "gray", bg = "white" } diff --git a/theme.toml b/theme.toml index 054093195a87..c7b5dc84e7e0 100644 --- a/theme.toml +++ b/theme.toml @@ -54,6 +54,7 @@ label = "honey" "ui.text" = { fg = "lavender" } "ui.text.focus" = { fg = "white" } +"ui.text.inactive" = "sirocco" "ui.virtual" = { fg = "comet" } "ui.virtual.indent-guide" = { fg = "comet" } From 99b346a9238b9e7c5b9b93abdf787213c4d67f92 Mon Sep 17 00:00:00 2001 From: Lukas Werling Date: Mon, 19 Dec 2022 18:00:47 +0100 Subject: [PATCH 144/269] tutor: Fix typos in 8.2 (#5213) --- runtime/tutor | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime/tutor b/runtime/tutor index 418c4195487e..885ea0bffcc9 100644 --- a/runtime/tutor +++ b/runtime/tutor @@ -848,13 +848,13 @@ lines. Ensure your cursor is on the '>' of the arrow. 2. Type Q to start recording. 3. Edit the line to look like the bottom one. - 4. Exit insert and Type Q again to stop recording. + 4. Exit insert and type Q again to stop recording. 5. Move to the line below and put your cursor on '>' again. 6. Type q to repeat the macro. - --> ... sentence doesn't have it's first and last ... . - --> ... sentence doesn't have it's first and last ... . - This sentence doesn't have it's first and last word. + --> ... sentence doesn't have its first and last ... . + --> ... sentence doesn't have its first and last ... . + This sentence doesn't have its first and last word. ================================================================= = CHAPTER 8 RECAP = From 45c58961424cca35bcab692b49949d45d917ef7e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Dec 2022 17:16:26 -0600 Subject: [PATCH 145/269] build(deps): bump anyhow from 1.0.66 to 1.0.68 (#5222) Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.66 to 1.0.68. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.66...1.0.68) --- updated-dependencies: - dependency-name: anyhow dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ae0a71f8c1b..52ed478fb6d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,9 +51,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" [[package]] name = "arc-swap" From bcb78c9382af059ccd89dd3c53a1846f2fff1d6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Dec 2022 17:21:30 -0600 Subject: [PATCH 146/269] build(deps): bump toml from 0.5.9 to 0.5.10 (#5224) Bumps [toml](https://github.com/toml-rs/toml) from 0.5.9 to 0.5.10. - [Release notes](https://github.com/toml-rs/toml/releases) - [Commits](https://github.com/toml-rs/toml/commits/toml-v0.5.10) --- updated-dependencies: - dependency-name: toml dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 52ed478fb6d7..3f4b081cba36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2142,9 +2142,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" dependencies = [ "serde", ] From 453c7b46993c7ecf2eb8c0549b93085907c6d6c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Dec 2022 17:21:51 -0600 Subject: [PATCH 147/269] build(deps): bump thiserror from 1.0.37 to 1.0.38 (#5223) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.37 to 1.0.38. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.37...1.0.38) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3f4b081cba36..7e98a0f75e21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2018,18 +2018,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", From 38fd20c858d166ce9e5b421722b18dc9f7d8810f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Dec 2022 17:22:27 -0600 Subject: [PATCH 148/269] build(deps): bump indoc from 1.0.7 to 1.0.8 (#5226) Bumps [indoc](https://github.com/dtolnay/indoc) from 1.0.7 to 1.0.8. - [Release notes](https://github.com/dtolnay/indoc/releases) - [Commits](https://github.com/dtolnay/indoc/compare/1.0.7...1.0.8) --- updated-dependencies: - dependency-name: indoc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- helix-term/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e98a0f75e21..1b4572bba57c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1386,9 +1386,9 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adab1eaa3408fb7f0c777a73e7465fd5656136fc93b670eb6df3c88c2c1344e3" +checksum = "da2d6f23ffea9d7e76c53eee25dfb67bcd8fde7f1198b0855350698c9f07c780" [[package]] name = "instant" diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 30bfc7ea38a3..9f2e5188d78a 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -78,5 +78,5 @@ helix-loader = { version = "0.6", path = "../helix-loader" } [dev-dependencies] smallvec = "1.10" -indoc = "1.0.6" +indoc = "1.0.8" tempfile = "3.3.0" From f7a9717088fd00f875f03ff89e7229e64eb7f5fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Dec 2022 17:24:26 -0600 Subject: [PATCH 149/269] build(deps): bump serde_json from 1.0.89 to 1.0.91 (#5225) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.89 to 1.0.91. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.89...v1.0.91) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1b4572bba57c..e00e1f6381ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1825,9 +1825,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ "itoa", "ryu", From 03baec8a2d83de59d7e8ada655022e4f81d1fa68 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Tue, 20 Dec 2022 02:36:56 +0300 Subject: [PATCH 150/269] build(nix): update inputs (#5219) --- flake.lock | 70 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index f097519e34af..4cf1018c4999 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "crane": { "flake": false, "locked": { - "lastModified": 1661875961, - "narHash": "sha256-f1h/2c6Teeu1ofAHWzrS8TwBPcnN+EEu+z1sRVmMQTk=", + "lastModified": 1670900067, + "narHash": "sha256-VXVa+KBfukhmWizaiGiHRVX/fuk66P8dgSFfkVN4/MY=", "owner": "ipetkov", "repo": "crane", - "rev": "d9f394e4e20e97c2a60c3ad82c2b6ef99be19e24", + "rev": "59b31b41a589c0a65e4a1f86b0e5eac68081468b", "type": "github" }, "original": { @@ -45,6 +45,7 @@ "nci", "devshell" ], + "flake-parts": "flake-parts", "flake-utils-pre-commit": [ "nci" ], @@ -57,6 +58,9 @@ "mach-nix": [ "nci" ], + "nix-pypi-fetcher": [ + "nci" + ], "nixpkgs": [ "nci", "nixpkgs" @@ -69,11 +73,11 @@ ] }, "locked": { - "lastModified": 1668851003, - "narHash": "sha256-X7RCQQynbxStZR2m7HW38r/msMQwVl3afD6UXOCtvx4=", + "lastModified": 1671323629, + "narHash": "sha256-9KHTPjIDjfnzZ4NjpE3gGIVHVHopy6weRDYO/7Y3hF8=", "owner": "nix-community", "repo": "dream2nix", - "rev": "c77e8379d8fe01213ba072e40946cbfb7b58e628", + "rev": "2d7d68505c8619410df2c6b6463985f97cbcba6e", "type": "github" }, "original": { @@ -82,6 +86,24 @@ "type": "github" } }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1668450977, + "narHash": "sha256-cfLhMhnvXn6x1vPm+Jow3RiFAUSCw/l1utktCw5rVA4=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "d591857e9d7dd9ddbfba0ea02b43b927c3c0f1fa", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, "flake-utils": { "locked": { "lastModified": 1659877975, @@ -109,11 +131,11 @@ ] }, "locked": { - "lastModified": 1669011203, - "narHash": "sha256-Lymj4HktNEFmVXtwI0Os7srDXHZbZW0Nzw3/+5Hf8ko=", + "lastModified": 1671430291, + "narHash": "sha256-UIc7H8F3N8rK72J/Vj5YJdV72tvDvYjH+UPsOFvlcsE=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "c5133b91fc1d549087c91228bd213f2518728a4b", + "rev": "b1b0d38b8c3b0d0e6a38638d5bbe10b0bc67522c", "type": "github" }, "original": { @@ -124,11 +146,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1668905981, - "narHash": "sha256-RBQa/+9Uk1eFTqIOXBSBezlEbA3v5OkgP+qptQs1OxY=", + "lastModified": 1671359686, + "narHash": "sha256-3MpC6yZo+Xn9cPordGz2/ii6IJpP2n8LE8e/ebUXLrs=", "owner": "nixos", "repo": "nixpkgs", - "rev": "690ffff026b4e635b46f69002c0f4e81c65dfc2e", + "rev": "04f574a1c0fde90b51bf68198e2297ca4e7cccf4", "type": "github" }, "original": { @@ -138,6 +160,24 @@ "type": "github" } }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1665349835, + "narHash": "sha256-UK4urM3iN80UXQ7EaOappDzcisYIuEURFRoGQ/yPkug=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "34c5293a71ffdb2fe054eb5288adc1882c1eb0b1", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, "root": { "inputs": { "nci": "nci", @@ -153,11 +193,11 @@ ] }, "locked": { - "lastModified": 1668998422, - "narHash": "sha256-G/BklIplCHZEeDIabaaxqgITdIXtMolRGlwxn9jG2/Q=", + "lastModified": 1671416426, + "narHash": "sha256-kpSH1Jrxfk2qd0pRPJn1eQdIOseGv5JuE+YaOrqU9s4=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "68ab029c93f8f8eed4cf3ce9a89a9fd4504b2d6e", + "rev": "fbaaff24f375ac25ec64268b0a0d63f91e474b7d", "type": "github" }, "original": { From a7146f58f00b7d15f584c630ca6e123793a0a051 Mon Sep 17 00:00:00 2001 From: farwyler <1705805+farwyler@users.noreply.github.com> Date: Tue, 20 Dec 2022 00:40:08 +0100 Subject: [PATCH 151/269] Add missing comment injection for nix (#5208) --- runtime/queries/nix/injections.scm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/queries/nix/injections.scm b/runtime/queries/nix/injections.scm index 82d79cc762c6..a1a0ebb88620 100644 --- a/runtime/queries/nix/injections.scm +++ b/runtime/queries/nix/injections.scm @@ -1,3 +1,6 @@ +((comment) @injection.content + (#set! injection.language "comment")) + ; mark arbitary languages with a comment ((((comment) @injection.language) . (indented_string_expression (string_fragment) @injection.content)) From bdeefbfb23077fcbbfe1e7df6c6ac88516244bbc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Dec 2022 17:49:23 -0600 Subject: [PATCH 152/269] build(deps): bump serde from 1.0.150 to 1.0.151 (#5221) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.150 to 1.0.151. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.150...v1.0.151) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e00e1f6381ba..a6ca94954c00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1805,18 +1805,18 @@ checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" [[package]] name = "serde" -version = "1.0.150" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91" +checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.150" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e" +checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" dependencies = [ "proc-macro2", "quote", From 6ab8591715daf932d0dc45d0d5fb9e5a272f2fe1 Mon Sep 17 00:00:00 2001 From: Chirikumbrah <78883260+Chirikumbrah@users.noreply.github.com> Date: Wed, 21 Dec 2022 02:33:14 +0300 Subject: [PATCH 153/269] Better diagnostics highlighting for Dracula theme. (#5236) --- runtime/themes/dracula.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index 90bdb446bd0a..0f459311c3ff 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -55,6 +55,9 @@ "markup.quote" = { fg = "yellow", modifiers = ["italic"] } "markup.raw" = { fg = "foreground" } +"diagnostic".underline = { color = "orange", style = "curl" } +"diagnostic.error".underline = { color = "red", style = "curl" } + [palette] background = "#282a36" background_dark = "#21222c" From d0a5e11c28a3ad2533b79e2922ca06aa7036516c Mon Sep 17 00:00:00 2001 From: LeoniePhiline <22329650+LeoniePhiline@users.noreply.github.com> Date: Thu, 22 Dec 2022 00:10:12 +0100 Subject: [PATCH 154/269] fix(theme): Replace invalid `cyan` by `blue` in line with original theme (#5250) --- runtime/themes/monokai_pro_spectrum.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/monokai_pro_spectrum.toml b/runtime/themes/monokai_pro_spectrum.toml index 89575e3a1414..f5787ca8c3b1 100644 --- a/runtime/themes/monokai_pro_spectrum.toml +++ b/runtime/themes/monokai_pro_spectrum.toml @@ -53,7 +53,7 @@ "constructor" = "blue" "function" = "green" "function.macro" = { fg = "blue" } -"function.builtin" = { fg = "cyan" } +"function.builtin" = { fg = "blue" } # operator, tags, units, punctuations "operator" = "red" From c4263d6a56c6490b34a43c7d393fce321514b6ef Mon Sep 17 00:00:00 2001 From: Chickenkeeper Date: Wed, 21 Dec 2022 23:10:45 +0000 Subject: [PATCH 155/269] Fix & Tweak Rust's Syntax Highlighting (#5238) --- runtime/queries/rust/highlights.scm | 31 ++++++++--------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/runtime/queries/rust/highlights.scm b/runtime/queries/rust/highlights.scm index d3c292708b63..66058034b79d 100644 --- a/runtime/queries/rust/highlights.scm +++ b/runtime/queries/rust/highlights.scm @@ -45,7 +45,8 @@ "'" @label (identifier) @label) (loop_label - (identifier) @type) + "'" @label + (identifier) @label) ; --- ; Punctuation @@ -102,8 +103,6 @@ (closure_parameters (identifier) @variable.parameter) - - ; ------- ; Keywords ; ------- @@ -129,9 +128,7 @@ [ "break" "continue" - "return" - "await" ] @keyword.control.return @@ -154,10 +151,7 @@ "trait" "for" - "unsafe" "default" - "macro_rules!" - "async" ] @keyword @@ -165,13 +159,13 @@ "struct" "enum" "union" - "type" ] @keyword.storage.type "let" @keyword.storage - "fn" @keyword.function +"unsafe" @keyword.special +"macro_rules!" @function.macro (mutable_specifier) @keyword.storage.modifier.mut @@ -202,11 +196,11 @@ (call_expression function: [ - ((identifier) @type.variant - (#match? @type.variant "^[A-Z]")) + ((identifier) @type.enum.variant + (#match? @type.enum.variant "^[A-Z]")) (scoped_identifier - name: ((identifier) @type.variant - (#match? @type.variant "^[A-Z]"))) + name: ((identifier) @type.enum.variant + (#match? @type.enum.variant "^[A-Z]"))) ]) ; --- @@ -237,8 +231,6 @@ ((identifier) @type (#match? @type "^[A-Z]")) - - (attribute (identifier) @_macro arguments: (token_tree (identifier) @constant.numeric.integer) @@ -246,7 +238,6 @@ ) @special - ; ------- ; Functions ; ------- @@ -303,8 +294,6 @@ (metavariable) @variable.parameter (fragment_specifier) @type - - ; ------- ; Operators ; ------- @@ -350,8 +339,6 @@ "'" ] @operator - - ; ------- ; Paths ; ------- @@ -382,8 +369,6 @@ (scoped_type_identifier path: (identifier) @namespace) - - ; ------- ; Remaining Identifiers ; ------- From 7905086b55eac2a817c16fe3a9ab987e718324c8 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Thu, 22 Dec 2022 19:21:02 -0600 Subject: [PATCH 156/269] Fix HTML injection within markdown (#5265) HTML nodes should be combined injections in the markdown block grammar. When nodes are together the highlighting works properly but when there is markdown content between HTML nodes like in a `
` tag, the highlighting of the closing tag breaks since tree-sitter-html looks for opening and closing tags. --- runtime/queries/markdown/injections.scm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runtime/queries/markdown/injections.scm b/runtime/queries/markdown/injections.scm index e184db157aa6..e88393512f59 100644 --- a/runtime/queries/markdown/injections.scm +++ b/runtime/queries/markdown/injections.scm @@ -5,7 +5,10 @@ (language) @injection.language) (code_fence_content) @injection.content (#set! injection.include-unnamed-children)) -((html_block) @injection.content (#set! injection.language "html") (#set! injection.include-unnamed-children)) +((html_block) @injection.content + (#set! injection.language "html") + (#set! injection.include-unnamed-children) + (#set! injection.combined)) ((pipe_table_cell) @injection.content (#set! injection.language "markdown.inline") (#set! injection.include-unnamed-children)) From 7a1fa0c74fb2c3b7b1c9aea9aa77c5c612e0bd12 Mon Sep 17 00:00:00 2001 From: Gioele De Vitti Date: Fri, 23 Dec 2022 02:12:49 +0000 Subject: [PATCH 157/269] tutor: Add a content cycling section (#5161) --- runtime/tutor | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/runtime/tutor b/runtime/tutor index 885ea0bffcc9..1fc5605eab02 100644 --- a/runtime/tutor +++ b/runtime/tutor @@ -985,11 +985,33 @@ lines. --> How much would would a wouldchuck chuck --> if a wouldchuck could chuck would? - Note: Additionally, Alt-( and Alt-) cycle the *contents* of the - selections as well. + + + +================================================================= += 10.2 CYCLING THE CONTENT OF SELECTIONS = +================================================================= + + Type Alt-) and Alt-( to cycle the content of the selections + forward and backward respectively. + + 1. Move the cursor to the line marked '-->' below. + 2. Select both lines with xx or 2x. + 3. Type s to select, type "through|water|know" and enter. + 4. Use Alt-( and Alt-) to cycle the content of the selections. + + --> Jumping through the water, + --> daring to know. + + + + + + + ================================================================= -= 10.2 CHANGING CASE = += 10.3 CHANGING CASE = ================================================================= Type ~ to switch the case of all selected letters. @@ -1011,7 +1033,7 @@ lines. --> THIS sentence should ALL BE IN uppercase! ================================================================= -= 10.3 SPLITTING SELECTIONS = += 10.4 SPLITTING SELECTIONS = ================================================================= Type S to split each selection on a regex pattern. @@ -1039,6 +1061,7 @@ letters! that is not good grammar. you can fix this. * Use ) and ( to cycle the primary selection back and forward through selections respectively. * Type Alt-, to remove the primary selection. + * Type Alt-) and Alt-( to cycle the content of the selections. * Type ~ to alternate case of selected letters. * Use ` and Alt-` to set the case of selected letters to @@ -1053,7 +1076,6 @@ letters! that is not good grammar. you can fix this. - ================================================================= = = ================================================================= From 1b89d3e5350f83b2ffb86a86326bd2714308ee53 Mon Sep 17 00:00:00 2001 From: Jack Allison Date: Thu, 22 Dec 2022 21:23:34 -0500 Subject: [PATCH 158/269] Add file picker dialogue when opening a directory with :o (#2707) --- helix-term/src/commands/typed.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index cb387fcb5b64..c3a7c9faabd9 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -65,12 +65,28 @@ fn open(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> ensure!(!args.is_empty(), "wrong argument count"); for arg in args { let (path, pos) = args::parse_file(arg); - let _ = cx.editor.open(&path, Action::Replace)?; - let (view, doc) = current!(cx.editor); - let pos = Selection::point(pos_at_coords(doc.text().slice(..), pos, true)); - doc.set_selection(view.id, pos); - // does not affect opening a buffer without pos - align_view(doc, view, Align::Center); + // If the path is a directory, open a file picker on that directory and update the status + // message + if std::fs::canonicalize(&path)?.is_dir() { + let callback = async move { + let call: job::Callback = job::Callback::EditorCompositor(Box::new( + move |editor: &mut Editor, compositor: &mut Compositor| { + let picker = ui::file_picker(path, &editor.config()); + compositor.push(Box::new(overlayed(picker))); + }, + )); + Ok(call) + }; + cx.jobs.callback(callback); + } else { + // Otherwise, just open the file + let _ = cx.editor.open(&path, Action::Replace)?; + let (view, doc) = current!(cx.editor); + let pos = Selection::point(pos_at_coords(doc.text().slice(..), pos, true)); + doc.set_selection(view.id, pos); + // does not affect opening a buffer without pos + align_view(doc, view, Align::Center); + } } Ok(()) } From 1107296ca9bfd728258a4571be35eb7c811ff3b3 Mon Sep 17 00:00:00 2001 From: DylanBulfin <31492860+DylanBulfin@users.noreply.github.com> Date: Thu, 22 Dec 2022 21:27:20 -0500 Subject: [PATCH 159/269] Add command to merge consecutive ranges in selection (#5047) --- book/src/keymap.md | 1 + helix-core/src/selection.rs | 95 ++++++++++++++++++++++++++++---- helix-term/src/commands.rs | 7 +++ helix-term/src/keymap/default.rs | 1 + 4 files changed, 92 insertions(+), 12 deletions(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index 153294007ee6..272c758b6317 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -111,6 +111,7 @@ | `s` | Select all regex matches inside selections | `select_regex` | | `S` | Split selection into subselections on regex matches | `split_selection` | | `Alt-s` | Split selection on newlines | `split_selection_on_newline` | +| `Alt-_ ` | Merge consecutive selections | `merge_consecutive_selections` | | `&` | Align selection in columns | `align_selections` | | `_` | Trim whitespace from the selection | `trim_selections` | | `;` | Collapse selection onto a single cursor | `collapse_selection` | diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index 1f28ecefb750..ffba46ab70ef 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -495,28 +495,53 @@ impl Selection { /// Normalizes a `Selection`. fn normalize(mut self) -> Self { - let primary = self.ranges[self.primary_index]; + let mut primary = self.ranges[self.primary_index]; self.ranges.sort_unstable_by_key(Range::from); + + self.ranges.dedup_by(|curr_range, prev_range| { + if prev_range.overlaps(curr_range) { + let new_range = curr_range.merge(*prev_range); + if prev_range == &primary || curr_range == &primary { + primary = new_range; + } + *prev_range = new_range; + true + } else { + false + } + }); + self.primary_index = self .ranges .iter() .position(|&range| range == primary) .unwrap(); - let mut prev_i = 0; - for i in 1..self.ranges.len() { - if self.ranges[prev_i].overlaps(&self.ranges[i]) { - self.ranges[prev_i] = self.ranges[prev_i].merge(self.ranges[i]); + self + } + + // Merges all ranges that are consecutive + pub fn merge_consecutive_ranges(mut self) -> Self { + let mut primary = self.ranges[self.primary_index]; + + self.ranges.dedup_by(|curr_range, prev_range| { + if prev_range.to() == curr_range.from() { + let new_range = curr_range.merge(*prev_range); + if prev_range == &primary || curr_range == &primary { + primary = new_range; + } + *prev_range = new_range; + true } else { - prev_i += 1; - self.ranges[prev_i] = self.ranges[i]; + false } - if i == self.primary_index { - self.primary_index = prev_i; - } - } + }); - self.ranges.truncate(prev_i + 1); + self.primary_index = self + .ranges + .iter() + .position(|&range| range == primary) + .unwrap(); self } @@ -1132,6 +1157,52 @@ mod test { &["", "abcd", "efg", "rs", "xyz"] ); } + + #[test] + fn test_merge_consecutive_ranges() { + let selection = Selection::new( + smallvec![ + Range::new(0, 1), + Range::new(1, 10), + Range::new(15, 20), + Range::new(25, 26), + Range::new(26, 30) + ], + 4, + ); + + let result = selection.merge_consecutive_ranges(); + + assert_eq!( + result.ranges(), + &[Range::new(0, 10), Range::new(15, 20), Range::new(25, 30)] + ); + assert_eq!(result.primary_index, 2); + + let selection = Selection::new(smallvec![Range::new(0, 1)], 0); + let result = selection.merge_consecutive_ranges(); + + assert_eq!(result.ranges(), &[Range::new(0, 1)]); + assert_eq!(result.primary_index, 0); + + let selection = Selection::new( + smallvec![ + Range::new(0, 1), + Range::new(1, 5), + Range::new(5, 8), + Range::new(8, 10), + Range::new(10, 15), + Range::new(18, 25) + ], + 3, + ); + + let result = selection.merge_consecutive_ranges(); + + assert_eq!(result.ranges(), &[Range::new(0, 15), Range::new(18, 25)]); + assert_eq!(result.primary_index, 0); + } + #[test] fn test_selection_contains() { fn contains(a: Vec<(usize, usize)>, b: Vec<(usize, usize)>) -> bool { diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 6cf494646d85..437e11b5c238 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -244,6 +244,7 @@ impl MappableCommand { select_regex, "Select all regex matches inside selections", split_selection, "Split selections on regex matches", split_selection_on_newline, "Split selection on newlines", + merge_consecutive_selections, "Merge consecutive selections", search, "Search for regex pattern", rsearch, "Reverse search for regex pattern", search_next, "Select next search match", @@ -1589,6 +1590,12 @@ fn split_selection_on_newline(cx: &mut Context) { doc.set_selection(view.id, selection); } +fn merge_consecutive_selections(cx: &mut Context) { + let (view, doc) = current!(cx.editor); + let selection = doc.selection(view.id).clone().merge_consecutive_ranges(); + doc.set_selection(view.id, selection); +} + #[allow(clippy::too_many_arguments)] fn search_impl( editor: &mut Editor, diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index ebcd125aa129..ef93dee08a77 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -76,6 +76,7 @@ pub fn default() -> HashMap { "s" => select_regex, "A-s" => split_selection_on_newline, + "A-_" => merge_consecutive_selections, "S" => split_selection, ";" => collapse_selection, "A-;" => flip_selections, From df1830ef28a7cb49abe31a18e4bd1bcfc7eb802a Mon Sep 17 00:00:00 2001 From: jliaoh <48660001+hunterliao29@users.noreply.github.com> Date: Thu, 22 Dec 2022 21:30:33 -0500 Subject: [PATCH 160/269] mouse operations respect scrolloff (#5255) --- helix-term/src/ui/editor.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index fc201853f7dc..35cf77abc9bf 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -1155,6 +1155,7 @@ impl EditorView { } editor.focus(view_id); + editor.ensure_cursor_in_view(view_id); return EventResult::Consumed(None); } @@ -1191,7 +1192,8 @@ impl EditorView { let primary = selection.primary_mut(); *primary = primary.put_cursor(doc.text().slice(..), pos, true); doc.set_selection(view.id, selection); - + let view_id = view.id; + cxt.editor.ensure_cursor_in_view(view_id); EventResult::Consumed(None) } @@ -1213,6 +1215,7 @@ impl EditorView { commands::scroll(cxt, offset, direction); cxt.editor.tree.focus = current_view; + cxt.editor.ensure_cursor_in_view(current_view); EventResult::Consumed(None) } From b1ca7ddf89c048a8da0d6cfe507ac3344e6f625f Mon Sep 17 00:00:00 2001 From: cor Date: Fri, 23 Dec 2022 15:03:54 +0100 Subject: [PATCH 161/269] Use curl underlines in the rose_pine theme (#5267) Also fixes the color "gold" being used for too many kinds of diagnostics, now there's a more conventional choice of diagnostics colors (redish = error, yellowish = warning, blueish = hint). --- runtime/themes/rose_pine.toml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/runtime/themes/rose_pine.toml b/runtime/themes/rose_pine.toml index 14e240dd505e..8558db3ab444 100644 --- a/runtime/themes/rose_pine.toml +++ b/runtime/themes/rose_pine.toml @@ -1,5 +1,6 @@ # Author: RayGervais # Author: ChrisHa +# Diagnostics patch author: cor "ui.background" = { bg = "base" } "ui.menu" = { fg = "text", bg = "overlay" } @@ -45,12 +46,18 @@ "diff.delta" = "rose" "diff.minus" = "love" -"info" = "gold" -"hint" = "gold" +"info" = "foam" +"hint" = "iris" "debug" = "rose" -"diagnostic" = "rose" +"warning" = "gold" "error" = "love" +"diagnostic" = { modifiers = ["underlined"] } +"diagnostic.error" = { underline = { style = "curl", color = "love" } } +"diagnostic.warning" = { underline = { style = "curl", color = "gold" } } +"diagnostic.info" = { underline = { style = "curl", color = "foam" } } +"diagnostic.hint" = { underline = { style = "curl", color = "iris" } } + "markup.heading.marker" = "subtle" "markup.heading.1" = { fg = "love", modifiers = ["bold"] } "markup.heading.2" = { fg = "gold", modifiers = ["bold"] } From 24c3b00d10858a02c6c1c351a7509e204c2bc647 Mon Sep 17 00:00:00 2001 From: Nick Date: Fri, 23 Dec 2022 19:43:05 +0530 Subject: [PATCH 162/269] Avoid trailing `s` in message when only 1 file is opened (#5189) --- helix-term/src/application.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 7a50e007b9b9..5f013b9af0a6 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -227,7 +227,11 @@ impl Application { doc.set_selection(view_id, pos); } } - editor.set_status(format!("Loaded {} files.", nr_of_files)); + editor.set_status(format!( + "Loaded {} file{}.", + nr_of_files, + if nr_of_files == 1 { "" } else { "s" } // avoid "Loaded 1 files." grammo + )); // align the view to center after all files are loaded, // does not affect views without pos since it is at the top let (view, doc) = current!(editor); From f0c6e6c9eeb1f2772571bcefe02bd344fa70d62f Mon Sep 17 00:00:00 2001 From: Erasin Date: Sat, 24 Dec 2022 19:30:44 +0800 Subject: [PATCH 163/269] fix comment token of godot resource file (#5276) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 8972a6e94389..53f65be7cf05 100644 --- a/languages.toml +++ b/languages.toml @@ -1460,7 +1460,7 @@ file-types = ["tscn","tres"] shebangs = [] roots = ["project.godot"] auto-format = false -comment-token = "#" +comment-token = ";" indent = { tab-width = 4, unit = "\t" } [[grammar]] From eb4ec3271005e9de7960a4dd08a9efbb648cb89f Mon Sep 17 00:00:00 2001 From: alois31 <36605164+alois31@users.noreply.github.com> Date: Sat, 24 Dec 2022 14:50:39 +0100 Subject: [PATCH 164/269] Fix opening new files (#5278) Commit 1b89d3e5350f83b2ffb86a86326bd2714308ee53 introduced a regression where opening a new file would no longer work, because attempting to canonicalize its path would lead to a "No such file or directory" error. Fall back to opening a new file when encountering an error to fix this case. --- helix-term/src/commands/typed.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index c3a7c9faabd9..c2ca1a47811b 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -67,7 +67,7 @@ fn open(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> let (path, pos) = args::parse_file(arg); // If the path is a directory, open a file picker on that directory and update the status // message - if std::fs::canonicalize(&path)?.is_dir() { + if let Ok(true) = std::fs::canonicalize(&path).map(|p| p.is_dir()) { let callback = async move { let call: job::Callback = job::Callback::EditorCompositor(Box::new( move |editor: &mut Editor, compositor: &mut Compositor| { From 1af76b738dd5bdae14b025d07d3001c4ad23e071 Mon Sep 17 00:00:00 2001 From: Alex Kladov Date: Sat, 24 Dec 2022 21:55:16 +0000 Subject: [PATCH 165/269] Add eb word selection trick to the tutor (#5247) --- runtime/tutor | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/runtime/tutor b/runtime/tutor index 1fc5605eab02..baf32c274e01 100644 --- a/runtime/tutor +++ b/runtime/tutor @@ -241,7 +241,7 @@ _________________________________________________________________ ================================================================= -= 3.2 MORE ON MOTIONS = += 3.2 MORE MOTIONS = ================================================================= As you saw, typing w moves the cursor forward until the start @@ -253,6 +253,19 @@ _________________________________________________________________ e - Move forward to the end of the current word. b - Move backward to the beginning of the current word. + To select the word under cursor, combine e and b. + + 1. Move the cursor to the line marked '-->' below. + 2. Move to a 'd' letter. + 3. Type e to select a half of the word. + 4. Type b to select the rest. + +--> The Middle Kingdom. + +================================================================= += 3.3 WORDS AND words = +================================================================= + The w,e,b motions also have counterparts - W,E,B - which traverse WORDS instead of words. WORDS are only separated by whitespace, whereas words can be separated by other characters @@ -262,8 +275,17 @@ _________________________________________________________________ + + + + + + + + + ================================================================= -= 3.3 THE CHANGE COMMAND = += 3.4 THE CHANGE COMMAND = ================================================================= Type c to change the current selection. @@ -285,7 +307,7 @@ _________________________________________________________________ ================================================================= -= 3.4 COUNTS WITH MOTIONS = += 3.5 COUNTS WITH MOTIONS = ================================================================= Type a number before a motion to repeat it that many times. @@ -307,7 +329,7 @@ _________________________________________________________________ ================================================================= -= 3.5 SELECT / EXTEND MODE = += 3.6 SELECT / EXTEND MODE = ================================================================= Type v to enter Select mode. @@ -329,7 +351,7 @@ _________________________________________________________________ ================================================================= -= 3.6 SELECTING LINES = += 3.7 SELECTING LINES = ================================================================= Type x to select a whole line. Type x again to select the next. @@ -351,7 +373,7 @@ _________________________________________________________________ subsequent lines. X on an empty line does nothing. ================================================================= -= 3.7 COLLAPSING SELECTIONS = += 3.8 COLLAPSING SELECTIONS = ================================================================= Type ; to collapse selections to single cursors. From a637461677bed1468af5a5d86c57113de3345247 Mon Sep 17 00:00:00 2001 From: "Soc Virnyl S. Estela" Date: Tue, 27 Dec 2022 03:11:42 +0800 Subject: [PATCH 166/269] tutor: add chapter for commenting lines (#5211) --- runtime/tutor | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/runtime/tutor b/runtime/tutor index baf32c274e01..408f74514cd0 100644 --- a/runtime/tutor +++ b/runtime/tutor @@ -1099,10 +1099,58 @@ letters! that is not good grammar. you can fix this. ================================================================= -= = += 11.1 COMMENTING A LINE = ================================================================= +Type Ctrl-c to comment the line under your cursor. +To uncomment the line, press Ctrl-c again. +1. Move your cursor to the line marked '-->' below. +2. Now comment the line marked with '-->'. +3. Now try uncommenting the line. + +--> Comment me please + + + + + + + + + + +================================================================= += 11.2 COMMENTING MULTIPLE LINES = +================================================================= + +Using the selections and multi-cursor functionality, you can +comment multiple lines as long as it is under the selection or +cursors. + +1. Move your cursor to the line marked with '-->' below. +2. Now try to select or add more cursors the other lines marked + with '-->'. +3. Comment those lines. + +--> How many are you going to comment? +--> Is this enough for a comment? +--> What are you doing?! +--> Stop commenting me! +--> AAAAaargh!!! + +Note: If there are already commented lines under selections or +multiple cursors, they won't be uncommented but commented again. + +================================================================= += CHAPTER 11 RECAP = +================================================================= + + * Use Ctrl-c to comment a line under your cursor. Type Ctrl-c + again to uncomment. + * To comment multiple lines, use the selections + and multi-cursors before typing Ctrl-c. + * Commented lines cannot be uncommented but commented again. From 792c2e3dbf1ae355f5cba829dff25d17d8b8c7d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:15:00 -0600 Subject: [PATCH 167/269] build(deps): bump git-repository from 0.29.0 to 0.30.2 (#5306) Bumps [git-repository](https://github.com/Byron/gitoxide) from 0.29.0 to 0.30.2. - [Release notes](https://github.com/Byron/gitoxide/releases) - [Changelog](https://github.com/Byron/gitoxide/blob/main/CHANGELOG.md) - [Commits](https://github.com/Byron/gitoxide/compare/git-repository-v0.29.0...git-repository-v0.30.2) --- updated-dependencies: - dependency-name: git-repository dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 207 +++++++++++++++++++++++-------------------- helix-vcs/Cargo.toml | 2 +- 2 files changed, 112 insertions(+), 97 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a6ca94954c00..1243bc51d1d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,9 +63,9 @@ checksum = "983cd8b9d4b02a6dc6ffa557262eb5858a27a0038ffffe21a0f133eaa819a164" [[package]] name = "atoi" -version = "1.0.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c57d12312ff59c811c0643f4d80830505833c9ffaebd193d819392b265be8e" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" dependencies = [ "num-traits", ] @@ -120,16 +120,6 @@ version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" -[[package]] -name = "byte-unit" -version = "4.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581ad4b3d627b0c09a0ccb2912148f839acaca0b93cf54cbe42b6c674e86079c" -dependencies = [ - "serde", - "utf8-width", -] - [[package]] name = "bytecount" version = "0.6.3" @@ -211,9 +201,9 @@ dependencies = [ [[package]] name = "clru" -version = "0.5.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "218d6bd3dde8e442a975fa1cd233c0e5fded7596bccfe39f58eca98d22421e0a" +checksum = "b8191fa7302e03607ff0e237d4246cc043ff5b3cb9409d995172ba3bea16b807" [[package]] name = "codespan-reporting" @@ -280,7 +270,7 @@ dependencies = [ "futures-core", "libc", "mio", - "parking_lot", + "parking_lot 0.12.1", "signal-hook", "signal-hook-mio", "winapi", @@ -349,7 +339,7 @@ dependencies = [ "hashbrown 0.12.3", "lock_api", "once_cell", - "parking_lot_core", + "parking_lot_core 0.9.4", ] [[package]] @@ -551,9 +541,9 @@ dependencies = [ [[package]] name = "git-actor" -version = "0.14.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9fb99c934ed45a62d9ae1e7b21949f2d869d1b82a07dcbf16ed61daa665870" +checksum = "7def29b46f25f95a2e196323cfb336eae9965e0a3c7c35ad9506f295c3a8e234" dependencies = [ "bstr 1.0.1", "btoi", @@ -565,9 +555,9 @@ dependencies = [ [[package]] name = "git-attributes" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e98446a2bf0eb5c8f29fa828d6529510a6fadeb59ce14ca98e58fa7e1e0199" +checksum = "f0affaed361598fdd06b2a184a566c823d0b5817b09f576018248fb267193a96" dependencies = [ "bstr 1.0.1", "compact_str", @@ -608,9 +598,9 @@ dependencies = [ [[package]] name = "git-config" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd1d13179bcf3dd68e83404f91a8d01c618f54eb97ef36c68ee5e6f30183a681" +checksum = "5ff189268cfb19d5151529ac30b6b708072ebfa1075643d785232675456ec320" dependencies = [ "bstr 1.0.1", "git-config-value", @@ -629,9 +619,9 @@ dependencies = [ [[package]] name = "git-config-value" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64561e9700f1fc737fa3c1c4ea55293be70dba98e45c54cf3715cb180f37a566" +checksum = "989a90c1c630513a153c685b4249b96fdf938afc75bf7ef2ae1ccbd3d799f5db" dependencies = [ "bitflags", "bstr 1.0.1", @@ -642,9 +632,9 @@ dependencies = [ [[package]] name = "git-credentials" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "621dd60288ae7b8f80bb0704f46d4d2b76fc1ec980a7804e48b02d94a927e331" +checksum = "28da3d029be10258007699d002321a3b1ebe45e67b0e140a4cf464ba3ee79b32" dependencies = [ "bstr 1.0.1", "git-command", @@ -658,9 +648,9 @@ dependencies = [ [[package]] name = "git-date" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33db9f4462b565a33507aee113f3383bf16b988d2c573f07691e34302b7aa0a" +checksum = "8a2874ce2f3a77cb144167901ea830969e5c991eac7bfee85e6e3f53ef9fcdf2" dependencies = [ "bstr 1.0.1", "itoa", @@ -670,9 +660,9 @@ dependencies = [ [[package]] name = "git-diff" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82f77407381267be95f1b26acfb32007258af342ee61729bb4271b1869bf5bb2" +checksum = "8f30011a43908645c492dfbea7b004e10528be6bd667bf5cdc12ff4297fe1e3c" dependencies = [ "git-hash", "git-object", @@ -682,9 +672,9 @@ dependencies = [ [[package]] name = "git-discover" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c2cfd1272824b126c6997ef479a71288d00fae14dc5144dfc48658f4dd24fbe" +checksum = "93c244b1cf7cf45501116e948506c25324e33ddc613f00557ff5bfded2132009" dependencies = [ "bstr 1.0.1", "git-hash", @@ -696,9 +686,9 @@ dependencies = [ [[package]] name = "git-features" -version = "0.24.1" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bdbe755d2129bc609437b6b18af1116f146128dda6070c15c0aa50201ac17c" +checksum = "0f98e6ede7b790dfba16bf3c62861ae75c3719485d675b522cf7d7e748a4011c" dependencies = [ "crc32fast", "flate2", @@ -713,9 +703,9 @@ dependencies = [ [[package]] name = "git-glob" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef858611602fce54b51e45671ca72f07fe6a3c0e24a0539c66b75dfd4d84bd77" +checksum = "3908404c9b76ac7b3f636a104142378d3eaa78623cbc6eb7c7f0651979d48e8a" dependencies = [ "bitflags", "bstr 1.0.1", @@ -731,11 +721,21 @@ dependencies = [ "thiserror", ] +[[package]] +name = "git-hashtable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c52b625ad8cc360a0b7f426266f21fb07bd49b8f4ccf1b3ca7bc89424db1dec4" +dependencies = [ + "git-hash", + "hashbrown 0.13.1", +] + [[package]] name = "git-index" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a87c32d2e012ee316d4037b2151e5893599379ff1fc2c6adb36d2d4d1c461e2c" +checksum = "20627f71f3a884b0ae50f9f3abb3a07d9b117d06e16110d25b85da4d71d478c0" dependencies = [ "atoi", "bitflags", @@ -766,9 +766,9 @@ dependencies = [ [[package]] name = "git-mailmap" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "480eecdfaf1bfd05973678520d182dc07afa25b133db18c52575fb65b782b7ba" +checksum = "f90e3ee2eaeebda8a12d17f4d99dff5b19d81536476020bcebb99ee121820466" dependencies = [ "bstr 1.0.1", "git-actor", @@ -777,9 +777,9 @@ dependencies = [ [[package]] name = "git-object" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce0f14f9cd8f0782e843898a2fb7b0c2f5a6e37bd4cdff4409bb8ec698597dad" +checksum = "35b658f1e3e149d88cb3e0a2234be749bb0cab65887405975dbe6f3190cf6571" dependencies = [ "bstr 1.0.1", "btoi", @@ -796,9 +796,9 @@ dependencies = [ [[package]] name = "git-odb" -version = "0.37.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13493da6cf0326454215414d29f933a1e26bdba3b9b60ad8cdcbe06f0639584b" +checksum = "55333419bbb25aa6d39e29155f747ad8e1777fe385f70f447be9d680824d23dd" dependencies = [ "arc-swap", "git-features", @@ -807,16 +807,16 @@ dependencies = [ "git-pack", "git-path", "git-quote", - "parking_lot", + "parking_lot 0.12.1", "tempfile", "thiserror", ] [[package]] name = "git-pack" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa8391cbf293f0f8ffbb5e324f25741f5e1e2d35fb87b89ab222a025661e0454" +checksum = "9ed3c9af66949553af9795b9eac9d450a5bdceee9959352cda468997ddce0d2f" dependencies = [ "bytesize", "clru", @@ -825,22 +825,22 @@ dependencies = [ "git-diff", "git-features", "git-hash", + "git-hashtable", "git-object", "git-path", "git-tempfile", "git-traverse", - "hash_hasher", "memmap2", - "parking_lot", + "parking_lot 0.12.1", "smallvec", "thiserror", ] [[package]] name = "git-path" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f60cbc13bc0fdd95df5f4b80437197e2853116792894b1bf38d1a6b4a64f8c9" +checksum = "e40e68481a06da243d3f4dfd86a4be39c24eefb535017a862e845140dcdb878a" dependencies = [ "bstr 1.0.1", "thiserror", @@ -848,14 +848,14 @@ dependencies = [ [[package]] name = "git-prompt" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21c6aaeb3f0f8de91f5e0eb950282c6508e05babcedef768db5a6f085d6e5242" +checksum = "3612a486e507dd431ef0f7108eeaafc8fd1ed7bd0f205a88554f6f91fe5dccbf" dependencies = [ "git-command", "git-config-value", "nix", - "parking_lot", + "parking_lot 0.12.1", "thiserror", ] @@ -872,9 +872,9 @@ dependencies = [ [[package]] name = "git-ref" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22484043921e699edc170415789f1b882c8f3546e1fbbc447a0043ef07e088c4" +checksum = "c97b7d719e4320179fb64d081016e7faca56fed4a8ee4cf84e4697faad9235a3" dependencies = [ "git-actor", "git-features", @@ -891,9 +891,9 @@ dependencies = [ [[package]] name = "git-refspec" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac2e8f36e7d5d48903b60051dfb75aedfc4ea9ba66bdffa7a9081e8d276b0107" +checksum = "d478e9db0956d60cd386d3348b5ec093e3ae613105a7a75ff6084b886254eba8" dependencies = [ "bstr 1.0.1", "git-hash", @@ -905,12 +905,10 @@ dependencies = [ [[package]] name = "git-repository" -version = "0.29.0" +version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89cec253dd3fba44694f7468d907506a52d0055850ecd7d84f4bac07f00e73f" +checksum = "1925a65a9fea6587e969a7a85cb239c8e1e438cf6dc520406df1b4c9d0e83bdc" dependencies = [ - "byte-unit", - "clru", "git-actor", "git-attributes", "git-config", @@ -921,6 +919,7 @@ dependencies = [ "git-features", "git-glob", "git-hash", + "git-hashtable", "git-index", "git-lock", "git-mailmap", @@ -940,6 +939,7 @@ dependencies = [ "git-worktree", "log", "once_cell", + "prodash", "signal-hook", "smallvec", "thiserror", @@ -948,23 +948,23 @@ dependencies = [ [[package]] name = "git-revision" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629289b0d7f7f2f2e46248527f5cac838e6a7cb9507eab06fc8473082db6cb6" +checksum = "f7516b1db551756b4d3176c4b7d18ccc4b79d35dcc5e74f768c90f5bb11bb6c9" dependencies = [ "bstr 1.0.1", "git-date", "git-hash", + "git-hashtable", "git-object", - "hash_hasher", "thiserror", ] [[package]] name = "git-sec" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecb370efde58da72827909292284b5c5b885e0621a342515a36976b0b3bf660" +checksum = "9e1802e8252fa223b0ad89a393aed461132174ced1e6842a41f56dc92a3fc14f" dependencies = [ "bitflags", "dirs", @@ -989,21 +989,21 @@ dependencies = [ [[package]] name = "git-traverse" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2746935c92d252e24f9d345e0a981510596faceb7edae821b9e4c8c35c285b" +checksum = "5e5141dde56d0c4861193c760e01fb61c7e03a32d0840ba93a0ac1c597588d4d" dependencies = [ "git-hash", + "git-hashtable", "git-object", - "hash_hasher", "thiserror", ] [[package]] name = "git-url" -version = "0.11.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dbd91c55b1b03a833ff8278776fed272918cd61cd48efe9a97ad1fea7ef93ec" +checksum = "8651924c9692a778f09141ca44d1bf2dada229fe9b240f1ff1bdecd9621a1a93" dependencies = [ "bstr 1.0.1", "git-features", @@ -1015,9 +1015,9 @@ dependencies = [ [[package]] name = "git-validate" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf83bae632fc064ca938ebfb987364d9083b7f98b1476805f0a2d5eebb48686" +checksum = "0431cf9352c596dc7c8ec9066ee551ce54e63c86c3c767e5baf763f6019ff3c2" dependencies = [ "bstr 1.0.1", "thiserror", @@ -1025,9 +1025,9 @@ dependencies = [ [[package]] name = "git-worktree" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eae0e0b1050208e611d5fac0d8366b29ef3f83849767ff9c4bcf570f0d5dc2b" +checksum = "17d748c54c3d904c914b987654a1416c7abe7cf048fdc83eeae69e6ac3d76f20" dependencies = [ "bstr 1.0.1", "git-attributes", @@ -1093,12 +1093,6 @@ dependencies = [ "memmap2", ] -[[package]] -name = "hash_hasher" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74721d007512d0cb3338cd20f0654ac913920061a4c4d0d8708edb3f2a698c0c" - [[package]] name = "hashbrown" version = "0.12.3" @@ -1258,7 +1252,7 @@ dependencies = [ "helix-core", "imara-diff", "log", - "parking_lot", + "parking_lot 0.12.1", "tempfile", "tokio", ] @@ -1531,14 +1525,14 @@ dependencies = [ [[package]] name = "nix" -version = "0.25.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" +checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694" dependencies = [ - "autocfg", "bitflags", "cfg-if", "libc", + "static_assertions", ] [[package]] @@ -1595,6 +1589,17 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -1602,7 +1607,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.4", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", ] [[package]] @@ -1647,12 +1666,14 @@ dependencies = [ [[package]] name = "prodash" -version = "21.1.0" +version = "22.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e13d7bd38cdab08b3a8b780cedcc54238c84fdca4084eb188807b308bcf11e6" +checksum = "38e2b91fcc982d0d8ae5e9d477561c73e09c24c5c19bac4858e202f6f065a13e" dependencies = [ "bytesize", + "dashmap", "human_format", + "parking_lot 0.11.2", ] [[package]] @@ -2110,7 +2131,7 @@ dependencies = [ "memchr", "mio", "num_cpus", - "parking_lot", + "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", "socket2", @@ -2235,12 +2256,6 @@ dependencies = [ "serde", ] -[[package]] -name = "utf8-width" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" - [[package]] name = "version_check" version = "0.9.4" diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml index e54cf828f51b..8e713638dd9f 100644 --- a/helix-vcs/Cargo.toml +++ b/helix-vcs/Cargo.toml @@ -16,7 +16,7 @@ helix-core = { version = "0.6", path = "../helix-core" } tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "parking_lot", "macros"] } parking_lot = "0.12" -git-repository = { version = "0.29", default-features = false , optional = true } +git-repository = { version = "0.30", default-features = false , optional = true } imara-diff = "0.1.5" log = "0.4" From eed80ef1c231a27ea76e6cb1b8800b299f56d834 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:28:21 -0600 Subject: [PATCH 168/269] build(deps): bump serde from 1.0.151 to 1.0.152 (#5307) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.151 to 1.0.152. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.151...v1.0.152) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1243bc51d1d2..3592e621ed0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1826,18 +1826,18 @@ checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" [[package]] name = "serde" -version = "1.0.151" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.151" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", From ebaf01924dd0e6251535d88ec0a2a00e88680d6b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:28:40 -0600 Subject: [PATCH 169/269] build(deps): bump cc from 1.0.77 to 1.0.78 (#5308) Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.0.77 to 1.0.78. - [Release notes](https://github.com/rust-lang/cc-rs/releases) - [Commits](https://github.com/rust-lang/cc-rs/compare/1.0.77...1.0.78) --- updated-dependencies: - dependency-name: cc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3592e621ed0f..96c39fd5c81d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.77" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" [[package]] name = "cfg-if" From 1f4d277013783c9c537444299ba4e558b9047fe2 Mon Sep 17 00:00:00 2001 From: farwyler <1705805+farwyler@users.noreply.github.com> Date: Tue, 27 Dec 2022 15:57:09 +0100 Subject: [PATCH 170/269] Allow custom preprocessors for 'vue' injections (#5268) --- runtime/queries/vue/injections.scm | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/runtime/queries/vue/injections.scm b/runtime/queries/vue/injections.scm index 73df868b6926..1b053e748d3f 100644 --- a/runtime/queries/vue/injections.scm +++ b/runtime/queries/vue/injections.scm @@ -8,13 +8,37 @@ (raw_text) @injection.content) (#set! injection.language "javascript")) +;