From ab7885e93423dbfb57e2b6e7589672c67a4666e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Thu, 31 Mar 2022 15:53:31 +0900 Subject: [PATCH 001/861] fix: copy_selection needs to account for to() being exclusive Fixes #1367 Fixes #1590 --- helix-term/src/commands.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index bd66f26a2..3ef72bde8 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1342,8 +1342,17 @@ fn copy_selection_on_line(cx: &mut Context, direction: Direction) { let mut primary_index = 0; for range in selection.iter() { let is_primary = *range == selection.primary(); - let head_pos = coords_at_pos(text, range.head); + + // The range is always head exclusive + let head = if range.anchor < range.head { + range.head - 1 + } else { + range.head + }; + + let head_pos = coords_at_pos(text, head); let anchor_pos = coords_at_pos(text, range.anchor); + let height = std::cmp::max(head_pos.row, anchor_pos.row) - std::cmp::min(head_pos.row, anchor_pos.row) + 1; From d15c875214d2147bf9bdf03ef3445752476d14b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Thu, 31 Mar 2022 15:58:52 +0900 Subject: [PATCH 002/861] Add a TODO for the future --- helix-term/src/commands.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 3ef72bde8..320bfc94e 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1350,6 +1350,7 @@ fn copy_selection_on_line(cx: &mut Context, direction: Direction) { range.head }; + // TODO: this should use visual offsets / pos_at_screen_coords let head_pos = coords_at_pos(text, head); let anchor_pos = coords_at_pos(text, range.anchor); From ef91b6500c208807cf71ab07f04bad27f0190a65 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Thu, 31 Mar 2022 02:31:38 -0500 Subject: [PATCH 003/861] set VERSION file to dev (#1883) * set VERSION file to dev * bump to 22.05-dev --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 24b267470..4c3f332ef 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -22.03 \ No newline at end of file +22.05-dev \ No newline at end of file From 5d61631507143194594f1dff6af9f862ce79992e Mon Sep 17 00:00:00 2001 From: Rohan Jain <343499+crodjer@users.noreply.github.com> Date: Thu, 31 Mar 2022 13:21:11 +0530 Subject: [PATCH 004/861] Resolve conflicts between prompt/picker bindings (#1792) Currently, the picker's re-using a few bindings which are also present in the prompt. This causes some editing behaviours to not function on the picker. **Ctrl + k** and **Ctrl + j** This should kill till the end of the line on prompt, but is overridden by the picker for scrolling. Since there are redundancies (`Ctrl + p`, `Ctrl + n`), we can remove it from picker. **Ctrl + f** and **Ctrl + b** This are used by the prompt for back/forward movement. We could modify it to be Ctrl + d and Ctrl + u, to match the `vim` behaviour. --- book/src/keymap.md | 8 ++++---- helix-term/src/ui/picker.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index 374513be0..e588ac925 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -331,10 +331,10 @@ Keys to use within picker. Remapping currently not supported. | Key | Description | | ----- | ------------- | -| `Up`, `Ctrl-k`, `Ctrl-p` | Previous entry | -| `PageUp`, `Ctrl-b` | Page up | -| `Down`, `Ctrl-j`, `Ctrl-n` | Next entry | -| `PageDown`, `Ctrl-f` | Page down | +| `Up`, `Ctrl-p` | Previous entry | +| `PageUp`, `Ctrl-u` | Page up | +| `Down`, `Ctrl-n` | Next entry | +| `PageDown`, `Ctrl-d` | Page down | | `Home` | Go to first entry | | `End` | Go to last entry | | `Ctrl-space` | Filter options | diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 42c42284c..dec59c892 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -498,16 +498,16 @@ impl Component for Picker { }))); match key_event.into() { - shift!(Tab) | key!(Up) | ctrl!('p') | ctrl!('k') => { + shift!(Tab) | key!(Up) | ctrl!('p') => { self.move_by(1, Direction::Backward); } - key!(Tab) | key!(Down) | ctrl!('n') | ctrl!('j') => { + key!(Tab) | key!(Down) | ctrl!('n') => { self.move_by(1, Direction::Forward); } - key!(PageDown) | ctrl!('f') => { + key!(PageDown) | ctrl!('d') => { self.page_down(); } - key!(PageUp) | ctrl!('b') => { + key!(PageUp) | ctrl!('u') => { self.page_up(); } key!(Home) => { From 84e799f0e4fdbae1dd574439f5b9776ce8ea3f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Thu, 31 Mar 2022 17:45:51 +0900 Subject: [PATCH 005/861] fix: Some LSPs still want rootPath, so provide it Refs #1898 --- helix-lsp/src/client.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 1ce5158be..dbdd885b2 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -235,7 +235,10 @@ impl Client { pub(crate) async fn initialize(&self) -> Result { // TODO: delay any requests that are triggered prior to initialize - let root = find_root(None, &self.root_markers) + let root_path = find_root(None, &self.root_markers); + + let root_uri = root_path + .clone() .and_then(|root| lsp::Url::from_file_path(root).ok()); if self.config.is_some() { @@ -245,9 +248,10 @@ impl Client { #[allow(deprecated)] let params = lsp::InitializeParams { process_id: Some(std::process::id()), - // root_path is obsolete, use root_uri - root_path: None, - root_uri: root, + // root_path is obsolete, but some clients like pyright still use it so we specify both. + // clients will prefer _uri if possible + root_path: root_path.and_then(|path| path.to_str().map(|path| path.to_owned())), + root_uri, initialization_options: self.config.clone(), capabilities: lsp::ClientCapabilities { workspace: Some(lsp::WorkspaceClientCapabilities { From 924462edda05a11f0dc260b516af39c13bee2949 Mon Sep 17 00:00:00 2001 From: Marcin Puc Date: Thu, 31 Mar 2022 21:55:55 +0200 Subject: [PATCH 006/861] Add install instructions for Void Linux (#1911) --- book/src/install.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/book/src/install.md b/book/src/install.md index b3d42aaf4..372ce12a1 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -41,6 +41,12 @@ sudo dnf copr enable varlad/helix sudo dnf install helix ``` +### Void Linux + +``` +sudo xbps-install helix +``` + ## Build from source ``` From 236c6b77077596f8c7b5a5377e23e96ecec45e07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Fri, 1 Apr 2022 10:10:59 +0900 Subject: [PATCH 007/861] fix: copy_selections was broken with selections (not cursors) --- helix-term/src/commands.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 320bfc94e..3c5e08527 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1392,7 +1392,8 @@ fn copy_selection_on_line(cx: &mut Context, direction: Direction) { if is_primary { primary_index = ranges.len(); } - ranges.push(Range::new(anchor, head)); + // This is Range::new(anchor, head), but it will place the cursor on the correct column + ranges.push(Range::point(anchor).put_cursor(text, head, true)); sels += 1; } From 8adf0c1b3a7a2173c80a86da5d435288bab456de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Fri, 1 Apr 2022 11:20:41 +0900 Subject: [PATCH 008/861] lsp: Implement support for workspace_folders (currently just one) Refs #1898 --- helix-lsp/src/client.rs | 53 +++++++++++++++++++++------- helix-lsp/src/lib.rs | 4 ++- helix-term/src/application.rs | 65 ++++++++++++++++------------------- 3 files changed, 72 insertions(+), 50 deletions(-) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index dbdd885b2..8b14b0b87 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -31,7 +31,9 @@ pub struct Client { pub(crate) capabilities: OnceCell, offset_encoding: OffsetEncoding, config: Option, - root_markers: Vec, + root_path: Option, + root_uri: Option, + workspace_folders: Vec, } impl Client { @@ -40,7 +42,7 @@ impl Client { cmd: &str, args: &[String], config: Option, - root_markers: Vec, + root_markers: &[String], id: usize, ) -> Result<(Self, UnboundedReceiver<(usize, Call)>, Arc)> { // Resolve path to the binary @@ -65,6 +67,27 @@ impl Client { let (server_rx, server_tx, initialize_notify) = Transport::start(reader, writer, stderr, id); + let root_path = find_root(None, root_markers); + + let root_uri = root_path + .clone() + .and_then(|root| lsp::Url::from_file_path(root).ok()); + + // TODO: support multiple workspace folders + let workspace_folders = root_uri + .clone() + .map(|root| { + vec![lsp::WorkspaceFolder { + name: root + .path_segments() + .and_then(|segments| segments.last()) + .map(|basename| basename.to_string()) + .unwrap_or_default(), + uri: root, + }] + }) + .unwrap_or_default(); + let client = Self { id, _process: process, @@ -73,7 +96,10 @@ impl Client { capabilities: OnceCell::new(), offset_encoding: OffsetEncoding::Utf8, config, - root_markers, + + root_path, + root_uri, + workspace_folders, }; Ok((client, server_rx, initialize_notify)) @@ -117,6 +143,10 @@ impl Client { self.config.as_ref() } + pub fn workspace_folders(&self) -> &[lsp::WorkspaceFolder] { + &self.workspace_folders + } + /// Execute a RPC request on the language server. async fn request(&self, params: R::Params) -> Result where @@ -234,13 +264,6 @@ impl Client { // ------------------------------------------------------------------------------------------- pub(crate) async fn initialize(&self) -> Result { - // TODO: delay any requests that are triggered prior to initialize - let root_path = find_root(None, &self.root_markers); - - let root_uri = root_path - .clone() - .and_then(|root| lsp::Url::from_file_path(root).ok()); - if self.config.is_some() { log::info!("Using custom LSP config: {}", self.config.as_ref().unwrap()); } @@ -248,10 +271,14 @@ impl Client { #[allow(deprecated)] let params = lsp::InitializeParams { process_id: Some(std::process::id()), + workspace_folders: Some(self.workspace_folders.clone()), // root_path is obsolete, but some clients like pyright still use it so we specify both. // clients will prefer _uri if possible - root_path: root_path.and_then(|path| path.to_str().map(|path| path.to_owned())), - root_uri, + root_path: self + .root_path + .clone() + .and_then(|path| path.to_str().map(|path| path.to_owned())), + root_uri: self.root_uri.clone(), initialization_options: self.config.clone(), capabilities: lsp::ClientCapabilities { workspace: Some(lsp::WorkspaceClientCapabilities { @@ -259,6 +286,7 @@ impl Client { did_change_configuration: Some(lsp::DynamicRegistrationClientCapabilities { dynamic_registration: Some(false), }), + workspace_folders: Some(true), ..Default::default() }), text_document: Some(lsp::TextDocumentClientCapabilities { @@ -314,7 +342,6 @@ impl Client { ..Default::default() }, trace: None, - workspace_folders: None, client_info: None, locale: None, // TODO }; diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 389dfb4dd..767481367 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -191,6 +191,7 @@ pub mod util { pub enum MethodCall { WorkDoneProgressCreate(lsp::WorkDoneProgressCreateParams), ApplyWorkspaceEdit(lsp::ApplyWorkspaceEditParams), + WorkspaceFolders, WorkspaceConfiguration(lsp::ConfigurationParams), } @@ -210,6 +211,7 @@ impl MethodCall { .expect("Failed to parse ApplyWorkspaceEdit params"); Self::ApplyWorkspaceEdit(params) } + lsp::request::WorkspaceFoldersRequest::METHOD => Self::WorkspaceFolders, lsp::request::WorkspaceConfiguration::METHOD => { let params: lsp::ConfigurationParams = params .parse() @@ -320,7 +322,7 @@ impl Registry { &config.command, &config.args, language_config.config.clone(), - language_config.roots.clone(), + &language_config.roots, id, )?; self.incoming.push(UnboundedReceiverStream::new(incoming)); diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 09b1ff619..ddf9e8d6d 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -601,7 +601,7 @@ impl Application { } }; - match call { + let reply = match call { MethodCall::WorkDoneProgressCreate(params) => { self.lsp_progress.create(server_id, params.token); @@ -613,16 +613,8 @@ impl Application { if spinner.is_stopped() { spinner.start(); } - let language_server = - match self.editor.language_servers.get_by_id(server_id) { - Some(language_server) => language_server, - None => { - warn!("can't find language server with id `{}`", server_id); - return; - } - }; - tokio::spawn(language_server.reply(id, Ok(serde_json::Value::Null))); + Ok(serde_json::Value::Null) } MethodCall::ApplyWorkspaceEdit(params) => { apply_workspace_edit( @@ -631,33 +623,19 @@ impl Application { ¶ms.edit, ); + Ok(json!(lsp::ApplyWorkspaceEditResponse { + applied: true, + failure_reason: None, + failed_change: None, + })) + } + MethodCall::WorkspaceFolders => { let language_server = - match self.editor.language_servers.get_by_id(server_id) { - Some(language_server) => language_server, - None => { - warn!("can't find language server with id `{}`", server_id); - return; - } - }; + self.editor.language_servers.get_by_id(server_id).unwrap(); - tokio::spawn(language_server.reply( - id, - Ok(json!(lsp::ApplyWorkspaceEditResponse { - applied: true, - failure_reason: None, - failed_change: None, - })), - )); + Ok(json!(language_server.workspace_folders())) } MethodCall::WorkspaceConfiguration(params) => { - let language_server = - match self.editor.language_servers.get_by_id(server_id) { - Some(language_server) => language_server, - None => { - warn!("can't find language server with id `{}`", server_id); - return; - } - }; let result: Vec<_> = params .items .iter() @@ -668,7 +646,12 @@ impl Application { let doc = self.editor.document_by_path(path)?; doc.language_config()?.config.as_ref()? } - None => language_server.config()?, + None => self + .editor + .language_servers + .get_by_id(server_id) + .unwrap() + .config()?, }; if let Some(section) = item.section.as_ref() { for part in section.split('.') { @@ -678,9 +661,19 @@ impl Application { Some(config) }) .collect(); - tokio::spawn(language_server.reply(id, Ok(json!(result)))); + Ok(json!(result)) } - } + }; + + let language_server = match self.editor.language_servers.get_by_id(server_id) { + Some(language_server) => language_server, + None => { + warn!("can't find language server with id `{}`", server_id); + return; + } + }; + + tokio::spawn(language_server.reply(id, reply)); } Call::Invalid { id } => log::error!("LSP invalid method call id={:?}", id), } From 6bb229839149742682d943a90f728e334c3cc560 Mon Sep 17 00:00:00 2001 From: Triton171 Date: Fri, 1 Apr 2022 04:27:06 +0200 Subject: [PATCH 009/861] Fix an issue that caused an empty indentation query to be used instead of using the fallback method of copying the indentation from the current line. (#1908) Co-authored-by: Triton171 --- helix-core/src/syntax.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index dde7e90cd..e736b3708 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -398,6 +398,9 @@ impl LanguageConfiguration { .get_or_init(|| { let lang_name = self.language_id.to_ascii_lowercase(); let query_text = read_query(&lang_name, "indents.scm"); + if query_text.is_empty() { + return None; + } let lang = self.highlight_config.get()?.as_ref()?.language; Query::new(lang, &query_text).ok() }) From a9635659f7d0dbbf2f11552842cf789ce1797914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D8=AC=D8=A7=D8=AF?= Date: Thu, 31 Mar 2022 19:35:47 -0700 Subject: [PATCH 010/861] Reintroduce win32yank as a clipboard provider on Linux for WSL2 + Windows 10 (#1912) * feat(clipboard): reintroduce win32yank for wsl2 linux * refactor(clipboard): adjust win32yank position to not interrupt wayland/x11 Co-authored-by: jiqb --- helix-view/src/clipboard.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/helix-view/src/clipboard.rs b/helix-view/src/clipboard.rs index c213827ee..5cc5cad89 100644 --- a/helix-view/src/clipboard.rs +++ b/helix-view/src/clipboard.rs @@ -104,6 +104,11 @@ pub fn get_clipboard_provider() -> Box { primary_paste => "xsel", "-o"; primary_copy => "xsel", "-i"; } + } else if exists("win32yank.exe") { + command_provider! { + paste => "win32yank.exe", "-o", "--lf"; + copy => "win32yank.exe", "-i", "--crlf"; + } } else if exists("termux-clipboard-set") && exists("termux-clipboard-get") { command_provider! { paste => "termux-clipboard-get"; From d0ff2ffd891eb9d674840fdff896e6f26dc60ca5 Mon Sep 17 00:00:00 2001 From: Amine Hmida Date: Fri, 1 Apr 2022 09:08:34 +0100 Subject: [PATCH 011/861] Add support for jsx (#1906) * Add support for javascriptreact language * Add support for jsx files --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 3439d7f01..3a61ea44e 100644 --- a/languages.toml +++ b/languages.toml @@ -266,7 +266,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-go", rev = "0fa917a name = "javascript" scope = "source.js" injection-regex = "^(js|javascript)$" -file-types = ["js", "mjs"] +file-types = ["js", "jsx", "mjs"] shebangs = ["node"] roots = [] comment-token = "//" From a24fb17b2a978d3165bd6304e9edd69bddb6dd82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Fri, 1 Apr 2022 17:14:25 +0900 Subject: [PATCH 012/861] Add JSX highlighting queries --- languages.toml | 6 +++--- runtime/queries/javascript/highlights-jsx.scm | 4 ---- runtime/queries/javascript/highlights.scm | 8 ++++++++ 3 files changed, 11 insertions(+), 7 deletions(-) delete mode 100644 runtime/queries/javascript/highlights-jsx.scm diff --git a/languages.toml b/languages.toml index 3a61ea44e..4bbf1689f 100644 --- a/languages.toml +++ b/languages.toml @@ -270,7 +270,7 @@ file-types = ["js", "jsx", "mjs"] shebangs = ["node"] roots = [] comment-token = "//" -# TODO: highlights-jsx, highlights-params +# TODO: highlights-params language-server = { command = "typescript-language-server", args = ["--stdio"], language-id = "javascript" } indent = { tab-width = 2, unit = " " } @@ -297,7 +297,7 @@ injection-regex = "^(ts|typescript)$" file-types = ["ts"] shebangs = [] roots = [] -# TODO: highlights-jsx, highlights-params +# TODO: highlights-params language-server = { command = "typescript-language-server", args = ["--stdio"], language-id = "typescript"} indent = { tab-width = 2, unit = " " } @@ -311,7 +311,7 @@ scope = "source.tsx" injection-regex = "^(tsx)$" # |typescript file-types = ["tsx"] roots = [] -# TODO: highlights-jsx, highlights-params +# TODO: highlights-params language-server = { command = "typescript-language-server", args = ["--stdio"], language-id = "typescriptreact" } indent = { tab-width = 2, unit = " " } diff --git a/runtime/queries/javascript/highlights-jsx.scm b/runtime/queries/javascript/highlights-jsx.scm deleted file mode 100644 index 751da0813..000000000 --- a/runtime/queries/javascript/highlights-jsx.scm +++ /dev/null @@ -1,4 +0,0 @@ -(jsx_opening_element (identifier) @tag) -(jsx_closing_element (identifier) @tag) -(jsx_self_closing_element (identifier) @tag) -(jsx_attribute (property_identifier) @attribute) diff --git a/runtime/queries/javascript/highlights.scm b/runtime/queries/javascript/highlights.scm index 6163b680d..96bad862f 100644 --- a/runtime/queries/javascript/highlights.scm +++ b/runtime/queries/javascript/highlights.scm @@ -1,3 +1,11 @@ +; JSX +;---- + +(jsx_opening_element (identifier) @tag) +(jsx_closing_element (identifier) @tag) +(jsx_self_closing_element (identifier) @tag) +(jsx_attribute (property_identifier) @variable.other.member) + ; Special identifiers ;-------------------- From 855e438f55cb278de8203ac4911561c4c7ad656c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Fri, 1 Apr 2022 17:18:44 +0900 Subject: [PATCH 013/861] jsx: Add special highlighting to component names --- runtime/queries/javascript/highlights.scm | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/runtime/queries/javascript/highlights.scm b/runtime/queries/javascript/highlights.scm index 96bad862f..ccc58a9ec 100644 --- a/runtime/queries/javascript/highlights.scm +++ b/runtime/queries/javascript/highlights.scm @@ -1,6 +1,28 @@ ; JSX ;---- +; Highlight component names differently + +(jsx_opening_element ((identifier) @constructor + (#match? @constructor "^[A-Z]"))) + +; Handle the dot operator effectively - +(jsx_opening_element ((nested_identifier (identifier) @tag (identifier) @constructor))) + +(jsx_closing_element ((identifier) @constructor + (#match? @constructor "^[A-Z]"))) + +; Handle the dot operator effectively - +(jsx_closing_element ((nested_identifier (identifier) @tag (identifier) @constructor))) + +(jsx_self_closing_element ((identifier) @constructor + (#match? @constructor "^[A-Z]"))) + +; Handle the dot operator effectively - +(jsx_self_closing_element ((nested_identifier (identifier) @tag (identifier) @constructor))) + +; TODO: also tag @punctuation.delimiter? + (jsx_opening_element (identifier) @tag) (jsx_closing_element (identifier) @tag) (jsx_self_closing_element (identifier) @tag) From 47fe7397574208ecdcccc63770ce1b0374de1126 Mon Sep 17 00:00:00 2001 From: antoyo Date: Fri, 1 Apr 2022 09:14:37 -0400 Subject: [PATCH 014/861] Jump to the next number on the line before incrementing (#1778) * Jump to the next number on the line before incrementing Partially fix #1645 * Refactor to avoid duplicating find_nth_next --- helix-core/src/search.rs | 26 +++++++++++++++++++++-- helix-term/src/commands.rs | 42 +++++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/helix-core/src/search.rs b/helix-core/src/search.rs index 243ac227a..81cb41293 100644 --- a/helix-core/src/search.rs +++ b/helix-core/src/search.rs @@ -1,6 +1,28 @@ use crate::RopeSlice; -pub fn find_nth_next(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Option { +// TODO: switch to std::str::Pattern when it is stable. +pub trait CharMatcher { + fn char_match(&self, ch: char) -> bool; +} + +impl CharMatcher for char { + fn char_match(&self, ch: char) -> bool { + *self == ch + } +} + +impl bool> CharMatcher for F { + fn char_match(&self, ch: char) -> bool { + (*self)(&ch) + } +} + +pub fn find_nth_next( + text: RopeSlice, + char_matcher: M, + mut pos: usize, + n: usize, +) -> Option { if pos >= text.len_chars() || n == 0 { return None; } @@ -13,7 +35,7 @@ pub fn find_nth_next(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Opt pos += 1; - if c == ch { + if char_matcher.char_match(c) { break; } } diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 3c5e08527..104db4590 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -18,7 +18,8 @@ use helix_core::{ movement::{self, Direction}, object, pos_at_coords, regex::{self, Regex, RegexBuilder}, - search, selection, shellwords, surround, textobject, + search::{self, CharMatcher}, + selection, shellwords, surround, textobject, tree_sitter::Node, unicode::width::UnicodeWidthChar, LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, Selection, SmallVec, Tendril, @@ -1053,15 +1054,15 @@ where // #[inline] -fn find_char_impl( +fn find_char_impl( editor: &mut Editor, search_fn: &F, inclusive: bool, extend: bool, - ch: char, + char_matcher: M, count: usize, ) where - F: Fn(RopeSlice, char, usize, usize, bool) -> Option + 'static, + F: Fn(RopeSlice, M, usize, usize, bool) -> Option + 'static, { let (view, doc) = current!(editor); let text = doc.text().slice(..); @@ -1076,7 +1077,7 @@ fn find_char_impl( range.head }; - search_fn(text, ch, search_start_pos, count, inclusive).map_or(range, |pos| { + search_fn(text, char_matcher, search_start_pos, count, inclusive).map_or(range, |pos| { if extend { range.put_cursor(text, pos, true) } else { @@ -4327,8 +4328,39 @@ fn decrement(cx: &mut Context) { increment_impl(cx, -(cx.count() as i64)); } +/// This function differs from find_next_char_impl in that it stops searching at the newline, but also +/// starts searching at the current character, instead of the next. +/// It does not want to start at the next character because this function is used for incrementing +/// number and we don't want to move forward if we're already on a digit. +fn find_next_char_until_newline( + text: RopeSlice, + char_matcher: M, + pos: usize, + _count: usize, + _inclusive: bool, +) -> Option { + // Since we send the current line to find_nth_next instead of the whole text, we need to adjust + // the position we send to this function so that it's relative to that line and its returned + // position since it's expected this function returns a global position. + let line_index = text.char_to_line(pos); + let pos_delta = text.line_to_char(line_index); + let pos = pos - pos_delta; + search::find_nth_next(text.line(line_index), char_matcher, pos, 1).map(|pos| pos + pos_delta) +} + /// Decrement object under cursor by `amount`. fn increment_impl(cx: &mut Context, amount: i64) { + // TODO: when incrementing or decrementing a number that gets a new digit or lose one, the + // selection is updated improperly. + find_char_impl( + cx.editor, + &find_next_char_until_newline, + true, + true, + char::is_ascii_digit, + 1, + ); + let (view, doc) = current!(cx.editor); let selection = doc.selection(view.id); let text = doc.text().slice(..); From 8165febe23cbd8bb9cd99cceac9d09b81f35456e Mon Sep 17 00:00:00 2001 From: jeepee Date: Fri, 1 Apr 2022 15:16:09 +0200 Subject: [PATCH 015/861] Fix start-position of next search (#1904) The search implementation would start searching at the next grapheme boundary after the previous selection. In case the next occurence of the needle is immediately after the current selection, this occurence would not be found (without wraparound) because the first grapheme is skipped. The correct approach is to use the ensure_grapheme_boundary functions instead of using the functions that skip unconditionally to the next grapheme. --- helix-term/src/commands.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 104db4590..f4844170a 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1488,11 +1488,11 @@ fn search_impl( // Get the right side of the primary block cursor for forward search, or the // grapheme before the start of the selection for reverse search. let start = match direction { - Direction::Forward => text.char_to_byte(graphemes::next_grapheme_boundary( + Direction::Forward => text.char_to_byte(graphemes::ensure_grapheme_boundary_next( text, selection.primary().to(), )), - Direction::Backward => text.char_to_byte(graphemes::prev_grapheme_boundary( + Direction::Backward => text.char_to_byte(graphemes::ensure_grapheme_boundary_prev( text, selection.primary().from(), )), From 85c23b31deb73d71bb38264485d728665f151d4a Mon Sep 17 00:00:00 2001 From: jeepee Date: Fri, 1 Apr 2022 15:16:51 +0200 Subject: [PATCH 016/861] Avoid unnecessary clone when formatting error (#1903) Instead of first cloning the query and then allocating again to format the error, format the error using a reference to the query. --- helix-term/src/commands.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index f4844170a..296480395 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1646,11 +1646,8 @@ fn search_next_or_prev_impl(cx: &mut Context, movement: Movement, direction: Dir wrap_around, ); } else { - // get around warning `mutable_borrow_reservation_conflict` - // which will be a hard error in the future - // see: https://github.com/rust-lang/rust/issues/59159 - let query = query.clone(); - cx.editor.set_error(format!("Invalid regex: {}", query)); + let error = format!("Invalid regex: {}", query); + cx.editor.set_error(error); } } } From deb7ee6595644accf88e0232aefe419d6f757365 Mon Sep 17 00:00:00 2001 From: joezak11 <69003115+joezak11@users.noreply.github.com> Date: Fri, 1 Apr 2022 15:48:39 +0200 Subject: [PATCH 017/861] Update bash tree sitter (#1917) --- languages.toml | 2 +- runtime/queries/bash/highlights.scm | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 4bbf1689f..ff8e7dfbf 100644 --- a/languages.toml +++ b/languages.toml @@ -402,7 +402,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "bash" -source = { git = "https://github.com/tree-sitter/tree-sitter-bash", rev = "a8eb5cb57c66f74c63ab950de081207cccf52017" } +source = { git = "https://github.com/tree-sitter/tree-sitter-bash", rev = "275effdfc0edce774acf7d481f9ea195c6c403cd" } [[language]] name = "php" diff --git a/runtime/queries/bash/highlights.scm b/runtime/queries/bash/highlights.scm index 57898f277..3f2df6386 100644 --- a/runtime/queries/bash/highlights.scm +++ b/runtime/queries/bash/highlights.scm @@ -46,6 +46,7 @@ ">>" "<" "|" + (expansion_flags) ] @operator ( From ffdc2f179334de82383670faed68acfc54317f55 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 1 Apr 2022 20:07:35 -0500 Subject: [PATCH 018/861] separate JSX queries from javascript (#1921) It looks like a24fb17b2a978d3165bd6304e9edd69bddb6dd82 (and 855e438f55cb278de8203ac4911561c4c7ad656c) broke the typescript highlights because typescript ; inherits: javascript but it doesn't have those named nodes in its grammar. So instead we can separate out JSX into its own language and copy over everything from javascript and supplement it with the new JSX highlights. Luckily there isn't too much duplication, just the language configuration parts - we can re-use the parser with the languages.toml `grammar` key and most of the queries with `inherits`. --- book/src/generated/lang-support.md | 1 + languages.toml | 11 +++++++++ runtime/queries/javascript/highlights.scm | 30 ----------------------- runtime/queries/jsx/highlights.scm | 27 ++++++++++++++++++++ runtime/queries/jsx/indents.scm | 1 + runtime/queries/jsx/injections.scm | 1 + runtime/queries/jsx/locals.scm | 1 + 7 files changed, 42 insertions(+), 30 deletions(-) create mode 100644 runtime/queries/jsx/highlights.scm create mode 100644 runtime/queries/jsx/indents.scm create mode 100644 runtime/queries/jsx/injections.scm create mode 100644 runtime/queries/jsx/locals.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 34e65e46c..8c1a78c89 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -28,6 +28,7 @@ | java | ✓ | | | | | javascript | ✓ | | ✓ | `typescript-language-server` | | json | ✓ | | ✓ | | +| jsx | ✓ | | ✓ | `typescript-language-server` | | julia | ✓ | | | `julia` | | kotlin | ✓ | | | `kotlin-language-server` | | latex | ✓ | | | | diff --git a/languages.toml b/languages.toml index ff8e7dfbf..d12093a43 100644 --- a/languages.toml +++ b/languages.toml @@ -290,6 +290,17 @@ args = { program = "{0}" } name = "javascript" source = { git = "https://github.com/tree-sitter/tree-sitter-javascript", rev = "4a95461c4761c624f2263725aca79eeaefd36cad" } +[[language]] +name = "jsx" +scope = "source.jsx" +injection-regex = "jsx" +file-types = ["jsx"] +roots = [] +comment-token = "//" +language-server = { command = "typescript-language-server", args = ["--stdio"], language-id = "javascript" } +indent = { tab-width = 2, unit = " " } +grammar = "javascript" + [[language]] name = "typescript" scope = "source.ts" diff --git a/runtime/queries/javascript/highlights.scm b/runtime/queries/javascript/highlights.scm index ccc58a9ec..6163b680d 100644 --- a/runtime/queries/javascript/highlights.scm +++ b/runtime/queries/javascript/highlights.scm @@ -1,33 +1,3 @@ -; JSX -;---- - -; Highlight component names differently - -(jsx_opening_element ((identifier) @constructor - (#match? @constructor "^[A-Z]"))) - -; Handle the dot operator effectively - -(jsx_opening_element ((nested_identifier (identifier) @tag (identifier) @constructor))) - -(jsx_closing_element ((identifier) @constructor - (#match? @constructor "^[A-Z]"))) - -; Handle the dot operator effectively - -(jsx_closing_element ((nested_identifier (identifier) @tag (identifier) @constructor))) - -(jsx_self_closing_element ((identifier) @constructor - (#match? @constructor "^[A-Z]"))) - -; Handle the dot operator effectively - -(jsx_self_closing_element ((nested_identifier (identifier) @tag (identifier) @constructor))) - -; TODO: also tag @punctuation.delimiter? - -(jsx_opening_element (identifier) @tag) -(jsx_closing_element (identifier) @tag) -(jsx_self_closing_element (identifier) @tag) -(jsx_attribute (property_identifier) @variable.other.member) - ; Special identifiers ;-------------------- diff --git a/runtime/queries/jsx/highlights.scm b/runtime/queries/jsx/highlights.scm new file mode 100644 index 000000000..9be5f5176 --- /dev/null +++ b/runtime/queries/jsx/highlights.scm @@ -0,0 +1,27 @@ +; inherits: javascript + +; Highlight component names differently +(jsx_opening_element ((identifier) @constructor + (#match? @constructor "^[A-Z]"))) + +; Handle the dot operator effectively - +(jsx_opening_element ((nested_identifier (identifier) @tag (identifier) @constructor))) + +(jsx_closing_element ((identifier) @constructor + (#match? @constructor "^[A-Z]"))) + +; Handle the dot operator effectively - +(jsx_closing_element ((nested_identifier (identifier) @tag (identifier) @constructor))) + +(jsx_self_closing_element ((identifier) @constructor + (#match? @constructor "^[A-Z]"))) + +; Handle the dot operator effectively - +(jsx_self_closing_element ((nested_identifier (identifier) @tag (identifier) @constructor))) + +; TODO: also tag @punctuation.delimiter? + +(jsx_opening_element (identifier) @tag) +(jsx_closing_element (identifier) @tag) +(jsx_self_closing_element (identifier) @tag) +(jsx_attribute (property_identifier) @variable.other.member) diff --git a/runtime/queries/jsx/indents.scm b/runtime/queries/jsx/indents.scm new file mode 100644 index 000000000..ff0ddfacf --- /dev/null +++ b/runtime/queries/jsx/indents.scm @@ -0,0 +1 @@ +; inherits: javascript diff --git a/runtime/queries/jsx/injections.scm b/runtime/queries/jsx/injections.scm new file mode 100644 index 000000000..ff0ddfacf --- /dev/null +++ b/runtime/queries/jsx/injections.scm @@ -0,0 +1 @@ +; inherits: javascript diff --git a/runtime/queries/jsx/locals.scm b/runtime/queries/jsx/locals.scm new file mode 100644 index 000000000..ff0ddfacf --- /dev/null +++ b/runtime/queries/jsx/locals.scm @@ -0,0 +1 @@ +; inherits: javascript From 36d1df71fc99b0f2e3b594f9d7d0f07ef829b9fc Mon Sep 17 00:00:00 2001 From: Simon H Date: Sat, 2 Apr 2022 10:32:36 +0200 Subject: [PATCH 019/861] Added checkmarks to health.rs output, Resolves #1894 (#1918) * Added checkmarks to health.rs output * replaced found/not found text with checkmarks --- helix-term/src/health.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/helix-term/src/health.rs b/helix-term/src/health.rs index f73139fc3..7f582cbf5 100644 --- a/helix-term/src/health.rs +++ b/helix-term/src/health.rs @@ -154,8 +154,8 @@ pub fn languages_all() -> std::io::Result<()> { for ts_feat in TsFeature::all() { match load_runtime_file(&lang.language_id, ts_feat.runtime_filename()).is_ok() { - true => column("Found", Color::Green), - false => column("Not Found", Color::Red), + true => column("✔", Color::Green), + false => column("✘", Color::Red), } } @@ -263,8 +263,8 @@ fn probe_treesitter_feature(lang: &str, feature: TsFeature) -> std::io::Result<( let mut stdout = stdout.lock(); let found = match load_runtime_file(lang, feature.runtime_filename()).is_ok() { - true => "Found".green(), - false => "Not found".red(), + true => "✔".green(), + false => "✘".red(), }; writeln!(stdout, "{} queries: {}", feature.short_title(), found)?; From e4561d1ddede65baaaf04adf5baa0edbaf8f8028 Mon Sep 17 00:00:00 2001 From: Lauri Gustafsson Date: Sat, 2 Apr 2022 17:00:05 +0300 Subject: [PATCH 020/861] Add texlab language server for latex (#1922) --- book/src/generated/lang-support.md | 2 +- languages.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 8c1a78c89..694d1d128 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -31,7 +31,7 @@ | jsx | ✓ | | ✓ | `typescript-language-server` | | julia | ✓ | | | `julia` | | kotlin | ✓ | | | `kotlin-language-server` | -| latex | ✓ | | | | +| latex | ✓ | | | `texlab` | | lean | ✓ | | | `lean` | | ledger | ✓ | | | | | llvm | ✓ | ✓ | ✓ | | diff --git a/languages.toml b/languages.toml index d12093a43..0220c33b8 100644 --- a/languages.toml +++ b/languages.toml @@ -447,6 +447,7 @@ injection-regex = "tex" file-types = ["tex"] roots = [] comment-token = "%" +language-server = { command = "texlab" } indent = { tab-width = 4, unit = "\t" } [[grammar]] From 8b02bf2ea8c07926697ad8e1e01d77596a540d59 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 7 Feb 2022 23:37:09 +0800 Subject: [PATCH 021/861] Add (prev) paragraph motion Also improved testing facility. Fix #1580 --- helix-core/src/lib.rs | 1 + helix-core/src/line_ending.rs | 5 ++ helix-core/src/movement.rs | 121 +++++++++++++++++++++++++++++++ helix-core/src/test.rs | 111 ++++++++++++++++++++++++++++ helix-term/src/commands.rs | 30 ++++++++ helix-term/src/keymap/default.rs | 2 + 6 files changed, 270 insertions(+) create mode 100644 helix-core/src/test.rs diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 1f43c2667..0ae68f914 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -24,6 +24,7 @@ pub mod shellwords; mod state; pub mod surround; pub mod syntax; +pub mod test; pub mod textobject; mod transaction; diff --git a/helix-core/src/line_ending.rs b/helix-core/src/line_ending.rs index 06ec2a459..f0cf3b101 100644 --- a/helix-core/src/line_ending.rs +++ b/helix-core/src/line_ending.rs @@ -119,6 +119,11 @@ pub fn str_is_line_ending(s: &str) -> bool { LineEnding::from_str(s).is_some() } +#[inline] +pub fn rope_is_line_ending(r: RopeSlice) -> bool { + r.chunks().all(str_is_line_ending) +} + /// Attempts to detect what line ending the passed document uses. pub fn auto_detect_line_ending(doc: &Rope) -> Option { // Return first matched line ending. Not all possible line endings diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs index e559f1ea6..21d169314 100644 --- a/helix-core/src/movement.rs +++ b/helix-core/src/movement.rs @@ -10,6 +10,7 @@ use crate::{ next_grapheme_boundary, nth_next_grapheme_boundary, nth_prev_grapheme_boundary, prev_grapheme_boundary, }, + line_ending::{rope_is_line_ending, str_is_line_ending}, pos_at_coords, syntax::LanguageConfiguration, textobject::TextObject, @@ -149,6 +150,63 @@ fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTar }) } +pub fn move_prev_para(slice: RopeSlice, range: Range, count: usize, behavior: Movement) -> Range { + let mut line = range.cursor_line(slice); + let first_char = slice.line_to_char(line) == range.cursor(slice); + let curr_line_empty = rope_is_line_ending(slice.line(line)); + let last_line_empty = rope_is_line_ending(slice.line(line.saturating_sub(1))); + let line_to_empty = last_line_empty && !curr_line_empty; + + // iterate current line if first character after paragraph boundary + if line_to_empty && !first_char { + line += 1; + } + let mut lines = slice.lines_at(line); + lines.reverse(); + let mut lines = lines.map(rope_is_line_ending).peekable(); + for _ in 0..count { + while lines.next_if(|&e| e).is_some() { + line -= 1; + } + while lines.next_if(|&e| !e).is_some() { + line -= 1; + } + } + + let head = slice.line_to_char(line); + let anchor = if behavior == Movement::Move { + // exclude first character after paragraph boundary + if line_to_empty && first_char { + range.cursor(slice) + } else { + range.head + } + } else { + range.put_cursor(slice, head, true).anchor + }; + Range::new(anchor, head) +} + +pub fn move_next_para(slice: RopeSlice, range: Range, count: usize, behavior: Movement) -> Range { + let mut line = slice.char_to_line(range.head); + let lines = slice.lines_at(line); + let mut lines = lines.map(|l| l.chunks().all(str_is_line_ending)).peekable(); + for _ in 0..count { + while lines.next_if(|&e| !e).is_some() { + line += 1; + } + while lines.next_if(|&e| e).is_some() { + line += 1; + } + } + let anchor = if behavior == Movement::Move { + range.cursor(slice) + } else { + range.anchor + }; + Range::new(anchor, slice.line_to_char(line)) +} + // ---- util ------------ #[inline] @@ -1179,4 +1237,67 @@ mod test { } } } + + #[test] + fn test_behaviour_when_moving_to_prev_paragraph_single() { + let tests = [ + ("^@", "@^"), + ("^s@tart at\nfirst char\n", "@s^tart at\nfirst char\n"), + ("start at\nlast char^\n@", "@start at\nlast char\n^"), + ("goto\nfirst\n\n^p@aragraph", "@goto\nfirst\n\n^paragraph"), + ("goto\nfirst\n^\n@paragraph", "@goto\nfirst\n\n^paragraph"), + ("goto\nsecond\n\np^a@ragraph", "goto\nsecond\n\n@pa^ragraph"), + ( + "here\n\nhave\nmultiple\nparagraph\n\n\n\n\n^@", + "here\n\n@have\nmultiple\nparagraph\n\n\n\n\n^", + ), + ]; + + for (actual, expected) in tests { + let (s, selection) = crate::test::print(actual); + let text = Rope::from(s.as_str()); + let selection = + selection.transform(|r| move_prev_para(text.slice(..), r, 1, Movement::Move)); + let actual = crate::test::plain(&s, selection); + assert_eq!(actual, expected); + } + } + + #[ignore] + #[test] + fn test_behaviour_when_moving_to_prev_paragraph_double() {} + + #[test] + fn test_behaviour_when_moving_to_next_paragraph_single() { + let tests = [ + ("^@", "@^"), + ("^s@tart at\nfirst char\n", "^start at\nfirst char\n@"), + ("start at\nlast char^\n@", "start at\nlast char^\n@"), + ( + "a\nb\n\n^g@oto\nthird\n\nparagraph", + "a\nb\n\n^goto\nthird\n\n@paragraph", + ), + ( + "a\nb\n^\n@goto\nthird\n\nparagraph", + "a\nb\n\n^goto\nthird\n\n@paragraph", + ), + ( + "a\nb^\n@\ngoto\nsecond\n\nparagraph", + "a\nb^\n\n@goto\nsecond\n\nparagraph", + ), + ( + "here\n\nhave\n^m@ultiple\nparagraph\n\n\n\n\n", + "here\n\nhave\n^multiple\nparagraph\n\n\n\n\n@", + ), + ]; + + for (actual, expected) in tests { + let (s, selection) = crate::test::print(actual); + let text = Rope::from(s.as_str()); + let selection = + selection.transform(|r| move_next_para(text.slice(..), r, 1, Movement::Move)); + let actual = crate::test::plain(&s, selection); + assert_eq!(actual, expected); + } + } } diff --git a/helix-core/src/test.rs b/helix-core/src/test.rs new file mode 100644 index 000000000..983c9a578 --- /dev/null +++ b/helix-core/src/test.rs @@ -0,0 +1,111 @@ +//! Test helpers. +use crate::{Range, Selection}; +use smallvec::SmallVec; +use std::cmp::Reverse; + +/// Convert annotated test string to test string and selection. +/// +/// `^` for `anchor` and `|` for head (`@` for primary), both must appear +/// or otherwise it will panic. +/// +/// # Examples +/// +/// ``` +/// use helix_core::{Range, Selection, test::print}; +/// use smallvec::smallvec; +/// +/// assert_eq!( +/// print("^a@b|c^"), +/// ("abc".to_owned(), Selection::new(smallvec![Range::new(0, 1), Range::new(3, 2)], 0)) +/// ); +/// ``` +/// +/// # Panics +/// +/// Panics when missing primary or appeared more than once. +/// Panics when missing head or anchor. +/// Panics when head come after head or anchor come after anchor. +pub fn print(s: &str) -> (String, Selection) { + let mut anchor = None; + let mut head = None; + let mut primary = None; + let mut ranges = SmallVec::new(); + let mut i = 0; + let s = s + .chars() + .filter(|c| { + match c { + '^' if anchor != None => panic!("anchor without head {s:?}"), + '^' if head == None => anchor = Some(i), + '^' => ranges.push(Range::new(i, head.take().unwrap())), + '|' if head != None => panic!("head without anchor {s:?}"), + '|' if anchor == None => head = Some(i), + '|' => ranges.push(Range::new(anchor.take().unwrap(), i)), + '@' if primary != None => panic!("head (primary) already appeared {s:?}"), + '@' if head != None => panic!("head (primary) without anchor {s:?}"), + '@' if anchor == None => { + primary = Some(ranges.len()); + head = Some(i); + } + '@' => { + primary = Some(ranges.len()); + ranges.push(Range::new(anchor.take().unwrap(), i)); + } + _ => { + i += 1; + return true; + } + }; + false + }) + .collect(); + if head.is_some() { + panic!("missing anchor (|) {s:?}"); + } + if anchor.is_some() { + panic!("missing head (^) {s:?}"); + } + let primary = match primary { + Some(i) => i, + None => panic!("missing primary (@) {s:?}"), + }; + let selection = Selection::new(ranges, primary); + (s, selection) +} + +/// Convert test string and selection to annotated test string. +/// +/// `^` for `anchor` and `|` for head (`@` for primary). +/// +/// # Examples +/// +/// ``` +/// use helix_core::{Range, Selection, test::plain}; +/// use smallvec::smallvec; +/// +/// assert_eq!( +/// plain("abc", Selection::new(smallvec![Range::new(0, 1), Range::new(3, 2)], 0)), +/// "^a@b|c^".to_owned() +/// ); +/// ``` +pub fn plain(s: &str, selection: Selection) -> String { + let primary = selection.primary_index(); + let mut out = String::with_capacity(s.len() + 2 * selection.len()); + out.push_str(s); + let mut insertion: Vec<_> = selection + .iter() + .enumerate() + .flat_map(|(i, range)| { + [ + (range.anchor, '^'), + (range.head, if i == primary { '@' } else { '|' }), + ] + }) + .collect(); + // insert in reverse order + insertion.sort_unstable_by_key(|k| Reverse(k.0)); + for (i, c) in insertion { + out.insert(i, c); + } + out +} diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 296480395..beb564ad1 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -209,6 +209,8 @@ impl MappableCommand { move_next_long_word_start, "Move to beginning of next long word", move_prev_long_word_start, "Move to beginning of previous long word", move_next_long_word_end, "Move to end of next long word", + move_prev_para, "Move to previous paragraph", + move_next_para, "Move to next paragraph", extend_next_word_start, "Extend to beginning of next word", extend_prev_word_start, "Extend to beginning of previous word", extend_next_long_word_start, "Extend to beginning of next long word", @@ -902,6 +904,34 @@ fn move_next_long_word_end(cx: &mut Context) { move_word_impl(cx, movement::move_next_long_word_end) } +fn move_para_impl(cx: &mut Context, move_fn: F) +where + F: Fn(RopeSlice, Range, usize, Movement) -> Range, +{ + let count = cx.count(); + let (view, doc) = current!(cx.editor); + let text = doc.text().slice(..); + let behavior = if doc.mode == Mode::Select { + Movement::Extend + } else { + Movement::Move + }; + + let selection = doc + .selection(view.id) + .clone() + .transform(|range| move_fn(text, range, count, behavior)); + doc.set_selection(view.id, selection); +} + +fn move_prev_para(cx: &mut Context) { + move_para_impl(cx, movement::move_prev_para) +} + +fn move_next_para(cx: &mut Context) { + move_para_impl(cx, movement::move_next_para) +} + fn goto_file_start(cx: &mut Context) { if cx.count.is_some() { goto_line(cx); diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index b5685082c..a7c1f1de6 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -104,6 +104,7 @@ pub fn default() -> HashMap { "c" => goto_prev_class, "a" => goto_prev_parameter, "o" => goto_prev_comment, + "p" => move_prev_para, "space" => add_newline_above, }, "]" => { "Right bracket" @@ -113,6 +114,7 @@ pub fn default() -> HashMap { "c" => goto_next_class, "a" => goto_next_parameter, "o" => goto_next_comment, + "p" => move_next_para, "space" => add_newline_below, }, From e2a6e33b98ac6dd1d42be659706c7e0d248e8f5d Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 21 Feb 2022 19:07:16 +0800 Subject: [PATCH 022/861] Add next paragraph --- helix-core/src/movement.rs | 109 ++++++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 15 deletions(-) diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs index 21d169314..dec6eeb93 100644 --- a/helix-core/src/movement.rs +++ b/helix-core/src/movement.rs @@ -10,7 +10,7 @@ use crate::{ next_grapheme_boundary, nth_next_grapheme_boundary, nth_prev_grapheme_boundary, prev_grapheme_boundary, }, - line_ending::{rope_is_line_ending, str_is_line_ending}, + line_ending::rope_is_line_ending, pos_at_coords, syntax::LanguageConfiguration, textobject::TextObject, @@ -188,9 +188,19 @@ pub fn move_prev_para(slice: RopeSlice, range: Range, count: usize, behavior: Mo } pub fn move_next_para(slice: RopeSlice, range: Range, count: usize, behavior: Movement) -> Range { - let mut line = slice.char_to_line(range.head); - let lines = slice.lines_at(line); - let mut lines = lines.map(|l| l.chunks().all(str_is_line_ending)).peekable(); + let mut line = range.cursor_line(slice); + let last_char = + prev_grapheme_boundary(slice, slice.line_to_char(line + 1)) == range.cursor(slice); + let curr_line_empty = rope_is_line_ending(slice.line(line)); + let next_line_empty = rope_is_line_ending(slice.line(line.saturating_sub(1))); + let empty_to_line = curr_line_empty && !next_line_empty; + + // iterate current line if first character after paragraph boundary + if empty_to_line && last_char { + line += 1; + } + + let mut lines = slice.lines_at(line).map(rope_is_line_ending).peekable(); for _ in 0..count { while lines.next_if(|&e| !e).is_some() { line += 1; @@ -199,12 +209,17 @@ pub fn move_next_para(slice: RopeSlice, range: Range, count: usize, behavior: Mo line += 1; } } + let head = slice.line_to_char(line); let anchor = if behavior == Movement::Move { - range.cursor(slice) + if empty_to_line && last_char { + range.head + } else { + range.cursor(slice) + } } else { - range.anchor + range.put_cursor(slice, head, true).anchor }; - Range::new(anchor, slice.line_to_char(line)) + Range::new(anchor, head) } // ---- util ------------ @@ -1253,19 +1268,49 @@ mod test { ), ]; - for (actual, expected) in tests { - let (s, selection) = crate::test::print(actual); + for (before, expected) in tests { + let (s, selection) = crate::test::print(before); let text = Rope::from(s.as_str()); let selection = selection.transform(|r| move_prev_para(text.slice(..), r, 1, Movement::Move)); let actual = crate::test::plain(&s, selection); - assert_eq!(actual, expected); + assert_eq!(actual, expected, "\nbefore: `{before:?}`"); } } - #[ignore] #[test] - fn test_behaviour_when_moving_to_prev_paragraph_double() {} + fn test_behaviour_when_moving_to_prev_paragraph_double() { + let tests = [ + ("on^e@\n\ntwo\n\nthree\n\n", "@one^\n\ntwo\n\nthree\n\n"), + ("one\n\ntwo\n\nth^r@ee\n\n", "one\n\n@two\n\nthr^ee\n\n"), + ]; + + for (before, expected) in tests { + let (s, selection) = crate::test::print(before); + let text = Rope::from(s.as_str()); + let selection = + selection.transform(|r| move_prev_para(text.slice(..), r, 2, Movement::Move)); + let actual = crate::test::plain(&s, selection); + assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + } + } + + #[test] + fn test_behaviour_when_moving_to_prev_paragraph_extend() { + let tests = [ + ("one\n\n@two\n\n^three\n\n", "@one\n\ntwo\n\n^three\n\n"), + ("@one\n\ntwo\n\n^three\n\n", "@one\n\ntwo\n\n^three\n\n"), + ]; + + for (before, expected) in tests { + let (s, selection) = crate::test::print(before); + let text = Rope::from(s.as_str()); + let selection = + selection.transform(|r| move_prev_para(text.slice(..), r, 1, Movement::Extend)); + let actual = crate::test::plain(&s, selection); + assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + } + } #[test] fn test_behaviour_when_moving_to_next_paragraph_single() { @@ -1291,13 +1336,47 @@ mod test { ), ]; - for (actual, expected) in tests { - let (s, selection) = crate::test::print(actual); + for (before, expected) in tests { + let (s, selection) = crate::test::print(before); let text = Rope::from(s.as_str()); let selection = selection.transform(|r| move_next_para(text.slice(..), r, 1, Movement::Move)); let actual = crate::test::plain(&s, selection); - assert_eq!(actual, expected); + assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + } + } + + #[test] + fn test_behaviour_when_moving_to_next_paragraph_double() { + let tests = [ + ("one\n\ntwo\n\nth^r@ee\n\n", "one\n\ntwo\n\nth^ree\n\n@"), + ("on^e@\n\ntwo\n\nthree\n\n", "on^e\n\ntwo\n\n@three\n\n"), + ]; + + for (before, expected) in tests { + let (s, selection) = crate::test::print(before); + let text = Rope::from(s.as_str()); + let selection = + selection.transform(|r| move_next_para(text.slice(..), r, 2, Movement::Move)); + let actual = crate::test::plain(&s, selection); + assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + } + } + + #[test] + fn test_behaviour_when_moving_to_next_paragraph_extend() { + let tests = [ + ("one\n\n^two\n\n@three\n\n", "one\n\n^two\n\nthree\n\n@"), + ("one\n\n^two\n\nthree\n\n@", "one\n\n^two\n\nthree\n\n@"), + ]; + + for (before, expected) in tests { + let (s, selection) = crate::test::print(before); + let text = Rope::from(s.as_str()); + let selection = + selection.transform(|r| move_next_para(text.slice(..), r, 1, Movement::Extend)); + let actual = crate::test::plain(&s, selection); + assert_eq!(actual, expected, "\nbefore: `{before:?}`"); } } } From 8350ee9a0ef38ff4e78bfa5dc30e874d6d2510ef Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 21 Feb 2022 22:58:54 +0800 Subject: [PATCH 023/861] Add paragraph textobject Change parameter/argument key from p to a since paragraph only have p but parameter are also called arguments sometimes and a is not used. --- book/src/keymap.md | 2 + helix-core/src/movement.rs | 23 +++--- helix-core/src/test.rs | 3 +- helix-core/src/textobject.rs | 147 ++++++++++++++++++++++++++++++++++- helix-term/src/commands.rs | 1 + 5 files changed, 162 insertions(+), 14 deletions(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index e588ac925..2fbc7b3f9 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -277,6 +277,8 @@ Mappings in the style of [vim-unimpaired](https://github.com/tpope/vim-unimpaire | `[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` | +| `]p` | Go to next paragraph | `goto_next_paragraph` | +| `[p` | Go to previous paragraph | `goto_prev_paragraph` | | `[space` | Add newline above | `add_newline_above` | | `]space` | Add newline below | `add_newline_below` | diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs index dec6eeb93..970aff88f 100644 --- a/helix-core/src/movement.rs +++ b/helix-core/src/movement.rs @@ -153,12 +153,12 @@ fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTar pub fn move_prev_para(slice: RopeSlice, range: Range, count: usize, behavior: Movement) -> Range { let mut line = range.cursor_line(slice); let first_char = slice.line_to_char(line) == range.cursor(slice); + let prev_line_empty = rope_is_line_ending(slice.line(line.saturating_sub(1))); let curr_line_empty = rope_is_line_ending(slice.line(line)); - let last_line_empty = rope_is_line_ending(slice.line(line.saturating_sub(1))); - let line_to_empty = last_line_empty && !curr_line_empty; + let prev_empty_to_line = prev_line_empty && !curr_line_empty; - // iterate current line if first character after paragraph boundary - if line_to_empty && !first_char { + // skip character before paragraph boundary + if prev_empty_to_line && !first_char { line += 1; } let mut lines = slice.lines_at(line); @@ -176,7 +176,7 @@ pub fn move_prev_para(slice: RopeSlice, range: Range, count: usize, behavior: Mo let head = slice.line_to_char(line); let anchor = if behavior == Movement::Move { // exclude first character after paragraph boundary - if line_to_empty && first_char { + if prev_empty_to_line && first_char { range.cursor(slice) } else { range.head @@ -193,13 +193,12 @@ pub fn move_next_para(slice: RopeSlice, range: Range, count: usize, behavior: Mo prev_grapheme_boundary(slice, slice.line_to_char(line + 1)) == range.cursor(slice); let curr_line_empty = rope_is_line_ending(slice.line(line)); let next_line_empty = rope_is_line_ending(slice.line(line.saturating_sub(1))); - let empty_to_line = curr_line_empty && !next_line_empty; + let curr_empty_to_line = curr_line_empty && !next_line_empty; - // iterate current line if first character after paragraph boundary - if empty_to_line && last_char { + // skip character after paragraph boundary + if curr_empty_to_line && last_char { line += 1; } - let mut lines = slice.lines_at(line).map(rope_is_line_ending).peekable(); for _ in 0..count { while lines.next_if(|&e| !e).is_some() { @@ -211,7 +210,7 @@ pub fn move_next_para(slice: RopeSlice, range: Range, count: usize, behavior: Mo } let head = slice.line_to_char(line); let anchor = if behavior == Movement::Move { - if empty_to_line && last_char { + if curr_empty_to_line && last_char { range.head } else { range.cursor(slice) @@ -1256,7 +1255,7 @@ mod test { #[test] fn test_behaviour_when_moving_to_prev_paragraph_single() { let tests = [ - ("^@", "@^"), + ("^@", "^@"), ("^s@tart at\nfirst char\n", "@s^tart at\nfirst char\n"), ("start at\nlast char^\n@", "@start at\nlast char\n^"), ("goto\nfirst\n\n^p@aragraph", "@goto\nfirst\n\n^paragraph"), @@ -1315,7 +1314,7 @@ mod test { #[test] fn test_behaviour_when_moving_to_next_paragraph_single() { let tests = [ - ("^@", "@^"), + ("^@", "^@"), ("^s@tart at\nfirst char\n", "^start at\nfirst char\n@"), ("start at\nlast char^\n@", "start at\nlast char^\n@"), ( diff --git a/helix-core/src/test.rs b/helix-core/src/test.rs index 983c9a578..da4f8facf 100644 --- a/helix-core/src/test.rs +++ b/helix-core/src/test.rs @@ -97,8 +97,9 @@ pub fn plain(s: &str, selection: Selection) -> String { .enumerate() .flat_map(|(i, range)| { [ - (range.anchor, '^'), + // sort like this before reversed so anchor < head later (range.head, if i == primary { '@' } else { '|' }), + (range.anchor, '^'), ] }) .collect(); diff --git a/helix-core/src/textobject.rs b/helix-core/src/textobject.rs index 5a55a6f1d..fb6b71427 100644 --- a/helix-core/src/textobject.rs +++ b/helix-core/src/textobject.rs @@ -4,7 +4,8 @@ use ropey::RopeSlice; use tree_sitter::{Node, QueryCursor}; use crate::chars::{categorize_char, char_is_whitespace, CharCategory}; -use crate::graphemes::next_grapheme_boundary; +use crate::graphemes::{next_grapheme_boundary, prev_grapheme_boundary}; +use crate::line_ending::rope_is_line_ending; use crate::movement::Direction; use crate::surround; use crate::syntax::LanguageConfiguration; @@ -111,6 +112,71 @@ pub fn textobject_word( } } +pub fn textobject_para( + slice: RopeSlice, + range: Range, + textobject: TextObject, + count: usize, +) -> Range { + let mut line = range.cursor_line(slice); + let prev_line_empty = rope_is_line_ending(slice.line(line.saturating_sub(1))); + let curr_line_empty = rope_is_line_ending(slice.line(line)); + let next_line_empty = rope_is_line_ending(slice.line(line.saturating_sub(1))); + let last_char = + prev_grapheme_boundary(slice, slice.line_to_char(line + 1)) == range.cursor(slice); + let prev_empty_to_line = prev_line_empty && !curr_line_empty; + let curr_empty_to_line = curr_line_empty && !next_line_empty; + + // skip character before paragraph boundary + let mut line_back = line; // line but backwards + if prev_empty_to_line || curr_empty_to_line { + line_back += 1; + } + let mut lines = slice.lines_at(line_back); + // do not include current paragraph on paragraph end (include next) + if !(curr_empty_to_line && last_char) { + lines.reverse(); + let mut lines = lines.map(rope_is_line_ending).peekable(); + while lines.next_if(|&e| e).is_some() { + line_back -= 1; + } + while lines.next_if(|&e| !e).is_some() { + line_back -= 1; + } + } + + // skip character after paragraph boundary + if curr_empty_to_line && last_char { + line += 1; + } + let mut lines = slice.lines_at(line).map(rope_is_line_ending).peekable(); + for _ in 0..count - 1 { + while lines.next_if(|&e| !e).is_some() { + line += 1; + } + while lines.next_if(|&e| e).is_some() { + line += 1; + } + } + while lines.next_if(|&e| !e).is_some() { + line += 1; + } + // handle last whitespaces part separately depending on textobject + match textobject { + TextObject::Around => { + while lines.next_if(|&e| e).is_some() { + line += 1; + } + } + TextObject::Inside => {} + TextObject::Movement => unreachable!(), + } + + let anchor = slice.line_to_char(line_back); + let head = slice.line_to_char(line); + Range::new(anchor, head) +} + pub fn textobject_surround( slice: RopeSlice, range: Range, @@ -288,6 +354,85 @@ mod test { } } + #[test] + fn test_textobject_paragraph_inside_single() { + let tests = [ + ("^@", "^@"), + ("firs^t@\n\nparagraph\n\n", "^first\n@\nparagraph\n\n"), + ("second\n\npa^r@agraph\n\n", "second\n\n^paragraph\n@\n"), + ("^f@irst char\n\n", "^first char\n@\n"), + ("last char\n^\n@", "last char\n\n^@"), + ( + "empty to line\n^\n@paragraph boundary\n\n", + "empty to line\n\n^paragraph boundary\n@\n", + ), + ( + "line to empty\n\n^p@aragraph boundary\n\n", + "line to empty\n\n^paragraph boundary\n@\n", + ), + ]; + + for (before, expected) in tests { + let (s, selection) = crate::test::print(before); + let text = Rope::from(s.as_str()); + let selection = + selection.transform(|r| textobject_para(text.slice(..), r, TextObject::Inside, 1)); + let actual = crate::test::plain(&s, selection); + assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + } + } + + #[test] + fn test_textobject_paragraph_inside_double() { + let tests = [ + ( + "last two\n\n^p@aragraph\n\nwithout whitespaces\n\n", + "last two\n\n^paragraph\n\nwithout whitespaces\n@\n", + ), + ( + "last two\n^\n@paragraph\n\nwithout whitespaces\n\n", + "last two\n\n^paragraph\n\nwithout whitespaces\n@\n", + ), + ]; + + for (before, expected) in tests { + let (s, selection) = crate::test::print(before); + let text = Rope::from(s.as_str()); + let selection = + selection.transform(|r| textobject_para(text.slice(..), r, TextObject::Inside, 2)); + let actual = crate::test::plain(&s, selection); + assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + } + } + + #[test] + fn test_textobject_paragraph_around_single() { + let tests = [ + ("^@", "^@"), + ("firs^t@\n\nparagraph\n\n", "^first\n\n@paragraph\n\n"), + ("second\n\npa^r@agraph\n\n", "second\n\n^paragraph\n\n@"), + ("^f@irst char\n\n", "^first char\n\n@"), + ("last char\n^\n@", "last char\n\n^@"), + ( + "empty to line\n^\n@paragraph boundary\n\n", + "empty to line\n\n^paragraph boundary\n\n@", + ), + ( + "line to empty\n\n^p@aragraph boundary\n\n", + "line to empty\n\n^paragraph boundary\n\n@", + ), + ]; + + for (before, expected) in tests { + let (s, selection) = crate::test::print(before); + let text = Rope::from(s.as_str()); + let selection = + selection.transform(|r| textobject_para(text.slice(..), r, TextObject::Around, 1)); + let actual = crate::test::plain(&s, selection); + assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + } + } + #[test] fn test_textobject_surround() { // (text, [(cursor position, textobject, final range, surround char, count), ...]) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index beb564ad1..ed3b45ae3 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3991,6 +3991,7 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) { 'f' => textobject_treesitter("function", range), 'a' => textobject_treesitter("parameter", range), 'o' => textobject_treesitter("comment", range), + 'p' => textobject::textobject_para(text, range, objtype, count), 'm' => { let ch = text.char(range.cursor(text)); if !ch.is_ascii_alphanumeric() { From 45b76db5068791fe6163963976a6a9daf3e9bf9d Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Thu, 3 Mar 2022 08:55:26 +0800 Subject: [PATCH 024/861] Change test mark from ^@ to #[|]# --- helix-core/src/movement.rs | 87 ++++++++++++++------- helix-core/src/test.rs | 145 +++++++++++++++++++++++------------ helix-core/src/textobject.rs | 50 ++++++------ 3 files changed, 185 insertions(+), 97 deletions(-) diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs index 970aff88f..c09b3c332 100644 --- a/helix-core/src/movement.rs +++ b/helix-core/src/movement.rs @@ -1255,15 +1255,24 @@ mod test { #[test] fn test_behaviour_when_moving_to_prev_paragraph_single() { let tests = [ - ("^@", "^@"), - ("^s@tart at\nfirst char\n", "@s^tart at\nfirst char\n"), - ("start at\nlast char^\n@", "@start at\nlast char\n^"), - ("goto\nfirst\n\n^p@aragraph", "@goto\nfirst\n\n^paragraph"), - ("goto\nfirst\n^\n@paragraph", "@goto\nfirst\n\n^paragraph"), - ("goto\nsecond\n\np^a@ragraph", "goto\nsecond\n\n@pa^ragraph"), + ("#[|]#", "#[|]#"), + ("#[s|]#tart at\nfirst char\n", "#[|s]#tart at\nfirst char\n"), + ("start at\nlast char#[\n|]#", "#[|start at\nlast char\n]#"), ( - "here\n\nhave\nmultiple\nparagraph\n\n\n\n\n^@", - "here\n\n@have\nmultiple\nparagraph\n\n\n\n\n^", + "goto\nfirst\n\n#[p|]#aragraph", + "#[|goto\nfirst\n\n]#paragraph", + ), + ( + "goto\nfirst\n#[\n|]#paragraph", + "#[|goto\nfirst\n\n]#paragraph", + ), + ( + "goto\nsecond\n\np#[a|]#ragraph", + "goto\nsecond\n\n#[|pa]#ragraph", + ), + ( + "here\n\nhave\nmultiple\nparagraph\n\n\n\n\n#[|]#", + "here\n\n#[|have\nmultiple\nparagraph\n\n\n\n\n]#", ), ]; @@ -1280,8 +1289,14 @@ mod test { #[test] fn test_behaviour_when_moving_to_prev_paragraph_double() { let tests = [ - ("on^e@\n\ntwo\n\nthree\n\n", "@one^\n\ntwo\n\nthree\n\n"), - ("one\n\ntwo\n\nth^r@ee\n\n", "one\n\n@two\n\nthr^ee\n\n"), + ( + "on#[e|]#\n\ntwo\n\nthree\n\n", + "#[|one]#\n\ntwo\n\nthree\n\n", + ), + ( + "one\n\ntwo\n\nth#[r|]#ee\n\n", + "one\n\n#[|two\n\nthr]#ee\n\n", + ), ]; for (before, expected) in tests { @@ -1297,8 +1312,14 @@ mod test { #[test] fn test_behaviour_when_moving_to_prev_paragraph_extend() { let tests = [ - ("one\n\n@two\n\n^three\n\n", "@one\n\ntwo\n\n^three\n\n"), - ("@one\n\ntwo\n\n^three\n\n", "@one\n\ntwo\n\n^three\n\n"), + ( + "one\n\n#[|two\n\n]#three\n\n", + "#[|one\n\ntwo\n\n]#three\n\n", + ), + ( + "#[|one\n\ntwo\n\n]#three\n\n", + "#[|one\n\ntwo\n\n]#three\n\n", + ), ]; for (before, expected) in tests { @@ -1314,24 +1335,24 @@ mod test { #[test] fn test_behaviour_when_moving_to_next_paragraph_single() { let tests = [ - ("^@", "^@"), - ("^s@tart at\nfirst char\n", "^start at\nfirst char\n@"), - ("start at\nlast char^\n@", "start at\nlast char^\n@"), + ("#[|]#", "#[|]#"), + ("#[s|]#tart at\nfirst char\n", "#[start at\nfirst char\n|]#"), + ("start at\nlast char#[\n|]#", "start at\nlast char#[\n|]#"), ( - "a\nb\n\n^g@oto\nthird\n\nparagraph", - "a\nb\n\n^goto\nthird\n\n@paragraph", + "a\nb\n\n#[g|]#oto\nthird\n\nparagraph", + "a\nb\n\n#[goto\nthird\n\n|]#paragraph", ), ( - "a\nb\n^\n@goto\nthird\n\nparagraph", - "a\nb\n\n^goto\nthird\n\n@paragraph", + "a\nb\n#[\n|]#goto\nthird\n\nparagraph", + "a\nb\n\n#[goto\nthird\n\n|]#paragraph", ), ( - "a\nb^\n@\ngoto\nsecond\n\nparagraph", - "a\nb^\n\n@goto\nsecond\n\nparagraph", + "a\nb#[\n|]#\ngoto\nsecond\n\nparagraph", + "a\nb#[\n\n|]#goto\nsecond\n\nparagraph", ), ( - "here\n\nhave\n^m@ultiple\nparagraph\n\n\n\n\n", - "here\n\nhave\n^multiple\nparagraph\n\n\n\n\n@", + "here\n\nhave\n#[m|]#ultiple\nparagraph\n\n\n\n\n", + "here\n\nhave\n#[multiple\nparagraph\n\n\n\n\n|]#", ), ]; @@ -1348,8 +1369,14 @@ mod test { #[test] fn test_behaviour_when_moving_to_next_paragraph_double() { let tests = [ - ("one\n\ntwo\n\nth^r@ee\n\n", "one\n\ntwo\n\nth^ree\n\n@"), - ("on^e@\n\ntwo\n\nthree\n\n", "on^e\n\ntwo\n\n@three\n\n"), + ( + "one\n\ntwo\n\nth#[r|]#ee\n\n", + "one\n\ntwo\n\nth#[ree\n\n|]#", + ), + ( + "on#[e|]#\n\ntwo\n\nthree\n\n", + "on#[e\n\ntwo\n\n|]#three\n\n", + ), ]; for (before, expected) in tests { @@ -1365,8 +1392,14 @@ mod test { #[test] fn test_behaviour_when_moving_to_next_paragraph_extend() { let tests = [ - ("one\n\n^two\n\n@three\n\n", "one\n\n^two\n\nthree\n\n@"), - ("one\n\n^two\n\nthree\n\n@", "one\n\n^two\n\nthree\n\n@"), + ( + "one\n\n#[two\n\n|]#three\n\n", + "one\n\n#[two\n\nthree\n\n|]#", + ), + ( + "one\n\n#[two\n\nthree\n\n|]#", + "one\n\n#[two\n\nthree\n\n|]#", + ), ]; for (before, expected) in tests { diff --git a/helix-core/src/test.rs b/helix-core/src/test.rs index da4f8facf..964a770a7 100644 --- a/helix-core/src/test.rs +++ b/helix-core/src/test.rs @@ -5,8 +5,10 @@ use std::cmp::Reverse; /// Convert annotated test string to test string and selection. /// -/// `^` for `anchor` and `|` for head (`@` for primary), both must appear -/// or otherwise it will panic. +/// `#[|` for primary selection with head before anchor followed by `]#`. +/// `#(|` for secondary selection with head before anchor followed by `)#`. +/// `#[` for primary selection with head after anchor followed by `|]#`. +/// `#(` for secondary selection with head after anchor followed by `|)#`. /// /// # Examples /// @@ -15,7 +17,7 @@ use std::cmp::Reverse; /// use smallvec::smallvec; /// /// assert_eq!( -/// print("^a@b|c^"), +/// print("#[a|]#b#(|c)#"), /// ("abc".to_owned(), Selection::new(smallvec![Range::new(0, 1), Range::new(3, 2)], 0)) /// ); /// ``` @@ -26,56 +28,101 @@ use std::cmp::Reverse; /// Panics when missing head or anchor. /// Panics when head come after head or anchor come after anchor. pub fn print(s: &str) -> (String, Selection) { - let mut anchor = None; - let mut head = None; let mut primary = None; let mut ranges = SmallVec::new(); - let mut i = 0; - let s = s - .chars() - .filter(|c| { - match c { - '^' if anchor != None => panic!("anchor without head {s:?}"), - '^' if head == None => anchor = Some(i), - '^' => ranges.push(Range::new(i, head.take().unwrap())), - '|' if head != None => panic!("head without anchor {s:?}"), - '|' if anchor == None => head = Some(i), - '|' => ranges.push(Range::new(anchor.take().unwrap(), i)), - '@' if primary != None => panic!("head (primary) already appeared {s:?}"), - '@' if head != None => panic!("head (primary) without anchor {s:?}"), - '@' if anchor == None => { - primary = Some(ranges.len()); - head = Some(i); + let mut iter = s.chars().peekable(); + let mut left = String::with_capacity(s.len()); + 'outer: while let Some(c) = iter.next() { + let start = left.len(); + if c == '#' { + if iter.next_if_eq(&'[').is_some() { + if primary.is_some() { + panic!("primary `#[` already appeared {left:?} {s:?}"); } - '@' => { - primary = Some(ranges.len()); - ranges.push(Range::new(anchor.take().unwrap(), i)); + if iter.next_if_eq(&'|').is_some() { + while let Some(c) = iter.next() { + if c == ']' && iter.next_if_eq(&'#').is_some() { + primary = Some(ranges.len()); + ranges.push(Range::new(left.len(), start)); + continue 'outer; + } else { + left.push(c); + } + } + panic!("missing primary end `]#` {left:?} {s:?}"); + } else { + while let Some(c) = iter.next() { + if c == '|' { + if let Some(cc) = iter.next_if_eq(&']') { + if iter.next_if_eq(&'#').is_some() { + primary = Some(ranges.len()); + ranges.push(Range::new(start, left.len())); + continue 'outer; + } else { + left.push(c); + left.push(cc); + } + } else { + left.push(c); + } + } else { + left.push(c); + } + } + panic!("missing primary end `|]#` {left:?} {s:?}"); } - _ => { - i += 1; - return true; + } else if iter.next_if_eq(&'(').is_some() { + if iter.next_if_eq(&'|').is_some() { + while let Some(c) = iter.next() { + if c == ')' && iter.next_if_eq(&'#').is_some() { + ranges.push(Range::new(left.len(), start)); + continue 'outer; + } else { + left.push(c); + } + } + panic!("missing end `)#` {left:?} {s:?}"); + } else { + while let Some(c) = iter.next() { + if c == '|' { + if let Some(cc) = iter.next_if_eq(&')') { + if iter.next_if_eq(&'#').is_some() { + ranges.push(Range::new(start, left.len())); + continue 'outer; + } else { + left.push(c); + left.push(cc); + } + } else { + left.push(c); + } + } else { + left.push(c); + } + } + panic!("missing end `|)#` {left:?} {s:?}"); } - }; - false - }) - .collect(); - if head.is_some() { - panic!("missing anchor (|) {s:?}"); - } - if anchor.is_some() { - panic!("missing head (^) {s:?}"); + } else { + left.push(c); + } + } else { + left.push(c); + } } let primary = match primary { Some(i) => i, - None => panic!("missing primary (@) {s:?}"), + None => panic!("missing primary `#[|]#` {s:?}"), }; let selection = Selection::new(ranges, primary); - (s, selection) + (left, selection) } /// Convert test string and selection to annotated test string. /// -/// `^` for `anchor` and `|` for head (`@` for primary). +/// `#[|` for primary selection with head before anchor followed by `]#`. +/// `#(|` for secondary selection with head before anchor followed by `)#`. +/// `#[` for primary selection with head after anchor followed by `|]#`. +/// `#(` for secondary selection with head after anchor followed by `|)#`. /// /// # Examples /// @@ -85,28 +132,30 @@ pub fn print(s: &str) -> (String, Selection) { /// /// assert_eq!( /// plain("abc", Selection::new(smallvec![Range::new(0, 1), Range::new(3, 2)], 0)), -/// "^a@b|c^".to_owned() +/// "#[a|]#b#(|c)#".to_owned() /// ); /// ``` pub fn plain(s: &str, selection: Selection) -> String { let primary = selection.primary_index(); - let mut out = String::with_capacity(s.len() + 2 * selection.len()); + let mut out = String::with_capacity(s.len() + 5 * selection.len()); out.push_str(s); let mut insertion: Vec<_> = selection .iter() .enumerate() .flat_map(|(i, range)| { - [ - // sort like this before reversed so anchor < head later - (range.head, if i == primary { '@' } else { '|' }), - (range.anchor, '^'), - ] + // sort like this before reversed so anchor < head later + match (range.anchor < range.head, i == primary) { + (true, true) => [(range.anchor, "#["), (range.head, "|]#")], + (true, false) => [(range.anchor, "#("), (range.head, "|)#")], + (false, true) => [(range.anchor, "]#"), (range.head, "#[|")], + (false, false) => [(range.anchor, ")#"), (range.head, "#(|")], + } }) .collect(); // insert in reverse order insertion.sort_unstable_by_key(|k| Reverse(k.0)); - for (i, c) in insertion { - out.insert(i, c); + for (i, s) in insertion { + out.insert_str(i, s); } out } diff --git a/helix-core/src/textobject.rs b/helix-core/src/textobject.rs index fb6b71427..cc1e337c7 100644 --- a/helix-core/src/textobject.rs +++ b/helix-core/src/textobject.rs @@ -357,18 +357,21 @@ mod test { #[test] fn test_textobject_paragraph_inside_single() { let tests = [ - ("^@", "^@"), - ("firs^t@\n\nparagraph\n\n", "^first\n@\nparagraph\n\n"), - ("second\n\npa^r@agraph\n\n", "second\n\n^paragraph\n@\n"), - ("^f@irst char\n\n", "^first char\n@\n"), - ("last char\n^\n@", "last char\n\n^@"), + ("#[|]#", "#[|]#"), + ("firs#[t|]#\n\nparagraph\n\n", "#[first\n|]#\nparagraph\n\n"), ( - "empty to line\n^\n@paragraph boundary\n\n", - "empty to line\n\n^paragraph boundary\n@\n", + "second\n\npa#[r|]#agraph\n\n", + "second\n\n#[paragraph\n|]#\n", ), + ("#[f|]#irst char\n\n", "#[first char\n|]#\n"), + ("last char\n#[\n|]#", "last char\n\n#[|]#"), ( - "line to empty\n\n^p@aragraph boundary\n\n", - "line to empty\n\n^paragraph boundary\n@\n", + "empty to line\n#[\n|]#paragraph boundary\n\n", + "empty to line\n\n#[paragraph boundary\n|]#\n", + ), + ( + "line to empty\n\n#[p|]#aragraph boundary\n\n", + "line to empty\n\n#[paragraph boundary\n|]#\n", ), ]; @@ -386,12 +389,12 @@ mod test { fn test_textobject_paragraph_inside_double() { let tests = [ ( - "last two\n\n^p@aragraph\n\nwithout whitespaces\n\n", - "last two\n\n^paragraph\n\nwithout whitespaces\n@\n", + "last two\n\n#[p|]#aragraph\n\nwithout whitespaces\n\n", + "last two\n\n#[paragraph\n\nwithout whitespaces\n|]#\n", ), ( - "last two\n^\n@paragraph\n\nwithout whitespaces\n\n", - "last two\n\n^paragraph\n\nwithout whitespaces\n@\n", + "last two\n#[\n|]#paragraph\n\nwithout whitespaces\n\n", + "last two\n\n#[paragraph\n\nwithout whitespaces\n|]#\n", ), ]; @@ -408,18 +411,21 @@ mod test { #[test] fn test_textobject_paragraph_around_single() { let tests = [ - ("^@", "^@"), - ("firs^t@\n\nparagraph\n\n", "^first\n\n@paragraph\n\n"), - ("second\n\npa^r@agraph\n\n", "second\n\n^paragraph\n\n@"), - ("^f@irst char\n\n", "^first char\n\n@"), - ("last char\n^\n@", "last char\n\n^@"), + ("#[|]#", "#[|]#"), + ("firs#[t|]#\n\nparagraph\n\n", "#[first\n\n|]#paragraph\n\n"), + ( + "second\n\npa#[r|]#agraph\n\n", + "second\n\n#[paragraph\n\n|]#", + ), + ("#[f|]#irst char\n\n", "#[first char\n\n|]#"), + ("last char\n#[\n|]#", "last char\n\n#[|]#"), ( - "empty to line\n^\n@paragraph boundary\n\n", - "empty to line\n\n^paragraph boundary\n\n@", + "empty to line\n#[\n|]#paragraph boundary\n\n", + "empty to line\n\n#[paragraph boundary\n\n|]#", ), ( - "line to empty\n\n^p@aragraph boundary\n\n", - "line to empty\n\n^paragraph boundary\n\n@", + "line to empty\n\n#[p|]#aragraph boundary\n\n", + "line to empty\n\n#[paragraph boundary\n\n|]#", ), ]; From 64c2490f2d9a9b98d1142243e815d2ff80c99f2a Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Mon, 7 Mar 2022 20:54:19 +0800 Subject: [PATCH 025/861] Refactor test print to be more readable --- helix-core/src/test.rs | 125 +++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 72 deletions(-) diff --git a/helix-core/src/test.rs b/helix-core/src/test.rs index 964a770a7..345d9e9c8 100644 --- a/helix-core/src/test.rs +++ b/helix-core/src/test.rs @@ -28,88 +28,69 @@ use std::cmp::Reverse; /// Panics when missing head or anchor. /// Panics when head come after head or anchor come after anchor. pub fn print(s: &str) -> (String, Selection) { - let mut primary = None; + let mut primary_idx = None; let mut ranges = SmallVec::new(); let mut iter = s.chars().peekable(); let mut left = String::with_capacity(s.len()); + 'outer: while let Some(c) = iter.next() { let start = left.len(); - if c == '#' { - if iter.next_if_eq(&'[').is_some() { - if primary.is_some() { - panic!("primary `#[` already appeared {left:?} {s:?}"); - } - if iter.next_if_eq(&'|').is_some() { - while let Some(c) = iter.next() { - if c == ']' && iter.next_if_eq(&'#').is_some() { - primary = Some(ranges.len()); - ranges.push(Range::new(left.len(), start)); - continue 'outer; - } else { - left.push(c); - } - } - panic!("missing primary end `]#` {left:?} {s:?}"); - } else { - while let Some(c) = iter.next() { - if c == '|' { - if let Some(cc) = iter.next_if_eq(&']') { - if iter.next_if_eq(&'#').is_some() { - primary = Some(ranges.len()); - ranges.push(Range::new(start, left.len())); - continue 'outer; - } else { - left.push(c); - left.push(cc); - } - } else { - left.push(c); - } - } else { - left.push(c); - } - } - panic!("missing primary end `|]#` {left:?} {s:?}"); - } - } else if iter.next_if_eq(&'(').is_some() { - if iter.next_if_eq(&'|').is_some() { - while let Some(c) = iter.next() { - if c == ')' && iter.next_if_eq(&'#').is_some() { - ranges.push(Range::new(left.len(), start)); - continue 'outer; - } else { - left.push(c); - } - } - panic!("missing end `)#` {left:?} {s:?}"); - } else { - while let Some(c) = iter.next() { - if c == '|' { - if let Some(cc) = iter.next_if_eq(&')') { - if iter.next_if_eq(&'#').is_some() { - ranges.push(Range::new(start, left.len())); - continue 'outer; - } else { - left.push(c); - left.push(cc); - } - } else { - left.push(c); - } - } else { - left.push(c); - } - } - panic!("missing end `|)#` {left:?} {s:?}"); - } - } else { + + if c != '#' { + left.push(c); + continue; + } + + let (is_primary, close_pair) = match iter.next() { + Some('[') => (true, ']'), + Some('(') => (false, ')'), + Some(ch) => { + left.push(ch); + continue; + } + None => break, + }; + + if is_primary && primary_idx.is_some() { + panic!("primary `#[` already appeared {left:?} {s:?}"); + } + + let head_at_beg = iter.next_if_eq(&'|').is_some(); + + while let Some(c) = iter.next() { + if !(c == close_pair && iter.peek() == Some(&'#')) { left.push(c); + continue; + } + if !head_at_beg { + let prev = left.pop().unwrap(); + if prev != '|' { + left.push(prev); + left.push(c); + continue; + } + } + iter.next(); // skip "#" + + if is_primary { + primary_idx = Some(ranges.len()); } + let (anchor, head) = match head_at_beg { + true => (left.len(), start), + false => (start, left.len()), + }; + ranges.push(Range::new(anchor, head)); + continue 'outer; + } + + if head_at_beg { + panic!("missing end `{close_pair}#` {left:?} {s:?}"); } else { - left.push(c); + panic!("missing end `|{close_pair}#` {left:?} {s:?}"); } } - let primary = match primary { + + let primary = match primary_idx { Some(i) => i, None => panic!("missing primary `#[|]#` {s:?}"), }; From 8b91ecde40e95a8ba956881c95da60adbf98abb6 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 7 Mar 2022 21:25:26 +0800 Subject: [PATCH 026/861] Rename _para to _paragraph --- helix-core/src/movement.rs | 30 ++++++++++++++++++++---------- helix-core/src/textobject.rs | 14 +++++++------- helix-term/src/commands.rs | 14 +++++++------- helix-term/src/keymap/default.rs | 4 ++-- 4 files changed, 36 insertions(+), 26 deletions(-) diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs index c09b3c332..3f3ffa35f 100644 --- a/helix-core/src/movement.rs +++ b/helix-core/src/movement.rs @@ -150,7 +150,12 @@ fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTar }) } -pub fn move_prev_para(slice: RopeSlice, range: Range, count: usize, behavior: Movement) -> Range { +pub fn move_prev_paragraph( + slice: RopeSlice, + range: Range, + count: usize, + behavior: Movement, +) -> Range { let mut line = range.cursor_line(slice); let first_char = slice.line_to_char(line) == range.cursor(slice); let prev_line_empty = rope_is_line_ending(slice.line(line.saturating_sub(1))); @@ -187,7 +192,12 @@ pub fn move_prev_para(slice: RopeSlice, range: Range, count: usize, behavior: Mo Range::new(anchor, head) } -pub fn move_next_para(slice: RopeSlice, range: Range, count: usize, behavior: Movement) -> Range { +pub fn move_next_paragraph( + slice: RopeSlice, + range: Range, + count: usize, + behavior: Movement, +) -> Range { let mut line = range.cursor_line(slice); let last_char = prev_grapheme_boundary(slice, slice.line_to_char(line + 1)) == range.cursor(slice); @@ -1280,7 +1290,7 @@ mod test { let (s, selection) = crate::test::print(before); let text = Rope::from(s.as_str()); let selection = - selection.transform(|r| move_prev_para(text.slice(..), r, 1, Movement::Move)); + selection.transform(|r| move_prev_paragraph(text.slice(..), r, 1, Movement::Move)); let actual = crate::test::plain(&s, selection); assert_eq!(actual, expected, "\nbefore: `{before:?}`"); } @@ -1303,7 +1313,7 @@ mod test { let (s, selection) = crate::test::print(before); let text = Rope::from(s.as_str()); let selection = - selection.transform(|r| move_prev_para(text.slice(..), r, 2, Movement::Move)); + selection.transform(|r| move_prev_paragraph(text.slice(..), r, 2, Movement::Move)); let actual = crate::test::plain(&s, selection); assert_eq!(actual, expected, "\nbefore: `{before:?}`"); } @@ -1325,8 +1335,8 @@ mod test { for (before, expected) in tests { let (s, selection) = crate::test::print(before); let text = Rope::from(s.as_str()); - let selection = - selection.transform(|r| move_prev_para(text.slice(..), r, 1, Movement::Extend)); + let selection = selection + .transform(|r| move_prev_paragraph(text.slice(..), r, 1, Movement::Extend)); let actual = crate::test::plain(&s, selection); assert_eq!(actual, expected, "\nbefore: `{before:?}`"); } @@ -1360,7 +1370,7 @@ mod test { let (s, selection) = crate::test::print(before); let text = Rope::from(s.as_str()); let selection = - selection.transform(|r| move_next_para(text.slice(..), r, 1, Movement::Move)); + selection.transform(|r| move_next_paragraph(text.slice(..), r, 1, Movement::Move)); let actual = crate::test::plain(&s, selection); assert_eq!(actual, expected, "\nbefore: `{before:?}`"); } @@ -1383,7 +1393,7 @@ mod test { let (s, selection) = crate::test::print(before); let text = Rope::from(s.as_str()); let selection = - selection.transform(|r| move_next_para(text.slice(..), r, 2, Movement::Move)); + selection.transform(|r| move_next_paragraph(text.slice(..), r, 2, Movement::Move)); let actual = crate::test::plain(&s, selection); assert_eq!(actual, expected, "\nbefore: `{before:?}`"); } @@ -1405,8 +1415,8 @@ mod test { for (before, expected) in tests { let (s, selection) = crate::test::print(before); let text = Rope::from(s.as_str()); - let selection = - selection.transform(|r| move_next_para(text.slice(..), r, 1, Movement::Extend)); + let selection = selection + .transform(|r| move_next_paragraph(text.slice(..), r, 1, Movement::Extend)); let actual = crate::test::plain(&s, selection); assert_eq!(actual, expected, "\nbefore: `{before:?}`"); } diff --git a/helix-core/src/textobject.rs b/helix-core/src/textobject.rs index cc1e337c7..67bf40a65 100644 --- a/helix-core/src/textobject.rs +++ b/helix-core/src/textobject.rs @@ -112,7 +112,7 @@ pub fn textobject_word( } } -pub fn textobject_para( +pub fn textobject_paragraph( slice: RopeSlice, range: Range, textobject: TextObject, @@ -378,8 +378,8 @@ mod test { for (before, expected) in tests { let (s, selection) = crate::test::print(before); let text = Rope::from(s.as_str()); - let selection = - selection.transform(|r| textobject_para(text.slice(..), r, TextObject::Inside, 1)); + let selection = selection + .transform(|r| textobject_paragraph(text.slice(..), r, TextObject::Inside, 1)); let actual = crate::test::plain(&s, selection); assert_eq!(actual, expected, "\nbefore: `{before:?}`"); } @@ -401,8 +401,8 @@ mod test { for (before, expected) in tests { let (s, selection) = crate::test::print(before); let text = Rope::from(s.as_str()); - let selection = - selection.transform(|r| textobject_para(text.slice(..), r, TextObject::Inside, 2)); + let selection = selection + .transform(|r| textobject_paragraph(text.slice(..), r, TextObject::Inside, 2)); let actual = crate::test::plain(&s, selection); assert_eq!(actual, expected, "\nbefore: `{before:?}`"); } @@ -432,8 +432,8 @@ mod test { for (before, expected) in tests { let (s, selection) = crate::test::print(before); let text = Rope::from(s.as_str()); - let selection = - selection.transform(|r| textobject_para(text.slice(..), r, TextObject::Around, 1)); + let selection = selection + .transform(|r| textobject_paragraph(text.slice(..), r, TextObject::Around, 1)); let actual = crate::test::plain(&s, selection); assert_eq!(actual, expected, "\nbefore: `{before:?}`"); } diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index ed3b45ae3..f0fb469b6 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -209,8 +209,8 @@ impl MappableCommand { move_next_long_word_start, "Move to beginning of next long word", move_prev_long_word_start, "Move to beginning of previous long word", move_next_long_word_end, "Move to end of next long word", - move_prev_para, "Move to previous paragraph", - move_next_para, "Move to next paragraph", + move_prev_paragraph, "Move to previous paragraph", + move_next_paragraph, "Move to next paragraph", extend_next_word_start, "Extend to beginning of next word", extend_prev_word_start, "Extend to beginning of previous word", extend_next_long_word_start, "Extend to beginning of next long word", @@ -924,12 +924,12 @@ where doc.set_selection(view.id, selection); } -fn move_prev_para(cx: &mut Context) { - move_para_impl(cx, movement::move_prev_para) +fn move_prev_paragraph(cx: &mut Context) { + move_para_impl(cx, movement::move_prev_paragraph) } -fn move_next_para(cx: &mut Context) { - move_para_impl(cx, movement::move_next_para) +fn move_next_paragraph(cx: &mut Context) { + move_para_impl(cx, movement::move_next_paragraph) } fn goto_file_start(cx: &mut Context) { @@ -3991,7 +3991,7 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) { 'f' => textobject_treesitter("function", range), 'a' => textobject_treesitter("parameter", range), 'o' => textobject_treesitter("comment", range), - 'p' => textobject::textobject_para(text, range, objtype, count), + 'p' => textobject::textobject_paragraph(text, range, objtype, count), 'm' => { let ch = text.char(range.cursor(text)); if !ch.is_ascii_alphanumeric() { diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index a7c1f1de6..a8144ebc2 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -104,7 +104,7 @@ pub fn default() -> HashMap { "c" => goto_prev_class, "a" => goto_prev_parameter, "o" => goto_prev_comment, - "p" => move_prev_para, + "p" => move_prev_paragraph, "space" => add_newline_above, }, "]" => { "Right bracket" @@ -114,7 +114,7 @@ pub fn default() -> HashMap { "c" => goto_next_class, "a" => goto_next_parameter, "o" => goto_next_comment, - "p" => move_next_para, + "p" => move_next_paragraph, "space" => add_newline_below, }, From ec21de08446656b9012c39db2db3d02c7ce3dc9c Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Thu, 10 Mar 2022 23:14:19 +0800 Subject: [PATCH 027/861] Add missing # back to test output --- helix-core/src/test.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/helix-core/src/test.rs b/helix-core/src/test.rs index 345d9e9c8..064ca8a38 100644 --- a/helix-core/src/test.rs +++ b/helix-core/src/test.rs @@ -45,6 +45,7 @@ pub fn print(s: &str) -> (String, Selection) { Some('[') => (true, ']'), Some('(') => (false, ')'), Some(ch) => { + left.push('#'); left.push(ch); continue; } From 9782204f739813ab5b2dd82451ef2d4695b41d22 Mon Sep 17 00:00:00 2001 From: "Dr. David A. Kunz" Date: Sun, 3 Apr 2022 14:26:46 +0200 Subject: [PATCH 028/861] Add typed commands buffer-next and buffer-previous (#1940) --- book/src/generated/typable-cmd.md | 2 ++ helix-term/src/commands.rs | 19 +++++++++--------- helix-term/src/commands/typed.rs | 32 +++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 1ee2fac4b..85507b19a 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -9,6 +9,8 @@ | `:buffer-close-others!`, `:bco!`, `:bcloseother!` | Close all buffers but the currently focused one. | | `:buffer-close-all`, `:bca`, `:bcloseall` | Close all buffers, without quiting. | | `:buffer-close-all!`, `:bca!`, `:bcloseall!` | Close all buffers forcefully (ignoring unsaved changes), without quiting. | +| `:buffer-next`, `:bn`, `:bnext` | Go to next buffer. | +| `:buffer-previous`, `:bp`, `:bprev` | Go to previous buffer. | | `:write`, `:w` | Write changes to disk. Accepts an optional path (:write some/path.txt) | | `:new`, `:n` | Create a new scratch buffer. | | `:format`, `:fmt` | Format the file using the LSP formatter. | diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index f0fb469b6..b93cfc41c 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -637,36 +637,35 @@ fn goto_line_start(cx: &mut Context) { } fn goto_next_buffer(cx: &mut Context) { - goto_buffer(cx, Direction::Forward); + goto_buffer(cx.editor, Direction::Forward); } fn goto_previous_buffer(cx: &mut Context) { - goto_buffer(cx, Direction::Backward); + goto_buffer(cx.editor, Direction::Backward); } -fn goto_buffer(cx: &mut Context, direction: Direction) { - let current = view!(cx.editor).doc; +fn goto_buffer(editor: &mut Editor, direction: Direction) { + let current = view!(editor).doc; let id = match direction { Direction::Forward => { - let iter = cx.editor.documents.keys(); + let iter = editor.documents.keys(); let mut iter = iter.skip_while(|id| *id != ¤t); iter.next(); // skip current item - iter.next().or_else(|| cx.editor.documents.keys().next()) + iter.next().or_else(|| editor.documents.keys().next()) } Direction::Backward => { - let iter = cx.editor.documents.keys(); + let iter = editor.documents.keys(); let mut iter = iter.rev().skip_while(|id| *id != ¤t); iter.next(); // skip current item - iter.next() - .or_else(|| cx.editor.documents.keys().rev().next()) + iter.next().or_else(|| editor.documents.keys().rev().next()) } } .unwrap(); let id = *id; - cx.editor.switch(id, Action::Replace); + editor.switch(id, Action::Replace); } fn extend_to_line_start(cx: &mut Context) { diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index c921f85b2..4c0447938 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -172,6 +172,24 @@ fn force_buffer_close_all( buffer_close_by_ids_impl(cx.editor, &document_ids, true) } +fn buffer_next( + cx: &mut compositor::Context, + _args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + goto_buffer(cx.editor, Direction::Forward); + Ok(()) +} + +fn buffer_previous( + cx: &mut compositor::Context, + _args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + goto_buffer(cx.editor, Direction::Backward); + Ok(()) +} + fn write_impl(cx: &mut compositor::Context, path: Option<&Cow>) -> anyhow::Result<()> { let jobs = &mut cx.jobs; let doc = doc_mut!(cx.editor); @@ -1082,6 +1100,20 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: force_buffer_close_all, completer: None, }, + TypableCommand { + name: "buffer-next", + aliases: &["bn", "bnext"], + doc: "Go to next buffer.", + fun: buffer_next, + completer: None, + }, + TypableCommand { + name: "buffer-previous", + aliases: &["bp", "bprev"], + doc: "Go to previous buffer.", + fun: buffer_previous, + completer: None, + }, TypableCommand { name: "write", aliases: &["w"], From 3fc4ea2938a0ee8048176a92c4bbf29aaaf0b853 Mon Sep 17 00:00:00 2001 From: Kirawi <67773714+kirawi@users.noreply.github.com> Date: Sun, 3 Apr 2022 18:59:02 -0400 Subject: [PATCH 029/861] [dark_plus] remove `ui.text` background (#1950) --- runtime/themes/dark_plus.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/dark_plus.toml b/runtime/themes/dark_plus.toml index ab7c16ecc..06bccd5d7 100644 --- a/runtime/themes/dark_plus.toml +++ b/runtime/themes/dark_plus.toml @@ -74,7 +74,7 @@ "ui.statusline" = { fg = "white", bg = "blue" } "ui.statusline.inactive" = { fg = "white", bg = "blue" } -"ui.text" = { fg = "text", bg = "background" } +"ui.text" = { fg = "text" } "ui.text.focus" = { fg = "white" } "warning" = { fg = "gold2" } From f8c83f98859fd618980141eb95e7927dcdf074d7 Mon Sep 17 00:00:00 2001 From: Rose Hudson Date: Sun, 3 Apr 2022 16:02:32 +0100 Subject: [PATCH 030/861] clear terminal after switching to alternate screen when using helix over mosh, the screen doesn't get cleared and characters get left all over the place until they are overwritten. with this change, the screen gets properly cleared as soon as helix starts --- helix-term/src/application.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index ddf9e8d6d..bc5f3bd77 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -683,6 +683,7 @@ impl Application { terminal::enable_raw_mode()?; let mut stdout = stdout(); execute!(stdout, terminal::EnterAlternateScreen)?; + execute!(stdout, terminal::Clear(terminal::ClearType::All))?; if self.config.load().editor.mouse { execute!(stdout, EnableMouseCapture)?; } From d3c8286ea0c984f69bbab09a480530a827647192 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 5 Apr 2022 08:41:28 +0800 Subject: [PATCH 031/861] Bump crossterm to 0.32.2 (#1955) Deduplicates mio dependency which results no crate duplication now and 7 lesser crate for cargo to build. --- Cargo.lock | 93 ++++++++++++++++++++++++------------------------------ 1 file changed, 41 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85438e01e..e96a0636d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,15 +131,15 @@ dependencies = [ [[package]] name = "crossterm" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fd7173631a4e9e2ca8b32ae2fad58aab9843ea5aaf56642661937d87e28a3e" +checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17" dependencies = [ "bitflags", "crossterm_winapi", "futures-core", "libc", - "mio 0.7.14", + "mio", "parking_lot", "signal-hook", "signal-hook-mio", @@ -293,9 +293,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" dependencies = [ "cfg-if", "libc", @@ -587,10 +587,11 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" dependencies = [ + "autocfg", "scopeguard", ] @@ -639,22 +640,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" -dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "winapi", -] - -[[package]] -name = "mio" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba42135c6a5917b9db9cd7b293e5409e1c6b041e6f9825e92e55a894c63b6f8" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" dependencies = [ "libc", "log", @@ -729,9 +717,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37" dependencies = [ "cfg-if", "libc", @@ -789,9 +777,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" dependencies = [ "proc-macro2", ] @@ -816,21 +804,22 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", "redox_syscall", + "thiserror", ] [[package]] @@ -947,12 +936,12 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" dependencies = [ "libc", - "mio 0.7.14", + "mio", "signal-hook", ] @@ -985,9 +974,9 @@ checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3" [[package]] name = "slab" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" [[package]] name = "slotmap" @@ -1039,15 +1028,15 @@ checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" [[package]] name = "str_indices" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "283baa48c486e4c5e27b4d92c435db9eaceac236a74dab5e3293570e2c3fa4aa" +checksum = "adfad63a1b47951101cd667a85b2959a62910cf03f814fff25df89c460b873f8" [[package]] name = "syn" -version = "1.0.89" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" +checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f" dependencies = [ "proc-macro2", "quote", @@ -1116,7 +1105,7 @@ dependencies = [ "bytes", "libc", "memchr", - "mio 0.8.1", + "mio", "num_cpus", "once_cell", "parking_lot", @@ -1302,9 +1291,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" dependencies = [ "windows_aarch64_msvc", "windows_i686_gnu", @@ -1315,33 +1304,33 @@ dependencies = [ [[package]] name = "windows_aarch64_msvc" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" +checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" [[package]] name = "windows_i686_gnu" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" +checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" [[package]] name = "windows_i686_msvc" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" +checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" [[package]] name = "windows_x86_64_gnu" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" +checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" [[package]] name = "windows_x86_64_msvc" -version = "0.32.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" +checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" [[package]] name = "xtask" From e7beb32fd7b9262e61dad96fdf4b36ebdc5367f7 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 5 Apr 2022 08:43:04 +0800 Subject: [PATCH 032/861] Add paragraph to last motion (#1956) Fix #1954 --- helix-term/src/commands.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index b93cfc41c..9a222427f 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -905,22 +905,26 @@ fn move_next_long_word_end(cx: &mut Context) { fn move_para_impl(cx: &mut Context, move_fn: F) where - F: Fn(RopeSlice, Range, usize, Movement) -> Range, + F: Fn(RopeSlice, Range, usize, Movement) -> Range + 'static, { let count = cx.count(); - let (view, doc) = current!(cx.editor); - let text = doc.text().slice(..); - let behavior = if doc.mode == Mode::Select { - Movement::Extend - } else { - Movement::Move - }; + let motion = move |editor: &mut Editor| { + let (view, doc) = current!(editor); + let text = doc.text().slice(..); + let behavior = if doc.mode == Mode::Select { + Movement::Extend + } else { + Movement::Move + }; - let selection = doc - .selection(view.id) - .clone() - .transform(|range| move_fn(text, range, count, behavior)); - doc.set_selection(view.id, selection); + let selection = doc + .selection(view.id) + .clone() + .transform(|range| move_fn(text, range, count, behavior)); + doc.set_selection(view.id, selection); + }; + motion(cx.editor); + cx.editor.last_motion = Some(Motion(Box::new(motion))); } fn move_prev_paragraph(cx: &mut Context) { From 6fc6f87260a2f11a892f09678fc6c10b01e88e3f Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 5 Apr 2022 08:43:14 +0800 Subject: [PATCH 033/861] Fix next paragraph logic over muliple blank lines (#1951) Fix #1928 --- helix-core/src/movement.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs index 3f3ffa35f..e695bf944 100644 --- a/helix-core/src/movement.rs +++ b/helix-core/src/movement.rs @@ -202,7 +202,8 @@ pub fn move_next_paragraph( let last_char = prev_grapheme_boundary(slice, slice.line_to_char(line + 1)) == range.cursor(slice); let curr_line_empty = rope_is_line_ending(slice.line(line)); - let next_line_empty = rope_is_line_ending(slice.line(line.saturating_sub(1))); + let next_line_empty = + rope_is_line_ending(slice.line(slice.len_lines().saturating_sub(1).min(line + 1))); let curr_empty_to_line = curr_line_empty && !next_line_empty; // skip character after paragraph boundary @@ -1364,6 +1365,14 @@ mod test { "here\n\nhave\n#[m|]#ultiple\nparagraph\n\n\n\n\n", "here\n\nhave\n#[multiple\nparagraph\n\n\n\n\n|]#", ), + ( + "#[t|]#ext\n\n\nafter two blank lines\n\nmore text\n", + "#[text\n\n\n|]#after two blank lines\n\nmore text\n", + ), + ( + "#[text\n\n\n|]#after two blank lines\n\nmore text\n", + "text\n\n\n#[after two blank lines\n\n|]#more text\n", + ), ]; for (before, expected) in tests { From d962e06e91b997813092cc5e49a800cc9d4f0ee1 Mon Sep 17 00:00:00 2001 From: Roland Kovacs Date: Tue, 5 Apr 2022 02:56:14 +0200 Subject: [PATCH 034/861] Add runtime language configuration (#1794) (#1866) * Add runtime language configuration (#1794) * Add set-language typable command to change the language of current buffer. * Add completer for available language options. * Update set-language to refresh language server as well * Add language id based config lookup on `syntax::Loader`. * Add `Document::set_language3` to set programming language based on language id. * Update `Editor::refresh_language_server` to try language detection only if language is not already set. * Remove language detection from Editor::refresh_language_server * Move document language detection to where the scratch buffer is saved. * Rename Document::set_language3 to Document::set_language_by_language_id. * Remove unnecessary clone in completers::language --- book/src/generated/typable-cmd.md | 1 + helix-core/src/syntax.rs | 11 +++++++++++ helix-term/src/commands/typed.rs | 26 ++++++++++++++++++++++++++ helix-term/src/ui/mod.rs | 21 +++++++++++++++++++++ helix-view/src/document.rs | 11 +++++++++++ helix-view/src/editor.rs | 1 - 6 files changed, 70 insertions(+), 1 deletion(-) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 85507b19a..f9261a756 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -53,6 +53,7 @@ | `:hsplit-new`, `:hnew` | Open a scratch buffer in a horizontal split. | | `:tutor` | Open the tutorial. | | `:goto`, `:g` | Go to line number. | +| `:set-language`, `:lang` | Set the language of current buffer. | | `:set-option`, `:set` | Set a config option at runtime | | `:sort` | Sort ranges in selection. | | `:rsort` | Sort ranges in selection in reverse order. | diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index e736b3708..bb0073e1c 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -504,6 +504,13 @@ impl Loader { .cloned() } + pub fn language_config_for_language_id(&self, id: &str) -> Option> { + self.language_configs + .iter() + .find(|config| config.language_id == id) + .cloned() + } + pub fn language_configuration_for_injection_string( &self, string: &str, @@ -529,6 +536,10 @@ impl Loader { None } + pub fn language_configs(&self) -> impl Iterator> { + self.language_configs.iter() + } + pub fn set_scopes(&self, scopes: Vec) { self.scopes.store(Arc::new(scopes)); diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 4c0447938..8f74adb62 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -217,6 +217,7 @@ fn write_impl(cx: &mut compositor::Context, path: Option<&Cow>) -> anyhow:: if path.is_some() { let id = doc.id(); + doc.detect_language(cx.editor.syn_loader.clone()); let _ = cx.editor.refresh_language_server(id); } Ok(()) @@ -931,6 +932,24 @@ fn setting( Ok(()) } +/// Change the language of the current buffer at runtime. +fn language( + cx: &mut compositor::Context, + args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + if args.len() != 1 { + anyhow::bail!("Bad arguments. Usage: `:set-language language`"); + } + + let doc = doc_mut!(cx.editor); + doc.set_language_by_language_id(&args[0], cx.editor.syn_loader.clone()); + + let id = doc.id(); + cx.editor.refresh_language_server(id); + Ok(()) +} + fn sort( cx: &mut compositor::Context, args: &[Cow], @@ -1408,6 +1427,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: goto_line_number, completer: None, }, + TypableCommand { + name: "set-language", + aliases: &["lang"], + doc: "Set the language of current buffer.", + fun: language, + completer: Some(completers::language), + }, TypableCommand { name: "set-option", aliases: &["set"], diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index a90debdb6..2dca870ba 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -298,6 +298,27 @@ pub mod completers { }) } + pub fn language(editor: &Editor, input: &str) -> Vec { + let matcher = Matcher::default(); + + let mut matches: Vec<_> = editor + .syn_loader + .language_configs() + .filter_map(|config| { + matcher + .fuzzy_match(&config.language_id, input) + .map(|score| (&config.language_id, score)) + }) + .collect(); + + matches.sort_unstable_by_key(|(_language, score)| Reverse(*score)); + + matches + .into_iter() + .map(|(language, _score)| ((0..), language.clone().into())) + .collect() + } + pub fn directory(_editor: &Editor, input: &str) -> Vec { filename_impl(input, |entry| { let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir()); diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index c9c1e5028..5d739af58 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -607,6 +607,17 @@ impl Document { self.set_language(language_config, Some(config_loader)); } + /// Set the programming language for the file if you know the language but don't have the + /// [`syntax::LanguageConfiguration`] for it. + pub fn set_language_by_language_id( + &mut self, + language_id: &str, + config_loader: Arc, + ) { + let language_config = config_loader.language_config_for_language_id(language_id); + self.set_language(language_config, Some(config_loader)); + } + /// Set the LSP. pub fn set_language_server(&mut self, language_server: Option>) { self.language_server = language_server; diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 9a2b4297f..c4e9ec283 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -448,7 +448,6 @@ impl Editor { /// Refreshes the language server for a given document pub fn refresh_language_server(&mut self, doc_id: DocumentId) -> Option<()> { let doc = self.documents.get_mut(&doc_id)?; - doc.detect_language(self.syn_loader.clone()); Self::launch_language_server(&mut self.language_servers, doc) } From 6b80cb8a7750885abf761d1b65e5c0065ae1640b Mon Sep 17 00:00:00 2001 From: Danilo Spinella Date: Tue, 5 Apr 2022 03:01:58 +0200 Subject: [PATCH 035/861] Fix toggle_comments command on multiple selections (#1882) --- helix-core/src/comment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index b22a95a65..44f6cdfec 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -72,7 +72,7 @@ pub fn toggle_line_comments(doc: &Rope, selection: &Selection, token: Option<&st let end = (end + 1).min(text.len_lines()); lines.extend(start..end); - min_next_line = end + 1; + min_next_line = end; } let (commented, to_change, min, margin) = find_line_comment(token, text, lines); From eb84d9493cc09bf27ae9c9e0dba79be3bb743e08 Mon Sep 17 00:00:00 2001 From: VuiMuich Date: Tue, 5 Apr 2022 14:39:22 +0200 Subject: [PATCH 036/861] add language `ron` (#1925) --- book/src/generated/lang-support.md | 1 + languages.toml | 10 ++++++++++ runtime/queries/ron/highlights.scm | 1 + runtime/queries/ron/indents.scm | 1 + runtime/queries/ron/injections.scm | 1 + 5 files changed, 14 insertions(+) create mode 100644 runtime/queries/ron/highlights.scm create mode 100644 runtime/queries/ron/indents.scm create mode 100644 runtime/queries/ron/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 694d1d128..b71349f31 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -53,6 +53,7 @@ | racket | | | | `racket` | | regex | ✓ | | | | | rescript | ✓ | ✓ | | `rescript-language-server` | +| ron | ✓ | | ✓ | | | ruby | ✓ | | ✓ | `solargraph` | | rust | ✓ | ✓ | ✓ | `rust-analyzer` | | scala | ✓ | | ✓ | `metals` | diff --git a/languages.toml b/languages.toml index 0220c33b8..d81d03733 100644 --- a/languages.toml +++ b/languages.toml @@ -1028,3 +1028,13 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "gleam" source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "7159ce961592192b0e7cdf88782cda0fdf41a4cb" } + +[[language]] +name = "ron" +scope = "source.ron" +injection-regex = "ron" +file-types = ["ron"] +roots = [] +comment-token = "//" +indent = { tab-width = 4, unit = " " } +grammar = "rust" diff --git a/runtime/queries/ron/highlights.scm b/runtime/queries/ron/highlights.scm new file mode 100644 index 000000000..43766a4f8 --- /dev/null +++ b/runtime/queries/ron/highlights.scm @@ -0,0 +1 @@ +; inherits: rust \ No newline at end of file diff --git a/runtime/queries/ron/indents.scm b/runtime/queries/ron/indents.scm new file mode 100644 index 000000000..43766a4f8 --- /dev/null +++ b/runtime/queries/ron/indents.scm @@ -0,0 +1 @@ +; inherits: rust \ No newline at end of file diff --git a/runtime/queries/ron/injections.scm b/runtime/queries/ron/injections.scm new file mode 100644 index 000000000..43766a4f8 --- /dev/null +++ b/runtime/queries/ron/injections.scm @@ -0,0 +1 @@ +; inherits: rust \ No newline at end of file From 0eb87996a8e8245d7aa2688fc7397ed5a174e311 Mon Sep 17 00:00:00 2001 From: bootradev <91094662+bootradev@users.noreply.github.com> Date: Tue, 5 Apr 2022 12:06:51 -0400 Subject: [PATCH 037/861] add boo_berry theme (#1962) --- runtime/themes/boo_berry.toml | 66 +++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 runtime/themes/boo_berry.toml diff --git a/runtime/themes/boo_berry.toml b/runtime/themes/boo_berry.toml new file mode 100644 index 000000000..79b89ed0a --- /dev/null +++ b/runtime/themes/boo_berry.toml @@ -0,0 +1,66 @@ +# made by bootra + +"comment" = { fg = "berry_desaturated" } +"constant" = { fg = "gold" } +"function" = { fg = "mint" } +"function.macro" = { fg = "bubblegum" } +"keyword" = { fg = "bubblegum" } +"operator" = { fg = "bubblegum" } +"punctuation" = { fg = "lilac" } +"string" = { fg = "gold" } +"type" = { fg = "violet" } +"variable" = { fg = "lilac" } +"variable.builtin" = { fg = "violet" } +"tag" = { fg = "gold" } +"label" = { fg = "gold" } +"attribute" = { fg = "lilac" } +"namespace" = { fg = "lilac" } +"module" = { fg = "lilac" } + +"markup.heading" = { fg = "gold", modifiers = ["bold"] } +"markup.heading.marker" = { fg = "berry_desaturated" } +"markup.list" = { fg = "bubblegum" } +"markup.bold" = { modifiers = ["bold"] } +"markup.italic" = { modifiers = ["italic"] } +"markup.link.url" = { fg = "violet", modifiers = ["underlined"] } +"markup.link.text" = { fg = "violet" } +"markup.quote" = { fg = "berry_desaturated" } +"markup.raw" = { fg = "mint" } + +"ui.background" = { bg = "berry" } +"ui.cursor" = { fg = "berry", bg = "lilac" } +"ui.cursor.match" = { fg = "berry", bg = "berry_desaturated" } +"ui.cursor.select" = { fg = "berry", bg = "mint" } +"ui.cursor.insert" = { fg = "berry", bg = "mint" } +"ui.linenr" = { fg = "berry_desaturated" } +"ui.linenr.selected" = { fg = "lilac" } +"ui.statusline" = { fg = "lilac", bg = "berry_saturated" } +"ui.statusline.inactive" = { fg = "berry_desaturated", bg = "berry_saturated" } +"ui.popup" = { fg = "lilac", bg = "berry_saturated" } +"ui.window" = { fg = "berry_desaturated", bg = "berry" } +"ui.help" = { fg = "lilac", bg = "berry_saturated" } +"ui.text" = { fg = "lilac" } +"ui.text.focus" = { fg = "mint" } +"ui.menu" = { fg = "lilac", bg = "berry_saturated" } +"ui.menu.selected" = { fg = "mint", bg = "berry_saturated" } +"ui.selection" = { bg = "berry_saturated" } + +"diff.plus" = { fg = "mint" } +"diff.delta" = { fg = "gold" } +"diff.minus" = { fg = "bubblegum" } + +"error" = { fg = "bubblegum" } +"warning" = { fg = "gold" } +"info" = { fg = "lilac" } +"hint" = { fg = "lilac" } +"diagnostic" = { modifiers = ["underlined"] } + +[palette] +berry = "#3A2A4D" +berry_saturated = "#2B1C3D" +berry_desaturated = "#886C9C" +bubblegum = "#D678B5" +gold = "#E3C0A8" +lilac = "#C7B8E0" +mint = "#7FC9AB" +violet = "#C78DFC" From b33318672173fd49ffbd3440b7857ebc9812de08 Mon Sep 17 00:00:00 2001 From: Kirawi <67773714+kirawi@users.noreply.github.com> Date: Wed, 6 Apr 2022 11:31:28 -0400 Subject: [PATCH 038/861] [dark_plus] update markup colors (#1989) --- runtime/themes/dark_plus.toml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/runtime/themes/dark_plus.toml b/runtime/themes/dark_plus.toml index 06bccd5d7..386401228 100644 --- a/runtime/themes/dark_plus.toml +++ b/runtime/themes/dark_plus.toml @@ -9,10 +9,10 @@ "constructor" = { fg = "constant" } "variable.other.member" = { fg = "variable" } -"keyword" = { fg = "keyword" } -"keyword.directive" = { fg = "keyword" } +"keyword" = { fg = "blue2" } +"keyword.directive" = { fg = "blue2" } "keyword.control" = { fg = "special" } -"label" = { fg = "keyword" } +"label" = { fg = "blue2" } "special" = { fg = "text" } "operator" = { fg = "text" } @@ -22,13 +22,13 @@ "variable" = { fg = "variable" } "variable.parameter" = { fg = "variable" } -"variable.builtin" = { fg = "keyword" } +"variable.builtin" = { fg = "blue2" } "constant" = { fg = "constant" } -"constant.builtin" = { fg = "keyword" } +"constant.builtin" = { fg = "blue2" } "function" = { fg = "fn_declaration" } "function.builtin" = { fg = "fn_declaration" } -"function.macro" = { fg = "keyword" } +"function.macro" = { fg = "blue2" } "attribute" = { fg = "fn_declaration" } "comment" = { fg = "dark_green" } @@ -39,15 +39,14 @@ "constant.numeric" = { fg = "pale_green" } "constant.character.escape" = { fg = "gold" } -# TODO -"markup.heading" = "blue" -"markup.list" = "red" -"markup.bold" = { fg = "yellow", modifiers = ["bold"] } -"markup.italic" = { fg = "magenta", modifiers = ["italic"] } -"markup.link.url" = { fg = "yellow", modifiers = ["underlined"] } -"markup.link.text" = "red" -"markup.quote" = "cyan" -"markup.raw" = "green" +"markup.heading" = { fg = "blue2", modifiers = ["bold"] } +"markup.list" = "blue3" +"markup.bold" = { fg = "blue2", modifiers = ["bold"] } +"markup.italic" = { modifiers = ["italic"] } +"markup.link.url" = { modifiers = ["underlined"] } +"markup.link.text" = "orange" +"markup.quote" = "dark_green" +"markup.raw" = "orange" "diff.plus" = { fg = "pale_green" } "diff.delta" = { fg = "gold" } @@ -97,12 +96,13 @@ light_gray3 = "#eeeeee" dark_gray = "#858585" dark_gray2 = "#1e1e1e" blue = "#007acc" +blue2 = "#569CD6" +blue3 = "#6796E6" light_blue = "#75beff" dark_blue = "#264f78" red = "#ff1212" type = "#4EC9B0" -keyword = "#569CD6" special = "#C586C0" variable = "#9CDCFE" fn_declaration = "#DCDCAA" From 275c05008fb5bc2f15044738a329939bc6b5befc Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 6 Apr 2022 10:31:40 -0500 Subject: [PATCH 039/861] fix keymap doc typo for 'delete' in insert-mode (#1990) closes #1980 see also #1180 --- 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 2fbc7b3f9..942292e0b 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -306,7 +306,7 @@ undo-able "save point" until you return to normal mode. | `Ctrl-k` | Delete to end of line | `kill_to_line_end` | | `Ctrl-j`, `Enter` | Insert new line | `insert_newline` | | `Backspace`, `Ctrl-h` | Delete previous char | `delete_char_backward` | -| `Delete`, `Ctrl-d` | Delete previous char | `delete_char_forward` | +| `Delete`, `Ctrl-d` | Delete next char | `delete_char_forward` | | `Ctrl-p`, `Up` | Move to previous line | `move_line_up` | | `Ctrl-n`, `Down` | Move to next line | `move_line_down` | | `PageUp` | Move one page up | `page_up` | From b03421a8c0811b48da0f30f4d4fce41a1f98a547 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 6 Apr 2022 10:32:00 -0500 Subject: [PATCH 040/861] remove hardcoded '/' from grammar source path (#1986) --- helix-loader/src/grammar.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index f0c5ea282..7474713a5 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -143,7 +143,8 @@ fn fetch_grammar(grammar: GrammarConfiguration) -> Result<()> { } = grammar.source { let grammar_dir = crate::runtime_dir() - .join("grammars/sources") + .join("grammars") + .join("sources") .join(&grammar.grammar_id); fs::create_dir_all(&grammar_dir).context(format!( @@ -233,7 +234,8 @@ fn build_grammar(grammar: GrammarConfiguration) -> Result<()> { PathBuf::from(&path) } else { crate::runtime_dir() - .join("grammars/sources") + .join("grammars") + .join("sources") .join(&grammar.grammar_id) }; From d37369c1e056e41d405bc95b13efd550c57fa933 Mon Sep 17 00:00:00 2001 From: tomKPZ Date: Wed, 6 Apr 2022 18:11:14 -0700 Subject: [PATCH 041/861] Add paragraph textobject to match infobox (#1969) --- helix-term/src/commands.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 9a222427f..c7eb46ab1 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4025,6 +4025,7 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) { let help_text = [ ("w", "Word"), ("W", "WORD"), + ("p", "Paragraph"), ("c", "Class (tree-sitter)"), ("f", "Function (tree-sitter)"), ("a", "Argument/parameter (tree-sitter)"), From 31c468ab95fe775dc65bef0674ca3c3ec219259f Mon Sep 17 00:00:00 2001 From: Matthew Toohey Date: Thu, 7 Apr 2022 20:30:44 -0400 Subject: [PATCH 042/861] add languages `r` and `rmarkdown` (#1998) * add languages `r` and `rmarkdown` * r: fix highlights * rmarkdown: add eof in queries * rmarkdown: update lang-support.md * r: fix highlight query precedence --- book/src/generated/lang-support.md | 2 + languages.toml | 25 +++++ runtime/queries/r/highlights.scm | 128 +++++++++++++++++++++++ runtime/queries/r/locals.scm | 11 ++ runtime/queries/rmarkdown/highlights.scm | 1 + runtime/queries/rmarkdown/indents.scm | 1 + runtime/queries/rmarkdown/injections.scm | 1 + 7 files changed, 169 insertions(+) create mode 100644 runtime/queries/r/highlights.scm create mode 100644 runtime/queries/r/locals.scm create mode 100644 runtime/queries/rmarkdown/highlights.scm create mode 100644 runtime/queries/rmarkdown/indents.scm create mode 100644 runtime/queries/rmarkdown/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index b71349f31..e8bb65e4f 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -50,9 +50,11 @@ | prolog | | | | `swipl` | | protobuf | ✓ | | ✓ | | | python | ✓ | ✓ | ✓ | `pylsp` | +| r | ✓ | | | `R` | | racket | | | | `racket` | | regex | ✓ | | | | | rescript | ✓ | ✓ | | `rescript-language-server` | +| rmarkdown | ✓ | | ✓ | `R` | | ron | ✓ | | ✓ | | | ruby | ✓ | | ✓ | `solargraph` | | rust | ✓ | ✓ | ✓ | `rust-analyzer` | diff --git a/languages.toml b/languages.toml index d81d03733..2c6f0c9a1 100644 --- a/languages.toml +++ b/languages.toml @@ -1038,3 +1038,28 @@ roots = [] comment-token = "//" indent = { tab-width = 4, unit = " " } grammar = "rust" + +[[language]] +name = "r" +scope = "source.r" +injection-regex = "(r|R)" +file-types = ["r", "R"] +shebangs = ["r", "R"] +roots = [] +comment-token = "#" +indent = { tab-width = 2, unit = " " } +language-server = { command = "R", args = ["--slave", "-e", "languageserver::run()"] } + +[[grammar]] +name = "r" +source = { git = "https://github.com/r-lib/tree-sitter-r", rev = "cc04302e1bff76fa02e129f332f44636813b0c3c" } + +[[language]] +name = "rmarkdown" +scope = "source.rmd" +injection-regex = "(r|R)md" +file-types = ["rmd", "Rmd"] +roots = [] +indent = { tab-width = 2, unit = " " } +grammar = "markdown" +language-server = { command = "R", args = ["--slave", "-e", "languageserver::run()"] } diff --git a/runtime/queries/r/highlights.scm b/runtime/queries/r/highlights.scm new file mode 100644 index 000000000..4b931a053 --- /dev/null +++ b/runtime/queries/r/highlights.scm @@ -0,0 +1,128 @@ +; highlights.scm + + +; Literals + +(integer) @constant.numeric.integer + +(float) @constant.numeric.float + +(complex) @constant.numeric.integer + +(string) @string +(string (escape_sequence) @constant.character.escape) + +(comment) @comment + +(formal_parameters (identifier) @variable.parameter) +(formal_parameters (default_parameter (identifier) @variable.parameter)) + +; Operators +[ + "=" + "<-" + "<<-" + "->>" + "->" +] @operator + +(unary operator: [ + "-" + "+" + "!" + "~" +] @operator) + +(binary operator: [ + "-" + "+" + "*" + "/" + "^" + "<" + ">" + "<=" + ">=" + "==" + "!=" + "||" + "|" + "&&" + "&" + ":" + "~" +] @operator) + +[ + "|>" + (special) +] @operator + +(lambda_function "\\" @operator) + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +(dollar "$" @operator) + +(subset2 + [ + "[[" + "]]" + ] @punctuation.bracket) + +[ + "in" + (dots) + (break) + (next) + (inf) +] @keyword + +[ + (nan) + (na) + (null) +] @type.builtin + +[ + "if" + "else" + "switch" +] @keyword.control.conditional + +[ + "while" + "repeat" + "for" +] @keyword.control.repeat + +[ + (true) + (false) +] @constant.builtin.boolean + +"function" @keyword.function + +(call function: (identifier) @function) +(default_argument name: (identifier) @variable.parameter) + + +(namespace_get namespace: (identifier) @namespace + "::" @operator) +(namespace_get_internal namespace: (identifier) @namespace + ":::" @operator) + +(namespace_get function: (identifier) @function.method) +(namespace_get_internal function: (identifier) @function.method) + +(identifier) @variable + +; Error +(ERROR) @error diff --git a/runtime/queries/r/locals.scm b/runtime/queries/r/locals.scm new file mode 100644 index 000000000..be6cc6379 --- /dev/null +++ b/runtime/queries/r/locals.scm @@ -0,0 +1,11 @@ +; locals.scm + +(function_definition) @local.scope + +(formal_parameters (identifier) @local.definition) + +(left_assignment name: (identifier) @local.definition) +(equals_assignment name: (identifier) @local.definition) +(right_assignment name: (identifier) @local.definition) + +(identifier) @local.reference diff --git a/runtime/queries/rmarkdown/highlights.scm b/runtime/queries/rmarkdown/highlights.scm new file mode 100644 index 000000000..a3a30e342 --- /dev/null +++ b/runtime/queries/rmarkdown/highlights.scm @@ -0,0 +1 @@ +; inherits: markdown diff --git a/runtime/queries/rmarkdown/indents.scm b/runtime/queries/rmarkdown/indents.scm new file mode 100644 index 000000000..a3a30e342 --- /dev/null +++ b/runtime/queries/rmarkdown/indents.scm @@ -0,0 +1 @@ +; inherits: markdown diff --git a/runtime/queries/rmarkdown/injections.scm b/runtime/queries/rmarkdown/injections.scm new file mode 100644 index 000000000..a3a30e342 --- /dev/null +++ b/runtime/queries/rmarkdown/injections.scm @@ -0,0 +1 @@ +; inherits: markdown From 420b5b8301060aa19ecc7d06cb05d0e8e11e570d Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Fri, 8 Apr 2022 06:12:57 +0530 Subject: [PATCH 043/861] Compute style only once per source highlight event (#1966) During a single HighlightEvent::Source, the highlight spans do not change and we can merge them into a single style at the beginning of the event and use it instead of re-computing it for every grapheme --- helix-term/src/ui/editor.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 28665ec3b..979b95d99 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -343,6 +343,9 @@ impl EditorView { // the rope, to allow cursor highlighting at the end // of the rope. let text = text.get_slice(start..end).unwrap_or_else(|| " ".into()); + let style = spans + .iter() + .fold(text_style, |acc, span| acc.patch(theme.highlight(span.0))); use helix_core::graphemes::{grapheme_width, RopeGraphemes}; @@ -352,10 +355,6 @@ impl EditorView { if LineEnding::from_rope_slice(&grapheme).is_some() { if !out_of_bounds { - let style = spans.iter().fold(text_style, |acc, span| { - acc.patch(theme.highlight(span.0)) - }); - // we still want to render an empty cell with the style surface.set_string( viewport.x + visual_x - offset.col as u16, @@ -387,10 +386,6 @@ impl EditorView { }; if !out_of_bounds { - let style = spans.iter().fold(text_style, |acc, span| { - acc.patch(theme.highlight(span.0)) - }); - // if we're offscreen just keep going until we hit a new line surface.set_string( viewport.x + visual_x - offset.col as u16, From 2d4f94eb276bb6519bebcb6aa11e78d92ed9ea11 Mon Sep 17 00:00:00 2001 From: Kirawi <67773714+kirawi@users.noreply.github.com> Date: Thu, 7 Apr 2022 22:08:16 -0400 Subject: [PATCH 044/861] [dark_plus] update tag and ui.menu.selected colors (#2014) --- runtime/themes/dark_plus.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runtime/themes/dark_plus.toml b/runtime/themes/dark_plus.toml index 386401228..42032be27 100644 --- a/runtime/themes/dark_plus.toml +++ b/runtime/themes/dark_plus.toml @@ -13,6 +13,7 @@ "keyword.directive" = { fg = "blue2" } "keyword.control" = { fg = "special" } "label" = { fg = "blue2" } +"tag" = "blue2" "special" = { fg = "text" } "operator" = { fg = "text" } @@ -57,7 +58,8 @@ "ui.window" = { bg = "widget" } "ui.popup" = { bg = "widget" } "ui.help" = { bg = "widget" } -"ui.menu.selected" = { bg = "widget" } +"ui.menu" = { bg = "widget" } +"ui.menu.selected" = { bg = "dark_blue2" } # TODO: Alternate bg colour for `ui.cursor.match` and `ui.selection`. "ui.cursor" = { fg = "cursor", modifiers = ["reversed"] } @@ -100,6 +102,7 @@ blue2 = "#569CD6" blue3 = "#6796E6" light_blue = "#75beff" dark_blue = "#264f78" +dark_blue2 = "#094771" red = "#ff1212" type = "#4EC9B0" From 581ac5660fdb0ae5d0dfe2bc9fd95e0333b68c5c Mon Sep 17 00:00:00 2001 From: Gaeulbyul <830515+gaeulbyul@users.noreply.github.com> Date: Fri, 8 Apr 2022 13:35:11 +0000 Subject: [PATCH 045/861] Fix typo (pallete -> palette) (#2020) --- helix-term/src/commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c7eb46ab1..3757912af 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -414,7 +414,7 @@ impl MappableCommand { decrement, "Decrement", record_macro, "Record macro", replay_macro, "Replay macro", - command_palette, "Open command pallete", + command_palette, "Open command palette", ); } From b5efb9d66cfb582eec0b96174d856c8f7e43d82c Mon Sep 17 00:00:00 2001 From: David <12832280+David-Else@users.noreply.github.com> Date: Fri, 8 Apr 2022 14:36:10 +0100 Subject: [PATCH 046/861] Add default language server for HTML (#2018) --- book/src/generated/lang-support.md | 2 +- languages.toml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index e8bb65e4f..e6b5ccc58 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -23,7 +23,7 @@ | graphql | ✓ | | | | | haskell | ✓ | | | `haskell-language-server-wrapper` | | hcl | ✓ | | ✓ | `terraform-ls` | -| html | ✓ | | | | +| html | ✓ | | | `vscode-html-language-server` | | iex | ✓ | | | | | java | ✓ | | | | | javascript | ✓ | | ✓ | `typescript-language-server` | diff --git a/languages.toml b/languages.toml index 2c6f0c9a1..351fa4ac6 100644 --- a/languages.toml +++ b/languages.toml @@ -348,6 +348,9 @@ scope = "text.html.basic" injection-regex = "html" file-types = ["html"] roots = [] +language-server = { command = "vscode-html-language-server", args = ["--stdio"] } +auto-format = true +config = { "provideFormatter" = true } indent = { tab-width = 2, unit = " " } [[grammar]] From 22629ca211152edfd8df3ae45b7cd380b18946fc Mon Sep 17 00:00:00 2001 From: David <12832280+David-Else@users.noreply.github.com> Date: Fri, 8 Apr 2022 16:06:41 +0100 Subject: [PATCH 047/861] Add default language server for JSON (#2024) --- book/src/generated/lang-support.md | 2 +- languages.toml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index e6b5ccc58..2109d227c 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -27,7 +27,7 @@ | iex | ✓ | | | | | java | ✓ | | | | | javascript | ✓ | | ✓ | `typescript-language-server` | -| json | ✓ | | ✓ | | +| json | ✓ | | ✓ | `vscode-json-language-server` | | jsx | ✓ | | ✓ | `typescript-language-server` | | julia | ✓ | | | `julia` | | kotlin | ✓ | | | `kotlin-language-server` | diff --git a/languages.toml b/languages.toml index 351fa4ac6..18a7d6b68 100644 --- a/languages.toml +++ b/languages.toml @@ -121,6 +121,9 @@ scope = "source.json" injection-regex = "json" file-types = ["json"] roots = [] +language-server = { command = "vscode-json-language-server", args = ["--stdio"] } +auto-format = true +config = { "provideFormatter" = true } indent = { tab-width = 2, unit = " " } [[grammar]] From 61d1684a329e933261fbb3863f7cffbda89292ac Mon Sep 17 00:00:00 2001 From: David <12832280+David-Else@users.noreply.github.com> Date: Fri, 8 Apr 2022 16:06:54 +0100 Subject: [PATCH 048/861] Add default language server for CSS (#2025) --- book/src/generated/lang-support.md | 2 +- languages.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 2109d227c..9039ca155 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -6,7 +6,7 @@ | cmake | ✓ | ✓ | ✓ | `cmake-language-server` | | comment | ✓ | | | | | cpp | ✓ | ✓ | ✓ | `clangd` | -| css | ✓ | | | | +| css | ✓ | | | `vscode-css-language-server` | | dart | ✓ | | ✓ | `dart` | | dockerfile | ✓ | | | `docker-langserver` | | elixir | ✓ | | | `elixir-ls` | diff --git a/languages.toml b/languages.toml index 18a7d6b68..8c91db9fb 100644 --- a/languages.toml +++ b/languages.toml @@ -339,6 +339,7 @@ scope = "source.css" injection-regex = "css" file-types = ["css", "scss"] roots = [] +language-server = { command = "vscode-css-language-server", args = ["--stdio"] } indent = { tab-width = 2, unit = " " } [[grammar]] From 19ff21eaa27141807ee206230d1e6e9f071b8180 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 8 Apr 2022 10:56:50 -0500 Subject: [PATCH 049/861] Remove usage of format ident feature from tests (#2028) --- helix-core/src/movement.rs | 12 ++++++------ helix-core/src/syntax.rs | 4 +++- helix-core/src/test.rs | 8 ++++---- helix-core/src/textobject.rs | 6 +++--- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs index e695bf944..f60b3c83f 100644 --- a/helix-core/src/movement.rs +++ b/helix-core/src/movement.rs @@ -1293,7 +1293,7 @@ mod test { let selection = selection.transform(|r| move_prev_paragraph(text.slice(..), r, 1, Movement::Move)); let actual = crate::test::plain(&s, selection); - assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + assert_eq!(actual, expected, "\nbefore: `{:?}`", before); } } @@ -1316,7 +1316,7 @@ mod test { let selection = selection.transform(|r| move_prev_paragraph(text.slice(..), r, 2, Movement::Move)); let actual = crate::test::plain(&s, selection); - assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + assert_eq!(actual, expected, "\nbefore: `{:?}`", before); } } @@ -1339,7 +1339,7 @@ mod test { let selection = selection .transform(|r| move_prev_paragraph(text.slice(..), r, 1, Movement::Extend)); let actual = crate::test::plain(&s, selection); - assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + assert_eq!(actual, expected, "\nbefore: `{:?}`", before); } } @@ -1381,7 +1381,7 @@ mod test { let selection = selection.transform(|r| move_next_paragraph(text.slice(..), r, 1, Movement::Move)); let actual = crate::test::plain(&s, selection); - assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + assert_eq!(actual, expected, "\nbefore: `{:?}`", before); } } @@ -1404,7 +1404,7 @@ mod test { let selection = selection.transform(|r| move_next_paragraph(text.slice(..), r, 2, Movement::Move)); let actual = crate::test::plain(&s, selection); - assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + assert_eq!(actual, expected, "\nbefore: `{:?}`", before); } } @@ -1427,7 +1427,7 @@ mod test { let selection = selection .transform(|r| move_next_paragraph(text.slice(..), r, 1, Movement::Extend)); let actual = crate::test::plain(&s, selection); - assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + assert_eq!(actual, expected, "\nbefore: `{:?}`", before); } } } diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index bb0073e1c..72b0e9562 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -1996,7 +1996,9 @@ mod test { assert_eq!( matches[0].byte_range(), range, - "@{capture} expected {range:?}" + "@{} expected {:?}", + capture, + range ) }; diff --git a/helix-core/src/test.rs b/helix-core/src/test.rs index 064ca8a38..45503107c 100644 --- a/helix-core/src/test.rs +++ b/helix-core/src/test.rs @@ -53,7 +53,7 @@ pub fn print(s: &str) -> (String, Selection) { }; if is_primary && primary_idx.is_some() { - panic!("primary `#[` already appeared {left:?} {s:?}"); + panic!("primary `#[` already appeared {:?} {:?}", left, s); } let head_at_beg = iter.next_if_eq(&'|').is_some(); @@ -85,15 +85,15 @@ pub fn print(s: &str) -> (String, Selection) { } if head_at_beg { - panic!("missing end `{close_pair}#` {left:?} {s:?}"); + panic!("missing end `{}#` {:?} {:?}", close_pair, left, s); } else { - panic!("missing end `|{close_pair}#` {left:?} {s:?}"); + panic!("missing end `|{}#` {:?} {:?}", close_pair, left, s); } } let primary = match primary_idx { Some(i) => i, - None => panic!("missing primary `#[|]#` {s:?}"), + None => panic!("missing primary `#[|]#` {:?}", s), }; let selection = Selection::new(ranges, primary); (left, selection) diff --git a/helix-core/src/textobject.rs b/helix-core/src/textobject.rs index 67bf40a65..e7bbfc43e 100644 --- a/helix-core/src/textobject.rs +++ b/helix-core/src/textobject.rs @@ -381,7 +381,7 @@ mod test { let selection = selection .transform(|r| textobject_paragraph(text.slice(..), r, TextObject::Inside, 1)); let actual = crate::test::plain(&s, selection); - assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + assert_eq!(actual, expected, "\nbefore: `{:?}`", before); } } @@ -404,7 +404,7 @@ mod test { let selection = selection .transform(|r| textobject_paragraph(text.slice(..), r, TextObject::Inside, 2)); let actual = crate::test::plain(&s, selection); - assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + assert_eq!(actual, expected, "\nbefore: `{:?}`", before); } } @@ -435,7 +435,7 @@ mod test { let selection = selection .transform(|r| textobject_paragraph(text.slice(..), r, TextObject::Around, 1)); let actual = crate::test::plain(&s, selection); - assert_eq!(actual, expected, "\nbefore: `{before:?}`"); + assert_eq!(actual, expected, "\nbefore: `{:?}`", before); } } From 8e12fd52908ecc7d53d1b456fe3b10e0833f1a63 Mon Sep 17 00:00:00 2001 From: Karl Grasegger <51945878+grasegger@users.noreply.github.com> Date: Fri, 8 Apr 2022 17:57:46 +0000 Subject: [PATCH 050/861] PHP roots and languageserver improvements (#2031) Co-authored-by: Karl Grasegger --- book/src/generated/lang-support.md | 2 +- languages.toml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 9039ca155..6331b0599 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -46,7 +46,7 @@ | ocaml-interface | ✓ | | | | | org | ✓ | | | | | perl | ✓ | ✓ | ✓ | | -| php | ✓ | ✓ | ✓ | | +| php | ✓ | ✓ | ✓ | `intelephense` | | prolog | | | | `swipl` | | protobuf | ✓ | | ✓ | | | python | ✓ | ✓ | ✓ | `pylsp` | diff --git a/languages.toml b/languages.toml index 8c91db9fb..f331edfe0 100644 --- a/languages.toml +++ b/languages.toml @@ -428,7 +428,8 @@ scope = "source.php" injection-regex = "php" file-types = ["php"] shebangs = ["php"] -roots = [] +roots = ["composer.json", "index.php"] +language-server = { command = "intelephense", args = ["--stdio"] } indent = { tab-width = 4, unit = " " } [[grammar]] From 9caf7c0d5aae16acd76e39b078ef8a94ed102b65 Mon Sep 17 00:00:00 2001 From: Aaron Housh Date: Fri, 8 Apr 2022 11:10:37 -0700 Subject: [PATCH 051/861] Add swift language (#2033) --- book/src/generated/lang-support.md | 1 + languages.toml | 14 +++ runtime/queries/swift/highlights.scm | 158 +++++++++++++++++++++++++++ runtime/queries/swift/locals.scm | 18 +++ 4 files changed, 191 insertions(+) create mode 100644 runtime/queries/swift/highlights.scm create mode 100644 runtime/queries/swift/locals.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 6331b0599..69419e325 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -61,6 +61,7 @@ | scala | ✓ | | ✓ | `metals` | | solidity | ✓ | | | `solc` | | svelte | ✓ | | ✓ | `svelteserver` | +| swift | ✓ | | | `sourcekit-lsp` | | tablegen | ✓ | ✓ | ✓ | | | toml | ✓ | | | | | tsq | ✓ | | | | diff --git a/languages.toml b/languages.toml index f331edfe0..b56328a85 100644 --- a/languages.toml +++ b/languages.toml @@ -1071,3 +1071,17 @@ roots = [] indent = { tab-width = 2, unit = " " } grammar = "markdown" language-server = { command = "R", args = ["--slave", "-e", "languageserver::run()"] } + +[[language]] +name = "swift" +scope = "source.swift" +injection-regex = "swift" +file-types = ["swift"] +roots = [ "Package.swift" ] +comment-token = "//" +auto-format = true +language-server = { command = "sourcekit-lsp" } + +[[grammar]] +name = "swift" +source = { git = "https://github.com/Dispersia/tree-sitter-swift", rev = "e75240f89bb3bfd3396155859ae364e5c58d7377" } diff --git a/runtime/queries/swift/highlights.scm b/runtime/queries/swift/highlights.scm new file mode 100644 index 000000000..fe240e9d9 --- /dev/null +++ b/runtime/queries/swift/highlights.scm @@ -0,0 +1,158 @@ +[ "." ";" ":" "," ] @punctuation.delimiter +[ "\\(" "(" ")" "[" "]" "{" "}"] @punctuation.bracket ; TODO: "\\(" ")" in interpolations should be @punctuation.special + +; Identifiers +(attribute) @variable +(type_identifier) @type +(self_expression) @variable.builtin + +; Declarations +"func" @keyword.function +[ + (visibility_modifier) + (member_modifier) + (function_modifier) + (property_modifier) + (parameter_modifier) + (inheritance_modifier) +] @keyword + +(function_declaration (simple_identifier) @function.method) +(function_declaration ["init" @constructor]) +(throws) @keyword +"async" @keyword +(where_keyword) @keyword +(parameter external_name: (simple_identifier) @variable.parameter) +(parameter name: (simple_identifier) @variable.parameter) +(type_parameter (type_identifier) @variable.parameter) +(inheritance_constraint (identifier (simple_identifier) @variable.parameter)) +(equality_constraint (identifier (simple_identifier) @variable.parameter)) +(non_binding_pattern bound_identifier: (simple_identifier)) @variable + +[ + "typealias" + "struct" + "class" + "enum" + "protocol" + "extension" + "indirect" + "some" +] @keyword + +[ + (getter_specifier) + (setter_specifier) + (modify_specifier) +] @keyword + +(class_body (property_declaration (value_binding_pattern (non_binding_pattern (simple_identifier) @variable.other.member)))) +(protocol_property_declaration (value_binding_pattern (non_binding_pattern (simple_identifier) @variable.other.member))) + +(import_declaration ["import" @keyword.control.import]) + +(enum_entry ["case" @keyword]) + +; Function calls +(call_expression (simple_identifier) @function) ; foo() +(call_expression ; foo.bar.baz(): highlight the baz() + (navigation_expression + (navigation_suffix (simple_identifier) @function))) +((navigation_expression + (simple_identifier) @type) ; SomeType.method(): highlight SomeType as a type + (#match? @type "^[A-Z]")) + +(directive) @function.macro +(diagnostic) @function.macro + +; Statements +(for_statement ["for" @keyword.control.repeat]) +(for_statement ["in" @keyword.control.repeat]) +(for_statement item: (simple_identifier) @variable) +(else) @keyword +(as_operator) @keyword + +["while" "repeat" "continue" "break"] @keyword.control.repeat + +["let" "var"] @keyword +(non_binding_pattern (simple_identifier) @variable) + +(guard_statement ["guard" @keyword.control.conditional]) +(if_statement ["if" @keyword.control.conditional]) +(switch_statement ["switch" @keyword.control.conditional]) +(switch_entry ["case" @keyword]) +(switch_entry ["fallthrough" @keyword]) +(switch_entry (default_keyword) @keyword) +"return" @keyword.control.return +(ternary_expression + ["?" ":"] @keyword.control.conditional) + +["do" (throw_keyword) (catch_keyword)] @keyword + +(statement_label) @label + +; Comments +(comment) @comment.line +(multiline_comment) @comment.block + +; String literals +(line_str_text) @string +(str_escaped_char) @string +(multi_line_str_text) @string +(raw_str_part) @string +(raw_str_end_part) @string +(raw_str_interpolation_start) @string.special +["\"" "\"\"\""] @string + +; Lambda literals +(lambda_literal ["in" @keyword.operator]) + +; Basic literals +(integer_literal) @constant.numeric.integer +[ + (hex_literal) + (oct_literal) + (bin_literal) +] @constant.numeric +(real_literal) @constant.numeric.float +(boolean_literal) @constant.builtin.boolean +"nil" @variable.builtin + +; Operators +(custom_operator) @operator +[ + "try" + "try?" + "try!" + "!" + "+" + "-" + "*" + "/" + "%" + "=" + "+=" + "-=" + "*=" + "/=" + "<" + ">" + "<=" + ">=" + "++" + "--" + "&" + "~" + "%=" + "!=" + "!==" + "==" + "===" + "??" + + "->" + + "..<" + "..." +] @operator + diff --git a/runtime/queries/swift/locals.scm b/runtime/queries/swift/locals.scm new file mode 100644 index 000000000..dfe1c83b1 --- /dev/null +++ b/runtime/queries/swift/locals.scm @@ -0,0 +1,18 @@ +(import_declaration (identifier) @definition.import) +(function_declaration name: (simple_identifier) @definition.function) + +; Scopes +[ + (statements) + (for_statement) + (while_statement) + (repeat_while_statement) + (do_statement) + (if_statement) + (guard_statement) + (switch_statement) + (property_declaration) + (function_declaration) + (class_declaration) + (protocol_declaration) +] @scope From 7f461895b02139b8e1addf6ee6651fc3811c6cbe Mon Sep 17 00:00:00 2001 From: unrelentingtech Date: Fri, 8 Apr 2022 23:02:25 +0300 Subject: [PATCH 052/861] Add language server command for OCaml (#2035) --- book/src/generated/lang-support.md | 4 ++-- languages.toml | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 69419e325..c4c649801 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -42,8 +42,8 @@ | markdown | ✓ | | | | | mint | | | | `mint` | | nix | ✓ | | ✓ | `rnix-lsp` | -| ocaml | ✓ | | ✓ | | -| ocaml-interface | ✓ | | | | +| ocaml | ✓ | | ✓ | `ocamllsp` | +| ocaml-interface | ✓ | | | `ocamllsp` | | org | ✓ | | | | | perl | ✓ | ✓ | ✓ | | | php | ✓ | ✓ | ✓ | `intelephense` | diff --git a/languages.toml b/languages.toml index b56328a85..6c07ec0b6 100644 --- a/languages.toml +++ b/languages.toml @@ -529,6 +529,7 @@ file-types = ["ml"] shebangs = [] roots = [] comment-token = "(**)" +language-server = { command = "ocamllsp" } indent = { tab-width = 2, unit = " " } [[grammar]] @@ -542,7 +543,8 @@ file-types = ["mli"] shebangs = [] roots = [] comment-token = "(**)" -indent = { tab-width = 2, unit = " "} +language-server = { command = "ocamllsp" } +indent = { tab-width = 2, unit = " " } [[grammar]] name = "ocaml-interface" From 209ec4468b82b49bac9bc47c539dfe8b049f41cb Mon Sep 17 00:00:00 2001 From: Sam Sartor Date: Fri, 8 Apr 2022 16:53:12 -0400 Subject: [PATCH 053/861] Add dracula at night theme (#2008) --- runtime/themes/dracula_at_night.toml | 64 ++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 runtime/themes/dracula_at_night.toml diff --git a/runtime/themes/dracula_at_night.toml b/runtime/themes/dracula_at_night.toml new file mode 100644 index 000000000..0a45f024b --- /dev/null +++ b/runtime/themes/dracula_at_night.toml @@ -0,0 +1,64 @@ +# Author : Sam Sartor +# A port of https://github.com/bceskavich/dracula-at-night +"comment" = { fg = "comment" } +"constant" = { fg = "purple" } +"constant.character.escape" = { fg = "pink" } +"function" = { fg = "green" } +"keyword" = { fg = "pink" } +"operator" = { fg = "pink" } +"punctuation" = { fg = "foreground" } +"string" = { fg = "yellow" } +"string.regexp" = { fg = "red" } +"tag" = { fg = "pink" } +"type" = { fg = "cyan", modifiers = ["italic"] } +"type.enum.variant" = { fg = "foreground", modifiers = ["italic"] } +"variable" = { fg = "foreground" } +"variable.builtin" = { fg = "cyan", modifiers = ["italic"] } +"variable.parameter" = { fg ="orange", modifiers = ["italic"] } + +"diff.plus" = { fg = "green" } +"diff.delta" = { fg = "orange" } +"diff.minus" = { fg = "red" } + +"ui.background" = { fg = "foreground", bg = "background" } +"ui.cursor" = { fg = "background", bg = "orange", modifiers = ["dim"] } +"ui.cursor.match" = { fg = "green", modifiers = ["underlined"] } +"ui.cursor.primary" = { fg = "background", bg = "cyan", modifier = ["dim"] } +"ui.help" = { fg = "foreground", bg = "background_dark" } +"ui.linenr" = { fg = "comment" } +"ui.linenr.selected" = { fg = "foreground" } +"ui.menu" = { fg = "foreground", bg = "background_dark" } +"ui.menu.selected" = { fg = "cyan", bg = "background_dark" } +"ui.popup" = { fg = "foreground", bg = "background_dark" } +"ui.selection" = { fg = "background", bg = "purple", modifiers = ["dim"] } +"ui.selection.primary" = { fg = "background", bg = "pink" } +"ui.statusline" = { fg = "foreground", bg = "background_dark" } +"ui.statusline.inactive" = { fg = "comment", bg = "background_dark" } +"ui.text" = { fg = "foreground" } +"ui.text.focus" = { fg = "cyan" } +"ui.window" = { fg = "foreground" } + +"error" = { fg = "red" } +"warning" = { fg = "cyan" } + +"markup.heading" = { fg = "purple", modifiers = ["bold"] } +"markup.list" = "cyan" +"markup.bold" = { fg = "orange", modifiers = ["bold"] } +"markup.italic" = { fg = "yellow", modifiers = ["italic"] } +"markup.link.url" = "cyan" +"markup.link.text" = "pink" +"markup.quote" = { fg = "yellow", modifiers = ["italic"] } +"markup.raw" = { fg = "foreground" } + +[palette] +background = "#0e1419" +background_dark = "#21222c" +foreground = "#f8f8f2" +comment = "#6272a4" +red = "#ff5555" +orange = "#ffb86c" +yellow = "#f1fa8c" +green = "#50fa7b" +purple = "#bd93f9" +cyan = "#8be9fd" +pink = "#ff79c6" From 7779dbfcb847e9aa20e01ae0f8354c3c0de38fe3 Mon Sep 17 00:00:00 2001 From: Evan Relf Date: Fri, 8 Apr 2022 15:21:52 -0700 Subject: [PATCH 054/861] docs: Quote TOML keys containing dots (#2040) --- book/src/themes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/book/src/themes.md b/book/src/themes.md index 62265e28b..219b0ee3e 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -37,8 +37,8 @@ configuration values in your theme. To do this, add a table called `palette` to your theme file: ```toml -ui.background = "white" -ui.text = "black" +"ui.background" = "white" +"ui.text" = "black" [palette] white = "#ffffff" From 0b410b0a162e0c46995cad492ff1c4a65c4e5279 Mon Sep 17 00:00:00 2001 From: Kurenshe Nurdaulet <63652620+EpsilonKu@users.noreply.github.com> Date: Sat, 9 Apr 2022 08:04:22 +0600 Subject: [PATCH 055/861] Add default language server for Vue (#2043) --- book/src/generated/lang-support.md | 2 +- languages.toml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index c4c649801..4e8e1c82d 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -68,7 +68,7 @@ | tsx | ✓ | | | `typescript-language-server` | | twig | ✓ | | | | | typescript | ✓ | | ✓ | `typescript-language-server` | -| vue | ✓ | | | | +| vue | ✓ | | | `vls` | | wgsl | ✓ | | | | | yaml | ✓ | | ✓ | | | zig | ✓ | | ✓ | `zls` | diff --git a/languages.toml b/languages.toml index 6c07ec0b6..e80ca280b 100644 --- a/languages.toml +++ b/languages.toml @@ -581,8 +581,9 @@ name = "vue" scope = "source.vue" injection-regex = "vue" file-types = ["vue"] -roots = [] +roots = ["package.json", "vue.config.js"] indent = { tab-width = 2, unit = " " } +language-server = { command = "vls" } [[grammar]] name = "vue" From 78b16009433041059597cc6ccea28c17254483b7 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 9 Apr 2022 01:47:32 -0500 Subject: [PATCH 056/861] Improve documentation on Language Server installation (#2037) --- README.md | 4 ++++ book/src/guides/adding_languages.md | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4052d9411..6fc98e728 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,10 @@ that sets the variable to the install dir. > NOTE: running via cargo also doesn't require setting explicit `HELIX_RUNTIME` path, it will automatically > detect the `runtime` directory in the project root. +In order to use LSP features like auto-complete, you will need to +[install the appropriate Language Server](https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers) +for a language. + [![Packaging status](https://repology.org/badge/vertical-allrepos/helix.svg)](https://repology.org/project/helix/versions) ## MacOS diff --git a/book/src/guides/adding_languages.md b/book/src/guides/adding_languages.md index e5fa456c6..c2c70779d 100644 --- a/book/src/guides/adding_languages.md +++ b/book/src/guides/adding_languages.md @@ -16,6 +16,7 @@ injection-regex = "^mylang$" file-types = ["mylang", "myl"] comment-token = "#" indent = { tab-width = 2, unit = " " } +language-server = { command = "mylang-lsp", args = ["--stdio"] } ``` These are the available keys and descriptions for the file. @@ -32,9 +33,14 @@ These are the available keys and descriptions for the file. | `diagnostic-severity` | Minimal severity of diagnostic for it to be displayed. (Allowed values: `Error`, `Warning`, `Info`, `Hint`) | | `comment-token` | The token to use as a comment-token | | `indent` | The indent to use. Has sub keys `tab-width` and `unit` | -| `config` | Language server configuration | +| `language-server` | The Language Server to run. Has sub keys `command` and `args` | +| `config` | Language Server configuration | | `grammar` | The tree-sitter grammar to use (defaults to the value of `name`) | +When adding a Language Server configuration, be sure to update the +[Language Server Wiki](https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers) +with installation notes. + ## Grammar configuration If a tree-sitter grammar is available for the language, add a new `grammar` From 494306ad7ae8ffb45d4d7d906528b64812eee3a5 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 9 Apr 2022 18:23:06 -0500 Subject: [PATCH 057/861] add tree-sitter-embedded-template (erb & ejs) (#2055) After the incremental parsing rewrite for injections (which was released in 22.03 https://helix-editor.com/news/release-22-03-highlights/#incremental-injection-parsing-rewrite), we can now do combined injections which lets us pull in some templating grammars. The most notable of those is embedded-template - a pretty straightforward grammar that covers ERB and EJS. The grammar and highlights queries are shared between the two but they have different injections. --- book/src/generated/lang-support.md | 2 ++ languages.toml | 22 ++++++++++++++++++++++ runtime/queries/ejs/highlights.scm | 12 ++++++++++++ runtime/queries/ejs/injections.scm | 7 +++++++ runtime/queries/erb/highlights.scm | 1 + runtime/queries/erb/injections.scm | 7 +++++++ 6 files changed, 51 insertions(+) create mode 100644 runtime/queries/ejs/highlights.scm create mode 100644 runtime/queries/ejs/injections.scm create mode 100644 runtime/queries/erb/highlights.scm create mode 100644 runtime/queries/erb/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 4e8e1c82d..efafc3e58 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -9,8 +9,10 @@ | css | ✓ | | | `vscode-css-language-server` | | dart | ✓ | | ✓ | `dart` | | dockerfile | ✓ | | | `docker-langserver` | +| ejs | ✓ | | | | | elixir | ✓ | | | `elixir-ls` | | elm | ✓ | | | `elm-language-server` | +| erb | ✓ | | | | | erlang | ✓ | | | `erlang_ls` | | fish | ✓ | ✓ | ✓ | | | git-commit | ✓ | | | | diff --git a/languages.toml b/languages.toml index e80ca280b..13c34e010 100644 --- a/languages.toml +++ b/languages.toml @@ -1088,3 +1088,25 @@ language-server = { command = "sourcekit-lsp" } [[grammar]] name = "swift" source = { git = "https://github.com/Dispersia/tree-sitter-swift", rev = "e75240f89bb3bfd3396155859ae364e5c58d7377" } + +[[language]] +name = "erb" +scope = "text.html.erb" +injection-regex = "erb" +file-types = ["erb"] +roots = [] +indent = { tab-width = 2, unit = " " } +grammar = "embedded-template" + +[[language]] +name = "ejs" +scope = "text.html.ejs" +injection-regex = "ejs" +file-types = ["ejs"] +roots = [] +indent = { tab-width = 2, unit = " " } +grammar = "embedded-template" + +[[grammar]] +name = "embedded-template" +source = { git = "https://github.com/tree-sitter/tree-sitter-embedded-template", rev = "d21df11b0ecc6fd211dbe11278e92ef67bd17e97" } diff --git a/runtime/queries/ejs/highlights.scm b/runtime/queries/ejs/highlights.scm new file mode 100644 index 000000000..0bf76a7d4 --- /dev/null +++ b/runtime/queries/ejs/highlights.scm @@ -0,0 +1,12 @@ +(comment_directive) @comment + +[ + "<%#" + "<%" + "<%=" + "<%_" + "<%-" + "%>" + "-%>" + "_%>" +] @keyword diff --git a/runtime/queries/ejs/injections.scm b/runtime/queries/ejs/injections.scm new file mode 100644 index 000000000..e612a936c --- /dev/null +++ b/runtime/queries/ejs/injections.scm @@ -0,0 +1,7 @@ +((content) @injection.content + (#set! injection.language "html") + (#set! injection.combined)) + +((code) @injection.content + (#set! injection.language "javascript") + (#set! injection.combined)) diff --git a/runtime/queries/erb/highlights.scm b/runtime/queries/erb/highlights.scm new file mode 100644 index 000000000..38830615f --- /dev/null +++ b/runtime/queries/erb/highlights.scm @@ -0,0 +1 @@ +; inherits: ejs diff --git a/runtime/queries/erb/injections.scm b/runtime/queries/erb/injections.scm new file mode 100644 index 000000000..2824f7a00 --- /dev/null +++ b/runtime/queries/erb/injections.scm @@ -0,0 +1,7 @@ +((content) @injection.content + (#set! injection.language "html") + (#set! injection.combined)) + +((code) @injection.content + (#set! injection.language "ruby") + (#set! injection.combined)) From 562874a720678a238966c69f413cb3d691f74c66 Mon Sep 17 00:00:00 2001 From: gavynriebau Date: Sun, 10 Apr 2022 10:30:09 +0800 Subject: [PATCH 058/861] Add command for picking files from CWD (#1600) The `file_picker_at_current_directory` command opens the file picker at the current working directory (CWD). This can be useful when paired with the built-in `:cd` command which changes the CWD. It has been mapped to `space F` by default. --- helix-term/src/commands.rs | 7 +++++++ helix-term/src/keymap/default.rs | 1 + 2 files changed, 8 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 3757912af..886ee62df 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -259,6 +259,7 @@ impl MappableCommand { append_mode, "Insert after selection (append)", command_mode, "Enter command mode", file_picker, "Open file picker", + file_picker_in_current_directory, "Open file picker at current working directory", code_action, "Perform code action", buffer_picker, "Open buffer picker", symbol_picker, "Open symbol picker", @@ -2047,6 +2048,12 @@ fn file_picker(cx: &mut Context) { cx.push_layer(Box::new(overlayed(picker))); } +fn file_picker_in_current_directory(cx: &mut Context) { + let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("./")); + let picker = ui::file_picker(cwd, &cx.editor.config()); + cx.push_layer(Box::new(picker)); +} + fn buffer_picker(cx: &mut Context) { let current = view!(cx.editor).doc; diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index a8144ebc2..18ebbcfed 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -196,6 +196,7 @@ pub fn default() -> HashMap { "space" => { "Space" "f" => file_picker, + "F" => file_picker_in_current_directory, "b" => buffer_picker, "s" => symbol_picker, "S" => workspace_symbol_picker, From 3d79c60a1ff7d2976c89b90976746df629be34fa Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 10 Apr 2022 12:50:05 -0500 Subject: [PATCH 059/861] Rewrite Language Support docs (#2065) --- book/src/guides/adding_languages.md | 8 ++++++-- book/src/lang-support.md | 16 +++++++++++----- languages.toml | 3 +++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/book/src/guides/adding_languages.md b/book/src/guides/adding_languages.md index c2c70779d..e9e1a69f3 100644 --- a/book/src/guides/adding_languages.md +++ b/book/src/guides/adding_languages.md @@ -37,9 +37,11 @@ These are the available keys and descriptions for the file. | `config` | Language Server configuration | | `grammar` | The tree-sitter grammar to use (defaults to the value of `name`) | +When adding a new language or Language Server configuration for an existing +language, run `cargo xtask docgen` to add the new configuration to the +[Language Support][lang-support] docs before creating a pull request. When adding a Language Server configuration, be sure to update the -[Language Server Wiki](https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers) -with installation notes. +[Language Server Wiki][install-lsp-wiki] with installation notes. ## Grammar configuration @@ -94,3 +96,5 @@ the last matching query supersedes the ones before it. See [treesitter-language-injection]: https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection [languages.toml]: https://github.com/helix-editor/helix/blob/master/languages.toml [neovim-query-precedence]: https://github.com/helix-editor/helix/pull/1170#issuecomment-997294090 +[install-lsp-wiki]: https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers +[lang-support]: ../lang-support.md diff --git a/book/src/lang-support.md b/book/src/lang-support.md index 3920f3424..6a08cd699 100644 --- a/book/src/lang-support.md +++ b/book/src/lang-support.md @@ -1,10 +1,16 @@ # Language Support -For more information like arguments passed to default LSP server, -extensions assosciated with a filetype, custom LSP settings, filetype -specific indent settings, etc see the default -[`languages.toml`][languages.toml] file. +The following languages and Language Servers are supported. In order to use +Language Server features, you must first [install][lsp-install-wiki] the +appropriate Language Server. + +Check the language support in your installed helix version with `hx --health`. + +Also see the [Language Configuration][lang-config] docs and the [Adding +Languages][adding-languages] guide for more language configuration information. {{#include ./generated/lang-support.md}} -[languages.toml]: https://github.com/helix-editor/helix/blob/master/languages.toml +[lsp-install-wiki]: https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers +[lang-config]: ./languages.md +[adding-languages]: ./guides/adding_languages.md diff --git a/languages.toml b/languages.toml index 13c34e010..b382b013c 100644 --- a/languages.toml +++ b/languages.toml @@ -1,3 +1,6 @@ +# Language support configuration. +# See the languages documentation: https://docs.helix-editor.com/master/languages.html + [[language]] name = "rust" scope = "source.rust" From 7cb6e07ba01e67685f9dd7e4de994c865dc64299 Mon Sep 17 00:00:00 2001 From: Aral Balkan Date: Mon, 11 Apr 2022 15:21:41 +0100 Subject: [PATCH 060/861] Improve Dracula Theme selections (#2075) (#2077) --- runtime/themes/dracula.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index 1db25d8f4..f77d151eb 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -29,8 +29,8 @@ "ui.menu" = { fg = "foreground", bg = "background_dark" } "ui.menu.selected" = { fg = "cyan", bg = "background_dark" } "ui.popup" = { fg = "foreground", bg = "background_dark" } -"ui.selection" = { fg = "background", bg = "purple", modifiers = ["dim"] } -"ui.selection.primary" = { fg = "background", bg = "pink" } +"ui.selection" = { bg = "secondary_highlight" } +"ui.selection.primary" = { bg = "primary_highlight" } "ui.statusline" = { fg = "foreground", bg = "background_dark" } "ui.statusline.inactive" = { fg = "comment", bg = "background_dark" } "ui.text" = { fg = "foreground" } @@ -52,6 +52,8 @@ [palette] background = "#282a36" background_dark = "#21222c" +primary_highlight = "#800049" +secondary_highlight = "#4d4f66" foreground = "#f8f8f2" comment = "#6272a4" red = "#ff5555" From f9ddc8a9acdc14c36bbb68ed3198feeed179ff78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 18:34:29 -0500 Subject: [PATCH 061/861] build(deps): bump actions/download-artifact from 2 to 3 (#2082) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eb36c7867..e11d159ff 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -104,7 +104,7 @@ jobs: uses: actions/checkout@v3 - name: Download grammars - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 - name: Move grammars under runtime if: "!startsWith(matrix.os, 'windows')" @@ -172,7 +172,7 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 - name: Calculate tag name run: | From 14079bd17b18296ef787e4a0304505992142b584 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 18:34:39 -0500 Subject: [PATCH 062/861] build(deps): bump cachix/install-nix-action from 16 to 17 (#2081) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/cachix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cachix.yml b/.github/workflows/cachix.yml index f820bc746..113f7fa1d 100644 --- a/.github/workflows/cachix.yml +++ b/.github/workflows/cachix.yml @@ -14,7 +14,7 @@ jobs: uses: actions/checkout@v3 - name: Install nix - uses: cachix/install-nix-action@v16 + uses: cachix/install-nix-action@v17 - name: Authenticate with Cachix uses: cachix/cachix-action@v10 From 6530d452a00e5868d924f7c22c8393a427eaf32a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Apr 2022 12:12:03 +0900 Subject: [PATCH 063/861] build(deps): bump encoding_rs from 0.8.30 to 0.8.31 (#2083) Bumps [encoding_rs](https://github.com/hsivonen/encoding_rs) from 0.8.30 to 0.8.31. - [Release notes](https://github.com/hsivonen/encoding_rs/releases) - [Commits](https://github.com/hsivonen/encoding_rs/compare/v0.8.30...v0.8.31) --- updated-dependencies: - dependency-name: encoding_rs dependency-type: direct:production update-type: version-update:semver-patch ... 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 e96a0636d..f2dc34c36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,9 +184,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "encoding_rs" -version = "0.8.30" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" dependencies = [ "cfg-if", ] From f3dcb4034fd528b620935780bcd5e86937c0b393 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Apr 2022 12:12:30 +0900 Subject: [PATCH 064/861] build(deps): bump lsp-types from 0.92.1 to 0.93.0 (#2084) Bumps [lsp-types](https://github.com/gluon-lang/lsp-types) from 0.92.1 to 0.93.0. - [Release notes](https://github.com/gluon-lang/lsp-types/releases) - [Changelog](https://github.com/gluon-lang/lsp-types/blob/master/CHANGELOG.md) - [Commits](https://github.com/gluon-lang/lsp-types/compare/v0.92.1...v0.93.0) --- updated-dependencies: - dependency-name: lsp-types dependency-type: direct:production update-type: version-update:semver-minor ... 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 f2dc34c36..4bbd4c252 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -606,9 +606,9 @@ dependencies = [ [[package]] name = "lsp-types" -version = "0.92.1" +version = "0.93.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79d4897790e8fd2550afa6d6125821edb5716e60e0e285046e070f0f6a06e0e" +checksum = "70c74e2173b2b31f8655d33724b4b45ac13f439386f66290f539c22b144c2212" dependencies = [ "bitflags", "serde", diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index 755f49b5c..da731a9f5 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -19,7 +19,7 @@ futures-executor = "0.3" futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false } jsonrpc-core = { version = "18.0", default-features = false } # don't pull in all of futures log = "0.4" -lsp-types = { version = "0.92", features = ["proposed"] } +lsp-types = { version = "0.93", features = ["proposed"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" From d5c086697896d87f034c1dbe0ae0ccbc71f37d2c Mon Sep 17 00:00:00 2001 From: unrelentingtech Date: Tue, 12 Apr 2022 10:48:30 +0300 Subject: [PATCH 065/861] Apply ui.gutter style to empty gutters (#2032) The unstyled column on the left from the diagnostics_or_breakpoints gutter looks sad if you want to add a background to all gutters. Let's fix this. --- helix-term/src/ui/editor.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 979b95d99..564605de4 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -471,14 +471,20 @@ impl EditorView { text.reserve(*width); // ensure there's enough space for the gutter for (i, line) in (view.offset.row..(last_line + 1)).enumerate() { let selected = cursors.contains(&line); + let x = viewport.x + offset; + let y = viewport.y + i as u16; if let Some(style) = gutter(line, selected, &mut text) { - surface.set_stringn( - viewport.x + offset, - viewport.y + i as u16, - &text, - *width, - gutter_style.patch(style), + surface.set_stringn(x, y, &text, *width, gutter_style.patch(style)); + } else { + surface.set_style( + Rect { + x, + y, + width: *width as u16, + height: 1, + }, + gutter_style, ); } text.clear(); From 660e0e44b2b6329c1d0af788d624dd5765c2acc6 Mon Sep 17 00:00:00 2001 From: Omnikar Date: Tue, 12 Apr 2022 03:52:54 -0400 Subject: [PATCH 066/861] Add `:write!` to create nonexistent subdirectories (#1839) * Make `:write` create nonexistent subdirectories Prompting as to whether this should take place remains a TODO. * Move subdirectory creation to new `w!` command --- book/src/generated/typable-cmd.md | 1 + helix-term/src/commands/typed.rs | 31 +++++++++++++++++++++++++------ helix-view/src/document.rs | 14 ++++++++++---- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index f9261a756..bb5da3bbe 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -12,6 +12,7 @@ | `:buffer-next`, `:bn`, `:bnext` | Go to next buffer. | | `:buffer-previous`, `:bp`, `:bprev` | Go to previous buffer. | | `:write`, `:w` | Write changes to disk. Accepts an optional path (:write some/path.txt) | +| `:write!`, `:w!` | Write changes to disk forcefully (creating necessary subdirectories). Accepts an optional path (:write some/path.txt) | | `:new`, `:n` | Create a new scratch buffer. | | `:format`, `:fmt` | Format the file using the LSP formatter. | | `:indent-style` | Set the indentation style for editing. ('t' for tabs or 1-8 for number of spaces.) | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 8f74adb62..d158388fc 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -190,7 +190,11 @@ fn buffer_previous( Ok(()) } -fn write_impl(cx: &mut compositor::Context, path: Option<&Cow>) -> anyhow::Result<()> { +fn write_impl( + cx: &mut compositor::Context, + path: Option<&Cow>, + force: bool, +) -> anyhow::Result<()> { let jobs = &mut cx.jobs; let doc = doc_mut!(cx.editor); @@ -212,7 +216,7 @@ fn write_impl(cx: &mut compositor::Context, path: Option<&Cow>) -> anyhow:: jobs.callback(callback); shared }); - let future = doc.format_and_save(fmt); + let future = doc.format_and_save(fmt, force); cx.jobs.add(Job::new(future).wait_before_exiting()); if path.is_some() { @@ -228,7 +232,15 @@ fn write( args: &[Cow], _event: PromptEvent, ) -> anyhow::Result<()> { - write_impl(cx, args.first()) + write_impl(cx, args.first(), false) +} + +fn force_write( + cx: &mut compositor::Context, + args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + write_impl(cx, args.first(), true) } fn new_file( @@ -381,7 +393,7 @@ fn write_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { - write_impl(cx, args.first())?; + write_impl(cx, args.first(), false)?; quit(cx, &[], event) } @@ -390,7 +402,7 @@ fn force_write_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { - write_impl(cx, args.first())?; + write_impl(cx, args.first(), true)?; force_quit(cx, &[], event) } @@ -447,7 +459,7 @@ fn write_all_impl( jobs.callback(callback); shared }); - let future = doc.format_and_save(fmt); + let future = doc.format_and_save(fmt, force); jobs.add(Job::new(future).wait_before_exiting()); } @@ -1140,6 +1152,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: write, completer: Some(completers::filename), }, + TypableCommand { + name: "write!", + aliases: &["w!"], + doc: "Write changes to disk forcefully (creating necessary subdirectories). Accepts an optional path (:write some/path.txt)", + fun: force_write, + completer: Some(completers::filename), + }, TypableCommand { name: "new", aliases: &["n"], diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 5d739af58..f4b4dc35f 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -434,15 +434,16 @@ impl Document { Some(fut) } - pub fn save(&mut self) -> impl Future> { - self.save_impl::>(None) + pub fn save(&mut self, force: bool) -> impl Future> { + self.save_impl::>(None, force) } pub fn format_and_save( &mut self, formatting: Option>, + force: bool, ) -> impl Future> { - self.save_impl(formatting) + self.save_impl(formatting, force) } // TODO: do we need some way of ensuring two save operations on the same doc can't run at once? @@ -454,6 +455,7 @@ impl Document { fn save_impl>( &mut self, formatting: Option, + force: bool, ) -> impl Future> { // we clone and move text + path into the future so that we asynchronously save the current // state without blocking any further edits. @@ -475,7 +477,11 @@ impl Document { if let Some(parent) = path.parent() { // TODO: display a prompt asking the user if the directories should be created if !parent.exists() { - bail!("can't save file, parent directory does not exist"); + if force { + std::fs::DirBuilder::new().recursive(true).create(parent)?; + } else { + bail!("can't save file, parent directory does not exist"); + } } } From 1fb614443292fe723e764782be560bb2ab3dda4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20M=C3=BCller?= Date: Tue, 12 Apr 2022 10:10:21 +0200 Subject: [PATCH 067/861] Add shell completion (#2022) * Add shell completion * Add shell completion to release --- .github/workflows/release.yml | 2 ++ contrib/completion/hx.bash | 23 +++++++++++++++++++++++ contrib/completion/hx.fish | 12 ++++++++++++ contrib/completion/hx.zsh | 29 +++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+) create mode 100644 contrib/completion/hx.bash create mode 100644 contrib/completion/hx.fish create mode 100644 contrib/completion/hx.zsh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e11d159ff..7c265db8c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -206,6 +206,8 @@ jobs: pkgname=helix-$TAG-$platform mkdir $pkgname cp $source/LICENSE $source/README.md $pkgname + mkdir $pkgname/contrib + cp -r $source/contrib/completion $pkgname/contrib mv bins-$platform/runtime $pkgname/ mv bins-$platform/hx$exe $pkgname chmod +x $pkgname/hx$exe diff --git a/contrib/completion/hx.bash b/contrib/completion/hx.bash new file mode 100644 index 000000000..6371bedb6 --- /dev/null +++ b/contrib/completion/hx.bash @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Bash completion script for Helix editor + +_hx() { + # $1 command name + # $2 word being completed + # $3 word preceding + COMPREPLY=() + + case "$3" in + -g | --grammar) + COMPREPLY=($(compgen -W "fetch build" -- $2)) + ;; + --health) + local languages=$(hx --health |tail -n '+7' |awk '{print $1}' |sed 's/\x1b\[[0-9;]*m//g') + COMPREPLY=($(compgen -W "$languages" -- $2)) + ;; + *) + COMPREPLY=($(compgen -fd -W "-h --help --tutor -V --version -v -vv -vvv --health -g --grammar" -- $2)) + ;; + esac +} && complete -F _hx hx + diff --git a/contrib/completion/hx.fish b/contrib/completion/hx.fish new file mode 100644 index 000000000..4ec690d8b --- /dev/null +++ b/contrib/completion/hx.fish @@ -0,0 +1,12 @@ +#!/usr/bin/env fish +# Fish completion script for Helix editor + +set -l langs (hx --health |tail -n '+7' |awk '{print $1}' |sed 's/\x1b\[[0-9;]*m//g') + +complete -c hx -s h -l help -d "Prints help information" +complete -c hx -l tutor -d "Loads the tutorial" +complete -c hx -l health -x -a "$langs" -d "Checks for errors in editor setup" +complete -c hx -s g -l grammar -x -a "fetch build" -d "Fetches or builds tree-sitter grammars" +complete -c hx -s v -o vv -o vvv -d "Increases logging verbosity" +complete -c hx -s V -l version -d "Prints version information" + diff --git a/contrib/completion/hx.zsh b/contrib/completion/hx.zsh new file mode 100644 index 000000000..16631519b --- /dev/null +++ b/contrib/completion/hx.zsh @@ -0,0 +1,29 @@ +#compdef _hx hx +# Zsh completion script for Helix editor + +_hx() { + _arguments -C \ + "-h[Prints help information]" \ + "--help[Prints help information]" \ + "-v[Increase logging verbosity]" \ + "-vv[Increase logging verbosity]" \ + "-vvv[Increase logging verbosity]" \ + "-V[Prints version information]" \ + "--version[Prints version information]" \ + "--tutor[Loads the tutorial]" \ + "--health[Checks for errors in editor setup]:language:->health" \ + "-g[Fetches or builds tree-sitter grammars]:action:->grammar" \ + "--grammar[Fetches or builds tree-sitter grammars]:action:->grammar" \ + "*:file:_files" + + case "$state" in + health) + local languages=($(hx --health |tail -n '+7' |awk '{print $1}' |sed 's/\x1b\[[0-9;]*m//g')) + _values 'language' $languages + ;; + grammar) + _values 'action' fetch build + ;; + esac +} + From 3deb1c92306877e4d99c45f20f61c17c5e980492 Mon Sep 17 00:00:00 2001 From: Nirmal Patel Date: Tue, 12 Apr 2022 04:21:16 -0400 Subject: [PATCH 068/861] Add true or false checkbox in health output table (#1947) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hx --health output table's second and third columns were not showing symbols like ✔ or ✘ to indicate whether LSP or DAP binaries were found. This change adds these symbols to improve accessibility. Fixes #1894 Signed-off-by: Nirmal Patel --- 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 7f582cbf5..bd74f4787 100644 --- a/helix-term/src/health.rs +++ b/helix-term/src/health.rs @@ -134,8 +134,8 @@ pub fn languages_all() -> std::io::Result<()> { let check_binary = |cmd: Option| match cmd { Some(cmd) => match which::which(&cmd) { - Ok(_) => column(&cmd, Color::Green), - Err(_) => column(&cmd, Color::Red), + Ok(_) => column(&format!("✔ {}", cmd), Color::Green), + Err(_) => column(&format!("✘ {}", cmd), Color::Red), }, None => column("None", Color::Yellow), }; From a0c6c45c1b5dc36f3c5151363d3f360bea388a99 Mon Sep 17 00:00:00 2001 From: Roland Kovacs Date: Wed, 13 Apr 2022 03:02:14 +0200 Subject: [PATCH 069/861] Fix panic when using set-language on a scratch (#1996) Skip launching a language server if a document doesn't have a valid URL. --- helix-view/src/editor.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index c4e9ec283..76fc67138 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -453,6 +453,9 @@ impl Editor { /// Launch a language server for a given document fn launch_language_server(ls: &mut helix_lsp::Registry, doc: &mut Document) -> Option<()> { + // if doc doesn't have a URL it's a scratch buffer, ignore it + let doc_url = doc.url()?; + // try to find a language server based on the language name let language_server = doc.language.as_ref().and_then(|language| { ls.get(language) @@ -476,7 +479,7 @@ impl Editor { // TODO: this now races with on_init code if the init happens too quickly tokio::spawn(language_server.text_document_did_open( - doc.url().unwrap(), + doc_url, doc.version(), doc.text(), language_id, From 62283fdadb762d77deaba7ff820fbdac0b2d3a3b Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Wed, 13 Apr 2022 09:02:53 +0800 Subject: [PATCH 070/861] Make textobject select last paragraph (#1992) * Make textobject select last paragraph Last paragraph shoud be selected if the cursor was placed on the whitespace paragraph part and `map` is done, otherwise it would do nothing useful, but now we select backwards for the last paragraph which behaves similarly to kakoune, making `map` useful for the last paragraph with whitespace. Example usecase is to copy and paste last ledger cli paragraph quickly by `mapyp` to duplicate last entry. * Fix typo in core textobject Co-authored-by: Michael Davis Co-authored-by: Michael Davis --- helix-core/src/textobject.rs | 39 +++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/helix-core/src/textobject.rs b/helix-core/src/textobject.rs index e7bbfc43e..ab418792c 100644 --- a/helix-core/src/textobject.rs +++ b/helix-core/src/textobject.rs @@ -132,9 +132,9 @@ pub fn textobject_paragraph( if prev_empty_to_line || curr_empty_to_line { line_back += 1; } - let mut lines = slice.lines_at(line_back); // do not include current paragraph on paragraph end (include next) if !(curr_empty_to_line && last_char) { + let mut lines = slice.lines_at(line_back); lines.reverse(); let mut lines = lines.map(rope_is_line_ending).peekable(); while lines.next_if(|&e| e).is_some() { @@ -150,25 +150,46 @@ pub fn textobject_paragraph( line += 1; } let mut lines = slice.lines_at(line).map(rope_is_line_ending).peekable(); - for _ in 0..count - 1 { + let mut count_done = 0; // count how many non-whitespace paragraphs done + for _ in 0..count { + let mut done = false; while lines.next_if(|&e| !e).is_some() { line += 1; + done = true; } while lines.next_if(|&e| e).is_some() { line += 1; } + count_done += done as usize; } - while lines.next_if(|&e| !e).is_some() { - line += 1; + + // search one paragraph backwards for last paragraph + // makes `map` at the end of the paragraph with trailing newlines useful + let last_paragraph = count_done != count && lines.peek().is_none(); + if last_paragraph { + let mut lines = slice.lines_at(line_back); + lines.reverse(); + let mut lines = lines.map(rope_is_line_ending).peekable(); + while lines.next_if(|&e| e).is_some() { + line_back -= 1; + } + while lines.next_if(|&e| !e).is_some() { + line_back -= 1; + } } + // handle last whitespaces part separately depending on textobject match textobject { - TextObject::Around => { + TextObject::Around => {} + TextObject::Inside => { + // remove last whitespace paragraph + let mut lines = slice.lines_at(line); + lines.reverse(); + let mut lines = lines.map(rope_is_line_ending).peekable(); while lines.next_if(|&e| e).is_some() { - line += 1; + line -= 1; } } - TextObject::Inside => {} TextObject::Movement => unreachable!(), } @@ -364,7 +385,7 @@ mod test { "second\n\n#[paragraph\n|]#\n", ), ("#[f|]#irst char\n\n", "#[first char\n|]#\n"), - ("last char\n#[\n|]#", "last char\n\n#[|]#"), + ("last char\n#[\n|]#", "#[last char\n|]#\n"), ( "empty to line\n#[\n|]#paragraph boundary\n\n", "empty to line\n\n#[paragraph boundary\n|]#\n", @@ -418,7 +439,7 @@ mod test { "second\n\n#[paragraph\n\n|]#", ), ("#[f|]#irst char\n\n", "#[first char\n\n|]#"), - ("last char\n#[\n|]#", "last char\n\n#[|]#"), + ("last char\n#[\n|]#", "#[last char\n\n|]#"), ( "empty to line\n#[\n|]#paragraph boundary\n\n", "empty to line\n\n#[paragraph boundary\n\n|]#", From 740f565c80a76ee499a93f2c1ccd6cc8388b7e63 Mon Sep 17 00:00:00 2001 From: scgtrp Date: Wed, 13 Apr 2022 00:00:17 -0400 Subject: [PATCH 071/861] Document values for editor.cursor-shape (#2094) These are hinted at in the example config at the top (except `none`), but really should be listed explicitly near the option itself for clarity. --- book/src/configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/book/src/configuration.md b/book/src/configuration.md index 9036b5018..dae46176b 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -55,6 +55,7 @@ hidden = false Defines the shape of cursor in each mode. Note that due to limitations of the terminal environment, only the primary cursor can change shape. +Valid values for these options are `block`, `bar`, `underline`, or `none`. | Key | Description | Default | | --- | ----------- | ------- | From 8c3c90198a43fd69e1e3e07a2e164db3fb11bb24 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 12 Apr 2022 20:38:01 -0500 Subject: [PATCH 072/861] update tree-sitter-elixir The new revision handles a case that I come across often: a stab clause (i.e. '->') with an empty right hand side: Enum.map(xs, fn x -> end) The old version would parse the "end" token as an error. This is technically valid syntax but more importantly it comes up very often when editing, and the old revision would flicker between the keyword highlight and the warning highlight. --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index b382b013c..e74088490 100644 --- a/languages.toml +++ b/languages.toml @@ -91,7 +91,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "elixir" -source = { git = "https://github.com/elixir-lang/tree-sitter-elixir", rev = "60863fc6e27d60cf4b1917499ed2259f92c7800e" } +source = { git = "https://github.com/elixir-lang/tree-sitter-elixir", rev = "1dabc1c790e07115175057863808085ea60dd08a" } [[language]] name = "fish" From 4ac94a5c431c8ddff38bba5061e66ed355c42747 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 12 Apr 2022 20:42:07 -0500 Subject: [PATCH 073/861] remove error highlighting for tree-sitter-elixir This will become more important with the HEEx grammar being added. Error highlighting with the Elixir grammar is a bit jumpy because in some scenarios, a bit of missing syntax can force tree-sitter to give up on error recovery and mark the entire tree as an error. This ends up looking bad when editing. We don't typically highlight error nodes so I'm inclined to leave it out of the highlights here. --- runtime/queries/elixir/highlights.scm | 2 -- 1 file changed, 2 deletions(-) diff --git a/runtime/queries/elixir/highlights.scm b/runtime/queries/elixir/highlights.scm index 4cfc0c242..6c0d1094b 100644 --- a/runtime/queries/elixir/highlights.scm +++ b/runtime/queries/elixir/highlights.scm @@ -217,5 +217,3 @@ "<<" ">>" ] @punctuation.bracket - -(ERROR) @warning From 9d095e0fdc78ad42c033193dd980b6218c9484d6 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 12 Apr 2022 20:55:30 -0500 Subject: [PATCH 074/861] add tree-sitter-eex EEx is an templating language for Elixir. Since the incremental parsing refactor we can used combined injections which allows us to add EEx support. --- book/src/generated/lang-support.md | 1 + languages.toml | 12 ++++++++++++ runtime/queries/eex/highlights.scm | 6 ++++++ runtime/queries/eex/injections.scm | 9 +++++++++ 4 files changed, 28 insertions(+) create mode 100644 runtime/queries/eex/highlights.scm create mode 100644 runtime/queries/eex/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index efafc3e58..a58c1595c 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -9,6 +9,7 @@ | css | ✓ | | | `vscode-css-language-server` | | dart | ✓ | | ✓ | `dart` | | dockerfile | ✓ | | | `docker-langserver` | +| eex | ✓ | | | | | ejs | ✓ | | | | | elixir | ✓ | | | `elixir-ls` | | elm | ✓ | | | `elm-language-server` | diff --git a/languages.toml b/languages.toml index e74088490..79738db10 100644 --- a/languages.toml +++ b/languages.toml @@ -1113,3 +1113,15 @@ grammar = "embedded-template" [[grammar]] name = "embedded-template" source = { git = "https://github.com/tree-sitter/tree-sitter-embedded-template", rev = "d21df11b0ecc6fd211dbe11278e92ef67bd17e97" } + +[[language]] +name = "eex" +scope = "source.eex" +injection-regex = "eex" +file-types = ["eex"] +roots = [] +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "eex" +source = { git = "https://github.com/connorlay/tree-sitter-eex", rev = "f742f2fe327463335e8671a87c0b9b396905d1d1" } diff --git a/runtime/queries/eex/highlights.scm b/runtime/queries/eex/highlights.scm new file mode 100644 index 000000000..e900a43dc --- /dev/null +++ b/runtime/queries/eex/highlights.scm @@ -0,0 +1,6 @@ +; https://github.com/connorlay/tree-sitter-eex/blob/f742f2fe327463335e8671a87c0b9b396905d1d1/queries/highlights.scm + +; wrapping in (directive .. ) prevents us from highlighting '%>' in a comment as a keyword +(directive ["<%" "<%=" "<%%" "<%%=" "%>"] @keyword) + +(comment) @comment diff --git a/runtime/queries/eex/injections.scm b/runtime/queries/eex/injections.scm new file mode 100644 index 000000000..4686bf4d5 --- /dev/null +++ b/runtime/queries/eex/injections.scm @@ -0,0 +1,9 @@ +; https://github.com/connorlay/tree-sitter-eex/blob/f742f2fe327463335e8671a87c0b9b396905d1d1/queries/injections.scm + +((directive (expression) @injection.content) + (#set! injection.language "elixir")) + +((partial_expression) @injection.content + (#set! injection.language "elixir") + (#set! injection.include-children) + (#set! injection.combined)) From 4836bb38d3c13c9f1ebd3533bc35a54f80c7e118 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 12 Apr 2022 20:57:07 -0500 Subject: [PATCH 075/861] add tree-sitter-heex HEEx is a templating engine on top of Elixir's EEx templating language specific to HTML that is included in Phoenix.LiveView (though I think the plan is to eventually include it in base Phoenix). It's a superset of EEx with some additional features like components and slots. The injections don't work perfectly because the Elixir grammar is newline sensitive (the _terminator rule). See https://github.com/elixir-lang/tree-sitter-elixir/issues/24 for more information. --- book/src/generated/lang-support.md | 1 + languages.toml | 12 ++++++ runtime/queries/elixir/injections.scm | 7 ++++ runtime/queries/heex/highlights.scm | 58 +++++++++++++++++++++++++++ runtime/queries/heex/injections.scm | 21 ++++++++++ 5 files changed, 99 insertions(+) create mode 100644 runtime/queries/heex/highlights.scm create mode 100644 runtime/queries/heex/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index a58c1595c..63f02d84f 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -26,6 +26,7 @@ | graphql | ✓ | | | | | haskell | ✓ | | | `haskell-language-server-wrapper` | | hcl | ✓ | | ✓ | `terraform-ls` | +| heex | ✓ | | | | | html | ✓ | | | `vscode-html-language-server` | | iex | ✓ | | | | | java | ✓ | | | | diff --git a/languages.toml b/languages.toml index 79738db10..7f2a17ab4 100644 --- a/languages.toml +++ b/languages.toml @@ -1125,3 +1125,15 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "eex" source = { git = "https://github.com/connorlay/tree-sitter-eex", rev = "f742f2fe327463335e8671a87c0b9b396905d1d1" } + +[[language]] +name = "heex" +scope = "source.heex" +injection-regex = "heex" +file-types = ["heex"] +roots = [] +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "heex" +source = { git = "https://github.com/connorlay/tree-sitter-heex", rev = "592e22292a367312c35e13de7fdb888f029981d6" } diff --git a/runtime/queries/elixir/injections.scm b/runtime/queries/elixir/injections.scm index 8370a0d8d..c88825344 100644 --- a/runtime/queries/elixir/injections.scm +++ b/runtime/queries/elixir/injections.scm @@ -7,3 +7,10 @@ (#match? @_sigil_name "^(r|R)$") (#set! injection.language "regex") (#set! injection.combined)) + +((sigil + (sigil_name) @_sigil_name + (quoted_content) @injection.content) + (#match? @_sigil_name "^(h|H)$") + (#set! injection.language "heex") + (#set! injection.combined)) diff --git a/runtime/queries/heex/highlights.scm b/runtime/queries/heex/highlights.scm new file mode 100644 index 000000000..301f57c84 --- /dev/null +++ b/runtime/queries/heex/highlights.scm @@ -0,0 +1,58 @@ +; https://github.com/connorlay/tree-sitter-heex/blob/592e22292a367312c35e13de7fdb888f029981d6/queries/highlights.scm +; HEEx delimiters +[ + "" + "" + "-->" + "/>" + "{" + "}" + ; These could be `@keyword`s but the closing `>` wouldn't be highlighted + ; as `@keyword` + "<:" + "" +] @keyword + +; HEEx operators are highlighted as such +"=" @operator + +; HEEx inherits the DOCTYPE tag from HTML +(doctype) @constant + +; HEEx comments are highlighted as such +(comment) @comment + +; HEEx tags are highlighted as HTML +(tag_name) @tag + +; HEEx slots are highlighted as atoms (symbols) +(slot_name) @string.special.symbol + +; HEEx attributes are highlighted as HTML attributes +(attribute_name) @attribute +[ + (attribute_value) + (quoted_attribute_value) +] @string + +; HEEx components are highlighted as Elixir modules and functions +(component_name + [ + (module) @module + (function) @function + "." @punctuation.delimiter + ]) diff --git a/runtime/queries/heex/injections.scm b/runtime/queries/heex/injections.scm new file mode 100644 index 000000000..ad4e4faa8 --- /dev/null +++ b/runtime/queries/heex/injections.scm @@ -0,0 +1,21 @@ +; https://github.com/connorlay/tree-sitter-heex/blob/592e22292a367312c35e13de7fdb888f029981d6/queries/injections.scm +; directives are standalone tags like '<%= @x %>' +; +; partial_expression_values are elixir code that is part of an expression that +; spans multiple directive nodes, so they must be combined. For example: +; <%= if true do %> +;

hello, tree-sitter!

+; <% end %> +((directive (partial_expression_value) @injection.content) + (#set! injection.language "elixir") + (#set! injection.include-children) + (#set! injection.combined)) + +; Regular expression_values do not need to be combined +((directive (expression_value) @injection.content) + (#set! injection.language "elixir")) + +; expressions live within HTML tags, and do not need to be combined +; +((expression (expression_value) @injection.content) + (#set! injection.language "elixir")) From 764adbdcf6f0a5615d1ddd3abb7ed7b9cf0f2d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Wed, 13 Apr 2022 15:17:44 +0900 Subject: [PATCH 076/861] fix: prompt: pass through unmapped keys regardless of modifiers Ctrl + Alt is apparently another common sequence for AltGr: https://devblogs.microsoft.com/oldnewthing/20040329-00/?p=40003 Fixes #595 Fixes #2080 --- helix-term/src/ui/prompt.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 4daa33e54..bd78ba632 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -2,7 +2,7 @@ use crate::compositor::{Component, Compositor, Context, EventResult}; use crate::{alt, ctrl, key, shift, ui}; use crossterm::event::Event; use helix_view::input::KeyEvent; -use helix_view::keyboard::{KeyCode, KeyModifiers}; +use helix_view::keyboard::KeyCode; use std::{borrow::Cow, ops::RangeFrom}; use tui::buffer::Buffer as Surface; use tui::widgets::{Block, Borders, Widget}; @@ -529,11 +529,11 @@ impl Component for Prompt { (self.callback_fn)(cx, &self.line, PromptEvent::Update) } ctrl!('q') => self.exit_selection(), - // any char event that's not combined with control or mapped to any other combo + // any char event that's not mapped to any other combo KeyEvent { code: KeyCode::Char(c), - modifiers, - } if !modifiers.contains(KeyModifiers::CONTROL) => { + modifiers: _, + } => { self.insert_char(c, cx); (self.callback_fn)(cx, &self.line, PromptEvent::Update); } From 460e6a857b44a2492c5c8888a3985ec413393300 Mon Sep 17 00:00:00 2001 From: Jared Ramirez Date: Thu, 14 Apr 2022 11:26:20 -0700 Subject: [PATCH 077/861] feat(languages): SQL (#2097) --- book/src/generated/lang-support.md | 1 + languages.toml | 13 +++ runtime/queries/sql/highlights.scm | 165 +++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 runtime/queries/sql/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 63f02d84f..79716d17c 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -64,6 +64,7 @@ | rust | ✓ | ✓ | ✓ | `rust-analyzer` | | scala | ✓ | | ✓ | `metals` | | solidity | ✓ | | | `solc` | +| sql | ✓ | | | | | svelte | ✓ | | ✓ | `svelteserver` | | swift | ✓ | | | `sourcekit-lsp` | | tablegen | ✓ | ✓ | ✓ | | diff --git a/languages.toml b/languages.toml index 7f2a17ab4..d3a21c2d0 100644 --- a/languages.toml +++ b/languages.toml @@ -1137,3 +1137,16 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "heex" source = { git = "https://github.com/connorlay/tree-sitter-heex", rev = "592e22292a367312c35e13de7fdb888f029981d6" } + +[[language]] +name = "sql" +scope = "source.sql" +file-types = ["sql"] +roots = [] +comment-token = "--" +indent = { tab-width = 4, unit = " " } +injection-regex = "sql" + +[[grammar]] +name = "sql" +source = { git = "https://github.com/DerekStride/tree-sitter-sql", rev = "0caa7fa2ee00e0b770493a79d4efacc1fc376cc5" } diff --git a/runtime/queries/sql/highlights.scm b/runtime/queries/sql/highlights.scm new file mode 100644 index 000000000..5025352e7 --- /dev/null +++ b/runtime/queries/sql/highlights.scm @@ -0,0 +1,165 @@ +(comment) @comment + +[ + "(" + ")" +] @punctuation.bracket + +[ + "*" + "+" + "-" + "/" + "%" + "^" + "||" + "=" + "<" + "<=" + "!=" + ">=" + ">" +] @operator + +[ + (keyword_null) + (keyword_true) + (keyword_false) +] @constant.builtin + +(literal) @string + +(set_schema schema: (identifier) @namespace) +(table_reference schema: (identifier) @namespace) +(table_expression schema: (identifier) @namespace) +(all_fields schema: (identifier) @namespace) +(field schema: (identifier) @namespace) + +[ + (keyword_select) + (keyword_delete) + (keyword_insert) + (keyword_replace) + (keyword_update) + (keyword_into) + (keyword_values) + (keyword_set) + (keyword_from) + (keyword_left) + (keyword_right) + (keyword_inner) + (keyword_outer) + (keyword_cross) + (keyword_join) + (keyword_lateral) + (keyword_on) + (keyword_not) + (keyword_order_by) + (keyword_group_by) + (keyword_having) + (keyword_desc) + (keyword_asc) + (keyword_limit) + (keyword_offset) + (keyword_primary) + (keyword_create) + (keyword_alter) + (keyword_drop) + (keyword_add) + (keyword_table) + (keyword_view) + (keyword_materialized) + (keyword_column) + (keyword_key) + (keyword_as) + (keyword_distinct) + (keyword_constraint) + ; (keyword_count) + (keyword_max) + (keyword_min) + (keyword_avg) + (keyword_end) + (keyword_force) + (keyword_using) + (keyword_use) + (keyword_index) + (keyword_for) + (keyword_if) + (keyword_exists) + (keyword_auto_increment) + (keyword_default) + (keyword_cascade) + (keyword_with) + (keyword_no) + (keyword_data) + (keyword_type) + (keyword_rename) + (keyword_to) + (keyword_schema) + (keyword_owner) + (keyword_temp) + (keyword_temporary) + (keyword_union) + (keyword_all) + (keyword_except) + (keyword_intersect) + (keyword_returning) + (keyword_begin) + (keyword_commit) + (keyword_rollback) + (keyword_transaction) +] @keyword + +[ + (keyword_case) + (keyword_when) + (keyword_then) + (keyword_else) + (keyword_where) +] @keyword.control.conditional + +[ + (keyword_in) + (keyword_and) + (keyword_or) + (keyword_is) +] @keyword.operator + +[ + (keyword_boolean) + (keyword_smallserial) + (keyword_serial) + (keyword_bigserial) + (keyword_smallint) + (keyword_int) + + (bigint) + (decimal) + (numeric) + (keyword_real) + (double) + + (keyword_money) + + (char) + (varchar) + (keyword_text) + + (keyword_uuid) + + (keyword_json) + (keyword_jsonb) + (keyword_xml) + + (keyword_bytea) + + (keyword_date) + (keyword_datetime) + (keyword_timestamp) + (keyword_timestamptz) + + (keyword_geometry) + (keyword_geography) + (keyword_box2d) + (keyword_box3d) +] @type.builtin From 893963df0ad8596034522cd18570517f823d7123 Mon Sep 17 00:00:00 2001 From: nosa <96927121+n0s4@users.noreply.github.com> Date: Fri, 15 Apr 2022 01:58:16 +0100 Subject: [PATCH 078/861] Additions to 'themes' section of docs (#2098) * Added more descriptions to the themes part of the docs * Add more descriptions to themes section of the docs * capitalised first letters of descriptions in docs Co-authored-by: Joe Mckay --- book/src/themes.md | 56 +++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/book/src/themes.md b/book/src/themes.md index 219b0ee3e..e23dbb692 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -205,32 +205,32 @@ These scopes are used for theming the editor interface. - `hover` - for hover popup ui -| Key | Notes | -| --- | --- | -| `ui.background` | | -| `ui.cursor` | | -| `ui.cursor.insert` | | -| `ui.cursor.select` | | -| `ui.cursor.match` | Matching bracket etc. | -| `ui.cursor.primary` | Cursor with primary selection | -| `ui.linenr` | | -| `ui.linenr.selected` | | -| `ui.statusline` | Statusline | -| `ui.statusline.inactive` | Statusline (unfocused document) | -| `ui.popup` | | -| `ui.popup.info` | | -| `ui.window` | | -| `ui.help` | | -| `ui.text` | | -| `ui.text.focus` | | -| `ui.text.info` | | -| `ui.menu` | | -| `ui.menu.selected` | | -| `ui.selection` | For selections in the editing area | -| `ui.selection.primary` | | -| `warning` | Diagnostics warning (gutter) | -| `error` | Diagnostics error (gutter) | -| `info` | Diagnostics info (gutter) | -| `hint` | Diagnostics hint (gutter) | -| `diagnostic` | For text in editing area | +| Key | Notes | +| --- | --- | +| `ui.background` | | +| `ui.cursor` | | +| `ui.cursor.insert` | | +| `ui.cursor.select` | | +| `ui.cursor.match` | Matching bracket etc. | +| `ui.cursor.primary` | Cursor with primary selection | +| `ui.linenr` | Line numbers | +| `ui.linenr.selected` | Line number for the line the cursor is on | +| `ui.statusline` | Statusline | +| `ui.statusline.inactive` | Statusline (unfocused document) | +| `ui.popup` | Documentation popups (e.g space-k) | +| `ui.popup.info` | Prompt for multiple key options | +| `ui.window` | Border lines separating splits | +| `ui.help` | Description box for commands | +| `ui.text` | Command prompts, popup text, etc. | +| `ui.text.focus` | | +| `ui.text.info` | The key: command text in `ui.popup.info` boxes | +| `ui.menu` | Code and command completion menus | +| `ui.menu.selected` | Selected autocomplete item | +| `ui.selection` | For selections in the editing area | +| `ui.selection.primary` | | +| `warning` | Diagnostics warning (gutter) | +| `error` | Diagnostics error (gutter) | +| `info` | Diagnostics info (gutter) | +| `hint` | Diagnostics hint (gutter) | +| `diagnostic` | For text in editing area | From 50df92481103ec4b2d2549eebc0dcbae73ed8a20 Mon Sep 17 00:00:00 2001 From: EmmChriss <42001129+EmmChriss@users.noreply.github.com> Date: Fri, 15 Apr 2022 18:35:23 +0300 Subject: [PATCH 079/861] gdscript support (#1985) --- book/src/generated/lang-support.md | 1 + languages.toml | 15 ++++ runtime/queries/gdscript/highlights.scm | 93 +++++++++++++++++++++++++ runtime/queries/gdscript/indents.scm | 26 +++++++ runtime/queries/gdscript/tags.scm | 5 ++ 5 files changed, 140 insertions(+) create mode 100644 runtime/queries/gdscript/highlights.scm create mode 100644 runtime/queries/gdscript/indents.scm create mode 100644 runtime/queries/gdscript/tags.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 79716d17c..776febdfc 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -16,6 +16,7 @@ | erb | ✓ | | | | | erlang | ✓ | | | `erlang_ls` | | fish | ✓ | ✓ | ✓ | | +| gdscript | ✓ | | ✓ | | | git-commit | ✓ | | | | | git-config | ✓ | | | | | git-diff | ✓ | | | | diff --git a/languages.toml b/languages.toml index d3a21c2d0..d5409eaaf 100644 --- a/languages.toml +++ b/languages.toml @@ -1150,3 +1150,18 @@ injection-regex = "sql" [[grammar]] name = "sql" source = { git = "https://github.com/DerekStride/tree-sitter-sql", rev = "0caa7fa2ee00e0b770493a79d4efacc1fc376cc5" } + +[[language]] +name = "gdscript" +scope = "source.gdscript" +injection-regex = "gdscript" +file-types = ["gd"] +shebangs = [] +roots = ["project.godot"] +auto-format = true +comment-token = "#" +indent = { tab-width = 4, unit = " " } + +[[grammar]] +name = "gdscript" +source = { git = "https://github.com/PrestonKnopp/tree-sitter-gdscript", rev = "2a6abdaa47fcb91397e09a97c7433fd995ea46c6" } diff --git a/runtime/queries/gdscript/highlights.scm b/runtime/queries/gdscript/highlights.scm new file mode 100644 index 000000000..0849eedb0 --- /dev/null +++ b/runtime/queries/gdscript/highlights.scm @@ -0,0 +1,93 @@ +; Identifier naming conventions + +((identifier) @constant + (#match? @constant "^[A-Z][A-Z_]*$")) + +; Function calls + +(attribute_call (identifier) @function) + +(base_call (identifier) @function) + +(call (identifier) @function) + +; Function definitions + +(function_definition (name) @function) + +(constructor_definition "_init" @function) + +;; Literals +(integer) @constant.numeric.integer +(float) @constant.numeric.float +(comment) @comment +(string) @string +(escape_sequence) @constant.character.escape +(identifier) @variable +(type) @type + +;; Literals +[ + (true) + (false) + (null) +] @constant.builtin + +[ + "+" + "-" + "*" + "/" + "%" + "==" + "!=" + ">" + "<" + ">=" + "<=" + "=" + "+=" + "-=" + "*=" + "/=" + "%=" + "&" + "|" + "^" + "~" + "<<" + ">>" + "and" + "or" + "not" +] @operator + +[ + (static_keyword) + (remote_keyword) + (tool_statement) + "var" + "func" + "setget" + "in" + "is" + "as" + "if" + "else" + "elif" + "while" + "for" + "return" + "break" + "continue" + "pass" + "match" + "class" + "class_name" + "enum" + "signal" + "onready" + "export" + "extends" + "const" +] @keyword diff --git a/runtime/queries/gdscript/indents.scm b/runtime/queries/gdscript/indents.scm new file mode 100644 index 000000000..01439e1c6 --- /dev/null +++ b/runtime/queries/gdscript/indents.scm @@ -0,0 +1,26 @@ +[ + (_compound_statement) + (match_statement) + (parenthesized_expression) + + (pattern_array) + (pattern_dictionary) + (argument_list) + (binary_operator) + + (parameters) + (body) + (enumerator_list) + + (function_definition) + (constructor_definition) + (class_definition) +] @indent + +[ + ")", + "]", + "}", + (return_statement) + (pass_statement) +] @outdent diff --git a/runtime/queries/gdscript/tags.scm b/runtime/queries/gdscript/tags.scm new file mode 100644 index 000000000..05796fdf2 --- /dev/null +++ b/runtime/queries/gdscript/tags.scm @@ -0,0 +1,5 @@ +(class_definition (name) @name) @definition.class + +(function_definition (name) @name) @definition.function + +(call (name) @name) @reference.call \ No newline at end of file From 450f348925ff1a2a39b73481f61af6fc7e57ebef Mon Sep 17 00:00:00 2001 From: Evan Lecklider Date: Fri, 15 Apr 2022 10:15:17 -0700 Subject: [PATCH 080/861] Add make file-type "mk" to languages.toml (#2120) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index d5409eaaf..70baabaf5 100644 --- a/languages.toml +++ b/languages.toml @@ -676,7 +676,7 @@ source = { git = "https://github.com/uyha/tree-sitter-cmake", rev = "f6616f1e417 [[language]] name = "make" scope = "source.make" -file-types = ["Makefile", "makefile", "justfile", ".justfile"] +file-types = ["Makefile", "makefile", "mk", "justfile", ".justfile"] roots =[] comment-token = "#" indent = { tab-width = 4, unit = "\t" } From b04c425c63d03f8320eb47ab6e38e4bb79763248 Mon Sep 17 00:00:00 2001 From: "Dr. David A. Kunz" Date: Sat, 16 Apr 2022 03:41:25 +0200 Subject: [PATCH 081/861] Make gutters configurable (#1967) * config option line numbers none * view tests * added tests * doc * comment * Make gutters configurable * docu * docu * rm none docu * order * order * precedence * simpler * rm todo * fixed clippy * order * double quotes * only allow diagnostics and line-numbers * tests * docu * format * rm short variant and more docu * performance improvements * typo * rename --- book/src/configuration.md | 1 + helix-term/src/ui/editor.rs | 2 +- helix-view/src/editor.rs | 28 ++++++++++++- helix-view/src/gutter.rs | 2 +- helix-view/src/tree.rs | 21 ++++++++-- helix-view/src/view.rs | 81 +++++++++++++++++++++++++++++-------- 6 files changed, 110 insertions(+), 25 deletions(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index dae46176b..3ec2bedb9 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -37,6 +37,7 @@ hidden = false | `scroll-lines` | Number of lines to scroll per scroll wheel step. | `3` | | `shell` | Shell to use when running external commands. | Unix: `["sh", "-c"]`
Windows: `["cmd", "/C"]` | | `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` | +| `gutters` | Gutters to display: Available are `diagnostics` and `line-numbers`, note that `diagnostics` also includes other features like breakpoints | `["diagnostics", "line-numbers"]` | | `auto-completion` | Enable automatic pop up of auto-completion. | `true` | | `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant. | `400` | | `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` | diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 564605de4..459a8c876 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -466,7 +466,7 @@ impl EditorView { // avoid lots of small allocations by reusing a text buffer for each line let mut text = String::with_capacity(8); - for (constructor, width) in view.gutters() { + for (constructor, width) in &view.gutters { let gutter = constructor(editor, doc, view, theme, is_focused, *width); 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-view/src/editor.rs b/helix-view/src/editor.rs index 76fc67138..dd805c000 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -117,6 +117,8 @@ pub struct Config { pub shell: Vec, /// Line number mode. pub line_number: LineNumber, + /// Gutters. Default ["diagnostics", "line-numbers"] + pub gutters: Vec, /// Middle click paste support. Defaults to true. pub middle_click_paste: bool, /// Automatic insertion of pairs to parentheses, brackets, @@ -238,6 +240,27 @@ impl std::str::FromStr for LineNumber { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GutterType { + /// Show diagnostics and other features like breakpoints + Diagnostics, + /// Show line numbers + LineNumbers, +} + +impl std::str::FromStr for GutterType { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "diagnostics" => Ok(Self::Diagnostics), + "line-numbers" => Ok(Self::LineNumbers), + _ => anyhow::bail!("Gutter type can only be `diagnostics` or `line-numbers`."), + } + } +} + impl Default for Config { fn default() -> Self { Self { @@ -250,6 +273,7 @@ impl Default for Config { vec!["sh".to_owned(), "-c".to_owned()] }, line_number: LineNumber::Absolute, + gutters: vec![GutterType::Diagnostics, GutterType::LineNumbers], middle_click_paste: true, auto_pairs: AutoPairConfig::default(), auto_completion: true, @@ -579,7 +603,7 @@ impl Editor { return; } Action::HorizontalSplit | Action::VerticalSplit => { - let view = View::new(id); + let view = View::new(id, self.config().gutters.clone()); let view_id = self.tree.split( view, match action { @@ -701,7 +725,7 @@ impl Editor { .map(|(&doc_id, _)| doc_id) .next() .unwrap_or_else(|| self.new_document(Document::default())); - let view = View::new(doc_id); + let view = View::new(doc_id, self.config().gutters.clone()); let view_id = self.tree.insert(view); let doc = self.documents.get_mut(&doc_id).unwrap(); doc.selections.insert(view_id, Selection::point(0)); diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 7327ed1a2..06ce1b2e7 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -39,7 +39,7 @@ pub fn diagnostic<'doc>( }) } -pub fn line_number<'doc>( +pub fn line_numbers<'doc>( editor: &'doc Editor, doc: &'doc Document, view: &View, diff --git a/helix-view/src/tree.rs b/helix-view/src/tree.rs index 99cbe0f90..b068f4c7e 100644 --- a/helix-view/src/tree.rs +++ b/helix-view/src/tree.rs @@ -568,6 +568,7 @@ impl<'a> Iterator for Traverse<'a> { #[cfg(test)] mod test { use super::*; + use crate::editor::GutterType; use crate::DocumentId; #[test] @@ -578,22 +579,34 @@ mod test { width: 180, height: 80, }); - let mut view = View::new(DocumentId::default()); + let mut view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); view.area = Rect::new(0, 0, 180, 80); tree.insert(view); let l0 = tree.focus; - let view = View::new(DocumentId::default()); + let view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); tree.split(view, Layout::Vertical); let r0 = tree.focus; tree.focus = l0; - let view = View::new(DocumentId::default()); + let view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); tree.split(view, Layout::Horizontal); let l1 = tree.focus; tree.focus = l0; - let view = View::new(DocumentId::default()); + let view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); tree.split(view, Layout::Vertical); let l2 = tree.focus; diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index c6ae0c56e..7cf88c2e1 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -11,6 +11,8 @@ use helix_core::{ visual_coords_at_pos, Position, RopeSlice, Selection, }; +use std::fmt; + type Jump = (DocumentId, Selection); #[derive(Debug, Clone)] @@ -64,17 +66,11 @@ impl JumpList { } } -const GUTTERS: &[(Gutter, usize)] = &[ - (gutter::diagnostics_or_breakpoints, 1), - (gutter::line_number, 5), -]; - -#[derive(Debug)] pub struct View { pub id: ViewId, - pub doc: DocumentId, pub offset: Position, pub area: Rect, + pub doc: DocumentId, pub jumps: JumpList, /// the last accessed file before the current one pub last_accessed_doc: Option, @@ -85,10 +81,29 @@ pub struct View { pub last_modified_docs: [Option; 2], /// used to store previous selections of tree-sitter objecs pub object_selections: Vec, + pub gutters: Vec<(Gutter, usize)>, +} + +impl fmt::Debug for View { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("View") + .field("id", &self.id) + .field("area", &self.area) + .field("doc", &self.doc) + .finish() + } } impl View { - pub fn new(doc: DocumentId) -> Self { + pub fn new(doc: DocumentId, gutter_types: Vec) -> Self { + let mut gutters: Vec<(Gutter, usize)> = vec![]; + use crate::editor::GutterType; + for gutter_type in &gutter_types { + match gutter_type { + GutterType::Diagnostics => gutters.push((gutter::diagnostics_or_breakpoints, 1)), + GutterType::LineNumbers => gutters.push((gutter::line_numbers, 5)), + } + } Self { id: ViewId::default(), doc, @@ -98,17 +113,14 @@ impl View { last_accessed_doc: None, last_modified_docs: [None, None], object_selections: Vec::new(), + gutters, } } - pub fn gutters(&self) -> &[(Gutter, usize)] { - GUTTERS - } - pub fn inner_area(&self) -> Rect { // TODO: cache this let offset = self - .gutters() + .gutters .iter() .map(|(_, width)| *width as u16) .sum::() @@ -324,11 +336,16 @@ mod tests { use super::*; use helix_core::Rope; const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter - // const OFFSET: u16 = GUTTERS.iter().map(|(_, width)| *width as u16).sum(); + const OFFSET_WITHOUT_LINE_NUMBERS: u16 = 2; // 1 diagnostic + 1 gutter + // const OFFSET: u16 = GUTTERS.iter().map(|(_, width)| *width as u16).sum(); + use crate::editor::GutterType; #[test] fn test_text_pos_at_screen_coords() { - let mut view = View::new(DocumentId::default()); + let mut view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("abc\n\tdef"); let text = rope.slice(..); @@ -372,9 +389,36 @@ mod tests { assert_eq!(view.text_pos_at_screen_coords(&text, 41, 80, 4), Some(8)); } + #[test] + fn test_text_pos_at_screen_coords_without_line_numbers_gutter() { + let mut view = View::new(DocumentId::default(), vec![GutterType::Diagnostics]); + view.area = Rect::new(40, 40, 40, 40); + let rope = Rope::from_str("abc\n\tdef"); + let text = rope.slice(..); + assert_eq!( + view.text_pos_at_screen_coords(&text, 41, 40 + OFFSET_WITHOUT_LINE_NUMBERS + 1, 4), + Some(4) + ); + } + + #[test] + fn test_text_pos_at_screen_coords_without_any_gutters() { + let mut view = View::new(DocumentId::default(), vec![]); + view.area = Rect::new(40, 40, 40, 40); + let rope = Rope::from_str("abc\n\tdef"); + let text = rope.slice(..); + assert_eq!( + view.text_pos_at_screen_coords(&text, 41, 40 + 1, 4), + Some(4) + ); + } + #[test] fn test_text_pos_at_screen_coords_cjk() { - let mut view = View::new(DocumentId::default()); + let mut view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("Hi! こんにちは皆さん"); let text = rope.slice(..); @@ -411,7 +455,10 @@ mod tests { #[test] fn test_text_pos_at_screen_coords_graphemes() { - let mut view = View::new(DocumentId::default()); + let mut view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("Hèl̀l̀ò world!"); let text = rope.slice(..); From dc8fef5dd311e239150dfcd62c90cc84ee32a8a0 Mon Sep 17 00:00:00 2001 From: Andrey Tkachenko Date: Sat, 16 Apr 2022 05:43:54 +0400 Subject: [PATCH 082/861] Fixes #1991 LSP Auto-import (#2088) --- helix-lsp/src/client.rs | 7 +++++++ helix-term/src/ui/completion.rs | 14 +++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 8b14b0b87..14918818d 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -293,6 +293,13 @@ impl Client { completion: Some(lsp::CompletionClientCapabilities { completion_item: Some(lsp::CompletionItemCapability { snippet_support: Some(false), + resolve_support: Some(lsp::CompletionItemCapabilityResolveSupport { + properties: vec![ + String::from("documentation"), + String::from("detail"), + String::from("additionalTextEdits"), + ], + }), ..Default::default() }), completion_item_kind: Some(lsp::CompletionItemKindCapability { diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index 1ee4a01a9..556273bc5 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -178,17 +178,21 @@ impl Completion { }); // apply additional edits, mostly used to auto import unqualified types - let resolved_additional_text_edits = if item.additional_text_edits.is_some() { + let resolved_item = if item + .additional_text_edits + .as_ref() + .map(|edits| !edits.is_empty()) + .unwrap_or(false) + { None } else { Self::resolve_completion_item(doc, item.clone()) - .and_then(|item| item.additional_text_edits) }; - if let Some(additional_edits) = item - .additional_text_edits + if let Some(additional_edits) = resolved_item .as_ref() - .or(resolved_additional_text_edits.as_ref()) + .and_then(|item| item.additional_text_edits.as_ref()) + .or(item.additional_text_edits.as_ref()) { if !additional_edits.is_empty() { let transaction = util::generate_transaction_from_edits( From 2eca2901f31083af85ffd6f299c64ad80a8bfaf5 Mon Sep 17 00:00:00 2001 From: Thomas <74479846+DeviousStoat@users.noreply.github.com> Date: Sun, 17 Apr 2022 05:03:47 +0200 Subject: [PATCH 083/861] Pipe typable command (#1972) Co-authored-by: DeviousStoat --- book/src/generated/typable-cmd.md | 1 + helix-term/src/commands.rs | 94 ++++++++++++++++--------------- helix-term/src/commands/typed.rs | 17 ++++++ 3 files changed, 67 insertions(+), 45 deletions(-) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index bb5da3bbe..0b591ba4a 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -61,3 +61,4 @@ | `:tree-sitter-subtree`, `:ts-subtree` | Display tree sitter subtree under cursor, primarily for debugging queries. | | `:config-reload` | Refreshes helix's config. | | `:config-open` | Open the helix config.toml file. | +| `:pipe` | Pipe each selection to the shell command. | diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 886ee62df..90226c537 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4150,19 +4150,19 @@ enum ShellBehavior { } fn shell_pipe(cx: &mut Context) { - shell(cx, "pipe:".into(), ShellBehavior::Replace); + shell_prompt(cx, "pipe:".into(), ShellBehavior::Replace); } fn shell_pipe_to(cx: &mut Context) { - shell(cx, "pipe-to:".into(), ShellBehavior::Ignore); + shell_prompt(cx, "pipe-to:".into(), ShellBehavior::Ignore); } fn shell_insert_output(cx: &mut Context) { - shell(cx, "insert-output:".into(), ShellBehavior::Insert); + shell_prompt(cx, "insert-output:".into(), ShellBehavior::Insert); } fn shell_append_output(cx: &mut Context) { - shell(cx, "append-output:".into(), ShellBehavior::Append); + shell_prompt(cx, "append-output:".into(), ShellBehavior::Append); } fn shell_keep_pipe(cx: &mut Context) { @@ -4256,65 +4256,69 @@ fn shell_impl( Ok((tendril, output.status.success())) } -fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) { +fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) { let pipe = match behavior { ShellBehavior::Replace | ShellBehavior::Ignore => true, ShellBehavior::Insert | ShellBehavior::Append => false, }; + let config = cx.editor.config(); + let shell = &config.shell; + let (view, doc) = current!(cx.editor); + let selection = doc.selection(view.id); + + let mut changes = Vec::with_capacity(selection.len()); + let text = doc.text().slice(..); + + for range in selection.ranges() { + let fragment = range.fragment(text); + let (output, success) = match shell_impl(shell, cmd, pipe.then(|| fragment.as_bytes())) { + Ok(result) => result, + Err(err) => { + cx.editor.set_error(err.to_string()); + return; + } + }; + + if !success { + cx.editor.set_error("Command failed"); + return; + } + + let (from, to) = match behavior { + ShellBehavior::Replace => (range.from(), range.to()), + ShellBehavior::Insert => (range.from(), range.from()), + ShellBehavior::Append => (range.to(), range.to()), + _ => (range.from(), range.from()), + }; + changes.push((from, to, Some(output))); + } + + if behavior != &ShellBehavior::Ignore { + let transaction = Transaction::change(doc.text(), changes.into_iter()); + doc.apply(&transaction, view.id); + } + + // after replace cursor may be out of bounds, do this to + // make sure cursor is in view and update scroll as well + view.ensure_cursor_in_view(doc, config.scrolloff); +} + +fn shell_prompt(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) { ui::prompt( cx, prompt, Some('|'), ui::completers::none, move |cx, input: &str, event: PromptEvent| { - let config = cx.editor.config(); - let shell = &config.shell; if event != PromptEvent::Validate { return; } if input.is_empty() { return; } - let (view, doc) = current!(cx.editor); - let selection = doc.selection(view.id); - - let mut changes = Vec::with_capacity(selection.len()); - let text = doc.text().slice(..); - - for range in selection.ranges() { - let fragment = range.fragment(text); - let (output, success) = - match shell_impl(shell, input, pipe.then(|| fragment.as_bytes())) { - Ok(result) => result, - Err(err) => { - cx.editor.set_error(err.to_string()); - return; - } - }; - - if !success { - cx.editor.set_error("Command failed"); - return; - } - - let (from, to) = match behavior { - ShellBehavior::Replace => (range.from(), range.to()), - ShellBehavior::Insert => (range.from(), range.from()), - ShellBehavior::Append => (range.to(), range.to()), - _ => (range.from(), range.from()), - }; - changes.push((from, to, Some(output))); - } - - if behavior != ShellBehavior::Ignore { - let transaction = Transaction::change(doc.text(), changes.into_iter()); - doc.apply(&transaction, view.id); - } - // after replace cursor may be out of bounds, do this to - // make sure cursor is in view and update scroll as well - view.ensure_cursor_in_view(doc, config.scrolloff); + shell(cx, input, &behavior); }, ); } diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index d158388fc..9a5298bba 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1067,6 +1067,16 @@ fn refresh_config( Ok(()) } +fn pipe( + cx: &mut compositor::Context, + args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + ensure!(!args.is_empty(), "Shell command required"); + shell(cx, &args.join(" "), &ShellBehavior::Replace); + Ok(()) +} + pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "quit", @@ -1495,6 +1505,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: open_config, completer: None, }, + TypableCommand { + name: "pipe", + aliases: &[], + doc: "Pipe each selection to the shell command.", + fun: pipe, + completer: None, + }, ]; pub static TYPABLE_COMMAND_MAP: Lazy> = From 33b7483db53684cdd0a36f873662f8d6ff163201 Mon Sep 17 00:00:00 2001 From: Robin Jadoul Date: Sun, 17 Apr 2022 05:05:23 +0200 Subject: [PATCH 084/861] Send active diagnostics to LSP when requesting code actions. (#2005) * Send active diagnostics to LSP when requesting code actions. This allows for e.g. clangd to properly send the quickfix code actions corresponding to those diagnostics as options. The LSP spec v3.16.0 introduced an opaque `data` member that would allow the server to persist arbitrary data between the diagnostic and the code actions request, but this is not supported yet by this commit. * Reuse existing range_to_lsp_range functionality --- helix-lsp/src/client.rs | 3 ++- helix-lsp/src/lib.rs | 30 ++++++++++++++++++++++++++++++ helix-term/src/commands/lsp.rs | 30 ++++++++++++++++++++++-------- 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 14918818d..dba134fc3 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -842,11 +842,12 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, range: lsp::Range, + context: lsp::CodeActionContext, ) -> impl Future> { let params = lsp::CodeActionParams { text_document, range, - context: lsp::CodeActionContext::default(), + context, work_done_progress_params: lsp::WorkDoneProgressParams::default(), partial_result_params: lsp::PartialResultParams::default(), }; diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 767481367..13ac32ff9 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -58,6 +58,36 @@ pub mod util { use super::*; use helix_core::{Range, Rope, Transaction}; + /// Converts a diagnostic in the document to [`lsp::Diagnostic`]. + /// + /// Panics when [`pos_to_lsp_pos`] would for an invalid range on the diagnostic. + pub fn diagnostic_to_lsp_diagnostic( + doc: &Rope, + diag: &helix_core::diagnostic::Diagnostic, + offset_encoding: OffsetEncoding, + ) -> lsp::Diagnostic { + use helix_core::diagnostic::Severity::*; + + let range = Range::new(diag.range.start, diag.range.end); + let severity = diag.severity.map(|s| match s { + Hint => lsp::DiagnosticSeverity::HINT, + Info => lsp::DiagnosticSeverity::INFORMATION, + Warning => lsp::DiagnosticSeverity::WARNING, + Error => lsp::DiagnosticSeverity::ERROR, + }); + + // TODO: add support for Diagnostic.data + lsp::Diagnostic::new( + range_to_lsp_range(doc, range, offset_encoding), + severity, + None, + None, + diag.message.to_owned(), + None, + None, + ) + } + /// Converts [`lsp::Position`] to a position in the document. /// /// Returns `None` if position exceeds document length or an operation overflows. diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 1db57ecf2..0a12ae392 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -1,6 +1,6 @@ use helix_lsp::{ block_on, lsp, - util::{lsp_pos_to_pos, lsp_range_to_range, range_to_lsp_range}, + util::{diagnostic_to_lsp_diagnostic, lsp_pos_to_pos, lsp_range_to_range, range_to_lsp_range}, OffsetEncoding, }; @@ -192,15 +192,29 @@ pub fn code_action(cx: &mut Context) { let language_server = language_server!(cx.editor, doc); - let range = range_to_lsp_range( - doc.text(), - doc.selection(view.id).primary(), - language_server.offset_encoding(), - ); - - let future = language_server.code_actions(doc.identifier(), range); + let selection_range = doc.selection(view.id).primary(); let offset_encoding = language_server.offset_encoding(); + let range = range_to_lsp_range(doc.text(), selection_range, offset_encoding); + + let future = language_server.code_actions( + doc.identifier(), + range, + // Filter and convert overlapping diagnostics + lsp::CodeActionContext { + diagnostics: doc + .diagnostics() + .iter() + .filter(|&diag| { + selection_range + .overlaps(&helix_core::Range::new(diag.range.start, diag.range.end)) + }) + .map(|diag| diagnostic_to_lsp_diagnostic(doc.text(), diag, offset_encoding)) + .collect(), + only: None, + }, + ); + cx.callback( future, move |editor, compositor, response: Option| { From b67e0616dd45089b6ffbfe6f416598638bb8d7eb Mon Sep 17 00:00:00 2001 From: AntonioLucibello <65395340+AntonioLucibello@users.noreply.github.com> Date: Sun, 17 Apr 2022 05:26:14 +0200 Subject: [PATCH 085/861] Add command to extend selection to line above (#2117) * added command to extend selection to line above * fixed view not scrolling up when reaching top of the screen * refactored shared code into separate impl --- helix-term/src/commands.rs | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 90226c537..15ccc247b 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -247,6 +247,7 @@ impl MappableCommand { search_selection, "Use current selection as search pattern", global_search, "Global Search in workspace folder", extend_line, "Select current line, if already selected, extend to next line", + extend_line_above, "Select current line, if already selected, extend to previous line", extend_to_line_bounds, "Extend selection to line bounds (line-wise selection)", delete_selection, "Delete selection", delete_selection_noyank, "Delete selection, without yanking", @@ -1854,7 +1855,20 @@ fn global_search(cx: &mut Context) { cx.jobs.callback(show_picker); } +enum Extend { + Above, + Below, +} + fn extend_line(cx: &mut Context) { + extend_line_impl(cx, Extend::Below); +} + +fn extend_line_above(cx: &mut Context) { + extend_line_impl(cx, Extend::Above); +} + +fn extend_line_impl(cx: &mut Context, extend: Extend) { let count = cx.count(); let (view, doc) = current!(cx.editor); @@ -1863,13 +1877,22 @@ fn extend_line(cx: &mut Context) { let (start_line, end_line) = range.line_range(text.slice(..)); let start = text.line_to_char(start_line); - let mut end = text.line_to_char((end_line + count).min(text.len_lines())); + let end = text.line_to_char((end_line + count).min(text.len_lines())); + + // extend to previous/next line if current line is selected + let (anchor, head) = if range.from() == start && range.to() == end { + match extend { + Extend::Above => (end, text.line_to_char(start_line.saturating_sub(1))), + Extend::Below => ( + start, + text.line_to_char((end_line + count + 1).min(text.len_lines())), + ), + } + } else { + (start, end) + }; - // go to next line if current line is selected - if range.from() == start && range.to() == end { - end = text.line_to_char((end_line + count + 1).min(text.len_lines())); - } - Range::new(start, end) + Range::new(anchor, head) }); doc.set_selection(view.id, selection); From c45fb08a9389e21d9694059819aed940ba446a0b Mon Sep 17 00:00:00 2001 From: Terry Brash Date: Sun, 17 Apr 2022 02:14:55 -0400 Subject: [PATCH 086/861] Add JavaScript control keywords (#2140) --- runtime/queries/javascript/highlights.scm | 35 ++++++++++++----------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/runtime/queries/javascript/highlights.scm b/runtime/queries/javascript/highlights.scm index 6163b680d..2616dffa1 100644 --- a/runtime/queries/javascript/highlights.scm +++ b/runtime/queries/javascript/highlights.scm @@ -163,43 +163,46 @@ [ "as" "async" - "await" - "break" - "case" - "catch" "class" "const" - "continue" "debugger" - "default" "delete" - "do" - "else" "export" "extends" - "finally" - "for" "from" "function" "get" - "if" "import" "in" "instanceof" "let" "new" "of" - "return" "set" "static" - "switch" "target" - "throw" "try" "typeof" "var" "void" - "while" "with" - "yield" ] @keyword + +[ + "switch" + "case" + "default" + "if" + "else" + "yield" + "throw" + "finally" + "return" + "catch" + "continue" + "while" + "break" + "for" + "do" + "await" +] @keyword.control From ad36a024da4dae0cc096cae8ab83740507bc8d8a Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 17 Apr 2022 12:46:22 -0500 Subject: [PATCH 087/861] Update tree-sitters Erlang and HEEx (#2149) --- languages.toml | 2 +- runtime/queries/erlang/highlights.scm | 26 +++++++++++++------------- runtime/queries/heex/highlights.scm | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/languages.toml b/languages.toml index 70baabaf5..fd14fc573 100644 --- a/languages.toml +++ b/languages.toml @@ -974,7 +974,7 @@ language-server = { command = "erlang_ls" } [[grammar]] name = "erlang" -source = { git = "https://github.com/the-mikedavis/tree-sitter-erlang", rev = "1e81393b8f0a81b35ff1679a9420fafbd2cf3511" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-erlang", rev = "3f611cfdc790214c3f9f9cf1658b3ae8039c54b8" } [[language]] name = "kotlin" diff --git a/runtime/queries/erlang/highlights.scm b/runtime/queries/erlang/highlights.scm index 067e0f82c..1e0753497 100644 --- a/runtime/queries/erlang/highlights.scm +++ b/runtime/queries/erlang/highlights.scm @@ -46,10 +46,16 @@ ]) (#eq? @keyword "define")) +(attribute + name: (atom) @keyword + (arguments + (_) @keyword.directive) + (#match? @keyword "ifn?def")) + (attribute name: (atom) @keyword module: (atom) @module - (#eq? @keyword "spec")) + (#eq? @keyword "(spec|callback)")) ; Functions (function name: (atom) @function) @@ -69,10 +75,7 @@ (record name: (atom) @type) ; Keywords -((attribute name: (atom) @keyword) - (#match? - @keyword - "^(define|export|export_type|include|include_lib|ifdef|ifndef|if|elif|else|endif|vsn|on_load|behaviour|record|file|type|opaque|spec)$")) +(attribute name: (atom) @keyword) ["case" "fun" "if" "of" "when" "end" "receive" "try" "catch" "after" "begin" "maybe"] @keyword @@ -86,10 +89,6 @@ (unary_operator operator: _ @operator) ["/" ":" "#" "->"] @operator -; Comments -((variable) @comment.discard - (#match? @comment.discard "^_")) - (tripledot) @comment.discard (comment) @comment @@ -99,12 +98,13 @@ "?"+ @keyword.directive name: (_) @keyword.directive) +; Comments +((variable) @comment.discard + (#match? @comment.discard "^_")) + ; Basic types (variable) @variable -[ - (atom) - (quoted_atom) -] @string.special.symbol +(atom) @string.special.symbol (string) @string (character) @constant.character diff --git a/runtime/queries/heex/highlights.scm b/runtime/queries/heex/highlights.scm index 301f57c84..d63853b5c 100644 --- a/runtime/queries/heex/highlights.scm +++ b/runtime/queries/heex/highlights.scm @@ -11,8 +11,6 @@ "--%>" "-->" "/>" - "{" - "}" ; These could be `@keyword`s but the closing `>` wouldn't be highlighted ; as `@keyword` "<:" @@ -21,6 +19,8 @@ ; Non-comment or tag delimiters [ + "{" + "}" "<%" "<%=" "<%%=" From be656c14e32243fc32ed68f9a3240301f2902df7 Mon Sep 17 00:00:00 2001 From: Danillo Melo Date: Sun, 17 Apr 2022 21:25:44 -0300 Subject: [PATCH 088/861] Ruby TextObjects and more file extensions (#2143) --- book/src/generated/lang-support.md | 2 +- languages.toml | 2 +- runtime/queries/ruby/textobjects.scm | 54 ++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 runtime/queries/ruby/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 776febdfc..55b928622 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -61,7 +61,7 @@ | rescript | ✓ | ✓ | | `rescript-language-server` | | rmarkdown | ✓ | | ✓ | `R` | | ron | ✓ | | ✓ | | -| ruby | ✓ | | ✓ | `solargraph` | +| ruby | ✓ | ✓ | ✓ | `solargraph` | | rust | ✓ | ✓ | ✓ | `rust-analyzer` | | scala | ✓ | | ✓ | `metals` | | solidity | ✓ | | | `solc` | diff --git a/languages.toml b/languages.toml index fd14fc573..6e78e78a5 100644 --- a/languages.toml +++ b/languages.toml @@ -399,7 +399,7 @@ source = { git = "https://github.com/cstrahan/tree-sitter-nix", rev = "50f38ceab name = "ruby" scope = "source.ruby" injection-regex = "ruby" -file-types = ["rb"] +file-types = ["rb", "rake", "rakefile", "irb", "gemfile", "gemspec"] shebangs = ["ruby"] roots = [] comment-token = "#" diff --git a/runtime/queries/ruby/textobjects.scm b/runtime/queries/ruby/textobjects.scm new file mode 100644 index 000000000..34888c17d --- /dev/null +++ b/runtime/queries/ruby/textobjects.scm @@ -0,0 +1,54 @@ +; Class +(class) @class.around + +(class [(constant) (scope_resolution)] !superclass + (_)+ @class.inside) + +(class [(constant) (scope_resolution)] (superclass) + (_)+ @class.inside) + +(singleton_class + value: (_) + (_)+ @class.inside) @class.around + +(call + receiver: (constant) @class_const + method: (identifier) @class_method + (#match? @class_const "Class") + (#match? @class_method "new") + (do_block (_)+ @class.inside)) @class.around + +; Functions +(method) @function.around + +(method (identifier) (method_parameters) + (_)+ @function.inside) + +(do_block !parameters + (_)+ @function.inside) + +(do_block (block_parameters) + (_)+ @function.inside) + +(block (block_parameters) + (_)+ @function.inside) + +(block !parameters + (_)+ @function.inside) + +(method (identifier) !parameters + (_)+ @function.inside) + +; Parameters +(method_parameters + (_) @parameter.inside) + +(block_parameters + (_) @parameter.inside) + +(lambda_parameters + (_) @parameter.inside) + +; Comments +(comment) @comment.inside +(comment)+ @comment.around From c2a40d9d5229c701fa1a6d0fb80ce4ba86e8dc0c Mon Sep 17 00:00:00 2001 From: Kirawi <67773714+kirawi@users.noreply.github.com> Date: Sun, 17 Apr 2022 23:10:51 -0400 Subject: [PATCH 089/861] Add support for local language configuration (#1249) * add local configuration * move config loading to Application::new * simplify find_root_impl --- Cargo.lock | 1 + book/src/languages.md | 2 ++ helix-core/src/config.rs | 4 +-- helix-core/src/lib.rs | 38 ++----------------------- helix-loader/Cargo.toml | 2 ++ helix-loader/src/config.rs | 26 +++++++++++++++++ helix-loader/src/grammar.rs | 2 +- helix-loader/src/lib.rs | 53 ++++++++++++++++++++++++----------- helix-term/src/application.rs | 33 +++++++++++++++++----- helix-term/src/main.rs | 30 ++------------------ 10 files changed, 102 insertions(+), 89 deletions(-) create mode 100644 helix-loader/src/config.rs diff --git a/Cargo.lock b/Cargo.lock index 4bbd4c252..61346d451 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -404,6 +404,7 @@ dependencies = [ "cc", "etcetera", "libloading", + "log", "once_cell", "serde", "threadpool", diff --git a/book/src/languages.md b/book/src/languages.md index 3372a1202..1fa247879 100644 --- a/book/src/languages.md +++ b/book/src/languages.md @@ -2,6 +2,8 @@ Language-specific settings and settings for particular language servers can be configured in a `languages.toml` file placed in your [configuration directory](./configuration.md). Helix actually uses two `languages.toml` files, the [first one](https://github.com/helix-editor/helix/blob/master/languages.toml) is in the main helix repository; it contains the default settings for each language and is included in the helix binary at compile time. Users who want to see the available settings and options can either reference the helix repo's `languages.toml` file, or consult the table in the [adding languages](./guides/adding_languages.md) section. +A local `languages.toml` can be created within a `.helix` directory. Its settings will be merged with both the global and default configs. + Changes made to the `languages.toml` file in a user's [configuration directory](./configuration.md) are merged with helix's defaults on start-up, such that a user's settings will take precedence over defaults in the event of a collision. For example, the default `languages.toml` sets rust's `auto-format` to `true`. If a user wants to disable auto-format, they can change the `languages.toml` in their [configuration directory](./configuration.md) to make the rust entry read like the example below; the new key/value pair `auto-format = false` will override the default when the two sets of settings are merged on start-up: ```toml diff --git a/helix-core/src/config.rs b/helix-core/src/config.rs index f399850e6..2076fc224 100644 --- a/helix-core/src/config.rs +++ b/helix-core/src/config.rs @@ -1,10 +1,10 @@ /// Syntax configuration loader based on built-in languages.toml. pub fn default_syntax_loader() -> crate::syntax::Configuration { - helix_loader::default_lang_config() + helix_loader::config::default_lang_config() .try_into() .expect("Could not serialize built-in languages.toml") } /// Syntax configuration loader based on user configured languages.toml. pub fn user_syntax_loader() -> Result { - helix_loader::user_lang_config()?.try_into() + helix_loader::config::user_lang_config()?.try_into() } diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 0ae68f914..023412657 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -46,41 +46,9 @@ pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option { /// * Top-most folder containing a root marker if not git repository detected /// * Current working directory as fallback pub fn find_root(root: Option<&str>, root_markers: &[String]) -> Option { - let current_dir = std::env::current_dir().expect("unable to determine current directory"); - - let root = match root { - Some(root) => { - let root = std::path::Path::new(root); - if root.is_absolute() { - root.to_path_buf() - } else { - current_dir.join(root) - } - } - None => current_dir.clone(), - }; - - let mut top_marker = None; - for ancestor in root.ancestors() { - for marker in root_markers { - if ancestor.join(marker).exists() { - top_marker = Some(ancestor); - break; - } - } - // don't go higher than repo - if ancestor.join(".git").is_dir() { - // Use workspace if detected from marker - return Some(top_marker.unwrap_or(ancestor).to_path_buf()); - } - } - - // In absence of git repo, use workspace if detected - if top_marker.is_some() { - top_marker.map(|a| a.to_path_buf()) - } else { - Some(current_dir) - } + helix_loader::find_root_impl(root, root_markers) + .first() + .cloned() } pub use ropey::{Rope, RopeBuilder, RopeSlice}; diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index 21b37333a..607d1a0ad 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -18,6 +18,8 @@ tree-sitter = "0.20" libloading = "0.7" once_cell = "1.9" +log = "0.4" + # cloning/compiling tree-sitter grammars cc = { version = "1" } threadpool = { version = "1.0" } diff --git a/helix-loader/src/config.rs b/helix-loader/src/config.rs new file mode 100644 index 000000000..3d71baede --- /dev/null +++ b/helix-loader/src/config.rs @@ -0,0 +1,26 @@ +/// Default bultin-in languages.toml. +pub fn default_lang_config() -> toml::Value { + toml::from_slice(include_bytes!("../../languages.toml")) + .expect("Could not parse bultin-in languages.toml to valid toml") +} + +/// User configured languages.toml file, merged with the default config. +pub fn user_lang_config() -> Result { + let config = crate::local_config_dirs() + .into_iter() + .chain([crate::config_dir()].into_iter()) + .map(|path| path.join("languages.toml")) + .filter_map(|file| { + std::fs::read(&file) + .map(|config| toml::from_slice(&config)) + .ok() + }) + .collect::, _>>()? + .into_iter() + .chain([default_lang_config()].into_iter()) + .fold(toml::Value::Table(toml::value::Table::default()), |a, b| { + crate::merge_toml_values(b, a) + }); + + Ok(config) +} diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index 7474713a5..9d63a2bed 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -92,7 +92,7 @@ pub fn build_grammars() -> Result<()> { // merged. The `grammar_selection` key of the config is then used to filter // down all grammars into a subset of the user's choosing. fn get_grammar_configs() -> Result> { - let config: Configuration = crate::user_lang_config() + let config: Configuration = crate::config::user_lang_config() .context("Could not parse languages.toml")? .try_into()?; diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index a2c4d96f0..de2951f8e 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -1,3 +1,4 @@ +pub mod config; pub mod grammar; use etcetera::base_strategy::{choose_base_strategy, BaseStrategy}; @@ -36,6 +37,15 @@ pub fn config_dir() -> std::path::PathBuf { path } +pub fn local_config_dirs() -> Vec { + let directories = find_root_impl(None, &[".helix".to_string()]) + .into_iter() + .map(|path| path.join(".helix")) + .collect(); + log::debug!("Located configuration folders: {:?}", directories); + directories +} + pub fn cache_dir() -> std::path::PathBuf { // TODO: allow env var override let strategy = choose_base_strategy().expect("Unable to find the config directory!"); @@ -56,25 +66,36 @@ pub fn log_file() -> std::path::PathBuf { cache_dir().join("helix.log") } -/// Default bultin-in languages.toml. -pub fn default_lang_config() -> toml::Value { - toml::from_slice(include_bytes!("../../languages.toml")) - .expect("Could not parse bultin-in languages.toml to valid toml") -} - -/// User configured languages.toml file, merged with the default config. -pub fn user_lang_config() -> Result { - let def_lang_conf = default_lang_config(); - let data = std::fs::read(crate::config_dir().join("languages.toml")); - let user_lang_conf = match data { - Ok(raw) => { - let value = toml::from_slice(&raw)?; - merge_toml_values(def_lang_conf, value) +pub fn find_root_impl(root: Option<&str>, root_markers: &[String]) -> Vec { + let current_dir = std::env::current_dir().expect("unable to determine current directory"); + let mut directories = Vec::new(); + + let root = match root { + Some(root) => { + let root = std::path::Path::new(root); + if root.is_absolute() { + root.to_path_buf() + } else { + current_dir.join(root) + } } - Err(_) => def_lang_conf, + None => current_dir, }; - Ok(user_lang_conf) + for ancestor in root.ancestors() { + // don't go higher than repo + if ancestor.join(".git").is_dir() { + // Use workspace if detected from marker + directories.push(ancestor.to_path_buf()); + break; + } else if root_markers + .iter() + .any(|marker| ancestor.join(marker).exists()) + { + directories.push(ancestor.to_path_buf()); + } + } + directories } // right overrides left diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index bc5f3bd77..7733c2c6f 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -56,15 +56,33 @@ pub struct Application { } impl Application { - pub fn new(args: Args, config: Config) -> Result { + pub fn new(args: Args) -> Result { use helix_view::editor::Action; - let mut compositor = Compositor::new()?; - let size = compositor.size(); - let conf_dir = helix_loader::config_dir(); + let config_dir = helix_loader::config_dir(); + if !config_dir.exists() { + std::fs::create_dir_all(&config_dir).ok(); + } - let theme_loader = - std::sync::Arc::new(theme::Loader::new(&conf_dir, &helix_loader::runtime_dir())); + let config = match std::fs::read_to_string(config_dir.join("config.toml")) { + Ok(config) => toml::from_str(&config) + .map(crate::keymap::merge_keys) + .unwrap_or_else(|err| { + eprintln!("Bad config: {}", err); + eprintln!("Press to continue with default config"); + use std::io::Read; + // This waits for an enter press. + let _ = std::io::stdin().read(&mut []); + Config::default() + }), + Err(err) if err.kind() == std::io::ErrorKind::NotFound => Config::default(), + Err(err) => return Err(Error::new(err)), + }; + + let theme_loader = std::sync::Arc::new(theme::Loader::new( + &config_dir, + &helix_loader::runtime_dir(), + )); let true_color = config.editor.true_color || crate::true_color(); let theme = config @@ -98,9 +116,10 @@ impl Application { }); let syn_loader = std::sync::Arc::new(syntax::Loader::new(syn_loader_conf)); + let mut compositor = Compositor::new()?; let config = Arc::new(ArcSwap::from_pointee(config)); let mut editor = Editor::new( - size, + compositor.size(), theme_loader.clone(), syn_loader.clone(), Box::new(Map::new(Arc::clone(&config), |config: &Config| { diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index 4a3434d1f..58a901316 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -1,7 +1,6 @@ -use anyhow::{Context, Error, Result}; +use anyhow::{Context, Result}; use helix_term::application::Application; use helix_term::args::Args; -use helix_term::config::{Config, ConfigLoadError}; use std::path::PathBuf; fn setup_logging(logpath: PathBuf, verbosity: u64) -> Result<()> { @@ -109,35 +108,10 @@ FLAGS: return Ok(0); } - let conf_dir = helix_loader::config_dir(); - if !conf_dir.exists() { - std::fs::create_dir_all(&conf_dir).ok(); - } - - let config = match Config::load_default() { - Ok(config) => config, - Err(err) => { - match err { - ConfigLoadError::BadConfig(err) => { - eprintln!("Bad config: {}", err); - eprintln!("Press to continue with default config"); - use std::io::Read; - // This waits for an enter press. - let _ = std::io::stdin().read(&mut []); - Config::default() - } - ConfigLoadError::Error(err) if err.kind() == std::io::ErrorKind::NotFound => { - Config::default() - } - ConfigLoadError::Error(err) => return Err(Error::new(err)), - } - } - }; - setup_logging(logpath, args.verbosity).context("failed to initialize logging")?; // TODO: use the thread local executor to spawn the application task separately from the work pool - let mut app = Application::new(args, config).context("unable to create new application")?; + let mut app = Application::new(args).context("unable to create new application")?; let exit_code = app.run().await?; From 2bddec02e7a810b1d73c6179e3ad708dd59ea5a9 Mon Sep 17 00:00:00 2001 From: Ben Lee-Cohen Date: Mon, 18 Apr 2022 00:12:47 -0400 Subject: [PATCH 090/861] Fixing (in two ways) a small typo (#2156) --- helix-loader/src/config.rs | 4 ++-- runtime/queries/fish/highlights.scm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/helix-loader/src/config.rs b/helix-loader/src/config.rs index 3d71baede..5dc2d6b67 100644 --- a/helix-loader/src/config.rs +++ b/helix-loader/src/config.rs @@ -1,7 +1,7 @@ -/// Default bultin-in languages.toml. +/// Default built-in languages.toml. pub fn default_lang_config() -> toml::Value { toml::from_slice(include_bytes!("../../languages.toml")) - .expect("Could not parse bultin-in languages.toml to valid toml") + .expect("Could not parse built-in languages.toml to valid toml") } /// User configured languages.toml file, merged with the default config. diff --git a/runtime/queries/fish/highlights.scm b/runtime/queries/fish/highlights.scm index def539319..4235cdd62 100644 --- a/runtime/queries/fish/highlights.scm +++ b/runtime/queries/fish/highlights.scm @@ -101,7 +101,7 @@ ] ) -; non-bultin command names +; non-builtin command names (command name: (word) @function) ; derived from builtin -n (fish 3.2.2) From 4b1fe367faa4d64f3823d3fee1f70762a4334e29 Mon Sep 17 00:00:00 2001 From: Lucy <11927498+lucypero@users.noreply.github.com> Date: Mon, 18 Apr 2022 07:22:26 -0300 Subject: [PATCH 091/861] Remove dim attribute in onedark ui.linenr (#2155) --- runtime/themes/onedark.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/onedark.toml b/runtime/themes/onedark.toml index acdaf99c8..1a3da452b 100644 --- a/runtime/themes/onedark.toml +++ b/runtime/themes/onedark.toml @@ -55,7 +55,7 @@ diagnostic = { modifiers = ["underlined"] } "ui.selection" = { bg = "light-gray" } "ui.selection.primary" = { bg = "gray" } -"ui.linenr" = { fg = "linenr", modifiers = ["dim"] } +"ui.linenr" = { fg = "linenr" } "ui.linenr.selected" = { fg = "white" } "ui.statusline" = { fg = "white", bg = "light-black" } From 449d1dfdfbf56ace564182dc85802e57b8494975 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 18 Apr 2022 10:11:28 -0500 Subject: [PATCH 092/861] prevent panic when receiving malformed LSP PublishDiagnostic (#2160) Instead of panicing we can discard the malformed diagnostic. This `.parse()` fails commonly when a non-conformant language server gives a diagnostic with a location that breaks the spec: { "character": 0, "line": -1 } can currently be returned by ElixirLS and the python LS. Other messages in this block are discarded but this one feels special enough to log. --- helix-lsp/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 13ac32ff9..47a376bb8 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -276,7 +276,13 @@ impl Notification { lsp::notification::PublishDiagnostics::METHOD => { let params: lsp::PublishDiagnosticsParams = params .parse() - .expect("Failed to parse PublishDiagnostics params"); + .map_err(|err| { + log::error!( + "received malformed PublishDiagnostic from Language Server: {}", + err + ) + }) + .ok()?; // TODO: need to loop over diagnostics and distinguish them by URI Self::PublishDiagnostics(params) From 4e877de54d4ad79cf5dafca6642f63ee1a8d5ae4 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 18 Apr 2022 10:14:48 -0500 Subject: [PATCH 093/861] Fix Golang textobject queries (#2153) * log textobject query construction errors The current behavior is that invalid queries are discarded silently which makes it difficult to debug invalid textobjects (either invalid syntax or an update may have come through that changed the valid set of nodes). * fix golang textobject query `method_spec_list` used to be a named node but was removed (I think for Helix, it was when updated to pull in the support for generics). Instead of a named node for the list of method specs we have a bunch of `method_spec` children nodes now. We can match on the set of them with a `+` wildcard. Example go for this query: type Shape interface { area() float64 perimeter() float64 } Which is parsed as: (source_file (type_declaration (type_spec name: (type_identifier) type: (interface_type (method_spec name: (field_identifier) parameters: (parameter_list) result: (type_identifier)) (method_spec name: (field_identifier) parameters: (parameter_list) result: (type_identifier)))))) --- helix-core/src/syntax.rs | 4 +++- runtime/queries/go/textobjects.scm | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 72b0e9562..905b33474 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -413,7 +413,9 @@ impl LanguageConfiguration { let lang_name = self.language_id.to_ascii_lowercase(); let query_text = read_query(&lang_name, "textobjects.scm"); let lang = self.highlight_config.get()?.as_ref()?.language; - let query = Query::new(lang, &query_text).ok()?; + let query = Query::new(lang, &query_text) + .map_err(|e| log::error!("Failed to parse textobjects.scm queries: {}", e)) + .ok()?; Some(TextObjectQuery { query }) }) .as_ref() diff --git a/runtime/queries/go/textobjects.scm b/runtime/queries/go/textobjects.scm index d77e14b71..3cdf62037 100644 --- a/runtime/queries/go/textobjects.scm +++ b/runtime/queries/go/textobjects.scm @@ -12,7 +12,7 @@ (type_spec (type_identifier) (struct_type (field_declaration_list (_)?) @class.inside))) @class.around (type_declaration - (type_spec (type_identifier) (interface_type (method_spec_list (_)?) @class.inside))) @class.around + (type_spec (type_identifier) (interface_type (method_spec)+ @class.inside))) @class.around (parameter_list (_) @parameter.inside) From 015a582d44a802bd1b983c88d737a7c290f87b22 Mon Sep 17 00:00:00 2001 From: Paul Graydon <43348144+paulgraydon@users.noreply.github.com> Date: Mon, 18 Apr 2022 16:20:19 +0000 Subject: [PATCH 094/861] Add tokyonight theme (#2162) --- runtime/themes/tokyonight.toml | 81 ++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 runtime/themes/tokyonight.toml diff --git a/runtime/themes/tokyonight.toml b/runtime/themes/tokyonight.toml new file mode 100644 index 000000000..19d805a82 --- /dev/null +++ b/runtime/themes/tokyonight.toml @@ -0,0 +1,81 @@ +# Author: Paul Graydon + +"comment" = { fg = "comment", modifiers = ["italic"] } +"constant" = { fg = "orange" } +"constant.character.escape" = { fg = "magenta" } +"function" = { fg = "blue", modifiers = ["italic"] } +"keyword" = { fg = "magenta" } +"keyword.control.import" = { fg = "cyan" } +"operator" = { fg = "turquoise" } +"punctuation" = { fg = "turquoise" } +"string" = { fg = "light-green" } +"string.regexp" = { fg = "light-blue" } +"tag" = { fg = "red" } +"type" = { fg = "teal" } +"namespace" = { fg = "blue" } +"variable" = { fg = "white" } +"variable.builtin" = { fg = "red", modifiers = ["italic"] } +"variable.other.member" = { fg = "magenta" } +"variable.parameter" = { fg = "yellow", modifiers = ["italic"] } + +"diff.plus" = { fg = "green" } +"diff.delta" = { fg = "orange" } +"diff.minus" = { fg = "red" } + +"ui.background" = { fg = "foreground", bg = "background" } +"ui.cursor" = { modifiers = ["reversed"] } +"ui.cursor.match" = { fg = "orange", modifiers = ["bold"] } +"ui.cursor.primary" = { modifiers = ["reversed"] } +"ui.help" = { fg = "foreground", bg = "background_menu" } +"ui.linenr" = { fg = "foreground_gutter" } +"ui.linenr.selected" = { fg = "foreground" } +"ui.menu" = { fg = "foreground", bg = "background_menu" } +"ui.menu.selected" = { bg = "background_highlight" } +"ui.popup" = { fg = "foreground", bg = "background_menu" } +"ui.selection" = { bg = "background_highlight" } +"ui.selection.primary" = { bg = "background_highlight" } +"ui.statusline" = { fg = "foreground", bg = "background_menu" } +"ui.statusline.inactive" = { fg = "foreground_gutter", bg = "background_menu" } +"ui.text" = { fg = "foreground" } +"ui.text.focus" = { fg = "cyan" } +"ui.window" = { fg = "black" } + +"error" = { fg = "red" } +"warning" = { fg = "yellow" } +"info" = { fg = "blue" } +"hint" = { fg = "teal" } +"diagnostic" = { modifiers = ["underlined"] } +"special" = { fg = "orange" } + +"markup.heading" = { fg = "cyan", modifiers = ["bold"] } +"markup.list" = { fg = "cyan" } +"markup.bold" = { fg = "orange", modifiers = ["bold"] } +"markup.italic" = { fg = "yellow", modifiers = ["italic"] } +"markup.link.url" = { fg = "green" } +"markup.link.text" = { fg = "light-gray" } +"markup.quote" = { fg = "yellow", modifiers = ["italic"] } +"markup.raw" = { fg = "cyan" } + +[palette] +red = "#f7768e" +orange = "#ff9e64" +yellow = "#e0af68" +light-green = "#9ece6a" +green = "#73daca" +turquoise = "#89ddff" +light-cyan = "#b4f9f8" +teal = "#2ac3de" +cyan = "#7dcfff" +blue = "#7aa2f7" +magenta = "#bb9af7" +white = "#c0caf5" +light-gray = "#9aa5ce" +parameters = "#cfc9c2" +comment = "#565f89" +black = "#414868" +foreground = "#a9b1d6" +foreground_highlight = "#c0caf5" +foreground_gutter = "#3b4261" +background = "#1a1b26" +background_highlight = "#30374b" +background_menu = "#16161e" From c53ec957087f1bd1e03ff8c0acc18bfd0add3244 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Apr 2022 08:54:09 +0900 Subject: [PATCH 095/861] build(deps): bump fern from 0.6.0 to 0.6.1 (#2165) Bumps [fern](https://github.com/daboross/fern) from 0.6.0 to 0.6.1. - [Release notes](https://github.com/daboross/fern/releases) - [Changelog](https://github.com/daboross/fern/blob/main/CHANGELOG.md) - [Commits](https://github.com/daboross/fern/compare/fern-0.6.0...fern-0.6.1) --- updated-dependencies: - dependency-name: fern dependency-type: direct:production update-type: version-update:semver-patch ... 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 61346d451..e5ef157fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -223,9 +223,9 @@ dependencies = [ [[package]] name = "fern" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065" +checksum = "3bdd7b0849075e79ee9a1836df22c717d1eba30451796fdc631b04565dd11e2a" dependencies = [ "log", ] From cc68fa857dced7d9433d145ebfa8cd70e5a0394d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Apr 2022 08:54:20 +0900 Subject: [PATCH 096/861] build(deps): bump toml from 0.5.8 to 0.5.9 (#2166) Bumps [toml](https://github.com/alexcrichton/toml-rs) from 0.5.8 to 0.5.9. - [Release notes](https://github.com/alexcrichton/toml-rs/releases) - [Commits](https://github.com/alexcrichton/toml-rs/compare/0.5.8...0.5.9) --- updated-dependencies: - dependency-name: toml dependency-type: direct:production update-type: version-update:semver-patch ... 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 e5ef157fb..22c128d91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1141,9 +1141,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] From 3a7bf1c40cba7f4763df38e347587b5c3003d080 Mon Sep 17 00:00:00 2001 From: Andrey Tkachenko Date: Wed, 20 Apr 2022 05:42:33 +0400 Subject: [PATCH 097/861] Restore document state on completion cancel (#2096) --- helix-term/src/ui/completion.rs | 1 + helix-term/src/ui/popup.rs | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index 556273bc5..38005aad0 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -135,6 +135,7 @@ impl Completion { match event { PromptEvent::Abort => { + doc.restore(view.id); editor.last_completion = None; } PromptEvent::Update => { diff --git a/helix-term/src/ui/popup.rs b/helix-term/src/ui/popup.rs index 455274822..069a22f45 100644 --- a/helix-term/src/ui/popup.rs +++ b/helix-term/src/ui/popup.rs @@ -124,7 +124,10 @@ impl Component for Popup { match key.into() { // esc or ctrl-c aborts the completion and closes the menu - key!(Esc) | ctrl!('c') => EventResult::Consumed(Some(close_fn)), + key!(Esc) | ctrl!('c') => { + let _ = self.contents.handle_event(event, cx); + EventResult::Consumed(Some(close_fn)) + } ctrl!('d') => { self.scroll(self.size.1 as usize / 2, true); EventResult::Consumed(None) From c8cfd0b1a0da071618a9efc71ac5735d6147a0ca Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 19 Apr 2022 20:43:09 -0500 Subject: [PATCH 098/861] override nested arrays when merging TOML (#2145) We merge the elements of arrays for the top-level array. For `languages.toml`, this is the array of languages. For any nested arrays, we simply take the `right` array as-is instead of using the union of `left` and `right`. closes #1000 --- helix-loader/src/config.rs | 2 +- helix-loader/src/lib.rs | 101 ++++++++++++++++++++++++++++--------- 2 files changed, 79 insertions(+), 24 deletions(-) diff --git a/helix-loader/src/config.rs b/helix-loader/src/config.rs index 5dc2d6b67..242af197a 100644 --- a/helix-loader/src/config.rs +++ b/helix-loader/src/config.rs @@ -19,7 +19,7 @@ pub fn user_lang_config() -> Result { .into_iter() .chain([default_lang_config()].into_iter()) .fold(toml::Value::Table(toml::value::Table::default()), |a, b| { - crate::merge_toml_values(b, a) + crate::merge_toml_values(b, a, false) }); Ok(config) diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index de2951f8e..767bff7a4 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -98,8 +98,24 @@ pub fn find_root_impl(root: Option<&str>, root_markers: &[String]) -> Vec toml::Value { +/// Merge two TOML documents, merging values from `right` onto `left` +/// +/// When an array exists in both `left` and `right`, `right`'s array is +/// used. When a table exists in both `left` and `right`, the merged table +/// consists of all keys in `left`'s table unioned with all keys in `right` +/// with the values of `right` being merged recursively onto values of +/// `left`. +/// +/// `merge_toplevel_arrays` controls whether a top-level array in the TOML +/// document is merged instead of overridden. This is useful for TOML +/// documents that use a top-level array of values like the `languages.toml`, +/// where one usually wants to override or add to the array instead of +/// replacing it altogether. +pub fn merge_toml_values( + left: toml::Value, + right: toml::Value, + merge_toplevel_arrays: bool, +) -> toml::Value { use toml::Value; fn get_name(v: &Value) -> Option<&str> { @@ -108,24 +124,35 @@ pub fn merge_toml_values(left: toml::Value, right: toml::Value) -> toml::Value { match (left, right) { (Value::Array(mut left_items), Value::Array(right_items)) => { - left_items.reserve(right_items.len()); - for rvalue in right_items { - let lvalue = get_name(&rvalue) - .and_then(|rname| left_items.iter().position(|v| get_name(v) == Some(rname))) - .map(|lpos| left_items.remove(lpos)); - let mvalue = match lvalue { - Some(lvalue) => merge_toml_values(lvalue, rvalue), - None => rvalue, - }; - left_items.push(mvalue); + // The top-level arrays should be merged but nested arrays should + // act as overrides. For the `languages.toml` config, this means + // that you can specify a sub-set of languages in an overriding + // `languages.toml` but that nested arrays like Language Server + // arguments are replaced instead of merged. + if merge_toplevel_arrays { + left_items.reserve(right_items.len()); + for rvalue in right_items { + let lvalue = get_name(&rvalue) + .and_then(|rname| { + left_items.iter().position(|v| get_name(v) == Some(rname)) + }) + .map(|lpos| left_items.remove(lpos)); + let mvalue = match lvalue { + Some(lvalue) => merge_toml_values(lvalue, rvalue, false), + None => rvalue, + }; + left_items.push(mvalue); + } + Value::Array(left_items) + } else { + Value::Array(right_items) } - Value::Array(left_items) } (Value::Table(mut left_map), Value::Table(right_map)) => { for (rname, rvalue) in right_map { match left_map.remove(&rname) { Some(lvalue) => { - let merged_value = merge_toml_values(lvalue, rvalue); + let merged_value = merge_toml_values(lvalue, rvalue, merge_toplevel_arrays); left_map.insert(rname, merged_value); } None => { @@ -143,23 +170,22 @@ pub fn merge_toml_values(left: toml::Value, right: toml::Value) -> toml::Value { #[cfg(test)] mod merge_toml_tests { use super::merge_toml_values; + use toml::Value; #[test] - fn language_tomls() { - use toml::Value; - - const USER: &str = " + fn language_toml_map_merges() { + const USER: &str = r#" [[language]] - name = \"nix\" - test = \"bbb\" - indent = { tab-width = 4, unit = \" \", test = \"aaa\" } - "; + name = "nix" + test = "bbb" + indent = { tab-width = 4, unit = " ", test = "aaa" } + "#; let base: Value = toml::from_slice(include_bytes!("../../languages.toml")) .expect("Couldn't parse built-in languages config"); let user: Value = toml::from_str(USER).unwrap(); - let merged = merge_toml_values(base, user); + let merged = merge_toml_values(base, user, true); let languages = merged.get("language").unwrap().as_array().unwrap(); let nix = languages .iter() @@ -179,4 +205,33 @@ mod merge_toml_tests { // We didn't change comment-token so it should be same assert_eq!(nix.get("comment-token").unwrap().as_str().unwrap(), "#"); } + + #[test] + fn language_toml_nested_array_merges() { + const USER: &str = r#" + [[language]] + name = "typescript" + language-server = { command = "deno", args = ["lsp"] } + "#; + + let base: Value = toml::from_slice(include_bytes!("../../languages.toml")) + .expect("Couldn't parse built-in languages config"); + let user: Value = toml::from_str(USER).unwrap(); + + let merged = merge_toml_values(base, user, true); + let languages = merged.get("language").unwrap().as_array().unwrap(); + let ts = languages + .iter() + .find(|v| v.get("name").unwrap().as_str().unwrap() == "typescript") + .unwrap(); + assert_eq!( + ts.get("language-server") + .unwrap() + .get("args") + .unwrap() + .as_array() + .unwrap(), + &vec![Value::String("lsp".into())] + ) + } } From e452b97cdc7617ec887744b764f1090e440a5983 Mon Sep 17 00:00:00 2001 From: Matthew Toohey Date: Tue, 19 Apr 2022 21:43:52 -0400 Subject: [PATCH 099/861] AppImage (#2089) * Add desktop entry file Co-authored-by: NNB * Add placeholder icon for AppImage * Add AppImage step to release workflow * Exclude grammar sources from AppImage Co-authored-by: NNB --- .github/workflows/release.yml | 52 +++++++++++++++++++- contrib/Helix.desktop | 89 ++++++++++++++++++++++++++++++++++ contrib/helix.png | Bin 0 -> 1838 bytes 3 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 contrib/Helix.desktop create mode 100644 contrib/helix.png diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7c265db8c..30f8ccc78 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -147,16 +147,60 @@ jobs: aarch64-linux-gnu-strip \ /target/${{ matrix.target }}/release/hx - - name: Build archive + - name: Build AppImage shell: bash + if: matrix.build == 'x86_64-linux' run: | mkdir dist + + name=dev + if [[ $GITHUB_REF == refs/tags/* ]]; then + name=${GITHUB_REF:10} + fi + + export VERSION="$name" + export ARCH=x86_64 + export APP=helix + export OUTPUT="helix-$VERSION-$ARCH.AppImage" + export UPDATE_INFORMATION="gh-releases-zsync|$GITHUB_REPOSITORY_OWNER|helix|latest|$APP-*-$ARCH.AppImage.zsync" + + mkdir -p "$APP.AppDir"/usr/{bin,lib/helix} + + cp "target/${{ matrix.target }}/release/hx" "$APP.AppDir/usr/bin/hx" + rm -rf runtime/grammars/sources + cp -r runtime "$APP.AppDir/usr/lib/helix/runtime" + + cat << 'EOF' > "$APP.AppDir/AppRun" + #!/bin/sh + + APPDIR="$(dirname "$(readlink -f "${0}")")" + HELIX_RUNTIME="$APPDIR/usr/lib/helix/runtime" exec "$APPDIR/usr/bin/hx" "$@" + EOF + chmod 755 "$APP.AppDir/AppRun" + + curl -Lo linuxdeploy-x86_64.AppImage \ + https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage + chmod +x linuxdeploy-x86_64.AppImage + + ./linuxdeploy-x86_64.AppImage \ + --appdir "$APP.AppDir" -d contrib/Helix.desktop \ + -i contrib/helix.png --output appimage + + mv "$APP-$VERSION-$ARCH.AppImage" \ + "$APP-$VERSION-$ARCH.AppImage.zsync" dist + + - name: Build archive + shell: bash + run: | + mkdir -p dist if [ "${{ matrix.os }}" = "windows-2019" ]; then cp "target/${{ matrix.target }}/release/hx.exe" "dist/" else cp "target/${{ matrix.target }}/release/hx" "dist/" fi - rm -rf runtime/grammars/sources + if [ -d runtime/grammars/sources ]; then + rm -rf runtime/grammars/sources + fi cp -r runtime dist - uses: actions/upload-artifact@v3 @@ -212,6 +256,10 @@ jobs: mv bins-$platform/hx$exe $pkgname chmod +x $pkgname/hx$exe + if [[ "$platform" = "x86_64-linux" ]]; then + mv bins-$platform/helix-*.AppImage* dist/ + fi + if [ "$exe" = "" ]; then tar cJf dist/$pkgname.tar.xz $pkgname else diff --git a/contrib/Helix.desktop b/contrib/Helix.desktop new file mode 100644 index 000000000..844286f84 --- /dev/null +++ b/contrib/Helix.desktop @@ -0,0 +1,89 @@ +[Desktop Entry] +Name=Helix +GenericName=Text Editor +GenericName[de]=Texteditor +GenericName[fr]=Éditeur de texte +GenericName[ru]=Текстовый редактор +GenericName[sr]=Едитор текст +GenericName[tr]=Metin Düzenleyici +Comment=Edit text files +Comment[af]=Redigeer tekslêers +Comment[am]=የጽሑፍ ፋይሎች ያስተካክሉ +Comment[ar]=حرّر ملفات نصية +Comment[az]=Mətn fayllarını redaktə edin +Comment[be]=Рэдагаваньне тэкставых файлаў +Comment[bg]=Редактиране на текстови файлове +Comment[bn]=টেক্স্ট ফাইল এডিট করুন +Comment[bs]=Izmijeni tekstualne datoteke +Comment[ca]=Edita fitxers de text +Comment[cs]=Úprava textových souborů +Comment[cy]=Golygu ffeiliau testun +Comment[da]=Redigér tekstfiler +Comment[de]=Textdateien bearbeiten +Comment[el]=Επεξεργασία αρχείων κειμένου +Comment[en_CA]=Edit text files +Comment[en_GB]=Edit text files +Comment[es]=Edita archivos de texto +Comment[et]=Redigeeri tekstifaile +Comment[eu]=Editatu testu-fitxategiak +Comment[fa]=ویرایش پرونده‌های متنی +Comment[fi]=Muokkaa tekstitiedostoja +Comment[fr]=Éditer des fichiers texte +Comment[ga]=Eagar comhad Téacs +Comment[gu]=લખાણ ફાઇલોમાં ફેરફાર કરો +Comment[he]=ערוך קבצי טקסט +Comment[hi]=पाठ फ़ाइलें संपादित करें +Comment[hr]=Uređivanje tekstualne datoteke +Comment[hu]=Szövegfájlok szerkesztése +Comment[id]=Edit file teks +Comment[it]=Modifica file di testo +Comment[ja]=テキストファイルを編集します +Comment[kn]=ಪಠ್ಯ ಕಡತಗಳನ್ನು ಸಂಪಾದಿಸು +Comment[ko]=텍스트 파일을 편집합니다 +Comment[lt]=Redaguoti tekstines bylas +Comment[lv]=Rediģēt teksta failus +Comment[mk]=Уреди текстуални фајлови +Comment[ml]=വാചക രചനകള് തിരുത്തുക +Comment[mn]=Текст файл боловсруулах +Comment[mr]=गद्य फाइल संपादित करा +Comment[ms]=Edit fail teks +Comment[nb]=Rediger tekstfiler +Comment[ne]=पाठ फाइललाई संशोधन गर्नुहोस् +Comment[nl]=Tekstbestanden bewerken +Comment[nn]=Rediger tekstfiler +Comment[no]=Rediger tekstfiler +Comment[or]=ପାଠ୍ଯ ଫାଇଲଗୁଡ଼ିକୁ ସମ୍ପାଦନ କରନ୍ତୁ +Comment[pa]=ਪਾਠ ਫਾਇਲਾਂ ਸੰਪਾਦਨ +Comment[pl]=Edytor plików tekstowych +Comment[pt]=Editar ficheiros de texto +Comment[pt_BR]=Edite arquivos de texto +Comment[ro]=Editare fişiere text +Comment[ru]=Редактирование текстовых файлов +Comment[sk]=Úprava textových súborov +Comment[sl]=Urejanje datotek z besedili +Comment[sq]=Përpuno files teksti +Comment[sr]=Уређујте текст фајлове +Comment[sr@Latn]=Izmeni tekstualne datoteke +Comment[sv]=Redigera textfiler +Comment[ta]=உரை கோப்புகளை தொகுக்கவும் +Comment[th]=แก้ไขแฟ้มข้อความ +Comment[tk]=Metin faýllary editle +Comment[tr]=Metin dosyaları düzenleyin +Comment[uk]=Редактор текстових файлів +Comment[vi]=Soạn thảo tập tin văn bản +Comment[wa]=Asspougnî des fitchîs tecses +Comment[zh_CN]=编辑文本文件 +Comment[zh_TW]=編輯文字檔 +TryExec=hx +Exec=hx %F +Terminal=true +Type=Application +Keywords=Text;editor; +Keywords[fr]=Texte;éditeur; +Keywords[ru]=текст;текстовый редактор; +Keywords[sr]=Текст;едитор; +Keywords[tr]=Metin;düzenleyici; +Icon=helix +Categories=Utility;TextEditor; +StartupNotify=false +MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++; diff --git a/contrib/helix.png b/contrib/helix.png new file mode 100644 index 0000000000000000000000000000000000000000..bef00b98418a3fefcf56a5d45fafb1403e26e996 GIT binary patch literal 1838 zcmYjRc{r478-L$1jWH^+WUFiDSQ4^?7-bAI#N@MOOV-MoEgH*_Wg1IlH%JP(n!|}m z_+-hTv7AC2bYvTyj9pA*$&8sZzVDxNZ@=gH-S>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: Wed, 20 Apr 2022 01:44:11 +0000 Subject: [PATCH 100/861] add table of OS/command for copy/symlink the runtime folder to the config (#2073) * create table of OS and commands in the readme * add link to wiki from health check (without color; just simple println) * move the table from readme to docs and add link from the readme to docs * drop copy on unix,and apply some style fixes from the conversations * by mistake, I edit master insted of develop * remove this file from pr * Update README.md Co-authored-by: Michael Davis * copy table to readme Co-authored-by: Michael Davis --- README.md | 13 ++++++++++--- book/src/install.md | 5 +++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6fc98e728..9c7b11777 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,11 @@ Note: Only certain languages have indentation definitions at the moment. Check # Installation -We provide packaging for various distributions, but here's a quick method to -build from source. +Packages are available for various distributions (see [Installation docs](https://docs.helix-editor.com/install.html)). -``` +If you would like to build from source: + +```shell git clone https://github.com/helix-editor/helix cd helix cargo install --path helix-term @@ -47,6 +48,12 @@ This will install the `hx` binary to `$HOME/.cargo/bin` and build tree-sitter gr Helix also needs its runtime files so make sure to copy/symlink the `runtime/` directory into the config directory (for example `~/.config/helix/runtime` on Linux/macOS, or `%AppData%/helix/runtime` on Windows). + +| OS | command | +|-----------|-----------| +|windows |`xcopy runtime %AppData%/helix/runtime`| +|linux/macos|`ln -s $PWD/runtime ~/.config/helix/runtime` + This location can be overridden via the `HELIX_RUNTIME` environment variable. Packages already solve this for you by wrapping the `hx` binary with a wrapper diff --git a/book/src/install.md b/book/src/install.md index 372ce12a1..3329d1c58 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -61,6 +61,11 @@ Helix also needs it's runtime files so make sure to copy/symlink the `runtime/` config directory (for example `~/.config/helix/runtime` on Linux/macOS). This location can be overriden via the `HELIX_RUNTIME` environment variable. +| OS | command | +|-----------|-----------| +|windows |`xcopy runtime %AppData%/helix/runtime`| +|linux/macos|`ln -s $PWD/runtime ~/.config/helix/runtime` + ## Building tree-sitter grammars Tree-sitter grammars must be fetched and compiled if not pre-packaged. From 5d5b6bab9ba5211c8c146fb38276f968892e7882 Mon Sep 17 00:00:00 2001 From: Thomas <74479846+DeviousStoat@users.noreply.github.com> Date: Wed, 20 Apr 2022 03:44:32 +0200 Subject: [PATCH 101/861] Add rulers option (#2060) * Add color_column option * Rename to ruler Co-authored-by: DeviousStoat --- book/src/configuration.md | 1 + helix-core/src/syntax.rs | 2 ++ helix-term/src/ui/editor.rs | 27 +++++++++++++++++++++++++++ helix-view/src/editor.rs | 3 +++ 4 files changed, 33 insertions(+) diff --git a/book/src/configuration.md b/book/src/configuration.md index 3ec2bedb9..153ebb806 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -43,6 +43,7 @@ hidden = false | `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` | | `auto-info` | Whether to display infoboxes | `true` | | `true-color` | Set to `true` to override automatic detection of terminal truecolor support in the event of a false negative. | `false` | +| `rulers` | List of column positions at which to display the rulers. Can be overidden by language specific `rulers` in `languages.toml` file. | `[]` | ### `[editor.lsp]` Section diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 905b33474..2fd4ed9ba 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -104,6 +104,8 @@ pub struct LanguageConfiguration { /// global setting. #[serde(default, skip_serializing, deserialize_with = "deserialize_auto_pairs")] pub auto_pairs: Option, + + pub rulers: Option>, // if set, override editor's rulers } #[derive(Debug, Serialize, Deserialize)] diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 459a8c876..fc8b64701 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -126,6 +126,7 @@ impl EditorView { Self::render_text_highlights(doc, view.offset, inner, surface, theme, highlights); Self::render_gutter(editor, doc, view, view.area, surface, theme, is_focused); + Self::render_rulers(editor, doc, view, inner, surface, theme); if is_focused { Self::render_focused_view_elements(view, doc, inner, theme, surface); @@ -152,6 +153,32 @@ impl EditorView { self.render_statusline(doc, view, statusline_area, surface, theme, is_focused); } + pub fn render_rulers( + editor: &Editor, + doc: &Document, + view: &View, + viewport: Rect, + surface: &mut Surface, + theme: &Theme, + ) { + let editor_rulers = &editor.config().rulers; + let ruler_theme = theme.get("ui.virtual.ruler"); + + let rulers = doc + .language_config() + .and_then(|config| config.rulers.as_ref()) + .unwrap_or(editor_rulers); + + rulers + .iter() + // View might be horizontally scrolled, convert from absolute distance + // from the 1st column to relative distance from left of viewport + .filter_map(|ruler| ruler.checked_sub(1 + view.offset.col as u16)) + .filter(|ruler| ruler < &viewport.width) + .map(|ruler| viewport.clip_left(ruler).with_width(1)) + .for_each(|area| surface.set_style(area, ruler_theme)) + } + /// Get syntax highlights for a document in a view represented by the first line /// and column (`offset`) and the last line. This is done instead of using a view /// directly to enable rendering syntax highlighted docs anywhere (eg. picker preview) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index dd805c000..0c2fad2b6 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -146,6 +146,8 @@ pub struct Config { #[serde(default)] pub search: SearchConfig, pub lsp: LspConfig, + /// Column numbers at which to draw the rulers. Default to `[]`, meaning no rulers. + pub rulers: Vec, } #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] @@ -285,6 +287,7 @@ impl Default for Config { true_color: false, search: SearchConfig::default(), lsp: LspConfig::default(), + rulers: Vec::new(), } } } From 2a853cd41dd15d2891ac6ca17372c9f5f00a8528 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Wed, 20 Apr 2022 09:46:46 +0800 Subject: [PATCH 102/861] Fix open on multiline selection (#2161) Select multiple line and open should be based on the whole selection and not just the line of the cursor, which causes weird behavior like opening in the middle of the selection which user might not expect. --- helix-term/src/commands.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 15ccc247b..4e13f74ad 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2292,8 +2292,10 @@ fn open(cx: &mut Context, open: Open) { let mut offs = 0; let mut transaction = Transaction::change_by_selection(contents, selection, |range| { - let cursor_line = range.cursor_line(text); - + let cursor_line = text.char_to_line(match open { + Open::Below => graphemes::prev_grapheme_boundary(text, range.to()), + Open::Above => range.from(), + }); let new_line = match open { // adjust position to the end of the line (next line - 1) Open::Below => cursor_line + 1, From 94eba0e66aa193c093b1d7eefc0e21391cb2485f Mon Sep 17 00:00:00 2001 From: adaliaramon <70635214+adaliaramon@users.noreply.github.com> Date: Wed, 20 Apr 2022 03:50:13 +0200 Subject: [PATCH 103/861] Added ability to remap 0 if it is not part of a count (#2174) * Added ability to remap 0 * Removed duplicated match body --- helix-term/src/ui/editor.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index fc8b64701..318180d7d 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -774,15 +774,15 @@ impl EditorView { } fn command_mode(&mut self, mode: Mode, cxt: &mut commands::Context, event: KeyEvent) { - match event { + match (event, cxt.editor.count) { // count handling - key!(i @ '0'..='9') => { + (key!(i @ '0'), Some(_)) | (key!(i @ '1'..='9'), _) => { let i = i.to_digit(10).unwrap() as usize; cxt.editor.count = std::num::NonZeroUsize::new(cxt.editor.count.map_or(i, |c| c.get() * 10 + i)); } // special handling for repeat operator - key!('.') if self.keymaps.pending().is_empty() => { + (key!('.'), _) if self.keymaps.pending().is_empty() => { // first execute whatever put us into insert mode self.last_insert.0.execute(cxt); // then replay the inputs From e6b865ed0b1b77934733d86b59d60870e9f5881f Mon Sep 17 00:00:00 2001 From: Omnikar Date: Wed, 1 Dec 2021 17:59:23 -0500 Subject: [PATCH 104/861] allow whitespace to be rendered Co-authored-by: Michael Davis --- Cargo.lock | 1 + book/src/configuration.md | 26 +++++++++++ book/src/themes.md | 2 +- helix-term/Cargo.toml | 1 + helix-term/src/application.rs | 2 +- helix-term/src/ui/editor.rs | 55 +++++++++++++++++++--- helix-term/src/ui/picker.rs | 1 + helix-view/src/editor.rs | 87 ++++++++++++++++++++++++++++++++++- 8 files changed, 166 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 22c128d91..0835d1075 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -457,6 +457,7 @@ dependencies = [ "once_cell", "pulldown-cmark", "retain_mut", + "ropey", "serde", "serde_json", "signal-hook", diff --git a/book/src/configuration.md b/book/src/configuration.md index 153ebb806..fea60d2f3 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -137,3 +137,29 @@ Search specific options. |--|--|---------| | `smart-case` | Enable smart case regex searching (case insensitive unless pattern contains upper case characters) | `true` | | `wrap-around`| Whether the search should wrap after depleting the matches | `true` | + +### `[editor.whitespace]` Section + +Options for rendering whitespace with visible characters. Use `:set whitespace.render all` to temporarily enable visible whitespace. + +| Key | Description | Default | +|-----|-------------|---------| +| `render` | Whether to render whitespace. May either be `"all"` or `"none"`, or a table with sub-keys `space`, `tab`, and `newline`. | `"none"` | +| `characters` | Literal characters to use when rendering whitespace. Sub-keys may be any of `tab`, `space` or `newline` | See example below | + +Example + +```toml +[editor.whitespace] +render = "all" +# or control each character +[editor.whitespace.render] +space = "all" +tab = "all" +newline = "none" + +[editor.whitespace.characters] +space = "·" +tab = "→" +newline = "⏎" +``` diff --git a/book/src/themes.md b/book/src/themes.md index e23dbb692..9009e2cad 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -224,6 +224,7 @@ These scopes are used for theming the editor interface. | `ui.text` | Command prompts, popup text, etc. | | `ui.text.focus` | | | `ui.text.info` | The key: command text in `ui.popup.info` boxes | +| `ui.virtual.whitespace` | Visible white-space characters | | `ui.menu` | Code and command completion menus | | `ui.menu.selected` | Selected autocomplete item | | `ui.selection` | For selections in the editing area | @@ -233,4 +234,3 @@ These scopes are used for theming the editor interface. | `info` | Diagnostics info (gutter) | | `hint` | Diagnostics hint (gutter) | | `diagnostic` | For text in editing area | - diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 2e0b774ba..4b2611eda 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -33,6 +33,7 @@ anyhow = "1" once_cell = "1.10" which = "4.2" +ropey = { version = "1.4", default-features = false } tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] } num_cpus = "1" diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 7733c2c6f..91caade79 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -283,7 +283,7 @@ impl Application { // the Application can apply it. ConfigEvent::Update(editor_config) => { let mut app_config = (*self.config.load().clone()).clone(); - app_config.editor = editor_config; + app_config.editor = *editor_config; self.config.store(Arc::new(app_config)); } } diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 318180d7d..798b8ac86 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -124,7 +124,15 @@ impl EditorView { Box::new(highlights) }; - Self::render_text_highlights(doc, view.offset, inner, surface, theme, highlights); + Self::render_text_highlights( + doc, + view.offset, + inner, + surface, + theme, + highlights, + &editor.config().whitespace, + ); Self::render_gutter(editor, doc, view, view.area, surface, theme, is_focused); Self::render_rulers(editor, doc, view, inner, surface, theme); @@ -344,7 +352,10 @@ impl EditorView { surface: &mut Surface, theme: &Theme, highlights: H, + whitespace: &helix_view::editor::WhitespaceConfig, ) { + use helix_view::editor::WhitespaceRenderValue; + // It's slightly more efficient to produce a full RopeSlice from the Rope, then slice that a bunch // of times than it is to always call Rope::slice/get_slice (it will internally always hit RSEnum::Light). let text = doc.text().slice(..); @@ -353,9 +364,20 @@ impl EditorView { let mut visual_x = 0u16; let mut line = 0u16; let tab_width = doc.tab_width(); - let tab = " ".repeat(tab_width); + let tab = if whitespace.render.tab() == WhitespaceRenderValue::All { + (1..tab_width).fold(whitespace.characters.tab.to_string(), |s, _| s + " ") + } else { + " ".repeat(tab_width) + }; + let space = whitespace.characters.space.to_string(); + let newline = if whitespace.render.newline() == WhitespaceRenderValue::All { + whitespace.characters.newline.to_string() + } else { + " ".to_string() + }; let text_style = theme.get("ui.text"); + let whitespace_style = theme.get("ui.virtual.whitespace"); 'outer: for event in highlights { match event { @@ -374,6 +396,14 @@ impl EditorView { .iter() .fold(text_style, |acc, span| acc.patch(theme.highlight(span.0))); + let space = if whitespace.render.space() == WhitespaceRenderValue::All + && text.len_chars() < end + { + &space + } else { + " " + }; + use helix_core::graphemes::{grapheme_width, RopeGraphemes}; for grapheme in RopeGraphemes::new(text) { @@ -386,8 +416,8 @@ impl EditorView { surface.set_string( viewport.x + visual_x - offset.col as u16, viewport.y + line, - " ", - style, + &newline, + style.patch(whitespace_style), ); } @@ -400,12 +430,21 @@ impl EditorView { } } else { let grapheme = Cow::from(grapheme); + let is_whitespace; let (grapheme, width) = if grapheme == "\t" { + is_whitespace = true; // make sure we display tab as appropriate amount of spaces let visual_tab_width = tab_width - (visual_x as usize % tab_width); - (&tab[..visual_tab_width], visual_tab_width) + let grapheme_tab_width = + ropey::str_utils::char_to_byte_idx(&tab, visual_tab_width); + + (&tab[..grapheme_tab_width], visual_tab_width) + } else if grapheme == " " { + is_whitespace = true; + (space, 1) } else { + is_whitespace = false; // Cow will prevent allocations if span contained in a single slice // which should really be the majority case let width = grapheme_width(&grapheme); @@ -418,7 +457,11 @@ impl EditorView { viewport.x + visual_x - offset.col as u16, viewport.y + line, grapheme, - style, + if is_whitespace { + style.patch(whitespace_style) + } else { + style + }, ); } diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index dec59c892..3ca6965cf 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -240,6 +240,7 @@ impl Component for FilePicker { surface, &cx.editor.theme, highlights, + &cx.editor.config().whitespace, ); // highlight the line diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 0c2fad2b6..79775c897 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -148,6 +148,8 @@ pub struct Config { pub lsp: LspConfig, /// Column numbers at which to draw the rulers. Default to `[]`, meaning no rulers. pub rulers: Vec, + #[serde(default)] + pub whitespace: WhitespaceConfig, } #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] @@ -263,6 +265,88 @@ impl std::str::FromStr for GutterType { } } +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(default)] +pub struct WhitespaceConfig { + pub render: WhitespaceRender, + pub characters: WhitespaceCharacters, +} + +impl Default for WhitespaceConfig { + fn default() -> Self { + Self { + render: WhitespaceRender::Basic(WhitespaceRenderValue::None), + characters: WhitespaceCharacters::default(), + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(untagged, rename_all = "kebab-case")] +pub enum WhitespaceRender { + Basic(WhitespaceRenderValue), + Specific { + default: Option, + space: Option, + tab: Option, + newline: Option, + }, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum WhitespaceRenderValue { + None, + // TODO + // Selection, + All, +} + +impl WhitespaceRender { + pub fn space(&self) -> WhitespaceRenderValue { + match *self { + Self::Basic(val) => val, + Self::Specific { default, space, .. } => { + space.or(default).unwrap_or(WhitespaceRenderValue::None) + } + } + } + pub fn tab(&self) -> WhitespaceRenderValue { + match *self { + Self::Basic(val) => val, + Self::Specific { default, tab, .. } => { + tab.or(default).unwrap_or(WhitespaceRenderValue::None) + } + } + } + pub fn newline(&self) -> WhitespaceRenderValue { + match *self { + Self::Basic(val) => val, + Self::Specific { + default, newline, .. + } => newline.or(default).unwrap_or(WhitespaceRenderValue::None), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(default)] +pub struct WhitespaceCharacters { + pub space: char, + pub tab: char, + pub newline: char, +} + +impl Default for WhitespaceCharacters { + fn default() -> Self { + Self { + space: '·', // U+00B7 + tab: '→', // U+2192 + newline: '⏎', // U+23CE + } + } +} + impl Default for Config { fn default() -> Self { Self { @@ -288,6 +372,7 @@ impl Default for Config { search: SearchConfig::default(), lsp: LspConfig::default(), rulers: Vec::new(), + whitespace: WhitespaceConfig::default(), } } } @@ -366,7 +451,7 @@ pub struct Editor { #[derive(Debug, Clone)] pub enum ConfigEvent { Refresh, - Update(Config), + Update(Box), } #[derive(Debug, Clone)] From 1525e3c6c846fc3dc4d4a68768105762f5abb376 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 1 Apr 2022 15:28:34 -0500 Subject: [PATCH 105/861] theme ui.virtual capture for existing themes --- runtime/themes/base16_default_dark.toml | 1 + runtime/themes/base16_default_light.toml | 1 + runtime/themes/base16_terminal.toml | 1 + runtime/themes/bogster.toml | 1 + runtime/themes/boo_berry.toml | 1 + runtime/themes/dark_plus.toml | 2 ++ runtime/themes/dracula.toml | 1 + runtime/themes/everforest_dark.toml | 1 + runtime/themes/everforest_light.toml | 1 + runtime/themes/gruvbox.toml | 1 + runtime/themes/gruvbox_light.toml | 1 + runtime/themes/ingrid.toml | 1 + runtime/themes/monokai.toml | 1 + runtime/themes/monokai_pro.toml | 1 + runtime/themes/monokai_pro_machine.toml | 1 + runtime/themes/monokai_pro_octagon.toml | 1 + runtime/themes/monokai_pro_ristretto.toml | 1 + runtime/themes/monokai_pro_spectrum.toml | 1 + runtime/themes/nord.toml | 1 + runtime/themes/onedark.toml | 1 + runtime/themes/rose_pine.toml | 1 + runtime/themes/rose_pine_dawn.toml | 1 + runtime/themes/serika-dark.toml | 1 + runtime/themes/serika-light.toml | 1 + runtime/themes/solarized_dark.toml | 2 ++ runtime/themes/solarized_light.toml | 2 ++ runtime/themes/spacebones_light.toml | 1 + runtime/themes/tokyonight.toml | 1 + theme.toml | 1 + 29 files changed, 32 insertions(+) diff --git a/runtime/themes/base16_default_dark.toml b/runtime/themes/base16_default_dark.toml index c8dd1b0e8..6074c450e 100644 --- a/runtime/themes/base16_default_dark.toml +++ b/runtime/themes/base16_default_dark.toml @@ -1,6 +1,7 @@ # Author: RayGervais "ui.background" = { bg = "base00" } +"ui.virtual" = "base03" "ui.menu" = { fg = "base05", bg = "base01" } "ui.menu.selected" = { fg = "base01", bg = "base04" } "ui.linenr" = { fg = "base03", bg = "base01" } diff --git a/runtime/themes/base16_default_light.toml b/runtime/themes/base16_default_light.toml index 50be51b30..2273c1912 100644 --- a/runtime/themes/base16_default_light.toml +++ b/runtime/themes/base16_default_light.toml @@ -13,6 +13,7 @@ "ui.help" = { fg = "base04", bg = "base01" } "ui.cursor" = { fg = "base04", modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "base05", modifiers = ["reversed"] } +"ui.virtual" = "base03" "ui.text" = "base05" "operator" = "base05" "ui.text.focus" = "base05" diff --git a/runtime/themes/base16_terminal.toml b/runtime/themes/base16_terminal.toml index a6ca71da9..e518d3d56 100644 --- a/runtime/themes/base16_terminal.toml +++ b/runtime/themes/base16_terminal.toml @@ -13,6 +13,7 @@ "ui.help" = { fg = "white", bg = "black" } "ui.cursor" = { fg = "light-gray", modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "light-white", modifiers = ["reversed"] } +"ui.virtual" = "light-gray" "variable" = "light-red" "constant.numeric" = "yellow" "constant" = "yellow" diff --git a/runtime/themes/bogster.toml b/runtime/themes/bogster.toml index e2b4277ec..af952071b 100644 --- a/runtime/themes/bogster.toml +++ b/runtime/themes/bogster.toml @@ -53,6 +53,7 @@ "ui.text" = { fg = "#e5ded6" } "ui.text.focus" = { fg = "#e5ded6", modifiers= ["bold"] } +"ui.virtual" = "#627d9d" "ui.selection" = { bg = "#313f4e" } # "ui.cursor.match" # TODO might want to override this because dimmed is not widely supported diff --git a/runtime/themes/boo_berry.toml b/runtime/themes/boo_berry.toml index 79b89ed0a..5cd253974 100644 --- a/runtime/themes/boo_berry.toml +++ b/runtime/themes/boo_berry.toml @@ -44,6 +44,7 @@ "ui.menu" = { fg = "lilac", bg = "berry_saturated" } "ui.menu.selected" = { fg = "mint", bg = "berry_saturated" } "ui.selection" = { bg = "berry_saturated" } +"ui.virtual" = { fg = "berry_desaturated" } "diff.plus" = { fg = "mint" } "diff.delta" = { fg = "gold" } diff --git a/runtime/themes/dark_plus.toml b/runtime/themes/dark_plus.toml index 42032be27..04e2bc9dc 100644 --- a/runtime/themes/dark_plus.toml +++ b/runtime/themes/dark_plus.toml @@ -78,6 +78,8 @@ "ui.text" = { fg = "text" } "ui.text.focus" = { fg = "white" } +"ui.virtual" = { fg = "dark_green" } + "warning" = { fg = "gold2" } "error" = { fg = "red" } "info" = { fg = "light_blue" } diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index f77d151eb..e32c3117b 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -36,6 +36,7 @@ "ui.text" = { fg = "foreground" } "ui.text.focus" = { fg = "cyan" } "ui.window" = { fg = "foreground" } +"ui.virtual" = { fg = "comment" } "error" = { fg = "red" } "warning" = { fg = "cyan" } diff --git a/runtime/themes/everforest_dark.toml b/runtime/themes/everforest_dark.toml index 8b8e9bbbe..5b6d1b7cf 100644 --- a/runtime/themes/everforest_dark.toml +++ b/runtime/themes/everforest_dark.toml @@ -70,6 +70,7 @@ "ui.menu" = { fg = "fg", bg = "bg2" } "ui.menu.selected" = { fg = "bg0", bg = "green" } "ui.selection" = { bg = "bg3" } +"ui.virtual" = "grey0" "hint" = "blue" "info" = "aqua" diff --git a/runtime/themes/everforest_light.toml b/runtime/themes/everforest_light.toml index d977bdf61..b03701653 100644 --- a/runtime/themes/everforest_light.toml +++ b/runtime/themes/everforest_light.toml @@ -70,6 +70,7 @@ "ui.menu" = { fg = "fg", bg = "bg2" } "ui.menu.selected" = { fg = "bg0", bg = "green" } "ui.selection" = { bg = "bg3" } +"ui.virtual" = "grey0" "hint" = "blue" "info" = "aqua" diff --git a/runtime/themes/gruvbox.toml b/runtime/themes/gruvbox.toml index f27b9934a..6de35244a 100644 --- a/runtime/themes/gruvbox.toml +++ b/runtime/themes/gruvbox.toml @@ -53,6 +53,7 @@ "ui.cursor.match" = { bg = "bg2" } "ui.menu" = { fg = "fg1", bg = "bg2" } "ui.menu.selected" = { fg = "bg2", bg = "blue1", modifiers = ["bold"] } +"ui.virtual" = "bg2" "diagnostic" = { modifiers = ["underlined"] } diff --git a/runtime/themes/gruvbox_light.toml b/runtime/themes/gruvbox_light.toml index ab8325c02..2930dff0d 100644 --- a/runtime/themes/gruvbox_light.toml +++ b/runtime/themes/gruvbox_light.toml @@ -54,6 +54,7 @@ "ui.cursor.match" = { bg = "bg2" } "ui.menu" = { fg = "fg1", bg = "bg2" } "ui.menu.selected" = { fg = "bg2", bg = "blue1", modifiers = ["bold"] } +"ui.virtual" = "bg2" "diagnostic" = { modifiers = ["underlined"] } diff --git a/runtime/themes/ingrid.toml b/runtime/themes/ingrid.toml index a7c33e2df..da8730cc1 100644 --- a/runtime/themes/ingrid.toml +++ b/runtime/themes/ingrid.toml @@ -53,6 +53,7 @@ "ui.text" = { fg = "#7B91B3" } "ui.text.focus" = { fg = "#250E07", modifiers= ["bold"] } +"ui.virtual" = "#A6B6CE" "ui.selection" = { bg = "#540099" } # "ui.cursor.match" # TODO might want to override this because dimmed is not widely supported diff --git a/runtime/themes/monokai.toml b/runtime/themes/monokai.toml index e6ff0a5e3..a71482728 100644 --- a/runtime/themes/monokai.toml +++ b/runtime/themes/monokai.toml @@ -32,6 +32,7 @@ "attribute" = { fg = "fn_declaration" } "comment" = { fg = "#88846F" } +"ui.virtual" = "#88846F" "string" = { fg = "#e6db74" } "constant.character" = { fg = "#e6db74" } diff --git a/runtime/themes/monokai_pro.toml b/runtime/themes/monokai_pro.toml index 8de9994c8..520bf70c1 100644 --- a/runtime/themes/monokai_pro.toml +++ b/runtime/themes/monokai_pro.toml @@ -5,6 +5,7 @@ "ui.linenr.selected" = { bg = "base3" } "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } "ui.menu.selected" = { fg = "base2", bg = "yellow" } +"ui.virtual" = "base5" "info" = "base8" "hint" = "base8" diff --git a/runtime/themes/monokai_pro_machine.toml b/runtime/themes/monokai_pro_machine.toml index c5890042a..8d493f1e2 100644 --- a/runtime/themes/monokai_pro_machine.toml +++ b/runtime/themes/monokai_pro_machine.toml @@ -5,6 +5,7 @@ "ui.linenr.selected" = { bg = "base3" } "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } "ui.menu.selected" = { fg = "base2", bg = "yellow" } +"ui.virtual" = "base5" "info" = "base8" "hint" = "base8" diff --git a/runtime/themes/monokai_pro_octagon.toml b/runtime/themes/monokai_pro_octagon.toml index d9badf3ca..8a69077bc 100644 --- a/runtime/themes/monokai_pro_octagon.toml +++ b/runtime/themes/monokai_pro_octagon.toml @@ -5,6 +5,7 @@ "ui.linenr.selected" = { bg = "base3" } "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } "ui.menu.selected" = { fg = "base2", bg = "yellow" } +"ui.virtual" = "base5" "info" = "base8" "hint" = "base8" diff --git a/runtime/themes/monokai_pro_ristretto.toml b/runtime/themes/monokai_pro_ristretto.toml index ed7ebeaee..f0d60dad1 100644 --- a/runtime/themes/monokai_pro_ristretto.toml +++ b/runtime/themes/monokai_pro_ristretto.toml @@ -5,6 +5,7 @@ "ui.linenr.selected" = { bg = "base3" } "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } "ui.menu.selected" = { fg = "base2", bg = "yellow" } +"ui.virtual" = "base5" "info" = "base8" "hint" = "base8" diff --git a/runtime/themes/monokai_pro_spectrum.toml b/runtime/themes/monokai_pro_spectrum.toml index da06e597c..54a53bfa9 100644 --- a/runtime/themes/monokai_pro_spectrum.toml +++ b/runtime/themes/monokai_pro_spectrum.toml @@ -5,6 +5,7 @@ "ui.linenr.selected" = { bg = "base3" } "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } "ui.menu.selected" = { fg = "base2", bg = "yellow" } +"ui.virtual" = "base5" "info" = "base8" "hint" = "base8" diff --git a/runtime/themes/nord.toml b/runtime/themes/nord.toml index deb904520..9fd3fcab3 100644 --- a/runtime/themes/nord.toml +++ b/runtime/themes/nord.toml @@ -3,6 +3,7 @@ "ui.linenr.selected" = { fg = "nord4" } "ui.text.focus" = { fg = "nord8", modifiers= ["bold"] } "ui.menu.selected" = { fg = "nord8", bg = "nord2" } +"ui.virtual" = "gray" "info" = "nord8" "hint" = "nord8" diff --git a/runtime/themes/onedark.toml b/runtime/themes/onedark.toml index 1a3da452b..cf7dd2b06 100644 --- a/runtime/themes/onedark.toml +++ b/runtime/themes/onedark.toml @@ -47,6 +47,7 @@ diagnostic = { modifiers = ["underlined"] } "error" = { fg = "red", modifiers = ["bold"] } "ui.background" = { bg = "black" } +"ui.virtual" = { fg = "light-gray" } "ui.cursor" = { fg = "white", modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "white", modifiers = ["reversed"] } diff --git a/runtime/themes/rose_pine.toml b/runtime/themes/rose_pine.toml index d0197095f..d005ac8ad 100644 --- a/runtime/themes/rose_pine.toml +++ b/runtime/themes/rose_pine.toml @@ -15,6 +15,7 @@ "ui.text" = { fg = "text" } "ui.text.focus" = { fg = "foam", modifiers = ["bold"]} "ui.text.info" = {fg = "pine", modifiers = ["bold"]} +"ui.virtual" = "highlight" "operator" = "rose" "variable" = "text" "constant.numeric" = "iris" diff --git a/runtime/themes/rose_pine_dawn.toml b/runtime/themes/rose_pine_dawn.toml index 0dc7a3250..1a9ac7df2 100644 --- a/runtime/themes/rose_pine_dawn.toml +++ b/runtime/themes/rose_pine_dawn.toml @@ -15,6 +15,7 @@ "ui.text" = { fg = "text" } "ui.text.focus" = { fg = "foam", modifiers = ["bold"]} "ui.text.info" = {fg = "pine", modifiers = ["bold"]} +"ui.virtual" = "highlight" "operator" = "rose" "variable" = "text" "number" = "iris" diff --git a/runtime/themes/serika-dark.toml b/runtime/themes/serika-dark.toml index da1457808..3dd982d19 100644 --- a/runtime/themes/serika-dark.toml +++ b/runtime/themes/serika-dark.toml @@ -50,6 +50,7 @@ "ui.menu" = { fg = "fg", bg = "bg2" } "ui.menu.selected" = { fg = "bg0", bg = "bg_yellow" } "ui.selection" = { bg = "bg3" } +"ui.virtual" = "grey2" "hint" = "blue" "info" = "aqua" diff --git a/runtime/themes/serika-light.toml b/runtime/themes/serika-light.toml index edde90445..67c8328b7 100644 --- a/runtime/themes/serika-light.toml +++ b/runtime/themes/serika-light.toml @@ -50,6 +50,7 @@ "ui.menu" = { fg = "bg0", bg = "bg3" } "ui.menu.selected" = { fg = "bg0", bg = "bg_yellow" } "ui.selection" = { fg = "bg0", bg = "bg3" } +"ui.virtual" = { fg = "bg2" } "hint" = "blue" "info" = "aqua" diff --git a/runtime/themes/solarized_dark.toml b/runtime/themes/solarized_dark.toml index dd2013e20..f15e1fa0d 100644 --- a/runtime/themes/solarized_dark.toml +++ b/runtime/themes/solarized_dark.toml @@ -39,6 +39,8 @@ # 背景 "ui.background" = { bg = "base03" } +"ui.virtual" = { fg = "base01" } + # 行号栏 "ui.linenr" = { fg = "base0", bg = "base02" } # 当前行号栏 diff --git a/runtime/themes/solarized_light.toml b/runtime/themes/solarized_light.toml index 9c8202945..e535e9b0c 100644 --- a/runtime/themes/solarized_light.toml +++ b/runtime/themes/solarized_light.toml @@ -39,6 +39,8 @@ # 背景 "ui.background" = { bg = "base03" } +"ui.virtual" = { fg = "base01" } + # 行号栏 "ui.linenr" = { fg = "base0", bg = "base02" } # 当前行号栏 diff --git a/runtime/themes/spacebones_light.toml b/runtime/themes/spacebones_light.toml index 29c7d7f7e..80a193751 100644 --- a/runtime/themes/spacebones_light.toml +++ b/runtime/themes/spacebones_light.toml @@ -64,6 +64,7 @@ "ui.cursor.match" = { bg = "bg3" } "ui.menu" = { fg = "fg1", bg = "bg2" } "ui.menu.selected" = { fg = "#655370", bg = "#d1dcdf", modifiers = ["bold"] } +"ui.virtual" = "bg2" "diagnostic" = { modifiers = ["underlined"] } diff --git a/runtime/themes/tokyonight.toml b/runtime/themes/tokyonight.toml index 19d805a82..f783b2d5f 100644 --- a/runtime/themes/tokyonight.toml +++ b/runtime/themes/tokyonight.toml @@ -39,6 +39,7 @@ "ui.text" = { fg = "foreground" } "ui.text.focus" = { fg = "cyan" } "ui.window" = { fg = "black" } +"ui.virtual" = { fg = "comment" } "error" = { fg = "red" } "warning" = { fg = "yellow" } diff --git a/theme.toml b/theme.toml index d2c1fc32a..31ecd32e4 100644 --- a/theme.toml +++ b/theme.toml @@ -53,6 +53,7 @@ label = "honey" "ui.text" = { fg = "lavender" } "ui.text.focus" = { fg = "white" } +"ui.virtual" = { fg = "comet" } "ui.selection" = { bg = "#540099" } "ui.selection.primary" = { bg = "#540099" } From 35d2693630a4ec29a654704bc4be47badb8d6070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Wed, 20 Apr 2022 17:09:03 +0900 Subject: [PATCH 106/861] Revert "override nested arrays when merging TOML (#2145)" Looks like there's some follow-up issues This reverts commit c8cfd0b1a0da071618a9efc71ac5735d6147a0ca. --- helix-loader/src/config.rs | 2 +- helix-loader/src/lib.rs | 101 +++++++++---------------------------- 2 files changed, 24 insertions(+), 79 deletions(-) diff --git a/helix-loader/src/config.rs b/helix-loader/src/config.rs index 242af197a..5dc2d6b67 100644 --- a/helix-loader/src/config.rs +++ b/helix-loader/src/config.rs @@ -19,7 +19,7 @@ pub fn user_lang_config() -> Result { .into_iter() .chain([default_lang_config()].into_iter()) .fold(toml::Value::Table(toml::value::Table::default()), |a, b| { - crate::merge_toml_values(b, a, false) + crate::merge_toml_values(b, a) }); Ok(config) diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index 767bff7a4..de2951f8e 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -98,24 +98,8 @@ pub fn find_root_impl(root: Option<&str>, root_markers: &[String]) -> Vec toml::Value { +// right overrides left +pub fn merge_toml_values(left: toml::Value, right: toml::Value) -> toml::Value { use toml::Value; fn get_name(v: &Value) -> Option<&str> { @@ -124,35 +108,24 @@ pub fn merge_toml_values( match (left, right) { (Value::Array(mut left_items), Value::Array(right_items)) => { - // The top-level arrays should be merged but nested arrays should - // act as overrides. For the `languages.toml` config, this means - // that you can specify a sub-set of languages in an overriding - // `languages.toml` but that nested arrays like Language Server - // arguments are replaced instead of merged. - if merge_toplevel_arrays { - left_items.reserve(right_items.len()); - for rvalue in right_items { - let lvalue = get_name(&rvalue) - .and_then(|rname| { - left_items.iter().position(|v| get_name(v) == Some(rname)) - }) - .map(|lpos| left_items.remove(lpos)); - let mvalue = match lvalue { - Some(lvalue) => merge_toml_values(lvalue, rvalue, false), - None => rvalue, - }; - left_items.push(mvalue); - } - Value::Array(left_items) - } else { - Value::Array(right_items) + left_items.reserve(right_items.len()); + for rvalue in right_items { + let lvalue = get_name(&rvalue) + .and_then(|rname| left_items.iter().position(|v| get_name(v) == Some(rname))) + .map(|lpos| left_items.remove(lpos)); + let mvalue = match lvalue { + Some(lvalue) => merge_toml_values(lvalue, rvalue), + None => rvalue, + }; + left_items.push(mvalue); } + Value::Array(left_items) } (Value::Table(mut left_map), Value::Table(right_map)) => { for (rname, rvalue) in right_map { match left_map.remove(&rname) { Some(lvalue) => { - let merged_value = merge_toml_values(lvalue, rvalue, merge_toplevel_arrays); + let merged_value = merge_toml_values(lvalue, rvalue); left_map.insert(rname, merged_value); } None => { @@ -170,22 +143,23 @@ pub fn merge_toml_values( #[cfg(test)] mod merge_toml_tests { use super::merge_toml_values; - use toml::Value; #[test] - fn language_toml_map_merges() { - const USER: &str = r#" + fn language_tomls() { + use toml::Value; + + const USER: &str = " [[language]] - name = "nix" - test = "bbb" - indent = { tab-width = 4, unit = " ", test = "aaa" } - "#; + name = \"nix\" + test = \"bbb\" + indent = { tab-width = 4, unit = \" \", test = \"aaa\" } + "; let base: Value = toml::from_slice(include_bytes!("../../languages.toml")) .expect("Couldn't parse built-in languages config"); let user: Value = toml::from_str(USER).unwrap(); - let merged = merge_toml_values(base, user, true); + let merged = merge_toml_values(base, user); let languages = merged.get("language").unwrap().as_array().unwrap(); let nix = languages .iter() @@ -205,33 +179,4 @@ mod merge_toml_tests { // We didn't change comment-token so it should be same assert_eq!(nix.get("comment-token").unwrap().as_str().unwrap(), "#"); } - - #[test] - fn language_toml_nested_array_merges() { - const USER: &str = r#" - [[language]] - name = "typescript" - language-server = { command = "deno", args = ["lsp"] } - "#; - - let base: Value = toml::from_slice(include_bytes!("../../languages.toml")) - .expect("Couldn't parse built-in languages config"); - let user: Value = toml::from_str(USER).unwrap(); - - let merged = merge_toml_values(base, user, true); - let languages = merged.get("language").unwrap().as_array().unwrap(); - let ts = languages - .iter() - .find(|v| v.get("name").unwrap().as_str().unwrap() == "typescript") - .unwrap(); - assert_eq!( - ts.get("language-server") - .unwrap() - .get("args") - .unwrap() - .as_array() - .unwrap(), - &vec![Value::String("lsp".into())] - ) - } } From 5247d3ae2d19da1959534b676fdbea9c34b0df06 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Wed, 20 Apr 2022 15:44:00 +0200 Subject: [PATCH 107/861] dark_plus: Add the borders color from the original theme (#2186) --- runtime/themes/dark_plus.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/runtime/themes/dark_plus.toml b/runtime/themes/dark_plus.toml index 04e2bc9dc..6c9d59194 100644 --- a/runtime/themes/dark_plus.toml +++ b/runtime/themes/dark_plus.toml @@ -5,7 +5,7 @@ "type" = { fg = "type" } "type.builtin" = { fg = "type" } -"type.enum.variant" = { fg = "constant" } +"type.enum.variant" = { fg = "constant" } "constructor" = { fg = "constant" } "variable.other.member" = { fg = "variable" } @@ -78,7 +78,8 @@ "ui.text" = { fg = "text" } "ui.text.focus" = { fg = "white" } -"ui.virtual" = { fg = "dark_green" } +"ui.virtual" = { fg = "dark_gray" } +"ui.virtual.ruler" = { bg = "borders" } "warning" = { fg = "gold2" } "error" = { fg = "red" } @@ -117,3 +118,4 @@ background = "#1e1e1e" text = "#d4d4d4" cursor = "#a6a6a6" widget = "#252526" +borders = "#323232" From 961647719769e6b2baa8ae74630c16ab8963fa61 Mon Sep 17 00:00:00 2001 From: Erin van der Veen Date: Wed, 20 Apr 2022 16:31:59 +0200 Subject: [PATCH 108/861] Add Nickel language (#2173) --- book/src/generated/lang-support.md | 1 + languages.toml | 15 ++++++ runtime/queries/nickel/highlights.scm | 67 +++++++++++++++++++++++++++ runtime/queries/nickel/indents.scm | 17 +++++++ 4 files changed, 100 insertions(+) create mode 100644 runtime/queries/nickel/highlights.scm create mode 100644 runtime/queries/nickel/indents.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 55b928622..a1746c4c4 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -46,6 +46,7 @@ | make | ✓ | | | | | markdown | ✓ | | | | | mint | | | | `mint` | +| nickel | ✓ | | ✓ | `nls` | | nix | ✓ | | ✓ | `rnix-lsp` | | ocaml | ✓ | | ✓ | `ocamllsp` | | ocaml-interface | ✓ | | | `ocamllsp` | diff --git a/languages.toml b/languages.toml index 6e78e78a5..fb54427d8 100644 --- a/languages.toml +++ b/languages.toml @@ -380,6 +380,21 @@ indent = { tab-width = 4, unit = " " } name = "python" source = { git = "https://github.com/tree-sitter/tree-sitter-python", rev = "d6210ceab11e8d812d4ab59c07c81458ec6e5184" } +[[language]] +name = "nickel" +scope = "source.nickel" +injection-regex = "nickel" +file-types = ["ncl"] +shebangs = [] +roots = [] +comment-token = "#" +language-server = { command = "nls" } +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "nickel" +source = { git = "https://github.com/nickel-lang/tree-sitter-nickel", rev = "85348774ccf7624fac72703b2264d18b6f572be6" } + [[language]] name = "nix" scope = "source.nix" diff --git a/runtime/queries/nickel/highlights.scm b/runtime/queries/nickel/highlights.scm new file mode 100644 index 000000000..a204dfcac --- /dev/null +++ b/runtime/queries/nickel/highlights.scm @@ -0,0 +1,67 @@ +(types) @type +(type_builtin) @type.builtin +"Array" @type.builtin + +(enum_tag) @constructor + +"null" @constant.builtin +(bool) @constant.builtin.boolean +(str_esc_char) @constant.character.escape +(num_literal) @constant.numeric + +(str_chunks) @string + +; NOTE: Nickel has no block comments +(comment) @comment.line +; Nickel doesn't use comments for documentation, ideally this would be +; `@documentation` or something similar +(annot_atom + doc: (static_string) @comment.block.documentation +) + +(record_operand (atom (ident) @variable)) +(let_expr + "let" @keyword + pat: (pattern + (ident) @variable + ) + "in" @keyword +) +(fun_expr + "fun" @keyword.function + pats: + (pattern + id: (ident) @variable.parameter + )+ + "=>" @operator +) +(record_field) @variable.other.member + +[ + "." +] @punctuation.delimiter +[ + "{" "}" + "(" ")" + "[|" "|]" + "[" "]" +] @punctuation.bracket +(multstr_start) @punctuation.bracket +(multstr_end) @punctuation.bracket +(interpolation_start) @punctuation.bracket +(interpolation_end) @punctuation.bracket + +["forall" "default" "doc"] @keyword +["if" "then" "else" "switch"] @keyword.control.conditional +"import" @keyword.control.import + +(infix_expr + op: (_) @operator +) + +(applicative + t1: (applicative + (record_operand) @function + ) +) +(builtin) @function.builtin diff --git a/runtime/queries/nickel/indents.scm b/runtime/queries/nickel/indents.scm new file mode 100644 index 000000000..8be5a6bd2 --- /dev/null +++ b/runtime/queries/nickel/indents.scm @@ -0,0 +1,17 @@ +[ + (fun_expr) + (let_expr) + (switch_expr) + (ite_expr) + + (uni_record) + (str_chunks_multi) + "[" + "[|" +] @indent + +[ + "}" + "]" + "|]" +] @outdent From b0bceb5674717c2c9f2d3b4c5526107d1c084e31 Mon Sep 17 00:00:00 2001 From: Jappie Klooster Date: Wed, 20 Apr 2022 10:55:09 -0400 Subject: [PATCH 109/861] Fix nix shell by hardcoding the flakecompat library (#2196) --- shell.nix | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/shell.nix b/shell.nix index 5c5a774e7..c0d998e3d 100644 --- a/shell.nix +++ b/shell.nix @@ -1,6 +1,9 @@ # Flake's devShell for non-flake-enabled nix instances let - src = (builtins.fromJSON (builtins.readFile ./flake.lock)).nodes.flakeCompat.locked; - compat = fetchTarball { url = "https://github.com/edolstra/flake-compat/archive/${src.rev}.tar.gz"; sha256 = src.narHash; }; + compat = + builtins.fetchGit { + url = "https://github.com/edolstra/flake-compat.git"; + rev = "b4a34015c698c7793d592d66adbab377907a2be8"; + }; in (import compat { src = ./.; }).shellNix.default From 8d335f63f00755c33721b656f289357d3bd5dfb7 Mon Sep 17 00:00:00 2001 From: ttys3 <41882455+ttys3@users.noreply.github.com> Date: Thu, 21 Apr 2022 00:08:57 +0800 Subject: [PATCH 110/861] chore(filetype): bash and hcl file type add more common used extensions or files (#2201) --- languages.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/languages.toml b/languages.toml index fb54427d8..fdf794a62 100644 --- a/languages.toml +++ b/languages.toml @@ -429,7 +429,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-ruby", rev = "dfff6 name = "bash" scope = "source.bash" injection-regex = "bash" -file-types = ["sh", "bash", "zsh", ".bash_login", ".bash_logout", ".bash_profile", ".bashrc", ".profile", ".zshenv", ".zlogin", ".zlogout", ".zprofile", ".zshrc"] +file-types = ["sh", "bash", "zsh", ".bash_login", ".bash_logout", ".bash_profile", ".bashrc", ".profile", ".zshenv", ".zlogin", ".zlogout", ".zprofile", ".zshrc", "APKBUILD", "PKGBUILD", "eclass", "ebuild"] shebangs = ["sh", "bash", "dash"] roots = [] comment-token = "#" @@ -1007,8 +1007,8 @@ source = { git = "https://github.com/fwcd/tree-sitter-kotlin", rev = "a4f71eb9b8 [[language]] name = "hcl" scope = "source.hcl" -injection-regex = "(hcl|tf)" -file-types = ["hcl", "tf", "tfvars"] +injection-regex = "(hcl|tf|nomad)" +file-types = ["hcl", "tf", "tfvars", "nomad"] roots = [] comment-token = "#" indent = { tab-width = 2, unit = " " } From 4144c9d2f2e712475d0ee54d029653f2c7dffff5 Mon Sep 17 00:00:00 2001 From: ttys3 <41882455+ttys3@users.noreply.github.com> Date: Thu, 21 Apr 2022 00:16:02 +0800 Subject: [PATCH 111/861] feat(lang): add go.mod and go.work support (#2197) --- book/src/generated/lang-support.md | 2 ++ languages.toml | 32 ++++++++++++++++++++++++++- runtime/queries/gomod/highlights.scm | 17 ++++++++++++++ runtime/queries/gomod/injections.scm | 2 ++ runtime/queries/gowork/highlights.scm | 14 ++++++++++++ runtime/queries/gowork/injections.scm | 2 ++ 6 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/gomod/highlights.scm create mode 100644 runtime/queries/gomod/injections.scm create mode 100644 runtime/queries/gowork/highlights.scm create mode 100644 runtime/queries/gowork/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index a1746c4c4..ef3c94513 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -24,6 +24,8 @@ | gleam | ✓ | | | | | glsl | ✓ | | ✓ | | | go | ✓ | ✓ | ✓ | `gopls` | +| gomod | ✓ | | | `gopls` | +| gowork | ✓ | | | `gopls` | | graphql | ✓ | | | | | haskell | ✓ | | | `haskell-language-server-wrapper` | | hcl | ✓ | | ✓ | `terraform-ls` | diff --git a/languages.toml b/languages.toml index fdf794a62..76b4ca167 100644 --- a/languages.toml +++ b/languages.toml @@ -268,6 +268,36 @@ args = { mode = "local", processId = "{0}" } name = "go" source = { git = "https://github.com/tree-sitter/tree-sitter-go", rev = "0fa917a7022d1cd2e9b779a6a8fc5dc7fad69c75" } +[[language]] +name = "gomod" +scope = "source.gomod" +injection-regex = "gomod" +file-types = ["go.mod"] +roots = [] +auto-format = true +comment-token = "//" +language-server = { command = "gopls" } +indent = { tab-width = 4, unit = "\t" } + +[[grammar]] +name = "gomod" +source = { git = "https://github.com/camdencheek/tree-sitter-go-mod", rev = "e8f51f8e4363a3d9a427e8f63f4c1bbc5ef5d8d0" } + +[[language]] +name = "gowork" +scope = "source.gowork" +injection-regex = "gowork" +file-types = ["go.work"] +roots = [] +auto-format = true +comment-token = "//" +language-server = { command = "gopls" } +indent = { tab-width = 4, unit = "\t" } + +[[grammar]] +name = "gowork" +source = { git = "https://github.com/omertuc/tree-sitter-go-work", rev = "6dd9dd79fb51e9f2abc829d5e97b15015b6a8ae2" } + [[language]] name = "javascript" scope = "source.js" @@ -998,7 +1028,7 @@ file-types = ["kt", "kts"] roots = ["settings.gradle", "settings.gradle.kts"] comment-token = "//" indent = { tab-width = 4, unit = " " } -language-server = { command = "kotlin-language-server" } +language-server = { command = "kotlin-language-server" } [[grammar]] name = "kotlin" diff --git a/runtime/queries/gomod/highlights.scm b/runtime/queries/gomod/highlights.scm new file mode 100644 index 000000000..63e1f0128 --- /dev/null +++ b/runtime/queries/gomod/highlights.scm @@ -0,0 +1,17 @@ +[ + "require" + "replace" + "go" + "exclude" + "retract" + "module" +] @keyword + +"=>" @operator + +(comment) @comment + +[ +(version) +(go_version) +] @string diff --git a/runtime/queries/gomod/injections.scm b/runtime/queries/gomod/injections.scm new file mode 100644 index 000000000..321c90add --- /dev/null +++ b/runtime/queries/gomod/injections.scm @@ -0,0 +1,2 @@ +((comment) @injection.content + (#set! injection.language "comment")) diff --git a/runtime/queries/gowork/highlights.scm b/runtime/queries/gowork/highlights.scm new file mode 100644 index 000000000..9c84bcc44 --- /dev/null +++ b/runtime/queries/gowork/highlights.scm @@ -0,0 +1,14 @@ +[ + "replace" + "go" + "use" +] @keyword + +"=>" @operator + +(comment) @comment + +[ +(version) +(go_version) +] @string diff --git a/runtime/queries/gowork/injections.scm b/runtime/queries/gowork/injections.scm new file mode 100644 index 000000000..321c90add --- /dev/null +++ b/runtime/queries/gowork/injections.scm @@ -0,0 +1,2 @@ +((comment) @injection.content + (#set! injection.language "comment")) From 6de2e7634fc0badd2b8cfdee4e5f0639684138f0 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 20 Apr 2022 13:04:17 -0500 Subject: [PATCH 112/861] Document `ui.virtual.ruler` scope in theme docs (#2199) From the rulers feature (#2060) --- book/src/themes.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/book/src/themes.md b/book/src/themes.md index 9009e2cad..91ca18b10 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -224,6 +224,7 @@ These scopes are used for theming the editor interface. | `ui.text` | Command prompts, popup text, etc. | | `ui.text.focus` | | | `ui.text.info` | The key: command text in `ui.popup.info` boxes | +| `ui.virtual.ruler` | Ruler columns (see the [`editor.rulers` config][rulers-config])| | `ui.virtual.whitespace` | Visible white-space characters | | `ui.menu` | Code and command completion menus | | `ui.menu.selected` | Selected autocomplete item | @@ -234,3 +235,5 @@ These scopes are used for theming the editor interface. | `info` | Diagnostics info (gutter) | | `hint` | Diagnostics hint (gutter) | | `diagnostic` | For text in editing area | + +[rulers-config]: ./configuration.md#editor-section From 3c250b7528175e67717a3c6d11be7409023d5a16 Mon Sep 17 00:00:00 2001 From: Jens Getreu Date: Fri, 22 Apr 2022 15:54:43 +0200 Subject: [PATCH 113/861] Add `autumn` theme (#2212) Co-authored-by: Jens Getreu --- runtime/themes/autumn.toml | 82 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 runtime/themes/autumn.toml diff --git a/runtime/themes/autumn.toml b/runtime/themes/autumn.toml new file mode 100644 index 000000000..fcad5003d --- /dev/null +++ b/runtime/themes/autumn.toml @@ -0,0 +1,82 @@ +# The structure is based on `base16_default_dark` by Ray Gervais. Most of +# the colors come the so called Autumn theme, a color scheme inspired by +# the colors you can find in autumn. Originally it was designed as a +# color scheme for the Komodo IDE and then ported to Vim by Kenneth Love +# and Chris Jones. Later, Yorick Peterse improved their work. See: +# +# Jens Getreu finally 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_gray4", bg = "my_gray2" } +"ui.popup" = { bg = "my_gray2" } +"ui.window" = { bg = "my_gray2" } +"ui.linenr.selected" = { fg = "my_gray5", bg = "my_gray2", modifiers = ["bold"] } +"ui.selection" = { bg = "my_gray3" } +"comment" = { fg = "my_gray4", modifiers = ["italic"] } +"ui.statusline" = { fg = "my_gray5", bg = "my_gray2" } +"ui.help" = { fg = "my_gray5", bg = "my_gray2" } +"ui.cursor" = { fg = "my_gray5", modifiers = ["reversed"] } +"ui.cursor.primary" = { fg = "my_white", modifiers = ["reversed"] } +"ui.text" = "my_white" +"operator" = "my_white" +"ui.text.focus" = "my_white" +"variable" = "my_white3" +"constant.numeric" = "my_turquoise" +"constant" = "my_white3" +"attributes" = "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_yellow" +"constructor" = "my_yellow" +"special" = "my_yellow" +"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_yellow" +"markup.list" = "my_white2" +"markup.bold" = { fg = "my_white3", modifiers = ["bold"] } +"markup.italic" = { fg = "my_white3", modifiers = ["italic"] } +"markup.link.url" = { fg = "my_green", modifiers = ["underlined"] } +"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_gray2" } +"info" = "my_yellow" +"hint" = "my_gray4" +"debug" = "my_gray4" +"warning" = "my_yellow" +"error" = "my_red" + +[palette] +my_gray0 = "#292929" # Default Background +my_gray1 = "#2e2e2e" # Ruler +my_gray2 = "#3a3a3a" # Lighter Background (Used for status bars, line number and folding marks) +my_gray3 = "#525252" # Selection Background +my_gray4 = "#7c7c7c" # Comments, Invisibles, Line Highlighting +my_gray5 = "#aaaaaa" # Dark Foreground (Used for status bars) +my_white = "#F3F2CC" # Default Foreground, Caret, Delimiters, Operators +my_gray6 = "#e8e8e8" # Light Foreground (Not often used) +my_gray7 = "#f8f8f8" # Light Background (Not often used) +my_white2 = "#F3F2CC" # Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted +my_turquoise = "#86c1b9" # Support, Regular Expressions, Escape Characters, Markup Quotes +my_white3 = "#F3F2CC" # Classes, Markup Bold, Search Text Background +my_green = "#8daf67" # Strings, Inherited Class, Markup Code, Diff Inserted +my_brown = "#cfba8b" # Member variables +my_yellow = "#FAD566" # Functions, Methods, Attribute IDs, Headings +my_red = "#F05E48" # Keywords, Storage, Selector, Markup Italic, Diff Changed From 5c2570582bdacf7acebf1bf4cab90699b98ecc67 Mon Sep 17 00:00:00 2001 From: Justin Ma Date: Fri, 22 Apr 2022 22:37:51 +0800 Subject: [PATCH 114/861] feat(lang): add nushell language support (#2225) Co-authored-by: Michael Davis --- book/src/generated/lang-support.md | 1 + languages.toml | 13 +++++++ runtime/queries/nu/folds.scm | 4 +++ runtime/queries/nu/highlights.scm | 55 ++++++++++++++++++++++++++++++ runtime/queries/nu/injections.scm | 2 ++ runtime/queries/nu/locals.scm | 13 +++++++ 6 files changed, 88 insertions(+) create mode 100644 runtime/queries/nu/folds.scm create mode 100644 runtime/queries/nu/highlights.scm create mode 100644 runtime/queries/nu/injections.scm create mode 100644 runtime/queries/nu/locals.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index ef3c94513..7292b61ba 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -50,6 +50,7 @@ | mint | | | | `mint` | | nickel | ✓ | | ✓ | `nls` | | nix | ✓ | | ✓ | `rnix-lsp` | +| nu | ✓ | | | | | ocaml | ✓ | | ✓ | `ocamllsp` | | ocaml-interface | ✓ | | | `ocamllsp` | | org | ✓ | | | | diff --git a/languages.toml b/languages.toml index 76b4ca167..3b2eedf2c 100644 --- a/languages.toml +++ b/languages.toml @@ -1210,3 +1210,16 @@ indent = { tab-width = 4, unit = " " } [[grammar]] name = "gdscript" source = { git = "https://github.com/PrestonKnopp/tree-sitter-gdscript", rev = "2a6abdaa47fcb91397e09a97c7433fd995ea46c6" } + +[[language]] +name = "nu" +scope = "source.nu" +injection-regex = "nu" +file-types = ["nu"] +roots = [] +comment-token = "#" +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "nu" +source = { git = "https://github.com/LhKipp/tree-sitter-nu", rev = "db4e990b78824c8abef3618e0f93b7fe1e8f4c0d" } diff --git a/runtime/queries/nu/folds.scm b/runtime/queries/nu/folds.scm new file mode 100644 index 000000000..f6b5acb15 --- /dev/null +++ b/runtime/queries/nu/folds.scm @@ -0,0 +1,4 @@ +[ + (function_definition) + (block) +] @fold diff --git a/runtime/queries/nu/highlights.scm b/runtime/queries/nu/highlights.scm new file mode 100644 index 000000000..b643a63af --- /dev/null +++ b/runtime/queries/nu/highlights.scm @@ -0,0 +1,55 @@ +(string) @string +(type) @type +(value_path) @variable +(comment) @comment + +(number_literal) @constant.numeric +(range from: (number_literal) @constant.numeric) +(range to: (number_literal) @constant.numeric) + +(command cmd_name: (identifier) @function) +(function_definition func_name: (identifier) @function) + +[ + (variable_declaration name: (identifier)) + (parameter (identifier)) + (flag (flag_name)) + (flag (flag_shorthand_name)) + (record_entry entry_name: (identifier)) + (block_args block_param: (identifier)) +] @variable.other.member +; (parameter (identifier) @variable.parameter) ; -- alternative highlighting group? + +(cmd_invocation) @embedded + + +((identifier) @constant + (#match? @constant "^[A-Z][A-Z\\d_]*$")) + +[ + "if" + "else" + "let" + "def" + "export" +] @keyword + +[ + ; "/" Not making / an operator may lead to better highlighting? + "$" + "|" + "+" + "-" + "*" + "=" + "!=" + "&&" + "||" + "==" + ">" +] @operator + +["." + "," + ";" +] @punctuation.delimiter diff --git a/runtime/queries/nu/injections.scm b/runtime/queries/nu/injections.scm new file mode 100644 index 000000000..321c90add --- /dev/null +++ b/runtime/queries/nu/injections.scm @@ -0,0 +1,2 @@ +((comment) @injection.content + (#set! injection.language "comment")) diff --git a/runtime/queries/nu/locals.scm b/runtime/queries/nu/locals.scm new file mode 100644 index 000000000..2a341f80e --- /dev/null +++ b/runtime/queries/nu/locals.scm @@ -0,0 +1,13 @@ +; Scopes +(function_definition) @scope + +; Definitions +(variable_declaration + name: (identifier) @definition.var) + +(function_definition + func_name: (identifier) @definition.function) + +; References +(value_path) @reference +(word) @reference From dd5a7c6191314b22347c323e8cda8aff225e21ba Mon Sep 17 00:00:00 2001 From: Kirawi <67773714+kirawi@users.noreply.github.com> Date: Sat, 23 Apr 2022 04:01:08 -0400 Subject: [PATCH 115/861] Replace line endings using `set_line_ending` command (#1871) * set_line_ending: now replace line endings * use ending.len_chars() directly * account for unicode-lines feaure in line-ending doc --- book/src/generated/typable-cmd.md | 2 +- helix-term/src/commands/typed.rs | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 0b591ba4a..33f3b8392 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -16,7 +16,7 @@ | `:new`, `:n` | Create a new scratch buffer. | | `:format`, `:fmt` | Format the file using the LSP formatter. | | `:indent-style` | Set the indentation style for editing. ('t' for tabs or 1-8 for number of spaces.) | -| `:line-ending` | Set the document's default line ending. Options: crlf, lf, cr, ff, nel. | +| `:line-ending` | Set the document's default line ending. Options: crlf, lf. | | `:earlier`, `:ear` | Jump back to an earlier point in edit history. Accepts a number of steps or a time span. | | `:later`, `:lat` | Jump to a later point in edit history. Accepts a number of steps or a time span. | | `:write-quit`, `:wq`, `:x` | Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt) | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 9a5298bba..d44bcf75d 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -352,8 +352,26 @@ fn set_line_ending( arg if arg.starts_with("nel") => Nel, _ => bail!("invalid line ending"), }; + let (view, doc) = current!(cx.editor); + doc.line_ending = line_ending; + + let mut pos = 0; + let transaction = Transaction::change( + doc.text(), + doc.text().lines().filter_map(|line| { + pos += line.len_chars(); + match helix_core::line_ending::get_line_ending(&line) { + Some(ending) if ending != line_ending => { + let start = pos - ending.len_chars(); + let end = pos; + Some((start, end, Some(line_ending.as_str().into()))) + } + _ => None, + } + }), + ); + doc.apply(&transaction, view.id); - doc_mut!(cx.editor).line_ending = line_ending; Ok(()) } @@ -1193,6 +1211,9 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "line-ending", aliases: &[], + #[cfg(not(feature = "unicode-lines"))] + doc: "Set the document's default line ending. Options: crlf, lf.", + #[cfg(feature = "unicode-lines")] doc: "Set the document's default line ending. Options: crlf, lf, cr, ff, nel.", fun: set_line_ending, completer: None, From c1d3d49f3f47a991e38e21d96dee3f9081c9a663 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sat, 23 Apr 2022 16:03:52 +0800 Subject: [PATCH 116/861] Fix ctrl-u on insert behavior (#1957) * Fix ctrl-u on insert behavior Now should follow vim behavior more - no longer remove text on cursor - no longer remove selected text while inserting - first kill to start non-whitespace, start, previous new line * Add comment for c-u parts --- helix-term/src/commands.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 4e13f74ad..504de73f2 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -681,7 +681,24 @@ fn kill_to_line_start(cx: &mut Context) { let selection = doc.selection(view.id).clone().transform(|range| { let line = range.cursor_line(text); - range.put_cursor(text, text.line_to_char(line), true) + let first_char = text.line_to_char(line); + let anchor = range.cursor(text); + let head = if anchor == first_char && line != 0 { + // select until previous line + line_end_char_index(&text, line - 1) + } else if let Some(pos) = find_first_non_whitespace_char(text.line(line)) { + if first_char + pos < anchor { + // select until first non-blank in line if cursor is after it + first_char + pos + } else { + // select until start of line + first_char + } + } else { + // select until start of line + first_char + }; + Range::new(head, anchor) }); delete_selection_insert_mode(doc, view, &selection); } From 19d042dde6ac7aad5b597c791c1f142f5c7f7198 Mon Sep 17 00:00:00 2001 From: ttys3 <41882455+ttys3@users.noreply.github.com> Date: Sat, 23 Apr 2022 16:09:16 +0800 Subject: [PATCH 117/861] chore(lsp): check rename capabilities before send rename action (#2203) --- helix-lsp/src/client.rs | 14 ++++++++++++++ helix-term/src/commands/lsp.rs | 6 ++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index dba134fc3..2459554c1 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -3,6 +3,7 @@ use crate::{ Call, Error, OffsetEncoding, Result, }; +use anyhow::anyhow; use helix_core::{find_root, ChangeSet, Rope}; use jsonrpc_core as jsonrpc; use lsp_types as lsp; @@ -861,6 +862,19 @@ impl Client { position: lsp::Position, new_name: String, ) -> anyhow::Result { + let capabilities = self.capabilities.get().unwrap(); + + // check if we're able to rename + match capabilities.rename_provider { + Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (), + // None | Some(false) + _ => { + let err = "The server does not support rename"; + log::warn!("rename_symbol failed: {}", err); + return Err(anyhow!(err)); + } + }; + let params = lsp::RenameParams { text_document_position: lsp::TextDocumentPositionParams { text_document, diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 0a12ae392..90a1ad7f8 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -674,8 +674,10 @@ 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()); - let edits = block_on(task).unwrap_or_default(); - apply_workspace_edit(cx.editor, offset_encoding, &edits); + match block_on(task) { + Ok(edits) => apply_workspace_edit(cx.editor, offset_encoding, &edits), + Err(err) => cx.editor.set_error(err.to_string()), + } }, ); } From 2c7f770aa9b094afca4454c8e85c8a963112ec32 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 23 Apr 2022 03:10:34 -0500 Subject: [PATCH 118/861] Only merge top-level array when merging `languages.toml` (#2215) * Revert "Revert "override nested arrays when merging TOML (#2145)"" This reverts commit 35d2693630a4ec29a654704bc4be47badb8d6070. * flip top-level table merging flag --- helix-loader/src/config.rs | 2 +- helix-loader/src/lib.rs | 101 ++++++++++++++++++++++++++++--------- 2 files changed, 79 insertions(+), 24 deletions(-) diff --git a/helix-loader/src/config.rs b/helix-loader/src/config.rs index 5dc2d6b67..a8c843612 100644 --- a/helix-loader/src/config.rs +++ b/helix-loader/src/config.rs @@ -19,7 +19,7 @@ pub fn user_lang_config() -> Result { .into_iter() .chain([default_lang_config()].into_iter()) .fold(toml::Value::Table(toml::value::Table::default()), |a, b| { - crate::merge_toml_values(b, a) + crate::merge_toml_values(b, a, true) }); Ok(config) diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index de2951f8e..767bff7a4 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -98,8 +98,24 @@ pub fn find_root_impl(root: Option<&str>, root_markers: &[String]) -> Vec toml::Value { +/// Merge two TOML documents, merging values from `right` onto `left` +/// +/// When an array exists in both `left` and `right`, `right`'s array is +/// used. When a table exists in both `left` and `right`, the merged table +/// consists of all keys in `left`'s table unioned with all keys in `right` +/// with the values of `right` being merged recursively onto values of +/// `left`. +/// +/// `merge_toplevel_arrays` controls whether a top-level array in the TOML +/// document is merged instead of overridden. This is useful for TOML +/// documents that use a top-level array of values like the `languages.toml`, +/// where one usually wants to override or add to the array instead of +/// replacing it altogether. +pub fn merge_toml_values( + left: toml::Value, + right: toml::Value, + merge_toplevel_arrays: bool, +) -> toml::Value { use toml::Value; fn get_name(v: &Value) -> Option<&str> { @@ -108,24 +124,35 @@ pub fn merge_toml_values(left: toml::Value, right: toml::Value) -> toml::Value { match (left, right) { (Value::Array(mut left_items), Value::Array(right_items)) => { - left_items.reserve(right_items.len()); - for rvalue in right_items { - let lvalue = get_name(&rvalue) - .and_then(|rname| left_items.iter().position(|v| get_name(v) == Some(rname))) - .map(|lpos| left_items.remove(lpos)); - let mvalue = match lvalue { - Some(lvalue) => merge_toml_values(lvalue, rvalue), - None => rvalue, - }; - left_items.push(mvalue); + // The top-level arrays should be merged but nested arrays should + // act as overrides. For the `languages.toml` config, this means + // that you can specify a sub-set of languages in an overriding + // `languages.toml` but that nested arrays like Language Server + // arguments are replaced instead of merged. + if merge_toplevel_arrays { + left_items.reserve(right_items.len()); + for rvalue in right_items { + let lvalue = get_name(&rvalue) + .and_then(|rname| { + left_items.iter().position(|v| get_name(v) == Some(rname)) + }) + .map(|lpos| left_items.remove(lpos)); + let mvalue = match lvalue { + Some(lvalue) => merge_toml_values(lvalue, rvalue, false), + None => rvalue, + }; + left_items.push(mvalue); + } + Value::Array(left_items) + } else { + Value::Array(right_items) } - Value::Array(left_items) } (Value::Table(mut left_map), Value::Table(right_map)) => { for (rname, rvalue) in right_map { match left_map.remove(&rname) { Some(lvalue) => { - let merged_value = merge_toml_values(lvalue, rvalue); + let merged_value = merge_toml_values(lvalue, rvalue, merge_toplevel_arrays); left_map.insert(rname, merged_value); } None => { @@ -143,23 +170,22 @@ pub fn merge_toml_values(left: toml::Value, right: toml::Value) -> toml::Value { #[cfg(test)] mod merge_toml_tests { use super::merge_toml_values; + use toml::Value; #[test] - fn language_tomls() { - use toml::Value; - - const USER: &str = " + fn language_toml_map_merges() { + const USER: &str = r#" [[language]] - name = \"nix\" - test = \"bbb\" - indent = { tab-width = 4, unit = \" \", test = \"aaa\" } - "; + name = "nix" + test = "bbb" + indent = { tab-width = 4, unit = " ", test = "aaa" } + "#; let base: Value = toml::from_slice(include_bytes!("../../languages.toml")) .expect("Couldn't parse built-in languages config"); let user: Value = toml::from_str(USER).unwrap(); - let merged = merge_toml_values(base, user); + let merged = merge_toml_values(base, user, true); let languages = merged.get("language").unwrap().as_array().unwrap(); let nix = languages .iter() @@ -179,4 +205,33 @@ mod merge_toml_tests { // We didn't change comment-token so it should be same assert_eq!(nix.get("comment-token").unwrap().as_str().unwrap(), "#"); } + + #[test] + fn language_toml_nested_array_merges() { + const USER: &str = r#" + [[language]] + name = "typescript" + language-server = { command = "deno", args = ["lsp"] } + "#; + + let base: Value = toml::from_slice(include_bytes!("../../languages.toml")) + .expect("Couldn't parse built-in languages config"); + let user: Value = toml::from_str(USER).unwrap(); + + let merged = merge_toml_values(base, user, true); + let languages = merged.get("language").unwrap().as_array().unwrap(); + let ts = languages + .iter() + .find(|v| v.get("name").unwrap().as_str().unwrap() == "typescript") + .unwrap(); + assert_eq!( + ts.get("language-server") + .unwrap() + .get("args") + .unwrap() + .as_array() + .unwrap(), + &vec![Value::String("lsp".into())] + ) + } } From 1c1ba006aed87b1f26cf8e337a1cb04d1b21879a Mon Sep 17 00:00:00 2001 From: Lukas Date: Sat, 23 Apr 2022 15:38:29 +0200 Subject: [PATCH 119/861] feat(lsp): add yaml lsp (#2234) --- book/src/generated/lang-support.md | 2 +- languages.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 7292b61ba..259ffe002 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -80,5 +80,5 @@ | typescript | ✓ | | ✓ | `typescript-language-server` | | vue | ✓ | | | `vls` | | wgsl | ✓ | | | | -| yaml | ✓ | | ✓ | | +| yaml | ✓ | | ✓ | `yaml-language-server` | | zig | ✓ | | ✓ | `zls` | diff --git a/languages.toml b/languages.toml index 3b2eedf2c..19d42e963 100644 --- a/languages.toml +++ b/languages.toml @@ -644,6 +644,7 @@ file-types = ["yml", "yaml"] roots = [] comment-token = "#" indent = { tab-width = 2, unit = " " } +language-server = { command = "yaml-language-server", args = ["--stdio"] } injection-regex = "yml|yaml" [[grammar]] From 6047506ec56787e5a87d0dfe9cb90646004becf5 Mon Sep 17 00:00:00 2001 From: Paul Graydon <43348144+paulgraydon@users.noreply.github.com> Date: Sat, 23 Apr 2022 15:56:43 +0200 Subject: [PATCH 120/861] Add tokyonight_storm theme variant (#2240) --- runtime/themes/tokyonight.toml | 4 +- runtime/themes/tokyonight_storm.toml | 82 ++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 runtime/themes/tokyonight_storm.toml diff --git a/runtime/themes/tokyonight.toml b/runtime/themes/tokyonight.toml index f783b2d5f..b41ff6f71 100644 --- a/runtime/themes/tokyonight.toml +++ b/runtime/themes/tokyonight.toml @@ -38,8 +38,8 @@ "ui.statusline.inactive" = { fg = "foreground_gutter", bg = "background_menu" } "ui.text" = { fg = "foreground" } "ui.text.focus" = { fg = "cyan" } +"ui.virtual" = { fg = "foreground_gutter" } "ui.window" = { fg = "black" } -"ui.virtual" = { fg = "comment" } "error" = { fg = "red" } "warning" = { fg = "yellow" } @@ -76,7 +76,7 @@ comment = "#565f89" black = "#414868" foreground = "#a9b1d6" foreground_highlight = "#c0caf5" -foreground_gutter = "#3b4261" +foreground_gutter = "#363b54" background = "#1a1b26" background_highlight = "#30374b" background_menu = "#16161e" diff --git a/runtime/themes/tokyonight_storm.toml b/runtime/themes/tokyonight_storm.toml new file mode 100644 index 000000000..4a018a285 --- /dev/null +++ b/runtime/themes/tokyonight_storm.toml @@ -0,0 +1,82 @@ +# Author: Paul Graydon + +"comment" = { fg = "comment", modifiers = ["italic"] } +"constant" = { fg = "orange" } +"constant.character.escape" = { fg = "magenta" } +"function" = { fg = "blue", modifiers = ["italic"] } +"keyword" = { fg = "magenta" } +"keyword.control.import" = { fg = "cyan" } +"operator" = { fg = "turquoise" } +"punctuation" = { fg = "turquoise" } +"string" = { fg = "light-green" } +"string.regexp" = { fg = "light-blue" } +"tag" = { fg = "red" } +"type" = { fg = "teal" } +"namespace" = { fg = "blue" } +"variable" = { fg = "white" } +"variable.builtin" = { fg = "red", modifiers = ["italic"] } +"variable.other.member" = { fg = "magenta" } +"variable.parameter" = { fg = "yellow", modifiers = ["italic"] } + +"diff.plus" = { fg = "green" } +"diff.delta" = { fg = "orange" } +"diff.minus" = { fg = "red" } + +"ui.background" = { fg = "foreground", bg = "background" } +"ui.cursor" = { modifiers = ["reversed"] } +"ui.cursor.match" = { fg = "orange", modifiers = ["bold"] } +"ui.cursor.primary" = { modifiers = ["reversed"] } +"ui.help" = { fg = "foreground", bg = "background_menu" } +"ui.linenr" = { fg = "foreground_gutter" } +"ui.linenr.selected" = { fg = "foreground" } +"ui.menu" = { fg = "foreground", bg = "background_menu" } +"ui.menu.selected" = { bg = "background_highlight" } +"ui.popup" = { fg = "foreground", bg = "background_menu" } +"ui.selection" = { bg = "background_highlight" } +"ui.selection.primary" = { bg = "background_highlight" } +"ui.statusline" = { fg = "foreground", bg = "background_menu" } +"ui.statusline.inactive" = { fg = "foreground_gutter", bg = "background_menu" } +"ui.text" = { fg = "foreground" } +"ui.text.focus" = { fg = "cyan" } +"ui.virtual" = { fg = "foreground_gutter" } +"ui.window" = { fg = "black" } + +"error" = { fg = "red" } +"warning" = { fg = "yellow" } +"info" = { fg = "blue" } +"hint" = { fg = "teal" } +"diagnostic" = { modifiers = ["underlined"] } +"special" = { fg = "orange" } + +"markup.heading" = { fg = "cyan", modifiers = ["bold"] } +"markup.list" = { fg = "cyan" } +"markup.bold" = { fg = "orange", modifiers = ["bold"] } +"markup.italic" = { fg = "yellow", modifiers = ["italic"] } +"markup.link.url" = { fg = "green" } +"markup.link.text" = { fg = "light-gray" } +"markup.quote" = { fg = "yellow", modifiers = ["italic"] } +"markup.raw" = { fg = "cyan" } + +[palette] +red = "#f7768e" +orange = "#ff9e64" +yellow = "#e0af68" +light-green = "#9ece6a" +green = "#73daca" +turquoise = "#89ddff" +light-cyan = "#b4f9f8" +teal = "#2ac3de" +cyan = "#7dcfff" +blue = "#7aa2f7" +magenta = "#bb9af7" +white = "#c0caf5" +light-gray = "#9aa5ce" +parameters = "#cfc9c2" +comment = "#565f89" +black = "#414868" +foreground = "#a9b1d6" +foreground_highlight = "#c0caf5" +foreground_gutter = "#3b4261" +background = "#24283b" +background_highlight = "#373d5a" +background_menu = "#1f2335" From 5ca8dfe57c044227274b73f9169ae68cebf1d074 Mon Sep 17 00:00:00 2001 From: Lukas Date: Sat, 23 Apr 2022 23:08:12 +0200 Subject: [PATCH 121/861] fix(lsp): divide hcl into seperate languages (#2244) --- book/src/generated/lang-support.md | 1 + languages.toml | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 259ffe002..1f0ae2412 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -73,6 +73,7 @@ | svelte | ✓ | | ✓ | `svelteserver` | | swift | ✓ | | | `sourcekit-lsp` | | tablegen | ✓ | ✓ | ✓ | | +| tfvars | | | | `terraform-ls` | | toml | ✓ | | | | | tsq | ✓ | | | | | tsx | ✓ | | | `typescript-language-server` | diff --git a/languages.toml b/languages.toml index 19d42e963..d5a93f110 100644 --- a/languages.toml +++ b/languages.toml @@ -1039,17 +1039,28 @@ source = { git = "https://github.com/fwcd/tree-sitter-kotlin", rev = "a4f71eb9b8 name = "hcl" scope = "source.hcl" injection-regex = "(hcl|tf|nomad)" -file-types = ["hcl", "tf", "tfvars", "nomad"] +file-types = ["hcl", "tf", "nomad"] roots = [] comment-token = "#" indent = { tab-width = 2, unit = " " } -language-server = { command = "terraform-ls", args = ["serve"] } +language-server = { command = "terraform-ls", args = ["serve"], language-id = "terraform" } auto-format = true [[grammar]] name = "hcl" source = { git = "https://github.com/MichaHoffmann/tree-sitter-hcl", rev = "3cb7fc28247efbcb2973b97e71c78838ad98a583" } +[[language]] +name = "tfvars" +scope = "source.tfvars" +file-types = ["tfvars"] +roots = [] +comment-token = "#" +indent = { tab-width = 2, unit = " " } +language-server = { command = "terraform-ls", args = ["serve"], language-id = "terraform-vars" } +auto-format = true +grammar = "hcl" + [[language]] name = "org" scope = "source.org" From 3f2bd7770e9cdbb57c139ef950e2d63ccf8ac674 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 23 Apr 2022 20:48:22 -0500 Subject: [PATCH 122/861] Rename paragraph motion commands from move to goto (#2226) * fix command name for next/prev paragraph motion * rename move_next/prev_paragraph to goto_next/prev_paragraph --- helix-term/src/commands.rs | 14 +++++++------- helix-term/src/keymap/default.rs | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 504de73f2..fb0940fd9 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -209,8 +209,6 @@ impl MappableCommand { move_next_long_word_start, "Move to beginning of next long word", move_prev_long_word_start, "Move to beginning of previous long word", move_next_long_word_end, "Move to end of next long word", - move_prev_paragraph, "Move to previous paragraph", - move_next_paragraph, "Move to next paragraph", extend_next_word_start, "Extend to beginning of next word", extend_prev_word_start, "Extend to beginning of previous word", extend_next_long_word_start, "Extend to beginning of next long word", @@ -390,6 +388,8 @@ impl MappableCommand { goto_prev_parameter, "Goto previous parameter", goto_next_comment, "Goto next comment", goto_prev_comment, "Goto previous comment", + goto_next_paragraph, "Goto next paragraph", + goto_prev_paragraph, "Goto previous paragraph", dap_launch, "Launch debug target", dap_toggle_breakpoint, "Toggle breakpoint", dap_continue, "Continue program execution", @@ -922,7 +922,7 @@ fn move_next_long_word_end(cx: &mut Context) { move_word_impl(cx, movement::move_next_long_word_end) } -fn move_para_impl(cx: &mut Context, move_fn: F) +fn goto_para_impl(cx: &mut Context, move_fn: F) where F: Fn(RopeSlice, Range, usize, Movement) -> Range + 'static, { @@ -946,12 +946,12 @@ where cx.editor.last_motion = Some(Motion(Box::new(motion))); } -fn move_prev_paragraph(cx: &mut Context) { - move_para_impl(cx, movement::move_prev_paragraph) +fn goto_prev_paragraph(cx: &mut Context) { + goto_para_impl(cx, movement::move_prev_paragraph) } -fn move_next_paragraph(cx: &mut Context) { - move_para_impl(cx, movement::move_next_paragraph) +fn goto_next_paragraph(cx: &mut Context) { + goto_para_impl(cx, movement::move_next_paragraph) } fn goto_file_start(cx: &mut Context) { diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index 18ebbcfed..10a43d122 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -104,7 +104,7 @@ pub fn default() -> HashMap { "c" => goto_prev_class, "a" => goto_prev_parameter, "o" => goto_prev_comment, - "p" => move_prev_paragraph, + "p" => goto_prev_paragraph, "space" => add_newline_above, }, "]" => { "Right bracket" @@ -114,7 +114,7 @@ pub fn default() -> HashMap { "c" => goto_next_class, "a" => goto_next_parameter, "o" => goto_next_comment, - "p" => move_next_paragraph, + "p" => goto_next_paragraph, "space" => add_newline_below, }, From 15db6031bbbdf7a795c15050a551dee09e9d1248 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 24 Apr 2022 03:30:18 -0700 Subject: [PATCH 123/861] Add :get-option command (#2231) --- book/src/generated/typable-cmd.md | 3 ++- helix-term/src/commands/typed.rs | 34 ++++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 33f3b8392..ee00e9ce9 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -55,7 +55,8 @@ | `:tutor` | Open the tutorial. | | `:goto`, `:g` | Go to line number. | | `:set-language`, `:lang` | Set the language of current buffer. | -| `:set-option`, `:set` | Set a config option at runtime | +| `:set-option`, `:set` | Set a config option at runtime. | +| `:get-option`, `:get` | Get the current value of a config option. | | `:sort` | Sort ranges in selection. | | `:rsort` | Sort ranges in selection in reverse order. | | `:tree-sitter-subtree`, `:ts-subtree` | Display tree sitter subtree under cursor, primarily for debugging queries. | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index d44bcf75d..9ed78d1dd 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -928,9 +928,30 @@ pub(super) fn goto_line_number( Ok(()) } +// Fetch the current value of a config option and output as status. +fn get_option( + cx: &mut compositor::Context, + args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + if args.len() != 1 { + anyhow::bail!("Bad arguments. Usage: `:get key`"); + } + + let key = &args[0].to_lowercase(); + let key_error = || anyhow::anyhow!("Unknown key `{}`", key); + + let config = serde_json::to_value(&cx.editor.config().clone()).unwrap(); + let pointer = format!("/{}", key.replace('.', "/")); + let value = config.pointer(&pointer).ok_or_else(key_error)?; + + cx.editor.set_status(value.to_string()); + Ok(()) +} + /// Change config at runtime. Access nested values by dot syntax, for /// example to disable smart case search, use `:set search.smart-case false`. -fn setting( +fn set_option( cx: &mut compositor::Context, args: &[Cow], _event: PromptEvent, @@ -1487,8 +1508,15 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "set-option", aliases: &["set"], - doc: "Set a config option at runtime", - fun: setting, + doc: "Set a config option at runtime.", + fun: set_option, + completer: Some(completers::setting), + }, + TypableCommand { + name: "get-option", + aliases: &["get"], + doc: "Get the current value of a config option.", + fun: get_option, completer: Some(completers::setting), }, TypableCommand { From ea02b46c5de443f90054a2d3bf43d1ef533f4962 Mon Sep 17 00:00:00 2001 From: workingj Date: Sun, 24 Apr 2022 15:04:47 +0200 Subject: [PATCH 124/861] Add Pop-Dark Theme (#2189) --- runtime/themes/pop-dark.toml | 158 +++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 runtime/themes/pop-dark.toml diff --git a/runtime/themes/pop-dark.toml b/runtime/themes/pop-dark.toml new file mode 100644 index 000000000..4ff732b76 --- /dev/null +++ b/runtime/themes/pop-dark.toml @@ -0,0 +1,158 @@ +# Pop Dark theme for the Helix Editor +# Author: workingj +# Repo: https://github.com/workingJ/helix-pop-theme +# Version: 1.0 +# This theme is based on Nathaniel Webb's VSCodePopTheme + +info = { fg = 'yellowH', bg = 'brownD' } +hint = { fg = 'brownD', bg = 'yellowH', modifiers = ['bold'] } +warning = { fg = 'brownD', bg = 'orangeW', modifiers = ['bold'] } +error = { fg = 'brownD', bg = 'redE', modifiers = ['bold'] } +diagnostic = { fg = 'greyT', bg = 'redD' } +'ui.background' = { bg = 'brownN' } +'ui.window' = { bg = 'brownH', fg = "brownD" } +'ui.gutter' = { bg = 'brownH' } +'ui.text' = { fg = 'greyT' } +'ui.text.focus' = { fg = 'orangeN' } +'ui.text.info' = { fg = 'orangeH', bg = 'brownH' } +'ui.cursor' = { fg = 'greyD', bg = 'orangeY' } +'ui.cursor.insert' = { fg = 'orangeN', bg = 'orangeN' } +'ui.cursor.select' = { fg = 'black', bg = 'orangeN' } +'ui.cursor.match' = { fg = 'black', bg = 'blueD' } +'ui.cursor.primary' = { fg = 'black', bg = 'orangeN' } +'ui.selection' = { bg = 'blueH', fg = 'white' } +'ui.selection.primary' = { bg = 'blueD', fg = 'white' } +'ui.linenr' = { bg = "brownN", fg = 'greyL' } +'ui.linenr.selected' = { bg = 'brownH', fg = 'orangeH' } +'ui.statusline' = { bg = 'brownH' } +'ui.statusline.inactive' = { bg = 'brownN' } +'ui.help' = { bg = 'brownD' } +'ui.highlight' = { bg = 'brownH' } +'ui.virtual' = { fg = 'brownV' } +'ui.virtual.ruler' = { bg = 'brownR' } +'ui.virtual.whitespace' = { fg = 'brownV' } +'ui.virtual.indent-guide' = { fg = 'brownR' } +'ui.menu' = { bg = 'brownD' } +'ui.menu.selected' = { fg = 'orangeH', bg = 'brownH' } +'ui.popup' = { bg = 'brownD' } +'ui.popup.info' = { bg = 'brownH', fg = 'greyT' } +tag = { fg = 'blueH' } +label = { fg = 'greenS' } +module = { bg = 'orangeL' } +special = { fg = 'orangeW' } +operator = { fg = 'orangeY' } +property = { bg = 'blueH' } +attribute = { fg = 'orangeL' } +attributes = { fg = 'orangeL' } +namespace = { fg = 'orangeL' } +'type' = { fg = 'redH' } +'type.builtin' = { fg = 'orangeL' } +'type.enum.variant' = { fg = 'orangeL' } +'constructor' = { fg = 'blueD' } +'constant' = { fg = 'greyG' } +'constant.builtin' = { fg = 'redL' } +'constant.builtin.boolean' = { fg = 'redL' } +'constant.character' = { fg = 'greenS' } +'constant.character.escape' = { fg = 'blueL' } +'constant.numeric' = { fg = 'redH' } +'constant.number' = { bg = 'blueH' } +'constant.number.integer' = { fg = 'orangeS' } +'constant.number.float' = { fg = 'orangeS' } +'string' = { fg = 'greenN' } +'string.regexp' = { fg = 'blueL' } +'string.special' = { fg = 'orangeW' } +'string.special.path' = { fg = 'orangeW' } +'string.special.url' = { fg = 'orangeW' } +'string.special.symbol' = { fg = 'orangeW' } +'comment' = { fg = 'greyC', modifiers = ['italic'] } +'comment.line' = { fg = 'greyC', modifiers = ['italic'] } +'comment.block' = { fg = 'greyC', modifiers = ['italic'] } +'comment.block.documentation' = { fg = 'greyC', modifiers = ['italic'] } +'variable' = { fg = 'greyT' } +'variable.builtin' = { fg = 'blueL' } +'variable.parameter' = { fg = 'white' } +'variable.other.member' = { fg = 'orangeH' } +'variable.function' = { fg = 'blueL' } +'punctuation' = { fg = 'blueL' } +'punctuation.delimeter' = { fg = 'blueH' } +'punctuation.bracket' = { fg = 'orangeN' } +'keyword' = { fg = 'blueH' } +'keyword.control' = { fg = 'blueL' } +'keyword.control.conditional' = { fg = 'blueL' } +'keyword.control.repeat' = { fg = 'blueL' } +'keyword.control.import' = { fg = 'redH' } +'keyword.control.return' = { fg = 'blueL' } +'keyword.control.exception' = { fg = 'redH' } +'keyword.operator' = { fg = 'blueL' } +'keyword.directive' = { fg = 'blueL' } +'keyword.function' = { fg = 'redH' } +'function' = { fg = 'blueH' } +'function.builtin' = { fg = 'blueH' } +'function.method' = { fg = 'blueH' } +'function.macro' = { fg = 'greyH' } +'function.special' = { fg = 'blueD' } +'markup.heading' = { fg = 'greenN' } +'markup.heading.1' = { fg = '#FFC977' } +'markup.heading.2' = { fg = '#FFC26C' } +'markup.heading.3' = { fg = '#FFC166' } +'markup.heading.4' = { fg = '#FFB950' } +'markup.heading.5' = { fg = '#FFB340' } +'markup.heading.6' = { fg = '#FFAD34' } +'markup.heading.marker' = { fg = 'orangeN' } +'markup.list' = { fg = 'greenN' } +'markup.list.numbered' = { fg = 'greenN' } +'markup.list.unnumbered' = { fg = 'greenN' } +'markup.bold' = { modifiers = ['bold'] } +'markup.italic' = { modifiers = ['italic'] } +'markup.link' = { fg = 'blueD' } +'markup.link.url' = { fg = 'blueL' } +'markup.link.label' = { fg = 'blueH' } +'markup.link.text' = { fg = 'blueN' } +'markup.quote' = { fg = 'blueL' } +'markup.normal' = { fg = 'blueL' } +'markup.normal.completion' = { bg = 'brownN' } +'markup.normal.raw' = { bg = 'brownN' } +'markup.heading.completion' = { fg = 'greenN' } +'markup.heading.raw' = { bg = 'brownN' } +'markup.raw' = { bg = 'brownN' } +'markup.raw.block' = { bg = 'brownH', fg = 'orangeH' } +'markup.raw.inline' = { fg = 'blueL' } +'markup.raw.inline.completion' = { fg = 'greenN' } +'markup.raw.inline.hover' = { fg = 'greenS' } +'diff.plus' = { fg = '#4dd44d' } +'diff.minus' = { fg = '#dd4d4d' } +'diff.delta' = { fg = '#4d4ddd' } +'diff.delta.moved' = { fg = '#dd4ddd' } + +[palette] +white = '#FFFFFF' +greyH = '#CFCFCF' +greyT = '#DEDEDE' +greyG = '#DDFFDD' +greyC = '#A0B4A7' +greyL = '#9A9A9A' +greyD = '#444444' +black = '#000000' +yellowH = '#FFCC00' +orangeH = '#FFD68A' +orangeL = '#FFCB6B' +orangeY = '#FDC33B' +orangeN = '#FDAF1F' +orangeW = '#FF9500' +orangeS = '#F79A6C' +redH = '#F78C6C' +redL = '#F96964' +redE = '#FF2200' +redD = '#CC3333' +greenN = '#73C48F' +greenS = '#6FC475' +blueH = '#8DEEF9' +blueL = '#6dd2fa' +blueN = '#39B7C7' +blueD = '#4AAAD6' +brownV = '#67634F' +brownH = '#56524E' +brownN = '#3F3B39' +brownR = '#35312f' +brownD = '#2B2928' + From a8cb46680d0588d24262aece840c6b66cb9b87de Mon Sep 17 00:00:00 2001 From: ttys3 <41882455+ttys3@users.noreply.github.com> Date: Mon, 25 Apr 2022 00:21:07 +0800 Subject: [PATCH 125/861] feat(lsp): add vala language support (#2243) --- book/src/generated/lang-support.md | 1 + languages.toml | 14 ++ runtime/queries/vala/highlights.scm | 218 ++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+) create mode 100644 runtime/queries/vala/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 1f0ae2412..1df83913c 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -79,6 +79,7 @@ | tsx | ✓ | | | `typescript-language-server` | | twig | ✓ | | | | | typescript | ✓ | | ✓ | `typescript-language-server` | +| vala | ✓ | | | `vala-language-server` | | vue | ✓ | | | `vls` | | wgsl | ✓ | | | | | yaml | ✓ | | ✓ | `yaml-language-server` | diff --git a/languages.toml b/languages.toml index d5a93f110..d77b36863 100644 --- a/languages.toml +++ b/languages.toml @@ -1235,3 +1235,17 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "nu" source = { git = "https://github.com/LhKipp/tree-sitter-nu", rev = "db4e990b78824c8abef3618e0f93b7fe1e8f4c0d" } + +[[language]] +name = "vala" +scope = "source.vala" +injection-regex = "vala" +file-types = ["vala", "vapi"] +roots = [] +comment-token = "//" +indent = { tab-width = 2, unit = " " } +language-server = { command = "vala-language-server" } + +[[grammar]] +name = "vala" +source = { git = "https://github.com/vala-lang/tree-sitter-vala", rev = "c9eea93ba2ec4ec1485392db11945819779745b3" } diff --git a/runtime/queries/vala/highlights.scm b/runtime/queries/vala/highlights.scm new file mode 100644 index 000000000..685cda13b --- /dev/null +++ b/runtime/queries/vala/highlights.scm @@ -0,0 +1,218 @@ +; highlights.scm + +; highlight constants +( + (member_access_expression (identifier) @constant) + (#match? @constant "^[A-Z][A-Z_0-9]*$") +) + +( + (member_access_expression (member_access_expression) @namespace (identifier) @constant) + (#match? @constant "^[A-Z][A-Z_0-9]*$") +) + +(comment) @comment + +(type (symbol (_)? @namespace (identifier) @type)) + +; highlight creation methods in object creation expressions +( + (object_creation_expression (type (symbol (symbol (symbol)? @namespace (identifier) @type) (identifier) @constructor))) + (#match? @constructor "^[a-z][a-z_0-9]*$") +) + +(unqualified_type (symbol . (identifier) @type)) +(unqualified_type (symbol (symbol) @namespace (identifier) @type)) + +(attribute) @variable.other.member +(method_declaration (symbol (symbol) @type (identifier) @function)) +(method_declaration (symbol (identifier) @function)) +(local_function_declaration (identifier) @function) +(destructor_declaration (identifier) @function) +(creation_method_declaration (symbol (symbol (identifier) @type) (identifier) @constructor)) +(creation_method_declaration (symbol (identifier) @constructor)) +(enum_declaration (symbol) @type) +(enum_value (identifier) @constant) +(errordomain_declaration (symbol) @type) +(errorcode (identifier) @constant) +(constant_declaration (identifier) @constant) +(method_call_expression (member_access_expression (identifier) @function)) +(lambda_expression (identifier) @variable.parameter) +(parameter (identifier) @variable.parameter) +(property_declaration (symbol (identifier) @variable.other.member)) +(field_declaration (identifier) @variable) +(identifier) @variable +[ + (this_access) + (base_access) + (value_access) +] @variable.builtin +(boolean) @constant.builtin.boolean +(character) @constant.character +(integer) @constant.numeric.integer +(null) @constant.builtin +(real) @constant.numeric.float +(regex) @string.regexp +(string) @string +[ + (escape_sequence) + (string_formatter) +] @string.special +(template_string) @string +(template_string_expression) @string.special +(verbatim_string) @string +[ + "var" + "void" +] @type.builtin + +[ + "abstract" + "async" + "break" + "case" + "catch" + "class" + "const" + "construct" + "continue" + "default" + "delegate" + "do" + "dynamic" + "else" + "enum" + "errordomain" + "extern" + "finally" + "for" + "foreach" + "get" + "if" + "inline" + "interface" + "internal" + "lock" + "namespace" + "new" + "out" + "override" + "owned" + "partial" + "private" + "protected" + "public" + "ref" + "set" + "signal" + "static" + "struct" + "switch" + "throw" + "throws" + "try" + "unowned" + "virtual" + "weak" + "while" + "with" +] @keyword + +[ + "and" + "as" + "delete" + "in" + "is" + "not" + "or" + "sizeof" + "typeof" +] @keyword.operator + +"using" @namespace + +(symbol "global::" @namespace) + +(array_creation_expression "new" @keyword.operator) +(object_creation_expression "new" @keyword.operator) +(argument "out" @keyword.operator) +(argument "ref" @keyword.operator) + +[ + "continue" + "do" + "for" + "foreach" + "while" +] @keyword.control.repeat + +[ + "catch" + "finally" + "throw" + "throws" + "try" +] @keyword.control.exception + +[ + "return" + "yield" +] @keyword.control.return + +[ + "=" + "==" + "+" + "+=" + "-" + "-=" + "++" + "--" + "|" + "|=" + "&" + "&=" + "^" + "^=" + "/" + "/=" + "*" + "*=" + "%" + "%=" + "<<" + "<<=" + ">>" + ">>=" + "." + "?." + "->" + "!" + "!=" + "~" + "??" + "?" + ":" + "<" + "<=" + ">" + ">=" + "||" + "&&" + "=>" +] @operator + +[ + "," + ";" +] @punctuation.delimiter + +[ + "(" + ")" + "{" + "}" + "[" + "]" +] @punctuation.bracket From db47761154ff8e36bd442ed64d4ccb6051279baa Mon Sep 17 00:00:00 2001 From: matt rice Date: Mon, 25 Apr 2022 02:14:46 +0000 Subject: [PATCH 126/861] register publish_diagnostics client capability (#2241) --- helix-lsp/src/client.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 2459554c1..4bfa2f643 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -341,6 +341,9 @@ impl Client { }), ..Default::default() }), + publish_diagnostics: Some(lsp::PublishDiagnosticsClientCapabilities { + ..Default::default() + }), ..Default::default() }), window: Some(lsp::WindowClientCapabilities { From b65fb0f64ad6cf7a54f4dda92bebfc22d80b236f Mon Sep 17 00:00:00 2001 From: Lucy <11927498+lucypero@users.noreply.github.com> Date: Mon, 25 Apr 2022 09:26:02 -0300 Subject: [PATCH 127/861] Fix typo (#2264) --- docs/architecture.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture.md b/docs/architecture.md index 33624aac2..74f973b0d 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -42,7 +42,7 @@ applying the transaction. > interface used to generate text edits. `Syntax` is the interface used to interact with tree-sitter ASTs for syntax -highling and other features. +highlighting and other features. ## View From 8eb15f52835c3669a5d5f0539a13f415a8a71856 Mon Sep 17 00:00:00 2001 From: Jens Getreu Date: Mon, 25 Apr 2022 19:39:24 +0200 Subject: [PATCH 128/861] Autumn theme: improve markup highlighting (#2270) Co-authored-by: Jens Getreu --- runtime/themes/autumn.toml | 56 ++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/runtime/themes/autumn.toml b/runtime/themes/autumn.toml index fcad5003d..032e773ac 100644 --- a/runtime/themes/autumn.toml +++ b/runtime/themes/autumn.toml @@ -32,9 +32,9 @@ "string" = "my_green" "variable.other.member" = "my_brown" "constant.character.escape" = "my_turquoise" -"function" = "my_yellow" -"constructor" = "my_yellow" -"special" = "my_yellow" +"function" = "my_yellow1" +"constructor" = "my_yellow1" +"special" = "my_yellow1" "keyword" = "my_red" "label" = "my_red" "namespace" = "my_white3" @@ -42,11 +42,11 @@ "ui.virtual.whitespace" = { fg = "my_gray5" } "ui.virtual.ruler" = { bg = "my_gray1" } -"markup.heading" = "my_yellow" +"markup.heading" = "my_yellow1" "markup.list" = "my_white2" -"markup.bold" = { fg = "my_white3", modifiers = ["bold"] } -"markup.italic" = { fg = "my_white3", modifiers = ["italic"] } -"markup.link.url" = { fg = "my_green", modifiers = ["underlined"] } +"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" @@ -57,26 +57,28 @@ "diagnostic" = { modifiers = ["underlined"] } "ui.gutter" = { bg = "my_gray2" } -"info" = "my_yellow" -"hint" = "my_gray4" -"debug" = "my_gray4" -"warning" = "my_yellow" +"hint" = "my_gray5" +"debug" = "my_yellow2" +"info" = "my_yellow2" +"warning" = "my_yellow2" "error" = "my_red" [palette] -my_gray0 = "#292929" # Default Background -my_gray1 = "#2e2e2e" # Ruler -my_gray2 = "#3a3a3a" # Lighter Background (Used for status bars, line number and folding marks) -my_gray3 = "#525252" # Selection Background -my_gray4 = "#7c7c7c" # Comments, Invisibles, Line Highlighting -my_gray5 = "#aaaaaa" # Dark Foreground (Used for status bars) -my_white = "#F3F2CC" # Default Foreground, Caret, Delimiters, Operators -my_gray6 = "#e8e8e8" # Light Foreground (Not often used) -my_gray7 = "#f8f8f8" # Light Background (Not often used) -my_white2 = "#F3F2CC" # Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted -my_turquoise = "#86c1b9" # Support, Regular Expressions, Escape Characters, Markup Quotes -my_white3 = "#F3F2CC" # Classes, Markup Bold, Search Text Background -my_green = "#8daf67" # Strings, Inherited Class, Markup Code, Diff Inserted -my_brown = "#cfba8b" # Member variables -my_yellow = "#FAD566" # Functions, Methods, Attribute IDs, Headings -my_red = "#F05E48" # Keywords, Storage, Selector, Markup Italic, Diff Changed +my_gray0 = "#292929" # Default Background +my_gray1 = "#2e2e2e" # Ruler +my_gray2 = "#3a3a3a" # Lighter Background (Used for status bars, line number and folding marks) +my_gray3 = "#525252" # Selection Background +my_gray4 = "#7c7c7c" # Comments, Invisibles, Line Highlighting +my_gray5 = "#aaaaaa" # Dark Foreground (Used for status bars) +my_gray6 = "#e8e8e8" # Light Foreground (Not often used) +my_gray7 = "#f8f8f8" # 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 +my_white3 = "#F3F2CC" # Classes, Markup Bold, Search Text Background +my_turquoise = "#86c1b9" # Support, Regular Expressions, Escape Characters +my_turquoise2 = "#72a59e" # URL +my_green = "#99be70" # Strings, Inherited Class, Markup Code, Diff Inserted +my_brown = "#cfba8b" # Member variables, Quotes +my_yellow1 = "#FAD566" # Functions, Methods, Attribute IDs, Headings +my_yellow2 = "#ffff9f" # Debug, Info +my_red = "#F05E48" # Keywords, Storage, Selector, Diff Changed From 3d3145d51145cde46ca062eec12d9635ab2b9b38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Apr 2022 11:20:58 +0800 Subject: [PATCH 129/861] build(deps): bump anyhow from 1.0.56 to 1.0.57 (#2273) Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.56 to 1.0.57. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.56...1.0.57) --- updated-dependencies: - dependency-name: anyhow dependency-type: direct:production update-type: version-update:semver-patch ... 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 0835d1075..b22c3065c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" [[package]] name = "arc-swap" From fcd0ca3912cf53b68cec21823d25677cba7e9eea Mon Sep 17 00:00:00 2001 From: Tomas Roos Date: Tue, 26 Apr 2022 14:53:02 +0200 Subject: [PATCH 130/861] Fix base16_terminal theme using incorrect ansi-color (#2279) --- runtime/themes/base16_terminal.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/base16_terminal.toml b/runtime/themes/base16_terminal.toml index e518d3d56..928488168 100644 --- a/runtime/themes/base16_terminal.toml +++ b/runtime/themes/base16_terminal.toml @@ -12,7 +12,7 @@ "ui.statusline.inactive" = { fg = "gray", bg = "black" } "ui.help" = { fg = "white", bg = "black" } "ui.cursor" = { fg = "light-gray", modifiers = ["reversed"] } -"ui.cursor.primary" = { fg = "light-white", modifiers = ["reversed"] } +"ui.cursor.primary" = { fg = "light-gray", modifiers = ["reversed"] } "ui.virtual" = "light-gray" "variable" = "light-red" "constant.numeric" = "yellow" From 773736b03a176159240bcef3162732d538917331 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 26 Apr 2022 12:31:45 -0500 Subject: [PATCH 131/861] Fix paste direction for typed paste commands (#2288) --- helix-term/src/commands/typed.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 9ed78d1dd..3e93cfd7a 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -648,7 +648,7 @@ fn paste_clipboard_before( _args: &[Cow], _event: PromptEvent, ) -> anyhow::Result<()> { - paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Clipboard, 1) + paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Clipboard, 1) } fn paste_primary_clipboard_after( @@ -664,7 +664,7 @@ fn paste_primary_clipboard_before( _args: &[Cow], _event: PromptEvent, ) -> anyhow::Result<()> { - paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Selection, 1) + paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Selection, 1) } fn replace_selections_with_clipboard_impl( From 1a3d6252b9d1a411df8ea27ee04960f599c35a6b Mon Sep 17 00:00:00 2001 From: meak Date: Tue, 26 Apr 2022 21:55:00 +0200 Subject: [PATCH 132/861] feat(lang): add hare language support (#2289) Co-authored-by: Mehdi Katranji --- book/src/generated/lang-support.md | 1 + languages.toml | 13 +++ runtime/queries/hare/highlights.scm | 158 ++++++++++++++++++++++++++++ runtime/queries/hare/indents.scm | 21 ++++ runtime/queries/hare/locals.scm | 20 ++++ 5 files changed, 213 insertions(+) create mode 100644 runtime/queries/hare/highlights.scm create mode 100644 runtime/queries/hare/indents.scm create mode 100644 runtime/queries/hare/locals.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 1df83913c..741012e79 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -27,6 +27,7 @@ | gomod | ✓ | | | `gopls` | | gowork | ✓ | | | `gopls` | | graphql | ✓ | | | | +| hare | ✓ | | ✓ | | | haskell | ✓ | | | `haskell-language-server-wrapper` | | hcl | ✓ | | ✓ | `terraform-ls` | | heex | ✓ | | | | diff --git a/languages.toml b/languages.toml index d77b36863..c786da9c5 100644 --- a/languages.toml +++ b/languages.toml @@ -1249,3 +1249,16 @@ language-server = { command = "vala-language-server" } [[grammar]] name = "vala" source = { git = "https://github.com/vala-lang/tree-sitter-vala", rev = "c9eea93ba2ec4ec1485392db11945819779745b3" } + +[[language]] +name = "hare" +scope = "source.hare" +injection-regex = "hare" +file-types = ["ha"] +roots = [] +comment-token = "//" +indent = { tab-width = 4, unit = "\t" } + +[[grammar]] +name = "hare" +source = { git = "https://git.sr.ht/~ecmma/tree-sitter-hare", rev = "bc26a6a949f2e0d98b7bfc437d459b250900a165" } diff --git a/runtime/queries/hare/highlights.scm b/runtime/queries/hare/highlights.scm new file mode 100644 index 000000000..cd3c1d0a0 --- /dev/null +++ b/runtime/queries/hare/highlights.scm @@ -0,0 +1,158 @@ +[ + "f32" + "f64" + "i16" + "i32" + "i64" + "i8" + "int" + "rune" + "str" + "u16" + "u32" + "u64" + "u8" + "uint" + "uintptr" + "void" +] @type + + +[ + "else" + "if" + "match" + "switch" +] @keyword.control.conditional + +[ + "export" + "use" +] @keyword.control.import + +[ + "continue" + "for" + "break" +] @keyword.control.repeat + +"return" @keyword.control.return + +[ + "abort" + "assert" +] @keyword.control.exception + +[ + "def" + "fn" +] @keyword.function + +[ + "alloc" + "append" + "as" + "bool" + "char" + "const" + "defer" + "delete" + "enum" + "free" + "is" + "len" + "let" + "match" + "nullable" + "offset" + "size" + "static" + "struct" + "type" + "union" +] @keyword + +[ + "." + "!" + "~" + "?" + "*" + "/" + "%" + "+" + "-" + "<<" + ">>" + "::" + "<" + "<=" + ">" + ">=" + "==" + "!=" + "&" + "|" + "^" + "&&" + "||" + "=" + "+=" + "-=" + "*=" + "/=" + "%=" + "&=" + "|=" + "<<=" + ">>=" + "^=" + "=>" +] @operator + +[ + "(" + ")" + "[" + "]" + ")" + "{" + "}" +] @punctuation.bracket + +[ + ":" + ";" +] @punctuation.delimiter + +"..." @special + +(comment) @comment + +[ + "false" + "null" + "true" +] @constant.builtin + +(string_constant) @string +(escape_sequence) @constant.character.escape +(rune_constant) @string +(integer_constant) @constant.numeric.integer +(floating_constant) @constant.numeric.float + +(call_expression + (postfix_expression) @function) + +(function_declaration + name: (identifier) @function) + +(parameter (name) @variable.parameter) + +(field_access_expression + selector: (name) @variable.other.member) +(decl_attr) @special +(fndec_attrs) @special + +(identifier) @variable + diff --git a/runtime/queries/hare/indents.scm b/runtime/queries/hare/indents.scm new file mode 100644 index 000000000..a2e83c000 --- /dev/null +++ b/runtime/queries/hare/indents.scm @@ -0,0 +1,21 @@ +[ + (struct_union_fields) + (expression_list) +] @indent + +[ + "case" + "}" + "]" + ")" +] @outdent + +; [ +; "{" +; "}" +; ] @branch + +; [ +; (comment) +; ] @ignore + diff --git a/runtime/queries/hare/locals.scm b/runtime/queries/hare/locals.scm new file mode 100644 index 000000000..b8b9b9f71 --- /dev/null +++ b/runtime/queries/hare/locals.scm @@ -0,0 +1,20 @@ +(unit) @local.scope + +(function_declaration) @local.scope + +(global_binding + (identifier) @local.definition) +(constant_binding + (identifier) @local.definition) +(type_bindings + (identifier) @local.definition) + +(function_declaration + (prototype + (parameter_list + (parameters + (parameter + (name) @local.definition))))) + +(identifier) @local.reference + From a3c0b4db48bb286a9b59a3fb1089607f6f29388c Mon Sep 17 00:00:00 2001 From: Erasin Date: Wed, 27 Apr 2022 21:09:45 +0800 Subject: [PATCH 133/861] Add onelight theme variant (#2287) --- runtime/themes/onelight.toml | 116 +++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 runtime/themes/onelight.toml diff --git a/runtime/themes/onelight.toml b/runtime/themes/onelight.toml new file mode 100644 index 000000000..84d47f340 --- /dev/null +++ b/runtime/themes/onelight.toml @@ -0,0 +1,116 @@ +# One Light +# Author : erasin + +"attribute" = { fg = "yellow" } +"comment" = { fg = "gray", modifiers = ["italic"] } + +"constant" = { fg = "red" } +"constant.numeric" = { fg = "gold" } +"constant.builtin" = { fg = "gold" } +"constant.character.escape" = { fg = "gold" } + +"constructor" = { fg = "blue" } + +"function" = { fg = "light-blue" } +"function.builtin" = { fg = "gray" } +"function.macro" = { fg = "red" } + +"keyword" = { fg = "purple" } +"keyword.control" = { fg = "purple" } +"keyword.control.import" = { fg = "purple" } +"keyword.directive" = { fg = "purple" } +"keyword.operator" = { fg = "purple" } + +"tag" = "yellow" +"label" = { fg = "cyan" } +"namespace" = { fg = "red" } +"operator" = { fg = "red" } +"property" = { fg = "red" } +"special" = { fg = "blue" } +"string" = { fg = "green" } +"module" = { fg = "cyan" } + +"type" = { fg = "yellow" } +"type.builtin" = "blue" + +"punctuation" = "gray" +"punctuation.delimiter" = "black" +# "punctuation.bracket" = "black" + +# "variable" = { fg = "blue" } +"variable.builtin" = { fg = "light-blue" } +"variable.parameter" = { fg = "blue" } +"variable.other.member" = { fg = "red" } + +"markup.heading" = { fg = "red" } +# "markup.raw" = { bg = "light-white" } +"markup.raw.inline" = { fg = "green", bg = "light-white" } +"markup.bold" = { fg = "yellow", modifiers = ["bold"] } +"markup.italic" = { fg = "purple", modifiers = ["italic"] } +"markup.list" = { fg = "red" } +"markup.quote" = { fg = "yellow" } +"markup.link.url" = { fg = "cyan", modifiers = ["underlined"] } +"markup.link.text" = { fg = "light-blue" } +"markup.heading.1" = { fg = "red", modifiers = ["bold"] } +"markup.heading.2" = { fg = "glod", modifiers = ["bold"] } +"markup.heading.3" = { fg = "yellow", modifiers = ["bold"] } +"markup.heading.4" = { fg = "green", modifiers = ["bold"] } +"markup.heading.5" = { fg = "blue", modifiers = ["bold"] } +"markup.heading.6" = { fg = "black", modifiers = ["bold"] } + +"diff.plus" = "green" +"diff.delta" = "gold" +"diff.minus" = "red" + +"diagnostic" = { modifiers = ["underlined"] } +"info" = { fg = "blue", modifiers = ["bold"] } +"hint" = { fg = "green", modifiers = ["bold"] } +"warning" = { fg = "yellow", modifiers = ["bold"] } +"error" = { fg = "red", modifiers = ["bold"] } + +"ui.background" = { bg = "white" } + +"ui.cursor" = { fg = "black", modifiers = ["reversed"] } +"ui.cursor.primary" = { fg = "white", bg="black", modifiers = [] } +"ui.cursor.match" = { fg = "purple", modifiers = ["underlined", "bold"] } +"ui.cursor.select" = { bg = "purple" } +"ui.cursor.insert" = { bg = "white" } + +"ui.highlight" = { bg = "light-white" } + +"ui.selection" = { bg = "light-white" } +"ui.selection.primary" = { bg = "light-white", modifiers = ["dim"] } + +"ui.virtual" = { fg = "light-white"} +"ui.virtual.ruler" = { bg = "light-white" } +"ui.virtual.whitespace" = {fg = "light-white" } + + +"ui.linenr" = { fg = "linenr" } +"ui.linenr.selected" = { fg = "black", modifiers = ["reversed"] } + +"ui.statusline" = { fg = "black", bg = "light-white" } +"ui.statusline.inactive" = { fg = "gray", bg = "light-white" } + +"ui.text" = { fg = "black" } +"ui.text.focus" = { fg = "red", bg = "light-white", modifiers = ["bold"] } + +"ui.help" = { bg = "light-white" } +"ui.popup" = { bg = "light-white" } +"ui.window" = { bg = "light-white" } +"ui.menu.selected" = { fg = "white", bg = "light-blue" } + +[palette] +white = "#FAFAFA" +yellow = "#A06600" +blue = "#5556FF" +light-blue = "#2F77FA" +red = "#DC003F" +purple = "#B500A9" +green = "#24A443" +gold = "#D19A66" +cyan = "#0086C1" +black = "#282C34" +light-white = "#EAEAEB" +gray = "#5C6370" +linenr = "#9D9D9F" From 52f5a4228aef2d31cf20aeee2bed317ba1767c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Dzivjak?= Date: Wed, 27 Apr 2022 18:14:46 +0200 Subject: [PATCH 134/861] feat(commands): better handling of buffer-close (#1397) * feat(commands): better handling of buffer-close Previously, when closing buffer, you would loose cursor position in other docs. Also, all splits where the buffer was open would be closed. This PR changes the behavior, if the view has also other buffer previously viewed it switches back to the last one instead of the view being closed. As a side effect, since the views are persisted, the cursor history is persisted as well. Fixes: https://github.com/helix-editor/helix/issues/1186 * Adjust buffer close behavior * Remove closed documents from jump history * Fix after rebase --- helix-term/src/commands.rs | 8 ++------ helix-view/src/editor.rs | 35 ++++++++++++++++++++++++++++------- helix-view/src/view.rs | 13 ++++++++++--- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index fb0940fd9..8a0313efe 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2489,8 +2489,8 @@ fn goto_last_line(cx: &mut Context) { } fn goto_last_accessed_file(cx: &mut Context) { - let alternate_file = view!(cx.editor).last_accessed_doc; - if let Some(alt) = alternate_file { + let view = view_mut!(cx.editor); + if let Some(alt) = view.docs_access_history.pop() { cx.editor.switch(alt, Action::Replace); } else { cx.editor.set_error("no last accessed buffer") @@ -3796,10 +3796,6 @@ fn jump_backward(cx: &mut Context) { let (view, doc) = current!(cx.editor); if let Some((id, selection)) = view.jumps.backward(view.id, doc, count) { - // manually set the alternate_file as we cannot use the Editor::switch function here. - if view.doc != *id { - view.last_accessed_doc = Some(view.doc) - } view.doc = *id; let selection = selection.clone(); let (view, doc) = current!(cx.editor); // refetch doc diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 79775c897..38826f4bf 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -667,7 +667,7 @@ impl Editor { view.jumps.push(jump); // Set last accessed doc if it is a different document if doc.id != id { - view.last_accessed_doc = Some(view.doc); + view.add_to_history(view.doc); // Set last modified doc if modified and last modified doc is different if std::mem::take(&mut doc.modified_since_accessed) && view.last_modified_docs[0] != Some(view.doc) @@ -785,20 +785,41 @@ impl Editor { tokio::spawn(language_server.text_document_did_close(doc.identifier())); } - let views_to_close = self + enum Action { + Close(ViewId), + ReplaceDoc(ViewId, DocumentId), + } + + let actions: Vec = self .tree - .views() + .views_mut() .filter_map(|(view, _focus)| { + // remove the document from jump list of all views + view.jumps.remove(&doc_id); + if view.doc == doc_id { - Some(view.id) + // something was previously open in the view, switch to previous doc + if let Some(prev_doc) = view.docs_access_history.pop() { + Some(Action::ReplaceDoc(view.id, prev_doc)) + } else { + // only the document that is being closed was in the view, close it + Some(Action::Close(view.id)) + } } else { None } }) - .collect::>(); + .collect(); - for view_id in views_to_close { - self.close(view_id); + for action in actions { + match action { + Action::Close(view_id) => { + self.close(view_id); + } + Action::ReplaceDoc(view_id, doc_id) => { + self.replace_document_in_view(view_id, doc_id); + } + } } self.documents.remove(&doc_id); diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 7cf88c2e1..3450da9b3 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -72,8 +72,8 @@ pub struct View { pub area: Rect, pub doc: DocumentId, pub jumps: JumpList, - /// the last accessed file before the current one - pub last_accessed_doc: Option, + // documents accessed from this view from the oldest one to last viewed one + pub docs_access_history: Vec, /// the last modified files before the current one /// ordered from most frequent to least frequent // uses two docs because we want to be able to swap between the @@ -110,13 +110,20 @@ impl View { offset: Position::new(0, 0), area: Rect::default(), // will get calculated upon inserting into tree jumps: JumpList::new((doc, Selection::point(0))), // TODO: use actual sel - last_accessed_doc: None, + docs_access_history: Vec::new(), last_modified_docs: [None, None], object_selections: Vec::new(), gutters, } } + pub fn add_to_history(&mut self, id: DocumentId) { + if let Some(pos) = self.docs_access_history.iter().position(|&doc| doc == id) { + self.docs_access_history.remove(pos); + } + self.docs_access_history.push(id); + } + pub fn inner_area(&self) -> Rect { // TODO: cache this let offset = self From 3626e38e51f0fdcbbb7c59cb6d2f2b3167792272 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Wed, 27 Apr 2022 23:06:41 +0530 Subject: [PATCH 135/861] Add ui.virtual theme scopes for onedark theme --- runtime/themes/onedark.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/themes/onedark.toml b/runtime/themes/onedark.toml index cf7dd2b06..573a635d7 100644 --- a/runtime/themes/onedark.toml +++ b/runtime/themes/onedark.toml @@ -47,7 +47,8 @@ diagnostic = { modifiers = ["underlined"] } "error" = { fg = "red", modifiers = ["bold"] } "ui.background" = { bg = "black" } -"ui.virtual" = { fg = "light-gray" } +"ui.virtual.whitespace" = { fg = "light-gray" } +"ui.virtual.ruler" = { bg = "gray" } "ui.cursor" = { fg = "white", modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "white", modifiers = ["reversed"] } From 2e46961886cb40b45a03a91c59823b0e437a9867 Mon Sep 17 00:00:00 2001 From: Alexis Kalabura <55039048+axdank@users.noreply.github.com> Date: Wed, 27 Apr 2022 14:48:04 -0400 Subject: [PATCH 136/861] feat(lsp): add toml lsp (#2302) --- book/src/generated/lang-support.md | 2 +- languages.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 741012e79..69ae35c12 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -75,7 +75,7 @@ | swift | ✓ | | | `sourcekit-lsp` | | tablegen | ✓ | ✓ | ✓ | | | tfvars | | | | `terraform-ls` | -| toml | ✓ | | | | +| toml | ✓ | | | `taplo` | | tsq | ✓ | | | | | tsx | ✓ | | | `typescript-language-server` | | twig | ✓ | | | | diff --git a/languages.toml b/languages.toml index c786da9c5..76d1f43a9 100644 --- a/languages.toml +++ b/languages.toml @@ -59,6 +59,7 @@ injection-regex = "toml" file-types = ["toml"] roots = [] comment-token = "#" +language-server = { command = "taplo", args = ["lsp", "stdio"] } indent = { tab-width = 2, unit = " " } [[grammar]] From 3a398eec56c907f9d0f166e77242eb13ded229bc Mon Sep 17 00:00:00 2001 From: chunghha Date: Wed, 27 Apr 2022 14:21:20 -0500 Subject: [PATCH 137/861] fix typos (#2304) --- CHANGELOG.md | 2 +- book/src/configuration.md | 2 +- book/src/generated/typable-cmd.md | 4 ++-- book/src/guides/README.md | 2 +- book/src/guides/indent.md | 2 +- book/src/install.md | 2 +- book/src/keymap.md | 2 +- book/src/themes.md | 2 +- book/theme/book.js | 6 +++--- book/theme/css/chrome.css | 2 +- book/theme/css/variables.css | 16 ++++++++-------- helix-core/src/history.rs | 8 ++++---- helix-core/src/path.rs | 2 +- helix-core/src/syntax.rs | 12 ++++++------ helix-lsp/src/lib.rs | 4 ++-- helix-term/src/commands.rs | 2 +- helix-term/src/commands/typed.rs | 4 ++-- helix-term/src/ui/editor.rs | 2 +- helix-tui/src/buffer.rs | 6 +++--- helix-tui/src/widgets/reflow.rs | 4 ++-- helix-tui/src/widgets/table.rs | 4 ++-- helix-tui/tests/terminal.rs | 8 ++++---- helix-view/src/document.rs | 4 ++-- helix-view/src/view.rs | 2 +- 24 files changed, 52 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56a8b2572..bbc7dec28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -445,7 +445,7 @@ Fixes: - A bunch of bugs regarding `o`/`O` behavior ([#281](https://github.com/helix-editor/helix/pull/281)) - `~` expansion now works in file completion ([#284](https://github.com/helix-editor/helix/pull/284)) - Several UI related overflow crashes ([#318](https://github.com/helix-editor/helix/pull/318)) -- Fix a test failure occuring only on `test --release` ([`4f108ab1`](https://github.com/helix-editor/helix/commit/4f108ab1b2197809506bd7305ad903a3525eabfa)) +- Fix a test failure occurring only on `test --release` ([`4f108ab1`](https://github.com/helix-editor/helix/commit/4f108ab1b2197809506bd7305ad903a3525eabfa)) - Prompts now support unicode input ([#295](https://github.com/helix-editor/helix/pull/295)) - Completion documentation no longer overlaps the popup ([#322](https://github.com/helix-editor/helix/pull/322)) - Fix a crash when trying to select `^` ([`9c534614`](https://github.com/helix-editor/helix/commit/9c53461429a3e72e3b1fb87d7ca490e168d7dee2)) diff --git a/book/src/configuration.md b/book/src/configuration.md index fea60d2f3..439c80f1c 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -43,7 +43,7 @@ hidden = false | `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` | | `auto-info` | Whether to display infoboxes | `true` | | `true-color` | Set to `true` to override automatic detection of terminal truecolor support in the event of a false negative. | `false` | -| `rulers` | List of column positions at which to display the rulers. Can be overidden by language specific `rulers` in `languages.toml` file. | `[]` | +| `rulers` | List of column positions at which to display the rulers. Can be overridden by language specific `rulers` in `languages.toml` file. | `[]` | ### `[editor.lsp]` Section diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index ee00e9ce9..ac2102020 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -7,8 +7,8 @@ | `:buffer-close!`, `:bc!`, `:bclose!` | Close the current buffer forcefully (ignoring unsaved changes). | | `:buffer-close-others`, `:bco`, `:bcloseother` | Close all buffers but the currently focused one. | | `:buffer-close-others!`, `:bco!`, `:bcloseother!` | Close all buffers but the currently focused one. | -| `:buffer-close-all`, `:bca`, `:bcloseall` | Close all buffers, without quiting. | -| `:buffer-close-all!`, `:bca!`, `:bcloseall!` | Close all buffers forcefully (ignoring unsaved changes), without quiting. | +| `:buffer-close-all`, `:bca`, `:bcloseall` | Close all buffers, without quitting. | +| `:buffer-close-all!`, `:bca!`, `:bcloseall!` | Close all buffers forcefully (ignoring unsaved changes), without quitting. | | `:buffer-next`, `:bn`, `:bnext` | Go to next buffer. | | `:buffer-previous`, `:bp`, `:bprev` | Go to previous buffer. | | `:write`, `:w` | Write changes to disk. Accepts an optional path (:write some/path.txt) | diff --git a/book/src/guides/README.md b/book/src/guides/README.md index 96e629783..e0c44ce7d 100644 --- a/book/src/guides/README.md +++ b/book/src/guides/README.md @@ -1,4 +1,4 @@ # Guides This section contains guides for adding new language server configurations, -tree-sitter grammers, textobject queries, etc. +tree-sitter grammars, textobject queries, etc. diff --git a/book/src/guides/indent.md b/book/src/guides/indent.md index 235a30c44..f4d916b21 100644 --- a/book/src/guides/indent.md +++ b/book/src/guides/indent.md @@ -39,7 +39,7 @@ changed by using a `#set!` declaration anywhere in the pattern: ## Capture Types - `@indent` (default scope `tail`): -Increase the indent level by 1. Multiple occurences in the same line +Increase the indent level by 1. Multiple occurrences in the same line don't stack. If there is at least one `@indent` and one `@outdent` capture on the same line, the indent level isn't changed at all. diff --git a/book/src/install.md b/book/src/install.md index 3329d1c58..34d8b651c 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -58,7 +58,7 @@ cargo install --path helix-term This will install the `hx` binary to `$HOME/.cargo/bin`. Helix also needs it's runtime files so make sure to copy/symlink the `runtime/` directory into the -config directory (for example `~/.config/helix/runtime` on Linux/macOS). This location can be overriden +config directory (for example `~/.config/helix/runtime` on Linux/macOS). This location can be overridden via the `HELIX_RUNTIME` environment variable. | OS | command | diff --git a/book/src/keymap.md b/book/src/keymap.md index 942292e0b..2abe4f74a 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -191,7 +191,7 @@ Jumps to various locations. #### Match mode -Enter this mode using `m` from normal mode. See the relavant section +Enter this mode using `m` from normal mode. See the relevant section in [Usage](./usage.md) for an explanation about [surround](./usage.md#surround) and [textobject](./usage.md#textobject) usage. diff --git a/book/src/themes.md b/book/src/themes.md index 91ca18b10..e73aedc94 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -158,7 +158,7 @@ We use a similar set of scopes as - `builtin` - `method` - `macro` - - `special` (preprocesor in C) + - `special` (preprocessor in C) - `tag` - Tags (e.g. `` in HTML) diff --git a/book/theme/book.js b/book/theme/book.js index 5e386369f..407361838 100644 --- a/book/theme/book.js +++ b/book/theme/book.js @@ -601,10 +601,10 @@ function playground_text(playground) { }); })(); -(function controllMenu() { +(function controlMenu() { var menu = document.getElementById('menu-bar'); - (function controllPosition() { + (function controlPosition() { var scrollTop = document.scrollingElement.scrollTop; var prevScrollTop = scrollTop; var minMenuY = -menu.clientHeight - 50; @@ -647,7 +647,7 @@ function playground_text(playground) { prevScrollTop = scrollTop; }, { passive: true }); })(); - (function controllBorder() { + (function controlBorder() { menu.classList.remove('bordered'); document.addEventListener('scroll', function () { if (menu.offsetTop === 0) { diff --git a/book/theme/css/chrome.css b/book/theme/css/chrome.css index aba8a417b..4e0513178 100644 --- a/book/theme/css/chrome.css +++ b/book/theme/css/chrome.css @@ -390,7 +390,7 @@ ul#searchresults span.teaser em { .chapter li { display: flex; - color: var(--sidebar-non-existant); + color: var(--sidebar-non-existent); } .chapter li a { display: block; diff --git a/book/theme/css/variables.css b/book/theme/css/variables.css index b62c75581..1bf91b19a 100644 --- a/book/theme/css/variables.css +++ b/book/theme/css/variables.css @@ -16,7 +16,7 @@ --sidebar-bg: #14191f; --sidebar-fg: #c8c9db; - --sidebar-non-existant: #5c6773; + --sidebar-non-existent: #5c6773; --sidebar-active: #ffb454; --sidebar-spacer: #2d334f; @@ -56,7 +56,7 @@ --sidebar-bg: #292c2f; --sidebar-fg: #a1adb8; - --sidebar-non-existant: #505254; + --sidebar-non-existent: #505254; --sidebar-active: #3473ad; --sidebar-spacer: #393939; @@ -96,7 +96,7 @@ --sidebar-bg: #fafafa; --sidebar-fg: hsl(0, 0%, 0%); - --sidebar-non-existant: #aaaaaa; + --sidebar-non-existent: #aaaaaa; --sidebar-active: #1f1fff; --sidebar-spacer: #f4f4f4; @@ -136,7 +136,7 @@ --sidebar-bg: #282d3f; --sidebar-fg: #c8c9db; - --sidebar-non-existant: #505274; + --sidebar-non-existent: #505274; --sidebar-active: #2b79a2; --sidebar-spacer: #2d334f; @@ -176,7 +176,7 @@ --sidebar-bg: #3b2e2a; --sidebar-fg: #c8c9db; - --sidebar-non-existant: #505254; + --sidebar-non-existent: #505254; --sidebar-active: #e69f67; --sidebar-spacer: #45373a; @@ -217,7 +217,7 @@ --sidebar-bg: #292c2f; --sidebar-fg: #a1adb8; - --sidebar-non-existant: #505254; + --sidebar-non-existent: #505254; --sidebar-active: #3473ad; --sidebar-spacer: #393939; @@ -259,7 +259,7 @@ --sidebar-bg: #281733; --sidebar-fg: #c8c9db; - --sidebar-non-existant: #505274; + --sidebar-non-existent: #505274; --sidebar-active: #a4a0e8; --sidebar-spacer: #2d334f; @@ -304,7 +304,7 @@ --sidebar-bg: #281733; --sidebar-fg: #c8c9db; - --sidebar-non-existant: #505274; + --sidebar-non-existent: #505274; --sidebar-active: #a4a0e8; --sidebar-spacer: #2d334f; diff --git a/helix-core/src/history.rs b/helix-core/src/history.rs index bb95213c1..3f324e340 100644 --- a/helix-core/src/history.rs +++ b/helix-core/src/history.rs @@ -22,10 +22,10 @@ use std::time::{Duration, Instant}; /// /// The current revision is the one currently displayed in the buffer. /// -/// Commiting a new revision to the history will update the last child of the +/// Committing a new revision to the history will update the last child of the /// current revision, and push a new revision to the end of the vector. /// -/// Revisions are commited with a timestamp. :earlier and :later can be used +/// Revisions are committed with a timestamp. :earlier and :later can be used /// to jump to the closest revision to a moment in time relative to the timestamp /// of the current revision plus (:later) or minus (:earlier) the duration /// given to the command. If a single integer is given, the editor will instead @@ -33,7 +33,7 @@ use std::time::{Duration, Instant}; /// /// Limitations: /// * Changes in selections currently don't commit history changes. The selection -/// will only be updated to the state after a commited buffer change. +/// will only be updated to the state after a committed buffer change. /// * The vector of history revisions is currently unbounded. This might /// cause the memory consumption to grow significantly large during long /// editing sessions. @@ -288,7 +288,7 @@ pub enum UndoKind { TimePeriod(std::time::Duration), } -/// A subset of sytemd.time time span syntax units. +/// A subset of systemd.time time span syntax units. const TIME_UNITS: &[(&[&str], &str, u64)] = &[ (&["seconds", "second", "sec", "s"], "seconds", 1), (&["minutes", "minute", "min", "m"], "minutes", 60), diff --git a/helix-core/src/path.rs b/helix-core/src/path.rs index e0c3bef65..6bf722a77 100644 --- a/helix-core/src/path.rs +++ b/helix-core/src/path.rs @@ -14,7 +14,7 @@ pub fn fold_home_dir(path: &Path) -> PathBuf { path.to_path_buf() } -/// Expands tilde `~` into users home directory if avilable, otherwise returns the path +/// Expands tilde `~` into users home directory if available, otherwise returns the path /// unchanged. The tilde will only be expanded when present as the first component of the path /// and only slash follows it. pub fn expand_tilde(path: &Path) -> PathBuf { diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 2fd4ed9ba..3f9e7bcf8 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -229,7 +229,7 @@ pub struct TextObjectQuery { pub enum CapturedNode<'a> { Single(Node<'a>), - /// Guarenteed to be not empty + /// Guaranteed to be not empty Grouped(Vec>), } @@ -1141,7 +1141,7 @@ pub enum HighlightEvent { HighlightEnd, } -/// Contains the data neeeded to higlight code written in a particular language. +/// Contains the data needed to highlight code written in a particular language. /// /// This struct is immutable and can be shared between threads. #[derive(Debug)] @@ -1976,7 +1976,7 @@ mod test { let source = Rope::from_str( r#" /// a comment on -/// mutiple lines +/// multiple lines "#, ); @@ -2006,10 +2006,10 @@ mod test { ) }; - test("quantified_nodes", 1..35); + test("quantified_nodes", 1..36); // NOTE: Enable after implementing proper node group capturing - // test("quantified_nodes_grouped", 1..35); - // test("multiple_nodes_grouped", 1..35); + // test("quantified_nodes_grouped", 1..36); + // test("multiple_nodes_grouped", 1..36); } #[test] diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 47a376bb8..aeda16d0d 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -428,7 +428,7 @@ impl LspProgressMap { Self::default() } - /// Returns a map of all tokens coresponding to the lanaguage server with `id`. + /// Returns a map of all tokens corresponding to the language server with `id`. pub fn progress_map(&self, id: usize) -> Option<&HashMap> { self.0.get(&id) } @@ -466,7 +466,7 @@ impl LspProgressMap { self.0.get_mut(&id).and_then(|vals| vals.remove(token)) } - /// Updates the progess of `token` for server with `id` to `status`, returns the value replaced or `None`. + /// Updates the progress of `token` for server with `id` to `status`, returns the value replaced or `None`. pub fn update( &mut self, id: usize, diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 8a0313efe..ee2afb72f 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3715,7 +3715,7 @@ fn shrink_selection(cx: &mut Context) { doc.set_selection(view.id, prev_selection); return; } else { - // clear existing selection as they can't be shrinked to anyway + // clear existing selection as they can't be shrunk to anyway view.object_selections.clear(); } } diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 3e93cfd7a..394760a2f 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1169,14 +1169,14 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "buffer-close-all", aliases: &["bca", "bcloseall"], - doc: "Close all buffers, without quiting.", + doc: "Close all buffers, without quitting.", fun: buffer_close_all, completer: None, }, TypableCommand { name: "buffer-close-all!", aliases: &["bca!", "bcloseall!"], - doc: "Close all buffers forcefully (ignoring unsaved changes), without quiting.", + doc: "Close all buffers forcefully (ignoring unsaved changes), without quitting.", fun: force_buffer_close_all, completer: None, }, diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 798b8ac86..ce8746a75 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -1239,7 +1239,7 @@ impl Component for EditorView { view.ensure_cursor_in_view(doc, config.scrolloff); // Store a history state if not in insert mode. This also takes care of - // commiting changes when leaving insert mode. + // committing changes when leaving insert mode. if doc.mode() != Mode::Insert { doc.append_changes_to_history(view.id); } diff --git a/helix-tui/src/buffer.rs b/helix-tui/src/buffer.rs index 22956b04c..21c53aadf 100644 --- a/helix-tui/src/buffer.rs +++ b/helix-tui/src/buffer.rs @@ -322,7 +322,7 @@ impl Buffer { continue; } // `x_offset + width > max_offset` could be integer overflow on 32-bit machines if we - // change dimenstions to usize or u32 and someone resizes the terminal to 1x2^32. + // change dimensions to usize or u32 and someone resizes the terminal to 1x2^32. if width > max_offset.saturating_sub(x_offset) { break; } @@ -563,9 +563,9 @@ impl Buffer { let width = self.area.width; let mut updates: Vec<(u16, u16, &Cell)> = vec![]; - // Cells invalidated by drawing/replacing preceeding multi-width characters: + // Cells invalidated by drawing/replacing preceding multi-width characters: let mut invalidated: usize = 0; - // Cells from the current buffer to skip due to preceeding multi-width characters taking their + // Cells from the current buffer to skip due to preceding multi-width characters taking their // place (the skipped cells should be blank anyway): let mut to_skip: usize = 0; for (i, (current, previous)) in next_buffer.iter().zip(previous_buffer.iter()).enumerate() { diff --git a/helix-tui/src/widgets/reflow.rs b/helix-tui/src/widgets/reflow.rs index 380719405..c30aa6e03 100644 --- a/helix-tui/src/widgets/reflow.rs +++ b/helix-tui/src/widgets/reflow.rs @@ -128,7 +128,7 @@ pub struct LineTruncator<'a, 'b> { symbols: &'b mut dyn Iterator>, max_line_width: u16, current_line: Vec>, - /// Record the offet to skip render + /// Record the offset to skip render horizontal_offset: u16, } @@ -439,7 +439,7 @@ mod test { assert_eq!(line_truncator, vec![" "]); } - /// Tests an input starting with a letter, folowed by spaces - some of the behaviour is + /// Tests an input starting with a letter, followed by spaces - some of the behaviour is /// incidental. #[test] fn line_composer_char_plus_lots_of_spaces() { diff --git a/helix-tui/src/widgets/table.rs b/helix-tui/src/widgets/table.rs index 6aee5988c..eb03704ea 100644 --- a/helix-tui/src/widgets/table.rs +++ b/helix-tui/src/widgets/table.rs @@ -68,7 +68,7 @@ where /// Row::new(vec!["Cell1", "Cell2", "Cell3"]); /// ``` /// -/// But if you need a bit more control over individual cells, you can explicity create [`Cell`]s: +/// But if you need a bit more control over individual cells, you can explicitly create [`Cell`]s: /// ```rust /// # use helix_tui::widgets::{Row, Cell}; /// # use helix_view::graphics::{Style, Color}; @@ -109,7 +109,7 @@ impl<'a> Row<'a> { self } - /// Set the [`Style`] of the entire row. This [`Style`] can be overriden by the [`Style`] of a + /// Set the [`Style`] of the entire row. This [`Style`] can be overridden by the [`Style`] of a /// any individual [`Cell`] or event by their [`Text`] content. pub fn style(mut self, style: Style) -> Self { self.style = style; diff --git a/helix-tui/tests/terminal.rs b/helix-tui/tests/terminal.rs index 3e1c19e36..3dd3b0b0d 100644 --- a/helix-tui/tests/terminal.rs +++ b/helix-tui/tests/terminal.rs @@ -17,15 +17,15 @@ fn terminal_buffer_size_should_be_limited() { // let backend = TestBackend::new(10, 10); // let mut terminal = Terminal::new(backend)?; // let frame = terminal.draw(|f| { -// let paragrah = Paragraph::new("Test"); -// f.render_widget(paragrah, f.size()); +// let paragraph = Paragraph::new("Test"); +// f.render_widget(paragraph, f.size()); // })?; // assert_eq!(frame.buffer.get(0, 0).symbol, "T"); // assert_eq!(frame.area, Rect::new(0, 0, 10, 10)); // terminal.backend_mut().resize(8, 8); // let frame = terminal.draw(|f| { -// let paragrah = Paragraph::new("test"); -// f.render_widget(paragrah, f.size()); +// let paragraph = Paragraph::new("test"); +// f.render_widget(paragraph, f.size()); // })?; // assert_eq!(frame.buffer.get(0, 0).symbol, "t"); // assert_eq!(frame.area, Rect::new(0, 0, 8, 8)); diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index f4b4dc35f..9c3853c82 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -648,7 +648,7 @@ impl Document { .clone() // Map through changes .map(transaction.changes()) - // Ensure all selections accross all views still adhere to invariants. + // Ensure all selections across all views still adhere to invariants. .ensure_invariants(self.text.slice(..)); } @@ -752,7 +752,7 @@ impl Document { self.undo_redo_impl(view_id, true) } - /// Redo the last modification to the [`Document`]. Returns whether the redo was sucessful. + /// 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) } diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 3450da9b3..091d1f2ee 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -79,7 +79,7 @@ pub struct View { // uses two docs because we want to be able to swap between the // two last modified docs which we need to manually keep track of pub last_modified_docs: [Option; 2], - /// used to store previous selections of tree-sitter objecs + /// used to store previous selections of tree-sitter objects pub object_selections: Vec, pub gutters: Vec<(Gutter, usize)>, } From 477b88e99cb64576c0ea85b13f71fb43d36fc259 Mon Sep 17 00:00:00 2001 From: CossonLeo <20379044+cossonleo@users.noreply.github.com> Date: Thu, 28 Apr 2022 21:17:24 +0800 Subject: [PATCH 138/861] Wrap current directory picker with overlay widget (#2308) --- helix-term/src/commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index ee2afb72f..d1c1724a1 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2091,7 +2091,7 @@ fn file_picker(cx: &mut Context) { fn file_picker_in_current_directory(cx: &mut Context) { let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("./")); let picker = ui::file_picker(cwd, &cx.editor.config()); - cx.push_layer(Box::new(picker)); + cx.push_layer(Box::new(overlayed(picker))); } fn buffer_picker(cx: &mut Context) { From e10cf0851633bba1424b9211932a624c0f4c9a72 Mon Sep 17 00:00:00 2001 From: nosa <96927121+n0s4@users.noreply.github.com> Date: Fri, 29 Apr 2022 02:52:11 +0100 Subject: [PATCH 139/861] Extend tutor file (#2133) * Adds tutorial sections for multiple areas including: - Changing selections to uppercase / lowercase - yanking and pasting - macros - selecting to chars with t and f PS: I got kind of carried away and put off commiting for a while, will commit to commit more often in the future. * Changed section titles to all uppercase * Added recap and section about jumplist * Added sections for searching in file, joining lines and indenting lines. * Removed some trailing whitespace * Evened out the space between sections to all be 5 lines * Add section on opening lines (o) and recap * Changed the amount of lines between sections This is so that - on a 24 line terminal - only one section is visible at a time and page up/page down goes straight to the next section keeping the header at the top. * Punctuation error Co-authored-by: Omnikar * Punctuation error Co-authored-by: Omnikar * Spelling error Co-authored-by: Omnikar * Remove unnecessary word Co-authored-by: Omnikar * Reword note about searches Co-authored-by: Omnikar * Change word Co-authored-by: Omnikar * Update tutor file * Made some small changes suggested by Omnikar * Added better demo for macros. * Small changes - Add newlines at the end - Make "MACROS" section fit into 22 lines - Correct mistake of saying helix copied to clipboard in "COPYING AND PASTING TEXT" * Reformatted notes in copying/pasting section to fit in screen * Add a note about n and N and their difference to Vim. * Combine f and t commands into one section. * Removed t/T section which was merged into the f/F section. * Merge sections on manipulating case into one. * Gave section's numbers * Convert 'press' to 'type' in some places * Added examples of how prompt lines should look. * Reformatted notes in copy/pasting section. * More rewording to more comfortably fit sections on screen. * Grammatical error. * Missing periods. * Missing capital + small reformat * Fix mis-numbered section * Reworded to use these conventions when referring to inputs: - "Press" for single keypresses - "Type" for multiple keypresses / modifiers - "Use" when referencing two inputs as a pair. * till not 'til * Say 'press' instead of 'type' when referring to symbols * 'outdent' not 'unindent' * Typo and grammar. * Replace all 'press's with 'type's (apart from places it would make no sense in). * Improve examples for joining and indenting lines. * Section alignment. Co-authored-by: Omnikar --- runtime/tutor.txt | 407 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 348 insertions(+), 59 deletions(-) diff --git a/runtime/tutor.txt b/runtime/tutor.txt index b6f600d02..ae14eb788 100644 --- a/runtime/tutor.txt +++ b/runtime/tutor.txt @@ -12,7 +12,7 @@ _________________________________________________________________ you might be used to in that it is modal, meaning that it has different modes for editing text. The primary modes you will use are Normal mode and Insert mode. While in Normal mode, the - keys you press won't actually type text. Instead, they will + keys you type won't actually type text. Instead, they will perform various actions with the text. This allows for more efficient editing. This tutor will teach you how you can make use of Helix's modal editing features. To begin, ensure your @@ -21,7 +21,7 @@ _________________________________________________________________ ================================================================= -= BASIC CURSOR MOVEMENT = += 1.1 BASIC CURSOR MOVEMENT = ================================================================= ↑ @@ -43,18 +43,18 @@ _________________________________________________________________ ================================================================= -= EXITING HELIX = += 1.2 EXITING HELIX = ================================================================= - 1. Press the : key to enter command mode. Your cursor will + 1. Type : to enter command mode. Your cursor will move to the bottom of the screen. - 2. Type q or quit and press to exit Helix. + 2. Type q or quit and type to exit Helix. Note: The quit command will fail if there are unsaved changes. - To force quit and DISCARD these changes, use q! or quit!. + To force quit and DISCARD these changes, type q! or quit!. You will learn how to save files later. - To exit command mode without entering a command, press . + To exit command mode without entering a command, type . Now, move on to the next lesson. @@ -65,13 +65,13 @@ _________________________________________________________________ ================================================================= -= DELETION = += 1.3 DELETION = ================================================================= - Press the d key to delete the character under the cursor. + Type the d key to delete the character under the cursor. 1. Move the cursor to the line below marked -->. - 2. Move the cursor to each extra character, and press d to + 2. Move the cursor to each extra character, and type d to delete it. --> Thhiss senttencee haass exxtra charracterss. @@ -87,16 +87,16 @@ _________________________________________________________________ ================================================================= -= INSERT MODE = += 1.4 INSERT MODE = ================================================================= - Press the i key to enter Insert mode. + Type the i key to enter Insert mode. 1. Move the cursor to the line below marked -->. - 2. Move to a place in the line which is missing text and press - i to enter Insert mode. Keys you press will now type text. + 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. Press to exit Insert mode and return to Normal mode. + 4. type to exit Insert mode and return to Normal mode. 5. Repeat until the line matches the line below it. --> Th stce misg so. @@ -106,13 +106,13 @@ _________________________________________________________________ you may use the arrow keys instead of exiting and reentering Insert mode. Note: The status bar will display your current mode. - Notice that when you press i, 'NOR' changes to 'INS'. + Notice that when you type i, 'NOR' changes to 'INS'. ================================================================= -= MORE ON INSERT MODE = += 1.5 MORE ON INSERT MODE = ================================================================= - As you saw, you can press i to enter Insert mode at the current + As you saw, you can type i to enter Insert mode at the current position of the cursor. There are a few other ways you can enter Insert mode at different locations. @@ -123,7 +123,7 @@ _________________________________________________________________ A - Insert at the end of the line. 1. Move to anywhere in the line below marked -->. - 2. Press A ( + a), your cursor will move to the end of + 2. Type A ( + a), your cursor will move to the end of the line and you will be able to type. 3. Type the text necessary to match the line below. @@ -131,19 +131,19 @@ _________________________________________________________________ This sentence is missing some text. ================================================================= -= SAVING A FILE = += 1.6 SAVING A FILE = ================================================================= - Use :w/:write to save a file. + Type :w/:write to save a file. 1. Exit Helix using :q! as explained before, or open a new terminal. 2. Open a file in Helix by running: hx FILENAME 3. Make some edits to the file. - 4. Press the : key to enter command mode. - 5. Type w or write, and press to save the file. + 4. Type : to enter command mode. + 5. Type w or write, and type to save the file. - You can also use wq or write-quit to save and exit. + You can also type wq or write-quit to save and exit. Note: You can optionally enter a filepath after the w/write command in order to save to that path. @@ -153,21 +153,21 @@ _________________________________________________________________ ================================================================= -= RECAP = += CHAPTER 1 RECAP = ================================================================= * Use the h,j,k,l keys to move the cursor. - * Press : to enter command mode. + * Type : to enter command mode. * The q/quit and q!/quit! commands will exit Helix. The former fails when there are unsaved changes. The latter discards them. * The w/write command will save the file. * The wq/write-quit command will do both. - * Press d to delete the character at the cursor. + * Type d to delete the character at the cursor. - * Press i to enter Insert mode and type text. Press to + * Type i to enter Insert mode and type text. Type to return to Normal mode. @@ -175,10 +175,10 @@ _________________________________________________________________ ================================================================= -= MOTIONS AND SELECTIONS = += 2.1 MOTIONS AND SELECTIONS = ================================================================= - Press w to select forward until the next word. + Type w to select forward until the next word. The d key doesn't actually delete the character at the cursor, it deletes all selected text. Your cursor is like a @@ -186,8 +186,8 @@ _________________________________________________________________ 1. Move the cursor to the line below marked -->. 2. Move to the beginning of a word that needs to be deleted. - 3. Press w to select until the beginning of the next word. - 4. Press d to delete the selection. + 3. Type w to select until the beginning of the next word. + 4. Type d to delete the selection. 5. Repeat for all extra words in the line. --> This sentence pencil has vacuum extra words in the it. @@ -197,10 +197,10 @@ _________________________________________________________________ ================================================================= -= MORE ON MOTIONS = += 2.2 MORE ON MOTIONS = ================================================================= - As you saw, pressing w moves the cursor forward until the start + As you saw, typing w moves the cursor forward until the start of the next word, selecting the text traversed. This is useful for moving around text and for selecting text to operate on. @@ -219,18 +219,18 @@ _________________________________________________________________ ================================================================= -= THE CHANGE COMMAND = += 2.3 THE CHANGE COMMAND = ================================================================= - Press c to change the current selection. + Type c to change the current selection. The change command deletes the current selection and enters Insert mode, so it is a very common shorthand for di. 1. Move the cursor to the line below marked -->. - 2. Move to the start of an incorrect word and press w to + 2. Move to the start of an incorrect word and type w to select it. - 3. Press c to delete the word and enter Insert mode. + 3. Type c to delete the word and enter Insert mode. 4. Type the correct word. 5. Repeat until the line matches the line below it. @@ -241,7 +241,7 @@ _________________________________________________________________ ================================================================= -= COUNTS WITH MOTIONS = += 2.4 COUNTS WITH MOTIONS = ================================================================= Type a number before a motion to repeat it that many times. @@ -263,15 +263,15 @@ _________________________________________________________________ ================================================================= -= SELECTING LINES = += 2.5 SELECTING LINES = ================================================================= - Press x to select a whole line. Press again to select the next. + Type x to select a whole line. Type x again to select the next. 1. Move the cursor to the second line below marked -->. - 2. Press x to select the line, and d to delete it. + 2. Type x to select the line, and d to delete it. 3. Move to the fourth line. - 4. Press x twice or type 2x to select 2 lines, and d to delete. + 4. Type x twice or type 2x to select 2 lines, and d to delete. --> 1) Roses are red, --> 2) Mud is fun, @@ -285,13 +285,13 @@ _________________________________________________________________ ================================================================= -= UNDOING = += 2.6 UNDOING = ================================================================= Type u to undo. Type U to redo. 1. Move the cursor to the line below marked -->. - 2. Move to the first error, and press d to delete it. + 2. Move to the first error, and type d to delete it. 3. Type u to undo your deletion. 4. Fix all the errors on the line. 5. Type u several times to undo your fixes. @@ -307,7 +307,7 @@ _________________________________________________________________ ================================================================= -= RECAP = += CHAPTER 2 RECAP = ================================================================= * Type w to select forward until the next word. @@ -329,14 +329,14 @@ _________________________________________________________________ ================================================================= -= MULTIPLE CURSORS = += 3.1 MULTIPLE CURSORS = ================================================================= Type C to duplicate the cursor to the next line. 1. Move the cursor to the first line below marked -->. 2. Type C to duplicate the cursor to the next line. Keys you - press will now affect both cursors. + type will now affect both cursors. 3. Use Insert mode to correct the lines. The two cursors will fix both lines simultaneously. 4. Type , to remove the second cursor. @@ -346,22 +346,22 @@ _________________________________________________________________ Fix these two lines at the same time. - + Note: Type alt-C to do the same above the cursor. ================================================================= -= THE SELECT COMMAND = += 3.2 THE SELECT COMMAND = ================================================================= Type s to select matches in the selection. 1. Move the cursor to the line below marked -->. - 2. Press x to select the line. - 3. Press s. A prompt will appear. - 4. Type 'apples' and press . Both occurrences of + 2. Type x to select the line. + 3. Type s. A prompt will appear. + 4. Type 'apples' and type . Both occurrences of 'apples' in the line will be selected. - 5. You can now press c and change 'apples' to something else, + 5. You can now type c and change 'apples' to something else, like 'oranges'. 6. Type , to remove the second cursor. @@ -373,16 +373,16 @@ _________________________________________________________________ ================================================================= -= SELECTING VIA REGEX = += 3.3 SELECTING VIA REGEX = ================================================================= The select command selects regular expressions, not just exact matches, allowing you to target more complex patterns. 1. Move the cursor to the line below marked -->. - 2. Select the line with x and then press s. + 2. Select the line with x and then type s. 3. Enter ' +' to select any amount of consecutive spaces >1. - 4. Press c and change the matches to single spaces. + 4. Type c and change the matches to single spaces. --> This sentence has some extra spaces. @@ -395,7 +395,7 @@ _________________________________________________________________ ================================================================= -= COLLAPSING SELECTIONS = += 3.4 COLLAPSING SELECTIONS = ================================================================= Type ; to collapse selections to single cursors. @@ -404,7 +404,6 @@ _________________________________________________________________ cursor(s). This can be done using the ; key. 1. Move the cursor to the line below marked -->. - 2. Use the motions you have learned to move around the line, and try using ; to deselect the text after it is selected by the motions. @@ -416,6 +415,296 @@ _________________________________________________________________ + +================================================================= += 3.5 SELECTING TO A CHARACTER = +================================================================= + + Type f to select up to and including (find) a character. + Type t to do the same, but not including (till) a character. + Type uppercase F/T to do the same backwards. + + 1. Move the cursor to the line below marked -->. Place the + cursor on the first dash. + 2. Type f[ to select to the square bracket. + 3. Type d to delete your selection. + 4. Go to the end of the line and repeat with F]. + 5. Move to the second line marked -->, just after the arrow. + 6. Use t and T to delete the dashes around the sentence. + + --> -----[Free this sentence of its brackets!]----- + --> ------Free this sentence of its dashes!------ + + Note: Unlike Vim, Helix doesn't limit these commands to the + current line. It searches for the character in the file. + +================================================================= += CHAPTER 3 RECAP = +================================================================= + + * Type C to copy the selection on the line below and Alt-C for + above. + + * Type s to select all instances of a regex pattern inside + the current selection. + + * Type semicolon ( ; ) to collapse selection. + + * Type f / F to extend selection up to & including a character. + + * Type t / T to extend selection until a character. + + + + + + + +================================================================= += 4.1 COPYING AND PASTING TEXT = +================================================================= + + Type y to yank (copy) the selection. + Type p to paste the yanked selection after the cursor. + Type P to paste the yanked text before the cursor. + + 1. Move the cursor to the line below marked -->. + Make sure your cursor is on the "b" of banana. + 2. Type w to select "banana" and y to yank it. + 3. Move to the space between "2" and "3" and type p to paste. + 4. Repeat between "3" and "4". + + --> 1 banana 2 3 4 + 1 banana 2 banana 3 banana 4 + + Note: Whenever you delete or change text, Helix will copy the + altered text. Use alt-d/c instead to avoid this. + Note: Helix doesn't share the system clipboard by default. Type + space-y/p to yank/paste on your computer's main clipboard. + +================================================================= += 4.2 CHANGING CASE = +================================================================= + + Type ~ to switch the case of all selected letters. + Type ` to set all selected letters to lowercase. + Type Alt-` to set all selected letters to uppercase. + + 1. Move the cursor to the first line below marked -->. + 2. Select each wrongly capitalised or lowercase letter + and type ~ over them. + 3. Move to the second line marked -->. + 4. Type x to select the line. + 5. Type ` to change the line to lowercase. + 6. Move to the third line marked -->. + 7. Type x to select the line. + 8. Type Alt-` to change the line to uppercase. + + --> thIs sENtencE hAs MIS-cApitalIsed leTTerS. + --> this SENTENCE SHOULD all be in LOWERCASE. + --> THIS sentence should ALL BE IN uppercase! + +================================================================= += 4.3 MACROS = +================================================================= + + Macros are a way to record a set of actions you want to repeat. + + Type Q to start recording a macro, you should see a popup at + the bottom of your screen. Type Q again to stop recording. + Type q to repeat your recorded macro. + + 1. Move the cursor to the first line below marked -->. + 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. + 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. + +================================================================= += CHAPTER 4 RECAP = +================================================================= + + * Type y to yank (copy) text and p to paste. + * Type space-Y and space-P to yank/paste on the system + clipboard. + + * Type ~ to alternate case of selected letters. + * Use ` and alt-` to set the case of selected layers to + upper and lower respectively. + + * Type Q to record and stop recording a macro. + * Type q to repeat the recorded macro. + + + + + + + + +================================================================= += 5.1 USING THE JUMPLIST = +================================================================= + + Helix can keep track of "jumps" which are big movements, like + jumping to the definition of a function in code. It stores + these in what's called the jumplist. + + Type C-s (ctrl-s) to manually save your current position to + the jumplist. + + Type C-i and C-o to move forward and backwards in the jumplist + respectively. + + 1. Type C-s somewhere. + 2. Move far away in the file. + 3. Type C-o (just once!) to come back to where you saved. + + + + + +================================================================= += 5.2 SEARCHING IN FILE = +================================================================= + + Type / to search forward in file, enter to confirm search. + Type n to go to the next search match. + Type N to go to the previous search match. + + 1. Type / and type in a common word, like 'banana'. + 2. Type enter to confirm the search. + 3. Use n and N to cycle through the matches. + + Like the select command, searching also uses regex. + + Note: To search backwards, type ? (shift-/). + + Note: Unlike Vim, N doesn't change the search direction. + N always goes backwards and n always goes forwards. + + + + +================================================================= += CHAPTER 5 RECAP = +================================================================= + + * Type C-s to save position to the jumplist. + * Type C-i and C-o to go forward and backward in the jumplist. + + * Type / to search forward in file, and ? to search backwards. + * Use n and N to cycle through search matches. + + + + + + + + + + + + + +================================================================= += 6.1 JOINING LINES = +================================================================= + + Type J to join together lines in selection. + + 1. Move the cursor to the line below marked -->. + 2. Type J thrice or 3J to join the sentence to one line. + + --> This line sentence +is spilling over +onto other +lines. + + Note: J works on all lines in selection, so typing xxx or 3x to + select the lines and then a single J will work the same. + + + + + + +================================================================= += 6.2 INDENTING LINES = +================================================================= + + Type > to indent a line and < to outdent it. + + 1. Move the cursor to the line below marked -->. + 2. Move down to the second line and type > to indent it. + 3. Move to the third line and type < to unindent it. + + --> These lines + are indented + very poorly. + + These lines + are indented + much better. + + + + + +================================================================= += 6.3 OPENING LINES = +================================================================= + + Type o to add a newline and insert below the cursor. + Type O to add a newline and insert above the cursor. + + 1. Move the cursor to the line below marked -->. + 2. Type o to open a line below and type your answer. + + --> What is the best editor? + + + + + + + + + + + +================================================================= += CHAPTER 6 RECAP = +================================================================= + + * Type J to join lines within selection. + + * Type > and < to indent and outdent selected lines. + + * Use o and O to open lines. + + + + + + + + + + + + + ================================================================= This tutorial is still a work-in-progress. More sections are planned. + + + From ab6a00e196832d3a2b942641f914a0c9727129e4 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Fri, 29 Apr 2022 14:49:15 +0800 Subject: [PATCH 140/861] Make A-hjkl tree-sitter nav A-pion (#2205) A-hl currently is not very consistent with hl when next object is selected, since it may go up/down or left/right and this behavior is confusing such that some people think it should swap the keys with A-jk, so it is better to use A-pn since that only specifies two direction. A-jk have the same issue as in it usually moves right and is not consistent with the behavior of jk so people may think A-hl is better, maybe A-oi is better here since A-hl will be swapped to A-pn, A-oi can convey the meaning of in and out, similar to some window manager keys? --- book/src/keymap.md | 8 ++++---- helix-term/src/keymap/default.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index 2abe4f74a..77682a388 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -111,10 +111,10 @@ | `K` | Keep selections matching the regex | `keep_selections` | | `Alt-K` | Remove selections matching the regex | `remove_selections` | | `Ctrl-c` | Comment/uncomment the selections | `toggle_comments` | -| `Alt-k`, `Alt-up` | Expand selection to parent syntax node (**TS**) | `expand_selection` | -| `Alt-j`, `Alt-down` | Shrink syntax tree object selection (**TS**) | `shrink_selection` | -| `Alt-h`, `Alt-left` | Select previous sibling node in syntax tree (**TS**) | `select_prev_sibling` | -| `Alt-l`, `Alt-right` | Select next sibling node in syntax tree (**TS**) | `select_next_sibling` | +| `Alt-o`, `Alt-up` | Expand selection to parent syntax node (**TS**) | `expand_selection` | +| `Alt-i`, `Alt-down` | Shrink syntax tree object selection (**TS**) | `shrink_selection` | +| `Alt-p`, `Alt-left` | Select previous sibling node in syntax tree (**TS**) | `select_prev_sibling` | +| `Alt-n`, `Alt-right` | Select next sibling node in syntax tree (**TS**) | `select_next_sibling` | ### Search diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index 10a43d122..da5127b2f 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -79,10 +79,10 @@ pub fn default() -> HashMap { "S" => split_selection, ";" => collapse_selection, "A-;" => flip_selections, - "A-k" | "A-up" => expand_selection, - "A-j" | "A-down" => shrink_selection, - "A-h" | "A-left" => select_prev_sibling, - "A-l" | "A-right" => select_next_sibling, + "A-o" | "A-up" => expand_selection, + "A-i" | "A-down" => shrink_selection, + "A-p" | "A-left" => select_prev_sibling, + "A-n" | "A-right" => select_next_sibling, "%" => select_all, "x" => extend_line, From c22873c33fa0163257b1421faa6f91268ad3a4d1 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Fri, 29 Apr 2022 14:50:01 +0800 Subject: [PATCH 141/861] Change A-left right to C-left right in insert (#2193) Currently A-left move one word left and the behavior will be more consistent for people coming GUI world if the key was changed to control given that both browsers and editors like vscode uses C-left right by default to move word rather than alt. --- book/src/keymap.md | 4 ++-- helix-term/src/keymap/default.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index 77682a388..9d5d08417 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -296,9 +296,9 @@ undo-able "save point" until you return to normal mode. | `Ctrl-r` | Insert a register content | `insert_register` | | `Ctrl-w`, `Alt-Backspace` | Delete previous word | `delete_word_backward` | | `Alt-d` | Delete next word | `delete_word_forward` | -| `Alt-b`, `Alt-Left` | Backward a word | `move_prev_word_end` | +| `Alt-b`, `Ctrl-Left` | Backward a word | `move_prev_word_end` | | `Ctrl-b`, `Left` | Backward a char | `move_char_left` | -| `Alt-f`, `Alt-Right` | Forward a word | `move_next_word_start` | +| `Alt-f`, `Ctrl-Right` | Forward a word | `move_next_word_start` | | `Ctrl-f`, `Right` | Forward a char | `move_char_right` | | `Ctrl-e`, `End` | Move to line end | `goto_line_end_newline` | | `Ctrl-a`, `Home` | Move to line start | `goto_line_start` | diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index da5127b2f..db24e97a7 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -336,9 +336,9 @@ pub fn default() -> HashMap { "right" => move_char_right, "C-f" => move_char_right, "A-b" => move_prev_word_end, - "A-left" => move_prev_word_end, + "C-left" => move_prev_word_end, "A-f" => move_next_word_start, - "A-right" => move_next_word_start, + "C-right" => move_next_word_start, "A-<" => goto_file_start, "A->" => goto_file_end, "pageup" => page_up, From de15d7017186cb735cdd31d12510f61a1707d5fb Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sun, 3 Apr 2022 21:31:43 +0530 Subject: [PATCH 142/861] Add `m` textobject to select closest surround pair --- book/src/usage.md | 1 + helix-core/src/surround.rs | 39 ++++++++++++++++++++++++++++++++++++ helix-core/src/textobject.rs | 26 +++++++++++++++++++++++- helix-term/src/commands.rs | 9 +-------- 4 files changed, 66 insertions(+), 9 deletions(-) diff --git a/book/src/usage.md b/book/src/usage.md index 010e30f59..7871e2b9e 100644 --- a/book/src/usage.md +++ b/book/src/usage.md @@ -66,6 +66,7 @@ Currently supported: `word`, `surround`, `function`, `class`, `parameter`. | `w` | Word | | `W` | WORD | | `(`, `[`, `'`, etc | Specified surround pairs | +| `m` | Closest surround pair | | `f` | Function | | `c` | Class | | `a` | Argument/parameter | diff --git a/helix-core/src/surround.rs b/helix-core/src/surround.rs index c14456b73..4cba81bff 100644 --- a/helix-core/src/surround.rs +++ b/helix-core/src/surround.rs @@ -52,6 +52,45 @@ pub fn get_pair(ch: char) -> (char, char) { .unwrap_or((ch, ch)) } +pub fn find_nth_closest_pairs_pos( + text: RopeSlice, + range: Range, + n: usize, +) -> Result<(usize, usize)> { + let is_open_pair = |ch| PAIRS.iter().any(|(open, _)| *open == ch); + let is_close_pair = |ch| PAIRS.iter().any(|(_, close)| *close == ch); + + let mut stack = Vec::with_capacity(2); + let pos = range.cursor(text); + + for ch in text.chars_at(pos) { + if is_open_pair(ch) { + // Track open pairs encountered so that we can step over + // the correspoding close pairs that will come up further + // down the loop. We want to find a lone close pair whose + // open pair is before the cursor position. + stack.push(ch); + continue; + } else if is_close_pair(ch) { + let (open, _) = get_pair(ch); + if stack.last() == Some(&open) { + stack.pop(); + continue; + } else { + // In the ideal case the stack would be empty here and the + // current character would be the close pair that we are + // looking for. It could also be the case that the pairs + // are unbalanced and we encounter a close pair that doesn't + // close the last seen open pair. In either case use this + // char as the auto-detected closest pair. + return find_nth_pairs_pos(text, ch, range, n); + } + } + } + + Err(Error::PairNotFound) +} + /// Find the position of surround pairs of `ch` which can be either a closing /// or opening pair. `n` will skip n - 1 pairs (eg. n=2 will discard (only) /// the first pair found and keep looking) diff --git a/helix-core/src/textobject.rs b/helix-core/src/textobject.rs index ab418792c..ee06bf470 100644 --- a/helix-core/src/textobject.rs +++ b/helix-core/src/textobject.rs @@ -205,7 +205,31 @@ pub fn textobject_surround( ch: char, count: usize, ) -> Range { - surround::find_nth_pairs_pos(slice, ch, range, count) + textobject_surround_impl(slice, range, textobject, Some(ch), count) +} + +pub fn textobject_surround_closest( + slice: RopeSlice, + range: Range, + textobject: TextObject, + count: usize, +) -> Range { + textobject_surround_impl(slice, range, textobject, None, count) +} + +fn textobject_surround_impl( + slice: RopeSlice, + range: Range, + textobject: TextObject, + ch: Option, + count: usize, +) -> Range { + let pair_pos = match ch { + Some(ch) => surround::find_nth_pairs_pos(slice, ch, range, count), + // Automatically find the closest surround pairs + None => surround::find_nth_closest_pairs_pos(slice, range, count), + }; + pair_pos .map(|(anchor, head)| match textobject { TextObject::Inside => Range::new(next_grapheme_boundary(slice, anchor), head), TextObject::Around => Range::new(anchor, next_grapheme_boundary(slice, head)), diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index d1c1724a1..75c84b748 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4040,14 +4040,7 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) { 'a' => textobject_treesitter("parameter", range), 'o' => textobject_treesitter("comment", range), 'p' => textobject::textobject_paragraph(text, range, objtype, count), - 'm' => { - let ch = text.char(range.cursor(text)); - if !ch.is_ascii_alphanumeric() { - textobject::textobject_surround(text, range, objtype, ch, count) - } else { - range - } - } + 'm' => textobject::textobject_surround_closest(text, range, objtype, count), // TODO: cancel new ranges if inconsistent surround matches across lines ch if !ch.is_ascii_alphanumeric() => { textobject::textobject_surround(text, range, objtype, ch, count) From 76175dbd6da4f57118eb52477f3336c6dcab5692 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sun, 3 Apr 2022 22:00:26 +0530 Subject: [PATCH 143/861] Support m in surround delete and replace --- helix-core/src/surround.rs | 11 ++++++++--- helix-term/src/commands.rs | 14 ++++++++------ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/helix-core/src/surround.rs b/helix-core/src/surround.rs index 4cba81bff..6f1fdb95d 100644 --- a/helix-core/src/surround.rs +++ b/helix-core/src/surround.rs @@ -212,17 +212,22 @@ fn find_nth_close_pair( /// Find position of surround characters around every cursor. Returns None /// if any positions overlap. Note that the positions are in a flat Vec. /// Use get_surround_pos().chunks(2) to get matching pairs of surround positions. -/// `ch` can be either closing or opening pair. +/// `ch` can be either closing or opening pair. If `ch` is None, surround pairs +/// are automatically detected around each cursor (note that this may result +/// in them selecting different surround characters for each selection). pub fn get_surround_pos( text: RopeSlice, selection: &Selection, - ch: char, + ch: Option, skip: usize, ) -> Result> { let mut change_pos = Vec::new(); for &range in selection { - let (open_pos, close_pos) = find_nth_pairs_pos(text, ch, range, skip)?; + let (open_pos, close_pos) = match ch { + Some(ch) => find_nth_pairs_pos(text, ch, range, skip)?, + None => find_nth_closest_pairs_pos(text, range, skip)?, + }; if change_pos.contains(&open_pos) || change_pos.contains(&close_pos) { return Err(Error::CursorOverlap); } diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 75c84b748..54dcc98fc 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4111,15 +4111,16 @@ fn surround_add(cx: &mut Context) { fn surround_replace(cx: &mut Context) { let count = cx.count(); cx.on_next_key(move |cx, event| { - let from = match event.char() { - Some(from) => from, + let surround_ch = match event.char() { + Some('m') => None, // m selects the closest surround pair + Some(ch) => Some(ch), None => return, }; let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); let selection = doc.selection(view.id); - let change_pos = match surround::get_surround_pos(text, selection, from, count) { + let change_pos = match surround::get_surround_pos(text, selection, surround_ch, count) { Ok(c) => c, Err(err) => { cx.editor.set_error(err.to_string()); @@ -4150,15 +4151,16 @@ fn surround_replace(cx: &mut Context) { fn surround_delete(cx: &mut Context) { let count = cx.count(); cx.on_next_key(move |cx, event| { - let ch = match event.char() { - Some(ch) => ch, + let surround_ch = match event.char() { + Some('m') => None, // m selects the closest surround pair + Some(ch) => Some(ch), None => return, }; let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); let selection = doc.selection(view.id); - let change_pos = match surround::get_surround_pos(text, selection, ch, count) { + let change_pos = match surround::get_surround_pos(text, selection, surround_ch, count) { Ok(c) => c, Err(err) => { cx.editor.set_error(err.to_string()); From 22ae1b92a6ef312a1a796bf857cca590efb970d6 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Mon, 18 Apr 2022 22:36:22 +0530 Subject: [PATCH 144/861] Fix tests for surround primitives --- helix-core/src/surround.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/helix-core/src/surround.rs b/helix-core/src/surround.rs index 6f1fdb95d..db51b8f18 100644 --- a/helix-core/src/surround.rs +++ b/helix-core/src/surround.rs @@ -343,7 +343,7 @@ mod test { // cursor on s[o]me, c[h]ars, newl[i]ne assert_eq!( - get_surround_pos(slice, &selection, '(', 1) + get_surround_pos(slice, &selection, Some('('), 1) .unwrap() .as_slice(), &[0, 5, 7, 13, 15, 23] @@ -359,7 +359,7 @@ mod test { Selection::new(SmallVec::from_slice(&[Range::point(2), Range::point(9)]), 0); // cursor on s[o]me, c[h]ars assert_eq!( - get_surround_pos(slice, &selection, '(', 1), + get_surround_pos(slice, &selection, Some('('), 1), Err(Error::PairNotFound) // different surround chars ); @@ -369,7 +369,7 @@ mod test { ); // cursor on [x]x, newli[n]e assert_eq!( - get_surround_pos(slice, &selection, '(', 1), + get_surround_pos(slice, &selection, Some('('), 1), Err(Error::PairNotFound) // overlapping surround chars ); @@ -377,7 +377,7 @@ mod test { Selection::new(SmallVec::from_slice(&[Range::point(2), Range::point(3)]), 0); // cursor on s[o][m]e assert_eq!( - get_surround_pos(slice, &selection, '[', 1), + get_surround_pos(slice, &selection, Some('['), 1), Err(Error::CursorOverlap) ); } From 21487d13fd6c651349fb8bb476f1aff3a6c61f8c Mon Sep 17 00:00:00 2001 From: Erin van der Veen Date: Fri, 29 Apr 2022 14:34:15 +0200 Subject: [PATCH 145/861] feat(lang): Update nickel to include "rec" keyword (#2320) --- languages.toml | 2 +- runtime/queries/nickel/highlights.scm | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 76d1f43a9..660cb4ca8 100644 --- a/languages.toml +++ b/languages.toml @@ -424,7 +424,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "nickel" -source = { git = "https://github.com/nickel-lang/tree-sitter-nickel", rev = "85348774ccf7624fac72703b2264d18b6f572be6" } +source = { git = "https://github.com/nickel-lang/tree-sitter-nickel", rev = "c4dd1420b6cfeb6103d38eb1ce5195eb81197edc" } [[language]] name = "nix" diff --git a/runtime/queries/nickel/highlights.scm b/runtime/queries/nickel/highlights.scm index a204dfcac..cd458df27 100644 --- a/runtime/queries/nickel/highlights.scm +++ b/runtime/queries/nickel/highlights.scm @@ -22,6 +22,7 @@ (record_operand (atom (ident) @variable)) (let_expr "let" @keyword + "rec"? @keyword pat: (pattern (ident) @variable ) From 667cdf929f6fa70b3b8006e070cf3c100377eb3f Mon Sep 17 00:00:00 2001 From: Yang Tang Date: Fri, 29 Apr 2022 12:03:46 -0400 Subject: [PATCH 146/861] Fix spelling errors in some themes (#2324) --- runtime/themes/monokai_pro.toml | 2 +- runtime/themes/monokai_pro_machine.toml | 2 +- runtime/themes/monokai_pro_octagon.toml | 2 +- runtime/themes/monokai_pro_ristretto.toml | 2 +- runtime/themes/monokai_pro_spectrum.toml | 2 +- runtime/themes/nord.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/runtime/themes/monokai_pro.toml b/runtime/themes/monokai_pro.toml index 520bf70c1..b28f700cd 100644 --- a/runtime/themes/monokai_pro.toml +++ b/runtime/themes/monokai_pro.toml @@ -41,7 +41,7 @@ "ui.text" = { fg = "base8" } "punctuation" = "base6" -# classes, types, primiatives +# classes, types, primitives "type" = "green" "type.builtin" = { fg = "red"} "label" = "base8" diff --git a/runtime/themes/monokai_pro_machine.toml b/runtime/themes/monokai_pro_machine.toml index 8d493f1e2..4a2e53e42 100644 --- a/runtime/themes/monokai_pro_machine.toml +++ b/runtime/themes/monokai_pro_machine.toml @@ -41,7 +41,7 @@ "ui.text" = { fg = "base8" } "punctuation" = "base6" -# classes, types, primiatives +# classes, types, primitives "type" = "green" "type.builtin" = { fg = "red"} "label" = "base8" diff --git a/runtime/themes/monokai_pro_octagon.toml b/runtime/themes/monokai_pro_octagon.toml index 8a69077bc..48709145e 100644 --- a/runtime/themes/monokai_pro_octagon.toml +++ b/runtime/themes/monokai_pro_octagon.toml @@ -41,7 +41,7 @@ "ui.text" = { fg = "base8" } "punctuation" = "base6" -# classes, types, primiatives +# classes, types, primitives "type" = "green" "type.builtin" = { fg = "red"} "label" = "base8" diff --git a/runtime/themes/monokai_pro_ristretto.toml b/runtime/themes/monokai_pro_ristretto.toml index f0d60dad1..f7c370949 100644 --- a/runtime/themes/monokai_pro_ristretto.toml +++ b/runtime/themes/monokai_pro_ristretto.toml @@ -41,7 +41,7 @@ "ui.text" = { fg = "base8" } "punctuation" = "base6" -# classes, types, primiatives +# classes, types, primitives "type" = "green" "type.builtin" = { fg = "red"} "label" = "base8" diff --git a/runtime/themes/monokai_pro_spectrum.toml b/runtime/themes/monokai_pro_spectrum.toml index 54a53bfa9..807c87f15 100644 --- a/runtime/themes/monokai_pro_spectrum.toml +++ b/runtime/themes/monokai_pro_spectrum.toml @@ -41,7 +41,7 @@ "ui.text" = { fg = "base8" } "punctuation" = "base6" -# classes, types, primiatives +# classes, types, primitives "type" = "green" "type.builtin" = { fg = "red"} "label" = "base8" diff --git a/runtime/themes/nord.toml b/runtime/themes/nord.toml index 9fd3fcab3..a6384d1b3 100644 --- a/runtime/themes/nord.toml +++ b/runtime/themes/nord.toml @@ -46,7 +46,7 @@ "punctuation" = "nord6" # Frost -# nord7 - classes, types, primiatives +# nord7 - classes, types, primitives "type" = "nord7" "type.builtin" = { fg = "nord7"} "label" = "nord7" From 668b39d1dfa21097540a9b29144c4fcc1f24b63c Mon Sep 17 00:00:00 2001 From: Erasin Date: Sat, 30 Apr 2022 00:11:36 +0800 Subject: [PATCH 147/861] change cursor for copy selection (#2323) --- runtime/themes/onelight.toml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/runtime/themes/onelight.toml b/runtime/themes/onelight.toml index 84d47f340..3674e821e 100644 --- a/runtime/themes/onelight.toml +++ b/runtime/themes/onelight.toml @@ -70,11 +70,9 @@ "ui.background" = { bg = "white" } -"ui.cursor" = { fg = "black", modifiers = ["reversed"] } -"ui.cursor.primary" = { fg = "white", bg="black", modifiers = [] } -"ui.cursor.match" = { fg = "purple", modifiers = ["underlined", "bold"] } -"ui.cursor.select" = { bg = "purple" } -"ui.cursor.insert" = { bg = "white" } +"ui.cursor" = { fg = "white", bg = "black" } +"ui.cursor.primary" = { fg = "white", bg = "black" } +"ui.cursor.match" = { fg = "white", bg = "purple" } "ui.highlight" = { bg = "light-white" } @@ -85,7 +83,6 @@ "ui.virtual.ruler" = { bg = "light-white" } "ui.virtual.whitespace" = {fg = "light-white" } - "ui.linenr" = { fg = "linenr" } "ui.linenr.selected" = { fg = "black", modifiers = ["reversed"] } From 030e7ab9884d9f319993a1987d64fa45956aaefe Mon Sep 17 00:00:00 2001 From: unrelentingtech Date: Fri, 29 Apr 2022 20:40:59 +0300 Subject: [PATCH 148/861] fix(docs): cleanup obsolete indents.toml mentions (#2327) --- README.md | 2 +- book/src/guides/adding_languages.md | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 9c7b11777..c03c14a23 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ It's a terminal-based editor first, but I'd like to explore a custom renderer (similar to emacs) in wgpu or skulpin. Note: Only certain languages have indentation definitions at the moment. Check -`runtime/queries//` for `indents.toml`. +`runtime/queries//` for `indents.scm`. # Installation diff --git a/book/src/guides/adding_languages.md b/book/src/guides/adding_languages.md index e9e1a69f3..0cd6c27bb 100644 --- a/book/src/guides/adding_languages.md +++ b/book/src/guides/adding_languages.md @@ -91,8 +91,6 @@ the last matching query supersedes the ones before it. See - If a parser is segfaulting or you want to remove the parser, make sure to remove the compiled parser in `runtime/grammar/.so` -- The indents query is `indents.toml`, *not* `indents.scm`. See [this](https://github.com/helix-editor/helix/issues/114) issue for more information. - [treesitter-language-injection]: https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection [languages.toml]: https://github.com/helix-editor/helix/blob/master/languages.toml [neovim-query-precedence]: https://github.com/helix-editor/helix/pull/1170#issuecomment-997294090 From 8e77e3388c5ea23f22bb5f8e7ff50906ff0116a3 Mon Sep 17 00:00:00 2001 From: unrelentingtech Date: Fri, 29 Apr 2022 23:08:00 +0300 Subject: [PATCH 149/861] feat(lang): add devicetree (Flattened Device Tree Source) (#2329) --- book/src/generated/lang-support.md | 1 + languages.toml | 13 +++++ runtime/queries/devicetree/highlights.scm | 66 +++++++++++++++++++++++ runtime/queries/devicetree/indents.scm | 12 +++++ 4 files changed, 92 insertions(+) create mode 100644 runtime/queries/devicetree/highlights.scm create mode 100644 runtime/queries/devicetree/indents.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 69ae35c12..fe697cdf7 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -8,6 +8,7 @@ | cpp | ✓ | ✓ | ✓ | `clangd` | | css | ✓ | | | `vscode-css-language-server` | | dart | ✓ | | ✓ | `dart` | +| devicetree | ✓ | | ✓ | | | dockerfile | ✓ | | | `docker-langserver` | | eex | ✓ | | | | | ejs | ✓ | | | | diff --git a/languages.toml b/languages.toml index 660cb4ca8..e5230fbaa 100644 --- a/languages.toml +++ b/languages.toml @@ -1263,3 +1263,16 @@ indent = { tab-width = 4, unit = "\t" } [[grammar]] name = "hare" source = { git = "https://git.sr.ht/~ecmma/tree-sitter-hare", rev = "bc26a6a949f2e0d98b7bfc437d459b250900a165" } + +[[language]] +name = "devicetree" +scope = "source.devicetree" +injection-regex = "(dtsi?|devicetree|fdt)" +file-types = ["dts", "dtsi"] +roots = [] +comment-token = "//" +indent = { tab-width = 4, unit = "\t" } + +[[grammar]] +name = "devicetree" +source = { git = "https://github.com/joelspadin/tree-sitter-devicetree", rev = "877adbfa0174d25894c40fa75ad52d4515a36368" } diff --git a/runtime/queries/devicetree/highlights.scm b/runtime/queries/devicetree/highlights.scm new file mode 100644 index 000000000..d27c79e4a --- /dev/null +++ b/runtime/queries/devicetree/highlights.scm @@ -0,0 +1,66 @@ +[ + "/dts-v1/" + "/memreserve/" + "/delete-node/" + "/delete-property/" +] @keyword + +[ + "#define" + "#include" +] @keyword.directive + +[ + "!" + "~" + "-" + "+" + "*" + "/" + "%" + "||" + "&&" + "|" + "^" + "&" + "==" + "!=" + ">" + ">=" + "<=" + ">" + "<<" + ">>" +] @operator + +[ + "," + ";" +] @punctuation.delimiter + +[ + "(" + ")" + "{" + "}" + "<" + ">" +] @punctuation.bracket + +(string_literal) @string + +(integer_literal) @constant.numeric.integer + +(call_expression + function: (identifier) @function) + +(labeled_item + label: (identifier) @label) + +(identifier) @variable + +(unit_address) @tag + +(reference) @constant + +(comment) @comment diff --git a/runtime/queries/devicetree/indents.scm b/runtime/queries/devicetree/indents.scm new file mode 100644 index 000000000..064908890 --- /dev/null +++ b/runtime/queries/devicetree/indents.scm @@ -0,0 +1,12 @@ +[ + (node) + (byte_string_literal) + (parenthesized_expression) + (argument_list) +] @indent + +[ + "}" + "]" + ")" +] @outdent \ No newline at end of file From 010617337556d5f6ea93e42eff5f716215018231 Mon Sep 17 00:00:00 2001 From: nosa <96927121+n0s4@users.noreply.github.com> Date: Fri, 29 Apr 2022 23:27:09 +0100 Subject: [PATCH 150/861] Add Night Owl Color Theme. (#2330) --- runtime/themes/night_owl.toml | 105 ++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 runtime/themes/night_owl.toml diff --git a/runtime/themes/night_owl.toml b/runtime/themes/night_owl.toml new file mode 100644 index 000000000..a26641b1c --- /dev/null +++ b/runtime/themes/night_owl.toml @@ -0,0 +1,105 @@ +# Author : Joe Mckay joemckay3006@gmail.com +# Palette from https://github.com/haishanh/night-owl.vim + +'warning' = { fg = 'peach' } +'error' = { fg = 'red' } +'info' = { fg = 'blue' } +'hint' = { fg = 'paleblue' } +'diagnostic' = { fg = 'background', bg = 'red' } + +# UI +'ui.background' = { fg = 'foreground', bg = 'background' } +'ui.window' = { fg = 'grey7' } +'ui.gutter' = { bg = 'grey2' } +'ui.text' = { fg = 'foreground' } +'ui.text.focus' = { fg = 'foreground' } +'ui.text.info' = { fg = 'foreground'} +'ui.cursor' = { fg = 'background', bg = 'blue' } +'ui.cursor.primary' = { fg = 'background', bg = 'gold' } +'ui.cursor.match' = { bg = 'selection', modifiers = ['underlined'] } +'ui.selection' = { fg = 'foreground', bg = 'selection' } +'ui.linenr' = { fg = 'grey4', bg = 'background2' } +'ui.linenr.selected' = { fg = 'greyE', bg = 'background2' } +'ui.statusline' = { fg = 'greyE', bg = 'background2' } +'ui.statusline.inactive' = { fg = 'grey7', bg = 'background2' } +'ui.menu' = { fg = 'foreground', bg = 'selection' } +'ui.menu.selected' = { fg = 'foreground', bg = 'pink' } +'ui.popup' = { fg = 'foreground', bg = 'background2' } +'ui.popup.info' = { fg = 'gold', bg = 'background2'} +'ui.help' = { fg = 'gold', bg = 'background2'} +'ui.virtual.ruler' = { bg = 'grey4' } +'ui.virtual.whitespace' = { fg = 'slate' } + +# SYNTAX +'type' = { fg = 'green' } +'constructor' = { fg = 'blue' } +'constant' = { fg = 'foreground' } +'constant.character.escape' = { fg = 'peach' } +'string' = { fg = 'gold' } +'string.regexp' = { fg = 'green' } +'string.special.url' = { fg = 'gold', modifiers = ['underlined'] } +'comment' = { fg = 'slate', modifiers = ['italic'] } +'comment.block.documentation' = { fg = 'slate' } +'variable' = { fg = 'green' } +'variable.builtin' = { fg = 'green', modifiers = ['italic'] } +'label' = { fg = 'foreground' } +'punctuation' = { fg = 'foreground' } +'punctuation.special' = { fg = 'pink' } +'keyword' = { fg = 'pink' } +'keyword.control.import' = { fg = 'green', modifiers = ['italic'] } +'keyword.control.return' = { fg = 'pink', modifiers = ['italic'] } +'keyword.control.exception' = { fg = 'red' } +'operator' = { fg = 'pink' } +'function' = { fg = 'blue' } +'function.macro' = { fg = 'peach' } +'function.special' = { fg = 'pink' } +'tag' = { fg = 'blue' } +'namespace' = { fg = 'peach' } +'property' = { fg = 'green' } +'special' = { fg = 'greyE' } +'module' = { fg = 'greyE' } +'attribute' = { fg = 'paleblue' } + +# MARKUP +'markup.heading' = { fg = 'blue', modifiers = ['bold'] } +'markup.heading.marker' = { fg = 'grey4', modifiers = ['dim'] } +'markup.heading.1' = { fg = 'blue', modifers = ['bold'] } +'markup.heading.2' = { fg = 'paleblue', modifers = ['bold'] } +'markup.heading.3' = { fg = 'green', modifiers = ['bold'] } +'markup.heading.4' = { fg = 'pink', modifiers = ['bold'] } +'markup.heading.5' = { fg = 'peach', modifiers = ['bold'] } +'markup.heading.6' = { fg = 'slate', modifiers = ['bold'] } +'markup.list' = { fg = 'pink' } +'markup.bold' = { fg = 'foreground', modifiers = ['bold'] } +'markup.italic' = { fg = 'foreground', modifiers = ['italic'] } +'markup.link' = { fg = 'pink', modifiers = ['underlined'] } +'markup.link.url' = { fg = 'slate', modifiers = ['underlined'] } +'markup.quote' = { fg = 'green', modifiers = ['italic'] } +'markup.raw' = { fg = 'gold', bg = 'background2' } + +# DIFF +'diff.plus' = { fg = 'green' } +'diff.minus' = { fg = 'red' } +'diff.delta' = { fg = 'blue' } +'diff.delta.moved' = { fg = 'blue', modifiers = ['italic'] } + +[palette] +background = '#011627' +background2 = '#112630' +foreground = '#d6deeb' +selection = '#2d2c5d' + +slate = '#637777' +red = '#ff5874' +peach = '#f78c6c' +gold = '#ecc48d' +pink = '#c792ea' +green = '#addb67' +blue = '#82aaff' +paleblue = '#7fdbca' + +# Greys are named after their value. +grey2 = '#222222' +grey4 = '#444444' +grey7 = '#777777' +greyE = '#eeeeee' From 2687b8fb3b3391b6104815afca47704187f22cb8 Mon Sep 17 00:00:00 2001 From: unrelentingtech Date: Sat, 30 Apr 2022 03:46:51 +0300 Subject: [PATCH 151/861] feat(ui): treat slashes as word separators in prompt (#2315) When fiddling with paths in a :o prompt, one usually would want Ctrl-W to erase a path segment rather than the whole path. This is how Ctrl-W works in e.g. (neo)vim out of the box. --- helix-term/src/ui/prompt.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index bd78ba632..165d87c79 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -56,6 +56,10 @@ pub enum Movement { None, } +fn is_word_sep(c: char) -> bool { + c == std::path::MAIN_SEPARATOR || c.is_whitespace() +} + impl Prompt { pub fn new( prompt: Cow<'static, str>, @@ -118,7 +122,7 @@ impl Prompt { let mut found = None; for prev in (0..char_position - 1).rev() { - if char_indices[prev].1.is_whitespace() { + if is_word_sep(char_indices[prev].1) { found = Some(prev + 1); break; } @@ -141,14 +145,14 @@ impl Prompt { for _ in 0..rep { // Skip any non-whitespace characters while char_position < char_indices.len() - && !char_indices[char_position].1.is_whitespace() + && !is_word_sep(char_indices[char_position].1) { char_position += 1; } // Skip any whitespace characters while char_position < char_indices.len() - && char_indices[char_position].1.is_whitespace() + && is_word_sep(char_indices[char_position].1) { char_position += 1; } From e4c261809980fa17436a8e87cf7e56ddda8bcb68 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 29 Apr 2022 19:48:11 -0500 Subject: [PATCH 152/861] prevent rendering visible whitespace on trailing cursor (#2331) --- helix-term/src/ui/editor.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index ce8746a75..5ceff39e5 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -388,6 +388,8 @@ impl EditorView { spans.pop(); } HighlightEvent::Source { start, end } => { + let is_trailing_cursor = text.len_chars() < end; + // `unwrap_or_else` part is for off-the-end indices of // the rope, to allow cursor highlighting at the end // of the rope. @@ -397,7 +399,7 @@ impl EditorView { .fold(text_style, |acc, span| acc.patch(theme.highlight(span.0))); let space = if whitespace.render.space() == WhitespaceRenderValue::All - && text.len_chars() < end + && !is_trailing_cursor { &space } else { From 2c60798b00cc9b8efc9fdbec304a7ea04d11de4c Mon Sep 17 00:00:00 2001 From: unrelentingtech Date: Sat, 30 Apr 2022 03:48:52 +0300 Subject: [PATCH 153/861] feat(ui): add nbsp (non-breaking space) to rendered whitespace (#2322) --- book/src/configuration.md | 3 ++- helix-term/src/ui/editor.rs | 12 ++++++++++++ helix-view/src/editor.rs | 11 +++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index 439c80f1c..913897d62 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -145,7 +145,7 @@ Options for rendering whitespace with visible characters. Use `:set whitespace.r | Key | Description | Default | |-----|-------------|---------| | `render` | Whether to render whitespace. May either be `"all"` or `"none"`, or a table with sub-keys `space`, `tab`, and `newline`. | `"none"` | -| `characters` | Literal characters to use when rendering whitespace. Sub-keys may be any of `tab`, `space` or `newline` | See example below | +| `characters` | Literal characters to use when rendering whitespace. Sub-keys may be any of `tab`, `space`, `nbsp` or `newline` | See example below | Example @@ -160,6 +160,7 @@ newline = "none" [editor.whitespace.characters] space = "·" +nbsp = "⍽" tab = "→" newline = "⏎" ``` diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 5ceff39e5..52e581632 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -370,6 +370,7 @@ impl EditorView { " ".repeat(tab_width) }; let space = whitespace.characters.space.to_string(); + let nbsp = whitespace.characters.nbsp.to_string(); let newline = if whitespace.render.newline() == WhitespaceRenderValue::All { whitespace.characters.newline.to_string() } else { @@ -406,6 +407,14 @@ impl EditorView { " " }; + let nbsp = if whitespace.render.nbsp() == WhitespaceRenderValue::All + && text.len_chars() < end + { +   + } else { + " " + }; + use helix_core::graphemes::{grapheme_width, RopeGraphemes}; for grapheme in RopeGraphemes::new(text) { @@ -445,6 +454,9 @@ impl EditorView { } else if grapheme == " " { is_whitespace = true; (space, 1) + } else if grapheme == "\u{00A0}" { + is_whitespace = true; + (nbsp, 1) } else { is_whitespace = false; // Cow will prevent allocations if span contained in a single slice diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 38826f4bf..0de1732c3 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -288,6 +288,7 @@ pub enum WhitespaceRender { Specific { default: Option, space: Option, + nbsp: Option, tab: Option, newline: Option, }, @@ -311,6 +312,14 @@ impl WhitespaceRender { } } } + pub fn nbsp(&self) -> WhitespaceRenderValue { + match *self { + Self::Basic(val) => val, + Self::Specific { default, nbsp, .. } => { + nbsp.or(default).unwrap_or(WhitespaceRenderValue::None) + } + } + } pub fn tab(&self) -> WhitespaceRenderValue { match *self { Self::Basic(val) => val, @@ -333,6 +342,7 @@ impl WhitespaceRender { #[serde(default)] pub struct WhitespaceCharacters { pub space: char, + pub nbsp: char, pub tab: char, pub newline: char, } @@ -341,6 +351,7 @@ impl Default for WhitespaceCharacters { fn default() -> Self { Self { space: '·', // U+00B7 + nbsp: '⍽', // U+237D tab: '→', // U+2192 newline: '⏎', // U+23CE } From 73879052c14a84de6efe6991881c53d542b7a8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Sun, 1 May 2022 11:24:17 +0900 Subject: [PATCH 154/861] Add Cairo support --- languages.toml | 13 ++++ runtime/queries/cairo/highlights.scm | 96 ++++++++++++++++++++++++++++ runtime/queries/cairo/injections.scm | 5 ++ 3 files changed, 114 insertions(+) create mode 100644 runtime/queries/cairo/highlights.scm create mode 100644 runtime/queries/cairo/injections.scm diff --git a/languages.toml b/languages.toml index e5230fbaa..f065b1099 100644 --- a/languages.toml +++ b/languages.toml @@ -1276,3 +1276,16 @@ indent = { tab-width = 4, unit = "\t" } [[grammar]] name = "devicetree" source = { git = "https://github.com/joelspadin/tree-sitter-devicetree", rev = "877adbfa0174d25894c40fa75ad52d4515a36368" } + +[[language]] +name = "cairo" +scope = "source.cairo" +injection-regex = "cairo" +file-types = ["cairo"] +roots = [] +comment-token = "#" +indent = { tab-width = 4, unit = " " } + +[[grammar]] +name = "cairo" +source = { git = "https://github.com/archseer/tree-sitter-cairo", rev = "5155c6eb40db6d437f4fa41b8bcd8890a1c91716" } diff --git a/runtime/queries/cairo/highlights.scm b/runtime/queries/cairo/highlights.scm new file mode 100644 index 000000000..3a30d188e --- /dev/null +++ b/runtime/queries/cairo/highlights.scm @@ -0,0 +1,96 @@ +(ERROR) @error + +((identifier) @constant + (#match? @constant "^[A-Z][A-Z\\d_]+$")) +((identifier_def) @constant + (#match? @constant "^[A-Z][A-Z\\d_]+$")) + +((identifier) @namespace + (#match? @namespace "^[A-Z]")) +((identifier_def) @namespace + (#match? @namespace "^[A-Z]")) + +(identifier "." @punctuation) +(function_call (identifier) @function) +(func (identifier_def) @function) + +(string) @string +(atom_short_string) @string + +(code_element_directive) @keyword.directive +"return" @keyword + +(number) @constant.numeric +(atom_hex_number) @constant.numeric + +(comment) @comment + +"*" @special +(type) @type + +[ + "felt" + ; "codeoffset" +] @type.builtin + +[ + "if" + "else" + "end" + "assert" + "with" + "with_attr" +] @keyword.control + +[ + "from" + "import" + "func" + "namespace" +] @keyword ; keyword.declaration + +[ + "let" + "const" + "local" + "struct" + "member" + "alloc_locals" + "tempvar" +] @keyword + +(decorator) @attribute + +[ + "=" + "+" + "-" + "*" + "/" + ; "%" + ; "!" + ; ">" + ; "<" + ; "\\" + ; "&" + ; "?" + ; "^" + ; "~" + "==" + "!=" + "new" +] @operator + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +[ + "," + ":" +] @punctuation.delimiter diff --git a/runtime/queries/cairo/injections.scm b/runtime/queries/cairo/injections.scm new file mode 100644 index 000000000..e6f9be1ba --- /dev/null +++ b/runtime/queries/cairo/injections.scm @@ -0,0 +1,5 @@ +((hint) @injection.content + (#set! injection.language "python")) + +((comment) @injection.content + (#set! injection.language "comment")) From 8bb89dafa2f3bae8d2c7605b880973992b04480f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Sun, 1 May 2022 11:37:14 +0900 Subject: [PATCH 155/861] cargo xtask docgen --- 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 fe697cdf7..ca2be23b0 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -3,6 +3,7 @@ | bash | ✓ | | | `bash-language-server` | | c | ✓ | ✓ | ✓ | `clangd` | | c-sharp | ✓ | | | `OmniSharp` | +| cairo | ✓ | | | | | cmake | ✓ | ✓ | ✓ | `cmake-language-server` | | comment | ✓ | | | | | cpp | ✓ | ✓ | ✓ | `clangd` | From 9191af3f8d73d2101c46192a4a80c41a19012320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Sun, 27 Mar 2022 11:23:58 +0900 Subject: [PATCH 156/861] helix-loader + helix-core now compile for WASM --- helix-loader/Cargo.toml | 7 ++++++- helix-loader/src/grammar.rs | 11 ++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index 607d1a0ad..c8cbf6d10 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -15,11 +15,16 @@ serde = { version = "1.0", features = ["derive"] } toml = "0.5" etcetera = "0.3" tree-sitter = "0.20" -libloading = "0.7" once_cell = "1.9" log = "0.4" +# TODO: these two should be on !wasm32 only + # cloning/compiling tree-sitter grammars cc = { version = "1" } threadpool = { version = "1.0" } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +libloading = "0.7" + diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index 9d63a2bed..df88f24b4 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -1,5 +1,4 @@ use anyhow::{anyhow, Context, Result}; -use libloading::{Library, Symbol}; use serde::{Deserialize, Serialize}; use std::fs; use std::time::SystemTime; @@ -17,6 +16,9 @@ const DYLIB_EXTENSION: &str = "so"; #[cfg(windows)] const DYLIB_EXTENSION: &str = "dll"; +#[cfg(target_arch = "wasm32")] +const DYLIB_EXTENSION: &str = "wasm"; + #[derive(Debug, Serialize, Deserialize)] struct Configuration { #[serde(rename = "use-grammars")] @@ -57,7 +59,14 @@ pub enum GrammarSource { const BUILD_TARGET: &str = env!("BUILD_TARGET"); const REMOTE_NAME: &str = "origin"; +#[cfg(target_arch = "wasm32")] +pub fn get_language(name: &str) -> Result { + unimplemented!() +} + +#[cfg(not(target_arch = "wasm32"))] pub fn get_language(name: &str) -> Result { + use libloading::{Library, Symbol}; let name = name.to_ascii_lowercase(); let mut library_path = crate::runtime_dir().join("grammars").join(&name); library_path.set_extension(DYLIB_EXTENSION); From ade4cbffaa9660b01bcd2ce7e6e2d6bb0a1ca3c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Sun, 27 Mar 2022 17:22:20 +0900 Subject: [PATCH 157/861] Add a nop clipboard provider for wasm --- helix-view/src/clipboard.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/helix-view/src/clipboard.rs b/helix-view/src/clipboard.rs index 5cc5cad89..8cd7983ba 100644 --- a/helix-view/src/clipboard.rs +++ b/helix-view/src/clipboard.rs @@ -75,7 +75,13 @@ pub fn get_clipboard_provider() -> Box { } } -#[cfg(not(any(windows, target_os = "macos")))] +#[cfg(target_os = "wasm32")] +pub fn get_clipboard_provider() -> Box { + // TODO: + Box::new(provider::NopProvider::new()) +} + +#[cfg(not(any(windows, target_os = "wasm32", target_os = "macos")))] pub fn get_clipboard_provider() -> Box { use provider::command::{env_var_is_set, exists, is_exit_success}; // TODO: support for user-defined provider, probably when we have plugin support by setting a @@ -201,6 +207,7 @@ mod provider { } } + #[cfg(not(target_arch = "wasm32"))] pub mod command { use super::*; use anyhow::{bail, Context as _, Result}; From ede01b5f1eb072022cb320d7ffddd0ecf6e1dab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 4 Apr 2022 10:45:45 +0900 Subject: [PATCH 158/861] num_cpus apparently unused in helix-term --- Cargo.lock | 1 - helix-term/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b22c3065c..18f50af62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -453,7 +453,6 @@ dependencies = [ "helix-view", "ignore", "log", - "num_cpus", "once_cell", "pulldown-cmark", "retain_mut", diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 4b2611eda..706453ae6 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -36,7 +36,6 @@ which = "4.2" ropey = { version = "1.4", default-features = false } tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] } -num_cpus = "1" tui = { path = "../helix-tui", package = "helix-tui", default-features = false, features = ["crossterm"] } crossterm = { version = "0.23", features = ["event-stream"] } signal-hook = "0.3" From 166818359030cd1649327160c9020d943a8de244 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 1 May 2022 16:34:46 +0200 Subject: [PATCH 159/861] feat(lang): Cpon lang support (#2355) Co-authored-by: Fanda Vacek --- book/src/generated/lang-support.md | 1 + languages.toml | 14 ++++++++++++++ runtime/queries/cpon/highlights.scm | 26 ++++++++++++++++++++++++++ runtime/queries/cpon/indents.scm | 12 ++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 runtime/queries/cpon/highlights.scm create mode 100644 runtime/queries/cpon/indents.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index ca2be23b0..5c5ecaafe 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -6,6 +6,7 @@ | cairo | ✓ | | | | | cmake | ✓ | ✓ | ✓ | `cmake-language-server` | | comment | ✓ | | | | +| cpon | ✓ | | ✓ | | | cpp | ✓ | ✓ | ✓ | `clangd` | | css | ✓ | | | `vscode-css-language-server` | | dart | ✓ | | ✓ | `dart` | diff --git a/languages.toml b/languages.toml index f065b1099..10f8f8441 100644 --- a/languages.toml +++ b/languages.toml @@ -1289,3 +1289,17 @@ indent = { tab-width = 4, unit = " " } [[grammar]] name = "cairo" source = { git = "https://github.com/archseer/tree-sitter-cairo", rev = "5155c6eb40db6d437f4fa41b8bcd8890a1c91716" } + +[[language]] +name = "cpon" +scope = "scope.cpon" +injection-regex = "^cpon$" +file-types = ["cpon", "cp"] +roots = [] +auto-format = true +comment-token = "//" +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "cpon" +source = { git = "https://github.com/fvacek/tree-sitter-cpon", rev = "11ba46a4de3eb86934003133099c9963a60f9687" } diff --git a/runtime/queries/cpon/highlights.scm b/runtime/queries/cpon/highlights.scm new file mode 100644 index 000000000..f85caf469 --- /dev/null +++ b/runtime/queries/cpon/highlights.scm @@ -0,0 +1,26 @@ +[ + (true) + (false) +] @constant.builtin.boolean +(null) @constant.builtin +(number) @constant.numeric +(pair + key: (_) @keyword) +(ipair + key: (_) @keyword) +(mpair + key: (_) @keyword) + +(string) @string +(escape_sequence) @constant.character.escape +(ERROR) @error + +"," @punctuation.delimiter +[ + "[" + "]" + "{" + "}" + "<" + ">" +] @punctuation.bracket diff --git a/runtime/queries/cpon/indents.scm b/runtime/queries/cpon/indents.scm new file mode 100644 index 000000000..53c827675 --- /dev/null +++ b/runtime/queries/cpon/indents.scm @@ -0,0 +1,12 @@ +[ + (meta) + (map) + (imap) + (array) +] @indent + +[ + "]" + "}" + ">" +] @outdent From f85f0b72729ebbc1d93020b1c1a52a2f2fb3bc59 Mon Sep 17 00:00:00 2001 From: Ryosuke Hayashi Date: Mon, 2 May 2022 23:15:02 +0900 Subject: [PATCH 160/861] Add run-shell-command for Commands (#1682) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add run_shell_command * docgen * fix command name Co-authored-by: Blaž Hrastnik * refactored Info::new * show 'Command failed' if execution fails * TypedCommand takes care of error handling and printing the error to the statusline. * docgen * use Popup instead of autoinfo * remove to_string in format! * Revert chage in info.rs * Show "Command succeed" when success * Fix info.rs Co-authored-by: Blaž Hrastnik --- book/src/generated/typable-cmd.md | 1 + helix-term/src/commands/typed.rs | 44 +++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index ac2102020..df0841b6f 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -63,3 +63,4 @@ | `:config-reload` | Refreshes helix's config. | | `:config-open` | Open the helix config.toml file. | | `:pipe` | Pipe each selection to the shell command. | +| `: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 394760a2f..373c70180 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1116,6 +1116,43 @@ fn pipe( Ok(()) } +fn run_shell_command( + cx: &mut compositor::Context, + args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + let shell = &cx.editor.config().shell; + let (output, success) = shell_impl(shell, &args.join(" "), None)?; + if success { + cx.editor.set_status("Command succeed"); + } else { + cx.editor.set_error("Command failed"); + } + + if !output.is_empty() { + let callback = async move { + let call: job::Callback = + Box::new(move |editor: &mut Editor, compositor: &mut Compositor| { + let contents = ui::Markdown::new( + format!("```sh\n{}\n```", output), + editor.syn_loader.clone(), + ); + let mut popup = Popup::new("shell", contents); + popup.set_position(Some(helix_core::Position::new( + editor.cursor().0.unwrap_or_default().row, + 2, + ))); + compositor.replace_or_push("shell", popup); + }); + Ok(call) + }; + + cx.jobs.callback(callback); + } + + Ok(()) +} + pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "quit", @@ -1561,6 +1598,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: pipe, completer: None, }, + TypableCommand { + name: "run-shell-command", + aliases: &["sh"], + doc: "Run a shell command", + fun: run_shell_command, + completer: Some(completers::directory), + }, ]; pub static TYPABLE_COMMAND_MAP: Lazy> = From 567ddef388986dd2cea5c7f3eb1aa1a978c3e6d3 Mon Sep 17 00:00:00 2001 From: Roland Kovacs Date: Mon, 2 May 2022 16:18:41 +0200 Subject: [PATCH 161/861] Auto-complete directory members (#1801) (#1907) Allow tab-completion to continue when there is only a single, unambigous completion target which is a directory. This allows e.g. nested directories to be quickly drilled down just by hitting instead of first selecting the completion then hitting . --- helix-term/src/ui/prompt.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 165d87c79..ef08edf2d 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -526,6 +526,11 @@ impl Component for Prompt { } key!(Tab) => { self.change_completion_selection(CompletionDirection::Forward); + // if single completion candidate is a directory list content in completion + if self.completion.len() == 1 && self.line.ends_with(std::path::MAIN_SEPARATOR) { + self.recalculate_completion(cx.editor); + self.exit_selection(); + } (self.callback_fn)(cx, &self.line, PromptEvent::Update) } shift!(Tab) => { From f9baced216df60122f2aae08d382931d77901ca9 Mon Sep 17 00:00:00 2001 From: Vince Mutolo Date: Mon, 2 May 2022 10:24:22 -0400 Subject: [PATCH 162/861] add reflow command (#2128) * add reflow command Users need to be able to hard-wrap text for many applications, including comments in code, git commit messages, plaintext documentation, etc. It often falls to the user to manually insert line breaks where appropriate in order to hard-wrap text. This commit introduces the "reflow" command (both in the TUI and core library) to automatically hard-wrap selected text to a given number of characters (defined by Unicode "extended grapheme clusters"). It handles lines with a repeated prefix, such as comments ("//") and indentation. * reflow: consider newlines to be word separators * replace custom reflow impl with textwrap crate * Sync reflow command docs with book * reflow: add default max_line_len language setting Co-authored-by: Vince Mutolo --- Cargo.lock | 27 ++++++++++++++++++ book/src/generated/typable-cmd.md | 1 + helix-core/Cargo.toml | 1 + helix-core/src/lib.rs | 1 + helix-core/src/syntax.rs | 1 + helix-core/src/wrap.rs | 7 +++++ helix-term/src/commands/typed.rs | 46 +++++++++++++++++++++++++++++++ 7 files changed, 84 insertions(+) create mode 100644 helix-core/src/wrap.rs diff --git a/Cargo.lock b/Cargo.lock index 18f50af62..f075249ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -374,6 +374,7 @@ dependencies = [ "slotmap", "smallvec", "smartstring", + "textwrap", "toml", "tree-sitter", "unicode-general-category", @@ -1005,6 +1006,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "smawk" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" + [[package]] name = "socket2" version = "0.4.4" @@ -1044,6 +1051,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.30" @@ -1179,6 +1197,15 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1218098468b8085b19a2824104c70d976491d247ce194bbd9dc77181150cdfd6" +[[package]] +name = "unicode-linebreak" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a52dcaab0c48d931f7cc8ef826fa51690a08e1ea55117ef26f89864f532383f" +dependencies = [ + "regex", +] + [[package]] name = "unicode-normalization" version = "0.1.19" diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index df0841b6f..426598e3d 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -59,6 +59,7 @@ | `:get-option`, `:get` | Get the current value of a config option. | | `:sort` | Sort ranges in selection. | | `:rsort` | Sort ranges in selection in reverse order. | +| `:reflow` | Hard-wrap the current selection of lines to a given width. | | `:tree-sitter-subtree`, `:ts-subtree` | Display tree sitter subtree under cursor, primarily for debugging queries. | | `:config-reload` | Refreshes helix's config. | | `:config-open` | Open the helix config.toml file. | diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 6e019a42e..ab937f0b1 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -41,6 +41,7 @@ encoding_rs = "0.8" chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] } etcetera = "0.3" +textwrap = "0.15.0" [dev-dependencies] quickcheck = { version = "1", default-features = false } diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 023412657..a022a42a1 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -27,6 +27,7 @@ pub mod syntax; pub mod test; pub mod textobject; mod transaction; +pub mod wrap; pub mod unicode { pub use unicode_general_category as category; diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 3f9e7bcf8..eab3ab79f 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -67,6 +67,7 @@ pub struct LanguageConfiguration { pub shebangs: Vec, // interpreter(s) associated with language pub roots: Vec, // these indicate project roots <.git, Cargo.toml> pub comment_token: Option, + pub max_line_length: Option, #[serde(default, skip_serializing, deserialize_with = "deserialize_lsp_config")] pub config: Option, diff --git a/helix-core/src/wrap.rs b/helix-core/src/wrap.rs new file mode 100644 index 000000000..eabc47d47 --- /dev/null +++ b/helix-core/src/wrap.rs @@ -0,0 +1,7 @@ +use smartstring::{LazyCompact, SmartString}; + +/// Given a slice of text, return the text re-wrapped to fit it +/// within the given width. +pub fn reflow_hard_wrap(text: &str, max_line_len: usize) -> SmartString { + textwrap::refill(text, max_line_len).into() +} diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 373c70180..ec86e4460 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1051,6 +1051,45 @@ fn sort_impl( Ok(()) } +fn reflow( + cx: &mut compositor::Context, + args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + let (view, doc) = current!(cx.editor); + + const DEFAULT_MAX_LEN: usize = 79; + + // Find the max line length by checking the following sources in order: + // - The passed argument in `args` + // - The configured max_line_len for this language in languages.toml + // - The const default we set above + let max_line_len: usize = args + .get(0) + .map(|num| num.parse::()) + .transpose()? + .or_else(|| { + doc.language_config() + .and_then(|config| config.max_line_length) + }) + .unwrap_or(DEFAULT_MAX_LEN); + + let rope = doc.text(); + + let selection = doc.selection(view.id); + let transaction = Transaction::change_by_selection(rope, selection, |range| { + let fragment = range.fragment(rope.slice(..)); + let reflowed_text = helix_core::wrap::reflow_hard_wrap(&fragment, max_line_len); + + (range.from(), range.to(), Some(reflowed_text)) + }); + + doc.apply(&transaction, view.id); + doc.append_changes_to_history(view.id); + + Ok(()) +} + fn tree_sitter_subtree( cx: &mut compositor::Context, _args: &[Cow], @@ -1570,6 +1609,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: sort_reverse, completer: None, }, + TypableCommand { + name: "reflow", + aliases: &[], + doc: "Hard-wrap the current selection of lines to a given width.", + fun: reflow, + completer: None, + }, TypableCommand { name: "tree-sitter-subtree", aliases: &["ts-subtree"], From 20162a426b991f1a07f347f8180480871d15a27a Mon Sep 17 00:00:00 2001 From: unrelentingtech Date: Mon, 2 May 2022 17:31:07 +0300 Subject: [PATCH 163/861] feat(commands): make it possible to disable format-on-save via the 'auto-format' option (#2321) --- book/src/configuration.md | 1 + helix-term/src/commands/typed.rs | 54 +++++++++++++++++++------------- helix-view/src/editor.rs | 3 ++ 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index 913897d62..94134ed4d 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -39,6 +39,7 @@ hidden = false | `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` | | `gutters` | Gutters to display: Available are `diagnostics` and `line-numbers`, note that `diagnostics` also includes other features like breakpoints | `["diagnostics", "line-numbers"]` | | `auto-completion` | Enable automatic pop up of auto-completion. | `true` | +| `auto-format` | Enable automatic formatting on save. | `true` | | `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant. | `400` | | `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` | | `auto-info` | Whether to display infoboxes | `true` | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index ec86e4460..68aa7703c 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -195,6 +195,7 @@ fn write_impl( path: Option<&Cow>, force: bool, ) -> anyhow::Result<()> { + let auto_format = cx.editor.config().auto_format; let jobs = &mut cx.jobs; let doc = doc_mut!(cx.editor); @@ -205,17 +206,21 @@ fn write_impl( if doc.path().is_none() { bail!("cannot write a buffer without a filename"); } - let fmt = doc.auto_format().map(|fmt| { - let shared = fmt.shared(); - let callback = make_format_callback( - doc.id(), - doc.version(), - Modified::SetUnmodified, - shared.clone(), - ); - jobs.callback(callback); - shared - }); + let fmt = if auto_format { + doc.auto_format().map(|fmt| { + let shared = fmt.shared(); + let callback = make_format_callback( + doc.id(), + doc.version(), + Modified::SetUnmodified, + shared.clone(), + ); + jobs.callback(callback); + shared + }) + } else { + None + }; let future = doc.format_and_save(fmt, force); cx.jobs.add(Job::new(future).wait_before_exiting()); @@ -454,6 +459,7 @@ fn write_all_impl( force: bool, ) -> anyhow::Result<()> { let mut errors = String::new(); + let auto_format = cx.editor.config().auto_format; let jobs = &mut cx.jobs; // save all documents for doc in &mut cx.editor.documents.values_mut() { @@ -466,17 +472,21 @@ fn write_all_impl( continue; } - let fmt = doc.auto_format().map(|fmt| { - let shared = fmt.shared(); - let callback = make_format_callback( - doc.id(), - doc.version(), - Modified::SetUnmodified, - shared.clone(), - ); - jobs.callback(callback); - shared - }); + let fmt = if auto_format { + doc.auto_format().map(|fmt| { + let shared = fmt.shared(); + let callback = make_format_callback( + doc.id(), + doc.version(), + Modified::SetUnmodified, + shared.clone(), + ); + jobs.callback(callback); + shared + }) + } else { + None + }; let future = doc.format_and_save(fmt, force); jobs.add(Job::new(future).wait_before_exiting()); } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 0de1732c3..29aea74b7 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -127,6 +127,8 @@ pub struct Config { pub auto_pairs: AutoPairConfig, /// Automatic auto-completion, automatically pop up without user trigger. Defaults to true. pub auto_completion: bool, + /// Automatic formatting on save. Defaults to true. + pub auto_format: bool, /// Time in milliseconds since last keypress before idle timers trigger. /// Used for autocompletion, set to 0 for instant. Defaults to 400ms. #[serde( @@ -374,6 +376,7 @@ impl Default for Config { middle_click_paste: true, auto_pairs: AutoPairConfig::default(), auto_completion: true, + auto_format: true, idle_timeout: Duration::from_millis(400), completion_trigger_len: 2, auto_info: true, From 77ff8d355051ef567c7998b226e28ba436c2e230 Mon Sep 17 00:00:00 2001 From: Kirawi <67773714+kirawi@users.noreply.github.com> Date: Mon, 2 May 2022 10:31:23 -0400 Subject: [PATCH 164/861] cfg-gate unused functions on macos & windows (#2332) --- helix-view/src/clipboard.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/helix-view/src/clipboard.rs b/helix-view/src/clipboard.rs index 8cd7983ba..fed1deb18 100644 --- a/helix-view/src/clipboard.rs +++ b/helix-view/src/clipboard.rs @@ -14,6 +14,7 @@ pub trait ClipboardProvider: std::fmt::Debug { fn set_contents(&mut self, contents: String, clipboard_type: ClipboardType) -> Result<()>; } +#[cfg(not(windows))] macro_rules! command_provider { (paste => $get_prg:literal $( , $get_arg:literal )* ; copy => $set_prg:literal $( , $set_arg:literal )* ; ) => {{ Box::new(provider::command::Provider { @@ -212,14 +213,17 @@ mod provider { use super::*; use anyhow::{bail, Context as _, Result}; + #[cfg(not(windows))] pub fn exists(executable_name: &str) -> bool { which::which(executable_name).is_ok() } + #[cfg(not(any(windows, target_os = "macos")))] pub fn env_var_is_set(env_var_name: &str) -> bool { std::env::var_os(env_var_name).is_some() } + #[cfg(not(any(windows, target_os = "macos")))] pub fn is_exit_success(program: &str, args: &[&str]) -> bool { std::process::Command::new(program) .args(args) From ac2ea800ce267b9ed3da5f743085f0afe8460473 Mon Sep 17 00:00:00 2001 From: AntonioLucibello <65395340+AntonioLucibello@users.noreply.github.com> Date: Mon, 2 May 2022 16:45:20 +0200 Subject: [PATCH 165/861] Add undo checkpoint command (#2115) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added undo checkpoint command * changed add_undo_checkpoint to commit_undo_checkpoint * mapped commit_undo_checkpoint to Alt-u * Update default.rs Co-authored-by: Blaž Hrastnik --- helix-term/src/commands.rs | 6 ++++++ helix-term/src/keymap/default.rs | 1 + 2 files changed, 7 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 54dcc98fc..e2d10d217 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -318,6 +318,7 @@ impl MappableCommand { redo, "Redo change", earlier, "Move backward in history", later, "Move forward in history", + commit_undo_checkpoint, "Commit changes to a new checkpoint", yank, "Yank selection", yank_joined_to_clipboard, "Join and yank selections to clipboard", yank_main_selection_to_clipboard, "Yank main selection to clipboard", @@ -3001,6 +3002,11 @@ 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); +} + // Yank / Paste fn yank(cx: &mut Context) { diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index db24e97a7..a8ff8be91 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -326,6 +326,7 @@ pub fn default() -> HashMap { "C-w" => delete_word_backward, "A-backspace" => delete_word_backward, "A-d" => delete_word_forward, + "C-s" => commit_undo_checkpoint, "left" => move_char_left, "C-b" => move_char_left, From fba198c1e0d20eac4a2af151608827057d4f36d5 Mon Sep 17 00:00:00 2001 From: Robert Walter <26892280+RobWalt@users.noreply.github.com> Date: Mon, 2 May 2022 23:46:25 +0200 Subject: [PATCH 166/861] Add documentation for `hx --health` (#2357) --- book/src/install.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/book/src/install.md b/book/src/install.md index 34d8b651c..cbd2c0280 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -66,6 +66,15 @@ via the `HELIX_RUNTIME` environment variable. |windows |`xcopy runtime %AppData%/helix/runtime`| |linux/macos|`ln -s $PWD/runtime ~/.config/helix/runtime` +## Finishing up the installation + +To make sure everything is set up as expected you should finally run the helix healthcheck via +``` +hx --health +``` +For more information on the information displayed in the healthcheck results refer to [Healthcheck](https://github.com/helix-editor/helix/wiki/Healthcheck). + + ## Building tree-sitter grammars Tree-sitter grammars must be fetched and compiled if not pre-packaged. From feea51830032a9aa827d3b258ff9e6304dbc3863 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 May 2022 09:30:46 +0900 Subject: [PATCH 167/861] build(deps): bump thiserror from 1.0.30 to 1.0.31 (#2372) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.30 to 1.0.31. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.30...1.0.31) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... 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 f075249ac..26877cfaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1064,18 +1064,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", From fc35791af96e7dd2eb681957560fb8c5aa3c2eba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 May 2022 09:31:05 +0900 Subject: [PATCH 168/861] build(deps): bump tokio from 1.17.0 to 1.18.1 (#2373) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.17.0 to 1.18.1. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.17.0...tokio-1.18.1) --- updated-dependencies: - dependency-name: tokio dependency-type: direct:production update-type: version-update:semver-minor ... 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 26877cfaa..16a8e5417 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1117,9 +1117,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.17.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +checksum = "dce653fb475565de9f6fb0614b28bca8df2c430c0cf84bcd9c843f15de5414cc" dependencies = [ "bytes", "libc", diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index da731a9f5..6eec89f03 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.17", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } +tokio = { version = "1.18", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } tokio-stream = "0.1.8" which = "4.2" From 0f1fce9af677ea2e89d5b7a32b9aefdfe35f8cff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 May 2022 09:31:23 +0900 Subject: [PATCH 169/861] build(deps): bump log from 0.4.16 to 0.4.17 (#2374) Bumps [log](https://github.com/rust-lang/log) from 0.4.16 to 0.4.17. - [Release notes](https://github.com/rust-lang/log/releases) - [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/log/commits/0.4.17) --- updated-dependencies: - dependency-name: log dependency-type: direct:production update-type: version-update:semver-patch ... 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 16a8e5417..5c2e37b85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -599,9 +599,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] From e418fae61bdfd2bacaca6473e2bb4d21bab54445 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 May 2022 09:31:34 +0900 Subject: [PATCH 170/861] build(deps): bump serde from 1.0.136 to 1.0.137 (#2375) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.136 to 1.0.137. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.136...v1.0.137) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... 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 5c2e37b85..85c31bb61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -886,18 +886,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", From 042463a4d1c6eab144b89f775d79759bd6c3df0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 May 2022 09:31:55 +0900 Subject: [PATCH 171/861] build(deps): bump serde_json from 1.0.79 to 1.0.80 (#2376) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.79 to 1.0.80. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.79...v1.0.80) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... 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 85c31bb61..244923822 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -906,9 +906,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "f972498cf015f7c0746cac89ebe1d6ef10c293b94175a243a2d9442c163d9944" dependencies = [ "itoa", "ryu", From d2b1add1f41c9d9a655a4637e3e276eb92e8eefb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Dzivjak?= Date: Tue, 3 May 2022 10:28:41 +0200 Subject: [PATCH 172/861] feat(term): wrap command palette in overlay (#2378) Looks better and is consistent with the rest, nothing else. --- helix-term/src/commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index e2d10d217..07d805cad 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2219,7 +2219,7 @@ pub fn command_palette(cx: &mut Context) { command.execute(&mut ctx); }, ); - compositor.push(Box::new(picker)); + compositor.push(Box::new(overlayed(picker))); }, )); } From e529ca1b92ac03fe1e4386756ee5811212ce96bd Mon Sep 17 00:00:00 2001 From: Johann Dahm Date: Wed, 4 May 2022 00:32:44 +0200 Subject: [PATCH 173/861] Fix build on aarch64-darwin (#1789) Co-authored-by: Yusuf Bera Ertan --- flake.lock | 31 +++++++++++++++---------------- flake.nix | 3 ++- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/flake.lock b/flake.lock index 40a87eb55..be0aaae51 100644 --- a/flake.lock +++ b/flake.lock @@ -25,11 +25,11 @@ ] }, "locked": { - "lastModified": 1646667754, - "narHash": "sha256-LahZHvCC3UVzGQ55iWDRZkuDssXl1rYgqgScrPV9S38=", + "lastModified": 1650900878, + "narHash": "sha256-qhNncMBSa9STnhiLfELEQpYC1L4GrYHNIzyCZ/pilsI=", "owner": "numtide", "repo": "devshell", - "rev": "59fbe1dfc0de8c3332957c16998a7d16dff365d8", + "rev": "d97df53b5ddaa1cfbea7cddbd207eb2634304733", "type": "github" }, "original": { @@ -75,16 +75,15 @@ ] }, "locked": { - "lastModified": 1646710334, - "narHash": "sha256-eLBcDgcbOUfeH4k6SEW5a5v0PTp2KNCn+5ZXIoWGYww=", + "lastModified": 1651609988, + "narHash": "sha256-oMjBD+noDmqTs3p31S+YES0zo0LTZ8GNe8klIre5NXQ=", "owner": "nix-community", "repo": "dream2nix", - "rev": "5dcfbfd3b60ce0208b894c1bdea00e2bdf80ca6a", + "rev": "6672d1f3d966c4d1e36ae66d156c0b1caec62dac", "type": "github" }, "original": { "owner": "nix-community", - "ref": "main", "repo": "dream2nix", "type": "github" } @@ -131,11 +130,11 @@ ] }, "locked": { - "lastModified": 1646766572, - "narHash": "sha256-DV3+zxvAIKsMHsHedJKYFsracvFyLKpFQqurUBR86oY=", + "lastModified": 1651610406, + "narHash": "sha256-VrVAvivU3Bx0JPI6c8rDsEgfJUftOA9LOiuYMMVYseE=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "3a3f47f43ba486b7554164a698c8dfc5a38624ce", + "rev": "d812e9a68fd7144d309b6b86876713759e5aaf7f", "type": "github" }, "original": { @@ -146,11 +145,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1646497237, - "narHash": "sha256-Ccpot1h/rV8MgcngDp5OrdmLTMaUTbStZTR5/sI7zW0=", + "lastModified": 1651558728, + "narHash": "sha256-8HzyRnWlgZluUrVFNOfZAOlA1fghpOSezXvxhalGMUo=", "owner": "nixos", "repo": "nixpkgs", - "rev": "062a0c5437b68f950b081bbfc8a699d57a4ee026", + "rev": "cbe587c735b734405f56803e267820ee1559e6c1", "type": "github" }, "original": { @@ -175,11 +174,11 @@ ] }, "locked": { - "lastModified": 1646792695, - "narHash": "sha256-2drCXIKIQnJMlTZbcCfuHZAh+iPcdlRkCqtZnA6MHLY=", + "lastModified": 1651545993, + "narHash": "sha256-+Qc553XIjn9/P2YpcTsL1nIG9hpLfBT9UMAhw0PkM3E=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "7f599870402c8d2a5806086c8ee0f2d92b175c54", + "rev": "8aeb9a75d2d52700ca987559de9859ef6fe38970", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 38ba9fd0c..495e441a8 100644 --- a/flake.nix +++ b/flake.nix @@ -25,6 +25,7 @@ package = "helix"; }; overrides = { + cCompiler = common: if common.pkgs.stdenv.isLinux then common.pkgs.gcc else common.pkgs.clang; crateOverrides = common: _: { helix-term = prev: let @@ -57,7 +58,7 @@ env = prev.env ++ [ { name = "HELIX_RUNTIME"; eval = "$PWD/runtime"; } { name = "RUST_BACKTRACE"; value = "1"; } - { name = "RUSTFLAGS"; value = "-C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment"; } + { name = "RUSTFLAGS"; value = if common.pkgs.stdenv.isLinux then "-C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment" else ""; } ]; }; }; From 25d128b5b3f173e3aa8b455194d128af35cc2a27 Mon Sep 17 00:00:00 2001 From: Matthew Toohey Date: Tue, 3 May 2022 21:55:40 -0400 Subject: [PATCH 174/861] feat(languages): detect cjs as javascript (#2387) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 10f8f8441..35438758e 100644 --- a/languages.toml +++ b/languages.toml @@ -303,7 +303,7 @@ source = { git = "https://github.com/omertuc/tree-sitter-go-work", rev = "6dd9dd name = "javascript" scope = "source.js" injection-regex = "^(js|javascript)$" -file-types = ["js", "jsx", "mjs"] +file-types = ["js", "jsx", "mjs", "cjs"] shebangs = ["node"] roots = [] comment-token = "//" From f59b3b91c86d8f92ce72a4bb873bbb6aaaa4d2a9 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 3 May 2022 21:16:34 -0500 Subject: [PATCH 175/861] rewrite auto-pairs docs (#2384) --- book/src/configuration.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index 94134ed4d..4d7e440a0 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -90,16 +90,18 @@ available, which is not defined by default. ### `[editor.auto-pairs]` Section -Enable automatic insertion of pairs to parentheses, brackets, etc. Can be -a simple boolean value, or a specific mapping of pairs of single characters. +Enables automatic insertion of pairs to parentheses, brackets, etc. Can be a +simple boolean value, or a specific mapping of pairs of single characters. -| Key | Description | -| --- | ----------- | -| `false` | Completely disable auto pairing, regardless of language-specific settings -| `true` | Use the default pairs: (){}[]''""`` -| Mapping of pairs | e.g. `{ "(" = ")", "{" = "}", ... }` +To disable auto-pairs altogether, set `auto-pairs` to `false`: -Example +```toml +[editor] +auto-pairs = false # defaults to `true` +``` + +The default pairs are (){}[]''""``, but these can be customized by +setting `auto-pairs` to a TOML table: ```toml [editor.auto-pairs] From 09a17e4fa3d0aa67e399c02c484a768d85acaac6 Mon Sep 17 00:00:00 2001 From: Ben Lee-Cohen Date: Tue, 3 May 2022 22:17:08 -0400 Subject: [PATCH 176/861] Making the 'set-option' command help more descriptive. (#2365) * Making the 'set-option' command help more descriptive. * Adding the generated docs * Making the message multi-line * Replace newline with break in generated docs --- book/src/generated/typable-cmd.md | 2 +- helix-term/src/commands/typed.rs | 2 +- xtask/src/main.rs | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 426598e3d..17d10c996 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -55,7 +55,7 @@ | `:tutor` | Open the tutorial. | | `:goto`, `:g` | Go to line number. | | `:set-language`, `:lang` | Set the language of current buffer. | -| `:set-option`, `:set` | Set a config option at runtime. | +| `:set-option`, `:set` | Set a config option at runtime.
For example to disable smart case search, use `:set search.smart-case false`. | | `:get-option`, `:get` | Get the current value of a config option. | | `:sort` | Sort ranges in selection. | | `:rsort` | Sort ranges in selection in reverse order. | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 68aa7703c..68b64bb8d 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1594,7 +1594,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "set-option", aliases: &["set"], - doc: "Set a config option at runtime.", + doc: "Set a config option at runtime.\nFor example to disable smart case search, use `:set search.smart-case false`.", fun: set_option, completer: Some(completers::setting), }, diff --git a/xtask/src/main.rs b/xtask/src/main.rs index ad120f4f1..a4c69d701 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -106,7 +106,9 @@ pub mod md_gen { .collect::>() .join(", "); - md.push_str(&md_table_row(&[names.to_owned(), cmd.doc.to_owned()])); + let doc = cmd.doc.replace("\n", "
"); + + md.push_str(&md_table_row(&[names.to_owned(), doc.to_owned()])); } Ok(md) From 5ab669f1ac546924d96fdf7760d82e047ac4a8b6 Mon Sep 17 00:00:00 2001 From: ChrHorn Date: Wed, 4 May 2022 07:51:31 +0200 Subject: [PATCH 177/861] replace constant.number with constant.numeric (#2389) --- runtime/queries/hcl/highlights.scm | 2 +- runtime/themes/pop-dark.toml | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/runtime/queries/hcl/highlights.scm b/runtime/queries/hcl/highlights.scm index 03b3e5258..d00f74f37 100644 --- a/runtime/queries/hcl/highlights.scm +++ b/runtime/queries/hcl/highlights.scm @@ -21,7 +21,7 @@ (identifier) @variable (comment) @comment (null_lit) @constant.builtin -(numeric_lit) @constant.number +(numeric_lit) @constant.numeric (bool_lit) @constant.builtin.boolean [ diff --git a/runtime/themes/pop-dark.toml b/runtime/themes/pop-dark.toml index 4ff732b76..e662f9575 100644 --- a/runtime/themes/pop-dark.toml +++ b/runtime/themes/pop-dark.toml @@ -55,9 +55,6 @@ namespace = { fg = 'orangeL' } 'constant.character' = { fg = 'greenS' } 'constant.character.escape' = { fg = 'blueL' } 'constant.numeric' = { fg = 'redH' } -'constant.number' = { bg = 'blueH' } -'constant.number.integer' = { fg = 'orangeS' } -'constant.number.float' = { fg = 'orangeS' } 'string' = { fg = 'greenN' } 'string.regexp' = { fg = 'blueL' } 'string.special' = { fg = 'orangeW' } From f1a77370cf679eb0f3a58cfb12deec8ff7fc6325 Mon Sep 17 00:00:00 2001 From: Pavel Borzenkov Date: Wed, 4 May 2022 15:32:05 +0200 Subject: [PATCH 178/861] feat(languages): detect 't' as perl (#2395) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 35438758e..9d3ad27bc 100644 --- a/languages.toml +++ b/languages.toml @@ -748,7 +748,7 @@ source = { git = "https://github.com/theHamsta/tree-sitter-glsl", rev = "88408ff [[language]] name = "perl" scope = "source.perl" -file-types = ["pl", "pm"] +file-types = ["pl", "pm", "t"] shebangs = ["perl"] roots = [] comment-token = "#" From fc61796895a0175ccfed7f572960dc3cd21e7f04 Mon Sep 17 00:00:00 2001 From: ChrHorn Date: Thu, 5 May 2022 09:14:17 +0200 Subject: [PATCH 179/861] TOML highlight: use variable.other.member instead of string for quoted keys (#2391) --- runtime/queries/toml/highlights.scm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/runtime/queries/toml/highlights.scm b/runtime/queries/toml/highlights.scm index 2742b2be6..3c4425f8c 100644 --- a/runtime/queries/toml/highlights.scm +++ b/runtime/queries/toml/highlights.scm @@ -1,8 +1,10 @@ ; Properties ;----------- -(bare_key) @variable.other.member -(quoted_key) @string +[ + (bare_key) + (quoted_key) +] @variable.other.member ; Literals ;--------- From a5f4925f53d447bb7201c9a6e7a1c2730f292ae4 Mon Sep 17 00:00:00 2001 From: Matthew Toohey Date: Thu, 5 May 2022 09:47:28 -0400 Subject: [PATCH 180/861] feat(languages): git-ignore and git-attributes (#2397) --- book/src/generated/lang-support.md | 2 ++ helix-core/src/syntax.rs | 2 +- languages.toml | 26 +++++++++++++++++++ runtime/queries/git-attributes/highlights.scm | 9 +++++++ runtime/queries/git-ignore/highlights.scm | 25 ++++++++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/git-attributes/highlights.scm create mode 100644 runtime/queries/git-ignore/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 5c5ecaafe..b4e7ff93e 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -20,9 +20,11 @@ | erlang | ✓ | | | `erlang_ls` | | fish | ✓ | ✓ | ✓ | | | gdscript | ✓ | | ✓ | | +| git-attributes | ✓ | | | | | git-commit | ✓ | | | | | git-config | ✓ | | | | | git-diff | ✓ | | | | +| git-ignore | ✓ | | | | | git-rebase | ✓ | | | | | gleam | ✓ | | | | | glsl | ✓ | | ✓ | | diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index eab3ab79f..9208f0e8e 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -321,7 +321,7 @@ impl TextObjectQuery { fn read_query(language: &str, filename: &str) -> String { static INHERITS_REGEX: Lazy = - Lazy::new(|| Regex::new(r";+\s*inherits\s*:?\s*([a-z_,()]+)\s*").unwrap()); + Lazy::new(|| Regex::new(r";+\s*inherits\s*:?\s*([a-z_,()-]+)\s*").unwrap()); let query = load_runtime_file(language, filename).unwrap_or_default(); diff --git a/languages.toml b/languages.toml index 9d3ad27bc..279dab1f0 100644 --- a/languages.toml +++ b/languages.toml @@ -956,6 +956,32 @@ indent = { tab-width = 4, unit = "\t" } name = "git-config" source = { git = "https://github.com/the-mikedavis/tree-sitter-git-config", rev = "0e4f0baf90b57e5aeb62dcdbf03062c6315d43ea" } +[[language]] +name = "git-attributes" +scope = "source.gitattributes" +roots = [] +file-types = [".gitattributes"] +injection-regex = "git-attributes" +comment-token = "#" +grammar = "gitattributes" + +[[grammar]] +name = "gitattributes" +source = { git = "https://github.com/mtoohey31/tree-sitter-gitattributes", rev = "3dd50808e3096f93dccd5e9dc7dc3dba2eb12dc4" } + +[[language]] +name = "git-ignore" +scope = "source.gitignore" +roots = [] +file-types = [".gitignore"] +injection-regex = "git-ignore" +comment-token = "#" +grammar = "gitignore" + +[[grammar]] +name = "gitignore" +source = { git = "https://github.com/shunsambongi/tree-sitter-gitignore", rev = "f4685bf11ac466dd278449bcfe5fd014e94aa504" } + [[language]] name = "graphql" scope = "source.graphql" diff --git a/runtime/queries/git-attributes/highlights.scm b/runtime/queries/git-attributes/highlights.scm new file mode 100644 index 000000000..0b1415b58 --- /dev/null +++ b/runtime/queries/git-attributes/highlights.scm @@ -0,0 +1,9 @@ +; inherits: git-ignore + +(attribute) @variable +(value) @string + +(quoted_pattern ["\""] @string) + +(attribute_unset) @operator +(attribute_set_to) @operator diff --git a/runtime/queries/git-ignore/highlights.scm b/runtime/queries/git-ignore/highlights.scm new file mode 100644 index 000000000..4264eb04e --- /dev/null +++ b/runtime/queries/git-ignore/highlights.scm @@ -0,0 +1,25 @@ +(pattern_char) @string +(pattern_char_escaped) @constant.character.escape + +(directory_separator) @string +(directory_separator_escaped) @constant.character.escape + +(negation) @operator + +(wildcard_char_single) @operator +(wildcard_chars) @operator +(wildcard_chars_allow_slash) @operator + +(bracket_char) @string +(bracket_char_escaped) @constant.character.escape + +(bracket_negation) @operator +(bracket_range) @operator +(bracket_char_class) @keyword + +[ + "[" + "]" +] @punctuation.bracket + +(comment) @comment From 2f240b018eb95457441a0cad9b7af47b0e55a54c Mon Sep 17 00:00:00 2001 From: Ben Lee-Cohen Date: Thu, 5 May 2022 11:58:18 -0400 Subject: [PATCH 181/861] Adding the global gitignore to the default (#2410) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 279dab1f0..ee9b9961a 100644 --- a/languages.toml +++ b/languages.toml @@ -973,7 +973,7 @@ source = { git = "https://github.com/mtoohey31/tree-sitter-gitattributes", rev = name = "git-ignore" scope = "source.gitignore" roots = [] -file-types = [".gitignore"] +file-types = [".gitignore", ".gitignore_global"] injection-regex = "git-ignore" comment-token = "#" grammar = "gitignore" From 495ba40eafe84f048e56b3d958a7727751f3aa99 Mon Sep 17 00:00:00 2001 From: Robert Walter <26892280+RobWalt@users.noreply.github.com> Date: Thu, 5 May 2022 19:09:09 +0200 Subject: [PATCH 182/861] feat(languages): add odin language (#2399) --- book/src/generated/lang-support.md | 1 + languages.toml | 13 +++ runtime/queries/odin/highlights.scm | 141 ++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 runtime/queries/odin/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index b4e7ff93e..68163e08b 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -59,6 +59,7 @@ | nu | ✓ | | | | | ocaml | ✓ | | ✓ | `ocamllsp` | | ocaml-interface | ✓ | | | `ocamllsp` | +| odin | ✓ | | | | | org | ✓ | | | | | perl | ✓ | ✓ | ✓ | | | php | ✓ | ✓ | ✓ | `intelephense` | diff --git a/languages.toml b/languages.toml index ee9b9961a..e4f203f8d 100644 --- a/languages.toml +++ b/languages.toml @@ -1329,3 +1329,16 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "cpon" source = { git = "https://github.com/fvacek/tree-sitter-cpon", rev = "11ba46a4de3eb86934003133099c9963a60f9687" } + +[[language]] +name = "odin" +auto-format = false +scope = "source.odin" +file-types = ["odin"] +roots = [] +comment-token = "//" +indent = { tab-width = 4, unit = " " } + +[[grammar]] +name = "odin" +source = { git = "https://github.com/MineBill/tree-sitter-odin", rev = "da885f4a387f169b9b69fe0968259ee257a8f69a" } diff --git a/runtime/queries/odin/highlights.scm b/runtime/queries/odin/highlights.scm new file mode 100644 index 000000000..1d801ff1b --- /dev/null +++ b/runtime/queries/odin/highlights.scm @@ -0,0 +1,141 @@ +; Function calls + +(call_expression + function: (identifier) @function) + +(call_expression + function: (selector_expression + field: (field_identifier) @function)) + + +; ; Function definitions + +(function_declaration + name: (identifier) @function) + +(proc_group + (identifier) @function) + +; ; Identifiers + +(type_identifier) @type +(field_identifier) @variable.other.member +(identifier) @variable + +(const_declaration + (identifier) @constant) +(const_declaration_with_type + (identifier) @constant) + +"any" @type + +(directive_identifier) @constant + +; ; Operators + +[ + "?" + "-" + "-=" + ":=" + "!" + "!=" + "*" + "*" + "*=" + "/" + "/=" + "&" + "&&" + "&=" + "%" + "%=" + "^" + "+" + "+=" + "<-" + "<" + "<<" + "<<=" + "<=" + "=" + "==" + ">" + ">=" + ">>" + ">>=" + "|" + "|=" + "||" + "~" + ".." + "..<" + "..=" + "::" +] @operator + +; ; Keywords + +[ + ; "asm" + "auto_cast" + ; "bit_set" + "cast" + ; "context" + ; "or_else" + ; "or_return" + "in" + ; "not_in" + "distinct" + "foreign" + "transmute" + ; "typeid" + + "break" + "case" + "continue" + "defer" + "else" + "using" + "when" + "where" + "fallthrough" + "for" + "proc" + "if" + "import" + "map" + "package" + "return" + "struct" + "union" + "enum" + "switch" + "dynamic" +] @keyword + +; ; Literals + +[ + (interpreted_string_literal) + (raw_string_literal) + (rune_literal) +] @string + +(escape_sequence) @constant.character.escape + +(int_literal) @constant.numeric.integer +(float_literal) @constant.numeric.float +(imaginary_literal) @constant.numeric + +[ + (true) + (false) +] @constant.builtin.boolean + +[ + (nil) + (undefined) +] @constant.builtin + +(comment) @comment.line From b38c26809740a827397347fc55300ffd26f46c91 Mon Sep 17 00:00:00 2001 From: ChrHorn Date: Sat, 7 May 2022 04:26:34 +0200 Subject: [PATCH 183/861] fix Markdown list highlighting (#2401) --- runtime/queries/markdown/highlights.scm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runtime/queries/markdown/highlights.scm b/runtime/queries/markdown/highlights.scm index ed22b806f..988a56b6d 100644 --- a/runtime/queries/markdown/highlights.scm +++ b/runtime/queries/markdown/highlights.scm @@ -35,9 +35,12 @@ (list_marker_plus) (list_marker_minus) (list_marker_star) +] @markup.list.numbered + +[ (list_marker_dot) (list_marker_parenthesis) -] @punctuation.special +] @markup.list.unnumbered [ (backslash_escape) From 76d55c0d9e12b7ae9f08d2b722c44473c9b0ef2a Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sat, 7 May 2022 13:47:15 +0200 Subject: [PATCH 184/861] Cpon support tree sitter version bumped (#2424) Co-authored-by: Fanda Vacek --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index e4f203f8d..08dadb15b 100644 --- a/languages.toml +++ b/languages.toml @@ -1328,7 +1328,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "cpon" -source = { git = "https://github.com/fvacek/tree-sitter-cpon", rev = "11ba46a4de3eb86934003133099c9963a60f9687" } +source = { git = "https://github.com/fvacek/tree-sitter-cpon", rev = "cc6a22b1fa8917c2d041af399f19f34a0a9d94ff" } [[language]] name = "odin" From f3164c1174fd1415140693486637bfd2ea6e6a68 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 8 May 2022 20:16:29 +0200 Subject: [PATCH 185/861] Monokai pro spectrum theme shows error in yellow on red background (#2433) Co-authored-by: Fanda Vacek --- 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 807c87f15..80e2a88d4 100644 --- a/runtime/themes/monokai_pro_spectrum.toml +++ b/runtime/themes/monokai_pro_spectrum.toml @@ -62,7 +62,7 @@ "variable.parameter" = "#f59762" # error -"error" = "red" +"error" = { bg = "red", fg = "yellow" } # annotations, decorators "special" = "#f59762" From ae19aaf1a65cf761e4669df8f7349cae6aad79e4 Mon Sep 17 00:00:00 2001 From: Yt Date: Mon, 9 May 2022 06:53:03 -0400 Subject: [PATCH 186/861] languages: add inc files to php (#2440) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 08dadb15b..bda195f2e 100644 --- a/languages.toml +++ b/languages.toml @@ -475,7 +475,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-bash", rev = "275ef name = "php" scope = "source.php" injection-regex = "php" -file-types = ["php"] +file-types = ["php", "inc"] shebangs = ["php"] roots = ["composer.json", "index.php"] language-server = { command = "intelephense", args = ["--stdio"] } From 544a05dabf485d3b9c46cfa3010e8f19e7d715cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 May 2022 07:55:01 +0800 Subject: [PATCH 187/861] build(deps): bump tokio from 1.18.1 to 1.18.2 (#2448) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.18.1 to 1.18.2. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.18.1...tokio-1.18.2) --- updated-dependencies: - dependency-name: tokio dependency-type: direct:production update-type: version-update:semver-patch ... 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 244923822..aa158ced8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1117,9 +1117,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.18.1" +version = "1.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce653fb475565de9f6fb0614b28bca8df2c430c0cf84bcd9c843f15de5414cc" +checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395" dependencies = [ "bytes", "libc", From 40647f03ed561532727d5939ccccf485045c4b5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 May 2022 07:55:31 +0800 Subject: [PATCH 188/861] build(deps): bump serde_json from 1.0.80 to 1.0.81 (#2447) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.80 to 1.0.81. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.80...v1.0.81) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... 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 aa158ced8..98c531af9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -906,9 +906,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f972498cf015f7c0746cac89ebe1d6ef10c293b94175a243a2d9442c163d9944" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ "itoa", "ryu", From e0b5cdfb477108a5cbd40afd9384a96b50d46fbb Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 10 May 2022 19:53:43 -0500 Subject: [PATCH 189/861] prevent selection collapse when inserting a newline (#2414) Inserting a newline currently collapses any connected selections when inserting or appending. It's happening because we're reducing the selections down to their cursors (`let selection = ..` line) and then computing the new selection based on the cursor. We're discarding the original head and anchor information which are necessary to emulate Kakoune's behavior. In Kakoune, inserting a newline retains the existing selection and _slides_ it (moves head and anchor by the same amount) forward by the newline and indentation amount. Appending a newline extends the selection to include the newline and any new indentation. With the implementation of insert_newline here, we slide by adding the global and local offsets to both head and anchor. We extend by adding the global offset to both head and anchor but the local offset only to the head. --- helix-term/src/commands.rs | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 07d805cad..c2bc04e02 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2777,14 +2777,14 @@ pub mod insert { let text = doc.text().slice(..); let contents = doc.text(); - let selection = doc.selection(view.id).clone().cursors(text); + let selection = doc.selection(view.id).clone(); let mut ranges = SmallVec::with_capacity(selection.len()); // TODO: this is annoying, but we need to do it to properly calculate pos after edits - let mut offs = 0; + let mut global_offs = 0; let mut transaction = Transaction::change_by_selection(contents, &selection, |range| { - let pos = range.head; + let pos = range.cursor(text); let prev = if pos == 0 { ' ' @@ -2814,27 +2814,41 @@ pub mod insert { .and_then(|pair| if pair.close == curr { Some(pair) } else { None }) .is_some(); - let new_head_pos = if on_auto_pair { + 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 new_head_pos = pos + offs + text.chars().count(); + let local_offs = text.chars().count(); text.push_str(doc.line_ending.as_str()); text.push_str(&indent); - new_head_pos + local_offs } else { text.reserve_exact(1 + indent.len()); text.push_str(doc.line_ending.as_str()); text.push_str(&indent); - pos + offs + text.chars().count() + text.chars().count() + }; + + let new_range = if doc.restore_cursor { + // when appending, extend the range by local_offs + Range::new( + range.anchor + global_offs, + range.head + local_offs + global_offs, + ) + } else { + // when inserting, slide the range by local_offs + Range::new( + range.anchor + local_offs + global_offs, + range.head + local_offs + global_offs, + ) }; // TODO: range replace or extend // 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(Range::new(new_head_pos, new_head_pos)); - offs += text.chars().count(); + ranges.push(new_range); + global_offs += text.chars().count(); (pos, pos, Some(text.into())) }); From 247ab25bc04b75fede667bc2736c8449e8608714 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 10 May 2022 19:53:54 -0500 Subject: [PATCH 190/861] prefer Document::set_selection to inserting selections directly (#2411) Inserting these with the `HashMap::insert` method evades the call to `Selection::ensure_invariants`. The effect is that the scratch buffer (or other buffers opened through these code-paths) can start with a selection at (0, 0), when a file with equivalent contents ("\n") would start with (0, 1). I.e.: hx and touch f hx f start with different selections even though they have an equivalent Rope. With this change they both start with (0, 1). --- helix-view/src/editor.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 29aea74b7..f4a48ba65 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -700,7 +700,7 @@ impl Editor { let view_id = view!(self).id; let doc = self.documents.get_mut(&id).unwrap(); if doc.selections().is_empty() { - doc.selections.insert(view_id, Selection::point(0)); + doc.set_selection(view_id, Selection::point(0)); } return; } @@ -716,7 +716,7 @@ impl Editor { ); // initialize selection for view let doc = self.documents.get_mut(&id).unwrap(); - doc.selections.insert(view_id, Selection::point(0)); + doc.set_selection(view_id, Selection::point(0)); } } @@ -851,7 +851,7 @@ impl Editor { let view = View::new(doc_id, self.config().gutters.clone()); let view_id = self.tree.insert(view); let doc = self.documents.get_mut(&doc_id).unwrap(); - doc.selections.insert(view_id, Selection::point(0)); + doc.set_selection(view_id, Selection::point(0)); } self._refresh(); From 807cdc60bf060bdbff95c2ab44c4f2ce0cf66e83 Mon Sep 17 00:00:00 2001 From: EmmChriss <42001129+EmmChriss@users.noreply.github.com> Date: Wed, 11 May 2022 03:54:35 +0300 Subject: [PATCH 191/861] configurable lsp request timeout (#2405) --- helix-core/src/syntax.rs | 6 ++++++ helix-lsp/src/client.rs | 8 ++++++-- helix-lsp/src/lib.rs | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 9208f0e8e..b20d9092f 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -50,6 +50,10 @@ where Ok(Option::::deserialize(deserializer)?.and_then(AutoPairConfig::into)) } +fn default_timeout() -> u64 { + 20 +} + #[derive(Debug, Serialize, Deserialize)] pub struct Configuration { pub language: Vec, @@ -116,6 +120,8 @@ pub struct LanguageServerConfiguration { #[serde(default)] #[serde(skip_serializing_if = "Vec::is_empty")] pub args: Vec, + #[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 4bfa2f643..08201b3f4 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -35,6 +35,7 @@ pub struct Client { root_path: Option, root_uri: Option, workspace_folders: Vec, + req_timeout: u64, } impl Client { @@ -45,6 +46,7 @@ impl Client { config: Option, root_markers: &[String], id: usize, + req_timeout: u64, ) -> Result<(Self, UnboundedReceiver<(usize, Call)>, Arc)> { // Resolve path to the binary let cmd = which::which(cmd).map_err(|err| anyhow::anyhow!(err))?; @@ -97,6 +99,7 @@ impl Client { capabilities: OnceCell::new(), offset_encoding: OffsetEncoding::Utf8, config, + req_timeout, root_path, root_uri, @@ -170,6 +173,7 @@ impl Client { { let server_tx = self.server_tx.clone(); let id = self.next_request_id(); + let timeout_secs = self.req_timeout; async move { use std::time::Duration; @@ -193,8 +197,8 @@ impl Client { }) .map_err(|e| Error::Other(e.into()))?; - // TODO: specifiable timeout, delay other calls until initialize success - timeout(Duration::from_secs(20), rx.recv()) + // TODO: delay other calls until initialize success + timeout(Duration::from_secs(timeout_secs), rx.recv()) .await .map_err(|_| Error::Timeout)? // return Timeout .ok_or(Error::StreamClosed)? diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index aeda16d0d..84fb00fe7 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -360,6 +360,7 @@ impl Registry { language_config.config.clone(), &language_config.roots, id, + config.timeout, )?; self.incoming.push(UnboundedReceiverStream::new(incoming)); let client = Arc::new(client); From 2cb1ea7127122bbcb0f05dfbb7959334c751c3d7 Mon Sep 17 00:00:00 2001 From: unrelentingtech Date: Wed, 11 May 2022 04:06:37 +0300 Subject: [PATCH 192/861] feat(lang): add Meson language support (#2314) https://mesonbuild.com/Syntax.html --- book/src/generated/lang-support.md | 1 + languages.toml | 13 ++++++ runtime/queries/meson/highlights.scm | 62 ++++++++++++++++++++++++++++ runtime/queries/meson/indents.scm | 16 +++++++ 4 files changed, 92 insertions(+) create mode 100644 runtime/queries/meson/highlights.scm create mode 100644 runtime/queries/meson/indents.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 68163e08b..95cf91a43 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -53,6 +53,7 @@ | lua | ✓ | | ✓ | | | make | ✓ | | | | | markdown | ✓ | | | | +| meson | ✓ | | ✓ | | | mint | | | | `mint` | | nickel | ✓ | | ✓ | `nls` | | nix | ✓ | | ✓ | `rnix-lsp` | diff --git a/languages.toml b/languages.toml index bda195f2e..bedde5a2d 100644 --- a/languages.toml +++ b/languages.toml @@ -1342,3 +1342,16 @@ indent = { tab-width = 4, unit = " " } [[grammar]] name = "odin" source = { git = "https://github.com/MineBill/tree-sitter-odin", rev = "da885f4a387f169b9b69fe0968259ee257a8f69a" } + +[[language]] +name = "meson" +scope = "source.meson" +injection-regex = "meson" +file-types = ["meson.build"] +roots = [] +comment-token = "#" +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "meson" +source = { git = "https://github.com/bearcove/tree-sitter-meson", rev = "feea83be9225842490066522ced2d13eb9cce0bd" } diff --git a/runtime/queries/meson/highlights.scm b/runtime/queries/meson/highlights.scm new file mode 100644 index 000000000..01df8f279 --- /dev/null +++ b/runtime/queries/meson/highlights.scm @@ -0,0 +1,62 @@ +(string_literal) @string + +(boolean_literal) @constant.builtin.boolean +(integer_literal) @constant.numeric.integer + +(comment) @comment.line +(function_id) @function +(keyword_arg_key) @variable.other.member +(id_expression) @variable + +[ + "if" + "elif" + "else" + "endif" +] @keyword.control.conditional + +[ + "foreach" + "endforeach" +] @keyword.control.repeat + +[ + "break" + "continue" +] @keyword.control + +[ + "not" + "in" + "and" + "or" +] @keyword.operator + +[ + "!" + "+" + "-" + "*" + "/" + "%" + "==" + "!=" + ">" + "<" + ">=" + "<=" +] @operator + +[ + ":" + "," +] @punctuation.delimiter + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket diff --git a/runtime/queries/meson/indents.scm b/runtime/queries/meson/indents.scm new file mode 100644 index 000000000..a1c7b3fab --- /dev/null +++ b/runtime/queries/meson/indents.scm @@ -0,0 +1,16 @@ +[ + (method_expression) + (function_expression) + (array_literal) + (dictionary_literal) + (selection_statement) + (iteration_statement) +] @indent + +[ + ")" + "]" + "}" + "endif" + "endforeach" +] @outdent From c80ac84978fa224498aaae86e2434b568221d216 Mon Sep 17 00:00:00 2001 From: Alexis Kalabura <55039048+axdank@users.noreply.github.com> Date: Tue, 10 May 2022 21:06:57 -0400 Subject: [PATCH 193/861] Run debug console in windows (#2294) --- helix-view/src/handlers/dap.rs | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/helix-view/src/handlers/dap.rs b/helix-view/src/handlers/dap.rs index c69d290d1..c7d3758d6 100644 --- a/helix-view/src/handlers/dap.rs +++ b/helix-view/src/handlers/dap.rs @@ -4,6 +4,7 @@ use helix_core::Selection; use helix_dap::{self as dap, Client, Payload, Request, ThreadId}; use helix_lsp::block_on; use log::warn; +use std::io::ErrorKind; use std::path::PathBuf; #[macro_export] @@ -285,11 +286,31 @@ impl Editor { serde_json::from_value(request.arguments.unwrap_or_default()).unwrap(); // TODO: no unwrap - let process = std::process::Command::new("tmux") - .arg("split-window") - .arg(arguments.args.join(" ")) - .spawn() - .unwrap(); + let process = if cfg!(windows) { + std::process::Command::new("wt") + .arg("new-tab") + .arg("--title") + .arg("DEBUG") + .arg("cmd") + .arg("/C") + .arg(arguments.args.join(" ")) + .spawn() + .unwrap_or_else(|error| match error.kind() { + ErrorKind::NotFound => std::process::Command::new("conhost") + .arg("cmd") + .arg("/C") + .arg(arguments.args.join(" ")) + .spawn() + .unwrap(), + e => panic!("Error to start debug console: {}", e), + }) + } else { + std::process::Command::new("tmux") + .arg("split-window") + .arg(arguments.args.join(" ")) + .spawn() + .unwrap() + }; let _ = debugger .reply( From 0477d0289476c34e6b4d11a28165fee0c49063b3 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Wed, 11 May 2022 09:12:27 +0800 Subject: [PATCH 194/861] Exclude cursor when doing ctrl-w (#2431) Currently ctrl-w in insert mode deletes the cursor which results in unexpected behavior. The patch also reduces the selection to cursor before performing prev word to remove the behavior of removing unnecessary text when nothing should be removed. 1. `::#(|)#::` after `ctrl-w` should be `#(|)#::`, previously `#(|)#:` 2. `#(|::)#` after `ctrl-w` should be `#(|::)#`, previously `#(|)#` Fix #2390 --- helix-term/src/commands.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c2bc04e02..f0b54e0b7 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2632,6 +2632,18 @@ pub mod insert { pub type Hook = fn(&Rope, &Selection, char) -> Option; pub type PostHook = fn(&mut Context, char); + /// Exclude the cursor in range. + fn exclude_cursor(text: RopeSlice, range: Range, cursor: Range) -> Range { + if range.to() == cursor.to() { + Range::new( + range.from(), + graphemes::prev_grapheme_boundary(text, cursor.to()), + ) + } else { + range + } + } + // It trigger completion when idle timer reaches deadline // Only trigger completion if the word under cursor is longer than n characters pub fn idle_completion(cx: &mut Context) { @@ -2948,10 +2960,11 @@ pub mod insert { let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); - let selection = doc - .selection(view.id) - .clone() - .transform(|range| movement::move_prev_word_start(text, range, count)); + let selection = doc.selection(view.id).clone().transform(|range| { + let cursor = Range::point(range.cursor(text)); + let next = movement::move_prev_word_start(text, cursor, count); + exclude_cursor(text, next, range) + }); delete_selection_insert_mode(doc, view, &selection); } From a5bc69c2b5c6821129b635227e9f152e92f08ddc Mon Sep 17 00:00:00 2001 From: amaihoefner Date: Wed, 11 May 2022 03:18:45 +0200 Subject: [PATCH 195/861] feat(commands): add log-open command (#2422) --- book/src/generated/typable-cmd.md | 1 + helix-term/src/commands/typed.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 17d10c996..5ae184daf 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -63,5 +63,6 @@ | `:tree-sitter-subtree`, `:ts-subtree` | Display tree sitter subtree under cursor, primarily for debugging queries. | | `:config-reload` | Refreshes helix's config. | | `:config-open` | Open the helix config.toml file. | +| `:log-open` | Open the helix log file. | | `:pipe` | Pipe each selection to the shell command. | | `: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 68b64bb8d..74ab73bef 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1146,6 +1146,15 @@ fn open_config( Ok(()) } +fn open_log( + cx: &mut compositor::Context, + _args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + cx.editor.open(helix_loader::log_file(), Action::Replace)?; + Ok(()) +} + fn refresh_config( cx: &mut compositor::Context, _args: &[Cow], @@ -1647,6 +1656,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: open_config, completer: None, }, + TypableCommand { + name: "log-open", + aliases: &[], + doc: "Open the helix log file.", + fun: open_log, + completer: None, + }, TypableCommand { name: "pipe", aliases: &[], From 8b1a03a1783d8eb176d178f11cfa229a9e9b8e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Wed, 11 May 2022 10:51:20 +0900 Subject: [PATCH 196/861] Add FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..90cb6945b --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +open_collective: helix-editor From 7ae6cad52ed001a903577e30fb71e346fd831af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Wed, 11 May 2022 11:00:55 +0900 Subject: [PATCH 197/861] Don't panic on LSP parsing errors This made sense initially when the implementation was still new (so we got user reports more frequently), but a parsing error now generally signifies a language server isn't properly implementing the spec. --- helix-lsp/src/lib.rs | 49 +++++++++++------------------------ helix-term/src/application.rs | 24 +++++++++++++---- 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 84fb00fe7..f33646c82 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -40,6 +40,8 @@ pub enum Error { StreamClosed, #[error("LSP not defined")] LspNotDefined, + #[error("Unhandled")] + Unhandled, #[error(transparent)] Other(#[from] anyhow::Error), } @@ -226,34 +228,27 @@ pub enum MethodCall { } impl MethodCall { - pub fn parse(method: &str, params: jsonrpc::Params) -> Option { + pub fn parse(method: &str, params: jsonrpc::Params) -> Result { use lsp::request::Request; let request = match method { lsp::request::WorkDoneProgressCreate::METHOD => { - let params: lsp::WorkDoneProgressCreateParams = params - .parse() - .expect("Failed to parse WorkDoneCreate params"); + let params: lsp::WorkDoneProgressCreateParams = params.parse()?; Self::WorkDoneProgressCreate(params) } lsp::request::ApplyWorkspaceEdit::METHOD => { - let params: lsp::ApplyWorkspaceEditParams = params - .parse() - .expect("Failed to parse ApplyWorkspaceEdit params"); + let params: lsp::ApplyWorkspaceEditParams = params.parse()?; Self::ApplyWorkspaceEdit(params) } lsp::request::WorkspaceFoldersRequest::METHOD => Self::WorkspaceFolders, lsp::request::WorkspaceConfiguration::METHOD => { - let params: lsp::ConfigurationParams = params - .parse() - .expect("Failed to parse WorkspaceConfiguration params"); + let params: lsp::ConfigurationParams = params.parse()?; Self::WorkspaceConfiguration(params) } _ => { - log::warn!("unhandled lsp request: {}", method); - return None; + return Err(Error::Unhandled); } }; - Some(request) + Ok(request) } } @@ -268,48 +263,34 @@ pub enum Notification { } impl Notification { - pub fn parse(method: &str, params: jsonrpc::Params) -> Option { + pub fn parse(method: &str, params: jsonrpc::Params) -> Result { use lsp::notification::Notification as _; let notification = match method { lsp::notification::Initialized::METHOD => Self::Initialized, lsp::notification::PublishDiagnostics::METHOD => { - let params: lsp::PublishDiagnosticsParams = params - .parse() - .map_err(|err| { - log::error!( - "received malformed PublishDiagnostic from Language Server: {}", - err - ) - }) - .ok()?; - - // TODO: need to loop over diagnostics and distinguish them by URI + let params: lsp::PublishDiagnosticsParams = params.parse()?; Self::PublishDiagnostics(params) } lsp::notification::ShowMessage::METHOD => { - let params: lsp::ShowMessageParams = params.parse().ok()?; - + let params: lsp::ShowMessageParams = params.parse()?; Self::ShowMessage(params) } lsp::notification::LogMessage::METHOD => { - let params: lsp::LogMessageParams = params.parse().ok()?; - + let params: lsp::LogMessageParams = params.parse()?; Self::LogMessage(params) } lsp::notification::Progress::METHOD => { - let params: lsp::ProgressParams = params.parse().ok()?; - + let params: lsp::ProgressParams = params.parse()?; Self::ProgressMessage(params) } _ => { - log::error!("unhandled LSP notification: {}", method); - return None; + return Err(Error::Unhandled); } }; - Some(notification) + Ok(notification) } } diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 91caade79..2dfccf043 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -399,8 +399,14 @@ impl Application { match call { Call::Notification(helix_lsp::jsonrpc::Notification { method, params, .. }) => { let notification = match Notification::parse(&method, params) { - Some(notification) => notification, - None => return, + Ok(notification) => notification, + Err(err) => { + log::error!( + "received malformed notification from Language Server: {}", + err + ); + return; + } }; match notification { @@ -613,9 +619,17 @@ impl Application { method, params, id, .. }) => { let call = match MethodCall::parse(&method, params) { - Some(call) => call, - None => { - error!("Method not found {}", method); + Ok(call) => call, + Err(helix_lsp::Error::Unhandled) => { + error!("Language Server: Method not found {}", method); + return; + } + Err(err) => { + log::error!( + "received malformed method call from Language Server: {}: {}", + method, + err + ); return; } }; From 7b287f636f72766356aadb95ba2f32636e0601d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Wed, 11 May 2022 11:02:40 +0900 Subject: [PATCH 198/861] nix: update flake dependencies --- flake.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index be0aaae51..d7ce01257 100644 --- a/flake.lock +++ b/flake.lock @@ -75,11 +75,11 @@ ] }, "locked": { - "lastModified": 1651609988, - "narHash": "sha256-oMjBD+noDmqTs3p31S+YES0zo0LTZ8GNe8klIre5NXQ=", + "lastModified": 1651844867, + "narHash": "sha256-a+bAmmeIudRVY23ZkEB5W5xJumBY3ydsiDIGN/56NmQ=", "owner": "nix-community", "repo": "dream2nix", - "rev": "6672d1f3d966c4d1e36ae66d156c0b1caec62dac", + "rev": "e5d0e9cdb00695b0b63d1f52ff3b39c0e3035fe3", "type": "github" }, "original": { @@ -130,11 +130,11 @@ ] }, "locked": { - "lastModified": 1651610406, - "narHash": "sha256-VrVAvivU3Bx0JPI6c8rDsEgfJUftOA9LOiuYMMVYseE=", + "lastModified": 1652163169, + "narHash": "sha256-WgFpNZgwqQOEkJJfA6z0NBL5+U/oMV3fT/j5TNERoYY=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "d812e9a68fd7144d309b6b86876713759e5aaf7f", + "rev": "f5719d90394a624549a00f01c76f6ef3ed079bb3", "type": "github" }, "original": { @@ -145,11 +145,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1651558728, - "narHash": "sha256-8HzyRnWlgZluUrVFNOfZAOlA1fghpOSezXvxhalGMUo=", + "lastModified": 1652172129, + "narHash": "sha256-8e2JMrswaKe02P8rYfvIMoc59pNuw6h/GYu8DBE1c+0=", "owner": "nixos", "repo": "nixpkgs", - "rev": "cbe587c735b734405f56803e267820ee1559e6c1", + "rev": "f419dc5763c2b3c5580e396dea065b6d8b58ee27", "type": "github" }, "original": { @@ -174,11 +174,11 @@ ] }, "locked": { - "lastModified": 1651545993, - "narHash": "sha256-+Qc553XIjn9/P2YpcTsL1nIG9hpLfBT9UMAhw0PkM3E=", + "lastModified": 1652149774, + "narHash": "sha256-rms5yNnnlmaqzEnI/9Log+5k/yVz4fB1BUVx5HXf8i8=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "8aeb9a75d2d52700ca987559de9859ef6fe38970", + "rev": "1dcdd08fcd39e4e053f58f9959be801399c5211e", "type": "github" }, "original": { From af387e6873e88c30f8dacbae9567c8b28f09213f Mon Sep 17 00:00:00 2001 From: spindlebink <63519521+spindlebink@users.noreply.github.com> Date: Thu, 12 May 2022 08:23:38 -0500 Subject: [PATCH 199/861] Default to tabs instead of spaces for Odin files (#2464) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index bedde5a2d..8c0f40482 100644 --- a/languages.toml +++ b/languages.toml @@ -1337,7 +1337,7 @@ scope = "source.odin" file-types = ["odin"] roots = [] comment-token = "//" -indent = { tab-width = 4, unit = " " } +indent = { tab-width = 4, unit = "\t" } [[grammar]] name = "odin" From 823eaad1a118e8865a6400afc22d37e060783d45 Mon Sep 17 00:00:00 2001 From: Timothy DeHerrera Date: Sat, 14 May 2022 15:49:06 -0600 Subject: [PATCH 200/861] Add Snazzy theme (#2473) --- runtime/themes/snazzy.toml | 68 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 runtime/themes/snazzy.toml diff --git a/runtime/themes/snazzy.toml b/runtime/themes/snazzy.toml new file mode 100644 index 000000000..c0547f33b --- /dev/null +++ b/runtime/themes/snazzy.toml @@ -0,0 +1,68 @@ +# Author : Sebastian Zivota +# Author : Timothy DeHerrera +"comment" = { fg = "comment" } +"constant" = { fg = "purple" } +"constant.character.escape" = { fg = "magenta" } +"function" = { fg = "green" } +"keyword" = { fg = "magenta" } +"operator" = { fg = "magenta" } +"punctuation" = { fg = "foreground" } +"string" = { fg = "yellow" } +"path" = { fg = "blue" } +"string.regexp" = { fg = "red" } +"tag" = { fg = "magenta" } +"type" = { fg = "cyan", modifiers = ["italic"] } +"type.enum.variant" = { fg = "foreground", modifiers = ["italic"] } +"variable" = { fg = "foreground" } +"variable.builtin" = { fg = "cyan", modifiers = ["italic"] } +"variable.parameter" = { fg ="blue", modifiers = ["italic"] } + +"diff.plus" = { fg = "green" } +"diff.delta" = { fg = "blue" } +"diff.minus" = { fg = "red" } + +"ui.background" = { fg = "foreground", bg = "background" } +"ui.cursor" = { fg = "background", bg = "blue", modifiers = ["dim"] } +"ui.cursor.match" = { fg = "green", modifiers = ["underlined"] } +"ui.cursor.primary" = { fg = "background", bg = "cyan", modifier = ["dim"] } +"ui.help" = { fg = "foreground", bg = "background_dark" } +"ui.linenr" = { fg = "comment" } +"ui.linenr.selected" = { fg = "foreground" } +"ui.menu" = { fg = "foreground", bg = "background_dark" } +"ui.menu.selected" = { fg = "cyan", bg = "background_dark" } +"ui.popup" = { fg = "foreground", bg = "background_dark" } +"ui.selection" = { bg = "secondary_highlight" } +"ui.selection.primary" = { bg = "primary_highlight" } +"ui.statusline" = { fg = "foreground", bg = "background_dark" } +"ui.statusline.inactive" = { fg = "comment", bg = "background_dark" } +"ui.text" = { fg = "foreground" } +"ui.text.focus" = { fg = "cyan" } +"ui.window" = { fg = "foreground" } +"ui.virtual" = { fg = "comment" } + +"error" = { fg = "red" } +"warning" = { fg = "cyan" } + +"markup.heading" = { fg = "purple", modifiers = ["bold"] } +"markup.list" = "cyan" +"markup.bold" = { fg = "blue", modifiers = ["bold"] } +"markup.italic" = { fg = "yellow", modifiers = ["italic"] } +"markup.link.url" = "cyan" +"markup.link.text" = "magenta" +"markup.quote" = { fg = "yellow", modifiers = ["italic"] } +"markup.raw" = { fg = "foreground" } + +[palette] +background = "#282a36" +background_dark = "#21222c" +primary_highlight = "#800049" +secondary_highlight = "#4d4f66" +foreground = "#eff0eb" +comment = "#a39e9b" +red = "#ff5c57" +blue = "#57c7ff" +yellow = "#f3f99d" +green = "#5af78e" +purple = "#bd93f9" +cyan = "#9aedfe" +magenta = "#ff6ac1" From 595213ca74e360d8de37fe7aa8f0f05ae6ec8f21 Mon Sep 17 00:00:00 2001 From: Alexis Geoffrey Date: Mon, 16 May 2022 07:48:28 +0000 Subject: [PATCH 201/861] Change default Hare tab width to 8 (#2480) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 8c0f40482..46b607472 100644 --- a/languages.toml +++ b/languages.toml @@ -1284,7 +1284,7 @@ injection-regex = "hare" file-types = ["ha"] roots = [] comment-token = "//" -indent = { tab-width = 4, unit = "\t" } +indent = { tab-width = 8, unit = "\t" } [[grammar]] name = "hare" From 0258cf45f300eb2ac1119be4186a83bfa5835bd9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 May 2022 12:32:18 +0900 Subject: [PATCH 202/861] build(deps): bump etcetera from 0.3.2 to 0.4.0 (#2486) Bumps [etcetera](https://github.com/arzg/etcetera) from 0.3.2 to 0.4.0. - [Release notes](https://github.com/arzg/etcetera/releases) - [Commits](https://github.com/arzg/etcetera/commits) --- updated-dependencies: - dependency-name: etcetera dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- helix-core/Cargo.toml | 2 +- helix-loader/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 98c531af9..0879faa65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -212,9 +212,9 @@ dependencies = [ [[package]] name = "etcetera" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016b04fd1e94fb833d432634245c9bb61cf1c7409668a0e7d4c3ab00c5172dec" +checksum = "d017fce18e4e9bfa75e1db51f49f4487bd3f8a7df509b24a46474a956ee962fd" dependencies = [ "cfg-if", "dirs-next", diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index ab937f0b1..9973516b5 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -40,7 +40,7 @@ encoding_rs = "0.8" chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] } -etcetera = "0.3" +etcetera = "0.4" textwrap = "0.15.0" [dev-dependencies] diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index c8cbf6d10..3a900f4ac 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -13,7 +13,7 @@ homepage = "https://helix-editor.com" anyhow = "1" serde = { version = "1.0", features = ["derive"] } toml = "0.5" -etcetera = "0.3" +etcetera = "0.4" tree-sitter = "0.20" once_cell = "1.9" From 50dd11985c107b9ed1abb7ca4ebc95f02deff9cf Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 17 May 2022 00:45:34 -0500 Subject: [PATCH 203/861] prevent panic when handling an LSP response with no request (#2475) A language server may push a response which doesn't belong to any request. With this change, we discard the response rather than crashing. In the case of #2474, the language server sends an error message with a null request ID which should not ever exist in the `pending_requests` HashMap. closes #2474 --- helix-lsp/src/transport.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/helix-lsp/src/transport.rs b/helix-lsp/src/transport.rs index 6e28094d1..6102c6c8e 100644 --- a/helix-lsp/src/transport.rs +++ b/helix-lsp/src/transport.rs @@ -215,20 +215,21 @@ impl Transport { } }; - let tx = self - .pending_requests - .lock() - .await - .remove(&id) - .expect("pending_request with id not found!"); - - match tx.send(result).await { - Ok(_) => (), - Err(_) => error!( - "Tried sending response into a closed channel (id={:?}), original request likely timed out", - id - ), - }; + if let Some(tx) = self.pending_requests.lock().await.remove(&id) { + match tx.send(result).await { + Ok(_) => (), + Err(_) => error!( + "Tried sending response into a closed channel (id={:?}), original request likely timed out", + id + ), + }; + } else { + log::error!( + "Discarding Language Server response without a request (id={:?}) {:?}", + id, + result + ); + } Ok(()) } From 29121a18b52a6dcc7478a243a8db8f8447102f4d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 May 2022 14:45:43 +0900 Subject: [PATCH 204/861] build(deps): bump signal-hook from 0.3.13 to 0.3.14 (#2485) Bumps [signal-hook](https://github.com/vorner/signal-hook) from 0.3.13 to 0.3.14. - [Release notes](https://github.com/vorner/signal-hook/releases) - [Changelog](https://github.com/vorner/signal-hook/blob/master/CHANGELOG.md) - [Commits](https://github.com/vorner/signal-hook/compare/v0.3.13...v0.3.14) --- updated-dependencies: - dependency-name: signal-hook dependency-type: direct:production update-type: version-update:semver-patch ... 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 0879faa65..466f500ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -928,9 +928,9 @@ dependencies = [ [[package]] name = "signal-hook" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d" +checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" dependencies = [ "libc", "signal-hook-registry", From 8493b5fca68097efd258ff0ffbcb6863e0c362c9 Mon Sep 17 00:00:00 2001 From: midnightexigent <36641328+midnightexigent@users.noreply.github.com> Date: Wed, 18 May 2022 21:49:50 +0200 Subject: [PATCH 205/861] Add tree-sitter ssh client config queries (#2498) Co-authored-by: Michael Davis --- book/src/generated/lang-support.md | 1 + languages.toml | 10 + .../queries/sshclientconfig/highlights.scm | 324 ++++++++++++++++++ 3 files changed, 335 insertions(+) create mode 100644 runtime/queries/sshclientconfig/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 95cf91a43..f857fc0d4 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -78,6 +78,7 @@ | scala | ✓ | | ✓ | `metals` | | solidity | ✓ | | | `solc` | | sql | ✓ | | | | +| sshclientconfig | ✓ | | | | | svelte | ✓ | | ✓ | `svelteserver` | | swift | ✓ | | | `sourcekit-lsp` | | tablegen | ✓ | ✓ | ✓ | | diff --git a/languages.toml b/languages.toml index 46b607472..ed406a718 100644 --- a/languages.toml +++ b/languages.toml @@ -1355,3 +1355,13 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "meson" source = { git = "https://github.com/bearcove/tree-sitter-meson", rev = "feea83be9225842490066522ced2d13eb9cce0bd" } + +[[language]] +name = "sshclientconfig" +scope = "source.sshclientconfig" +file-types = [".ssh/config", "/etc/ssh/ssh_config"] +roots = [] + +[[grammar]] +name = "sshclientconfig" +source = { git = "https://github.com/metio/tree-sitter-ssh-client-config", rev = "769d7a01a2e5493b4bb5a51096c6bf4be130b024" } diff --git a/runtime/queries/sshclientconfig/highlights.scm b/runtime/queries/sshclientconfig/highlights.scm new file mode 100644 index 000000000..83a212a20 --- /dev/null +++ b/runtime/queries/sshclientconfig/highlights.scm @@ -0,0 +1,324 @@ +(host) @keyword +(host_value) @identifier + +(match) @keyword +(match_value) @identifier + +(add_keys_to_agent) @keyword +(add_keys_to_agent_value) @boolean + +(address_family) @keyword +(address_family_value) @type + +(batch_mode) @keyword +(batch_mode_value) @boolean + +(bind_address) @keyword +(bind_address_value) @string + +(bind_interface) @keyword +(bind_interface_value) @string + +(canonical_domains) @keyword +(canonical_domains_value) @identifier + +(canonicalize_fallback_local) @keyword +(canonicalize_fallback_local_value) @boolean + +(canonicalize_hostname) @keyword +(canonicalize_hostname_value) @boolean + +(canonicalize_max_dots) @keyword +(canonicalize_max_dots_value) @number + +(canonicalize_permitted_cnames) @keyword +(canonicalize_permitted_cnames_value) @identifier + +(ca_signature_algorithms) @keyword +(ca_signature_algorithms_value) @identifier + +(certificate_file) @keyword +(certificate_file_value) @file + +(challenge_response_authentication) @keyword +(challenge_response_authentication_value) @boolean + +(check_host_ip) @keyword +(check_host_ip_value) @boolean + +(cipher) @keyword +(cipher_value) @identifier + +(ciphers) @keyword +(ciphers_value) @identifier + +(clear_all_forwardings) @keyword +(clear_all_forwardings_value) @boolean + +(comment) @comment + +(compression) @keyword +(compression_value) @boolean + +(connect_timeout) @keyword +(connect_timeout_value) @number + +(connection_attempts) @keyword +(connection_attempts_value) @number + +(control_master) @keyword +(control_master_value) @type + +(control_path) @keyword +(control_path_value) @file + +(control_persist) @keyword +(control_persist_value) @type + +(dynamic_forward) @keyword +(dynamic_forward_value) @string + +(enable_ssh_keysign) @keyword +(enable_ssh_keysign_value) @boolean + +(escape_char) @keyword +(escape_char_value) @string + +(exit_on_forward_failure) @keyword +(exit_on_forward_failure_value) @boolean + +(fingerprint_hash) @keyword +(fingerprint_hash_value) @identifier + +(fork_after_authentication) @keyword +(fork_after_authentication_value) @boolean + +(forward_agent) @keyword +(forward_agent_value) @boolean + +(forward_x11) @keyword +(forward_x11_value) @boolean + +(forward_x11_timeout) @keyword +(forward_x11_timeout_value) @time + +(forward_x11_trusted) @keyword +(forward_x11_trusted_value) @boolean + +(gateway_ports) @keyword +(gateway_ports_value) @boolean + +(global_known_hosts_file) @keyword +(global_known_hosts_file_value) @file + +(gssapi_authentication) @keyword +(gssapi_authentication_value) @boolean + +(gssapi_client_identity) @keyword +(gssapi_client_identity_value) @string + +(gssapi_delegate_credentials) @keyword +(gssapi_delegate_credentials_value) @boolean + +(gssapi_kex_algorithms) @keyword +(gssapi_kex_algorithms_value) @identifier + +(gssapi_key_exchange) @keyword +(gssapi_key_exchange_value) @boolean + +(gssapi_renewal_forces_rekey) @keyword +(gssapi_renewal_forces_rekey_value) @boolean + +(gssapi_server_identity) @keyword +(gssapi_server_identity_value) @string + +(gssapi_trust_dns) @keyword +(gssapi_trust_dns_value) @boolean + +(hash_known_hosts) @keyword +(hash_known_hosts_value) @boolean + +(host_key_algorithms) @keyword +(host_key_algorithms_value) @identifier + +(host_key_alias) @keyword +(host_key_alias_value) @string + +(hostbased_accepted_algorithms) @keyword +(hostbased_accepted_algorithms_value) @identifier + +(hostbased_authentication) @keyword +(hostbased_authentication_value) @boolean + +(hostname) @keyword +(hostname_value) @string + +(identities_only) @keyword +(identities_only_value) @boolean + +(identity_agent) @keyword +(identity_agent_value) @string + +(identity_file) @keyword +(identity_file_value) @file + +(ignore_unknown) @keyword +(ignore_unknown_value) @string + +(include) @keyword +(include_value) @file + +(ip_qos) @keyword +(ip_qos_value) @type + +(kbd_interactive_authentication) @keyword +(kbd_interactive_authentication_value) @boolean + +(kbd_interactive_devices) @keyword +(kbd_interactive_devices_value) @type + +(kex_algorithms) @keyword +(kex_algorithms_value) @identifier + +(known_hosts_command) @keyword +(known_hosts_command_value) @string + +(local_command) @keyword +(local_command_value) @string + +(local_forward) @keyword +(local_forward_value) @string + +(log_level) @keyword +(log_level_value) @type + +(log_verbose) @keyword +(log_verbose_value) @string + +(macs) @keyword +(macs_value) @identifier + +(no_host_authentication_for_localhost) @keyword +(no_host_authentication_for_localhost_value) @boolean + +(number_of_password_prompts) @keyword +(number_of_password_prompts_value) @number + +(password_authentication) @keyword +(password_authentication_value) @boolean + +(permit_local_command) @keyword +(permit_local_command_value) @boolean + +(permit_remote_open) @keyword +(permit_remote_open_value) @string + +(pkcs11_provider) @keyword +(pkcs11_provider_value) @string + +(port) @keyword +(port_value) @number + +(preferred_authentications) @keyword +(preferred_authentications_value) @type + +(protocol) @keyword +(protocol_value) @number + +(proxy_command) @keyword +(proxy_command_value) @string + +(proxy_jump) @keyword +(proxy_jump_value) @string + +(proxy_use_fdpass) @keyword +(proxy_use_fdpass_value) @boolean + +(pubkey_accepted_algorithms) @keyword +(pubkey_accepted_algorithms_value) @identifier + +(pubkey_accepted_key_types) @keyword +(pubkey_accepted_key_types_value) @identifier + +(pubkey_authentication) @keyword +(pubkey_authentication_value) @boolean + +(rekey_limit) @keyword +(rekey_limit_value) @string + +(remote_command) @keyword +(remote_command_value) @string + +(remote_forward) @keyword +(remote_forward_value) @string + +(request_tty) @keyword +(request_tty_value) @type + +(revoked_host_keys) @keyword +(revoked_host_keys_value) @file + +(security_key_provider) @keyword +(security_key_provider_value) @string + +(send_env) @keyword +(send_env_value) @string + +(server_alive_count_max) @keyword +(server_alive_count_max_value) @number + +(server_alive_interval) @keyword +(server_alive_interval_value) @number + +(session_type) @keyword +(session_type_value) @type + +(set_env) @keyword +(set_env_value) @string + +(stdin_null) @keyword +(stdin_null_value) @boolean + +(stream_local_bind_mask) @keyword +(stream_local_bind_mask_value) @string + +(stream_local_bind_unlink) @keyword +(stream_local_bind_unlink_value) @boolean + +(strict_host_key_checking) @keyword +(strict_host_key_checking_value) @type + +(syslog_facility) @keyword +(syslog_facility_value) @type + +(tcp_keep_alive) @keyword +(tcp_keep_alive_value) @boolean +(keep_alive) @keyword +(keep_alive_value) @boolean + +(tunnel) @keyword +(tunnel_value) @type + +(tunnel_device) @keyword +(tunnel_device_value) @string + +(update_host_keys) @keyword +(update_host_keys_value) @type + +(use_keychain) @keyword +(use_keychain_value) @boolean + +(user) @keyword +(user_value) @string + +(user_known_hosts_file) @keyword +(user_known_hosts_file_value) @file + +(verify_host_key_dns) @keyword +(verify_host_key_dns_value) @type + +(visual_host_key) @keyword +(visual_host_key_value) @boolean + +(xauth_location) @keyword +(xauth_location_value) @file From 301ed9b48f3a331233a4d707a728e1a572702233 Mon Sep 17 00:00:00 2001 From: Alexis Kalabura <55039048+axdank@users.noreply.github.com> Date: Thu, 19 May 2022 21:18:19 -0400 Subject: [PATCH 206/861] deletion of lines affecting popup scrolling (#2497) --- helix-term/src/ui/popup.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/helix-term/src/ui/popup.rs b/helix-term/src/ui/popup.rs index 069a22f45..185ec15da 100644 --- a/helix-term/src/ui/popup.rs +++ b/helix-term/src/ui/popup.rs @@ -88,8 +88,6 @@ impl Popup { pub fn scroll(&mut self, offset: usize, direction: bool) { if direction { - self.scroll += offset; - let max_offset = self.child_size.1.saturating_sub(self.size.1); self.scroll = (self.scroll + offset).min(max_offset as usize); } else { From 62fd1f699988bdf7bba4a9ada511b5303b01d328 Mon Sep 17 00:00:00 2001 From: Andrey Tkachenko Date: Fri, 20 May 2022 05:19:46 +0400 Subject: [PATCH 207/861] Include macro attributes to impls, structs, enums, functions etc. textobjects (#2494) --- helix-core/src/syntax.rs | 52 ++++++++++++----------- runtime/queries/rust/textobjects.scm | 63 ++++++++++++++++++++++------ 2 files changed, 78 insertions(+), 37 deletions(-) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index b20d9092f..1cfa04e7c 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -234,6 +234,7 @@ pub struct TextObjectQuery { pub query: Query, } +#[derive(Debug)] pub enum CapturedNode<'a> { Single(Node<'a>), /// Guaranteed to be not empty @@ -268,12 +269,12 @@ impl TextObjectQuery { /// and support for this is partial and could use improvement. /// /// ```query - /// ;; supported: /// (comment)+ @capture /// - /// ;; unsupported: + /// ; OR /// ( - /// (comment)+ + /// (comment)* + /// . /// (function) /// ) @capture /// ``` @@ -299,28 +300,29 @@ impl TextObjectQuery { let capture_idx = capture_names .iter() .find_map(|cap| self.query.capture_index_for_name(cap))?; - let captures = cursor.matches(&self.query, node, RopeProvider(slice)); - - let nodes = captures.flat_map(move |mat| { - let captures = mat.captures.iter().filter(move |c| c.index == capture_idx); - let nodes = captures.map(|c| c.node); - let pattern_idx = mat.pattern_index; - let quantifier = self.query.capture_quantifiers(pattern_idx)[capture_idx as usize]; - - let iter: Box> = match quantifier { - CaptureQuantifier::OneOrMore | CaptureQuantifier::ZeroOrMore => { - let nodes: Vec = nodes.collect(); - if nodes.is_empty() { - Box::new(std::iter::empty()) - } else { - Box::new(std::iter::once(CapturedNode::Grouped(nodes))) - } + + let nodes = cursor + .captures(&self.query, node, RopeProvider(slice)) + .filter_map(move |(mat, _)| { + let nodes: Vec<_> = mat + .captures + .iter() + .filter_map(|x| { + if x.index == capture_idx { + Some(x.node) + } else { + None + } + }) + .collect(); + + if nodes.len() > 1 { + Some(CapturedNode::Grouped(nodes)) + } else { + nodes.into_iter().map(CapturedNode::Single).next() } - _ => Box::new(nodes.map(CapturedNode::Single)), - }; + }); - iter - }); Some(nodes) } } @@ -1122,8 +1124,8 @@ pub(crate) fn generate_edits( use std::sync::atomic::{AtomicUsize, Ordering}; use std::{iter, mem, ops, str, usize}; use tree_sitter::{ - CaptureQuantifier, Language as Grammar, Node, Parser, Point, Query, QueryCaptures, QueryCursor, - QueryError, QueryMatch, Range, TextProvider, Tree, + Language as Grammar, Node, Parser, Point, Query, QueryCaptures, QueryCursor, QueryError, + QueryMatch, Range, TextProvider, Tree, }; const CANCELLATION_CHECK_INTERVAL: usize = 100; diff --git a/runtime/queries/rust/textobjects.scm b/runtime/queries/rust/textobjects.scm index 086db67ae..99b5eb4d9 100644 --- a/runtime/queries/rust/textobjects.scm +++ b/runtime/queries/rust/textobjects.scm @@ -1,23 +1,62 @@ -(function_item - body: (_) @function.inside) @function.around +( + [ + (attribute_item)+ + (line_comment)+ + ]* + . + (function_item + body: (_) @function.inside)) @function.around -(struct_item - body: (_) @class.inside) @class.around +( + [ + (attribute_item)+ + (line_comment)+ + ]* + . + (struct_item + body: (_) @class.inside)) @class.around -(enum_item - body: (_) @class.inside) @class.around +( + [ + (attribute_item)+ + (line_comment)+ + ]* + . + (enum_item + body: (_) @class.inside)) @class.around -(union_item - body: (_) @class.inside) @class.around +( + [ + (attribute_item)+ + (line_comment)+ + ]* + . + (union_item + body: (_) @class.inside)) @class.around -(trait_item - body: (_) @class.inside) @class.around +( + [ + (attribute_item)+ + (line_comment)+ + ]* + . + (trait_item + body: (_) @class.inside)) @class.around -(impl_item - body: (_) @class.inside) @class.around +( + [ + (attribute_item)+ + (line_comment)+ + ]* + . + (impl_item + body: (_) @class.inside)) @class.around (parameters (_) @parameter.inside) + +(type_parameters + (_) @parameter.inside) (closure_parameters (_) @parameter.inside) From 8958bf0a926a6e6afc63f0c59f3fa6761f5da709 Mon Sep 17 00:00:00 2001 From: Roland Kovacs Date: Fri, 20 May 2022 03:25:04 +0200 Subject: [PATCH 208/861] Implement view transpose (#2461) Change the layout of existing split view from horizontal to vertical and vica-versa. It only effects the focused view and its siblings, i.e. not recursive. Command is mapped to 't' or 'C-t' under the Window menus. --- helix-term/src/commands.rs | 5 +++++ helix-term/src/keymap/default.rs | 2 ++ helix-view/src/editor.rs | 4 ++++ helix-view/src/tree.rs | 12 ++++++++++++ 4 files changed, 23 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index f0b54e0b7..855f2d7dc 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -360,6 +360,7 @@ impl MappableCommand { jump_view_left, "Jump to the split to the left", jump_view_up, "Jump to the split above", jump_view_down, "Jump to the split below", + transpose_view, "Transpose splits", rotate_view, "Goto next window", hsplit, "Horizontal bottom split", hsplit_new, "Horizontal bottom split scratch buffer", @@ -3863,6 +3864,10 @@ fn jump_view_down(cx: &mut Context) { cx.editor.focus_down() } +fn transpose_view(cx: &mut Context) { + cx.editor.transpose_view() +} + // split helper, clear it later fn split(cx: &mut Context, action: Action) { let (view, doc) = current!(cx.editor); diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index a8ff8be91..124517d4a 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -171,6 +171,7 @@ pub fn default() -> HashMap { "C-w" | "w" => rotate_view, "C-s" | "s" => hsplit, "C-v" | "v" => vsplit, + "C-t" | "t" => transpose_view, "f" => goto_file_hsplit, "F" => goto_file_vsplit, "C-q" | "q" => wclose, @@ -226,6 +227,7 @@ pub fn default() -> HashMap { "C-w" | "w" => rotate_view, "C-s" | "s" => hsplit, "C-v" | "v" => vsplit, + "C-t" | "t" => transpose_view, "f" => goto_file_hsplit, "F" => goto_file_vsplit, "C-q" | "q" => wclose, diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index f4a48ba65..1ad210592 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -885,6 +885,10 @@ impl Editor { self.tree.focus_direction(tree::Direction::Down); } + pub fn transpose_view(&mut self) { + self.tree.transpose(); + } + pub fn should_close(&self) -> bool { self.tree.is_empty() } diff --git a/helix-view/src/tree.rs b/helix-view/src/tree.rs index b068f4c7e..522a79d78 100644 --- a/helix-view/src/tree.rs +++ b/helix-view/src/tree.rs @@ -526,6 +526,18 @@ impl Tree { } } + pub fn transpose(&mut self) { + let focus = self.focus; + let parent = self.nodes[focus].parent; + if let Content::Container(container) = &mut self.nodes[parent].content { + container.layout = match container.layout { + Layout::Vertical => Layout::Horizontal, + Layout::Horizontal => Layout::Vertical, + }; + self.recalculate(); + } + } + pub fn area(&self) -> Rect { self.area } From 6462542fc50078e41074b70d0e70d52f351959fa Mon Sep 17 00:00:00 2001 From: Bob Date: Fri, 20 May 2022 09:27:59 +0800 Subject: [PATCH 209/861] support insert register in prompt (#2458) * support insert register in prompt * use next_char_handler instead of a flag * Fix clippy issue * show autoinfo when inserting register * Revert "show autoinfo when inserting register" This reverts commit 5488344de1c607d44bdf8693287a85b92cb32518. * use completion instead of autoinfo autoinfo is overlapped when using prompt * recalculate_completion after inserting register * Update helix-term/src/ui/prompt.rs Co-authored-by: Ivan Tham Co-authored-by: Ivan Tham --- book/src/keymap.md | 1 + helix-term/src/ui/prompt.rs | 39 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/book/src/keymap.md b/book/src/keymap.md index 9d5d08417..e56eeefc4 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -367,6 +367,7 @@ Keys to use within prompt, Remapping currently not supported. | `Ctrl-s` | Insert a word under doc cursor, may be changed to Ctrl-r Ctrl-w later | | `Ctrl-p`, `Up` | Select previous history | | `Ctrl-n`, `Down` | Select next history | +| `Ctrl-r` | Insert the content of the register selected by following input char | | `Tab` | Select next completion item | | `BackTab` | Select previous completion item | | `Enter` | Open selected | diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index ef08edf2d..c3c502e0d 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -16,6 +16,7 @@ use helix_view::{ }; pub type Completion = (RangeFrom, Cow<'static, str>); +type PromptCharHandler = Box; pub struct Prompt { prompt: Cow<'static, str>, @@ -28,6 +29,7 @@ pub struct Prompt { completion_fn: Box Vec>, callback_fn: Box, pub doc_fn: Box Option>>, + next_char_handler: Option, } #[derive(Clone, Copy, PartialEq)] @@ -78,6 +80,7 @@ impl Prompt { completion_fn: Box::new(completion_fn), callback_fn: Box::new(callback_fn), doc_fn: Box::new(|_| None), + next_char_handler: None, } } @@ -191,6 +194,13 @@ impl Prompt { } pub fn insert_char(&mut self, c: char, cx: &Context) { + if let Some(handler) = &self.next_char_handler.take() { + handler(self, c, cx); + + self.next_char_handler = None; + return; + } + self.line.insert(self.cursor, c); let mut cursor = GraphemeCursor::new(self.cursor, self.line.len(), false); if let Ok(Some(pos)) = cursor.next_boundary(&self.line, 0) { @@ -538,6 +548,35 @@ impl Component for Prompt { (self.callback_fn)(cx, &self.line, PromptEvent::Update) } ctrl!('q') => self.exit_selection(), + ctrl!('r') => { + self.completion = cx + .editor + .registers + .inner() + .iter() + .map(|(ch, reg)| { + let content = reg + .read() + .get(0) + .and_then(|s| s.lines().next().to_owned()) + .unwrap_or_default(); + (0.., format!("{} {}", ch, &content).into()) + }) + .collect(); + self.next_char_handler = Some(Box::new(|prompt, c, context| { + prompt.insert_str( + context + .editor + .registers + .read(c) + .and_then(|r| r.first()) + .map_or("", |r| r.as_str()), + ); + prompt.recalculate_completion(context.editor); + })); + (self.callback_fn)(cx, &self.line, PromptEvent::Update); + return EventResult::Consumed(None); + } // any char event that's not mapped to any other combo KeyEvent { code: KeyCode::Char(c), From a6da99a14483c2c18c8fa83c5291b2ae866bbbca Mon Sep 17 00:00:00 2001 From: Zeddicus414 <31261142+Zeddicus414@users.noreply.github.com> Date: Mon, 9 May 2022 22:50:00 -0500 Subject: [PATCH 210/861] Change python highlights.scm to more fully utilize the themes. Create type keywords Allow _CONSTANTS to start with _ Highlight constants before constructors Move some keywords into @keyword.control --- runtime/queries/python/highlights.scm | 51 +++++++++++++++++---------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/runtime/queries/python/highlights.scm b/runtime/queries/python/highlights.scm index 9131acc5b..88d9755ca 100644 --- a/runtime/queries/python/highlights.scm +++ b/runtime/queries/python/highlights.scm @@ -1,10 +1,19 @@ ; Identifier naming conventions +((identifier) @constant + (#match? @constant "^[A-Z_]*$")) + ((identifier) @constructor (#match? @constructor "^[A-Z]")) -((identifier) @constant - (#match? @constant "^[A-Z][A-Z_]*$")) +; Types + +((identifier) @type + (#match? + @type + "^(bool|bytes|dict|float|frozenset|int|list|set|str|tuple)$")) + +(type (identifier)) @type ; Builtin functions @@ -12,7 +21,7 @@ function: (identifier) @function.builtin) (#match? @function.builtin - "^(abs|all|any|ascii|bin|bool|breakpoint|bytearray|bytes|callable|chr|classmethod|compile|complex|delattr|dict|dir|divmod|enumerate|eval|exec|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|isinstance|issubclass|iter|len|list|locals|map|max|memoryview|min|next|object|oct|open|ord|pow|print|property|range|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|vars|zip|__import__)$")) + "^(abs|all|any|ascii|bin|breakpoint|bytearray|callable|chr|classmethod|compile|complex|delattr|dir|divmod|enumerate|eval|exec|filter|format|getattr|globals|hasattr|hash|help|hex|id|input|isinstance|issubclass|iter|len|locals|map|max|memoryview|min|next|object|oct|open|ord|pow|print|property|range|repr|reversed|round|setattr|slice|sorted|staticmethod|sum|super|type|vars|zip|__import__)$")) ; Function calls @@ -30,7 +39,6 @@ (identifier) @variable (attribute attribute: (identifier) @variable.other.member) -(type (identifier) @type) ; Literals @@ -81,41 +89,48 @@ ">>" "|" "~" - "and" - "in" - "is" - "not" - "or" ] @operator [ "as" "assert" - "async" "await" "break" - "class" "continue" - "def" - "del" "elif" "else" "except" - "exec" "finally" "for" "from" - "global" "if" "import" - "lambda" - "nonlocal" "pass" - "print" "raise" "return" "try" "while" "with" "yield" +] @keyword.control + +(for_statement "in" @keyword.control) +(for_in_clause "in" @keyword.control) + +[ + "and" + "async" + "class" + "def" + "del" + "exec" + "global" + "in" + "is" + "lambda" + "nonlocal" + "not" + "or" + "print" ] @keyword + From 8e8d4ba27f7610f228595e84e7c201c29ffa447c Mon Sep 17 00:00:00 2001 From: Zeddicus414 <31261142+Zeddicus414@users.noreply.github.com> Date: Mon, 9 May 2022 22:50:31 -0500 Subject: [PATCH 211/861] dark_plus theme constructor should be green. --- runtime/themes/dark_plus.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/dark_plus.toml b/runtime/themes/dark_plus.toml index 6c9d59194..c785dd388 100644 --- a/runtime/themes/dark_plus.toml +++ b/runtime/themes/dark_plus.toml @@ -6,7 +6,7 @@ "type" = { fg = "type" } "type.builtin" = { fg = "type" } "type.enum.variant" = { fg = "constant" } -"constructor" = { fg = "constant" } +"constructor" = { fg = "type" } "variable.other.member" = { fg = "variable" } "keyword" = { fg = "blue2" } From abef250c58620fb0a439b13b9f857a5b661e325f Mon Sep 17 00:00:00 2001 From: Paul Scott Date: Fri, 13 May 2022 16:21:38 +1000 Subject: [PATCH 212/861] Python highlight improvements: type, parameter etc * str, list, etc. handled as @function.builtin and @type.builtin * None and non-conforming type indentifiers as @type in type hints * class identifiers treated as @type * @constructor used for constructor definitions and calls rather than as a catch-all for type-like things * Parameters highlighted * self and cls as @variable.builtin * improved decorator highlighting as part of @function Re-ordering of some statements to give more accurate priority. --- runtime/queries/python/highlights.scm | 74 +++++++++++++++++++-------- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/runtime/queries/python/highlights.scm b/runtime/queries/python/highlights.scm index 88d9755ca..fa622435a 100644 --- a/runtime/queries/python/highlights.scm +++ b/runtime/queries/python/highlights.scm @@ -1,44 +1,78 @@ -; Identifier naming conventions - -((identifier) @constant - (#match? @constant "^[A-Z_]*$")) - -((identifier) @constructor - (#match? @constructor "^[A-Z]")) - -; Types - -((identifier) @type - (#match? - @type - "^(bool|bytes|dict|float|frozenset|int|list|set|str|tuple)$")) - -(type (identifier)) @type - ; Builtin functions ((call function: (identifier) @function.builtin) (#match? @function.builtin - "^(abs|all|any|ascii|bin|breakpoint|bytearray|callable|chr|classmethod|compile|complex|delattr|dir|divmod|enumerate|eval|exec|filter|format|getattr|globals|hasattr|hash|help|hex|id|input|isinstance|issubclass|iter|len|locals|map|max|memoryview|min|next|object|oct|open|ord|pow|print|property|range|repr|reversed|round|setattr|slice|sorted|staticmethod|sum|super|type|vars|zip|__import__)$")) + "^(abs|all|any|ascii|bin|bool|breakpoint|bytearray|bytes|callable|chr|classmethod|compile|complex|delattr|dict|dir|divmod|enumerate|eval|exec|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|isinstance|issubclass|iter|len|list|locals|map|max|memoryview|min|next|object|oct|open|ord|pow|print|property|range|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|vars|zip|__import__)$")) ; Function calls -(decorator) @function +(call + function: (attribute attribute: (identifier) @constructor) + (#match? @constructor "^[A-Z]")) +(call + function: (identifier) @constructor + (#match? @constructor "^[A-Z]")) (call function: (attribute attribute: (identifier) @function.method)) + (call function: (identifier) @function) ; Function definitions +(function_definition + name: (identifier) @constructor + (#match? @constructor "^(__new__|__init__)$")) + (function_definition name: (identifier) @function) -(identifier) @variable +; Decorators + +(decorator) @function +(decorator (identifier) @function) + +; Parameters + +((identifier) @variable.builtin + (#match? @variable.builtin "^(self|cls)$")) + +(parameters (identifier) @variable.parameter) +(parameters (typed_parameter (identifier) @variable.parameter)) + +; Types + +((identifier) @type.builtin + (#match? + @type.builtin + "^(bool|bytes|dict|float|frozenset|int|list|set|str|tuple)$")) + +; In type hints make everything types to catch non-conforming identifiers +; (e.g., datetime.datetime) and None +(type [(identifier) (none)] @type) +; Handle [] . and | nesting 4 levels deep +(type + (_ [(identifier) (none)]? @type + (_ [(identifier) (none)]? @type + (_ [(identifier) (none)]? @type + (_ [(identifier) (none)]? @type))))) + +(class_definition name: (identifier) @type) +(class_definition superclasses: (argument_list (identifier) @type)) + +; Variables + +((identifier) @constant + (#match? @constant "^[A-Z_]{2,}$")) + +((identifier) @type + (#match? @type "^[A-Z]")) + (attribute attribute: (identifier) @variable.other.member) +(identifier) @variable ; Literals From e680f9644d485bcb5b9518515739f682d5a683f6 Mon Sep 17 00:00:00 2001 From: Paul Scott Date: Sat, 14 May 2022 12:39:36 +1000 Subject: [PATCH 213/861] Python handling highlighting parameters with defaults --- runtime/queries/python/highlights.scm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/queries/python/highlights.scm b/runtime/queries/python/highlights.scm index fa622435a..75e76c685 100644 --- a/runtime/queries/python/highlights.scm +++ b/runtime/queries/python/highlights.scm @@ -42,6 +42,8 @@ (parameters (identifier) @variable.parameter) (parameters (typed_parameter (identifier) @variable.parameter)) +(parameters (default_parameter name: (identifier) @variable.parameter)) +(parameters (typed_default_parameter name: (identifier) @variable.parameter)) ; Types From 2a2030142f1d5cb8a130b0541399860d0e0cae15 Mon Sep 17 00:00:00 2001 From: Paul Scott Date: Sat, 14 May 2022 12:50:08 +1000 Subject: [PATCH 214/861] Python highlight keyword argument as parameter --- runtime/queries/python/highlights.scm | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/queries/python/highlights.scm b/runtime/queries/python/highlights.scm index 75e76c685..352940727 100644 --- a/runtime/queries/python/highlights.scm +++ b/runtime/queries/python/highlights.scm @@ -44,6 +44,7 @@ (parameters (typed_parameter (identifier) @variable.parameter)) (parameters (default_parameter name: (identifier) @variable.parameter)) (parameters (typed_default_parameter name: (identifier) @variable.parameter)) +(keyword_argument name: (identifier) @variable.parameter) ; Types From 09f9f70576830c328af37b73f96286d80ecf20f9 Mon Sep 17 00:00:00 2001 From: Paul Scott Date: Sun, 15 May 2022 00:03:53 +1000 Subject: [PATCH 215/861] Python highlight decorator attribute --- runtime/queries/python/highlights.scm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/queries/python/highlights.scm b/runtime/queries/python/highlights.scm index 352940727..93e08d584 100644 --- a/runtime/queries/python/highlights.scm +++ b/runtime/queries/python/highlights.scm @@ -34,6 +34,9 @@ (decorator) @function (decorator (identifier) @function) +(decorator (attribute attribute: (identifier) @function)) +(decorator (call + function: (attribute attribute: (identifier) @function))) ; Parameters From 776686ab2471419b9c9aac8507e8d301f450389a Mon Sep 17 00:00:00 2001 From: Robert Walter <26892280+RobWalt@users.noreply.github.com> Date: Fri, 20 May 2022 03:30:28 +0200 Subject: [PATCH 216/861] Separate colors for different diagnostics types (#2437) * feat(theme): add separate diagnostic colors This commit adds separate diagnostic highlight colors for the different types of LSP severities. If the severity type doesn't exist or is unknown, we use some fallback coloring which was in use before this commit. Some initial color options were also added in the theme.toml Resolves issue #2157 * feat(theme): add docs for new diagnostic options * feat(theme): adjust defaults & reduce redundancy - the different colors for different diagnostic severities are now disabled in the default theme, instead diagnostics are just generally underlined (as prior to the changes of this feature) - the theme querying is now done once instead of every iteration in the loop of processing every diagnostic message --- book/src/themes.md | 6 +++++- helix-term/src/ui/editor.rs | 25 ++++++++++++++++++++++--- theme.toml | 4 ++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/book/src/themes.md b/book/src/themes.md index e73aedc94..97955cb71 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -234,6 +234,10 @@ These scopes are used for theming the editor interface. | `error` | Diagnostics error (gutter) | | `info` | Diagnostics info (gutter) | | `hint` | Diagnostics hint (gutter) | -| `diagnostic` | For text in editing area | +| `diagnostic` | Diagnostics fallback style (editing area) | +| `diagnostic.hint` | Diagnostics hint (editing area) | +| `diagnostic.info` | Diagnostics info (editing area) | +| `diagnostic.warning` | Diagnostics warning (editing area) | +| `diagnostic.error` | Diagnostics error (editing area) | [rulers-config]: ./configuration.md#editor-section diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 52e581632..85028e2ff 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -247,17 +247,36 @@ impl EditorView { doc: &Document, theme: &Theme, ) -> Vec<(usize, std::ops::Range)> { - let diagnostic_scope = theme - .find_scope_index("diagnostic") + use helix_core::diagnostic::Severity; + let get_scope_of = |scope| { + theme + .find_scope_index(scope) + // get one of the themes below as fallback values + .or_else(|| theme.find_scope_index("diagnostic")) .or_else(|| theme.find_scope_index("ui.cursor")) .or_else(|| theme.find_scope_index("ui.selection")) .expect( "at least one of the following scopes must be defined in the theme: `diagnostic`, `ui.cursor`, or `ui.selection`", - ); + ) + }; + + // basically just queries the theme color defined in the config + let hint = get_scope_of("diagnostic.hint"); + let info = get_scope_of("diagnostic.info"); + let warning = get_scope_of("diagnostic.warning"); + let error = get_scope_of("diagnostic.error"); + let r#default = get_scope_of("diagnostic"); // this is a bit redundant but should be fine doc.diagnostics() .iter() .map(|diagnostic| { + let diagnostic_scope = match diagnostic.severity { + Some(Severity::Info) => info, + Some(Severity::Hint) => hint, + Some(Severity::Warning) => warning, + Some(Severity::Error) => error, + _ => r#default, + }; ( diagnostic_scope, diagnostic.range.start..diagnostic.range.end, diff --git a/theme.toml b/theme.toml index 31ecd32e4..2e6da866d 100644 --- a/theme.toml +++ b/theme.toml @@ -67,6 +67,10 @@ label = "honey" "ui.menu.selected" = { fg = "revolver", bg = "white" } diagnostic = { modifiers = ["underlined"] } +# "diagnostic.hint" = { fg = "revolver", bg = "lilac" } +# "diagnostic.info" = { fg = "revolver", bg = "lavender" } +# "diagnostic.warning" = { fg = "revolver", bg = "honey" } +# "diagnostic.error" = { fg = "revolver", bg = "apricot" } warning = "lightning" error = "apricot" From 82fb217b6a99548065899b8405198eb08442803a Mon Sep 17 00:00:00 2001 From: Christoph Horn Date: Wed, 4 May 2022 11:13:13 +0200 Subject: [PATCH 217/861] use ui.menu instead of ui.statusline for command completion menu theme --- helix-term/src/ui/prompt.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index c3c502e0d..a5be33ffe 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -340,7 +340,7 @@ impl Prompt { pub fn render_prompt(&self, area: Rect, surface: &mut Surface, cx: &mut Context) { let theme = &cx.editor.theme; let prompt_color = theme.get("ui.text"); - let completion_color = theme.get("ui.statusline"); + let completion_color = theme.get("ui.menu"); let selected_color = theme.get("ui.menu.selected"); // completion @@ -368,7 +368,7 @@ impl Prompt { if !self.completion.is_empty() { let area = completion_area; - let background = theme.get("ui.statusline"); + let background = theme.get("ui.menu"); let items = height as usize * cols as usize; From e7e13dcf0681999fcc601aab54c45ddf9b3f22d3 Mon Sep 17 00:00:00 2001 From: Christoph Horn Date: Thu, 5 May 2022 09:55:37 +0200 Subject: [PATCH 218/861] add `ui.menu` to default theme --- theme.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/theme.toml b/theme.toml index 2e6da866d..55e859c82 100644 --- a/theme.toml +++ b/theme.toml @@ -64,6 +64,7 @@ label = "honey" "ui.cursor" = { modifiers = ["reversed"] } "ui.highlight" = { bg = "bossanova" } +"ui.menu" = { fg = "lilac", bg = "revolver" } "ui.menu.selected" = { fg = "revolver", bg = "white" } diagnostic = { modifiers = ["underlined"] } From 9be810fd01f495c795ab5e5b7240a32708d19f5c Mon Sep 17 00:00:00 2001 From: Christoph Horn Date: Fri, 6 May 2022 14:07:22 +0200 Subject: [PATCH 219/861] add missing `ui.menu` to themes, fix issues with some themes --- runtime/themes/bogster.toml | 4 +++- runtime/themes/ingrid.toml | 1 + runtime/themes/monokai.toml | 6 ++++-- runtime/themes/monokai_pro.toml | 1 + runtime/themes/monokai_pro_machine.toml | 1 + runtime/themes/monokai_pro_octagon.toml | 1 + runtime/themes/monokai_pro_ristretto.toml | 1 + runtime/themes/monokai_pro_spectrum.toml | 1 + runtime/themes/nord.toml | 1 + runtime/themes/onedark.toml | 1 + runtime/themes/onelight.toml | 3 ++- theme.toml | 2 +- 12 files changed, 18 insertions(+), 5 deletions(-) diff --git a/runtime/themes/bogster.toml b/runtime/themes/bogster.toml index af952071b..df3a7f315 100644 --- a/runtime/themes/bogster.toml +++ b/runtime/themes/bogster.toml @@ -59,7 +59,9 @@ # "ui.cursor.match" # TODO might want to override this because dimmed is not widely supported "ui.cursor.match" = { fg = "#313f4e", bg = "#dc7759" } "ui.cursor" = { fg = "#ABB2BF", modifiers = ["reversed"] } -"ui.menu.selected" = { fg = "#e5ded6", bg = "#313f4e" } + +"ui.menu" = { fg = "#e5ded6bg", bg = "#232d38" } +"ui.menu.selected" = { bg = "#313f4e" } "warning" = "#dc7759" "error" = "#dc597f" diff --git a/runtime/themes/ingrid.toml b/runtime/themes/ingrid.toml index da8730cc1..79b749b14 100644 --- a/runtime/themes/ingrid.toml +++ b/runtime/themes/ingrid.toml @@ -57,6 +57,7 @@ "ui.selection" = { bg = "#540099" } # "ui.cursor.match" # TODO might want to override this because dimmed is not widely supported +"ui.menu" = { fg = "#7B91B3", bg = "#F3EAE9" } "ui.menu.selected" = { fg = "#D74E50", bg = "#F3EAE9" } "warning" = "#D4A520" diff --git a/runtime/themes/monokai.toml b/runtime/themes/monokai.toml index a71482728..3fb1fadc3 100644 --- a/runtime/themes/monokai.toml +++ b/runtime/themes/monokai.toml @@ -59,7 +59,8 @@ "ui.window" = { bg = "widget" } "ui.popup" = { bg = "widget" } "ui.help" = { bg = "widget" } -"ui.menu.selected" = { bg = "widget" } +"ui.menu" = { bg = "widget" } +"ui.menu.selected" = { bg = "#414339" } "ui.cursor" = { fg = "cursor", modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "cursor", modifiers = ["reversed"] } @@ -71,7 +72,7 @@ "ui.linenr" = { fg = "#90908a" } "ui.linenr.selected" = { fg = "#c2c2bf" } -"ui.statusline" = { fg = "active_text", bg = "#75715e" } +"ui.statusline" = { fg = "active_text", bg = "#414339" } "ui.statusline.inactive" = { fg = "active_text", bg = "#75715e" } "ui.text" = { fg = "text", bg = "background" } @@ -98,3 +99,4 @@ active_text = "#ffffff" cursor = "#a6a6a6" inactive_cursor = "#878b91" widget = "#1e1f1c" +selection = "#414339" diff --git a/runtime/themes/monokai_pro.toml b/runtime/themes/monokai_pro.toml index b28f700cd..5580a33c6 100644 --- a/runtime/themes/monokai_pro.toml +++ b/runtime/themes/monokai_pro.toml @@ -4,6 +4,7 @@ "ui.linenr.selected" = { bg = "base3" } "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } +"ui.menu" = { fg = "base8", bg = "base3" } "ui.menu.selected" = { fg = "base2", bg = "yellow" } "ui.virtual" = "base5" diff --git a/runtime/themes/monokai_pro_machine.toml b/runtime/themes/monokai_pro_machine.toml index 4a2e53e42..abbe5bdca 100644 --- a/runtime/themes/monokai_pro_machine.toml +++ b/runtime/themes/monokai_pro_machine.toml @@ -4,6 +4,7 @@ "ui.linenr.selected" = { bg = "base3" } "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } +"ui.menu" = { fg = "base8", bg = "base3" } "ui.menu.selected" = { fg = "base2", bg = "yellow" } "ui.virtual" = "base5" diff --git a/runtime/themes/monokai_pro_octagon.toml b/runtime/themes/monokai_pro_octagon.toml index 48709145e..b249cfe21 100644 --- a/runtime/themes/monokai_pro_octagon.toml +++ b/runtime/themes/monokai_pro_octagon.toml @@ -4,6 +4,7 @@ "ui.linenr.selected" = { bg = "base3" } "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } +"ui.menu" = { fg = "base8", bg = "base3" } "ui.menu.selected" = { fg = "base2", bg = "yellow" } "ui.virtual" = "base5" diff --git a/runtime/themes/monokai_pro_ristretto.toml b/runtime/themes/monokai_pro_ristretto.toml index f7c370949..cd4cbd8e9 100644 --- a/runtime/themes/monokai_pro_ristretto.toml +++ b/runtime/themes/monokai_pro_ristretto.toml @@ -4,6 +4,7 @@ "ui.linenr.selected" = { bg = "base3" } "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } +"ui.menu" = { fg = "base8", bg = "base3" } "ui.menu.selected" = { fg = "base2", bg = "yellow" } "ui.virtual" = "base5" diff --git a/runtime/themes/monokai_pro_spectrum.toml b/runtime/themes/monokai_pro_spectrum.toml index 80e2a88d4..4160a15e1 100644 --- a/runtime/themes/monokai_pro_spectrum.toml +++ b/runtime/themes/monokai_pro_spectrum.toml @@ -4,6 +4,7 @@ "ui.linenr.selected" = { bg = "base3" } "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } +"ui.menu" = { fg = "base8", bg = "base3" } "ui.menu.selected" = { fg = "base2", bg = "yellow" } "ui.virtual" = "base5" diff --git a/runtime/themes/nord.toml b/runtime/themes/nord.toml index a6384d1b3..a61c17157 100644 --- a/runtime/themes/nord.toml +++ b/runtime/themes/nord.toml @@ -2,6 +2,7 @@ "ui.linenr.selected" = { fg = "nord4" } "ui.text.focus" = { fg = "nord8", modifiers= ["bold"] } +"ui.menu" = { fg = "nord6", bg = "#232d38" } "ui.menu.selected" = { fg = "nord8", bg = "nord2" } "ui.virtual" = "gray" diff --git a/runtime/themes/onedark.toml b/runtime/themes/onedark.toml index 573a635d7..280f6914d 100644 --- a/runtime/themes/onedark.toml +++ b/runtime/themes/onedark.toml @@ -69,6 +69,7 @@ diagnostic = { modifiers = ["underlined"] } "ui.help" = { bg = "gray" } "ui.popup" = { bg = "gray" } "ui.window" = { bg = "gray" } +"ui.menu" = { fg = "white", bg = "gray" } "ui.menu.selected" = { fg = "black", bg = "blue" } [palette] diff --git a/runtime/themes/onelight.toml b/runtime/themes/onelight.toml index 3674e821e..c89e20f93 100644 --- a/runtime/themes/onelight.toml +++ b/runtime/themes/onelight.toml @@ -92,9 +92,10 @@ "ui.text" = { fg = "black" } "ui.text.focus" = { fg = "red", bg = "light-white", modifiers = ["bold"] } -"ui.help" = { bg = "light-white" } +"ui.help" = { fg = "black", bg = "light-white" } "ui.popup" = { bg = "light-white" } "ui.window" = { bg = "light-white" } +"ui.menu" = { fg = "black", bg = "light-white" } "ui.menu.selected" = { fg = "white", bg = "light-blue" } [palette] diff --git a/theme.toml b/theme.toml index 55e859c82..a0186e92a 100644 --- a/theme.toml +++ b/theme.toml @@ -64,7 +64,7 @@ label = "honey" "ui.cursor" = { modifiers = ["reversed"] } "ui.highlight" = { bg = "bossanova" } -"ui.menu" = { fg = "lilac", bg = "revolver" } +"ui.menu" = { fg = "lavender", bg = "revolver" } "ui.menu.selected" = { fg = "revolver", bg = "white" } diagnostic = { modifiers = ["underlined"] } From e04bb8b8915bfe1df1a5ee7a8750f2589f2aae06 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Thu, 19 May 2022 22:16:11 -0500 Subject: [PATCH 220/861] address rust 1.61.0 clippy lints (#2514) --- helix-term/src/commands.rs | 4 ++-- helix-term/src/ui/picker.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 855f2d7dc..c3c7d224e 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1225,11 +1225,11 @@ fn replace(cx: &mut Context) { // need to wait for next key cx.on_next_key(move |cx, event| { let (view, doc) = current!(cx.editor); - let ch = match event { + let ch: Option<&str> = match event { KeyEvent { code: KeyCode::Char(ch), .. - } => Some(&ch.encode_utf8(&mut buf[..])[..]), + } => Some(ch.encode_utf8(&mut buf[..])), KeyEvent { code: KeyCode::Enter, .. diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 3ca6965cf..49d91be61 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -366,6 +366,7 @@ impl Picker { ); } else if pattern.starts_with(&self.previous_pattern) { // TODO: remove when retain_mut is in stable rust + #[allow(unused_imports)] use retain_mut::RetainMut; // optimization: if the pattern is a more specific version of the previous one From e8e252648f0287ccd503c59ea2c1fd7a155dafb5 Mon Sep 17 00:00:00 2001 From: Jacob Thompson Date: Fri, 20 May 2022 00:17:46 -0600 Subject: [PATCH 221/861] Added a default lsp server for Java in languages.toml (#2511) * Added a default lsp server for Java in languages.toml * Added a default lsp server for Java in languages.toml cont. Co-authored-by: Jacob Thompson --- book/src/generated/lang-support.md | 2 +- languages.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index f857fc0d4..2e670807c 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -38,7 +38,7 @@ | heex | ✓ | | | | | html | ✓ | | | `vscode-html-language-server` | | iex | ✓ | | | | -| java | ✓ | | | | +| java | ✓ | | | `jdtls` | | javascript | ✓ | | ✓ | `typescript-language-server` | | json | ✓ | | ✓ | `vscode-json-language-server` | | jsx | ✓ | | ✓ | `typescript-language-server` | diff --git a/languages.toml b/languages.toml index ed406a718..5deed3576 100644 --- a/languages.toml +++ b/languages.toml @@ -551,6 +551,7 @@ scope = "source.java" injection-regex = "java" file-types = ["java"] roots = ["pom.xml"] +language-server = { command = "jdtls" } indent = { tab-width = 4, unit = " " } [[grammar]] From 3f10473d30eec79e135ea74fa2bc4cc996426128 Mon Sep 17 00:00:00 2001 From: Roland Kovacs Date: Mon, 9 May 2022 21:12:01 +0200 Subject: [PATCH 222/861] Implement view swapping * add Tree::swap_split_in_direction() * add swap_view_{left,down,up,right} commands, bound to H,J,K,L respectively in the Window menu(s) * add test for view swapping --- helix-term/src/commands.rs | 20 +++++ helix-term/src/keymap/default.rs | 8 ++ helix-view/src/editor.rs | 16 ++++ helix-view/src/tree.rs | 147 +++++++++++++++++++++++++++++++ 4 files changed, 191 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c3c7d224e..2839f495c 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -360,6 +360,10 @@ impl MappableCommand { jump_view_left, "Jump to the split to the left", jump_view_up, "Jump to the split above", jump_view_down, "Jump to the split below", + swap_view_right, "Swap with the split to the right", + swap_view_left, "Swap with the split to the left", + swap_view_up, "Swap with the split above", + swap_view_down, "Swap with the split below", transpose_view, "Transpose splits", rotate_view, "Goto next window", hsplit, "Horizontal bottom split", @@ -3864,6 +3868,22 @@ fn jump_view_down(cx: &mut Context) { cx.editor.focus_down() } +fn swap_view_right(cx: &mut Context) { + cx.editor.swap_right() +} + +fn swap_view_left(cx: &mut Context) { + cx.editor.swap_left() +} + +fn swap_view_up(cx: &mut Context) { + cx.editor.swap_up() +} + +fn swap_view_down(cx: &mut Context) { + cx.editor.swap_down() +} + fn transpose_view(cx: &mut Context) { cx.editor.transpose_view() } diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index 124517d4a..a887f4b3f 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -180,6 +180,10 @@ pub fn default() -> HashMap { "C-j" | "j" | "down" => jump_view_down, "C-k" | "k" | "up" => jump_view_up, "C-l" | "l" | "right" => jump_view_right, + "L" => swap_view_right, + "K" => swap_view_up, + "H" => swap_view_left, + "J" => swap_view_down, "n" => { "New split scratch buffer" "C-s" | "s" => hsplit_new, "C-v" | "v" => vsplit_new, @@ -236,6 +240,10 @@ pub fn default() -> HashMap { "C-j" | "j" | "down" => jump_view_down, "C-k" | "k" | "up" => jump_view_up, "C-l" | "l" | "right" => jump_view_right, + "H" => swap_view_left, + "J" => swap_view_down, + "K" => swap_view_up, + "L" => swap_view_right, "n" => { "New split scratch buffer" "C-s" | "s" => hsplit_new, "C-v" | "v" => vsplit_new, diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 1ad210592..3ba6fea87 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -885,6 +885,22 @@ impl Editor { self.tree.focus_direction(tree::Direction::Down); } + pub fn swap_right(&mut self) { + self.tree.swap_split_in_direction(tree::Direction::Right); + } + + pub fn swap_left(&mut self) { + self.tree.swap_split_in_direction(tree::Direction::Left); + } + + pub fn swap_up(&mut self) { + self.tree.swap_split_in_direction(tree::Direction::Up); + } + + pub fn swap_down(&mut self) { + self.tree.swap_split_in_direction(tree::Direction::Down); + } + pub fn transpose_view(&mut self) { self.tree.transpose(); } diff --git a/helix-view/src/tree.rs b/helix-view/src/tree.rs index 522a79d78..2aa35dee8 100644 --- a/helix-view/src/tree.rs +++ b/helix-view/src/tree.rs @@ -538,6 +538,24 @@ impl Tree { } } + pub fn swap_split_in_direction(&mut self, direction: Direction) { + if let Some(id) = self.find_split_in_direction(self.focus, direction) { + if let Some([focused, target]) = self.nodes.get_disjoint_mut([self.focus, id]) { + match (&mut focused.content, &mut target.content) { + (Content::View(focused), Content::View(target)) => { + std::mem::swap(&mut focused.doc, &mut target.doc); + std::mem::swap(&mut focused.id, &mut target.id); + self.focus = id; + } + // self.focus always points to a view which has a content of Content::View + // and find_split_in_direction() only returns a view which has content of + // Content::View. + _ => unreachable!(), + } + } + } + } + pub fn area(&self) -> Rect { self.area } @@ -649,4 +667,133 @@ mod test { assert_eq!(None, tree.find_split_in_direction(r0, Direction::Right)); assert_eq!(None, tree.find_split_in_direction(r0, Direction::Up)); } + + #[test] + fn swap_split_in_direction() { + let mut tree = Tree::new(Rect { + x: 0, + y: 0, + width: 180, + height: 80, + }); + + let doc_l0 = DocumentId::default(); + let mut view = View::new( + doc_l0, + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); + view.area = Rect::new(0, 0, 180, 80); + tree.insert(view); + + let l0 = tree.focus; + + let doc_r0 = DocumentId::default(); + let view = View::new( + doc_r0, + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); + tree.split(view, Layout::Vertical); + let r0 = tree.focus; + + tree.focus = l0; + + let doc_l1 = DocumentId::default(); + let view = View::new( + doc_l1, + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); + tree.split(view, Layout::Horizontal); + let l1 = tree.focus; + + tree.focus = l0; + + let doc_l2 = DocumentId::default(); + let view = View::new( + doc_l2, + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); + tree.split(view, Layout::Vertical); + let l2 = tree.focus; + + // Views in test + // | L0 | L2 | | + // | L1 | R0 | + + // Document IDs in test + // | l0 | l2 | | + // | l1 | r0 | + + fn doc_id(tree: &Tree, view_id: ViewId) -> Option { + if let Content::View(view) = &tree.nodes[view_id].content { + Some(view.doc) + } else { + None + } + } + + tree.focus = l0; + // `*` marks the view in focus from view table (here L0) + // | l0* | l2 | | + // | l1 | r0 | + tree.swap_split_in_direction(Direction::Down); + // | l1 | l2 | | + // | l0* | r0 | + assert_eq!(tree.focus, l1); + assert_eq!(doc_id(&tree, l0), Some(doc_l1)); + assert_eq!(doc_id(&tree, l1), Some(doc_l0)); + assert_eq!(doc_id(&tree, l2), Some(doc_l2)); + assert_eq!(doc_id(&tree, r0), Some(doc_r0)); + + tree.swap_split_in_direction(Direction::Right); + + // | l1 | l2 | | + // | r0 | l0* | + assert_eq!(tree.focus, r0); + assert_eq!(doc_id(&tree, l0), Some(doc_l1)); + assert_eq!(doc_id(&tree, l1), Some(doc_r0)); + assert_eq!(doc_id(&tree, l2), Some(doc_l2)); + assert_eq!(doc_id(&tree, r0), Some(doc_l0)); + + // cannot swap, nothing changes + tree.swap_split_in_direction(Direction::Up); + // | l1 | l2 | | + // | r0 | l0* | + assert_eq!(tree.focus, r0); + assert_eq!(doc_id(&tree, l0), Some(doc_l1)); + assert_eq!(doc_id(&tree, l1), Some(doc_r0)); + assert_eq!(doc_id(&tree, l2), Some(doc_l2)); + assert_eq!(doc_id(&tree, r0), Some(doc_l0)); + + // cannot swap, nothing changes + tree.swap_split_in_direction(Direction::Down); + // | l1 | l2 | | + // | r0 | l0* | + assert_eq!(tree.focus, r0); + assert_eq!(doc_id(&tree, l0), Some(doc_l1)); + assert_eq!(doc_id(&tree, l1), Some(doc_r0)); + assert_eq!(doc_id(&tree, l2), Some(doc_l2)); + assert_eq!(doc_id(&tree, r0), Some(doc_l0)); + + tree.focus = l2; + // | l1 | l2* | | + // | r0 | l0 | + + tree.swap_split_in_direction(Direction::Down); + // | l1 | r0 | | + // | l2* | l0 | + assert_eq!(tree.focus, l1); + assert_eq!(doc_id(&tree, l0), Some(doc_l1)); + assert_eq!(doc_id(&tree, l1), Some(doc_l2)); + assert_eq!(doc_id(&tree, l2), Some(doc_r0)); + assert_eq!(doc_id(&tree, r0), Some(doc_l0)); + + tree.swap_split_in_direction(Direction::Up); + // | l2* | r0 | | + // | l1 | l0 | + assert_eq!(tree.focus, l0); + assert_eq!(doc_id(&tree, l0), Some(doc_l2)); + assert_eq!(doc_id(&tree, l1), Some(doc_l1)); + assert_eq!(doc_id(&tree, l2), Some(doc_r0)); + assert_eq!(doc_id(&tree, r0), Some(doc_l0)); + } } From 6bd8924436636c252ec2bfcd02986771665f0c02 Mon Sep 17 00:00:00 2001 From: Roland Kovacs Date: Wed, 11 May 2022 21:12:59 +0200 Subject: [PATCH 223/861] Move Tree nodes on view swap Instead of moving the Node contents on view swap if they have the same parent reorder them to keep traversal order otherwise re-parent them. --- helix-view/src/tree.rs | 90 +++++++++++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 19 deletions(-) diff --git a/helix-view/src/tree.rs b/helix-view/src/tree.rs index 2aa35dee8..e6dba9163 100644 --- a/helix-view/src/tree.rs +++ b/helix-view/src/tree.rs @@ -538,20 +538,72 @@ impl Tree { } } - pub fn swap_split_in_direction(&mut self, direction: Direction) { - if let Some(id) = self.find_split_in_direction(self.focus, direction) { - if let Some([focused, target]) = self.nodes.get_disjoint_mut([self.focus, id]) { - match (&mut focused.content, &mut target.content) { - (Content::View(focused), Content::View(target)) => { - std::mem::swap(&mut focused.doc, &mut target.doc); - std::mem::swap(&mut focused.id, &mut target.id); - self.focus = id; - } - // self.focus always points to a view which has a content of Content::View - // and find_split_in_direction() only returns a view which has content of - // Content::View. - _ => unreachable!(), + pub fn swap_split_in_direction(&mut self, direction: Direction) -> Option<()> { + let focus = self.focus; + let target = self.find_split_in_direction(focus, direction)?; + let focus_parent = self.nodes[focus].parent; + let target_parent = self.nodes[target].parent; + + if focus_parent == target_parent { + let parent = focus_parent; + let [parent, focus, target] = self.nodes.get_disjoint_mut([parent, focus, target])?; + match (&mut parent.content, &mut focus.content, &mut target.content) { + ( + Content::Container(parent), + Content::View(focus_view), + Content::View(target_view), + ) => { + let focus_pos = parent.children.iter().position(|id| focus_view.id == *id)?; + let target_pos = parent + .children + .iter() + .position(|id| target_view.id == *id)?; + // swap node positions so that traversal order is kept + parent.children[focus_pos] = target_view.id; + parent.children[target_pos] = focus_view.id; + // swap area so that views rendered at the correct location + std::mem::swap(&mut focus_view.area, &mut target_view.area); + + Some(()) } + _ => unreachable!(), + } + } else { + let [focus_parent, target_parent, focus, target] = + self.nodes + .get_disjoint_mut([focus_parent, target_parent, focus, target])?; + match ( + &mut focus_parent.content, + &mut target_parent.content, + &mut focus.content, + &mut target.content, + ) { + ( + Content::Container(focus_parent), + Content::Container(target_parent), + Content::View(focus_view), + Content::View(target_view), + ) => { + let focus_pos = focus_parent + .children + .iter() + .position(|id| focus_view.id == *id)?; + let target_pos = target_parent + .children + .iter() + .position(|id| target_view.id == *id)?; + // re-parent target and focus nodes + std::mem::swap( + &mut focus_parent.children[focus_pos], + &mut target_parent.children[target_pos], + ); + std::mem::swap(&mut focus.parent, &mut target.parent); + // swap area so that views rendered at the correct location + std::mem::swap(&mut focus_view.area, &mut target_view.area); + + Some(()) + } + _ => unreachable!(), } } } @@ -738,7 +790,7 @@ mod test { tree.swap_split_in_direction(Direction::Down); // | l1 | l2 | | // | l0* | r0 | - assert_eq!(tree.focus, l1); + assert_eq!(tree.focus, l0); assert_eq!(doc_id(&tree, l0), Some(doc_l1)); assert_eq!(doc_id(&tree, l1), Some(doc_l0)); assert_eq!(doc_id(&tree, l2), Some(doc_l2)); @@ -748,7 +800,7 @@ mod test { // | l1 | l2 | | // | r0 | l0* | - assert_eq!(tree.focus, r0); + assert_eq!(tree.focus, l0); assert_eq!(doc_id(&tree, l0), Some(doc_l1)); assert_eq!(doc_id(&tree, l1), Some(doc_r0)); assert_eq!(doc_id(&tree, l2), Some(doc_l2)); @@ -758,7 +810,7 @@ mod test { tree.swap_split_in_direction(Direction::Up); // | l1 | l2 | | // | r0 | l0* | - assert_eq!(tree.focus, r0); + assert_eq!(tree.focus, l0); assert_eq!(doc_id(&tree, l0), Some(doc_l1)); assert_eq!(doc_id(&tree, l1), Some(doc_r0)); assert_eq!(doc_id(&tree, l2), Some(doc_l2)); @@ -768,7 +820,7 @@ mod test { tree.swap_split_in_direction(Direction::Down); // | l1 | l2 | | // | r0 | l0* | - assert_eq!(tree.focus, r0); + assert_eq!(tree.focus, l0); assert_eq!(doc_id(&tree, l0), Some(doc_l1)); assert_eq!(doc_id(&tree, l1), Some(doc_r0)); assert_eq!(doc_id(&tree, l2), Some(doc_l2)); @@ -781,7 +833,7 @@ mod test { tree.swap_split_in_direction(Direction::Down); // | l1 | r0 | | // | l2* | l0 | - assert_eq!(tree.focus, l1); + assert_eq!(tree.focus, l2); assert_eq!(doc_id(&tree, l0), Some(doc_l1)); assert_eq!(doc_id(&tree, l1), Some(doc_l2)); assert_eq!(doc_id(&tree, l2), Some(doc_r0)); @@ -790,7 +842,7 @@ mod test { tree.swap_split_in_direction(Direction::Up); // | l2* | r0 | | // | l1 | l0 | - assert_eq!(tree.focus, l0); + assert_eq!(tree.focus, l2); assert_eq!(doc_id(&tree, l0), Some(doc_l2)); assert_eq!(doc_id(&tree, l1), Some(doc_l1)); assert_eq!(doc_id(&tree, l2), Some(doc_r0)); From d25bae844c2a13f9d91c34a9016c3c6fd5cc26dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Sun, 22 May 2022 00:00:05 +0900 Subject: [PATCH 224/861] Add Scheme support Skipped scm for now :/ it overlaps with tree-sitter-tsq --- languages.toml | 13 ++++ runtime/queries/scheme/highlights.scm | 100 ++++++++++++++++++++++++++ runtime/queries/scheme/injections.scm | 5 ++ 3 files changed, 118 insertions(+) create mode 100644 runtime/queries/scheme/highlights.scm create mode 100644 runtime/queries/scheme/injections.scm diff --git a/languages.toml b/languages.toml index 5deed3576..d3c4ef435 100644 --- a/languages.toml +++ b/languages.toml @@ -1366,3 +1366,16 @@ roots = [] [[grammar]] name = "sshclientconfig" source = { git = "https://github.com/metio/tree-sitter-ssh-client-config", rev = "769d7a01a2e5493b4bb5a51096c6bf4be130b024" } + +[[language]] +name = "scheme" +scope = "source.scheme" +injection-regex = "scheme" +file-types = ["ss", "rkt"] # "scm", +roots = [] +comment-token = ";" +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "scheme" +source = { git = "https://github.com/6cdh/tree-sitter-scheme", rev = "27fb77db05f890c2823b4bd751c6420378df146b" } diff --git a/runtime/queries/scheme/highlights.scm b/runtime/queries/scheme/highlights.scm new file mode 100644 index 000000000..3b7a42755 --- /dev/null +++ b/runtime/queries/scheme/highlights.scm @@ -0,0 +1,100 @@ +(number) @constant.numeric +(character) @constant.character +(boolean) @constant.builtin.boolean + +[(string) + (character)] @string + +(escape_sequence) @constant.character.escape + +[(comment) + (block_comment) + (directive)] @comment + +[(boolean) + (character)] @constant + +((symbol) @function.builtin + (#match? @function.builtin "^(eqv\\?|eq\\?|equal\\?)")) ; TODO + +; keywords + +((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)$")) + +; special forms + +(list + "[" + (symbol)+ @variable + "]") + +(list + . + (symbol) @_f + . + (list + (symbol) @variable) + (#eq? @_f "lambda")) + +(list + . + (symbol) @_f + . + (list + (list + (symbol) @variable)) + (#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 + +; library + +(list + . + (symbol) @_lib + . + (symbol) @namespace + + (#eq? @_lib "library")) + +; procedure + +(list + . + (symbol) @function) + +;; variables + +((symbol) @variable.builtin + (#eq? @variable.builtin "...")) + +(symbol) @variable +((symbol) @variable.builtin + (#eq? @variable.builtin ".")) + +(symbol) @variable + + +["(" ")" "[" "]" "{" "}"] @punctuation.bracket + diff --git a/runtime/queries/scheme/injections.scm b/runtime/queries/scheme/injections.scm new file mode 100644 index 000000000..aebb54d93 --- /dev/null +++ b/runtime/queries/scheme/injections.scm @@ -0,0 +1,5 @@ +((comment) @injection.content + (#set! injection.language "comment")) + +((block_comment) @injection.content + (#set! injection.language "comment")) From 8df8ff27c2f95864a426a48839d065b237622bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Sun, 22 May 2022 00:20:45 +0900 Subject: [PATCH 225/861] cargo xtask docgen --- 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 2e670807c..df4d36b5c 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -76,6 +76,7 @@ | ruby | ✓ | ✓ | ✓ | `solargraph` | | rust | ✓ | ✓ | ✓ | `rust-analyzer` | | scala | ✓ | | ✓ | `metals` | +| scheme | ✓ | | | | | solidity | ✓ | | | `solc` | | sql | ✓ | | | | | sshclientconfig | ✓ | | | | From 5c864922d88a88898ab7525f8ebd33f8f5096c59 Mon Sep 17 00:00:00 2001 From: Leoi Hung Kin Date: Sun, 22 May 2022 09:24:32 +0800 Subject: [PATCH 226/861] Fix panic when reloading a shrunk file (#2506) * fix panic when reloading a shrunk file * linting * use scrolloff --- helix-term/src/commands/typed.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 74ab73bef..5121eaa18 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -781,8 +781,11 @@ fn reload( _args: &[Cow], _event: PromptEvent, ) -> anyhow::Result<()> { + let scrolloff = cx.editor.config().scrolloff; let (view, doc) = current!(cx.editor); - doc.reload(view.id) + doc.reload(view.id).map(|_| { + view.ensure_cursor_in_view(doc, scrolloff); + }) } fn tree_sitter_scopes( From bfc4ff4dcfd9135924d90bb822f2e23ae9cb2420 Mon Sep 17 00:00:00 2001 From: kyrime Date: Sun, 22 May 2022 02:24:51 +0100 Subject: [PATCH 227/861] Add theme key for picker separator (#2523) Co-authored-by: ky <> --- book/src/themes.md | 69 +++++++++++++++++++------------------ helix-term/src/ui/picker.rs | 4 +-- theme.toml | 1 + 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/book/src/themes.md b/book/src/themes.md index 97955cb71..7562b2056 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -205,39 +205,40 @@ These scopes are used for theming the editor interface. - `hover` - for hover popup ui -| Key | Notes | -| --- | --- | -| `ui.background` | | -| `ui.cursor` | | -| `ui.cursor.insert` | | -| `ui.cursor.select` | | -| `ui.cursor.match` | Matching bracket etc. | -| `ui.cursor.primary` | Cursor with primary selection | -| `ui.linenr` | Line numbers | -| `ui.linenr.selected` | Line number for the line the cursor is on | -| `ui.statusline` | Statusline | -| `ui.statusline.inactive` | Statusline (unfocused document) | -| `ui.popup` | Documentation popups (e.g space-k) | -| `ui.popup.info` | Prompt for multiple key options | -| `ui.window` | Border lines separating splits | -| `ui.help` | Description box for commands | -| `ui.text` | Command prompts, popup text, etc. | -| `ui.text.focus` | | -| `ui.text.info` | The key: command text in `ui.popup.info` boxes | -| `ui.virtual.ruler` | Ruler columns (see the [`editor.rulers` config][rulers-config])| -| `ui.virtual.whitespace` | Visible white-space characters | -| `ui.menu` | Code and command completion menus | -| `ui.menu.selected` | Selected autocomplete item | -| `ui.selection` | For selections in the editing area | -| `ui.selection.primary` | | -| `warning` | Diagnostics warning (gutter) | -| `error` | Diagnostics error (gutter) | -| `info` | Diagnostics info (gutter) | -| `hint` | Diagnostics hint (gutter) | -| `diagnostic` | Diagnostics fallback style (editing area) | -| `diagnostic.hint` | Diagnostics hint (editing area) | -| `diagnostic.info` | Diagnostics info (editing area) | -| `diagnostic.warning` | Diagnostics warning (editing area) | -| `diagnostic.error` | Diagnostics error (editing area) | +| Key | Notes | +| --- | --- | +| `ui.background` | | +| `ui.background.separator` | Picker separator below input line | +| `ui.cursor` | | +| `ui.cursor.insert` | | +| `ui.cursor.select` | | +| `ui.cursor.match` | Matching bracket etc. | +| `ui.cursor.primary` | Cursor with primary selection | +| `ui.linenr` | Line numbers | +| `ui.linenr.selected` | Line number for the line the cursor is on | +| `ui.statusline` | Statusline | +| `ui.statusline.inactive` | Statusline (unfocused document) | +| `ui.popup` | Documentation popups (e.g space-k) | +| `ui.popup.info` | Prompt for multiple key options | +| `ui.window` | Border lines separating splits | +| `ui.help` | Description box for commands | +| `ui.text` | Command prompts, popup text, etc. | +| `ui.text.focus` | | +| `ui.text.info` | The key: command text in `ui.popup.info` boxes | +| `ui.virtual.ruler` | Ruler columns (see the [`editor.rulers` config][rulers-config])| +| `ui.virtual.whitespace` | Visible white-space characters | +| `ui.menu` | Code and command completion menus | +| `ui.menu.selected` | Selected autocomplete item | +| `ui.selection` | For selections in the editing area | +| `ui.selection.primary` | | +| `warning` | Diagnostics warning (gutter) | +| `error` | Diagnostics error (gutter) | +| `info` | Diagnostics info (gutter) | +| `hint` | Diagnostics hint (gutter) | +| `diagnostic` | Diagnostics fallback style (editing area) | +| `diagnostic.hint` | Diagnostics hint (editing area) | +| `diagnostic.info` | Diagnostics info (editing area) | +| `diagnostic.warning` | Diagnostics warning (editing area) | +| `diagnostic.error` | Diagnostics error (editing area) | [rulers-config]: ./configuration.md#editor-section diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 49d91be61..181c2077d 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -26,7 +26,7 @@ use crate::ui::{Prompt, PromptEvent}; use helix_core::{movement::Direction, Position}; use helix_view::{ editor::Action, - graphics::{Color, CursorKind, Margin, Modifier, Rect, Style}, + graphics::{CursorKind, Margin, Modifier, Rect}, Document, Editor, }; @@ -587,7 +587,7 @@ impl Component for Picker { self.prompt.render(area, surface, cx); // -- Separator - let sep_style = Style::default().fg(Color::Rgb(90, 89, 119)); + let sep_style = cx.editor.theme.get("ui.background.separator"); let borders = BorderType::line_symbols(BorderType::Plain); for x in inner.left()..inner.right() { if let Some(cell) = surface.get_mut(x, inner.y + 1) { diff --git a/theme.toml b/theme.toml index a0186e92a..ecd4ebe54 100644 --- a/theme.toml +++ b/theme.toml @@ -43,6 +43,7 @@ label = "honey" # concat (ERROR) @error.syntax and "MISSING ;" selectors for errors "ui.background" = { bg = "midnight" } +"ui.background.separator" = { fg = "comet" } "ui.linenr" = { fg = "comet" } "ui.linenr.selected" = { fg = "lilac" } "ui.statusline" = { fg = "lilac", bg = "revolver" } From 1837b5e4a61f0230b3cd382ed487fa09be7b2b68 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sat, 14 May 2022 22:28:37 +0800 Subject: [PATCH 228/861] Refactor Block with Default and bitflags Specifying empty for bitflags is not recommended, it is now removed and added Default. For BorderType, it now defaults to plain. --- helix-tui/src/widgets/block.rs | 21 ++++++++------------- helix-tui/src/widgets/mod.rs | 11 +++++------ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/helix-tui/src/widgets/block.rs b/helix-tui/src/widgets/block.rs index 26223c3eb..3c05a2a3c 100644 --- a/helix-tui/src/widgets/block.rs +++ b/helix-tui/src/widgets/block.rs @@ -6,6 +6,7 @@ use crate::{ }; use helix_view::graphics::{Rect, Style}; +/// Border render type. Defaults to [`BorderType::Plain`]. #[derive(Debug, Clone, Copy, PartialEq)] pub enum BorderType { Plain, @@ -25,6 +26,12 @@ impl BorderType { } } +impl Default for BorderType { + fn default() -> BorderType { + BorderType::Plain + } +} + /// Base widget to be used with all upper level ones. It may be used to display a box border around /// the widget and/or add a title. /// @@ -40,7 +47,7 @@ impl BorderType { /// .border_type(BorderType::Rounded) /// .style(Style::default().bg(Color::Black)); /// ``` -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Default, Clone, PartialEq)] pub struct Block<'a> { /// Optional title place on the upper left of the block title: Option>, @@ -55,18 +62,6 @@ pub struct Block<'a> { style: Style, } -impl<'a> Default for Block<'a> { - fn default() -> Block<'a> { - Block { - title: None, - borders: Borders::NONE, - border_style: Default::default(), - border_type: BorderType::Plain, - style: Default::default(), - } - } -} - impl<'a> Block<'a> { pub fn title(mut self, title: T) -> Block<'a> where diff --git a/helix-tui/src/widgets/mod.rs b/helix-tui/src/widgets/mod.rs index e5608a79e..c0c3a994a 100644 --- a/helix-tui/src/widgets/mod.rs +++ b/helix-tui/src/widgets/mod.rs @@ -27,17 +27,16 @@ use helix_view::graphics::Rect; bitflags! { /// Bitflags that can be composed to set the visible borders essentially on the block widget. + #[derive(Default)] pub struct Borders: u32 { - /// Show no border (default) - const NONE = 0b0000_0001; /// Show the top border - const TOP = 0b0000_0010; + const TOP = 0b0000_0001; /// Show the right border - const RIGHT = 0b0000_0100; + const RIGHT = 0b0000_0010; /// Show the bottom border - const BOTTOM = 0b000_1000; + const BOTTOM = 0b000_0100; /// Show the left border - const LEFT = 0b0001_0000; + const LEFT = 0b0000_1000; /// Show all borders const ALL = Self::TOP.bits | Self::RIGHT.bits | Self::BOTTOM.bits | Self::LEFT.bits; } From 5bcb31a6dfb007b31b6ba38c5a1455727904ba27 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 22 May 2022 00:25:20 +0800 Subject: [PATCH 229/861] Make Borders u8 --- helix-tui/src/widgets/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-tui/src/widgets/mod.rs b/helix-tui/src/widgets/mod.rs index c0c3a994a..8946ef056 100644 --- a/helix-tui/src/widgets/mod.rs +++ b/helix-tui/src/widgets/mod.rs @@ -28,7 +28,7 @@ use helix_view::graphics::Rect; bitflags! { /// Bitflags that can be composed to set the visible borders essentially on the block widget. #[derive(Default)] - pub struct Borders: u32 { + pub struct Borders: u8 { /// Show the top border const TOP = 0b0000_0001; /// Show the right border From 0c05447d49103e96fc21910d336bdc75ab96338d Mon Sep 17 00:00:00 2001 From: Daniel S Poulin Date: Sat, 21 May 2022 21:33:11 -0400 Subject: [PATCH 230/861] Add shrink equivalent of extend_to_line_bounds (#2450) * Add shrink equivalent of extend_to_line_bounds * Add a check for being past rope end in end position calc * Include the EOL character in calculations * Bind to `A-x` for now * Document new keybind --- book/src/keymap.md | 1 + helix-term/src/commands.rs | 42 ++++++++++++++++++++++++++++++++ helix-term/src/keymap/default.rs | 2 +- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index e56eeefc4..25280d711 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -107,6 +107,7 @@ | `%` | Select entire file | `select_all` | | `x` | Select current line, if already selected, extend to next line | `extend_line` | | `X` | Extend selection to line bounds (line-wise selection) | `extend_to_line_bounds` | +| `Alt-x` | Shrink selection to line bounds (line-wise selection) | `shrink_to_line_bounds` | | `J` | Join lines inside selection | `join_selections` | | `K` | Keep selections matching the regex | `keep_selections` | | `Alt-K` | Remove selections matching the regex | `remove_selections` | diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 2839f495c..8024e3f03 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -247,6 +247,7 @@ impl MappableCommand { extend_line, "Select current line, if already selected, extend to next line", extend_line_above, "Select current line, if already selected, extend to previous line", extend_to_line_bounds, "Extend selection to line bounds (line-wise selection)", + shrink_to_line_bounds, "Shrink selection to line bounds (line-wise selection)", delete_selection, "Delete selection", delete_selection_noyank, "Delete selection, without yanking", change_selection, "Change selection (delete and enter insert mode)", @@ -1942,6 +1943,47 @@ fn extend_to_line_bounds(cx: &mut Context) { ); } +fn shrink_to_line_bounds(cx: &mut Context) { + let (view, doc) = current!(cx.editor); + + doc.set_selection( + view.id, + doc.selection(view.id).clone().transform(|range| { + let text = doc.text(); + + let (start_line, end_line) = range.line_range(text.slice(..)); + + // Do nothing if the selection is within one line to prevent + // conditional logic for the behavior of this command + if start_line == end_line { + return range; + } + + let mut start = text.line_to_char(start_line); + + // line_to_char gives us the start position of the line, so + // we need to get the start position of the next line. In + // the editor, this will correspond to the cursor being on + // the EOL whitespace charactor, which is what we want. + let mut end = text.line_to_char((end_line + 1).min(text.len_lines())); + + if start != range.from() { + start = text.line_to_char((start_line + 1).min(text.len_lines())); + } + + if end != range.to() { + end = text.line_to_char(end_line); + } + + if range.anchor <= range.head { + Range::new(start, end) + } else { + Range::new(end, start) + } + }), + ); +} + enum Operation { Delete, Change, diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index a887f4b3f..0f0b09dd5 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -87,7 +87,7 @@ pub fn default() -> HashMap { "%" => select_all, "x" => extend_line, "X" => extend_to_line_bounds, - // crop_to_whole_line + "A-x" => shrink_to_line_bounds, "m" => { "Match" "m" => match_brackets, From 0018545263b6a8416b0b8b943be236ea0abb7a67 Mon Sep 17 00:00:00 2001 From: Joel Date: Sun, 22 May 2022 15:10:01 +1000 Subject: [PATCH 231/861] fix: remove duplicated `ui.help` in themes the bottom value is used, so i've removed the top `ui.help` values from all themes also, the values are not merged, so: ```toml "ui.help" = { modifiers = ["reversed"] } "ui.help" = { fg = "white", bg = "black" } ``` is equal to: ```toml "ui.help" = { fg = "white", bg = "black" } ``` --- base16_theme.toml | 1 - runtime/themes/autumn.toml | 1 - runtime/themes/base16_default_dark.toml | 1 - runtime/themes/base16_default_light.toml | 1 - runtime/themes/rose_pine.toml | 1 - runtime/themes/rose_pine_dawn.toml | 1 - 6 files changed, 6 deletions(-) diff --git a/base16_theme.toml b/base16_theme.toml index 42e02a98a..5c0c253e1 100644 --- a/base16_theme.toml +++ b/base16_theme.toml @@ -10,7 +10,6 @@ "comment" = { fg = "gray" } "ui.statusline" = { fg = "black", bg = "white" } "ui.statusline.inactive" = { fg = "gray", bg = "white" } -"ui.help" = { modifiers = ["reversed"] } "ui.cursor" = { fg = "white", modifiers = ["reversed"] } "variable" = "red" "constant.numeric" = "yellow" diff --git a/runtime/themes/autumn.toml b/runtime/themes/autumn.toml index 032e773ac..afcc1a113 100644 --- a/runtime/themes/autumn.toml +++ b/runtime/themes/autumn.toml @@ -17,7 +17,6 @@ "ui.selection" = { bg = "my_gray3" } "comment" = { fg = "my_gray4", modifiers = ["italic"] } "ui.statusline" = { fg = "my_gray5", bg = "my_gray2" } -"ui.help" = { fg = "my_gray5", bg = "my_gray2" } "ui.cursor" = { fg = "my_gray5", modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "my_white", modifiers = ["reversed"] } "ui.text" = "my_white" diff --git a/runtime/themes/base16_default_dark.toml b/runtime/themes/base16_default_dark.toml index 6074c450e..7516e492e 100644 --- a/runtime/themes/base16_default_dark.toml +++ b/runtime/themes/base16_default_dark.toml @@ -11,7 +11,6 @@ "ui.selection" = { bg = "base02" } "comment" = { fg = "base03", modifiers = ["italic"] } "ui.statusline" = { fg = "base04", bg = "base01" } -"ui.help" = { fg = "base04", bg = "base01" } "ui.cursor" = { fg = "base04", modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "base05", modifiers = ["reversed"] } "ui.text" = "base05" diff --git a/runtime/themes/base16_default_light.toml b/runtime/themes/base16_default_light.toml index 2273c1912..368474591 100644 --- a/runtime/themes/base16_default_light.toml +++ b/runtime/themes/base16_default_light.toml @@ -10,7 +10,6 @@ "ui.selection" = { bg = "base02" } "comment" = { fg = "base03", modifiers = ["italic"] } "ui.statusline" = { fg = "base04", bg = "base01" } -"ui.help" = { fg = "base04", bg = "base01" } "ui.cursor" = { fg = "base04", modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "base05", modifiers = ["reversed"] } "ui.virtual" = "base03" diff --git a/runtime/themes/rose_pine.toml b/runtime/themes/rose_pine.toml index d005ac8ad..f05758801 100644 --- a/runtime/themes/rose_pine.toml +++ b/runtime/themes/rose_pine.toml @@ -10,7 +10,6 @@ "comment" = "subtle" "ui.statusline" = {fg = "foam", bg = "surface" } "ui.statusline.inactive" = { fg = "iris", bg = "surface" } -"ui.help" = { fg = "foam", bg = "surface" } "ui.cursor" = { fg = "rose", modifiers = ["reversed"] } "ui.text" = { fg = "text" } "ui.text.focus" = { fg = "foam", modifiers = ["bold"]} diff --git a/runtime/themes/rose_pine_dawn.toml b/runtime/themes/rose_pine_dawn.toml index 1a9ac7df2..5ad304e38 100644 --- a/runtime/themes/rose_pine_dawn.toml +++ b/runtime/themes/rose_pine_dawn.toml @@ -10,7 +10,6 @@ "comment" = "subtle" "ui.statusline" = {fg = "foam", bg = "surface" } "ui.statusline.inactive" = { fg = "iris", bg = "surface" } -"ui.help" = { fg = "foam", bg = "surface" } "ui.cursor" = { fg = "rose", modifiers = ["reversed"] } "ui.text" = { fg = "text" } "ui.text.focus" = { fg = "foam", modifiers = ["bold"]} From 682bcc3a32d90bfb58872610af20f47ee4089c83 Mon Sep 17 00:00:00 2001 From: Joel Date: Sun, 22 May 2022 15:12:46 +1000 Subject: [PATCH 232/861] fix: missing quotes around `variable.other.member` --- theme.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme.toml b/theme.toml index ecd4ebe54..7a518b2fe 100644 --- a/theme.toml +++ b/theme.toml @@ -6,7 +6,7 @@ punctuation = "lavender" "punctuation.delimiter" = "lavender" operator = "lilac" special = "honey" -variable.other.member = "white" +"variable.other.member" = "white" variable = "lavender" # variable = "almond" # TODO: metavariables only # "variable.parameter" = { fg = "lavender", modifiers = ["underlined"] } From 6801b28da0539bceb342e99a709961ec70148dbb Mon Sep 17 00:00:00 2001 From: Jens Getreu Date: Sun, 22 May 2022 17:40:27 +0200 Subject: [PATCH 233/861] Highlight active window in Autumn theme (#2531) Co-authored-by: Jens Getreu --- runtime/themes/autumn.toml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/runtime/themes/autumn.toml b/runtime/themes/autumn.toml index afcc1a113..68e41f5af 100644 --- a/runtime/themes/autumn.toml +++ b/runtime/themes/autumn.toml @@ -1,10 +1,10 @@ # The structure is based on `base16_default_dark` by Ray Gervais. Most of -# the colors come the so called Autumn theme, a color scheme inspired by -# the colors you can find in autumn. Originally it was designed as a +# the colors come from the so called Autumn theme, a color scheme inspired by +# the colors you can find in the autumn. Originally it was designed as a # color scheme for the Komodo IDE and then ported to Vim by Kenneth Love # and Chris Jones. Later, Yorick Peterse improved their work. See: # -# Jens Getreu finally ported and optimised the color theme for the Helix editor. +# Jens Getreu ported and optimised the color theme for the Helix editor. # Author: Jens Getreu "ui.background" = { bg = "my_gray0" } @@ -12,11 +12,12 @@ "ui.menu.selected" = { fg = "my_gray2", bg = "my_gray5" } "ui.linenr" = { fg = "my_gray4", bg = "my_gray2" } "ui.popup" = { bg = "my_gray2" } -"ui.window" = { bg = "my_gray2" } -"ui.linenr.selected" = { fg = "my_gray5", bg = "my_gray2", modifiers = ["bold"] } +"ui.window" = { fg = "my_gray4", bg = "my_gray2" } +"ui.linenr.selected" = { fg = "my_gray6", bg = "my_gray2", modifiers = ["bold"]} "ui.selection" = { bg = "my_gray3" } "comment" = { fg = "my_gray4", modifiers = ["italic"] } -"ui.statusline" = { fg = "my_gray5", bg = "my_gray2" } +"ui.statusline" = { fg = "my_gray6", bg = "my_gray2" } +"ui.statusline.inactive" = { fg = 'my_gray4', bg = 'my_gray2' } "ui.cursor" = { fg = "my_gray5", modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "my_white", modifiers = ["reversed"] } "ui.text" = "my_white" @@ -69,8 +70,8 @@ my_gray2 = "#3a3a3a" # Lighter Background (Used for status bars, line numbe my_gray3 = "#525252" # Selection Background my_gray4 = "#7c7c7c" # Comments, Invisibles, Line Highlighting my_gray5 = "#aaaaaa" # Dark Foreground (Used for status bars) -my_gray6 = "#e8e8e8" # Light Foreground (Not often used) -my_gray7 = "#f8f8f8" # Light Background (Not often used) +my_gray6 = "#c0c0c0" # 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 my_white3 = "#F3F2CC" # Classes, Markup Bold, Search Text Background From 35303f749e3e918b76bcf3f01223da6e27c77f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 23 May 2022 13:48:00 +0900 Subject: [PATCH 234/861] Replace handwritten CI cache with Swatinem/rust-cache The cache kept growing as dependencies kept changing and updating. --- .github/workflows/build.yml | 84 ++--------------------------------- .github/workflows/release.yml | 21 +-------- 2 files changed, 5 insertions(+), 100 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 69d88f836..c4594cfa0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,26 +22,7 @@ jobs: toolchain: stable override: true - - name: Cache cargo registry - uses: actions/cache@v3 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-registry- - - - name: Cache cargo index - uses: actions/cache@v3 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-index- - - - name: Cache cargo target dir - uses: actions/cache@v3 - with: - path: target - key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-build-target- + - uses: Swatinem/rust-cache@v1 - name: Run cargo check uses: actions-rs/cargo@v1 @@ -62,26 +43,7 @@ jobs: toolchain: ${{ matrix.rust }} override: true - - name: Cache cargo registry - uses: actions/cache@v3 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-registry- - - - name: Cache cargo index - uses: actions/cache@v3 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-index- - - - name: Cache cargo target dir - uses: actions/cache@v3 - with: - path: target - key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-build-target- + - uses: Swatinem/rust-cache@v1 - name: Copy minimal languages config run: cp .github/workflows/languages.toml ./languages.toml @@ -119,26 +81,7 @@ jobs: override: true components: rustfmt, clippy - - name: Cache cargo registry - uses: actions/cache@v3 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-registry- - - - name: Cache cargo index - uses: actions/cache@v3 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-index- - - - name: Cache cargo target dir - uses: actions/cache@v3 - with: - path: target - key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-build-target- + - uses: Swatinem/rust-cache@v1 - name: Run cargo fmt uses: actions-rs/cargo@v1 @@ -166,26 +109,7 @@ jobs: toolchain: stable override: true - - name: Cache cargo registry - uses: actions/cache@v3 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-registry- - - - name: Cache cargo index - uses: actions/cache@v3 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-index- - - - name: Cache cargo target dir - uses: actions/cache@v3 - with: - path: target - key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-build-target- + - uses: Swatinem/rust-cache@v1 - name: Generate docs uses: actions-rs/cargo@v1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 30f8ccc78..d6bb52ce1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,26 +20,7 @@ jobs: toolchain: stable override: true - - name: Cache cargo registry - uses: actions/cache@v3 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-v2-cargo-registry-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-registry- - - - name: Cache cargo index - uses: actions/cache@v3 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-v2-cargo-index-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-index- - - - name: Cache cargo target dir - uses: actions/cache@v3 - with: - path: target - key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-v2-cargo-build-target- + - uses: Swatinem/rust-cache@v1 - name: Fetch tree-sitter grammars uses: actions-rs/cargo@v1 From f6531c9db013b59dced06e24e132fcb6f4b65152 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 21 May 2022 20:46:20 -0500 Subject: [PATCH 235/861] inherit rust toolchain channel from rust-toolchain.toml We've forked actions-rs/toolchain and merged https://github.com/actions-rs/toolchain/pull/209 so we can take advantage of full support of `rust-toolchain.toml`. Without that PR, the action fails because the `rustup` version built into the runners by default is too old. #2528 covers switching back to the upstream when it includes those changes. --- .github/workflows/build.yml | 13 ++++--------- .github/workflows/release.yml | 1 - 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c4594cfa0..f3cd128a9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,10 +16,9 @@ jobs: uses: actions/checkout@v3 - name: Install stable toolchain - uses: actions-rs/toolchain@v1 + uses: helix-editor/rust-toolchain@v1 with: profile: minimal - toolchain: stable override: true - uses: Swatinem/rust-cache@v1 @@ -37,10 +36,9 @@ jobs: uses: actions/checkout@v3 - name: Install stable toolchain - uses: actions-rs/toolchain@v1 + uses: helix-editor/rust-toolchain@v1 with: profile: minimal - toolchain: ${{ matrix.rust }} override: true - uses: Swatinem/rust-cache@v1 @@ -64,7 +62,6 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - rust: [stable] lints: name: Lints @@ -74,10 +71,9 @@ jobs: uses: actions/checkout@v3 - name: Install stable toolchain - uses: actions-rs/toolchain@v1 + uses: helix-editor/rust-toolchain@v1 with: profile: minimal - toolchain: stable override: true components: rustfmt, clippy @@ -103,10 +99,9 @@ jobs: uses: actions/checkout@v3 - name: Install stable toolchain - uses: actions-rs/toolchain@v1 + uses: helix-editor/rust-toolchain@v1 with: profile: minimal - toolchain: stable override: true - uses: Swatinem/rust-cache@v1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d6bb52ce1..bfafd7ed8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,6 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable override: true - uses: Swatinem/rust-cache@v1 From aa87adf54b0b8dec07baa257aed71d09c3efb119 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 21 May 2022 20:49:06 -0500 Subject: [PATCH 236/861] pin the rust toolchain to 1.61.0 1.61.0 in particular introduced new clippy lints that unexpectedly failed CI until addressed. The lints are a bit tough to fix since the toolchain action starts using new rust versions almost immediately after release, so if you aren't using rustup, you may have a hard time reproducing the lint results until your package manager updates rust. This brings an extra burden that we have to remember to make a commit/PR to update rust in CI. --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 79f6f8f65..b169d31e6 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "stable" +channel = "1.61.0" components = ["rustfmt", "rust-src"] From 92df5a542509e49a5ff71087b65fca2a17d5d25e Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 21 May 2022 21:27:08 -0500 Subject: [PATCH 237/861] check MSRV in CI It's very easy to use new rust features without realizing it since the CI and local development workflows may use the latest rust version. We try to keep some backwards compatibility with rust versions to make packaging easier for some OS-level package-managers like Void Linux's. See #1881. This change runs the "Check" step for the pinned version of rust in the rust-toolchain.toml file as well as the MSRV version in a matrix. In order to bump the MSRV, we need to edit .github/workflows/msrv-rust-toolchain.toml This commit sets the MSRV as 1.60.0 but a later child commit will reduce the MSRV back to 1.57.0. Closes #2482. --- .github/workflows/build.yml | 11 +++++++++-- .github/workflows/msrv-rust-toolchain.toml | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/msrv-rust-toolchain.toml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f3cd128a9..1368d1bc4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,10 +11,17 @@ jobs: check: name: Check runs-on: ubuntu-latest + strategy: + matrix: + rust: [stable, msrv] steps: - name: Checkout sources uses: actions/checkout@v3 + - name: Use MSRV rust toolchain + if: matrix.rust == 'msrv' + run: cp .github/workflows/msrv-rust-toolchain.toml rust-toolchain.toml + - name: Install stable toolchain uses: helix-editor/rust-toolchain@v1 with: @@ -50,8 +57,8 @@ jobs: uses: actions/cache@v3 with: path: runtime/grammars - key: ${{ runner.os }}-v2-tree-sitter-grammars-${{ hashFiles('languages.toml') }} - restore-keys: ${{ runner.os }}-v2-tree-sitter-grammars- + key: ${{ runner.os }}-stable-v${{ env.CACHE_VERSION }}-tree-sitter-grammars-${{ hashFiles('languages.toml') }} + restore-keys: ${{ runner.os }}-stable-v${{ env.CACHE_VERSION }}-tree-sitter-grammars- - name: Run cargo test uses: actions-rs/cargo@v1 diff --git a/.github/workflows/msrv-rust-toolchain.toml b/.github/workflows/msrv-rust-toolchain.toml new file mode 100644 index 000000000..958edb457 --- /dev/null +++ b/.github/workflows/msrv-rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.60.0" +components = ["rustfmt", "rust-src"] From 89c0998aee1717dff8b6afe712e52b576c496257 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 22 May 2022 19:13:10 -0500 Subject: [PATCH 238/861] lower MSRV to 1.57.0 This line uses the Display trait for io::ErrorKind which was stabilized in Rust 1.60.0. We can set MSRV all the way back to 1.57.0 by replacing it with a pretty-print. Closes #2460. --- .github/workflows/msrv-rust-toolchain.toml | 2 +- helix-view/src/handlers/dap.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/msrv-rust-toolchain.toml b/.github/workflows/msrv-rust-toolchain.toml index 958edb457..ece2fa768 100644 --- a/.github/workflows/msrv-rust-toolchain.toml +++ b/.github/workflows/msrv-rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.60.0" +channel = "1.57.0" components = ["rustfmt", "rust-src"] diff --git a/helix-view/src/handlers/dap.rs b/helix-view/src/handlers/dap.rs index c7d3758d6..2ea21f624 100644 --- a/helix-view/src/handlers/dap.rs +++ b/helix-view/src/handlers/dap.rs @@ -302,7 +302,9 @@ impl Editor { .arg(arguments.args.join(" ")) .spawn() .unwrap(), - e => panic!("Error to start debug console: {}", e), + // TODO replace the pretty print {:?} with a regular format {} + // when the MSRV is raised to 1.60.0 + e => panic!("Error to start debug console: {:?}", e), }) } else { std::process::Command::new("tmux") From d6865cdca3c49eea9dd5bde54a7006ff6366331c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Tue, 24 May 2022 09:37:17 +0900 Subject: [PATCH 239/861] nix: bump dependencies --- flake.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index d7ce01257..8fb4a4667 100644 --- a/flake.lock +++ b/flake.lock @@ -25,11 +25,11 @@ ] }, "locked": { - "lastModified": 1650900878, - "narHash": "sha256-qhNncMBSa9STnhiLfELEQpYC1L4GrYHNIzyCZ/pilsI=", + "lastModified": 1652959711, + "narHash": "sha256-wpQhlE/NocxlU3jLiMoF1KYHOEFD5MEFJZkyXXVVef8=", "owner": "numtide", "repo": "devshell", - "rev": "d97df53b5ddaa1cfbea7cddbd207eb2634304733", + "rev": "a5327cd01e58d2848c73062f2661278ad615748f", "type": "github" }, "original": { @@ -75,11 +75,11 @@ ] }, "locked": { - "lastModified": 1651844867, - "narHash": "sha256-a+bAmmeIudRVY23ZkEB5W5xJumBY3ydsiDIGN/56NmQ=", + "lastModified": 1653135531, + "narHash": "sha256-pYwJrEQrG8BgeVcI+lveK3KbOBDx9MT28HxV09v+jgI=", "owner": "nix-community", "repo": "dream2nix", - "rev": "e5d0e9cdb00695b0b63d1f52ff3b39c0e3035fe3", + "rev": "4b3dfb101fd2fdbe25bd128072f138276aa4bc82", "type": "github" }, "original": { @@ -130,11 +130,11 @@ ] }, "locked": { - "lastModified": 1652163169, - "narHash": "sha256-WgFpNZgwqQOEkJJfA6z0NBL5+U/oMV3fT/j5TNERoYY=", + "lastModified": 1653286465, + "narHash": "sha256-CEI2prA74sy9SgAJKdDpyAMv1nnp91c8e5Fw9QbtR/Q=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "f5719d90394a624549a00f01c76f6ef3ed079bb3", + "rev": "95efd76ab68b20aba45b7d647460319b88c2a4c0", "type": "github" }, "original": { @@ -145,11 +145,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1652172129, - "narHash": "sha256-8e2JMrswaKe02P8rYfvIMoc59pNuw6h/GYu8DBE1c+0=", + "lastModified": 1653060744, + "narHash": "sha256-kfRusllRumpt33J1hPV+CeCCylCXEU7e0gn2/cIM7cY=", "owner": "nixos", "repo": "nixpkgs", - "rev": "f419dc5763c2b3c5580e396dea065b6d8b58ee27", + "rev": "dfd82985c273aac6eced03625f454b334daae2e8", "type": "github" }, "original": { @@ -174,11 +174,11 @@ ] }, "locked": { - "lastModified": 1652149774, - "narHash": "sha256-rms5yNnnlmaqzEnI/9Log+5k/yVz4fB1BUVx5HXf8i8=", + "lastModified": 1653273659, + "narHash": "sha256-dHXYaNL1axhZZyiZXxt1WKhvZrYXq7bjCs3y5VjgyGI=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "1dcdd08fcd39e4e053f58f9959be801399c5211e", + "rev": "0fa3e01da1ce98e3b40063b8e2678095943402b1", "type": "github" }, "original": { From c429ed660f62e59f0c00115efd03543f3ae3ba8f Mon Sep 17 00:00:00 2001 From: Isotoxal <62714538+IsotoxalDev@users.noreply.github.com> Date: Tue, 24 May 2022 19:32:26 +0530 Subject: [PATCH 240/861] Add Catppuccin Theme (#2546) Co-authored-by: Michael Davis --- runtime/themes/catpuccin.toml | 93 +++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 runtime/themes/catpuccin.toml diff --git a/runtime/themes/catpuccin.toml b/runtime/themes/catpuccin.toml new file mode 100644 index 000000000..1b27eaefa --- /dev/null +++ b/runtime/themes/catpuccin.toml @@ -0,0 +1,93 @@ +attribute = "blue" +keyword = "blue" +"keyword.directive" = "red" # -- preprocessor comments (#if in C) +namespace = "peach" +punctuation = "white" +"punctuation.delimiter" = "blue" +operator = "blue" +special = "peach" +"variable.other.member" = "green" +variable = "peach" +"variable.parameter" = { fg = "pink" } +"variable.builtin" = "green" +type = "blue" +"type.builtin" = "white" +constructor = "blue" +function = "red" +"function.macro" = "green" +"function.builtin" = "blue" +tag = "peach" +comment = "gray_1" +constant = "white" +"constant.builtin" = "green" +string = "green" +"constant.numeric" = "blue" +"constant.character.escape" = "peach" +# used for lifetimes +label = "peach" + +"markup.heading" = "mauve" +"markup.bold" = { modifiers = ["bold"] } +"markup.italic" = { modifiers = ["italic"] } +"markup.link.url" = { fg = "gray_2", modifiers = ["underlined"] } +"markup.link.text" = "peach" +"markup.raw" = "peach" + +"diff.plus" = "#35bf86" +"diff.minus" = "#f22c86" +"diff.delta" = "#6f44f0" + +"ui.background" = { bg = "black_2" } +"ui.linenr" = { fg = "gray_0" } +"ui.linenr.selected" = { fg = "mauve" } +"ui.statusline" = { fg = "black_2", bg = "blue" } +"ui.statusline.inactive" = { fg = "pink", bg = "gray_1" } +"ui.popup" = { bg = "black_2" } +"ui.window" = { fg = "maroon" } +"ui.help" = { bg = "#7958DC", fg = "#171452" } + +"ui.text" = { fg = "pink" } +"ui.text.focus" = { fg = "white" } +"ui.virtual" = { fg = "gray_0" } + +"ui.selection" = { bg = "#540099" } +"ui.selection.primary" = { bg = "#540099" } +"ui.cursor.select" = { bg = "lavender" } +"ui.cursor.insert" = { bg = "white" } +"ui.cursor.match" = { fg = "#212121", bg = "#6C6999" } +"ui.cursor" = { modifiers = ["reversed"] } +"ui.highlight" = { bg = "maroon" } + +"ui.menu.selected" = { fg = "gray_1", bg = "white" } + +diagnostic = { modifiers = ["underlined"] } + +warning = "lightning" +error = "apricot" +info = "delta" +hint = "silver" + +[palette] +flamingo = "#F2CDCD" +mauve = "#DDB6F2" +pink = "#F5C2E7" +maroon = "#E8A2AF" +red = "#F28FAD" +peach = "#F8BD96" +yellow = "#FAE3B0" +green = "#ABE9B3" +teal = "#B5E8E0" +blue = "#96CDFB" +sky = "#89DCEB" + +black_0 = "#161320" +black_1 = "#1A1826" +black_2 = "#1E1E2E" +black_3 = "#302D41" +black_4 = "#575268" +gray_0 = "#6E6C7E" +gray_1 = "#988BA2" +gray_2 = "#C3BAC6" +white = "#D9E0EE" +lavender = "#C9CBFF" +rosewater = "#F5E0DC" From 386dccc84ed4cdeea6a9aed727c04bbb0facc374 Mon Sep 17 00:00:00 2001 From: Erasin Date: Tue, 24 May 2022 23:03:53 +0800 Subject: [PATCH 241/861] Add lua lsp (#2560) --- book/src/generated/lang-support.md | 2 +- languages.toml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index df4d36b5c..908021cf0 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -50,7 +50,7 @@ | llvm | ✓ | ✓ | ✓ | | | llvm-mir | ✓ | ✓ | ✓ | | | llvm-mir-yaml | ✓ | | ✓ | | -| lua | ✓ | | ✓ | | +| lua | ✓ | | ✓ | `lua-language-server` | | make | ✓ | | | | | markdown | ✓ | | | | | meson | ✓ | | ✓ | | diff --git a/languages.toml b/languages.toml index d3c4ef435..2c79b9770 100644 --- a/languages.toml +++ b/languages.toml @@ -605,9 +605,10 @@ name = "lua" scope = "source.lua" file-types = ["lua"] shebangs = ["lua"] -roots = [] +roots = [".luarc.json", ".luacheckrc", ".stylua.toml", "selene.toml", ".git"] comment-token = "--" indent = { tab-width = 2, unit = " " } +language-server = { command = "lua-language-server", args = [] } [[grammar]] name = "lua" From 67fe16008e60893e1dfc9ef237c2421ebb703841 Mon Sep 17 00:00:00 2001 From: Andrey Tkachenko Date: Tue, 24 May 2022 21:52:32 +0400 Subject: [PATCH 242/861] Basic verilog support (#2552) --- book/src/generated/lang-support.md | 1 + languages.toml | 14 ++ runtime/queries/verilog/highlights.scm | 311 ++++++++++++++++++++++++ runtime/queries/verilog/injections.scm | 2 + runtime/queries/verilog/locals.scm | 61 +++++ runtime/queries/verilog/textobjects.scm | 6 + 6 files changed, 395 insertions(+) create mode 100644 runtime/queries/verilog/highlights.scm create mode 100644 runtime/queries/verilog/injections.scm create mode 100644 runtime/queries/verilog/locals.scm create mode 100644 runtime/queries/verilog/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 908021cf0..e47ccbc4d 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -90,6 +90,7 @@ | twig | ✓ | | | | | typescript | ✓ | | ✓ | `typescript-language-server` | | vala | ✓ | | | `vala-language-server` | +| verilog | ✓ | ✓ | | `svlangserver` | | vue | ✓ | | | `vls` | | wgsl | ✓ | | | | | yaml | ✓ | | ✓ | `yaml-language-server` | diff --git a/languages.toml b/languages.toml index 2c79b9770..16e78a9b1 100644 --- a/languages.toml +++ b/languages.toml @@ -1380,3 +1380,17 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "scheme" source = { git = "https://github.com/6cdh/tree-sitter-scheme", rev = "27fb77db05f890c2823b4bd751c6420378df146b" } + +[[language]] +name = "verilog" +scope = "source.verilog" +file-types = ["v", "sv", "svh"] +roots = [] +comment-token = "//" +language-server = { command = "svlangserver", args = [] } +indent = { tab-width = 2, unit = " " } +injection-regex = "verilog" + +[[grammar]] +name = "verilog" +source = { git = "https://github.com/andreytkachenko/tree-sitter-verilog", rev = "514d8d70593d29ef3ef667fa6b0e504ae7c977e3" } diff --git a/runtime/queries/verilog/highlights.scm b/runtime/queries/verilog/highlights.scm new file mode 100644 index 000000000..97ec06e3a --- /dev/null +++ b/runtime/queries/verilog/highlights.scm @@ -0,0 +1,311 @@ +; Keywords + +[ + ; block delimeters + (module_keyword) + "endmodule" + "program" + "endprogram" + "class" + "endclass" + "interface" + "endinterface" + "package" + "endpackage" + "checker" + "endchecker" + "config" + "endconfig" + + "pure" + "virtual" + "extends" + "implements" + "super" + (class_item_qualifier) + + "parameter" + "localparam" + "defparam" + "assign" + "typedef" + "modport" + "fork" + "join" + "join_none" + "join_any" + "default" + "break" + "assert" + (unique_priority) + "tagged" + "extern" +] @keyword + +[ + "function" + "endfunction" + + "task" + "endtask" +] @keyword.function + +"return" @keyword.control.return + +[ + "begin" + "end" +] @label + +[ + (always_keyword) + "generate" + "for" + "foreach" + "repeat" + "forever" + "initial" + "while" +] @keyword.control + +[ + "if" + "else" + (case_keyword) + "endcase" +] @keyword.control.conditional + +(comment) @comment + +(include_compiler_directive) @keyword.directive +(package_import_declaration + "import" @keyword.control.import) + +(package_import_declaration + (package_import_item + (package_identifier + (simple_identifier) @constant))) + +(text_macro_identifier + (simple_identifier) @keyword.directive) + +(package_scope + (package_identifier + (simple_identifier) @constant)) + +(package_declaration + (package_identifier + (simple_identifier) @constant)) + +(parameter_port_list + "#" @constructor) + +[ + "=" + "-" + "+" + "/" + "*" + "^" + "&" + "|" + "&&" + "||" + ":" + (unary_operator) + "{" + "}" + "'{" + "<=" + "@" + "or" + "and" + "==" + "!=" + "===" + "!==" + "-:" + "<" + ">" + ">=" + "%" + ">>" + "<<" + "|=" + (inc_or_dec_operator) +] @keyword.operator + +(cast + ["'" "(" ")"] @keyword.operator) + +(edge_identifier) @constant + +(port_direction) @label +(port_identifier + (simple_identifier) @variable) + +[ + (net_type) + (integer_vector_type) + (integer_atom_type) +] @type.builtin + +[ + "signed" + "unsigned" +] @label + +(data_type + (simple_identifier) @type) + +(method_call_body + (method_identifier) @variable.other.member) + +(interface_identifier + (simple_identifier) @type) + +(modport_identifier + (modport_identifier + (simple_identifier) @variable.other.member)) + +(net_port_type1 + (simple_identifier) @type) + +[ + (double_quoted_string) + (string_literal) +] @string + +[ + (include_compiler_directive) + (default_nettype_compiler_directive) + (timescale_compiler_directive) +] @keyword.directive + +; begin/end label +(seq_block + (simple_identifier) @comment) + +[ + ";" + "::" + "," + "." +] @punctuation.delimiter + + +(default_nettype_compiler_directive + (default_nettype_value) @string) + +(text_macro_identifier + (simple_identifier) @function.macro) + +(module_declaration + (module_header + (simple_identifier) @constructor)) + +(class_constructor_declaration + "new" @constructor) + +(parameter_identifier + (simple_identifier) @variable.parameter) + +[ + (integral_number) + (unsigned_number) + (unbased_unsized_literal) +] @constant.numeric + +(time_unit) @constant + +(checker_instantiation + (checker_identifier + (simple_identifier) @constructor)) + +(module_instantiation + (simple_identifier) @constructor) + +(name_of_instance + (instance_identifier + (simple_identifier) @variable)) + +(interface_port_declaration + (interface_identifier + (simple_identifier) @type)) + +(net_declaration + (simple_identifier) @type) + +(lifetime) @label + +(function_identifier + (function_identifier + (simple_identifier) @function)) + +(function_subroutine_call + (subroutine_call + (tf_call + (simple_identifier) @function))) + +(function_subroutine_call + (subroutine_call + (system_tf_call + (system_tf_identifier) @function.builtin))) + +(task_identifier + (task_identifier + (simple_identifier) @function.method)) + +;;TODO: fixme +;(assignment_pattern_expression + ;(assignment_pattern + ;(parameter_identifier) @variable.other.member)) + +(type_declaration + (data_type ["packed"] @label)) + +(struct_union) @type + +[ + "enum" +] @type + +(enum_name_declaration + (enum_identifier + (simple_identifier) @constant)) + +(type_declaration + (simple_identifier) @type) + +[ + (integer_atom_type) + (non_integer_type) + "genvar" +] @type.builtin + +(struct_union_member + (list_of_variable_decl_assignments + (variable_decl_assignment + (simple_identifier) @variable.other.member))) + +(member_identifier + (simple_identifier) @variable.other.member) + +(struct_union_member + (data_type_or_void + (data_type + (simple_identifier) @type))) + +(type_declaration + (simple_identifier) @type) + +(generate_block_identifier) @comment + +[ + "[" + "]" + "(" + ")" +] @punctuation.bracket + +(ERROR) @error diff --git a/runtime/queries/verilog/injections.scm b/runtime/queries/verilog/injections.scm new file mode 100644 index 000000000..30804d652 --- /dev/null +++ b/runtime/queries/verilog/injections.scm @@ -0,0 +1,2 @@ +((comment) @injection.content + (#set! injection.language "comment")) \ No newline at end of file diff --git a/runtime/queries/verilog/locals.scm b/runtime/queries/verilog/locals.scm new file mode 100644 index 000000000..507ddea44 --- /dev/null +++ b/runtime/queries/verilog/locals.scm @@ -0,0 +1,61 @@ +[ + (loop_generate_construct) + (loop_statement) + (conditional_statement) + (case_item) + (function_declaration) + (always_construct) + (module_declaration) +] @scope + +(data_declaration + (list_of_variable_decl_assignments + (variable_decl_assignment + (simple_identifier) @definition.var))) + +(genvar_initialization + (genvar_identifier + (simple_identifier) @definition.var)) + +(for_initialization + (for_variable_declaration + (simple_identifier) @definition.var)) + +(net_declaration + (list_of_net_decl_assignments + (net_decl_assignment + (simple_identifier) @definition.var))) + +(ansi_port_declaration + (port_identifier + (simple_identifier) @definition.var)) + +(parameter_declaration + (list_of_param_assignments + (param_assignment + (parameter_identifier + (simple_identifier) @definition.parameter)))) + +(local_parameter_declaration + (list_of_param_assignments + (param_assignment + (parameter_identifier + (simple_identifier) @definition.parameter)))) + +;; TODO: fixme +;(function_declaration + ;(function_identifier + ;(simple_identifier) @definition.function)) + +(function_declaration + (function_body_declaration + (function_identifier + (function_identifier + (simple_identifier) @definition.function)))) + +(tf_port_item1 + (port_identifier + (simple_identifier) @definition.parameter)) + +; too broad, now includes types etc +(simple_identifier) @reference diff --git a/runtime/queries/verilog/textobjects.scm b/runtime/queries/verilog/textobjects.scm new file mode 100644 index 000000000..3b1c0fe50 --- /dev/null +++ b/runtime/queries/verilog/textobjects.scm @@ -0,0 +1,6 @@ + +(function_declaration + (function_body_declaration + (function_identifier + (function_identifier + (simple_identifier) @function.inside)))) @funtions.around \ No newline at end of file From a13ff27023832ae8c2ac565da825caab8bc024d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 23:14:05 +0000 Subject: [PATCH 243/861] build(deps): bump regex from 1.5.5 to 1.5.6 Bumps [regex](https://github.com/rust-lang/regex) from 1.5.5 to 1.5.6. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.5.5...1.5.6) --- updated-dependencies: - dependency-name: regex dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 466f500ce..12689d87e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -826,9 +826,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.5" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "aho-corasick", "memchr", @@ -843,9 +843,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] name = "retain_mut" From da2952725880d132fdfc2117dedebfe56ffdb646 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 23:13:58 +0000 Subject: [PATCH 244/861] build(deps): bump once_cell from 1.10.0 to 1.12.0 Bumps [once_cell](https://github.com/matklad/once_cell) from 1.10.0 to 1.12.0. - [Release notes](https://github.com/matklad/once_cell/releases) - [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md) - [Commits](https://github.com/matklad/once_cell/compare/v1.10.0...v1.12.0) --- updated-dependencies: - dependency-name: once_cell dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- helix-core/Cargo.toml | 2 +- helix-loader/Cargo.toml | 2 +- helix-term/Cargo.toml | 2 +- helix-view/Cargo.toml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12689d87e..47d89bcf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -703,9 +703,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "parking_lot" diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 9973516b5..8d6a343f7 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -25,7 +25,7 @@ unicode-general-category = "0.5" # slab = "0.4.2" slotmap = "1.0" tree-sitter = "0.20" -once_cell = "1.10" +once_cell = "1.12" arc-swap = "1" regex = "1" diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index 3a900f4ac..aee03fc29 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -15,7 +15,7 @@ serde = { version = "1.0", features = ["derive"] } toml = "0.5" etcetera = "0.4" tree-sitter = "0.20" -once_cell = "1.9" +once_cell = "1.12" log = "0.4" diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 706453ae6..9be29b0f3 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -30,7 +30,7 @@ helix-dap = { version = "0.6", path = "../helix-dap" } helix-loader = { version = "0.6", path = "../helix-loader" } anyhow = "1" -once_cell = "1.10" +once_cell = "1.12" which = "4.2" ropey = { version = "1.4", default-features = false } diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index ce3f1af4b..77634ce58 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -22,7 +22,7 @@ helix-dap = { version = "0.6", path = "../helix-dap" } crossterm = { version = "0.23", optional = true } # Conversion traits -once_cell = "1.10" +once_cell = "1.12" url = "2" arc-swap = { version = "1.5.0" } From 10463fe32c789f49c65d53c9d22621e415a854ea Mon Sep 17 00:00:00 2001 From: Andrey Tkachenko Date: Mon, 23 May 2022 16:24:30 +0400 Subject: [PATCH 245/861] Add `parameter.around` text object query --- runtime/queries/c/textobjects.scm | 6 +++++- runtime/queries/go/textobjects.scm | 7 +++++-- runtime/queries/php/textobjects.scm | 12 +++++++++--- runtime/queries/python/textobjects.scm | 6 +++--- runtime/queries/rust/textobjects.scm | 15 +++++++++------ 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/runtime/queries/c/textobjects.scm b/runtime/queries/c/textobjects.scm index 45f554e28..2a3da66f3 100644 --- a/runtime/queries/c/textobjects.scm +++ b/runtime/queries/c/textobjects.scm @@ -10,7 +10,11 @@ (union_specifier body: (_) @class.inside) @class.around -(parameter_declaration) @parameter.inside +(parameter_list + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +(argument_list + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) (comment) @comment.inside diff --git a/runtime/queries/go/textobjects.scm b/runtime/queries/go/textobjects.scm index 3cdf62037..a48ccce18 100644 --- a/runtime/queries/go/textobjects.scm +++ b/runtime/queries/go/textobjects.scm @@ -14,11 +14,14 @@ (type_declaration (type_spec (type_identifier) (interface_type (method_spec)+ @class.inside))) @class.around +(type_parameter_list + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + (parameter_list - (_) @parameter.inside) + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) (argument_list - (_) @parameter.inside) + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) (comment) @comment.inside diff --git a/runtime/queries/php/textobjects.scm b/runtime/queries/php/textobjects.scm index 51abe5c7d..e35eebd76 100644 --- a/runtime/queries/php/textobjects.scm +++ b/runtime/queries/php/textobjects.scm @@ -21,13 +21,19 @@ (anonymous_function_creation_expression body: (_) @function.inside) @function.around - + +(anonymous_function_use_clause + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + (formal_parameters - [ + ([ (simple_parameter) (variadic_parameter) (property_promotion_parameter) - ] @parameter.inside) + ] @parameter.inside . ","? @parameter.around) @parameter.around) + +(arguments + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) (comment) @comment.inside diff --git a/runtime/queries/python/textobjects.scm b/runtime/queries/python/textobjects.scm index 0ca260890..5c6a61d17 100644 --- a/runtime/queries/python/textobjects.scm +++ b/runtime/queries/python/textobjects.scm @@ -5,13 +5,13 @@ body: (block)? @class.inside) @class.around (parameters - (_) @parameter.inside) + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) (lambda_parameters - (_) @parameter.inside) + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) (argument_list - (_) @parameter.inside) + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) (comment) @comment.inside diff --git a/runtime/queries/rust/textobjects.scm b/runtime/queries/rust/textobjects.scm index 99b5eb4d9..b2769c139 100644 --- a/runtime/queries/rust/textobjects.scm +++ b/runtime/queries/rust/textobjects.scm @@ -52,17 +52,20 @@ (impl_item body: (_) @class.inside)) @class.around -(parameters - (_) @parameter.inside) - +(parameters + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + (type_parameters - (_) @parameter.inside) + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +(type_arguments + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) (closure_parameters - (_) @parameter.inside) + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) (arguments - (_) @parameter.inside) + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) [ (line_comment) From 45dd54082e4dde74b7d344c6bb8a4ff2a09e627e Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 17 May 2022 14:31:39 -0500 Subject: [PATCH 246/861] update Gleam grammar and queries With respect to the queries: The locals scope for functions was not large enough, so a function's parameter could outlive the function body. To fix it, we just widen the scope to the `function` node. See also https://github.com/gleam-lang/tree-sitter-gleam/issues/25 With respect to the parser: An external scanner has been added that fixes the parsing of strings. Previously, a comment inside a string would act like a comment rather than string contents. See also https://github.com/gleam-lang/tree-sitter-gleam/issues/14#issuecomment-1129263640 A new constructor node has been added as well which makes type highlighting more fine grained. See also https://github.com/gleam-lang/tree-sitter-gleam/pull/29 --- languages.toml | 2 +- runtime/queries/gleam/highlights.scm | 5 +++++ runtime/queries/gleam/locals.scm | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/languages.toml b/languages.toml index 16e78a9b1..b1984fb52 100644 --- a/languages.toml +++ b/languages.toml @@ -1127,7 +1127,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "gleam" -source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "7159ce961592192b0e7cdf88782cda0fdf41a4cb" } +source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "d7861b2a4b4d594c58bb4f1be5f1f4ee4c67e5c3" } [[language]] name = "ron" diff --git a/runtime/queries/gleam/highlights.scm b/runtime/queries/gleam/highlights.scm index ed3fcecad..8cff6b51d 100644 --- a/runtime/queries/gleam/highlights.scm +++ b/runtime/queries/gleam/highlights.scm @@ -12,6 +12,8 @@ (import alias: (identifier) @namespace) (remote_type_identifier module: (identifier) @namespace) +(remote_constructor_name + module: (identifier) @namespace) ((field_access record: (identifier) @namespace field: (label) @function) @@ -45,6 +47,9 @@ (remote_type_identifier) @type (type_identifier) @type +; Data constructors +(constructor_name) @constructor + ; Literals (string) @string (bit_string_segment_option) @function.builtin diff --git a/runtime/queries/gleam/locals.scm b/runtime/queries/gleam/locals.scm index bd5903e56..493005739 100644 --- a/runtime/queries/gleam/locals.scm +++ b/runtime/queries/gleam/locals.scm @@ -1,5 +1,5 @@ ; Scopes -(function_body) @local.scope +(function) @local.scope (case_clause) @local.scope From 82da9bd4f28cd2a050222173d6429478bed5b3cb Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 17 May 2022 14:38:34 -0500 Subject: [PATCH 247/861] update Erlang grammar and queries The update to the grammar itself covers the case where the document is a single expression without a trailing newline such as "min(A, B)". A small change to the parser now parses these expressions correctly which improves the display of the function head in the signature help popup. The update to the queries marks 'andalso', 'orelse', 'not', etc. as `@keyword.operator` which improves the look - it looks odd to see operators that are words highlighted the same as tokens like '->' or '=:='. --- languages.toml | 2 +- runtime/queries/erlang/highlights.scm | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index b1984fb52..e2bf26bf4 100644 --- a/languages.toml +++ b/languages.toml @@ -1049,7 +1049,7 @@ language-server = { command = "erlang_ls" } [[grammar]] name = "erlang" -source = { git = "https://github.com/the-mikedavis/tree-sitter-erlang", rev = "3f611cfdc790214c3f9f9cf1658b3ae8039c54b8" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-erlang", rev = "6cd8f956ada445b277de1581b5328ae8e8be9aac" } [[language]] name = "kotlin" diff --git a/runtime/queries/erlang/highlights.scm b/runtime/queries/erlang/highlights.scm index 1e0753497..bea3871a6 100644 --- a/runtime/queries/erlang/highlights.scm +++ b/runtime/queries/erlang/highlights.scm @@ -85,6 +85,11 @@ operator: "/" right: (integer) @constant.numeric.integer) +((binary_operator operator: _ @keyword.operator) + (#match? @keyword.operator "^\\w+$")) +((unary_operator operator: _ @keyword.operator) + (#match? @keyword.operator "^\\w+$")) + (binary_operator operator: _ @operator) (unary_operator operator: _ @operator) ["/" ":" "#" "->"] @operator From 7160e745f72e5d742e19fecf9a7e78f32e5b34da Mon Sep 17 00:00:00 2001 From: Ben Lee-Cohen Date: Tue, 24 May 2022 14:54:08 -0400 Subject: [PATCH 248/861] Changing Macro color to avoid color confusion I noticed that in Rust, `println!`being a macro, it matched the color of string literals. This was visually confusing to me, so I checked what the nvim catpuccin theme (https://github.com/catppuccin/nvim) does. While it is pretty different, it does use different colors for strings and all function types: https://share.cleanshot.com/RLG2y1 I don't know if blue or red makes more sense given the other syntax choices, but wanted to propose this change cc @IsotoxalDev --- runtime/themes/catpuccin.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/catpuccin.toml b/runtime/themes/catpuccin.toml index 1b27eaefa..f7f113279 100644 --- a/runtime/themes/catpuccin.toml +++ b/runtime/themes/catpuccin.toml @@ -14,7 +14,7 @@ type = "blue" "type.builtin" = "white" constructor = "blue" function = "red" -"function.macro" = "green" +"function.macro" = "blue" "function.builtin" = "blue" tag = "peach" comment = "gray_1" From efae76160d19ebba2bba31ecd5c104374c7b4483 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 25 May 2022 20:39:58 -0500 Subject: [PATCH 249/861] add section on syntax tree motions to the usage docs (#2568) --- book/src/usage.md | 72 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/book/src/usage.md b/book/src/usage.md index 7871e2b9e..ad21a94c9 100644 --- a/book/src/usage.md +++ b/book/src/usage.md @@ -51,6 +51,78 @@ It can also act on multiple selections (yay!). For example, to change every occu Multiple characters are currently not supported, but planned. +## Syntax-tree Motions + +`A-p`, `A-o`, `A-i`, and `A-n` (or `Alt` and arrow keys) move the primary +selection according to the selection's place in the syntax tree. Let's walk +through an example to get familiar with them. Many languages have a syntax like +so for function calls: + +``` +func(arg1, arg2, arg3) +``` + +A function call might be parsed by tree-sitter into a tree like the following. + +```tsq +(call + function: (identifier) ; func + arguments: + (arguments ; (arg1, arg2, arg3) + (identifier) ; arg1 + (identifier) ; arg2 + (identifier))) ; arg3 +``` + +Use `:tree-sitter-subtree` to view the syntax tree of the primary selection. In +a more intuitive tree format: + +``` + ┌────┐ + │call│ + ┌─────┴────┴─────┐ + │ │ +┌─────▼────┐ ┌────▼────┐ +│identifier│ │arguments│ +│ "func" │ ┌────┴───┬─────┴───┐ +└──────────┘ │ │ │ + │ │ │ + ┌─────────▼┐ ┌────▼─────┐ ┌▼─────────┐ + │identifier│ │identifier│ │identifier│ + │ "arg1" │ │ "arg2" │ │ "arg3" │ + └──────────┘ └──────────┘ └──────────┘ +``` + +Say we have a selection that wraps `arg1`. The selection is on the `arg1` leaf +in the tree above. + +``` +func([arg1], arg2, arg3) +``` + +Using `A-n` would select the next sibling in the syntax tree: `arg2`. + +``` +func(arg1, [arg2], arg3) +``` + +While `A-o` would expand the selection to the parent node. In the tree above we +can see that we would select the `arguments` node. + +``` +func[(arg1, arg2, arg3)] +``` + +There is also some nuanced behavior that prevents you from getting stuck on a +node with no sibling. If we have a selection on `arg1`, `A-p` would bring us +to the previous child node. Since `arg1` doesn't have a sibling to its left, +though, we climb the syntax tree and then take the previous selection. So `A-p` +will move the selection over to the "func" `identifier`. + +``` +[func](arg1, arg2, arg3) +``` + ## Textobjects Currently supported: `word`, `surround`, `function`, `class`, `parameter`. From 46f9320709400423ff7947b8aa2c140a63a1cb5b Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 28 May 2022 09:18:15 -0500 Subject: [PATCH 250/861] add 22.05 changelog notes (#2584) --- CHANGELOG.md | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbc7dec28..5b50bf699 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,188 @@ +# 22.05 (2022-05-28) + +An even bigger shout out than usual to all the contributors - we had a whopping +110 contributors in this release! That's more than double the number of +contributors as last release! + +Check out some of the highlights in the [news section](https://helix-editor.com/news/release-22-05-highlights/). + +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.03..22.05). + +Breaking Changes: + +- Removed `C-j`, `C-k` bindings from file picker ([#1792](https://github.com/helix-editor/helix/pull/1792)) +- Replaced `C-f` with `C-d` and `C-b` with `C-u` bindings in file picker ([#1792](https://github.com/helix-editor/helix/pull/1792)) +- `A-hjkl` bindings have been moved to `A-pion` ([#2205](https://github.com/helix-editor/helix/pull/2205)) +- `A-Left`/`A-Right` have been moved to `C-Left`/`C-Right` ([#2193](https://github.com/helix-editor/helix/pull/2193)) + +Features: + +- The indentation mechanism has been reworked ([#1562](https://github.com/helix-editor/helix/pull/1562), [#1908](https://github.com/helix-editor/helix/pull/1908)) +- Configurable gutters ([#1967](https://github.com/helix-editor/helix/pull/1967)) +- Support for local language configuration ([#1249](https://github.com/helix-editor/helix/pull/1249)) +- Configurable themed rulers ([#2060](https://github.com/helix-editor/helix/pull/2060)) +- Render visible whitespace ([e6b865e](https://github.com/helix-editor/helix/commit/e6b865e), [#2322](https://github.com/helix-editor/helix/pull/2322), [#2331](https://github.com/helix-editor/helix/pull/2331)) + +Commands: + +- Paragraph motion and textobject (`]p`, `[p`) ([#1627](https://github.com/helix-editor/helix/pull/1627), [#1956](https://github.com/helix-editor/helix/pull/1956), [#1969](https://github.com/helix-editor/helix/pull/1969), [#1992](https://github.com/helix-editor/helix/pull/1992), [#2226](https://github.com/helix-editor/helix/pull/2226)) +- `:buffer-next`, `:buffer-previous` ([#1940](https://github.com/helix-editor/helix/pull/1940)) +- `:set-language` to set the buffers language ([#1866](https://github.com/helix-editor/helix/pull/1866), [#1996](https://github.com/helix-editor/helix/pull/1996)) +- Command for picking files from the current working directory (`Space-F`) ([#1600](https://github.com/helix-editor/helix/pull/1600), [#2308](https://github.com/helix-editor/helix/pull/2308)) +- `:write!` which creates non-existent subdirectories ([#1839](https://github.com/helix-editor/helix/pull/1839)) +- Add `m` textobject that selects closest surrounding pair ([de15d70](https://github.com/helix-editor/helix/commit/de15d70), [76175db](https://github.com/helix-editor/helix/commit/76175db)) +- `:pipe` typable command for piping selections ([#1972](https://github.com/helix-editor/helix/pull/1972)) +- `extend_line_above` which extends to previous lines ([#2117](https://github.com/helix-editor/helix/pull/2117)) +- `set_line_ending` which replaces line endings ([#1871](https://github.com/helix-editor/helix/pull/1871)) +- `:get-option` for getting the current value of an option (`:get`) ([#2231](https://github.com/helix-editor/helix/pull/2231)) +- `:run-shell-command` which does not interact with selections ([#1682](https://github.com/helix-editor/helix/pull/1682)) +- `:reflow` which hard-wraps selected text ([#2128](https://github.com/helix-editor/helix/pull/2128)) +- `commit_undo_checkpoint` which adds an undo checkpoint ([#2115](https://github.com/helix-editor/helix/pull/2115)) +- `:log-open` which opens the log file ([#2422](https://github.com/helix-editor/helix/pull/2422)) +- `transpose_view` which transposes window splits ([#2461](https://github.com/helix-editor/helix/pull/2461)) +- View-swapping: `swap_view_right`, `swap_view_left`, `swap_view_up`, `swap_view_down` ([#2445](https://github.com/helix-editor/helix/pull/2445)) +- `shrink_to_line_bounds` which shrinks selections to line-bounds ([#2450](https://github.com/helix-editor/helix/pull/2450)) + +Usability improvements and fixes: + +- Handle broken pipes when piping `hx --health` through `head` ([#1876](https://github.com/helix-editor/helix/pull/1876)) +- Fix for `copy_selection` on newlines ([ab7885e](https://github.com/helix-editor/helix/commit/ab7885e), [236c6b7](https://github.com/helix-editor/helix/commit/236c6b7)) +- Use `win32yank` clipboard provider on WSL2 ([#1912](https://github.com/helix-editor/helix/pull/1912)) +- Jump to the next number on the line before incrementing ([#1778](https://github.com/helix-editor/helix/pull/1778)) +- Fix start position of next search ([#1904](https://github.com/helix-editor/helix/pull/1904)) +- Use check and X marks for health check output ([#1918](https://github.com/helix-editor/helix/pull/1918)) +- Clear terminal after switching to alternate screens ([#1944](https://github.com/helix-editor/helix/pull/1944)) +- Fix `toggle_comments` command on multiple selections ([#1882](https://github.com/helix-editor/helix/pull/1882)) +- Apply `ui.gutter` theming to empty gutter spans ([#2032](https://github.com/helix-editor/helix/pull/2032)) +- Use checkboxes in `hx --health` output ([#1947](https://github.com/helix-editor/helix/pull/1947)) +- Pass unmapped keys through prompt regardless of modifiers ([764adbd](https://github.com/helix-editor/helix/commit/764adbd)) +- LSP: pull formatting options from config ([c18de0e](https://github.com/helix-editor/helix/commit/c18de0e)) +- LSP: provide `rootPath` ([84e799f](https://github.com/helix-editor/helix/commit/84e799f)) +- LSP: implement `workspace_folders` ([8adf0c1](https://github.com/helix-editor/helix/commit/8adf0c1)) +- LSP: fix auto-import ([#2088](https://github.com/helix-editor/helix/pull/2088)) +- Send active diagnostic to LSP when requesting code actions ([#2005](https://github.com/helix-editor/helix/pull/2005)) +- Prevent panic when parsing malformed LSP `PublishDiagnostic` ([#2160](https://github.com/helix-editor/helix/pull/2160)) +- Restore document state on completion cancel ([#2096](https://github.com/helix-editor/helix/pull/2096)) +- Only merge top-level array when merging `languages.toml` ([#2145](https://github.com/helix-editor/helix/pull/2145), [#2215](https://github.com/helix-editor/helix/pull/2215)) +- Fix open on multiline selection ([#2161](https://github.com/helix-editor/helix/pull/2161)) +- Allow re-binding `0` if it is not used in a count ([#2174](https://github.com/helix-editor/helix/pull/2174)) +- Fix `ctrl-u` behavior in insert mode ([#1957](https://github.com/helix-editor/helix/pull/1957)) +- Check LSP rename capabilities before sending rename action ([#2203](https://github.com/helix-editor/helix/pull/2203)) +- Register the `publish_diagnostics` LSP capability ([#2241](https://github.com/helix-editor/helix/pull/2241)) +- Fix paste direction for typed paste commands ([#2288](https://github.com/helix-editor/helix/pull/2288)) +- Improve handling of buffer-close ([#1397](https://github.com/helix-editor/helix/pull/1397)) +- Extend the tutor file ([#2133](https://github.com/helix-editor/helix/pull/2133)) +- Treat slashes as word separators in prompts ([#2315](https://github.com/helix-editor/helix/pull/2315)) +- Auto-complete directory members ([#1682](https://github.com/helix-editor/helix/pull/1682)) +- Allow disabling format-on-save as a global editor setting ([#2321](https://github.com/helix-editor/helix/pull/2321)) +- Wrap command palette in overlay ([#2378](https://github.com/helix-editor/helix/pull/2378)) +- Prevent selections from collapsing when inserting newlines ([#2414](https://github.com/helix-editor/helix/pull/2414)) +- Allow configuration of LSP request timeout ([#2405](https://github.com/helix-editor/helix/pull/2405)) +- Use debug console on Windows for DAP terminal ([#2294](https://github.com/helix-editor/helix/pull/2294)) +- Exclude cursor when deleting with `C-w` in insert mode ([#2431](https://github.com/helix-editor/helix/pull/2431)) +- Prevent panics from LSP parsing errors ([7ae6cad](https://github.com/helix-editor/helix/commit/7ae6cad)) +- Prevent panics from LSP responses without requests ([#2475](https://github.com/helix-editor/helix/pull/2475)) +- Fix scroll rate for documentation popups ([#2497](https://github.com/helix-editor/helix/pull/2497)) +- Support inserting into prompts from registers ([#2458](https://github.com/helix-editor/helix/pull/2458)) +- Separate theme scopes for diagnostic types ([#2437](https://github.com/helix-editor/helix/pull/2437)) +- Use `ui.menu` instead of `ui.statusline` for command completion menu theming ([82fb217](https://github.com/helix-editor/helix/commit/82fb217)) +- Panic when reloading a shrunk file ([#2506](https://github.com/helix-editor/helix/pull/2506)) +- Add theme key for picker separator ([#2523](https://github.com/helix-editor/helix/pull/2523)) + +Themes: + +- Remove `ui.text` background from dark_plus ([#1950](https://github.com/helix-editor/helix/pull/1950)) +- Add `boo_berry` ([#1962](https://github.com/helix-editor/helix/pull/1962)) +- Update `dark_plus` markup colors ([#1989](https://github.com/helix-editor/helix/pull/1989)) +- Update `dark_plus` `tag` and `ui.menu.selected` colors ([#2014](https://github.com/helix-editor/helix/pull/2014)) +- Add `dracula_at_night` ([#2008](https://github.com/helix-editor/helix/pull/2008)) +- Improve `dracula` selection theming ([#2077](https://github.com/helix-editor/helix/pull/2077)) +- Remove dim attribute on `onedark` line-number gutter ([#2155](https://github.com/helix-editor/helix/pull/2155)) +- Add `tokyonight` ([#2162](https://github.com/helix-editor/helix/pull/2162)) +- Use border colors from the original `dark_plus` theme ([#2186](https://github.com/helix-editor/helix/pull/2186)) +- Add `autumn` ([#2212](https://github.com/helix-editor/helix/pull/2212), [#2270](https://github.com/helix-editor/helix/pull/2270), [#2531](https://github.com/helix-editor/helix/pull/2531)) +- Add `tokyonight_storm` ([#2240](https://github.com/helix-editor/helix/pull/2240)) +- Add `pop-dark` ([#2240](https://github.com/helix-editor/helix/pull/2240)) +- Fix `base16_terminal` theme using incorrect ansi-color ([#2279](https://github.com/helix-editor/helix/pull/2279)) +- Add `onelight` ([#2287](https://github.com/helix-editor/helix/pull/2287), [#2323](https://github.com/helix-editor/helix/pull/2323)) +- Add `ui.virtual` scopes to `onedark` theme ([3626e38](https://github.com/helix-editor/helix/commit/3626e38)) +- Add `night_owl` ([#2330](https://github.com/helix-editor/helix/pull/2330)) +- Use yellow foreground and red background for `monokai_pro_spectrum` ([#2433](https://github.com/helix-editor/helix/pull/2433)) +- Add `snazzy` ([#2473](https://github.com/helix-editor/helix/pull/2473)) +- Update `dark_plus` constructor color ([8e8d4ba](https://github.com/helix-editor/helix/commit/8e8d4ba)) +- Add `ui.menu` to the default theme ([e7e13dc](https://github.com/helix-editor/helix/commit/e7e13dc)) +- Add `ui.menu` to any themes missing the key ([9be810f](https://github.com/helix-editor/helix/commit/9be810f)) +- Add `catppuccin` ([#2546](https://github.com/helix-editor/helix/pull/2546), [7160e74](https://github.com/helix-editor/helix/commit/7160e74)) + +LSP: + +- Use texlab for latex ([#1922](https://github.com/helix-editor/helix/pull/1922)) +- HTML ([#2018](https://github.com/helix-editor/helix/pull/2018)) +- JSON ([#2024](https://github.com/helix-editor/helix/pull/2024)) +- CSS ([#2025](https://github.com/helix-editor/helix/pull/2025)) +- PHP ([#2031](https://github.com/helix-editor/helix/pull/2031)) +- Swift ([#2033](https://github.com/helix-editor/helix/pull/2033)) +- OCaml ([#2035](https://github.com/helix-editor/helix/pull/2035)) +- Vue ([#2043](https://github.com/helix-editor/helix/pull/2043)) +- Yaml ([#2234](https://github.com/helix-editor/helix/pull/2234)) +- Vala ([#2243](https://github.com/helix-editor/helix/pull/2243)) +- TOML ([#2302](https://github.com/helix-editor/helix/pull/2302)) +- Java ([#2511](https://github.com/helix-editor/helix/pull/2511)) +- Lua ([#2560](https://github.com/helix-editor/helix/pull/2560)) +- Verilog ([#2552](https://github.com/helix-editor/helix/pull/2552)) + +New Languages: + +- JSX ([#1906](https://github.com/helix-editor/helix/pull/1906), [a24fb17](https://github.com/helix-editor/helix/commit/a24fb17), [855e438](https://github.com/helix-editor/helix/commit/855e438), [#1921](https://github.com/helix-editor/helix/pull/1921)) +- Rust Object Notation (RON) ([#1925](https://github.com/helix-editor/helix/pull/1925)) +- R and R Markdown ([#1998](https://github.com/helix-editor/helix/pull/1998)) +- Swift ([#2033](https://github.com/helix-editor/helix/pull/2033)) +- EJS and ERB ([#2055](https://github.com/helix-editor/helix/pull/2055)) +- EEx ([9d095e0](https://github.com/helix-editor/helix/commit/9d095e0)) +- HEEx ([4836bb3](https://github.com/helix-editor/helix/commit/4836bb3), [#2149](https://github.com/helix-editor/helix/pull/2149)) +- SQL ([#2097](https://github.com/helix-editor/helix/pull/2097)) +- GDScript ([#1985](https://github.com/helix-editor/helix/pull/1985)) +- Nickel ([#2173](https://github.com/helix-editor/helix/pull/2173), [#2320](https://github.com/helix-editor/helix/pull/2320)) +- `go.mod` and `go.work` ([#2197](https://github.com/helix-editor/helix/pull/2197)) +- Nushell ([#2225](https://github.com/helix-editor/helix/pull/2225)) +- Vala ([#2243](https://github.com/helix-editor/helix/pull/2243)) +- Hare ([#2289](https://github.com/helix-editor/helix/pull/2289), [#2480](https://github.com/helix-editor/helix/pull/2480)) +- DeviceTree ([#2329](https://github.com/helix-editor/helix/pull/2329)) +- Cairo ([7387905](https://github.com/helix-editor/helix/commit/7387905)) +- CPON ([#2355](https://github.com/helix-editor/helix/pull/2355), [#2424](https://github.com/helix-editor/helix/pull/2424)) +- git-ignore ([#2397](https://github.com/helix-editor/helix/pull/2397)) +- git-attributes ([#2397](https://github.com/helix-editor/helix/pull/2397)) +- Odin ([#2399](https://github.com/helix-editor/helix/pull/2399), [#2464](https://github.com/helix-editor/helix/pull/2464)) +- Meson ([#2314](https://github.com/helix-editor/helix/pull/2314)) +- SSH Client Config ([#2498](https://github.com/helix-editor/helix/pull/2498)) +- Scheme ([d25bae8](https://github.com/helix-editor/helix/commit/d25bae8)) +- Verilog ([#2552](https://github.com/helix-editor/helix/pull/2552)) + +Updated Languages and Queries: + +- Erlang ([e2a5071](https://github.com/helix-editor/helix/commit/e2a5071), [#2149](https://github.com/helix-editor/helix/pull/2149), [82da9bd](https://github.com/helix-editor/helix/commit/82da9bd)) +- Elixir ([1819478](https://github.com/helix-editor/helix/commit/1819478), [8c3c901](https://github.com/helix-editor/helix/commit/8c3c901), [4ac94a5](https://github.com/helix-editor/helix/commit/4ac94a5)) +- Gleam ([7cd6050](https://github.com/helix-editor/helix/commit/7cd6050), [45dd540](https://github.com/helix-editor/helix/commit/45dd540)) +- Bash ([#1917](https://github.com/helix-editor/helix/pull/1917)) +- JavaScript ([#2140](https://github.com/helix-editor/helix/pull/2140)) +- Ruby textobject queries ([#2143](https://github.com/helix-editor/helix/pull/2143)) +- Fix Golang textobject queries ([#2153](https://github.com/helix-editor/helix/pull/2153)) +- Add more bash and HCL file extensions ([#2201](https://github.com/helix-editor/helix/pull/2201)) +- Divide HCL and tfvars into separate languages ([#2244](https://github.com/helix-editor/helix/pull/2244)) +- Use JavaScript for `cjs` files ([#2387](https://github.com/helix-editor/helix/pull/2387)) +- Use Perl for `t` files ([#2395](https://github.com/helix-editor/helix/pull/2395)) +- Use `markup.list` scopes for lists ([#2401](https://github.com/helix-editor/helix/pull/2401)) +- Use PHP for `inc` files ([#2440](https://github.com/helix-editor/helix/pull/2440)) +- Improve Rust textobjects ([#2494](https://github.com/helix-editor/helix/pull/2494), [10463fe](https://github.com/helix-editor/helix/commit/10463fe)) +- Python ([#2451](https://github.com/helix-editor/helix/pull/2451)) + +Packaging: + +- Use `builtins.fromTOML` in Nix Flake on Nix 2.6+ ([#1892](https://github.com/helix-editor/helix/pull/1892)) +- Shell auto-completion files are now available ([#2022](https://github.com/helix-editor/helix/pull/2022)) +- Create an AppImage on release ([#2089](https://github.com/helix-editor/helix/pull/2089)) + # 22.03 (2022-03-28) A big shout out to all the contributors! We had 51 contributors in this release. From a106341fd73b1be3d42353ee154d0612b7bfceba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Sat, 28 May 2022 23:23:08 +0900 Subject: [PATCH 251/861] Fix release action --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bfafd7ed8..efeb77e09 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: uses: actions/checkout@v3 - name: Install stable toolchain - uses: actions-rs/toolchain@v1 + uses: helix-editor/rust-toolchain@v1 with: profile: minimal override: true From b31788102e96d55b69dc422b439386207fdab0fd Mon Sep 17 00:00:00 2001 From: nitish-17 <62102673+nitish-17@users.noreply.github.com> Date: Sat, 28 May 2022 21:32:47 +0530 Subject: [PATCH 252/861] mention the requirement of C++ compiler for building grammar in doc (#2592) --- book/src/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/install.md b/book/src/install.md index cbd2c0280..bf59ea234 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -79,4 +79,4 @@ For more information on the information displayed in the healthcheck results ref Tree-sitter grammars must be fetched and compiled if not pre-packaged. Fetch grammars with `hx --grammar fetch` (requires `git`) and compile them -with `hx --grammar build` (requires a C compiler). +with `hx --grammar build` (requires a C++ compiler). From 27609f50652e28b9bb7a190322fbb8f7c4479c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Sun, 29 May 2022 01:07:18 +0900 Subject: [PATCH 253/861] Fix the VERSION file --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4c3f332ef..bb7635c70 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -22.05-dev \ No newline at end of file +22.05 \ No newline at end of file From 7c107d0d3ac163139d9616cdbc4fb021cca6d20d Mon Sep 17 00:00:00 2001 From: booklearner Date: Sat, 28 May 2022 14:11:31 -0400 Subject: [PATCH 254/861] Fix link to `pop-dark` in `CHANGELOG.md` (#2594) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b50bf699..693a2a5f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,7 +103,7 @@ Themes: - Use border colors from the original `dark_plus` theme ([#2186](https://github.com/helix-editor/helix/pull/2186)) - Add `autumn` ([#2212](https://github.com/helix-editor/helix/pull/2212), [#2270](https://github.com/helix-editor/helix/pull/2270), [#2531](https://github.com/helix-editor/helix/pull/2531)) - Add `tokyonight_storm` ([#2240](https://github.com/helix-editor/helix/pull/2240)) -- Add `pop-dark` ([#2240](https://github.com/helix-editor/helix/pull/2240)) +- Add `pop-dark` ([#2189](https://github.com/helix-editor/helix/pull/2189)) - Fix `base16_terminal` theme using incorrect ansi-color ([#2279](https://github.com/helix-editor/helix/pull/2279)) - Add `onelight` ([#2287](https://github.com/helix-editor/helix/pull/2287), [#2323](https://github.com/helix-editor/helix/pull/2323)) - Add `ui.virtual` scopes to `onedark` theme ([3626e38](https://github.com/helix-editor/helix/commit/3626e38)) From 7706a4a0d8b67b943c31d0c5f7b00d357b5d838d Mon Sep 17 00:00:00 2001 From: pancake Date: Sat, 28 May 2022 21:46:10 +0200 Subject: [PATCH 255/861] Add Vlang tree-sitter in the languages.toml (#2526) Co-authored-by: pancake Co-authored-by: Michael Davis --- book/src/generated/lang-support.md | 1 + languages.toml | 15 +++ runtime/queries/v/highlights.scm | 150 +++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 runtime/queries/v/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index e47ccbc4d..c4e602452 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -89,6 +89,7 @@ | tsx | ✓ | | | `typescript-language-server` | | twig | ✓ | | | | | typescript | ✓ | | ✓ | `typescript-language-server` | +| v | ✓ | | | `vls` | | vala | ✓ | | | `vala-language-server` | | verilog | ✓ | ✓ | | `svlangserver` | | vue | ✓ | | | `vls` | diff --git a/languages.toml b/languages.toml index e2bf26bf4..35c4b4704 100644 --- a/languages.toml +++ b/languages.toml @@ -1381,6 +1381,21 @@ indent = { tab-width = 2, unit = " " } name = "scheme" source = { git = "https://github.com/6cdh/tree-sitter-scheme", rev = "27fb77db05f890c2823b4bd751c6420378df146b" } +[[language]] +name = "v" +scope = "source.v" +file-types = ["v", "vv"] +shebangs = ["v run"] +roots = ["v.mod"] +language-server = { command = "vls", args = [] } +auto-format = true +comment-token = "//" +indent = { tab-width = 4, unit = "\t" } + +[[grammar]] +name = "v" +source = { git = "https://github.com/vlang/vls", subpath = "tree_sitter_v", rev = "3e8124ea4ab80aa08ec77f03df53f577902a0cdd" } + [[language]] name = "verilog" scope = "source.verilog" diff --git a/runtime/queries/v/highlights.scm b/runtime/queries/v/highlights.scm new file mode 100644 index 000000000..c71245dca --- /dev/null +++ b/runtime/queries/v/highlights.scm @@ -0,0 +1,150 @@ +(parameter_declaration + name: (identifier) @variable.parameter) +(function_declaration + name: (identifier) @function) +(function_declaration + receiver: (parameter_list) + name: (identifier) @function.method) + +(call_expression + function: (identifier) @function) +(call_expression + function: (selector_expression + field: (identifier) @function.method)) + +(field_identifier) @variable.other.member +(selector_expression + field: (identifier) @variable.other.member) + +(int_literal) @constant.numeric.integer +(interpreted_string_literal) @string +(rune_literal) @string +(escape_sequence) @constant.character.escape + +[ + (type_identifier) + (builtin_type) + (pointer_type) + (array_type) +] @type + +[ + (identifier) + (module_identifier) + (import_path) +] @variable + +[ + "as" + "asm" + "assert" + ;"atomic" + ;"break" + "const" + ;"continue" + "defer" + "else" + "enum" + "fn" + "for" + "$for" + "go" + "goto" + "if" + "$if" + "import" + "in" + "!in" + "interface" + "is" + "!is" + "lock" + "match" + "module" + "mut" + "or" + "pub" + "return" + "rlock" + "select" + ;"shared" + ;"static" + "struct" + "type" + ;"union" + "unsafe" +] @keyword + +[ + (true) + (false) +] @boolean + +[ + "." + "," + ":" + ";" +] @punctuation.delimiter + +[ + "(" + ")" + "{" + "}" + "[" + "]" +] @punctuation.bracket + +(array) @punctuation.bracket + +[ + "++" + "--" + + "+" + "-" + "*" + "/" + "%" + + "~" + "&" + "|" + "^" + + "!" + "&&" + "||" + "!=" + + "<<" + ">>" + + "<" + ">" + "<=" + ">=" + + "+=" + "-=" + "*=" + "/=" + "&=" + "|=" + "^=" + "<<=" + ">>=" + + "=" + ":=" + "==" + + "?" + "<-" + "$" + ".." + "..." +] @operator + +(comment) @comment \ No newline at end of file From 93e6eac15a1302aa790fec2778cdfee3eefd94e3 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 28 May 2022 21:06:31 -0500 Subject: [PATCH 256/861] mention the C++ compiler in the grammar build failure message (#2597) Earlier in the builder we enable C++ (`.cpp(true)`) but only mention the C compiler in the build failure message. Some grammars that have C++ external scanners can provoke build failures in this step if a C++ compiler isn't installed, so mentioning it in the error message should help out debugging. --- helix-loader/src/grammar.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index df88f24b4..99791f26c 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -355,7 +355,9 @@ fn build_tree_sitter_library(src_path: &Path, grammar: GrammarConfiguration) -> } } - let output = command.output().context("Failed to execute C compiler")?; + let output = command + .output() + .context("Failed to execute C/C++ compiler")?; if !output.status.success() { return Err(anyhow!( "Parser compilation failed.\nStdout: {}\nStderr: {}", From 10415a80690256c2ba40e2608191b8a081c7e21b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Sun, 29 May 2022 11:10:23 +0900 Subject: [PATCH 257/861] Bump dependencies, allow retain_mut for now --- Cargo.lock | 130 +++++++++++++++--------------------- helix-term/src/ui/picker.rs | 2 +- 2 files changed, 56 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47d89bcf3..4ab923899 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -548,9 +548,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "jsonrpc-core" @@ -573,9 +573,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "libloading" @@ -627,9 +627,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" @@ -642,41 +642,21 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" +checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" dependencies = [ "libc", "log", - "miow", - "ntapi", "wasi 0.11.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", -] - -[[package]] -name = "ntapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" -dependencies = [ - "winapi", + "windows-sys", ] [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", @@ -684,9 +664,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] @@ -719,9 +699,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ "cfg-if", "libc", @@ -738,9 +718,9 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project-lite" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -750,11 +730,11 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -779,9 +759,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] @@ -849,9 +829,9 @@ checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] name = "retain_mut" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c31b5c4033f8fdde8700e4657be2c497e7288f01515be52168c631e2e4d4086" +checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" [[package]] name = "ropey" @@ -865,9 +845,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" [[package]] name = "same-file" @@ -917,9 +897,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" +checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" dependencies = [ "proc-macro2", "quote", @@ -1030,9 +1010,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "str-buf" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" +checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" [[package]] name = "str_indices" @@ -1042,13 +1022,13 @@ checksum = "adfad63a1b47951101cd667a85b2959a62910cf03f814fff25df89c460b873f8" [[package]] name = "syn" -version = "1.0.90" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -1102,9 +1082,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -1187,9 +1167,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-general-category" @@ -1197,6 +1177,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1218098468b8085b19a2824104c70d976491d247ce194bbd9dc77181150cdfd6" +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + [[package]] name = "unicode-linebreak" version = "0.1.2" @@ -1227,12 +1213,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - [[package]] name = "url" version = "2.2.2" @@ -1319,9 +1299,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ "windows_aarch64_msvc", "windows_i686_gnu", @@ -1332,33 +1312,33 @@ dependencies = [ [[package]] name = "windows_aarch64_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_i686_gnu" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_x86_64_gnu" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "xtask" diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 181c2077d..9ffe45c1b 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -366,7 +366,7 @@ impl Picker { ); } else if pattern.starts_with(&self.previous_pattern) { // TODO: remove when retain_mut is in stable rust - #[allow(unused_imports)] + #[allow(unused_imports, deprecated)] use retain_mut::RetainMut; // optimization: if the pattern is a more specific version of the previous one From 89c6e8aa9419df3b7975bcae28f83e2ccc3bc318 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sun, 29 May 2022 04:13:21 +0200 Subject: [PATCH 258/861] Remove unnecessary `unwrap` (#2599) `strip_prefix` will itself check whether the string starts with the prefix, so the extra call to `starts_with` was unnecessary. --- helix-core/src/path.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/helix-core/src/path.rs b/helix-core/src/path.rs index 6bf722a77..cb50e136c 100644 --- a/helix-core/src/path.rs +++ b/helix-core/src/path.rs @@ -5,9 +5,8 @@ use std::path::{Component, Path, PathBuf}; /// is available, otherwise returns the path unchanged. pub fn fold_home_dir(path: &Path) -> PathBuf { if let Ok(home) = home_dir() { - if path.starts_with(&home) { - // it's ok to unwrap, the path starts with home dir - return PathBuf::from("~").join(path.strip_prefix(&home).unwrap()); + if let Ok(stripped) = path.strip_prefix(&home) { + return PathBuf::from("~").join(stripped); } } From cd4622db9b041b9766b940fed0560b3d1a46a234 Mon Sep 17 00:00:00 2001 From: Marcin Puc Date: Sun, 29 May 2022 17:52:26 +0200 Subject: [PATCH 259/861] Update from-source install instruction in README (#2603) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c03c14a23..032ecf675 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,11 @@ If you would like to build from source: git clone https://github.com/helix-editor/helix cd helix cargo install --path helix-term -hx --grammar fetch -hx --grammar build ``` This will install the `hx` binary to `$HOME/.cargo/bin` and build tree-sitter grammars. +If you want to customize your `languages.toml` config, +tree-sitter grammars may be manually fetched and built with `hx --grammar fetch` and `hx --grammar build`. Helix also needs its runtime files so make sure to copy/symlink the `runtime/` directory into the config directory (for example `~/.config/helix/runtime` on Linux/macOS, or `%AppData%/helix/runtime` on Windows). From b43074dad3b1094dab608adf1482dc3c9069770e Mon Sep 17 00:00:00 2001 From: Michael Zeller Date: Sun, 29 May 2022 11:52:48 -0400 Subject: [PATCH 260/861] illumos linker doesn't currently have -z relro (#2602) --- helix-loader/src/grammar.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index 99791f26c..d2769d81f 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -350,7 +350,10 @@ fn build_tree_sitter_library(src_path: &Path, grammar: GrammarConfiguration) -> } } command.arg("-xc").arg(parser_path); - if cfg!(all(unix, not(target_os = "macos"))) { + if cfg!(all( + unix, + not(any(target_os = "macos", target_os = "illumos")) + )) { command.arg("-Wl,-z,relro,-z,now"); } } From 710c4a84b22bc149e2f9fadfc37aaabbfe3b1c42 Mon Sep 17 00:00:00 2001 From: Paul Graydon <43348144+paulgraydon@users.noreply.github.com> Date: Sun, 29 May 2022 15:56:10 +0000 Subject: [PATCH 261/861] Adjust colors in tokyonight themes (#2606) --- runtime/themes/tokyonight.toml | 13 +++++++++---- runtime/themes/tokyonight_storm.toml | 13 +++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/runtime/themes/tokyonight.toml b/runtime/themes/tokyonight.toml index b41ff6f71..14cc40e2d 100644 --- a/runtime/themes/tokyonight.toml +++ b/runtime/themes/tokyonight.toml @@ -4,8 +4,12 @@ "constant" = { fg = "orange" } "constant.character.escape" = { fg = "magenta" } "function" = { fg = "blue", modifiers = ["italic"] } -"keyword" = { fg = "magenta" } +"function.macro" = { fg = "cyan" } +"keyword" = { fg = "cyan", modifiers = ["italic"] } +"keyword.control" = { fg = "magenta" } "keyword.control.import" = { fg = "cyan" } +"keyword.operator" = { fg = "turquoise" } +"keyword.function" = { fg = "magenta", modifiers = ["italic"] } "operator" = { fg = "turquoise" } "punctuation" = { fg = "turquoise" } "string" = { fg = "light-green" } @@ -14,8 +18,8 @@ "type" = { fg = "teal" } "namespace" = { fg = "blue" } "variable" = { fg = "white" } -"variable.builtin" = { fg = "red", modifiers = ["italic"] } -"variable.other.member" = { fg = "magenta" } +"variable.builtin" = { fg = "red" } +"variable.other.member" = { fg = "green" } "variable.parameter" = { fg = "yellow", modifiers = ["italic"] } "diff.plus" = { fg = "green" } @@ -38,7 +42,8 @@ "ui.statusline.inactive" = { fg = "foreground_gutter", bg = "background_menu" } "ui.text" = { fg = "foreground" } "ui.text.focus" = { fg = "cyan" } -"ui.virtual" = { fg = "foreground_gutter" } +"ui.virtual.ruler" = { bg = "foreground_gutter" } +"ui.virtual.whitespace" = { fg = "foreground_gutter" } "ui.window" = { fg = "black" } "error" = { fg = "red" } diff --git a/runtime/themes/tokyonight_storm.toml b/runtime/themes/tokyonight_storm.toml index 4a018a285..6c6fd9c8d 100644 --- a/runtime/themes/tokyonight_storm.toml +++ b/runtime/themes/tokyonight_storm.toml @@ -4,8 +4,12 @@ "constant" = { fg = "orange" } "constant.character.escape" = { fg = "magenta" } "function" = { fg = "blue", modifiers = ["italic"] } -"keyword" = { fg = "magenta" } +"function.macro" = { fg = "cyan" } +"keyword" = { fg = "cyan", modifiers = ["italic"] } +"keyword.control" = { fg = "magenta" } "keyword.control.import" = { fg = "cyan" } +"keyword.operator" = { fg = "turquoise" } +"keyword.function" = { fg = "magenta", modifiers = ["italic"] } "operator" = { fg = "turquoise" } "punctuation" = { fg = "turquoise" } "string" = { fg = "light-green" } @@ -14,8 +18,8 @@ "type" = { fg = "teal" } "namespace" = { fg = "blue" } "variable" = { fg = "white" } -"variable.builtin" = { fg = "red", modifiers = ["italic"] } -"variable.other.member" = { fg = "magenta" } +"variable.builtin" = { fg = "red" } +"variable.other.member" = { fg = "green" } "variable.parameter" = { fg = "yellow", modifiers = ["italic"] } "diff.plus" = { fg = "green" } @@ -38,7 +42,8 @@ "ui.statusline.inactive" = { fg = "foreground_gutter", bg = "background_menu" } "ui.text" = { fg = "foreground" } "ui.text.focus" = { fg = "cyan" } -"ui.virtual" = { fg = "foreground_gutter" } +"ui.virtual.ruler" = { bg = "foreground_gutter" } +"ui.virtual.whitespace" = { fg = "foreground_gutter" } "ui.window" = { fg = "black" } "error" = { fg = "red" } From 5ed622399026754b3712db7ac8c2d6fc372d0238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 30 May 2022 01:21:41 +0900 Subject: [PATCH 262/861] fix: Remove empty scratch buffer from jumplists when removing it Fixes #1238 --- helix-view/src/editor.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 3ba6fea87..c53fcc7f7 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -671,11 +671,18 @@ impl Editor { .any(|(_, v)| v.doc == doc.id && v.id != view.id); let (view, doc) = current!(self); + let view_id = view.id; + 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`. let id = doc.id; self.documents.remove(&id); + + // Remove the scratch buffer from any jumplists + for (view, _) in self.tree.views_mut() { + view.jumps.remove(&id) + } } else { let jump = (view.doc, doc.selection(view.id).clone()); view.jumps.push(jump); @@ -691,7 +698,6 @@ impl Editor { } } - let view_id = view.id; self.replace_document_in_view(view_id, id); return; From 370a16d0f00d6146fdeb87cc16fb352e860e2377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 30 May 2022 12:29:07 +0900 Subject: [PATCH 263/861] Update to ropey 1.5 --- Cargo.lock | 9 ++++----- helix-core/Cargo.toml | 2 +- helix-core/src/lib.rs | 2 +- helix-term/Cargo.toml | 1 - helix-term/src/ui/editor.rs | 2 +- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ab923899..86ae08159 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -457,7 +457,6 @@ dependencies = [ "once_cell", "pulldown-cmark", "retain_mut", - "ropey", "serde", "serde_json", "signal-hook", @@ -835,9 +834,9 @@ checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" [[package]] name = "ropey" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0dd9b26e2a102b33d400b7b7d196c81a4014eb96eda90b1c5b48d7215d9633" +checksum = "bbd22239fafefc42138ca5da064f3c17726a80d2379d817a3521240e78dd0064" dependencies = [ "smallvec", "str_indices", @@ -1016,9 +1015,9 @@ checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" [[package]] name = "str_indices" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adfad63a1b47951101cd667a85b2959a62910cf03f814fff25df89c460b873f8" +checksum = "9d9199fa80c817e074620be84374a520062ebac833f358d74b37060ce4a0f2c0" [[package]] name = "syn" diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 8d6a343f7..6574d144b 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -16,7 +16,7 @@ unicode-lines = ["ropey/unicode_lines"] [dependencies] helix-loader = { version = "0.6", path = "../helix-loader" } -ropey = { version = "1.4", default-features = false } +ropey = { version = "1.5", default-features = false, features = ["simd"] } smallvec = "1.8" smartstring = "1.0.1" unicode-segmentation = "1.9" diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index a022a42a1..7d857b0f0 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -52,7 +52,7 @@ pub fn find_root(root: Option<&str>, root_markers: &[String]) -> Option Date: Mon, 30 May 2022 12:47:18 -0600 Subject: [PATCH 264/861] feat(lang): Update Nix grammar & improve queries (#2472) --- languages.toml | 2 +- runtime/queries/nix/highlights.scm | 54 +++++++++++++++++------------- runtime/queries/nix/indents.scm | 33 +++++++++++------- 3 files changed, 52 insertions(+), 37 deletions(-) diff --git a/languages.toml b/languages.toml index 35c4b4704..fdf0513a0 100644 --- a/languages.toml +++ b/languages.toml @@ -439,7 +439,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "nix" -source = { git = "https://github.com/cstrahan/tree-sitter-nix", rev = "50f38ceab667f9d482640edfee803d74f4edeba5" } +source = { git = "https://github.com/cstrahan/tree-sitter-nix", rev = "6b71a810c0acd49b980c50fc79092561f7cee307" } [[language]] name = "ruby" diff --git a/runtime/queries/nix/highlights.scm b/runtime/queries/nix/highlights.scm index f6682065e..d5ff40325 100644 --- a/runtime/queries/nix/highlights.scm +++ b/runtime/queries/nix/highlights.scm @@ -1,15 +1,16 @@ (comment) @comment [ - "if" + "if" "then" "else" "let" "inherit" "in" "rec" - "with" + "with" "assert" + "or" ] @keyword ((identifier) @variable.builtin @@ -21,25 +22,25 @@ (#is-not? local)) [ - (string) - (indented_string) + (string_expression) + (indented_string_expression) ] @string [ - (path) - (hpath) - (spath) + (path_expression) + (hpath_expression) + (spath_expression) ] @string.special.path -(uri) @string.special.uri +(uri_expression) @string.special.uri ; boolean ((identifier) @constant.builtin.boolean (#match? @constant.builtin.boolean "^(true|false)$")) @constant.builtin.boolean ; null ((identifier) @constant.builtin (#eq? @constant.builtin "null")) @constant.builtin -(integer) @constant.numeric.integer -(float) @constant.numeric.float +(integer_expression) @constant.numeric.integer +(float_expression) @constant.numeric.float (interpolation "${" @punctuation.special @@ -47,7 +48,7 @@ (escape_sequence) @constant.character.escape -(function +(function_expression universal: (identifier) @variable.parameter ) @@ -55,27 +56,36 @@ name: (identifier) @variable.parameter "?"? @punctuation.delimiter) -(app +(select_expression + attrpath: (attrpath (identifier)) @variable.other.member) + +(apply_expression function: [ - (identifier) @function - (select + (variable_expression (identifier)) @function + (select_expression attrpath: (attrpath - attr: (attr_identifier) @function .))]) - + attr: (identifier) @function .))]) -(unary +(unary_expression operator: _ @operator) -(binary +(binary_expression operator: _ @operator) -(attr_identifier) @variable.other.member -(inherit attrs: (attrs_inherited (identifier) @variable.other.member) ) +(variable_expression (identifier) @variable) + +(binding + attrpath: (attrpath (identifier)) @variable.other.member) + +(identifier) @variable.other.member + +(inherit_from attrs: (inherited_attrs attr: (identifier) @variable.other.member) ) [ ";" "." "," + "=" ] @punctuation.delimiter [ @@ -85,6 +95,4 @@ "]" "{" "}" -] @punctuation.bracket - -(identifier) @variable +] @punctuation.bracket \ No newline at end of file diff --git a/runtime/queries/nix/indents.scm b/runtime/queries/nix/indents.scm index 0790ce291..a12376e7d 100644 --- a/runtime/queries/nix/indents.scm +++ b/runtime/queries/nix/indents.scm @@ -1,18 +1,25 @@ + [ - ; "function", - (bind) - (assert) - (with) + ; Bracket like (let) - (if) - (attrset) - (list) - (indented_string) + (rec_attrset) + (let_attrset) (parenthesized) -] @indent + (list) -[ - "}" - "]" -] @outdent + ; Binding + (bind) + (inherit) + (inherit_from) + (formal) + + ; Binary operations + (binary) + (has_attr) + (select) + (app) + + ; Conditional + (if) +] @indent \ No newline at end of file From fc8c48832257672b92a1b3c08b79c6cbffad1761 Mon Sep 17 00:00:00 2001 From: Clay Date: Mon, 30 May 2022 19:32:14 -0700 Subject: [PATCH 265/861] Elixir: inject Markdown into docs, remove h sigil HEEx injection (#2619) Co-authored-by: Michael Davis --- runtime/queries/elixir/injections.scm | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/runtime/queries/elixir/injections.scm b/runtime/queries/elixir/injections.scm index c88825344..5c58a8630 100644 --- a/runtime/queries/elixir/injections.scm +++ b/runtime/queries/elixir/injections.scm @@ -11,6 +11,15 @@ ((sigil (sigil_name) @_sigil_name (quoted_content) @injection.content) - (#match? @_sigil_name "^(h|H)$") + (#eq? @_sigil_name "H") (#set! injection.language "heex") (#set! injection.combined)) + +(unary_operator + operator: "@" + operand: (call + target: ((identifier) @_identifier (#match? @_identifier "^(module|type|short)?doc$")) + (arguments [ + (string (quoted_content) @injection.content) + (sigil (quoted_content) @injection.content) + ])) (#set! injection.language "markdown")) From fa2eeccc573cd985b428d337294a7171a1ba35b5 Mon Sep 17 00:00:00 2001 From: Andrey Tkachenko Date: Tue, 31 May 2022 18:08:16 +0400 Subject: [PATCH 266/861] Fix unwrap error when undo after `shell_append_output` (#2625) --- helix-term/src/commands.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 8024e3f03..a692822fb 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4430,6 +4430,7 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) { if behavior != &ShellBehavior::Ignore { let transaction = Transaction::change(doc.text(), changes.into_iter()); doc.apply(&transaction, view.id); + doc.append_changes_to_history(view.id); } // after replace cursor may be out of bounds, do this to From fc666db6b99a8baab0acf3791f9965e7cb2be9e1 Mon Sep 17 00:00:00 2001 From: Ben Lee-Cohen Date: Tue, 31 May 2022 11:15:32 -0400 Subject: [PATCH 267/861] Solarized Light: Fixing menu colors and adding English translation (#2626) --- runtime/themes/solarized_light.toml | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/runtime/themes/solarized_light.toml b/runtime/themes/solarized_light.toml index e535e9b0c..eec4220db 100644 --- a/runtime/themes/solarized_light.toml +++ b/runtime/themes/solarized_light.toml @@ -37,53 +37,69 @@ "diff.minus" = { fg = "red" } # 背景 +# background "ui.background" = { bg = "base03" } "ui.virtual" = { fg = "base01" } # 行号栏 +# line number column "ui.linenr" = { fg = "base0", bg = "base02" } # 当前行号栏 +# current line number column "ui.linenr.selected" = { fg = "blue", modifiers = ["bold"] } # 状态栏 +# status bar "ui.statusline" = { fg = "base03", bg = "base0" } # 非活动状态栏 +# inactive status bar "ui.statusline.inactive" = { fg = "base1", bg = "base01" } # 补全窗口, preview窗口 +# Completion window, preview window "ui.popup" = { bg = "base02" } # 影响 补全选中 cmd弹出信息选中 +# Affect completion selection, cmd pop-up information selection "ui.menu.selected" = { fg = "base02", bg = "base2"} -"ui.menu" = { fg = "base1" } +"ui.menu" = { fg = "base0", bg = "base02" } # ?? "ui.window" = { fg = "base3" } # 命令行 补全的帮助信息 +# Command line completion help information "ui.help" = { modifiers = ["reversed"] } # 快捷键窗口 +# Shortcut window "ui.popup.info" = { bg = "base1" } # 快捷键字体 +# Shortcut font "ui.text.info" = {fg = "base02", modifiers = ["bold"]} # 普通ui的字体样式 +# Normal ui font style "ui.text" = { fg = "base1" } # 影响 picker列表选中, 快捷键帮助窗口文本 +# Affects picker list selection, shortcut key help window text "ui.text.focus" = { fg = "blue", modifiers = ["bold"]} # file picker中, 预览的当前选中项 +# In file picker, the currently selected item of the preview "ui.highlight" = { fg = "red", modifiers = ["bold", "italic", "underlined"] } -# 主光标/selectio +# 主光标/selection +# main cursor/selection "ui.cursor.primary" = { fg = "base03", bg = "base1" } "ui.cursor.select" = { fg = "base02", bg = "cyan" } "ui.selection" = { bg = "base0175" } "ui.selection.primary" = { bg = "base015" } # normal模式的光标 +# normal mode cursor "ui.cursor" = {fg = "base02", bg = "cyan"} "ui.cursor.insert" = {fg = "base03", bg = "base3"} # 当前光标匹配的标点符号 -"ui.cursor.match" = { fg = "base02", bg = "light-gray" } +# The punctuation character matched by the current cursor +"ui.cursor.match" = { fg = "base02", bg = "base015" } "warning" = { fg = "orange", modifiers= ["bold", "underlined"] } "error" = { fg = "red", modifiers= ["bold", "underlined"] } @@ -102,12 +118,14 @@ orange = '#cb4b16' violet = '#6c71c4' # 深色 越来越深 +# dark getting darker base0 = '#657b83' base1 = '#586e75' base2 = '#073642' base3 = '#002b36' -## 浅色 越來越浅 +# 浅色 越來越浅 +# Lighter and lighter base00 = '#839496' base01 = '#93a1a1' base015 = '#c5c8bd' From ae12c58f0ff924e9cc512f0368e5fca858566cdd Mon Sep 17 00:00:00 2001 From: Ryan Russell Date: Wed, 1 Jun 2022 12:01:37 -0500 Subject: [PATCH 268/861] Improve Readability (#2639) --- book/src/from-vim.md | 2 +- helix-core/src/graphemes.rs | 2 +- helix-core/src/history.rs | 6 +++--- helix-core/src/increment/number.rs | 2 +- helix-core/src/lib.rs | 2 +- helix-core/src/selection.rs | 2 +- helix-core/src/surround.rs | 2 +- helix-term/src/commands.rs | 4 ++-- helix-term/src/commands/lsp.rs | 4 ++-- helix-term/src/keymap.rs | 2 +- helix-view/src/handlers/dap.rs | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/book/src/from-vim.md b/book/src/from-vim.md index 09f33386b..ed6155d32 100644 --- a/book/src/from-vim.md +++ b/book/src/from-vim.md @@ -9,4 +9,4 @@ single width selection. See also Kakoune's [Migrating from Vim](https://github.com/mawww/kakoune/wiki/Migrating-from-Vim). -> TODO: Mention texobjects, surround, registers +> TODO: Mention textobjects, surround, registers diff --git a/helix-core/src/graphemes.rs b/helix-core/src/graphemes.rs index c0c617750..675f57505 100644 --- a/helix-core/src/graphemes.rs +++ b/helix-core/src/graphemes.rs @@ -14,7 +14,7 @@ pub fn grapheme_width(g: &str) -> usize { // Point 1: theoretically, ascii control characters should have zero // width, but in our case we actually want them to have width: if they // show up in text, we want to treat them as textual elements that can - // be editied. So we can get away with making all ascii single width + // be edited. So we can get away with making all ascii single width // here. // Point 2: we're only examining the first codepoint here, which means // we're ignoring graphemes formed with combining characters. However, diff --git a/helix-core/src/history.rs b/helix-core/src/history.rs index 3f324e340..b608097ca 100644 --- a/helix-core/src/history.rs +++ b/helix-core/src/history.rs @@ -177,7 +177,7 @@ impl History { } } - /// List of nodes on the way from `n` to 'a`. Doesn`t include `a`. + /// List of nodes on the way from `n` to 'a`. Doesn't include `a`. /// Includes `n` unless `a == n`. `a` must be an ancestor of `n`. fn path_up(&self, mut n: usize, a: usize) -> Vec { let mut path = Vec::new(); @@ -546,8 +546,8 @@ mod test { // Units are validated. assert_eq!( - "1 millenium".parse::(), - Err("incorrect time unit: millenium".to_string()) + "1 millennium".parse::(), + Err("incorrect time unit: millennium".to_string()) ); // Units can't be specified twice. diff --git a/helix-core/src/increment/number.rs b/helix-core/src/increment/number.rs index 57171f671..62b4a19dc 100644 --- a/helix-core/src/increment/number.rs +++ b/helix-core/src/increment/number.rs @@ -377,7 +377,7 @@ mod test { } #[test] - fn test_increment_basic_hexadedimal_numbers() { + fn test_increment_basic_hexadecimal_numbers() { let tests = [ ("0x0100", 1, "0x0101"), ("0x0100", -1, "0x00ff"), diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 7d857b0f0..627b73bb0 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -43,7 +43,7 @@ pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option { /// /// Order of detection: /// * Top-most folder containing a root marker in current git repository -/// * Git repostory root if no marker detected +/// * Git repository root if no marker detected /// * Top-most folder containing a root marker if not git repository detected /// * Current working directory as fallback pub fn find_root(root: Option<&str>, root_markers: &[String]) -> Option { diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index c6eceb4b5..1b2416f5b 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -830,7 +830,7 @@ mod test { } #[test] - fn test_graphem_aligned() { + fn test_grapheme_aligned() { let r = Rope::from_str("\r\nHi\r\n"); let s = r.slice(..); diff --git a/helix-core/src/surround.rs b/helix-core/src/surround.rs index db51b8f18..6244b3805 100644 --- a/helix-core/src/surround.rs +++ b/helix-core/src/surround.rs @@ -66,7 +66,7 @@ pub fn find_nth_closest_pairs_pos( for ch in text.chars_at(pos) { if is_open_pair(ch) { // Track open pairs encountered so that we can step over - // the correspoding close pairs that will come up further + // the corresponding close pairs that will come up further // down the loop. We want to find a lone close pair whose // open pair is before the cursor position. stack.push(ch); diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index a692822fb..44e2f8c22 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1964,7 +1964,7 @@ fn shrink_to_line_bounds(cx: &mut Context) { // line_to_char gives us the start position of the line, so // we need to get the start position of the next line. In // the editor, this will correspond to the cursor being on - // the EOL whitespace charactor, which is what we want. + // the EOL whitespace character, which is what we want. let mut end = text.line_to_char((end_line + 1).min(text.len_lines())); if start != range.from() { @@ -2929,7 +2929,7 @@ pub mod insert { Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| { let pos = range.cursor(text); let line_start_pos = text.line_to_char(range.cursor_line(text)); - // considier to delete by indent level if all characters before `pos` are indent units. + // consider to delete by indent level if all characters before `pos` are indent units. let fragment = Cow::from(text.slice(line_start_pos..pos)); if !fragment.is_empty() && fragment.chars().all(|ch| ch.is_whitespace()) { if text.get_char(pos.saturating_sub(1)) == Some('\t') { diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 90a1ad7f8..bf62fd3c3 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -416,8 +416,8 @@ pub fn apply_workspace_edit( } lsp::DocumentChanges::Operations(operations) => { log::debug!("document changes - operations: {:?}", operations); - for operateion in operations { - match operateion { + for operation in operations { + match operation { lsp::DocumentChangeOperation::Op(op) => { apply_document_resource_op(op).unwrap(); } diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 37dbc5de2..db9588330 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -542,7 +542,7 @@ mod tests { vec![vec![key!('j')], vec![key!('k')]] ), ]), - "Mistmatch" + "Mismatch" ) } } diff --git a/helix-view/src/handlers/dap.rs b/helix-view/src/handlers/dap.rs index 2ea21f624..b17ca3530 100644 --- a/helix-view/src/handlers/dap.rs +++ b/helix-view/src/handlers/dap.rs @@ -86,7 +86,7 @@ pub fn breakpoints_changed( path: PathBuf, breakpoints: &mut [Breakpoint], ) -> Result<(), anyhow::Error> { - // TODO: handle capabilities correctly again, by filterin breakpoints when emitting + // TODO: handle capabilities correctly again, by filtering breakpoints when emitting // if breakpoint.condition.is_some() // && !debugger // .caps From 8d4c954060ef0a67bf081692e92ef64576d0a27b Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Wed, 1 Jun 2022 22:11:14 +0200 Subject: [PATCH 269/861] CPON parser supports unsigned int (#2643) Co-authored-by: Fanda Vacek --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index fdf0513a0..3e6793656 100644 --- a/languages.toml +++ b/languages.toml @@ -1330,7 +1330,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "cpon" -source = { git = "https://github.com/fvacek/tree-sitter-cpon", rev = "cc6a22b1fa8917c2d041af399f19f34a0a9d94ff" } +source = { git = "https://github.com/fvacek/tree-sitter-cpon", rev = "0d01fcdae5a53191df5b1349f9bce053833270e7" } [[language]] name = "odin" From 99e08f50bdfeb24abe6afff8082ee160a7cadb6f Mon Sep 17 00:00:00 2001 From: Michael Zeller Date: Wed, 1 Jun 2022 17:11:58 -0400 Subject: [PATCH 270/861] catpuccin ui.popup should be a different color from ui.background (#2644) --- runtime/themes/catpuccin.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/catpuccin.toml b/runtime/themes/catpuccin.toml index f7f113279..da9be4fbd 100644 --- a/runtime/themes/catpuccin.toml +++ b/runtime/themes/catpuccin.toml @@ -42,7 +42,7 @@ label = "peach" "ui.linenr.selected" = { fg = "mauve" } "ui.statusline" = { fg = "black_2", bg = "blue" } "ui.statusline.inactive" = { fg = "pink", bg = "gray_1" } -"ui.popup" = { bg = "black_2" } +"ui.popup" = { bg = "black_1" } "ui.window" = { fg = "maroon" } "ui.help" = { bg = "#7958DC", fg = "#171452" } From 3d91c99c3e64460d292e0393e89d723feefe10aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Thu, 2 Jun 2022 11:30:22 +0900 Subject: [PATCH 271/861] fix: lsp: Sort edits by start range, Omnisharp sends them in reverse --- helix-lsp/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index f33646c82..2bc554e6b 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -173,9 +173,13 @@ pub mod util { pub fn generate_transaction_from_edits( doc: &Rope, - edits: Vec, + mut edits: Vec, offset_encoding: OffsetEncoding, ) -> Transaction { + // Sort edits by start range, since some LSPs (Omnisharp) send them + // in reverse order. + edits.sort_unstable_by_key(|edit| edit.range.start); + Transaction::change( doc, edits.into_iter().map(|edit| { From 6de6a3edbbdb1b9c87051d535e2b55635aa368e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Thu, 2 Jun 2022 13:58:46 +0900 Subject: [PATCH 272/861] fix: lsp: be more defensive about URI conversions --- helix-term/src/commands/lsp.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index bf62fd3c3..761a387b0 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -46,10 +46,16 @@ fn jump_to_location( offset_encoding: OffsetEncoding, action: Action, ) { - let path = location - .uri - .to_file_path() - .expect("unable to convert URI to filepath"); + let path = match location.uri.to_file_path() { + Ok(path) => path, + Err(_) => { + editor.set_error(format!( + "unable to convert URI to filepath: {}", + location.uri + )); + return; + } + }; let _id = editor.open(path, action).expect("editor.open failed"); let (view, doc) = current!(editor); let definition_pos = location.range.start; @@ -344,9 +350,15 @@ pub fn apply_workspace_edit( workspace_edit: &lsp::WorkspaceEdit, ) { let mut apply_edits = |uri: &helix_lsp::Url, text_edits: Vec| { - let path = uri - .to_file_path() - .expect("unable to convert URI to filepath"); + let path = match uri.to_file_path() { + Ok(path) => path, + Err(_) => { + let err = format!("unable to convert URI to filepath: {}", uri); + log::error!("{}", err); + editor.set_error(err); + return; + } + }; let current_view_id = view!(editor).id; let doc_id = editor.open(path, Action::Load).unwrap(); @@ -381,7 +393,7 @@ pub fn apply_workspace_edit( log::debug!("workspace changes: {:?}", changes); for (uri, text_edits) in changes { let text_edits = text_edits.to_vec(); - apply_edits(uri, text_edits); + apply_edits(uri, text_edits) } return; // Not sure if it works properly, it'll be safer to just panic here to avoid breaking some parts of code on which code actions will be used From 378f438fb033561831cd6e0f94845feaf82bbbcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Thu, 2 Jun 2022 14:06:58 +0900 Subject: [PATCH 273/861] fix: lsp: be more defensive about URI conversions --- helix-term/src/commands/lsp.rs | 49 +++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 761a387b0..bfedb209b 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -49,10 +49,8 @@ fn jump_to_location( let path = match location.uri.to_file_path() { Ok(path) => path, Err(_) => { - editor.set_error(format!( - "unable to convert URI to filepath: {}", - location.uri - )); + let err = format!("unable to convert URI to filepath: {}", location.uri); + editor.set_error(err); return; } }; @@ -83,19 +81,37 @@ fn sym_picker( if current_path.as_ref() == Some(&symbol.location.uri) { symbol.name.as_str().into() } else { - let path = symbol.location.uri.to_file_path().unwrap(); - let relative_path = helix_core::path::get_relative_path(path.as_path()) - .to_string_lossy() - .into_owned(); - format!("{} ({})", &symbol.name, relative_path).into() + match symbol.location.uri.to_file_path() { + Ok(path) => { + let relative_path = helix_core::path::get_relative_path(path.as_path()) + .to_string_lossy() + .into_owned(); + format!("{} ({})", &symbol.name, relative_path).into() + } + Err(_) => format!("{} ({})", &symbol.name, &symbol.location.uri).into(), + } } }, move |cx, symbol, action| { if current_path2.as_ref() == Some(&symbol.location.uri) { push_jump(cx.editor); } else { - let path = symbol.location.uri.to_file_path().unwrap(); - cx.editor.open(path, action).expect("editor.open failed"); + let uri = &symbol.location.uri; + let path = match uri.to_file_path() { + Ok(path) => path, + Err(_) => { + let err = format!("unable to convert URI to filepath: {}", uri); + log::error!("{}", err); + cx.editor.set_error(err); + return; + } + }; + if let Err(err) = cx.editor.open(path, action) { + let err = format!("failed to open document: {}: {}", uri, err); + log::error!("{}", err); + cx.editor.set_error(err); + return; + } } let (view, doc) = current!(cx.editor); @@ -361,7 +377,16 @@ pub fn apply_workspace_edit( }; let current_view_id = view!(editor).id; - let doc_id = editor.open(path, Action::Load).unwrap(); + let doc_id = match editor.open(path, Action::Load) { + Ok(doc_id) => doc_id, + Err(err) => { + let err = format!("failed to open document: {}: {}", uri, err); + log::error!("{}", err); + editor.set_error(err); + return; + } + }; + let doc = editor .document_mut(doc_id) .expect("Document for document_changes not found"); From f7c27b604f32cbd10ec42f70d3fec3ff79cacc63 Mon Sep 17 00:00:00 2001 From: Frojdholm Date: Thu, 2 Jun 2022 09:54:11 +0200 Subject: [PATCH 274/861] Ignore SendErrors when handling grammars (#2641) When handling grammars, fetching and building is done in a thread pool. Results are communicated over channels and the receiving channel is closed on first error. This causes subsequent sends to fail causing a mess in stderr. This ignores all SendErrors causing only the first error to be printed. --- helix-loader/src/grammar.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index d2769d81f..7aa9bc834 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -133,7 +133,9 @@ where let tx = tx.clone(); pool.execute(move || { - tx.send(job(grammar)).unwrap(); + // Ignore any SendErrors, if any job in another thread has encountered an + // error the Receiver will be closed causing this send to fail. + let _ = tx.send(job(grammar)); }); } From 4f3d0a77064aac18cc4386df5c43c312c3b03f69 Mon Sep 17 00:00:00 2001 From: Kirawi <67773714+kirawi@users.noreply.github.com> Date: Thu, 2 Jun 2022 11:46:53 -0400 Subject: [PATCH 275/861] append `set_line_ending` to document history (#2649) --- helix-term/src/commands/typed.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 5121eaa18..0b207f947 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -376,6 +376,7 @@ fn set_line_ending( }), ); doc.apply(&transaction, view.id); + doc.append_changes_to_history(view.id); Ok(()) } From 42d780b1037f36bd37e2a8dc40b5e9bb95fb5be7 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Thu, 2 Jun 2022 18:41:17 -0500 Subject: [PATCH 276/861] add tree-sitter-edoc (#2640) * add tree-sitter-edoc * fix escape character capture in markdown queries * add field negation operator "!" to tsq highlights --- book/src/generated/lang-support.md | 1 + languages.toml | 14 ++++++- runtime/queries/edoc/highlights.scm | 50 +++++++++++++++++++++++++ runtime/queries/edoc/injections.scm | 20 ++++++++++ runtime/queries/erlang/injections.scm | 4 +- runtime/queries/markdown/highlights.scm | 2 +- runtime/queries/tsq/highlights.scm | 1 + 7 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 runtime/queries/edoc/highlights.scm create mode 100644 runtime/queries/edoc/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index c4e602452..3f8bc0a4e 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -12,6 +12,7 @@ | dart | ✓ | | ✓ | `dart` | | devicetree | ✓ | | ✓ | | | dockerfile | ✓ | | | `docker-langserver` | +| edoc | ✓ | | | | | eex | ✓ | | | | | ejs | ✓ | | | | | elixir | ✓ | | | `elixir-ls` | diff --git a/languages.toml b/languages.toml index 3e6793656..b29efc199 100644 --- a/languages.toml +++ b/languages.toml @@ -1049,7 +1049,7 @@ language-server = { command = "erlang_ls" } [[grammar]] name = "erlang" -source = { git = "https://github.com/the-mikedavis/tree-sitter-erlang", rev = "6cd8f956ada445b277de1581b5328ae8e8be9aac" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-erlang", rev = "481e7f8ddf27f07a47d1531b6e2b154b89ece31d" } [[language]] name = "kotlin" @@ -1409,3 +1409,15 @@ injection-regex = "verilog" [[grammar]] name = "verilog" source = { git = "https://github.com/andreytkachenko/tree-sitter-verilog", rev = "514d8d70593d29ef3ef667fa6b0e504ae7c977e3" } + +[[language]] +name = "edoc" +scope = "source.edoc" +file-types = ["edoc", "edoc.in"] +injection-regex = "edoc" +roots = [] +indent = { tab-width = 4, unit = " " } + +[[grammar]] +name = "edoc" +source = { git = "https://github.com/the-mikedavis/tree-sitter-edoc", rev = "1691ec0aa7ad1ed9fa295590545f27e570d12d60" } diff --git a/runtime/queries/edoc/highlights.scm b/runtime/queries/edoc/highlights.scm new file mode 100644 index 000000000..3a309960f --- /dev/null +++ b/runtime/queries/edoc/highlights.scm @@ -0,0 +1,50 @@ +((section + (section_marker) @markup.heading.marker + (section_content) @markup.heading.1 + (section_marker) @markup.heading.marker) + (#eq? @markup.heading.marker "==")) + +((section + (section_marker) @markup.heading.marker + (section_content) @markup.heading.2 + (section_marker) @markup.heading.marker) + (#eq? @markup.heading.marker "===")) + +((section + (section_marker) @markup.heading.marker + (section_content) @markup.heading.3 + (section_marker) @markup.heading.marker) + (#eq? @markup.heading.marker "====")) + +(macro (tag) @function.macro) +(tag) @keyword +(macro_escape) @constant.character.escape +(inline_quote) @markup.raw.inline +(email_address) @markup.link.url + +(em_xhtml_tag + (open_xhtml_tag) @tag + (xhtml_tag_content) @markup.italic + (close_xhtml_tag) @tag) + +(strong_xhtml_tag + (open_xhtml_tag) @tag + (xhtml_tag_content) @markup.bold + (close_xhtml_tag) @tag) + +(module) @namespace +(function) @function +(type) @type + +; could be @constant.numeric.integer but this looks similar to a capture +(arity) @operator + +[":" "/"] @operator +["(" ")"] @punctuation.delimiter +["{" "}"] @function.macro + +[ + (quote_marker) + (language_identifier) + (quote_content) +] @markup.raw.block diff --git a/runtime/queries/edoc/injections.scm b/runtime/queries/edoc/injections.scm new file mode 100644 index 000000000..9630995b6 --- /dev/null +++ b/runtime/queries/edoc/injections.scm @@ -0,0 +1,20 @@ +((xhtml_tag) @injection.content + (#set! injection.combined) + (#set! injection.include-children) + (#set! injection.language "html")) + +((block_quote + !language + (quote_content) @injection.content) + (#set! injection.language "erlang")) + +(block_quote + language: (language_identifier) @injection.language + (quote_content) @injection.content) + +((macro + (tag) @_tag + (argument) @injection.content) + (#eq? @_tag "@type") + (#set injection.language "erlang") + (#set injection.include-children)) diff --git a/runtime/queries/erlang/injections.scm b/runtime/queries/erlang/injections.scm index 321c90add..07858185e 100644 --- a/runtime/queries/erlang/injections.scm +++ b/runtime/queries/erlang/injections.scm @@ -1,2 +1,2 @@ -((comment) @injection.content - (#set! injection.language "comment")) +((comment_content) @injection.content + (#set! injection.language "edoc")) diff --git a/runtime/queries/markdown/highlights.scm b/runtime/queries/markdown/highlights.scm index 988a56b6d..44b19741c 100644 --- a/runtime/queries/markdown/highlights.scm +++ b/runtime/queries/markdown/highlights.scm @@ -45,5 +45,5 @@ [ (backslash_escape) (hard_line_break) -] @string.character.escape +] @constant.character.escape diff --git a/runtime/queries/tsq/highlights.scm b/runtime/queries/tsq/highlights.scm index 549895c15..fd5917fb1 100644 --- a/runtime/queries/tsq/highlights.scm +++ b/runtime/queries/tsq/highlights.scm @@ -16,6 +16,7 @@ ] @punctuation.bracket ":" @punctuation.delimiter +"!" @operator [ (one_or_more) From fd4858c03d5457872408bef3e58305c9233e78fc Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Thu, 2 Jun 2022 23:56:47 -0500 Subject: [PATCH 277/861] add tree-sitter-jsdoc (#2650) --- book/src/generated/lang-support.md | 1 + languages.toml | 12 ++++++++++++ runtime/queries/jsdoc/highlights.scm | 2 ++ 3 files changed, 15 insertions(+) create mode 100644 runtime/queries/jsdoc/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 3f8bc0a4e..aa9fc1417 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -41,6 +41,7 @@ | iex | ✓ | | | | | java | ✓ | | | `jdtls` | | javascript | ✓ | | ✓ | `typescript-language-server` | +| jsdoc | ✓ | | | | | json | ✓ | | ✓ | `vscode-json-language-server` | | jsx | ✓ | | ✓ | `typescript-language-server` | | julia | ✓ | | | `julia` | diff --git a/languages.toml b/languages.toml index b29efc199..1f42ddcc0 100644 --- a/languages.toml +++ b/languages.toml @@ -1421,3 +1421,15 @@ indent = { tab-width = 4, unit = " " } [[grammar]] name = "edoc" source = { git = "https://github.com/the-mikedavis/tree-sitter-edoc", rev = "1691ec0aa7ad1ed9fa295590545f27e570d12d60" } + +[[language]] +name = "jsdoc" +scope = "source.jsdoc" +injection-regex = "jsdoc" +file-types = ["jsdoc"] +roots = [] +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "jsdoc" +source = { git = "https://github.com/tree-sitter/tree-sitter-jsdoc", rev = "189a6a4829beb9cdbe837260653b4a3dfb0cc3db" } diff --git a/runtime/queries/jsdoc/highlights.scm b/runtime/queries/jsdoc/highlights.scm new file mode 100644 index 000000000..4b4266c9f --- /dev/null +++ b/runtime/queries/jsdoc/highlights.scm @@ -0,0 +1,2 @@ +(tag_name) @keyword +(type) @type From dfd07543946321223c16aeae3f46398f16f89805 Mon Sep 17 00:00:00 2001 From: nosa <96927121+n0s4@users.noreply.github.com> Date: Fri, 3 Jun 2022 13:09:35 +0100 Subject: [PATCH 278/861] Update keymap docs for window swapping (#2659) --- book/src/keymap.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/book/src/keymap.md b/book/src/keymap.md index 25280d711..fef76efb6 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -224,6 +224,10 @@ This layer is similar to vim keybindings as kakoune does not support window. | `l`, `Ctrl-l`, `Right` | Move to right split | `jump_view_right` | | `q`, `Ctrl-q` | Close current window | `wclose` | | `o`, `Ctrl-o` | Only keep the current window, closing all the others | `wonly` | +| `H` | Swap window to the left | `swap_view_left` | +| `J` | Swap window downwards | `swap_view_down` | +| `K` | Swap window upwards | `swap_view_up` | +| `L` | Swap window to the right | `swap_view_right` | #### Space mode From 5b4e0a304bc85b55202c895622b5cccf930a171f Mon Sep 17 00:00:00 2001 From: nosa <96927121+n0s4@users.noreply.github.com> Date: Sat, 4 Jun 2022 06:10:39 +0100 Subject: [PATCH 279/861] Update selection style of Night Owl (#2668) --- runtime/themes/night_owl.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/night_owl.toml b/runtime/themes/night_owl.toml index a26641b1c..337fae86e 100644 --- a/runtime/themes/night_owl.toml +++ b/runtime/themes/night_owl.toml @@ -17,7 +17,7 @@ 'ui.cursor' = { fg = 'background', bg = 'blue' } 'ui.cursor.primary' = { fg = 'background', bg = 'gold' } 'ui.cursor.match' = { bg = 'selection', modifiers = ['underlined'] } -'ui.selection' = { fg = 'foreground', bg = 'selection' } +'ui.selection' = { bg = 'selection', modifiers = ['dim'] } 'ui.linenr' = { fg = 'grey4', bg = 'background2' } 'ui.linenr.selected' = { fg = 'greyE', bg = 'background2' } 'ui.statusline' = { fg = 'greyE', bg = 'background2' } From 026241cf72df9a684ec889a146bead9266dba374 Mon Sep 17 00:00:00 2001 From: gavynriebau Date: Sun, 5 Jun 2022 10:27:41 +0800 Subject: [PATCH 280/861] Fix panic on close last buffer (#2367) (#2658) * Fix panic on close last buffer (#2367) In certain circumstances it was possible to cause a panic when closing buffers due to some mishandling of view document history. A change has been made to delete removed documents from the history of accessed documents for each view. The ensures we don't attempt to jump to a deleted document by mistake. * Move remove document code into View function 'remove_document' * Replace 'view.jumps.remove' call with 'view.remove_document' call --- helix-view/src/editor.rs | 5 ++--- helix-view/src/view.rs | 5 +++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index c53fcc7f7..f2fb43018 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -681,7 +681,7 @@ impl Editor { // Remove the scratch buffer from any jumplists for (view, _) in self.tree.views_mut() { - view.jumps.remove(&id) + view.remove_document(&id); } } else { let jump = (view.doc, doc.selection(view.id).clone()); @@ -814,8 +814,7 @@ impl Editor { .tree .views_mut() .filter_map(|(view, _focus)| { - // remove the document from jump list of all views - view.jumps.remove(&doc_id); + view.remove_document(&doc_id); if view.doc == doc_id { // something was previously open in the view, switch to previous doc diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 091d1f2ee..a496fe330 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -316,6 +316,11 @@ impl View { )) } + pub fn remove_document(&mut self, doc_id: &DocumentId) { + self.jumps.remove(doc_id); + self.docs_access_history.retain(|doc| doc != doc_id); + } + // pub fn traverse(&self, text: RopeSlice, start: usize, end: usize, fun: F) // where // F: Fn(usize, usize), From d24ca66dbb5e67ed609f7b2cf11abaee05beaef7 Mon Sep 17 00:00:00 2001 From: yzwduck Date: Sun, 5 Jun 2022 18:44:55 +0800 Subject: [PATCH 281/861] Avoid modifying jumplist until jumping to ref (#2670) When a goto command is cancelled, the jumplist should remain unchanged. This commit delays saving the current selection to the jumplist until jumping to a reference. --- helix-term/src/commands/lsp.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index bfedb209b..8f139b3bd 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -485,8 +485,6 @@ fn goto_impl( locations: Vec, offset_encoding: OffsetEncoding, ) { - push_jump(editor); - let cwdir = std::env::current_dir().expect("couldn't determine current directory"); match locations.as_slice() { @@ -520,6 +518,7 @@ fn goto_impl( format!("{}:{}", file, line).into() }, move |cx, location, action| { + push_jump(cx.editor); jump_to_location(cx.editor, location, offset_encoding, action) }, move |_editor, location| Some(location_to_file_location(location)), From 1c2aaf3bafd363ac5efd4befdb1d65bf5895769f Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 5 Jun 2022 05:48:16 -0500 Subject: [PATCH 282/861] ensure :quit and :quit! take no arguments (#2654) --- helix-term/src/commands/typed.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 0b207f947..fd33e6b4c 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -15,9 +15,11 @@ pub struct TypableCommand { fn quit( cx: &mut compositor::Context, - _args: &[Cow], + args: &[Cow], _event: PromptEvent, ) -> anyhow::Result<()> { + ensure!(args.is_empty(), ":quit takes no arguments"); + // last view and we have unsaved changes if cx.editor.tree.views().count() == 1 { buffers_remaining_impl(cx.editor)? @@ -30,9 +32,11 @@ fn quit( fn force_quit( cx: &mut compositor::Context, - _args: &[Cow], + args: &[Cow], _event: PromptEvent, ) -> anyhow::Result<()> { + ensure!(args.is_empty(), ":quit! takes no arguments"); + cx.editor.close(view!(cx.editor).id); Ok(()) From b2bd87df81756d4925bf1f4da6962b9dd83a807c Mon Sep 17 00:00:00 2001 From: gavynriebau Date: Sun, 5 Jun 2022 18:49:41 +0800 Subject: [PATCH 283/861] Fix crash due to cycles when replaying macros (#2647) In certain circumstances it was possible to get into an infinite loop when replaying macros such as when different macros attempt to replay each other. This commit adds changes to track which macros are currently being replayed and prevent getting into infinite loops. --- helix-term/src/commands.rs | 13 +++++++++++++ helix-view/src/editor.rs | 2 ++ 2 files changed, 15 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 44e2f8c22..e7efa6c37 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4617,6 +4617,17 @@ fn record_macro(cx: &mut Context) { fn replay_macro(cx: &mut Context) { let reg = cx.register.unwrap_or('@'); + + if cx.editor.macro_replaying.contains(®) { + cx.editor.set_error(format!( + "Cannot replay from register [{}] because already replaying from same register", + reg + )); + return; + } + + cx.editor.macro_replaying.push(reg); + let keys: Vec = if let Some([keys_str]) = cx.editor.registers.read(reg) { match helix_view::input::parse_macro(keys_str) { Ok(keys) => keys, @@ -4638,4 +4649,6 @@ fn replay_macro(cx: &mut Context) { } } })); + + cx.editor.macro_replaying.pop(); } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index f2fb43018..8e53936a4 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -433,6 +433,7 @@ pub struct Editor { pub selected_register: Option, pub registers: Registers, pub macro_recording: Option<(char, Vec)>, + pub macro_replaying: Vec, pub theme: Theme, pub language_servers: helix_lsp::Registry, @@ -503,6 +504,7 @@ impl Editor { count: None, selected_register: None, macro_recording: None, + macro_replaying: Vec::new(), theme: theme_loader.default(), language_servers, debugger: None, From f92a25a856d572c7bd4b8e597a3f86ce211e81d5 Mon Sep 17 00:00:00 2001 From: farwyler <1705805+farwyler@users.noreply.github.com> Date: Sun, 5 Jun 2022 12:50:57 +0200 Subject: [PATCH 284/861] Passing extra formatting options to LSPs (#2635) * allows passing extra formatting options to LSPs - adds optional field 'format' to [[language]] sections in 'languages.toml' - passes specified options the LSPs via FormattingOptions * cleaner conversion of formatting properties * move formatting options inside lsp::Client * cleans up formatting properties merge --- book/src/languages.md | 12 ++++++++++++ helix-core/src/syntax.rs | 1 + helix-lsp/src/client.rs | 20 ++++++++++++++++++++ helix-view/src/document.rs | 1 + 4 files changed, 34 insertions(+) diff --git a/book/src/languages.md b/book/src/languages.md index 1fa247879..8c27785e2 100644 --- a/book/src/languages.md +++ b/book/src/languages.md @@ -14,6 +14,18 @@ name = "rust" auto-format = false ``` +## LSP formatting options + +Use `format` field to pass extra formatting options to [Document Formatting Requests](https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-16.md#document-formatting-request--leftwards_arrow_with_hook). + +```toml +[[language]] +name = "typescript" +auto-format = true +# pass format options according to https://github.com/typescript-language-server/typescript-language-server#workspacedidchangeconfiguration omitting the "[language].format." prefix. +config = { format = { "semicolons" = "insert", "insertSpaceBeforeFunctionParenthesis" = true } } +``` + ## Tree-sitter grammars Tree-sitter grammars can also be configured in `languages.toml`: diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 1cfa04e7c..ca497b648 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -78,6 +78,7 @@ pub struct LanguageConfiguration { #[serde(default)] pub auto_format: bool, + #[serde(default)] pub diagnostic_severity: Severity, diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 08201b3f4..7f556ca6d 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -7,7 +7,9 @@ use anyhow::anyhow; use helix_core::{find_root, ChangeSet, Rope}; use jsonrpc_core as jsonrpc; use lsp_types as lsp; +use serde::Deserialize; use serde_json::Value; +use std::collections::HashMap; use std::future::Future; use std::process::Stdio; use std::sync::{ @@ -693,6 +695,24 @@ impl Client { }; // TODO: return err::unavailable so we can fall back to tree sitter formatting + // merge FormattingOptions with 'config.format' + let config_format = self + .config + .as_ref() + .and_then(|cfg| cfg.get("format")) + .and_then(|fmt| HashMap::::deserialize(fmt).ok()); + + let options = if let Some(mut properties) = config_format { + // passed in options take precedence over 'config.format' + properties.extend(options.properties); + lsp::FormattingOptions { + properties, + ..options + } + } else { + options + }; + let params = lsp::DocumentFormattingParams { text_document, options, diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 9c3853c82..2c4b5de96 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -410,6 +410,7 @@ impl Document { let language_server = self.language_server()?; let text = self.text.clone(); let offset_encoding = language_server.offset_encoding(); + let request = language_server.text_document_formatting( self.identifier(), lsp::FormattingOptions { From f1ae496860e10560d9a8b91a721168524411096a Mon Sep 17 00:00:00 2001 From: Termina94 <47091253+Termina94@users.noreply.github.com> Date: Sun, 5 Jun 2022 11:52:41 +0100 Subject: [PATCH 285/861] Add shell insert commands to typable and config (#2589) * Add shell insert commands to typable and config * generate docs Co-authored-by: Dean Revell --- book/src/generated/typable-cmd.md | 2 ++ helix-term/src/commands/typed.rs | 34 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 5ae184daf..71a33fa72 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -64,5 +64,7 @@ | `:config-reload` | Refreshes helix's config. | | `:config-open` | Open the helix config.toml file. | | `:log-open` | Open the helix log file. | +| `:insert-output` | Run shell command, inserting output after each selection. | +| `:append-output` | Run shell command, appending output after each selection. | | `:pipe` | Pipe each selection to the shell command. | | `: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 fd33e6b4c..0f8884dbb 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1172,6 +1172,26 @@ fn refresh_config( Ok(()) } +fn append_output( + cx: &mut compositor::Context, + args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + ensure!(!args.is_empty(), "Shell command required"); + shell(cx, &args.join(" "), &ShellBehavior::Append); + Ok(()) +} + +fn insert_output( + cx: &mut compositor::Context, + args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + ensure!(!args.is_empty(), "Shell command required"); + shell(cx, &args.join(" "), &ShellBehavior::Insert); + Ok(()) +} + fn pipe( cx: &mut compositor::Context, args: &[Cow], @@ -1671,6 +1691,20 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: open_log, completer: None, }, + TypableCommand { + name: "insert-output", + aliases: &[], + doc: "Run shell command, inserting output after each selection.", + fun: insert_output, + completer: None, + }, + TypableCommand { + name: "append-output", + aliases: &[], + doc: "Run shell command, appending output after each selection.", + fun: append_output, + completer: None, + }, TypableCommand { name: "pipe", aliases: &[], From 0035c29fc16f6c795257e241fddd9f2178bc4b4c Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 5 Jun 2022 05:53:20 -0500 Subject: [PATCH 286/861] Use a minimal binary to fetch grammar sources in release CI (#2557) This is an optimization for the release CI. The release CI can take a while since it compiles release builds for all operating systems. We cut down on duplicate work and overall time by fetching tree-sitter grammar repositories and then using those repositories in all later steps. Previously we built all of helix just to run helix_loader::grammar::fetch_grammars() which is wasteful on time. With this change we only build the helix-loader crate. --- .github/workflows/release.yml | 4 +--- helix-loader/Cargo.toml | 5 ++++- helix-loader/src/main.rs | 9 +++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 helix-loader/src/main.rs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index efeb77e09..a83a14239 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,11 +23,9 @@ jobs: - name: Fetch tree-sitter grammars uses: actions-rs/cargo@v1 - env: - HELIX_DISABLE_AUTO_GRAMMAR_BUILD: yes with: command: run - args: -- --grammar fetch + args: --package=helix-loader --bin=hx-loader - name: Bundle grammars run: tar cJf grammars.tar.xz -C runtime/grammars/sources . diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index aee03fc29..203844727 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -9,6 +9,10 @@ categories = ["editor"] repository = "https://github.com/helix-editor/helix" homepage = "https://helix-editor.com" +[[bin]] +name = "hx-loader" +path = "src/main.rs" + [dependencies] anyhow = "1" serde = { version = "1.0", features = ["derive"] } @@ -27,4 +31,3 @@ threadpool = { version = "1.0" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] libloading = "0.7" - diff --git a/helix-loader/src/main.rs b/helix-loader/src/main.rs new file mode 100644 index 000000000..c1ce45ffa --- /dev/null +++ b/helix-loader/src/main.rs @@ -0,0 +1,9 @@ +use anyhow::Result; +use helix_loader::grammar::fetch_grammars; + +// This binary is used in the Release CI as an optimization to cut down on +// compilation time. This is not meant to be run manually. + +fn main() -> Result<()> { + fetch_grammars() +} From 8351a82c2cae58dd49c654d0e878c9d7227ef9c8 Mon Sep 17 00:00:00 2001 From: Henry Date: Sun, 5 Jun 2022 22:22:10 -0400 Subject: [PATCH 287/861] simplify some keymap key names (#2677) --- book/src/remapping.md | 5 ----- helix-view/src/input.rs | 38 ++++++++++++++++++-------------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/book/src/remapping.md b/book/src/remapping.md index 1cdf9b1f2..bd4ac7f81 100644 --- a/book/src/remapping.md +++ b/book/src/remapping.md @@ -33,12 +33,7 @@ Control, Shift and Alt modifiers are encoded respectively with the prefixes | Backspace | `"backspace"` | | Space | `"space"` | | Return/Enter | `"ret"` | -| < | `"lt"` | -| \> | `"gt"` | -| \+ | `"plus"` | | \- | `"minus"` | -| ; | `"semicolon"` | -| % | `"percent"` | | Left | `"left"` | | Right | `"right"` | | Up | `"up"` | diff --git a/helix-view/src/input.rs b/helix-view/src/input.rs index 14dadc3b9..b4875d491 100644 --- a/helix-view/src/input.rs +++ b/helix-view/src/input.rs @@ -41,12 +41,7 @@ pub(crate) mod keys { pub(crate) const NULL: &str = "null"; pub(crate) const ESC: &str = "esc"; pub(crate) const SPACE: &str = "space"; - pub(crate) const LESS_THAN: &str = "lt"; - pub(crate) const GREATER_THAN: &str = "gt"; - pub(crate) const PLUS: &str = "plus"; pub(crate) const MINUS: &str = "minus"; - pub(crate) const SEMICOLON: &str = "semicolon"; - pub(crate) const PERCENT: &str = "percent"; } impl fmt::Display for KeyEvent { @@ -86,12 +81,7 @@ impl fmt::Display for KeyEvent { KeyCode::Null => f.write_str(keys::NULL)?, KeyCode::Esc => f.write_str(keys::ESC)?, KeyCode::Char(' ') => f.write_str(keys::SPACE)?, - KeyCode::Char('<') => f.write_str(keys::LESS_THAN)?, - KeyCode::Char('>') => f.write_str(keys::GREATER_THAN)?, - KeyCode::Char('+') => f.write_str(keys::PLUS)?, KeyCode::Char('-') => f.write_str(keys::MINUS)?, - KeyCode::Char(';') => f.write_str(keys::SEMICOLON)?, - KeyCode::Char('%') => f.write_str(keys::PERCENT)?, KeyCode::F(i) => f.write_fmt(format_args!("F{}", i))?, KeyCode::Char(c) => f.write_fmt(format_args!("{}", c))?, }; @@ -119,12 +109,7 @@ impl UnicodeWidthStr for KeyEvent { KeyCode::Null => keys::NULL.len(), KeyCode::Esc => keys::ESC.len(), KeyCode::Char(' ') => keys::SPACE.len(), - KeyCode::Char('<') => keys::LESS_THAN.len(), - KeyCode::Char('>') => keys::GREATER_THAN.len(), - KeyCode::Char('+') => keys::PLUS.len(), KeyCode::Char('-') => keys::MINUS.len(), - KeyCode::Char(';') => keys::SEMICOLON.len(), - KeyCode::Char('%') => keys::PERCENT.len(), KeyCode::F(1..=9) => 2, KeyCode::F(_) => 3, KeyCode::Char(c) => c.width().unwrap_or(0), @@ -168,12 +153,7 @@ impl std::str::FromStr for KeyEvent { keys::NULL => KeyCode::Null, keys::ESC => KeyCode::Esc, keys::SPACE => KeyCode::Char(' '), - keys::LESS_THAN => KeyCode::Char('<'), - keys::GREATER_THAN => KeyCode::Char('>'), - keys::PLUS => KeyCode::Char('+'), keys::MINUS => KeyCode::Char('-'), - keys::SEMICOLON => KeyCode::Char(';'), - keys::PERCENT => KeyCode::Char('%'), 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(); @@ -336,6 +316,14 @@ mod test { modifiers: KeyModifiers::NONE } ); + + assert_eq!( + str::parse::("%").unwrap(), + KeyEvent { + code: KeyCode::Char('%'), + modifiers: KeyModifiers::NONE + } + ) } #[test] @@ -375,6 +363,16 @@ mod test { assert!(str::parse::("FU").is_err()); assert!(str::parse::("123").is_err()); assert!(str::parse::("S--").is_err()); + assert!(str::parse::("S-percent").is_err()); + } + + #[test] + fn parsing_unsupported_named_keys() { + assert!(str::parse::("lt").is_err()); + assert!(str::parse::("gt").is_err()); + assert!(str::parse::("plus").is_err()); + assert!(str::parse::("percent").is_err()); + assert!(str::parse::("semicolon").is_err()); } #[test] From b14c258a2c447b892c89d3e68ef4c9a74effca85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Tue, 7 Jun 2022 00:08:47 +0900 Subject: [PATCH 288/861] prompt: If submitting empty prompt, use default (last used) --- helix-core/src/register.rs | 4 ++++ helix-term/src/commands.rs | 8 ++++---- helix-term/src/ui/mod.rs | 19 +++++++------------ helix-term/src/ui/prompt.rs | 26 ++++++++++++++++++++++++-- 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/helix-core/src/register.rs b/helix-core/src/register.rs index b39e4034e..7fa34644b 100644 --- a/helix-core/src/register.rs +++ b/helix-core/src/register.rs @@ -69,6 +69,10 @@ impl Registers { self.get(name).map(|reg| reg.read()) } + pub fn first(&self, name: char) -> Option<&String> { + self.read(name).and_then(|entries| entries.first()) + } + pub fn inner(&self) -> &HashMap { &self.inner } diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index e7efa6c37..e2ef8f2a9 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1488,7 +1488,7 @@ fn select_regex(cx: &mut Context) { Some(reg), ui::completers::none, move |view, doc, regex, event| { - if event != PromptEvent::Update { + if !matches!(event, PromptEvent::Update | PromptEvent::Validate) { return; } let text = doc.text().slice(..); @@ -1509,7 +1509,7 @@ fn split_selection(cx: &mut Context) { Some(reg), ui::completers::none, move |view, doc, regex, event| { - if event != PromptEvent::Update { + if !matches!(event, PromptEvent::Update | PromptEvent::Validate) { return; } let text = doc.text().slice(..); @@ -1657,7 +1657,7 @@ fn searcher(cx: &mut Context, direction: Direction) { .collect() }, move |view, doc, regex, event| { - if event != PromptEvent::Update { + if !matches!(event, PromptEvent::Update | PromptEvent::Validate) { return; } search_impl( @@ -3563,7 +3563,7 @@ fn keep_or_remove_selections_impl(cx: &mut Context, remove: bool) { Some(reg), ui::completers::none, move |view, doc, regex, event| { - if event != PromptEvent::Update { + if !matches!(event, PromptEvent::Update | PromptEvent::Validate) { return; } let text = doc.text().slice(..); diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 2dca870ba..6dea21924 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -63,18 +63,8 @@ pub fn regex_prompt( doc.set_selection(view.id, snapshot.clone()); view.offset = offset_snapshot; } - PromptEvent::Validate => match Regex::new(input) { - Ok(regex) => { - let (view, doc) = current!(cx.editor); - // Equivalent to push_jump to store selection just before jump - view.jumps.push((doc_id, snapshot.clone())); - fun(view, doc, regex, event); - } - Err(_err) => (), // TODO: mark command line as error - }, - - PromptEvent::Update => { - // skip empty input, TODO: trigger default + PromptEvent::Update | PromptEvent::Validate => { + // skip empty input if input.is_empty() { return; } @@ -96,6 +86,11 @@ pub fn regex_prompt( // revert state to what it was before the last update doc.set_selection(view.id, snapshot.clone()); + if event == PromptEvent::Validate { + // Equivalent to push_jump to store selection just before jump + view.jumps.push((doc_id, snapshot.clone())); + } + fun(view, doc, regex, event); view.ensure_cursor_in_view(doc, config.scrolloff); diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index a5be33ffe..64154bae3 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -442,10 +442,21 @@ impl Prompt { let line = area.height - 1; // render buffer text surface.set_string(area.x, area.y + line, &self.prompt, prompt_color); + + let input: Cow = if self.line.is_empty() { + // latest value in the register list + self.history_register + .and_then(|reg| cx.editor.registers.first(reg).cloned()) // TODO: can we avoid cloning? + .map(|entry| entry.into()) + .unwrap_or_else(|| Cow::from("")) + } else { + self.line.as_str().into() + }; + surface.set_string( area.x + self.prompt.len() as u16, area.y + line, - &self.line, + &input, prompt_color, ); } @@ -510,7 +521,18 @@ impl Component for Prompt { self.recalculate_completion(cx.editor); self.exit_selection(); } else { - (self.callback_fn)(cx, &self.line, PromptEvent::Validate); + // handle executing with last command in history if nothing entered + let input: Cow = if self.line.is_empty() { + // latest value in the register list + self.history_register + .and_then(|reg| cx.editor.registers.first(reg).cloned()) + .map(|entry| entry.into()) + .unwrap_or_else(|| Cow::from("")) + } else { + self.line.as_str().into() + }; + + (self.callback_fn)(cx, &input, PromptEvent::Validate); if let Some(register) = self.history_register { // store in history From 3d9923969afb56be03b87a6a1cc47c486bead66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Tue, 7 Jun 2022 00:11:08 +0900 Subject: [PATCH 289/861] minor: Simplify Document.language_id() --- helix-view/src/document.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 2c4b5de96..a2d2af77c 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -854,9 +854,11 @@ impl Document { /// `language-server` configuration, or the document language if no /// `language-id` has been specified. pub fn language_id(&self) -> Option<&str> { - self.language_config() - .and_then(|config| config.language_server.as_ref()) - .and_then(|lsp_config| lsp_config.language_id.as_deref()) + self.language_config()? + .language_server + .as_ref()? + .language_id + .as_deref() .or_else(|| Some(self.language()?.rsplit_once('.')?.1)) } From 26dbdb70fb29bdad2e875a776b70815bf5533a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Tue, 7 Jun 2022 00:19:01 +0900 Subject: [PATCH 290/861] Refactor push_jump so we're not needlessly fetching doc twice --- helix-term/src/commands.rs | 21 ++++++++++----------- helix-term/src/commands/lsp.rs | 12 +++++++----- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index e2ef8f2a9..628fd8fbc 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -965,19 +965,18 @@ fn goto_file_start(cx: &mut Context) { if cx.count.is_some() { goto_line(cx); } else { - push_jump(cx.editor); let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); let selection = doc .selection(view.id) .clone() .transform(|range| range.put_cursor(text, 0, doc.mode == Mode::Select)); + push_jump(view, doc); doc.set_selection(view.id, selection); } } fn goto_file_end(cx: &mut Context) { - push_jump(cx.editor); let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); let pos = doc.text().len_chars(); @@ -985,6 +984,7 @@ fn goto_file_end(cx: &mut Context) { .selection(view.id) .clone() .transform(|range| range.put_cursor(text, pos, doc.mode == Mode::Select)); + push_jump(view, doc); doc.set_selection(view.id, selection); } @@ -2485,8 +2485,7 @@ fn try_restore_indent(doc: &mut Document, view_id: ViewId) { } // Store a jump on the jumplist. -fn push_jump(editor: &mut Editor) { - let (view, doc) = current!(editor); +fn push_jump(view: &mut View, doc: &Document) { let jump = (doc.id(), doc.selection(view.id).clone()); view.jumps.push(jump); } @@ -2497,8 +2496,6 @@ fn goto_line(cx: &mut Context) { fn goto_line_impl(editor: &mut Editor, count: Option) { if let Some(count) = count { - push_jump(editor); - let (view, doc) = current!(editor); let max_line = if doc.text().line(doc.text().len_lines() - 1).len_chars() == 0 { // If the last line is blank, don't jump to it. @@ -2513,13 +2510,13 @@ fn goto_line_impl(editor: &mut Editor, count: Option) { .selection(view.id) .clone() .transform(|range| range.put_cursor(text, pos, doc.mode == Mode::Select)); + + push_jump(view, doc); doc.set_selection(view.id, selection); } } fn goto_last_line(cx: &mut Context) { - push_jump(cx.editor); - let (view, doc) = current!(cx.editor); let line_idx = if doc.text().line(doc.text().len_lines() - 1).len_chars() == 0 { // If the last line is blank, don't jump to it. @@ -2533,6 +2530,8 @@ fn goto_last_line(cx: &mut Context) { .selection(view.id) .clone() .transform(|range| range.put_cursor(text, pos, doc.mode == Mode::Select)); + + push_jump(view, doc); doc.set_selection(view.id, selection); } @@ -2601,10 +2600,9 @@ fn exit_select_mode(cx: &mut Context) { } fn goto_pos(editor: &mut Editor, pos: usize) { - push_jump(editor); - let (view, doc) = current!(editor); + push_jump(view, doc); doc.set_selection(view.id, Selection::point(pos)); align_view(doc, view, Align::Center); } @@ -3886,7 +3884,8 @@ fn jump_backward(cx: &mut Context) { } fn save_selection(cx: &mut Context) { - push_jump(cx.editor); + let (view, doc) = current!(cx.editor); + push_jump(view, doc); cx.editor.set_status("Selection saved to jumplist"); } diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 8f139b3bd..93ae23536 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -39,13 +39,15 @@ fn location_to_file_location(location: &lsp::Location) -> FileLocation { } // TODO: share with symbol picker(symbol.location) -// TODO: need to use push_jump() before? fn jump_to_location( editor: &mut Editor, location: &lsp::Location, offset_encoding: OffsetEncoding, action: Action, ) { + let (view, doc) = current!(editor); + push_jump(view, doc); + let path = match location.uri.to_file_path() { Ok(path) => path, Err(_) => { @@ -93,9 +95,10 @@ fn sym_picker( } }, move |cx, symbol, action| { - if current_path2.as_ref() == Some(&symbol.location.uri) { - push_jump(cx.editor); - } else { + let (view, doc) = current!(cx.editor); + push_jump(view, doc); + + if current_path2.as_ref() != Some(&symbol.location.uri) { let uri = &symbol.location.uri; let path = match uri.to_file_path() { Ok(path) => path, @@ -518,7 +521,6 @@ fn goto_impl( format!("{}:{}", file, line).into() }, move |cx, location, action| { - push_jump(cx.editor); jump_to_location(cx.editor, location, offset_encoding, action) }, move |_editor, location| Some(location_to_file_location(location)), From f0d1c855539cfeb8e66c3602a971857f8c20be0f Mon Sep 17 00:00:00 2001 From: farwyler <1705805+farwyler@users.noreply.github.com> Date: Mon, 6 Jun 2022 19:26:56 +0200 Subject: [PATCH 291/861] support for openscad (#2680) Co-authored-by: Michael Davis --- book/src/generated/lang-support.md | 1 + languages.toml | 15 ++++++ runtime/queries/openscad/highlights.scm | 63 +++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 runtime/queries/openscad/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index aa9fc1417..1d9b89a40 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -63,6 +63,7 @@ | ocaml | ✓ | | ✓ | `ocamllsp` | | ocaml-interface | ✓ | | | `ocamllsp` | | odin | ✓ | | | | +| openscad | ✓ | | | `openscad-language-server` | | org | ✓ | | | | | perl | ✓ | ✓ | ✓ | | | php | ✓ | ✓ | ✓ | `intelephense` | diff --git a/languages.toml b/languages.toml index 1f42ddcc0..7ab8ff845 100644 --- a/languages.toml +++ b/languages.toml @@ -1433,3 +1433,18 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "jsdoc" source = { git = "https://github.com/tree-sitter/tree-sitter-jsdoc", rev = "189a6a4829beb9cdbe837260653b4a3dfb0cc3db" } + + +[[language]] +name = "openscad" +scope = "source.openscad" +injection-regex = "openscad" +file-types = ["scad"] +roots = [] +comment-token = "//" +language-server = { command = "openscad-language-server" } +indent = { tab-width = 2, unit = "\t" } + +[[grammar]] +name = "openscad" +source = { git = "https://github.com/bollian/tree-sitter-openscad", rev = "5c3ce93df0ac1da7197cf6ae125aade26d6b8972" } diff --git a/runtime/queries/openscad/highlights.scm b/runtime/queries/openscad/highlights.scm new file mode 100644 index 000000000..c06738e85 --- /dev/null +++ b/runtime/queries/openscad/highlights.scm @@ -0,0 +1,63 @@ +(number) @constant.numeric +(string) @string +(boolean) @constant.builtin.boolean +(include_path) @string.special.path + +(parameters_declaration (identifier) @variable.parameter) +(function_declaration name: (identifier) @function) + +(function_call function: (identifier) @function) +(module_call name: (identifier) @function) + +(identifier) @variable +(special_variable) @variable.builtin + +[ + "function" + "let" + "assign" +] @keyword + +[ + "for" + "each" + "intersection_for" +] @keyword.control.repeat + +[ + "if" +] @keyword.control.conditional + +[ + "module" + "use" + "include" +] @keyword.control.import + +[ + "||" + "&&" + "==" + "!=" + "<" + ">" + "<=" + ">=" + "+" + "-" + "*" + "/" + "%" + "^" + "?" + "!" + ":" +] @operator + +[ + ";" + "," + "." +] @punctuation.delimiter + +(comment) @comment \ No newline at end of file From bb83ea83938b7098cc1c1823c791d3b05dd5399f Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Mon, 6 Jun 2022 22:24:52 +0300 Subject: [PATCH 292/861] chore(nix): format nix files with alejandra, update deps, minor code refactors (#2683) --- flake.lock | 65 +++++++++++++--------------------- flake.nix | 99 ++++++++++++++++++++++++++++++++++------------------ grammars.nix | 96 ++++++++++++++++++++++++++++---------------------- shell.nix | 11 +++--- 4 files changed, 149 insertions(+), 122 deletions(-) diff --git a/flake.lock b/flake.lock index 8fb4a4667..50a7b77b0 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "crane": { "flake": false, "locked": { - "lastModified": 1644785799, - "narHash": "sha256-VpAJO1L0XeBvtCuNGK4IDKp6ENHIpTrlaZT7yfBCvwo=", + "lastModified": 1654444508, + "narHash": "sha256-4OBvQ4V7jyt7afs6iKUvRzJ1u/9eYnKzVQbeQdiamuY=", "owner": "ipetkov", "repo": "crane", - "rev": "fc7a94f841347c88f2cb44217b2a3faa93e2a0b2", + "rev": "db5482bf225acc3160899124a1df5a617cfa27b5", "type": "github" }, "original": { @@ -17,19 +17,13 @@ } }, "devshell": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": [ - "nixCargoIntegration", - "nixpkgs" - ] - }, + "flake": false, "locked": { - "lastModified": 1652959711, - "narHash": "sha256-wpQhlE/NocxlU3jLiMoF1KYHOEFD5MEFJZkyXXVVef8=", + "lastModified": 1653917170, + "narHash": "sha256-FyxOnEE/V4PNEcMU62ikY4FfYPo349MOhMM97HS0XEo=", "owner": "numtide", "repo": "devshell", - "rev": "a5327cd01e58d2848c73062f2661278ad615748f", + "rev": "fc7a3e3adde9bbcab68af6d1e3c6eb738e296a92", "type": "github" }, "original": { @@ -45,6 +39,10 @@ "nixpkgs" ], "crane": "crane", + "devshell": [ + "nixCargoIntegration", + "devshell" + ], "flake-utils-pre-commit": [ "nixCargoIntegration", "nixpkgs" @@ -75,11 +73,11 @@ ] }, "locked": { - "lastModified": 1653135531, - "narHash": "sha256-pYwJrEQrG8BgeVcI+lveK3KbOBDx9MT28HxV09v+jgI=", + "lastModified": 1654451959, + "narHash": "sha256-yWztC96o8Dw65jDbmNUxV1i61T3uLqvqhC3ziwnB/Fk=", "owner": "nix-community", "repo": "dream2nix", - "rev": "4b3dfb101fd2fdbe25bd128072f138276aa4bc82", + "rev": "90b353682ef927bd39b59085e0dc6b7454888de7", "type": "github" }, "original": { @@ -89,21 +87,6 @@ } }, "flake-utils": { - "locked": { - "lastModified": 1642700792, - "narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "846b2ae0fc4cc943637d3d1def4454213e203cba", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_2": { "locked": { "lastModified": 1637014545, "narHash": "sha256-26IZAc5yzlD9FlDT54io1oqG/bBoyka+FJk5guaX4x4=", @@ -130,11 +113,11 @@ ] }, "locked": { - "lastModified": 1653286465, - "narHash": "sha256-CEI2prA74sy9SgAJKdDpyAMv1nnp91c8e5Fw9QbtR/Q=", + "lastModified": 1654531591, + "narHash": "sha256-DtDAwkl2Pn8w1BW1z2OssT/bWjVhMZQBBpr2uDY7tHY=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "95efd76ab68b20aba45b7d647460319b88c2a4c0", + "rev": "c935099d6851d0ff94098e9a12f42147524f0c5b", "type": "github" }, "original": { @@ -145,11 +128,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1653060744, - "narHash": "sha256-kfRusllRumpt33J1hPV+CeCCylCXEU7e0gn2/cIM7cY=", + "lastModified": 1654230545, + "narHash": "sha256-8Vlwf0x8ow6pPOK2a04bT+pxIeRnM1+O0Xv9/CuDzRs=", "owner": "nixos", "repo": "nixpkgs", - "rev": "dfd82985c273aac6eced03625f454b334daae2e8", + "rev": "236cc2971ac72acd90f0ae3a797f9f83098b17ec", "type": "github" }, "original": { @@ -168,17 +151,17 @@ }, "rust-overlay": { "inputs": { - "flake-utils": "flake-utils_2", + "flake-utils": "flake-utils", "nixpkgs": [ "nixpkgs" ] }, "locked": { - "lastModified": 1653273659, - "narHash": "sha256-dHXYaNL1axhZZyiZXxt1WKhvZrYXq7bjCs3y5VjgyGI=", + "lastModified": 1654483484, + "narHash": "sha256-Ki/sMgrUEj+31P3YMzZZp5Nea7+MQVVTdaRWQVS1PL4=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "0fa3e01da1ce98e3b40063b8e2678095943402b1", + "rev": "6bc59b9c4ad1cc1089219e935aa727a96d948c5d", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 495e441a8..1949580dc 100644 --- a/flake.nix +++ b/flake.nix @@ -14,10 +14,14 @@ }; }; - outputs = inputs@{ nixCargoIntegration, ... }: + outputs = inputs @ { + nixpkgs, + nixCargoIntegration, + ... + }: nixCargoIntegration.lib.makeOutputs { root = ./.; - renameOutputs = { "helix-term" = "helix"; }; + renameOutputs = {"helix-term" = "helix";}; # Set default app to hx (binary is from helix-term release build) # Set default package to helix-term release build defaultOutputs = { @@ -25,41 +29,70 @@ package = "helix"; }; overrides = { - cCompiler = common: if common.pkgs.stdenv.isLinux then common.pkgs.gcc else common.pkgs.clang; + cCompiler = common: + with common.pkgs; + if stdenv.isLinux + then gcc + else clang; crateOverrides = common: _: { - helix-term = prev: - let - inherit (common) pkgs; - grammars = pkgs.callPackage ./grammars.nix { }; - runtimeDir = pkgs.runCommand "helix-runtime" { } '' - mkdir -p $out - ln -s ${common.root}/runtime/* $out - rm -r $out/grammars - ln -s ${grammars} $out/grammars - ''; - in - { - # disable fetching and building of tree-sitter grammars in the helix-term build.rs - HELIX_DISABLE_AUTO_GRAMMAR_BUILD = "1"; - # link languages and theme toml files since helix-term expects them (for tests) - preConfigure = "ln -s ${common.root}/{languages.toml,theme.toml,base16_theme.toml} .."; - buildInputs = (prev.buildInputs or [ ]) ++ [ common.cCompiler.cc.lib ]; - nativeBuildInputs = [ pkgs.makeWrapper ]; + helix-term = prev: let + inherit (common) pkgs; + mkRootPath = rel: + builtins.path { + path = "${common.root}/${rel}"; + name = rel; + }; + grammars = pkgs.callPackage ./grammars.nix {}; + runtimeDir = pkgs.runCommandNoCC "helix-runtime" {} '' + mkdir -p $out + ln -s ${mkRootPath "runtime"}/* $out + rm -r $out/grammars + ln -s ${grammars} $out/grammars + ''; + in { + # disable fetching and building of tree-sitter grammars in the helix-term build.rs + HELIX_DISABLE_AUTO_GRAMMAR_BUILD = "1"; + # link languages and theme toml files since helix-term expects them (for tests) + preConfigure = + pkgs.lib.concatMapStringsSep + "\n" + (path: "ln -sf ${mkRootPath path} ..") + ["languages.toml" "theme.toml" "base16_theme.toml"]; + buildInputs = (prev.buildInputs or []) ++ [common.cCompiler.cc.lib]; + nativeBuildInputs = [pkgs.makeWrapper]; - postFixup = '' - if [ -f "$out/bin/hx" ]; then - wrapProgram "$out/bin/hx" --set HELIX_RUNTIME "${runtimeDir}" - fi - ''; - }; + postFixup = '' + if [ -f "$out/bin/hx" ]; then + wrapProgram "$out/bin/hx" --set HELIX_RUNTIME "${runtimeDir}" + fi + ''; + }; }; shell = common: prev: { - packages = prev.packages ++ (with common.pkgs; [ lld_13 lldb cargo-tarpaulin cargo-flamegraph ]); - env = prev.env ++ [ - { name = "HELIX_RUNTIME"; eval = "$PWD/runtime"; } - { name = "RUST_BACKTRACE"; value = "1"; } - { name = "RUSTFLAGS"; value = if common.pkgs.stdenv.isLinux then "-C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment" else ""; } - ]; + packages = + prev.packages + ++ ( + with common.pkgs; [lld_13 lldb cargo-tarpaulin cargo-flamegraph] + ); + env = + prev.env + ++ [ + { + name = "HELIX_RUNTIME"; + eval = "$PWD/runtime"; + } + { + name = "RUST_BACKTRACE"; + value = "1"; + } + { + name = "RUSTFLAGS"; + value = + if common.pkgs.stdenv.isLinux + then "-C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment" + else ""; + } + ]; }; }; }; diff --git a/grammars.nix b/grammars.nix index ada14aaf9..2f50662eb 100644 --- a/grammars.nix +++ b/grammars.nix @@ -1,17 +1,23 @@ -{ stdenv, lib, runCommand, yj }: -let +{ + stdenv, + lib, + runCommandLocal, + runCommandNoCC, + yj, +}: let # HACK: nix < 2.6 has a bug in the toml parser, so we convert to JSON # before parsing - languages-json = runCommand "languages-toml-to-json" { } '' + languages-json = runCommandLocal "languages-toml-to-json" {} '' ${yj}/bin/yj -t < ${./languages.toml} > $out ''; - languagesConfig = if lib.versionAtLeast builtins.nixVersion "2.6.0" then - builtins.fromTOML (builtins.readFile ./languages.toml) - else - builtins.fromJSON (builtins.readFile (builtins.toPath languages-json)); - isGitGrammar = (grammar: - builtins.hasAttr "source" grammar && builtins.hasAttr "git" grammar.source - && builtins.hasAttr "rev" grammar.source); + languagesConfig = + if lib.versionAtLeast builtins.nixVersion "2.6.0" + then builtins.fromTOML (builtins.readFile ./languages.toml) + else builtins.fromJSON (builtins.readFile (builtins.toPath languages-json)); + isGitGrammar = grammar: + builtins.hasAttr "source" grammar + && builtins.hasAttr "git" grammar.source + && builtins.hasAttr "rev" grammar.source; isGitHubGrammar = grammar: lib.hasPrefix "https://github.com" grammar.source.git; toGitHubFetcher = url: let match = builtins.match "https://github\.com/([^/]*)/([^/]*)/?" url; @@ -20,33 +26,36 @@ let repo = builtins.elemAt match 1; }; gitGrammars = builtins.filter isGitGrammar languagesConfig.grammar; - buildGrammar = grammar: - let - gh = toGitHubFetcher grammar.source.git; - sourceGit = builtins.fetchTree { - type = "git"; - url = grammar.source.git; - rev = grammar.source.rev; - ref = grammar.source.ref or "HEAD"; - shallow = true; - }; - sourceGitHub = builtins.fetchTree { - type = "github"; - owner = gh.owner; - repo = gh.repo; - inherit (grammar.source) rev; - }; - source = if isGitHubGrammar grammar then sourceGitHub else sourceGit; - in stdenv.mkDerivation rec { + buildGrammar = grammar: let + gh = toGitHubFetcher grammar.source.git; + sourceGit = builtins.fetchTree { + type = "git"; + url = grammar.source.git; + rev = grammar.source.rev; + ref = grammar.source.ref or "HEAD"; + shallow = true; + }; + sourceGitHub = builtins.fetchTree { + type = "github"; + owner = gh.owner; + repo = gh.repo; + inherit (grammar.source) rev; + }; + source = + if isGitHubGrammar grammar + then sourceGitHub + else sourceGit; + in + stdenv.mkDerivation rec { # see https://github.com/NixOS/nixpkgs/blob/fbdd1a7c0bc29af5325e0d7dd70e804a972eb465/pkgs/development/tools/parsing/tree-sitter/grammar.nix pname = "helix-tree-sitter-${grammar.name}"; version = grammar.source.rev; - src = if builtins.hasAttr "subpath" grammar.source then - "${source}/${grammar.source.subpath}" - else - source; + src = + if builtins.hasAttr "subpath" grammar.source + then "${source}/${grammar.source.subpath}" + else source; dontUnpack = true; dontConfigure = true; @@ -93,14 +102,17 @@ let runHook postFixup ''; }; - builtGrammars = builtins.map (grammar: { - inherit (grammar) name; - artifact = buildGrammar grammar; - }) gitGrammars; - grammarLinks = builtins.map (grammar: - "ln -s ${grammar.artifact}/${grammar.name}.so $out/${grammar.name}.so") + builtGrammars = + builtins.map (grammar: { + inherit (grammar) name; + artifact = buildGrammar grammar; + }) + gitGrammars; + grammarLinks = + builtins.map (grammar: "ln -s ${grammar.artifact}/${grammar.name}.so $out/${grammar.name}.so") builtGrammars; -in runCommand "consolidated-helix-grammars" { } '' - mkdir -p $out - ${builtins.concatStringsSep "\n" grammarLinks} -'' +in + runCommandNoCC "consolidated-helix-grammars" {} '' + mkdir -p $out + ${builtins.concatStringsSep "\n" grammarLinks} + '' diff --git a/shell.nix b/shell.nix index c0d998e3d..d5e1a215b 100644 --- a/shell.nix +++ b/shell.nix @@ -1,9 +1,8 @@ # Flake's devShell for non-flake-enabled nix instances let - compat = - builtins.fetchGit { - url = "https://github.com/edolstra/flake-compat.git"; - rev = "b4a34015c698c7793d592d66adbab377907a2be8"; - }; + compat = builtins.fetchGit { + url = "https://github.com/edolstra/flake-compat.git"; + rev = "b4a34015c698c7793d592d66adbab377907a2be8"; + }; in -(import compat { src = ./.; }).shellNix.default + (import compat {src = ./.;}).shellNix.default From 5c7d9d602705e148ee5c616009ee0ff778d41130 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jun 2022 11:10:00 +0530 Subject: [PATCH 293/861] build(deps): bump tokio from 1.18.2 to 1.19.2 (#2691) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.18.2 to 1.19.2. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/commits) --- updated-dependencies: - dependency-name: tokio dependency-type: direct:production update-type: version-update:semver-minor ... 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 86ae08159..02932a930 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1096,9 +1096,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.18.2" +version = "1.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" dependencies = [ "bytes", "libc", diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index 6eec89f03..6353c3f0c 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.18", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } +tokio = { version = "1.19", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } tokio-stream = "0.1.8" which = "4.2" From 9f8df05d96b0c475fefe079bca01c23eb492e6bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jun 2022 14:51:36 +0900 Subject: [PATCH 294/861] build(deps): bump tokio-stream from 0.1.8 to 0.1.9 (#2690) Bumps [tokio-stream](https://github.com/tokio-rs/tokio) from 0.1.8 to 0.1.9. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-stream-0.1.8...tokio-stream-0.1.9) --- updated-dependencies: - dependency-name: tokio-stream dependency-type: direct:production update-type: version-update:semver-patch ... 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 02932a930..1d1dac956 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1127,9 +1127,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" dependencies = [ "futures-core", "pin-project-lite", diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index 6353c3f0c..fb36758f0 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -24,5 +24,5 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" tokio = { version = "1.19", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } -tokio-stream = "0.1.8" +tokio-stream = "0.1.9" which = "4.2" From 7a9147489e8c058561bb37834c791b027fb0b4ae Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 1 Jun 2022 18:40:05 -0500 Subject: [PATCH 295/861] add textobject queries for erlang --- book/src/generated/lang-support.md | 2 +- languages.toml | 2 +- runtime/queries/erlang/highlights.scm | 2 +- runtime/queries/erlang/textobjects.scm | 8 ++++++++ 4 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 runtime/queries/erlang/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 1d9b89a40..8d8936ae5 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -18,7 +18,7 @@ | elixir | ✓ | | | `elixir-ls` | | elm | ✓ | | | `elm-language-server` | | erb | ✓ | | | | -| erlang | ✓ | | | `erlang_ls` | +| erlang | ✓ | ✓ | | `erlang_ls` | | fish | ✓ | ✓ | ✓ | | | gdscript | ✓ | | ✓ | | | git-attributes | ✓ | | | | diff --git a/languages.toml b/languages.toml index 7ab8ff845..6ab394b76 100644 --- a/languages.toml +++ b/languages.toml @@ -1049,7 +1049,7 @@ language-server = { command = "erlang_ls" } [[grammar]] name = "erlang" -source = { git = "https://github.com/the-mikedavis/tree-sitter-erlang", rev = "481e7f8ddf27f07a47d1531b6e2b154b89ece31d" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-erlang", rev = "c0ebc82600caaf4339f2b00691f958e9df97c065" } [[language]] name = "kotlin" diff --git a/runtime/queries/erlang/highlights.scm b/runtime/queries/erlang/highlights.scm index bea3871a6..0cb60ca99 100644 --- a/runtime/queries/erlang/highlights.scm +++ b/runtime/queries/erlang/highlights.scm @@ -58,7 +58,7 @@ (#eq? @keyword "(spec|callback)")) ; Functions -(function name: (atom) @function) +(function_clause name: (atom) @function) (call module: (atom) @module) (call function: (atom) @function) (stab_clause name: (atom) @function) diff --git a/runtime/queries/erlang/textobjects.scm b/runtime/queries/erlang/textobjects.scm new file mode 100644 index 000000000..c46b5c6f6 --- /dev/null +++ b/runtime/queries/erlang/textobjects.scm @@ -0,0 +1,8 @@ +(function_clause + pattern: (arguments (_)? @parameter.inside) + body: (_) @function.inside) @function.around + +(anonymous_function + (stab_clause body: (_) @function.inside)) @function.around + +(comment (comment_content) @comment.inside) @comment.around From bcafdf404fe22f61c9d2f0d883a6654a8a9b3ca3 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 3 Jun 2022 09:26:48 -0500 Subject: [PATCH 296/861] add textobject queries for elixir --- book/src/generated/lang-support.md | 2 +- runtime/queries/elixir/textobjects.scm | 27 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/elixir/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 8d8936ae5..064438fdf 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -15,7 +15,7 @@ | edoc | ✓ | | | | | eex | ✓ | | | | | ejs | ✓ | | | | -| elixir | ✓ | | | `elixir-ls` | +| elixir | ✓ | ✓ | | `elixir-ls` | | elm | ✓ | | | `elm-language-server` | | erb | ✓ | | | | | erlang | ✓ | ✓ | | `erlang_ls` | diff --git a/runtime/queries/elixir/textobjects.scm b/runtime/queries/elixir/textobjects.scm new file mode 100644 index 000000000..52a6f66de --- /dev/null +++ b/runtime/queries/elixir/textobjects.scm @@ -0,0 +1,27 @@ +; Function heads and guards have no body at all, so `keywords` and `do_block` nodes are both optional +((call + target: (identifier) @_keyword + (arguments + [ + (call + (arguments (_)? @parameter.inside)) + ; function has a guard + (binary_operator + left: + (call + (arguments (_)? @parameter.inside))) + ] + ; body is "do: body" instead of a do-block + (keywords + (pair + value: (_) @function.inside))?)? + (do_block (_)* @function.inside)?) + (#match? @_keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp|test|describe|setup)$")) @function.around + +(anonymous_function + (stab_clause right: (body) @function.inside)) @function.around + +((call + target: (identifier) @_keyword + (do_block (_)* @class.inside)) + (#match? @_keyword "^(defmodule|defprotocol|defimpl)$")) @class.around From f7a3d357527ab30970c8da9a8ebea9e0df88329b Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 3 Jun 2022 09:31:45 -0500 Subject: [PATCH 297/861] add textobject queries for gleam --- book/src/generated/lang-support.md | 2 +- runtime/queries/gleam/textobjects.scm | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/gleam/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 064438fdf..980b3bdc9 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -27,7 +27,7 @@ | git-diff | ✓ | | | | | git-ignore | ✓ | | | | | git-rebase | ✓ | | | | -| gleam | ✓ | | | | +| gleam | ✓ | ✓ | | | | glsl | ✓ | | ✓ | | | go | ✓ | ✓ | ✓ | `gopls` | | gomod | ✓ | | | `gopls` | diff --git a/runtime/queries/gleam/textobjects.scm b/runtime/queries/gleam/textobjects.scm new file mode 100644 index 000000000..b382f4bd0 --- /dev/null +++ b/runtime/queries/gleam/textobjects.scm @@ -0,0 +1,6 @@ +(function + parameters: (function_parameters (function_parameter)? @parameter.inside) + body: (function_body) @function.inside) @function.around + +(anonymous_function + body: (function_body) @function.inside) @function.around From 4a27e2d93846f3b66ab0dc225e65d2fb869463f3 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 6 Jun 2022 10:18:14 -0500 Subject: [PATCH 298/861] capture rust closures as function textobjects Closures like iter.map(|a| a + 1) Are sort-of functions, so `]f` or `maf` or `mif` can apply to them as well as named function definitions. --- runtime/queries/rust/textobjects.scm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/queries/rust/textobjects.scm b/runtime/queries/rust/textobjects.scm index b2769c139..ba86050b5 100644 --- a/runtime/queries/rust/textobjects.scm +++ b/runtime/queries/rust/textobjects.scm @@ -7,6 +7,8 @@ (function_item body: (_) @function.inside)) @function.around +(closure_expression body: (_) @function.inside) @function.around + ( [ (attribute_item)+ From e0532771cc3503afcbfb5cd5d45b8c57462587f9 Mon Sep 17 00:00:00 2001 From: Frojdholm Date: Wed, 8 Jun 2022 02:44:07 +0200 Subject: [PATCH 299/861] Do not add extra line breaks in markdown lists (#2689) --- helix-term/src/ui/markdown.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/helix-term/src/ui/markdown.rs b/helix-term/src/ui/markdown.rs index 5f78c3cc4..452730025 100644 --- a/helix-term/src/ui/markdown.rs +++ b/helix-term/src/ui/markdown.rs @@ -171,6 +171,8 @@ impl Markdown { Event::Start(Tag::List(list)) => list_stack.push(list), Event::End(Tag::List(_)) => { list_stack.pop(); + // whenever list closes, new line + lines.push(Spans::default()); } Event::Start(Tag::Item) => { tags.push(Tag::Item); @@ -186,11 +188,19 @@ impl Markdown { | Tag::Paragraph | Tag::CodeBlock(CodeBlockKind::Fenced(_)) | Tag::Item => { - // whenever code block or paragraph closes, new line let spans = std::mem::take(&mut spans); if !spans.is_empty() { lines.push(Spans::from(spans)); } + } + _ => (), + } + + // whenever heading, code block or paragraph closes, new line + match tag { + Tag::Heading(_, _, _) + | Tag::Paragraph + | Tag::CodeBlock(CodeBlockKind::Fenced(_)) => { lines.push(Spans::default()); } _ => (), From 567e71fbbcc047119675691a05e7c16b865e8be1 Mon Sep 17 00:00:00 2001 From: Danny Date: Wed, 8 Jun 2022 11:03:26 -0700 Subject: [PATCH 300/861] fix spelling of catppuccin theme (#2713) --- runtime/themes/{catpuccin.toml => catppuccin.toml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename runtime/themes/{catpuccin.toml => catppuccin.toml} (100%) diff --git a/runtime/themes/catpuccin.toml b/runtime/themes/catppuccin.toml similarity index 100% rename from runtime/themes/catpuccin.toml rename to runtime/themes/catppuccin.toml From f37ffaa3a1c7754238029390db00148ec8105874 Mon Sep 17 00:00:00 2001 From: Clay Date: Thu, 9 Jun 2022 18:45:17 -0700 Subject: [PATCH 301/861] elixirLS disable dialyzer by default (#2710) Not all Elixir projects use dialyzer and it can cause the editor to slow down quite a bit on large projects if the PLT is not built. See https://github.com/elixir-lsp/elixir-ls#dialyzer-integration= --- languages.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/languages.toml b/languages.toml index 6ab394b76..2961778fd 100644 --- a/languages.toml +++ b/languages.toml @@ -88,6 +88,7 @@ shebangs = ["elixir"] roots = [] comment-token = "#" language-server = { command = "elixir-ls" } +config = { elixirLS.dialyzerEnabled = false } indent = { tab-width = 2, unit = " " } [[grammar]] From 9b9c3e5ae263448b07b5bac1971d1c6e4bf7e674 Mon Sep 17 00:00:00 2001 From: Daniel Hines Date: Sat, 11 Jun 2022 04:23:18 -0400 Subject: [PATCH 302/861] add rust-analyzer to shell environment (#2739) --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 1949580dc..54637ab9e 100644 --- a/flake.nix +++ b/flake.nix @@ -72,7 +72,7 @@ packages = prev.packages ++ ( - with common.pkgs; [lld_13 lldb cargo-tarpaulin cargo-flamegraph] + with common.pkgs; [lld_13 lldb cargo-tarpaulin cargo-flamegraph rust-analyzer] ); env = prev.env From 0b8a00ac967f4fd0608d83e2804bb6b1a8bf9c5d Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sat, 11 Jun 2022 21:09:21 +0530 Subject: [PATCH 303/861] Refactor textobject node capture (#2741) --- helix-core/src/syntax.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index ca497b648..8d7520c3d 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -308,13 +308,7 @@ impl TextObjectQuery { let nodes: Vec<_> = mat .captures .iter() - .filter_map(|x| { - if x.index == capture_idx { - Some(x.node) - } else { - None - } - }) + .filter_map(|cap| (cap.index == capture_idx).then(|| cap.node)) .collect(); if nodes.len() > 1 { From e9283b20b432d40782bcf78423ef770289f6a013 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sun, 12 Jun 2022 06:23:58 +0530 Subject: [PATCH 304/861] Add docstring for language_server!() macro (#2750) --- helix-term/src/commands/lsp.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 93ae23536..b6bea8d61 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -16,6 +16,11 @@ use crate::{ use std::borrow::Cow; +/// Gets the language server that is attached to a document, and +/// if it's not active displays a status message. Using this macro +/// in a context where the editor automatically queries the LSP +/// (instead of when the user explicitly does so via a keybind like +/// `gd`) will spam the "LSP inactive" status message confusingly. #[macro_export] macro_rules! language_server { ($editor:expr, $doc:expr) => { From 0bc7259672c525f2bd16e6703f3848d617458836 Mon Sep 17 00:00:00 2001 From: Ivan <94393106+seshotake@users.noreply.github.com> Date: Sun, 12 Jun 2022 22:08:51 +0300 Subject: [PATCH 305/861] add prisma tree-sitter and lsp support (#2703) Co-authored-by: Michael Davis --- book/src/generated/lang-support.md | 1 + languages.toml | 14 +++++++ runtime/queries/prisma/highlights.scm | 56 +++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 runtime/queries/prisma/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 980b3bdc9..29b7f346d 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -67,6 +67,7 @@ | org | ✓ | | | | | perl | ✓ | ✓ | ✓ | | | php | ✓ | ✓ | ✓ | `intelephense` | +| prisma | ✓ | | | `prisma-language-server` | | prolog | | | | `swipl` | | protobuf | ✓ | | ✓ | | | python | ✓ | ✓ | ✓ | `pylsp` | diff --git a/languages.toml b/languages.toml index 2961778fd..374865f13 100644 --- a/languages.toml +++ b/languages.toml @@ -1449,3 +1449,17 @@ indent = { tab-width = 2, unit = "\t" } [[grammar]] name = "openscad" source = { git = "https://github.com/bollian/tree-sitter-openscad", rev = "5c3ce93df0ac1da7197cf6ae125aade26d6b8972" } + +[[language]] +name = "prisma" +scope = "source.prisma" +injection-regex = "prisma" +file-types = ["prisma"] +roots = ["package.json"] +comment-token = "//" +language-server = { command = "prisma-language-server", args = ["--stdio"] } +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "prisma" +source = { git = "https://github.com/victorhqc/tree-sitter-prisma", rev = "17a59236ac25413b81b1613ea6ba5d8d52d7cd6c" } diff --git a/runtime/queries/prisma/highlights.scm b/runtime/queries/prisma/highlights.scm new file mode 100644 index 000000000..b5c0c4ae3 --- /dev/null +++ b/runtime/queries/prisma/highlights.scm @@ -0,0 +1,56 @@ +(string) @string + +(enumeral) @constant +(number) @constant.numeric + +(variable) @variable +(column_type) @type + +(arguments) @variable.other.member +(model_declaration (identifier) @type) + +[ + "datasource" + "enum" + "generator" + "model" + "type" +] @keyword + +[ + (comment) + (developer_comment) +] @comment + +[ + (attribute) + (block_attribute_declaration) + (call_expression) +] @function.builtin + +[ + (true) + (false) + (null) +] @constant.builtin.boolean + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +[ + ":" + "," +] @punctuation.delimiter + +[ + "=" + "@" + "@@" + (binary_expression) +] @operator \ No newline at end of file From a766b32ed197221aca7a9fec3af805b4d04a6f1d Mon Sep 17 00:00:00 2001 From: Jonas Tepe Date: Sat, 11 Jun 2022 14:16:09 +0200 Subject: [PATCH 306/861] Expand chapter one recap of tutor This add the missing variant of entering insert mode to the chapter 1 recap section. --- runtime/tutor.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/runtime/tutor.txt b/runtime/tutor.txt index ae14eb788..a31e73d98 100644 --- a/runtime/tutor.txt +++ b/runtime/tutor.txt @@ -169,7 +169,11 @@ _________________________________________________________________ * Type i to enter Insert mode and type text. Type to return to Normal mode. - + * Use a to enter Insert mode after the current selection + instead of before. + * Use I to enter Insert mode at the first non-whitespace + character at the start of a line. + * Use A to enter Insert mode at the end of a line. From 3b2d4031f11b9c3ea676c49aa83e3fdf71353b17 Mon Sep 17 00:00:00 2001 From: Bjorn Ove Hay Andersen Date: Mon, 13 Jun 2022 16:00:40 +0200 Subject: [PATCH 307/861] Clarified the text in chapter 3 of the tutor (#2735) * Clarified the text in chapter 3 of the tutor (#2725) * Adjusted section 3.1 to better show how C works --- runtime/tutor.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/runtime/tutor.txt b/runtime/tutor.txt index a31e73d98..f21f5aa7e 100644 --- a/runtime/tutor.txt +++ b/runtime/tutor.txt @@ -336,21 +336,25 @@ _________________________________________________________________ = 3.1 MULTIPLE CURSORS = ================================================================= - Type C to duplicate the cursor to the next line. + Type C to duplicate the cursor to the next suitable line. 1. Move the cursor to the first line below marked -->. - 2. Type C to duplicate the cursor to the next line. Keys you - type will now affect both cursors. + 2. Type C to duplicate the cursor to the next suitable line. + Notice how it skips the line in the middle. Keys you type + will now affect both cursors. 3. Use Insert mode to correct the lines. The two cursors will fix both lines simultaneously. 4. Type , to remove the second cursor. --> Fix th two nes at same ime. + --> --> Fix th two nes at same ime. Fix these two lines at the same time. Note: Type alt-C to do the same above the cursor. + Note: This also works for selections, but it will pick the first + line that fits the entire selection at the same column. @@ -446,7 +450,7 @@ _________________________________________________________________ = CHAPTER 3 RECAP = ================================================================= - * Type C to copy the selection on the line below and Alt-C for + * Type C to copy the current selection to below and Alt-C for above. * Type s to select all instances of a regex pattern inside From d7bd4416754fb4e3051c3ceedd5fd525b0361ef8 Mon Sep 17 00:00:00 2001 From: Kappa <72104527+kappq@users.noreply.github.com> Date: Mon, 13 Jun 2022 17:12:13 +0200 Subject: [PATCH 308/861] Cleanup for runtime/tutor.txt (#2590) --- runtime/tutor.txt | 98 +++++++---------------------------------------- 1 file changed, 14 insertions(+), 84 deletions(-) diff --git a/runtime/tutor.txt b/runtime/tutor.txt index f21f5aa7e..bb4268670 100644 --- a/runtime/tutor.txt +++ b/runtime/tutor.txt @@ -20,6 +20,7 @@ _________________________________________________________________ the first lesson. + ================================================================= = 1.1 BASIC CURSOR MOVEMENT = ================================================================= @@ -38,10 +39,6 @@ _________________________________________________________________ - - - - ================================================================= = 1.2 EXITING HELIX = ================================================================= @@ -60,10 +57,6 @@ _________________________________________________________________ - - - - ================================================================= = 1.3 DELETION = ================================================================= @@ -80,12 +73,6 @@ _________________________________________________________________ - - - - - - ================================================================= = 1.4 INSERT MODE = ================================================================= @@ -108,6 +95,8 @@ _________________________________________________________________ Note: The status bar will display your current mode. Notice that when you type i, 'NOR' changes to 'INS'. + + ================================================================= = 1.5 MORE ON INSERT MODE = ================================================================= @@ -130,6 +119,8 @@ _________________________________________________________________ --> This sentence is miss This sentence is missing some text. + + ================================================================= = 1.6 SAVING A FILE = ================================================================= @@ -176,8 +167,6 @@ _________________________________________________________________ * Use A to enter Insert mode at the end of a line. - - ================================================================= = 2.1 MOTIONS AND SELECTIONS = ================================================================= @@ -198,8 +187,6 @@ _________________________________________________________________ - - ================================================================= = 2.2 MORE ON MOTIONS = ================================================================= @@ -243,7 +230,6 @@ _________________________________________________________________ - ================================================================= = 2.4 COUNTS WITH MOTIONS = ================================================================= @@ -251,21 +237,15 @@ _________________________________________________________________ Type a number before a motion to repeat it that many times. 1. Move the cursor to the line below marked -->. - 2. Type 2w to move 2 words forward. - 3. Type 3e to move to the end of the third word forward. - 4. Type 2b to move 2 words backwards - 5. Try the above with different numbers. --> This is just a line with words you can move around in. - - ================================================================= = 2.5 SELECTING LINES = ================================================================= @@ -287,7 +267,6 @@ _________________________________________________________________ - ================================================================= = 2.6 UNDOING = ================================================================= @@ -305,11 +284,6 @@ _________________________________________________________________ - - - - - ================================================================= = CHAPTER 2 RECAP = ================================================================= @@ -332,6 +306,7 @@ _________________________________________________________________ * Type u to undo. Type U to redo. + ================================================================= = 3.1 MULTIPLE CURSORS = ================================================================= @@ -377,9 +352,6 @@ _________________________________________________________________ - - - ================================================================= = 3.3 SELECTING VIA REGEX = ================================================================= @@ -401,7 +373,6 @@ _________________________________________________________________ - ================================================================= = 3.4 COLLAPSING SELECTIONS = ================================================================= @@ -420,10 +391,6 @@ _________________________________________________________________ - - - - ================================================================= = 3.5 SELECTING TO A CHARACTER = ================================================================= @@ -446,6 +413,8 @@ _________________________________________________________________ Note: Unlike Vim, Helix doesn't limit these commands to the current line. It searches for the character in the file. + + ================================================================= = CHAPTER 3 RECAP = ================================================================= @@ -464,10 +433,6 @@ _________________________________________________________________ - - - - ================================================================= = 4.1 COPYING AND PASTING TEXT = ================================================================= @@ -490,6 +455,8 @@ _________________________________________________________________ Note: Helix doesn't share the system clipboard by default. Type space-y/p to yank/paste on your computer's main clipboard. + + ================================================================= = 4.2 CHANGING CASE = ================================================================= @@ -512,6 +479,8 @@ _________________________________________________________________ --> this SENTENCE SHOULD all be in LOWERCASE. --> THIS sentence should ALL BE IN uppercase! + + ================================================================= = 4.3 MACROS = ================================================================= @@ -534,6 +503,8 @@ _________________________________________________________________ --> ... sentence doesn't have it's first and last ... . This sentence doesn't have it's first and last word. + + ================================================================= = CHAPTER 4 RECAP = ================================================================= @@ -551,11 +522,6 @@ _________________________________________________________________ - - - - - ================================================================= = 5.1 USING THE JUMPLIST = ================================================================= @@ -576,8 +542,6 @@ _________________________________________________________________ - - ================================================================= = 5.2 SEARCHING IN FILE = ================================================================= @@ -599,7 +563,6 @@ _________________________________________________________________ - ================================================================= = CHAPTER 5 RECAP = ================================================================= @@ -612,16 +575,6 @@ _________________________________________________________________ - - - - - - - - - - ================================================================= = 6.1 JOINING LINES = ================================================================= @@ -641,9 +594,6 @@ lines. - - - ================================================================= = 6.2 INDENTING LINES = ================================================================= @@ -664,8 +614,6 @@ lines. - - ================================================================= = 6.3 OPENING LINES = ================================================================= @@ -680,14 +628,6 @@ lines. - - - - - - - - ================================================================= = CHAPTER 6 RECAP = ================================================================= @@ -703,16 +643,6 @@ lines. - - - - - - - ================================================================= This tutorial is still a work-in-progress. More sections are planned. - - - From 3bd554557782ff4c3c5d2f686f01c4a84aab6e41 Mon Sep 17 00:00:00 2001 From: Ryang Sohn Date: Tue, 14 Jun 2022 22:37:40 +0900 Subject: [PATCH 309/861] Add a check to prevent re-selecting same range (#2760) --- helix-term/src/commands.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 628fd8fbc..c9c8e6a98 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3770,12 +3770,15 @@ fn expand_selection(cx: &mut Context) { let text = doc.text().slice(..); let current_selection = doc.selection(view.id); + let selection = object::expand_selection(syntax, text, current_selection.clone()); - // save current selection so it can be restored using shrink_selection - view.object_selections.push(current_selection.clone()); + // check if selection is different from the last one + if *current_selection != selection { + // save current selection so it can be restored using shrink_selection + view.object_selections.push(current_selection.clone()); - let selection = object::expand_selection(syntax, text, current_selection.clone()); - doc.set_selection(view.id, selection); + doc.set_selection(view.id, selection); + } } }; motion(cx.editor); From cdeab337cdba5265dcc72070f2b2e4fd11724670 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 14 Jun 2022 11:10:38 -0500 Subject: [PATCH 310/861] simplify fallback for selected line-number theming (#2768) --- helix-view/src/gutter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 06ce1b2e7..eb6796bec 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -54,7 +54,7 @@ pub fn line_numbers<'doc>( let draw_last = text.line_to_byte(last_line) < text.len_bytes(); let linenr = theme.get("ui.linenr"); - let linenr_select: Style = theme.try_get("ui.linenr.selected").unwrap_or(linenr); + let linenr_select = theme.get("ui.linenr.selected"); let current_line = doc .text() From 7983c71752e2443266ecc65581f3a980696cc294 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Tue, 14 Jun 2022 10:35:36 -0700 Subject: [PATCH 311/861] Introduce storage_class highlight scope (#2731) --- book/src/themes.md | 1 + runtime/queries/c/highlights.scm | 4 ++-- runtime/queries/rust/highlights.scm | 18 ++++++++++++------ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/book/src/themes.md b/book/src/themes.md index 7562b2056..4c0eda228 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -151,6 +151,7 @@ We use a similar set of scopes as - `operator` - `or`, `in` - `directive` - Preprocessor directives (`#if` in C) - `function` - `fn`, `func` + - `storage` - Keywords that affect the storage of a variable, function or data structure `static`, `mut`, `const`, `ref` - `operator` - `||`, `+=`, `>` diff --git a/runtime/queries/c/highlights.scm b/runtime/queries/c/highlights.scm index 918f3f66b..1263cff62 100644 --- a/runtime/queries/c/highlights.scm +++ b/runtime/queries/c/highlights.scm @@ -1,8 +1,9 @@ +(storage_class_specifier) @keyword.storage + "goto" @keyword "register" @keyword "break" @keyword "case" @keyword -"const" @keyword "continue" @keyword "default" @keyword "do" @keyword @@ -14,7 +15,6 @@ "inline" @keyword "return" @keyword "sizeof" @keyword -"static" @keyword "struct" @keyword "switch" @keyword "typedef" @keyword diff --git a/runtime/queries/rust/highlights.scm b/runtime/queries/rust/highlights.scm index 26496c66b..99cb83813 100644 --- a/runtime/queries/rust/highlights.scm +++ b/runtime/queries/rust/highlights.scm @@ -156,16 +156,22 @@ "macro_rules!" "let" - "ref" - "move" - "dyn" - "static" - "const" "async" ] @keyword -(mutable_specifier) @keyword.mut +(mutable_specifier) @keyword.storage.modifier.mut + +(reference_type "&" @keyword.storage.modifier.ref) +(self_parameter "&" @keyword.storage.modifier.ref) + +[ + "static" + "const" + "ref" + "move" + "dyn" +] @keyword.storage.modifier ; TODO: variable.mut to highlight mutable identifiers via locals.scm From c2cc2037b548a39d374b11c6919e10b1a7115cfb Mon Sep 17 00:00:00 2001 From: Roland Kovacs Date: Wed, 15 Jun 2022 06:17:17 +0200 Subject: [PATCH 312/861] Better handling of symlinks (#2718) - Add file-picker.follow-symlinks configuration option (default is true), this also controls if filename and directory completers follow symlinks. - Update FilePicker to set editor error if opening a file fails, instead of panicing. Fix #1548 Fix #2246 --- helix-term/src/ui/mod.rs | 32 +++++++++++++++++++------------- helix-view/src/editor.rs | 4 ++++ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 6dea21924..23d0dca0a 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -118,6 +118,7 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi .hidden(config.file_picker.hidden) .parents(config.file_picker.parents) .ignore(config.file_picker.ignore) + .follow_links(config.file_picker.follow_symlinks) .git_ignore(config.file_picker.git_ignore) .git_global(config.file_picker.git_global) .git_exclude(config.file_picker.git_exclude) @@ -146,14 +147,13 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi let entry = entry.ok()?; // This is faster than entry.path().is_dir() since it uses cached fs::Metadata fetched by ignore/walkdir - let is_dir = entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false); - + let is_dir = entry.file_type().map_or(false, |ft| ft.is_dir()); if is_dir { // Will give a false positive if metadata cannot be read (eg. permission error) - return None; + None + } else { + Some(entry.into_path()) } - - Some(entry.into_path()) }); // Cap the number of files if we aren't in a git project, preventing @@ -175,9 +175,14 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi path.strip_prefix(&root).unwrap_or(path).to_string_lossy() }, move |cx, path: &PathBuf, action| { - cx.editor - .open(path.into(), action) - .expect("editor.open failed"); + if let Err(e) = cx.editor.open(path.into(), action) { + let err = if let Some(err) = e.source() { + format!("{}", err) + } else { + format!("unable to open \"{}\"", path.display()) + }; + cx.editor.set_error(err); + } }, |_editor, path| Some((path.clone(), None)), ) @@ -281,8 +286,8 @@ pub mod completers { .collect() } - pub fn filename(_editor: &Editor, input: &str) -> Vec { - filename_impl(input, |entry| { + pub fn filename(editor: &Editor, input: &str) -> Vec { + filename_impl(editor, input, |entry| { let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir()); if is_dir { @@ -314,8 +319,8 @@ pub mod completers { .collect() } - pub fn directory(_editor: &Editor, input: &str) -> Vec { - filename_impl(input, |entry| { + pub fn directory(editor: &Editor, input: &str) -> Vec { + filename_impl(editor, input, |entry| { let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir()); if is_dir { @@ -338,7 +343,7 @@ pub mod completers { } // TODO: we could return an iter/lazy thing so it can fetch as many as it needs. - fn filename_impl(input: &str, filter_fn: F) -> Vec + fn filename_impl(editor: &Editor, input: &str, filter_fn: F) -> Vec where F: Fn(&ignore::DirEntry) -> FileMatch, { @@ -370,6 +375,7 @@ pub mod completers { let mut files: Vec<_> = WalkBuilder::new(&dir) .hidden(false) + .follow_links(editor.config().file_picker.follow_symlinks) .max_depth(Some(1)) .build() .filter_map(|file| { diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 8e53936a4..3bc3ecb1e 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -71,6 +71,9 @@ pub struct FilePickerConfig { /// Enables ignoring hidden files. /// Whether to hide hidden files in file picker and global search results. Defaults to true. pub hidden: bool, + /// Enables following symlinks. + /// Whether to follow symbolic links in file picker and file or directory completions. Defaults to true. + pub follow_symlinks: bool, /// Enables reading ignore files from parent directories. Defaults to true. pub parents: bool, /// Enables reading `.ignore` files. @@ -94,6 +97,7 @@ impl Default for FilePickerConfig { fn default() -> Self { Self { hidden: true, + follow_symlinks: true, parents: true, ignore: true, git_ignore: true, From 402f285ba59f0139ea0d2f4aa862e143ecce9e50 Mon Sep 17 00:00:00 2001 From: Frojdholm Date: Wed, 15 Jun 2022 06:20:19 +0200 Subject: [PATCH 313/861] Improve markdown list rendering (#2687) * Cleanup old commented code * Implement line breaks in markdown rendering * Implement markdown nested, numbered and multiparagraph lists --- helix-term/src/ui/markdown.rs | 77 +++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/helix-term/src/ui/markdown.rs b/helix-term/src/ui/markdown.rs index 452730025..037e2f134 100644 --- a/helix-term/src/ui/markdown.rs +++ b/helix-term/src/ui/markdown.rs @@ -135,6 +135,7 @@ impl Markdown { "markup.heading.5", "markup.heading.6", ]; + const INDENT: &'static str = " "; pub fn new(contents: String, config_loader: Arc) -> Self { Self { @@ -144,8 +145,12 @@ impl Markdown { } fn parse(&self, theme: Option<&Theme>) -> tui::text::Text<'_> { - // // also 2021-03-04T16:33:58.553 helix_lsp::transport [INFO] <- {"contents":{"kind":"markdown","value":"\n```rust\ncore::num\n```\n\n```rust\npub const fn saturating_sub(self, rhs:Self) ->Self\n```\n\n---\n\n```rust\n```"},"range":{"end":{"character":61,"line":101},"start":{"character":47,"line":101}}} - // let text = "\n```rust\ncore::iter::traits::iterator::Iterator\n```\n\n```rust\nfn collect>(self) -> B\nwhere\n Self: Sized,\n```\n\n---\n\nTransforms an iterator into a collection.\n\n`collect()` can take anything iterable, and turn it into a relevant\ncollection. This is one of the more powerful methods in the standard\nlibrary, used in a variety of contexts.\n\nThe most basic pattern in which `collect()` is used is to turn one\ncollection into another. You take a collection, call [`iter`](https://doc.rust-lang.org/nightly/core/iter/traits/iterator/trait.Iterator.html) on it,\ndo a bunch of transformations, and then `collect()` at the end.\n\n`collect()` can also create instances of types that are not typical\ncollections. For example, a [`String`](https://doc.rust-lang.org/nightly/core/iter/std/string/struct.String.html) can be built from [`char`](type@char)s,\nand an iterator of [`Result`](https://doc.rust-lang.org/nightly/core/result/enum.Result.html) items can be collected\ninto `Result, E>`. See the examples below for more.\n\nBecause `collect()` is so general, it can cause problems with type\ninference. As such, `collect()` is one of the few times you'll see\nthe syntax affectionately known as the 'turbofish': `::<>`. This\nhelps the inference algorithm understand specifically which collection\nyou're trying to collect into.\n\n# Examples\n\nBasic usage:\n\n```rust\nlet a = [1, 2, 3];\n\nlet doubled: Vec = a.iter()\n .map(|&x| x * 2)\n .collect();\n\nassert_eq!(vec![2, 4, 6], doubled);\n```\n\nNote that we needed the `: Vec` on the left-hand side. This is because\nwe could collect into, for example, a [`VecDeque`](https://doc.rust-lang.org/nightly/core/iter/std/collections/struct.VecDeque.html) instead:\n\n```rust\nuse std::collections::VecDeque;\n\nlet a = [1, 2, 3];\n\nlet doubled: VecDeque = a.iter().map(|&x| x * 2).collect();\n\nassert_eq!(2, doubled[0]);\nassert_eq!(4, doubled[1]);\nassert_eq!(6, doubled[2]);\n```\n\nUsing the 'turbofish' instead of annotating `doubled`:\n\n```rust\nlet a = [1, 2, 3];\n\nlet doubled = a.iter().map(|x| x * 2).collect::>();\n\nassert_eq!(vec![2, 4, 6], doubled);\n```\n\nBecause `collect()` only cares about what you're collecting into, you can\nstill use a partial type hint, `_`, with the turbofish:\n\n```rust\nlet a = [1, 2, 3];\n\nlet doubled = a.iter().map(|x| x * 2).collect::>();\n\nassert_eq!(vec![2, 4, 6], doubled);\n```\n\nUsing `collect()` to make a [`String`](https://doc.rust-lang.org/nightly/core/iter/std/string/struct.String.html):\n\n```rust\nlet chars = ['g', 'd', 'k', 'k', 'n'];\n\nlet hello: String = chars.iter()\n .map(|&x| x as u8)\n .map(|x| (x + 1) as char)\n .collect();\n\nassert_eq!(\"hello\", hello);\n```\n\nIf you have a list of [`Result`](https://doc.rust-lang.org/nightly/core/result/enum.Result.html)s, you can use `collect()` to\nsee if any of them failed:\n\n```rust\nlet results = [Ok(1), Err(\"nope\"), Ok(3), Err(\"bad\")];\n\nlet result: Result, &str> = results.iter().cloned().collect();\n\n// gives us the first error\nassert_eq!(Err(\"nope\"), result);\n\nlet results = [Ok(1), Ok(3)];\n\nlet result: Result, &str> = results.iter().cloned().collect();\n\n// gives us the list of answers\nassert_eq!(Ok(vec![1, 3]), result);\n```"; + fn push_line<'a>(spans: &mut Vec>, lines: &mut Vec>) { + let spans = std::mem::take(spans); + if !spans.is_empty() { + lines.push(Spans::from(spans)); + } + } let mut options = Options::empty(); options.insert(Options::ENABLE_STRIKETHROUGH); @@ -155,6 +160,15 @@ impl Markdown { let mut tags = Vec::new(); let mut spans = Vec::new(); let mut lines = Vec::new(); + let mut list_stack = Vec::new(); + + let get_indent = |level: usize| { + if level < 1 { + String::new() + } else { + Self::INDENT.repeat(level - 1) + } + }; let get_theme = |key: &str| -> Style { theme.map(|t| t.get(key)).unwrap_or_default() }; let text_style = get_theme(Self::TEXT_STYLE); @@ -164,22 +178,53 @@ impl Markdown { .map(|key| get_theme(key)) .collect(); - let mut list_stack = Vec::new(); - for event in parser { match event { - Event::Start(Tag::List(list)) => list_stack.push(list), + Event::Start(Tag::List(list)) => { + // if the list stack is not empty this is a sub list, in that + // case we need to push the current line before proceeding + if !list_stack.is_empty() { + push_line(&mut spans, &mut lines); + } + + list_stack.push(list); + } Event::End(Tag::List(_)) => { list_stack.pop(); - // whenever list closes, new line - lines.push(Spans::default()); + + // whenever top-level list closes, empty line + if list_stack.is_empty() { + lines.push(Spans::default()); + } } Event::Start(Tag::Item) => { + if list_stack.is_empty() { + log::warn!("markdown parsing error, list item without list"); + } + tags.push(Tag::Item); - spans.push(Span::from("- ")); + + // get the approriate bullet for the current list + let bullet = list_stack + .last() + .unwrap_or(&None) // use the '- ' bullet in case the list stack would be empty + .map_or(String::from("- "), |number| format!("{}. ", number)); + + // increment the current list number if there is one + if let Some(v) = list_stack.last_mut().unwrap_or(&mut None).as_mut() { + *v += 1; + } + + let prefix = get_indent(list_stack.len()) + bullet.as_str(); + spans.push(Span::from(prefix)); } Event::Start(tag) => { tags.push(tag); + if spans.is_empty() && !list_stack.is_empty() { + // TODO: could push indent + 2 or 3 spaces to align with + // the rest of the list. + spans.push(Span::from(get_indent(list_stack.len()))); + } } Event::End(tag) => { tags.pop(); @@ -188,15 +233,12 @@ impl Markdown { | Tag::Paragraph | Tag::CodeBlock(CodeBlockKind::Fenced(_)) | Tag::Item => { - let spans = std::mem::take(&mut spans); - if !spans.is_empty() { - lines.push(Spans::from(spans)); - } + push_line(&mut spans, &mut lines); } _ => (), } - // whenever heading, code block or paragraph closes, new line + // whenever heading, code block or paragraph closes, empty line match tag { Tag::Heading(_, _, _) | Tag::Paragraph @@ -237,9 +279,12 @@ impl Markdown { spans.push(Span::styled(text, code_style)); } Event::SoftBreak | Event::HardBreak => { - // let spans = std::mem::replace(&mut spans, Vec::new()); - // lines.push(Spans::from(spans)); - spans.push(Span::raw(" ")); + push_line(&mut spans, &mut lines); + if !list_stack.is_empty() { + // TODO: could push indent + 2 or 3 spaces to align with + // the rest of the list. + spans.push(Span::from(get_indent(list_stack.len()))); + } } Event::Rule => { lines.push(Spans::from(Span::styled("---", code_style))); From 11dadab371c126cdecd333c142175ee089692b9e Mon Sep 17 00:00:00 2001 From: Tennix Date: Thu, 16 Jun 2022 00:04:17 +0800 Subject: [PATCH 314/861] Add migrate from Vim wiki link (#2781) --- book/src/from-vim.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/from-vim.md b/book/src/from-vim.md index ed6155d32..54f8d3b1d 100644 --- a/book/src/from-vim.md +++ b/book/src/from-vim.md @@ -7,6 +7,6 @@ going to act on (a word, a paragraph, a line, etc) is selected first and the action itself (delete, change, yank, etc) comes second. A cursor is simply a single width selection. -See also Kakoune's [Migrating from Vim](https://github.com/mawww/kakoune/wiki/Migrating-from-Vim). +See also Kakoune's [Migrating from Vim](https://github.com/mawww/kakoune/wiki/Migrating-from-Vim) and Helix's [Migrating from Vim](https://github.com/helix-editor/helix/wiki/Migrating-from-Vim). > TODO: Mention textobjects, surround, registers From 794576a5b0b9a7b9e59275acd47448525de1aac1 Mon Sep 17 00:00:00 2001 From: Bjorn Ove Hay Andersen Date: Wed, 15 Jun 2022 19:29:58 +0200 Subject: [PATCH 315/861] Update auto-pairs and idle-timeout when the config is reloaded (#2736) --- helix-term/src/application.rs | 5 +++++ helix-view/src/editor.rs | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 2dfccf043..0c8de2ab0 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -287,6 +287,10 @@ impl Application { self.config.store(Arc::new(app_config)); } } + + // Update all the relevant members in the editor after updating + // the configuration. + self.editor.refresh_config(); } fn refresh_config(&mut self) { @@ -316,6 +320,7 @@ impl Application { }), ); } + self.config.store(Arc::new(config)); } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 3bc3ecb1e..ac19def10 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -535,6 +535,14 @@ impl Editor { self.config.load() } + /// Call if the config has changed to let the editor update all + /// relevant members. + pub fn refresh_config(&mut self) { + let config = self.config(); + self.auto_pairs = (&config.auto_pairs).into(); + self.reset_idle_timer(); + } + pub fn clear_idle_timer(&mut self) { // equivalent to internal Instant::far_future() (30 years) self.idle_timer From 3b1866f959c45a964cc69a4d61a978a7cfd289ae Mon Sep 17 00:00:00 2001 From: nosa <96927121+n0s4@users.noreply.github.com> Date: Wed, 15 Jun 2022 21:31:26 +0100 Subject: [PATCH 316/861] update tutor (#2716) * update tutor * Capitalize "command mode ". * Update runtime/tutor.txt Editing mistake. Co-authored-by: Michael Davis Co-authored-by: Michael Davis --- runtime/tutor.txt | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/runtime/tutor.txt b/runtime/tutor.txt index bb4268670..d531dab81 100644 --- a/runtime/tutor.txt +++ b/runtime/tutor.txt @@ -43,7 +43,7 @@ _________________________________________________________________ = 1.2 EXITING HELIX = ================================================================= - 1. Type : to enter command mode. Your cursor will + 1. Type : to enter Command mode. Your cursor will move to the bottom of the screen. 2. Type q or quit and type to exit Helix. @@ -51,7 +51,7 @@ _________________________________________________________________ To force quit and DISCARD these changes, type q! or quit!. You will learn how to save files later. - To exit command mode without entering a command, type . + To exit Command mode without entering a command, type . Now, move on to the next lesson. @@ -68,11 +68,13 @@ _________________________________________________________________ delete it. --> Thhiss senttencee haass exxtra charracterss. + This sentence has extra characters. Once the sentence is correct, move on to the next lesson. + ================================================================= = 1.4 INSERT MODE = ================================================================= @@ -131,7 +133,7 @@ _________________________________________________________________ terminal. 2. Open a file in Helix by running: hx FILENAME 3. Make some edits to the file. - 4. Type : to enter command mode. + 4. Type : to enter Command mode. 5. Type w or write, and type to save the file. You can also type wq or write-quit to save and exit. @@ -149,7 +151,7 @@ _________________________________________________________________ * Use the h,j,k,l keys to move the cursor. - * Type : to enter command mode. + * Type : to enter Command mode. * The q/quit and q!/quit! commands will exit Helix. The former fails when there are unsaved changes. The latter discards them. @@ -184,7 +186,7 @@ _________________________________________________________________ 5. Repeat for all extra words in the line. --> This sentence pencil has vacuum extra words in the it. - + This sentence has extra words in it. ================================================================= @@ -349,7 +351,7 @@ _________________________________________________________________ 6. Type , to remove the second cursor. --> I like to eat apples since my favorite fruit is apples. - + I like to eat oranges since my favourite fruit is oranges. ================================================================= @@ -365,6 +367,7 @@ _________________________________________________________________ 4. Type c and change the matches to single spaces. --> This sentence has some extra spaces. + This sentence has some extra spaces. Note: If you want to perform find-and-replace, the select command is the way to do it. Select the text you want @@ -582,12 +585,14 @@ _________________________________________________________________ Type J to join together lines in selection. 1. Move the cursor to the line below marked -->. - 2. Type J thrice or 3J to join the sentence to one line. + 2. Type x four times or 4x to select all four lines. + 3. Type J to join the lines together. - --> This line sentence + --> This sentence is spilling over onto other lines. + This sentence is spilling over onto other lines. Note: J works on all lines in selection, so typing xxx or 3x to select the lines and then a single J will work the same. From 4d604d3b50da482049de46af02febdc04c9f0079 Mon Sep 17 00:00:00 2001 From: Axot Date: Thu, 16 Jun 2022 18:47:52 +0200 Subject: [PATCH 317/861] Add clojure language support (#2780) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mateusz Ledwoń --- book/src/generated/lang-support.md | 1 + languages.toml | 14 +++++ runtime/queries/clojure/highlights.scm | 84 ++++++++++++++++++++++++++ runtime/queries/clojure/injections.scm | 2 + 4 files changed, 101 insertions(+) create mode 100644 runtime/queries/clojure/highlights.scm create mode 100644 runtime/queries/clojure/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 29b7f346d..0ed4062d4 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -4,6 +4,7 @@ | c | ✓ | ✓ | ✓ | `clangd` | | c-sharp | ✓ | | | `OmniSharp` | | cairo | ✓ | | | | +| clojure | ✓ | | | `clojure-lsp` | | cmake | ✓ | ✓ | ✓ | `cmake-language-server` | | comment | ✓ | | | | | cpon | ✓ | | ✓ | | diff --git a/languages.toml b/languages.toml index 374865f13..e59803dae 100644 --- a/languages.toml +++ b/languages.toml @@ -1463,3 +1463,17 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "prisma" source = { git = "https://github.com/victorhqc/tree-sitter-prisma", rev = "17a59236ac25413b81b1613ea6ba5d8d52d7cd6c" } + +[[language]] +name = "clojure" +scope = "source.clojure" +injection-regex = "(clojure|clj)" +file-types = ["clj"] +roots = ["project.clj"] +comment-token = ";;" +language-server = { command = "clojure-lsp" } +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "clojure" +source = { git = "https://github.com/sogaiu/tree-sitter-clojure", rev = "e57c569ae332ca365da623712ae1f50f84daeae2" } diff --git a/runtime/queries/clojure/highlights.scm b/runtime/queries/clojure/highlights.scm new file mode 100644 index 000000000..1441ea97d --- /dev/null +++ b/runtime/queries/clojure/highlights.scm @@ -0,0 +1,84 @@ +(dis_expr) @comment + +(kwd_lit) @string.special.symbol + +(str_lit) @string + +(num_lit) @constant.numeric + +[(bool_lit) (nil_lit)] @constant.builtin + +(comment) @comment + +;; metadata experiment +(meta_lit + marker: "^" @punctuation) + +;; dynamic variables +((sym_lit) @variable + (#match? @variable "^\\*.+\\*$")) + +;; parameter-related +((sym_lit) @variable.parameter + (#match? @variable.parameter "^&.*$")) + +;; gensym +((sym_lit) @variable + (#match? @variable "^.*#$")) + +;; def-like things +(list_lit + . + (sym_lit) @function.macro + . + (sym_lit) @function + (#match? @function.macro "^(declare|def|definline|definterface|defmacro|defmethod|defmulti|defn|defn-|defonce|defprotocol|defstruct|deftype|ns)$")) + +;; other macros +(list_lit + . + (sym_lit) @function.macro + (#match? @function.macro "^(\\.|\\.\\.|\\->|\\->>|amap|and|areduce|as\\->|assert|binding|bound\\-fn|case|catch|comment|cond|cond\\->|cond\\->>|condp|delay|do|doseq|dosync|dotimes|doto|extend-protocol|extend-type|finally|fn|fn\\*|for|future|gen-class|gen-interface|if|if\\-let|if\\-not|if\\-some|import|io!|lazy\\-cat|lazy\\-seq|let|letfn|locking|loop|memfn|monitor\\-enter|monitor\\-exit|or|proxy|proxy-super|pvalues|quote|recur|refer\\-clojure|reify|set!|some\\->|some\\->>|sync|throw|time|try|unquote|unquote\\-splicing|var|vswap!|when|when\\-first|when\\-let|when\\-not|when\\-some|while|with\\-bindings|with\\-in\\-str|with\\-loading\\-context|with\\-local\\-vars|with\\-open|with\\-out\\-str|with\\-precision|with\\-redefs)$")) + +(anon_fn_lit + . + (sym_lit) @function.macro + (#match? @function.macro "^(\\.|\\.\\.|\\->|\\->>|amap|and|areduce|as\\->|assert|binding|bound\\-fn|case|catch|comment|cond|cond\\->|cond\\->>|condp|delay|do|doseq|dosync|dotimes|doto|extend-protocol|extend-type|finally|fn|fn\\*|for|future|gen-class|gen-interface|if|if\\-let|if\\-not|if\\-some|import|io!|lazy\\-cat|lazy\\-seq|let|letfn|locking|loop|memfn|monitor\\-enter|monitor\\-exit|or|proxy|proxy-super|pvalues|quote|recur|refer\\-clojure|reify|set!|some\\->|some\\->>|sync|throw|time|try|unquote|unquote\\-splicing|var|vswap!|when|when\\-first|when\\-let|when\\-not|when\\-some|while|with\\-bindings|with\\-in\\-str|with\\-loading\\-context|with\\-local\\-vars|with\\-open|with\\-out\\-str|with\\-precision|with\\-redefs)$")) + +;; clojure.core=> (cp/pprint (sort (keep (fn [[s v]] (when-not (:macro (meta v)) s)) (ns-publics *ns*)))) +;; ...and then some manual filtering... +(list_lit + . + (sym_lit) @function.builtin + (#match? @function.builtin "^(\\*|\\*'|\\+|\\+'|\\-|\\-'|\\->ArrayChunk|\\->Eduction|\\->Vec|\\->VecNode|\\->VecSeq|\\-cache\\-protocol\\-fn|\\-reset\\-methods|/|<|<=|=|==|>|>=|PrintWriter\\-on|StackTraceElement\\->vec|Throwable\\->map|accessor|aclone|add\\-classpath|add\\-tap|add\\-watch|agent|agent\\-error|agent\\-errors|aget|alength|alias|all\\-ns|alter|alter\\-meta!|alter\\-var\\-root|ancestors|any\\?|apply|array\\-map|aset|aset\\-boolean|aset\\-byte|aset\\-char|aset\\-double|aset\\-float|aset\\-int|aset\\-long|aset\\-short|assoc|assoc!|assoc\\-in|associative\\?|atom|await|await\\-for|await1|bases|bean|bigdec|bigint|biginteger|bit\\-and|bit\\-and\\-not|bit\\-clear|bit\\-flip|bit\\-not|bit\\-or|bit\\-set|bit\\-shift\\-left|bit\\-shift\\-right|bit\\-test|bit\\-xor|boolean|boolean\\-array|boolean\\?|booleans|bound\\-fn\\*|bound\\?|bounded\\-count|butlast|byte|byte\\-array|bytes|bytes\\?|cast|cat|char|char\\-array|char\\-escape\\-string|char\\-name\\-string|char\\?|chars|chunk|chunk\\-append|chunk\\-buffer|chunk\\-cons|chunk\\-first|chunk\\-next|chunk\\-rest|chunked\\-seq\\?|class|class\\?|clear\\-agent\\-errors|clojure\\-version|coll\\?|commute|comp|comparator|compare|compare\\-and\\-set!|compile|complement|completing|concat|conj|conj!|cons|constantly|construct\\-proxy|contains\\?|count|counted\\?|create\\-ns|create\\-struct|cycle|dec|dec'|decimal\\?|dedupe|default\\-data\\-readers|delay\\?|deliver|denominator|deref|derive|descendants|destructure|disj|disj!|dissoc|dissoc!|distinct|distinct\\?|doall|dorun|double|double\\-array|double\\?|doubles|drop|drop\\-last|drop\\-while|eduction|empty|empty\\?|ensure|ensure\\-reduced|enumeration\\-seq|error\\-handler|error\\-mode|eval|even\\?|every\\-pred|every\\?|ex\\-cause|ex\\-data|ex\\-info|ex\\-message|extend|extenders|extends\\?|false\\?|ffirst|file\\-seq|filter|filterv|find|find\\-keyword|find\\-ns|find\\-protocol\\-impl|find\\-protocol\\-method|find\\-var|first|flatten|float|float\\-array|float\\?|floats|flush|fn\\?|fnext|fnil|force|format|frequencies|future\\-call|future\\-cancel|future\\-cancelled\\?|future\\-done\\?|future\\?|gensym|get|get\\-in|get\\-method|get\\-proxy\\-class|get\\-thread\\-bindings|get\\-validator|group\\-by|halt\\-when|hash|hash\\-combine|hash\\-map|hash\\-ordered\\-coll|hash\\-set|hash\\-unordered\\-coll|ident\\?|identical\\?|identity|ifn\\?|in\\-ns|inc|inc'|indexed\\?|init\\-proxy|inst\\-ms|inst\\-ms\\*|inst\\?|instance\\?|int|int\\-array|int\\?|integer\\?|interleave|intern|interpose|into|into\\-array|ints|isa\\?|iterate|iterator\\-seq|juxt|keep|keep\\-indexed|key|keys|keyword|keyword\\?|last|line\\-seq|list|list\\*|list\\?|load|load\\-file|load\\-reader|load\\-string|loaded\\-libs|long|long\\-array|longs|macroexpand|macroexpand\\-1|make\\-array|make\\-hierarchy|map|map\\-entry\\?|map\\-indexed|map\\?|mapcat|mapv|max|max\\-key|memoize|merge|merge\\-with|meta|method\\-sig|methods|min|min\\-key|mix\\-collection\\-hash|mod|munge|name|namespace|namespace\\-munge|nat\\-int\\?|neg\\-int\\?|neg\\?|newline|next|nfirst|nil\\?|nnext|not|not\\-any\\?|not\\-empty|not\\-every\\?|not=|ns\\-aliases|ns\\-imports|ns\\-interns|ns\\-map|ns\\-name|ns\\-publics|ns\\-refers|ns\\-resolve|ns\\-unalias|ns\\-unmap|nth|nthnext|nthrest|num|number\\?|numerator|object\\-array|odd\\?|parents|partial|partition|partition\\-all|partition\\-by|pcalls|peek|persistent!|pmap|pop|pop!|pop\\-thread\\-bindings|pos\\-int\\?|pos\\?|pr|pr\\-str|prefer\\-method|prefers|primitives\\-classnames|print|print\\-ctor|print\\-dup|print\\-method|print\\-simple|print\\-str|printf|println|println\\-str|prn|prn\\-str|promise|proxy\\-call\\-with\\-super|proxy\\-mappings|proxy\\-name|push\\-thread\\-bindings|qualified\\-ident\\?|qualified\\-keyword\\?|qualified\\-symbol\\?|quot|rand|rand\\-int|rand\\-nth|random\\-sample|range|ratio\\?|rational\\?|rationalize|re\\-find|re\\-groups|re\\-matcher|re\\-matches|re\\-pattern|re\\-seq|read|read+string|read\\-line|read\\-string|reader\\-conditional|reader\\-conditional\\?|realized\\?|record\\?|reduce|reduce\\-kv|reduced|reduced\\?|reductions|ref|ref\\-history\\-count|ref\\-max\\-history|ref\\-min\\-history|ref\\-set|refer|release\\-pending\\-sends|rem|remove|remove\\-all\\-methods|remove\\-method|remove\\-ns|remove\\-tap|remove\\-watch|repeat|repeatedly|replace|replicate|require|requiring\\-resolve|reset!|reset\\-meta!|reset\\-vals!|resolve|rest|restart\\-agent|resultset\\-seq|reverse|reversible\\?|rseq|rsubseq|run!|satisfies\\?|second|select\\-keys|send|send\\-off|send\\-via|seq|seq\\?|seqable\\?|seque|sequence|sequential\\?|set|set\\-agent\\-send\\-executor!|set\\-agent\\-send\\-off\\-executor!|set\\-error\\-handler!|set\\-error\\-mode!|set\\-validator!|set\\?|short|short\\-array|shorts|shuffle|shutdown\\-agents|simple\\-ident\\?|simple\\-keyword\\?|simple\\-symbol\\?|slurp|some|some\\-fn|some\\?|sort|sort\\-by|sorted\\-map|sorted\\-map\\-by|sorted\\-set|sorted\\-set\\-by|sorted\\?|special\\-symbol\\?|spit|split\\-at|split\\-with|str|string\\?|struct|struct\\-map|subs|subseq|subvec|supers|swap!|swap\\-vals!|symbol|symbol\\?|tagged\\-literal|tagged\\-literal\\?|take|take\\-last|take\\-nth|take\\-while|tap>|test|the\\-ns|thread\\-bound\\?|to\\-array|to\\-array\\-2d|trampoline|transduce|transient|tree\\-seq|true\\?|type|unchecked\\-add|unchecked\\-add\\-int|unchecked\\-byte|unchecked\\-char|unchecked\\-dec|unchecked\\-dec\\-int|unchecked\\-divide\\-int|unchecked\\-double|unchecked\\-float|unchecked\\-inc|unchecked\\-inc\\-int|unchecked\\-int|unchecked\\-long|unchecked\\-multiply|unchecked\\-multiply\\-int|unchecked\\-negate|unchecked\\-negate\\-int|unchecked\\-remainder\\-int|unchecked\\-short|unchecked\\-subtract|unchecked\\-subtract\\-int|underive|unquote|unquote\\-splicing|unreduced|unsigned\\-bit\\-shift\\-right|update|update\\-in|update\\-proxy|uri\\?|use|uuid\\?|val|vals|var\\-get|var\\-set|var\\?|vary\\-meta|vec|vector|vector\\-of|vector\\?|volatile!|volatile\\?|vreset!|with\\-bindings\\*|with\\-meta|with\\-redefs\\-fn|xml\\-seq|zero\\?|zipmap)$")) + +(anon_fn_lit + . + (sym_lit) @function.builtin + (#match? @function.builtin "^(\\*|\\*'|\\+|\\+'|\\-|\\-'|\\->ArrayChunk|\\->Eduction|\\->Vec|\\->VecNode|\\->VecSeq|\\-cache\\-protocol\\-fn|\\-reset\\-methods|/|<|<=|=|==|>|>=|PrintWriter\\-on|StackTraceElement\\->vec|Throwable\\->map|accessor|aclone|add\\-classpath|add\\-tap|add\\-watch|agent|agent\\-error|agent\\-errors|aget|alength|alias|all\\-ns|alter|alter\\-meta!|alter\\-var\\-root|ancestors|any\\?|apply|array\\-map|aset|aset\\-boolean|aset\\-byte|aset\\-char|aset\\-double|aset\\-float|aset\\-int|aset\\-long|aset\\-short|assoc|assoc!|assoc\\-in|associative\\?|atom|await|await\\-for|await1|bases|bean|bigdec|bigint|biginteger|bit\\-and|bit\\-and\\-not|bit\\-clear|bit\\-flip|bit\\-not|bit\\-or|bit\\-set|bit\\-shift\\-left|bit\\-shift\\-right|bit\\-test|bit\\-xor|boolean|boolean\\-array|boolean\\?|booleans|bound\\-fn\\*|bound\\?|bounded\\-count|butlast|byte|byte\\-array|bytes|bytes\\?|cast|cat|char|char\\-array|char\\-escape\\-string|char\\-name\\-string|char\\?|chars|chunk|chunk\\-append|chunk\\-buffer|chunk\\-cons|chunk\\-first|chunk\\-next|chunk\\-rest|chunked\\-seq\\?|class|class\\?|clear\\-agent\\-errors|clojure\\-version|coll\\?|commute|comp|comparator|compare|compare\\-and\\-set!|compile|complement|completing|concat|conj|conj!|cons|constantly|construct\\-proxy|contains\\?|count|counted\\?|create\\-ns|create\\-struct|cycle|dec|dec'|decimal\\?|dedupe|default\\-data\\-readers|delay\\?|deliver|denominator|deref|derive|descendants|destructure|disj|disj!|dissoc|dissoc!|distinct|distinct\\?|doall|dorun|double|double\\-array|double\\?|doubles|drop|drop\\-last|drop\\-while|eduction|empty|empty\\?|ensure|ensure\\-reduced|enumeration\\-seq|error\\-handler|error\\-mode|eval|even\\?|every\\-pred|every\\?|ex\\-cause|ex\\-data|ex\\-info|ex\\-message|extend|extenders|extends\\?|false\\?|ffirst|file\\-seq|filter|filterv|find|find\\-keyword|find\\-ns|find\\-protocol\\-impl|find\\-protocol\\-method|find\\-var|first|flatten|float|float\\-array|float\\?|floats|flush|fn\\?|fnext|fnil|force|format|frequencies|future\\-call|future\\-cancel|future\\-cancelled\\?|future\\-done\\?|future\\?|gensym|get|get\\-in|get\\-method|get\\-proxy\\-class|get\\-thread\\-bindings|get\\-validator|group\\-by|halt\\-when|hash|hash\\-combine|hash\\-map|hash\\-ordered\\-coll|hash\\-set|hash\\-unordered\\-coll|ident\\?|identical\\?|identity|ifn\\?|in\\-ns|inc|inc'|indexed\\?|init\\-proxy|inst\\-ms|inst\\-ms\\*|inst\\?|instance\\?|int|int\\-array|int\\?|integer\\?|interleave|intern|interpose|into|into\\-array|ints|isa\\?|iterate|iterator\\-seq|juxt|keep|keep\\-indexed|key|keys|keyword|keyword\\?|last|line\\-seq|list|list\\*|list\\?|load|load\\-file|load\\-reader|load\\-string|loaded\\-libs|long|long\\-array|longs|macroexpand|macroexpand\\-1|make\\-array|make\\-hierarchy|map|map\\-entry\\?|map\\-indexed|map\\?|mapcat|mapv|max|max\\-key|memoize|merge|merge\\-with|meta|method\\-sig|methods|min|min\\-key|mix\\-collection\\-hash|mod|munge|name|namespace|namespace\\-munge|nat\\-int\\?|neg\\-int\\?|neg\\?|newline|next|nfirst|nil\\?|nnext|not|not\\-any\\?|not\\-empty|not\\-every\\?|not=|ns\\-aliases|ns\\-imports|ns\\-interns|ns\\-map|ns\\-name|ns\\-publics|ns\\-refers|ns\\-resolve|ns\\-unalias|ns\\-unmap|nth|nthnext|nthrest|num|number\\?|numerator|object\\-array|odd\\?|parents|partial|partition|partition\\-all|partition\\-by|pcalls|peek|persistent!|pmap|pop|pop!|pop\\-thread\\-bindings|pos\\-int\\?|pos\\?|pr|pr\\-str|prefer\\-method|prefers|primitives\\-classnames|print|print\\-ctor|print\\-dup|print\\-method|print\\-simple|print\\-str|printf|println|println\\-str|prn|prn\\-str|promise|proxy\\-call\\-with\\-super|proxy\\-mappings|proxy\\-name|push\\-thread\\-bindings|qualified\\-ident\\?|qualified\\-keyword\\?|qualified\\-symbol\\?|quot|rand|rand\\-int|rand\\-nth|random\\-sample|range|ratio\\?|rational\\?|rationalize|re\\-find|re\\-groups|re\\-matcher|re\\-matches|re\\-pattern|re\\-seq|read|read+string|read\\-line|read\\-string|reader\\-conditional|reader\\-conditional\\?|realized\\?|record\\?|reduce|reduce\\-kv|reduced|reduced\\?|reductions|ref|ref\\-history\\-count|ref\\-max\\-history|ref\\-min\\-history|ref\\-set|refer|release\\-pending\\-sends|rem|remove|remove\\-all\\-methods|remove\\-method|remove\\-ns|remove\\-tap|remove\\-watch|repeat|repeatedly|replace|replicate|require|requiring\\-resolve|reset!|reset\\-meta!|reset\\-vals!|resolve|rest|restart\\-agent|resultset\\-seq|reverse|reversible\\?|rseq|rsubseq|run!|satisfies\\?|second|select\\-keys|send|send\\-off|send\\-via|seq|seq\\?|seqable\\?|seque|sequence|sequential\\?|set|set\\-agent\\-send\\-executor!|set\\-agent\\-send\\-off\\-executor!|set\\-error\\-handler!|set\\-error\\-mode!|set\\-validator!|set\\?|short|short\\-array|shorts|shuffle|shutdown\\-agents|simple\\-ident\\?|simple\\-keyword\\?|simple\\-symbol\\?|slurp|some|some\\-fn|some\\?|sort|sort\\-by|sorted\\-map|sorted\\-map\\-by|sorted\\-set|sorted\\-set\\-by|sorted\\?|special\\-symbol\\?|spit|split\\-at|split\\-with|str|string\\?|struct|struct\\-map|subs|subseq|subvec|supers|swap!|swap\\-vals!|symbol|symbol\\?|tagged\\-literal|tagged\\-literal\\?|take|take\\-last|take\\-nth|take\\-while|tap>|test|the\\-ns|thread\\-bound\\?|to\\-array|to\\-array\\-2d|trampoline|transduce|transient|tree\\-seq|true\\?|type|unchecked\\-add|unchecked\\-add\\-int|unchecked\\-byte|unchecked\\-char|unchecked\\-dec|unchecked\\-dec\\-int|unchecked\\-divide\\-int|unchecked\\-double|unchecked\\-float|unchecked\\-inc|unchecked\\-inc\\-int|unchecked\\-int|unchecked\\-long|unchecked\\-multiply|unchecked\\-multiply\\-int|unchecked\\-negate|unchecked\\-negate\\-int|unchecked\\-remainder\\-int|unchecked\\-short|unchecked\\-subtract|unchecked\\-subtract\\-int|underive|unquote|unquote\\-splicing|unreduced|unsigned\\-bit\\-shift\\-right|update|update\\-in|update\\-proxy|uri\\?|use|uuid\\?|val|vals|var\\-get|var\\-set|var\\?|vary\\-meta|vec|vector|vector\\-of|vector\\?|volatile!|volatile\\?|vreset!|with\\-bindings\\*|with\\-meta|with\\-redefs\\-fn|xml\\-seq|zero\\?|zipmap)$")) + +;; anonymous function positional arguments +((sym_lit) @operator + (#match? @operator "^%")) + +;; other calls +(list_lit + . + (sym_lit) @function) + +;; interop-ish +(list_lit + . + (sym_lit) @function.method + (#match? @function.method "^\\.")) + +;; other symbols +(sym_lit) @variable + +;; quote +(quoting_lit) @constant.character.escape + +;; syntax quote +["{" "}" "(" ")" "[" "]"] @punctuation.bracket +["~" "~@" "#'" "@"] @operator +(syn_quoting_lit) @constant.character.escape diff --git a/runtime/queries/clojure/injections.scm b/runtime/queries/clojure/injections.scm new file mode 100644 index 000000000..af94d41de --- /dev/null +++ b/runtime/queries/clojure/injections.scm @@ -0,0 +1,2 @@ +((regex_lit) @injection.content + (#set! injection.language "regex")) From debd2405d9cb65b08fbb260854c869701ae64178 Mon Sep 17 00:00:00 2001 From: Gygaxis Vainhardt <44003709+AloeareV@users.noreply.github.com> Date: Thu, 16 Jun 2022 18:09:30 -0300 Subject: [PATCH 318/861] views -> buffers in write-all (#2788) --- book/src/generated/typable-cmd.md | 6 +++--- helix-term/src/commands/typed.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 71a33fa72..6e6beab4b 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -21,9 +21,9 @@ | `:later`, `:lat` | Jump to a later point in edit history. Accepts a number of steps or a time span. | | `:write-quit`, `:wq`, `:x` | Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt) | | `:write-quit!`, `:wq!`, `:x!` | Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt) | -| `:write-all`, `:wa` | Write changes from all views to disk. | -| `:write-quit-all`, `:wqa`, `:xa` | Write changes from all views to disk and close all views. | -| `:write-quit-all!`, `:wqa!`, `:xa!` | Write changes from all views to disk and close all views forcefully (ignoring unsaved changes). | +| `:write-all`, `:wa` | Write changes from all buffers to disk. | +| `:write-quit-all`, `:wqa`, `:xa` | Write changes from all buffers to disk and close all views. | +| `:write-quit-all!`, `:wqa!`, `:xa!` | Write changes from all buffers to disk and close all views forcefully (ignoring unsaved changes). | | `:quit-all`, `:qa` | Close all views. | | `:quit-all!`, `:qa!` | Close all views forcefully (ignoring unsaved changes). | | `:cquit`, `:cq` | Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2). | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 0f8884dbb..ae3e63af9 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1393,21 +1393,21 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "write-all", aliases: &["wa"], - doc: "Write changes from all views to disk.", + doc: "Write changes from all buffers to disk.", fun: write_all, completer: None, }, TypableCommand { name: "write-quit-all", aliases: &["wqa", "xa"], - doc: "Write changes from all views to disk and close all views.", + doc: "Write changes from all buffers to disk and close all views.", fun: write_all_quit, completer: None, }, TypableCommand { name: "write-quit-all!", aliases: &["wqa!", "xa!"], - doc: "Write changes from all views to disk and close all views forcefully (ignoring unsaved changes).", + doc: "Write changes from all buffers to disk and close all views forcefully (ignoring unsaved changes).", fun: force_write_all_quit, completer: None, }, From 21d12e1487f98b5dea93eba7bdc53d303932f990 Mon Sep 17 00:00:00 2001 From: nosa <96927121+n0s4@users.noreply.github.com> Date: Thu, 16 Jun 2022 23:28:55 +0100 Subject: [PATCH 319/861] Restore section spacing in tutor. (#2791) --- runtime/tutor.txt | 96 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 21 deletions(-) diff --git a/runtime/tutor.txt b/runtime/tutor.txt index d531dab81..c9e23ad4b 100644 --- a/runtime/tutor.txt +++ b/runtime/tutor.txt @@ -20,7 +20,6 @@ _________________________________________________________________ the first lesson. - ================================================================= = 1.1 BASIC CURSOR MOVEMENT = ================================================================= @@ -39,6 +38,10 @@ _________________________________________________________________ + + + + ================================================================= = 1.2 EXITING HELIX = ================================================================= @@ -57,6 +60,10 @@ _________________________________________________________________ + + + + ================================================================= = 1.3 DELETION = ================================================================= @@ -75,6 +82,10 @@ _________________________________________________________________ + + + + ================================================================= = 1.4 INSERT MODE = ================================================================= @@ -97,8 +108,6 @@ _________________________________________________________________ Note: The status bar will display your current mode. Notice that when you type i, 'NOR' changes to 'INS'. - - ================================================================= = 1.5 MORE ON INSERT MODE = ================================================================= @@ -121,8 +130,6 @@ _________________________________________________________________ --> This sentence is miss This sentence is missing some text. - - ================================================================= = 1.6 SAVING A FILE = ================================================================= @@ -162,13 +169,11 @@ _________________________________________________________________ * Type i to enter Insert mode and type text. Type to return to Normal mode. - * Use a to enter Insert mode after the current selection - instead of before. + * Use a to enter Insert mode after the current selection. * Use I to enter Insert mode at the first non-whitespace character at the start of a line. * Use A to enter Insert mode at the end of a line. - ================================================================= = 2.1 MOTIONS AND SELECTIONS = ================================================================= @@ -189,6 +194,8 @@ _________________________________________________________________ This sentence has extra words in it. + + ================================================================= = 2.2 MORE ON MOTIONS = ================================================================= @@ -232,6 +239,7 @@ _________________________________________________________________ + ================================================================= = 2.4 COUNTS WITH MOTIONS = ================================================================= @@ -248,6 +256,12 @@ _________________________________________________________________ + + + + + + ================================================================= = 2.5 SELECTING LINES = ================================================================= @@ -269,6 +283,7 @@ _________________________________________________________________ + ================================================================= = 2.6 UNDOING = ================================================================= @@ -286,6 +301,11 @@ _________________________________________________________________ + + + + + ================================================================= = CHAPTER 2 RECAP = ================================================================= @@ -308,7 +328,6 @@ _________________________________________________________________ * Type u to undo. Type U to redo. - ================================================================= = 3.1 MULTIPLE CURSORS = ================================================================= @@ -330,10 +349,6 @@ _________________________________________________________________ Fix these two lines at the same time. Note: Type alt-C to do the same above the cursor. - Note: This also works for selections, but it will pick the first - line that fits the entire selection at the same column. - - ================================================================= = 3.2 THE SELECT COMMAND = @@ -354,6 +369,9 @@ _________________________________________________________________ I like to eat oranges since my favourite fruit is oranges. + + + ================================================================= = 3.3 SELECTING VIA REGEX = ================================================================= @@ -394,6 +412,10 @@ _________________________________________________________________ + + + + ================================================================= = 3.5 SELECTING TO A CHARACTER = ================================================================= @@ -416,8 +438,6 @@ _________________________________________________________________ Note: Unlike Vim, Helix doesn't limit these commands to the current line. It searches for the character in the file. - - ================================================================= = CHAPTER 3 RECAP = ================================================================= @@ -436,6 +456,10 @@ _________________________________________________________________ + + + + ================================================================= = 4.1 COPYING AND PASTING TEXT = ================================================================= @@ -458,8 +482,6 @@ _________________________________________________________________ Note: Helix doesn't share the system clipboard by default. Type space-y/p to yank/paste on your computer's main clipboard. - - ================================================================= = 4.2 CHANGING CASE = ================================================================= @@ -482,8 +504,6 @@ _________________________________________________________________ --> this SENTENCE SHOULD all be in LOWERCASE. --> THIS sentence should ALL BE IN uppercase! - - ================================================================= = 4.3 MACROS = ================================================================= @@ -506,8 +526,6 @@ _________________________________________________________________ --> ... sentence doesn't have it's first and last ... . This sentence doesn't have it's first and last word. - - ================================================================= = CHAPTER 4 RECAP = ================================================================= @@ -525,6 +543,11 @@ _________________________________________________________________ + + + + + ================================================================= = 5.1 USING THE JUMPLIST = ================================================================= @@ -545,6 +568,8 @@ _________________________________________________________________ + + ================================================================= = 5.2 SEARCHING IN FILE = ================================================================= @@ -566,6 +591,7 @@ _________________________________________________________________ + ================================================================= = CHAPTER 5 RECAP = ================================================================= @@ -578,6 +604,16 @@ _________________________________________________________________ + + + + + + + + + + ================================================================= = 6.1 JOINING LINES = ================================================================= @@ -599,6 +635,7 @@ lines. + ================================================================= = 6.2 INDENTING LINES = ================================================================= @@ -619,6 +656,8 @@ lines. + + ================================================================= = 6.3 OPENING LINES = ================================================================= @@ -633,6 +672,14 @@ lines. + + + + + + + + ================================================================= = CHAPTER 6 RECAP = ================================================================= @@ -648,6 +695,13 @@ lines. + + + + + + + ================================================================= This tutorial is still a work-in-progress. More sections are planned. From 33ea3eff052a38af9dc8cda8fa934aa3ee3dd2e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grenier=20C=C3=A9lestin?= <43825779+PictElm@users.noreply.github.com> Date: Fri, 17 Jun 2022 13:24:18 +0200 Subject: [PATCH 320/861] Update theme base16_default (`ui.menu`) (#2794) --- base16_theme.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base16_theme.toml b/base16_theme.toml index 5c0c253e1..63fc2f790 100644 --- a/base16_theme.toml +++ b/base16_theme.toml @@ -1,6 +1,6 @@ # Author: NNB -"ui.menu" = "black" +"ui.menu" = { fg = "black", bg = "white" } "ui.menu.selected" = { modifiers = ["reversed"] } "ui.linenr" = { fg = "gray", bg = "black" } "ui.popup" = { modifiers = ["reversed"] } From 15807d5f273012d048107487e3d9e13f3987878c Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 17 Jun 2022 10:51:45 -0400 Subject: [PATCH 321/861] simplify some keymap key names follow up tests (#2694) --- helix-view/src/input.rs | 42 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/helix-view/src/input.rs b/helix-view/src/input.rs index b4875d491..5b8679305 100644 --- a/helix-view/src/input.rs +++ b/helix-view/src/input.rs @@ -323,7 +323,39 @@ mod test { code: KeyCode::Char('%'), modifiers: KeyModifiers::NONE } - ) + ); + + assert_eq!( + str::parse::(";").unwrap(), + KeyEvent { + code: KeyCode::Char(';'), + modifiers: KeyModifiers::NONE + } + ); + + assert_eq!( + str::parse::(">").unwrap(), + KeyEvent { + code: KeyCode::Char('>'), + modifiers: KeyModifiers::NONE + } + ); + + assert_eq!( + str::parse::("<").unwrap(), + KeyEvent { + code: KeyCode::Char('<'), + modifiers: KeyModifiers::NONE + } + ); + + assert_eq!( + str::parse::("+").unwrap(), + KeyEvent { + code: KeyCode::Char('+'), + modifiers: KeyModifiers::NONE + } + ); } #[test] @@ -351,6 +383,14 @@ mod test { modifiers: KeyModifiers::SHIFT | KeyModifiers::CONTROL } ); + + assert_eq!( + str::parse::("A-C-+").unwrap(), + KeyEvent { + code: KeyCode::Char('+'), + modifiers: KeyModifiers::ALT | KeyModifiers::CONTROL + } + ); } #[test] From b13e534b92a2616134157d9df80c49dd6af223c6 Mon Sep 17 00:00:00 2001 From: Clay Date: Fri, 17 Jun 2022 15:30:28 -0700 Subject: [PATCH 322/861] HEEx: upgrade version and support new special_attribute node (#2800) --- languages.toml | 2 +- runtime/queries/heex/highlights.scm | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index e59803dae..ba9419b3e 100644 --- a/languages.toml +++ b/languages.toml @@ -1223,7 +1223,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "heex" -source = { git = "https://github.com/connorlay/tree-sitter-heex", rev = "592e22292a367312c35e13de7fdb888f029981d6" } +source = { git = "https://github.com/phoenixframework/tree-sitter-heex", rev = "961bc4d2937cfd24ceb0a5a6b2da607809f8822e" } [[language]] name = "sql" diff --git a/runtime/queries/heex/highlights.scm b/runtime/queries/heex/highlights.scm index d63853b5c..c42a689fc 100644 --- a/runtime/queries/heex/highlights.scm +++ b/runtime/queries/heex/highlights.scm @@ -49,6 +49,9 @@ (quoted_attribute_value) ] @string +; HEEx special attributes are keywords +(special_attribute_name) @keyword + ; HEEx components are highlighted as Elixir modules and functions (component_name [ From 45ce1ebdb604ae8b044a012f2933e6a42574430a Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 17 Jun 2022 22:59:57 -0500 Subject: [PATCH 323/861] embed jsonrpc types from jsonrpc-core crate (#2801) We should not depend on jsonrpc-core anymore: * The project just announced it's no longer actively maintained[^1], preferring their new implementation in `jsonrpsee`. * The types are too strict: we would benefit from removing some `#[serde(deny_unknown_fields)]` annotations to allow language servers that disrespect the spec[^2]. * We don't use much of the project. Just the types out of core. These are easy to embed directly into the `helix-lsp` crate. [^1]: https://github.com/paritytech/jsonrpc/pull/674 [^2]: https://github.com/helix-editor/helix/issues/2786 --- Cargo.lock | 14 -- helix-lsp/Cargo.toml | 1 - helix-lsp/src/client.rs | 2 +- helix-lsp/src/jsonrpc.rs | 370 +++++++++++++++++++++++++++++++++++++ helix-lsp/src/lib.rs | 2 +- helix-lsp/src/transport.rs | 3 +- 6 files changed, 373 insertions(+), 19 deletions(-) create mode 100644 helix-lsp/src/jsonrpc.rs diff --git a/Cargo.lock b/Cargo.lock index 1d1dac956..ddf267906 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -421,7 +421,6 @@ dependencies = [ "futures-executor", "futures-util", "helix-core", - "jsonrpc-core", "log", "lsp-types", "serde", @@ -551,19 +550,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" -[[package]] -name = "jsonrpc-core" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" -dependencies = [ - "futures-util", - "log", - "serde", - "serde_derive", - "serde_json", -] - [[package]] name = "lazy_static" version = "1.4.0" diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index fb36758f0..b7d266624 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -17,7 +17,6 @@ helix-core = { version = "0.6", path = "../helix-core" } anyhow = "1.0" futures-executor = "0.3" futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false } -jsonrpc-core = { version = "18.0", default-features = false } # don't pull in all of futures log = "0.4" lsp-types = { version = "0.93", features = ["proposed"] } serde = { version = "1.0", features = ["derive"] } diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 7f556ca6d..8ee9c9d71 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -1,11 +1,11 @@ use crate::{ + jsonrpc, transport::{Payload, Transport}, Call, Error, OffsetEncoding, Result, }; use anyhow::anyhow; use helix_core::{find_root, ChangeSet, Rope}; -use jsonrpc_core as jsonrpc; use lsp_types as lsp; use serde::Deserialize; use serde_json::Value; diff --git a/helix-lsp/src/jsonrpc.rs b/helix-lsp/src/jsonrpc.rs new file mode 100644 index 000000000..b9b3fd2c0 --- /dev/null +++ b/helix-lsp/src/jsonrpc.rs @@ -0,0 +1,370 @@ +//! An implementation of the JSONRPC 2.0 spec types + +// Upstream implementation: https://github.com/paritytech/jsonrpc/tree/38af3c9439aa75481805edf6c05c6622a5ab1e70/core/src/types +// Changes from upstream: +// * unused functions (almost all non-trait-implementation functions) have been removed +// * `#[serde(deny_unknown_fields)]` annotations have been removed on response types +// for compatibility with non-strict language server implementations like Ruby Sorbet +// (see https://github.com/helix-editor/helix/issues/2786) +// * some variable names have been lengthened for readability + +use serde::de::{self, DeserializeOwned, Visitor}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +// https://www.jsonrpc.org/specification#error_object +#[derive(Debug, PartialEq, Clone)] +pub enum ErrorCode { + ParseError, + InvalidRequest, + MethodNotFound, + InvalidParams, + InternalError, + ServerError(i64), +} + +impl ErrorCode { + pub fn code(&self) -> i64 { + match *self { + ErrorCode::ParseError => -32700, + ErrorCode::InvalidRequest => -32600, + ErrorCode::MethodNotFound => -32601, + ErrorCode::InvalidParams => -32602, + ErrorCode::InternalError => -32603, + ErrorCode::ServerError(code) => code, + } + } +} + +impl From for ErrorCode { + fn from(code: i64) -> Self { + match code { + -32700 => ErrorCode::ParseError, + -32600 => ErrorCode::InvalidRequest, + -32601 => ErrorCode::MethodNotFound, + -32602 => ErrorCode::InvalidParams, + -32603 => ErrorCode::InternalError, + code => ErrorCode::ServerError(code), + } + } +} + +impl<'de> Deserialize<'de> for ErrorCode { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let code: i64 = Deserialize::deserialize(deserializer)?; + Ok(ErrorCode::from(code)) + } +} + +impl Serialize for ErrorCode { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_i64(self.code()) + } +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +pub struct Error { + pub code: ErrorCode, + pub message: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +impl Error { + pub fn invalid_params(message: M) -> Self + where + M: Into, + { + Error { + code: ErrorCode::InvalidParams, + message: message.into(), + data: None, + } + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}: {}", self.code, self.message) + } +} + +impl std::error::Error for Error {} + +// https://www.jsonrpc.org/specification#request_object + +/// Request ID +#[derive(Debug, PartialEq, Clone, Hash, Eq, Deserialize, Serialize)] +#[serde(untagged)] +pub enum Id { + Null, + Num(u64), + Str(String), +} + +/// Protocol Version +#[derive(Debug, PartialEq, Clone, Copy, Hash, Eq)] +pub enum Version { + V2, +} + +impl Serialize for Version { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match *self { + Version::V2 => serializer.serialize_str("2.0"), + } + } +} + +struct VersionVisitor; + +impl<'v> Visitor<'v> for VersionVisitor { + type Value = Version; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a string") + } + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + match value { + "2.0" => Ok(Version::V2), + _ => Err(de::Error::custom("invalid version")), + } + } +} + +impl<'de> Deserialize<'de> for Version { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_identifier(VersionVisitor) + } +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum Params { + None, + Array(Vec), + Map(serde_json::Map), +} + +impl Params { + pub fn parse(self) -> Result + where + D: DeserializeOwned, + { + let value: Value = self.into(); + serde_json::from_value(value) + .map_err(|err| Error::invalid_params(format!("Invalid params: {}.", err))) + } +} + +impl From for Value { + fn from(params: Params) -> Value { + match params { + Params::Array(vec) => Value::Array(vec), + Params::Map(map) => Value::Object(map), + Params::None => Value::Null, + } + } +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct MethodCall { + pub jsonrpc: Option, + pub method: String, + #[serde(default = "default_params")] + pub params: Params, + pub id: Id, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct Notification { + pub jsonrpc: Option, + pub method: String, + #[serde(default = "default_params")] + pub params: Params, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +#[serde(untagged)] +pub enum Call { + MethodCall(MethodCall), + Notification(Notification), + Invalid { + // We can attempt to salvage the id out of the invalid request + // for better debugging + #[serde(default = "default_id")] + id: Id, + }, +} + +fn default_params() -> Params { + Params::None +} + +fn default_id() -> Id { + Id::Null +} + +impl From for Call { + fn from(method_call: MethodCall) -> Self { + Call::MethodCall(method_call) + } +} + +impl From for Call { + fn from(notification: Notification) -> Self { + Call::Notification(notification) + } +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +#[serde(untagged)] +pub enum Request { + Single(Call), + Batch(Vec), +} + +// https://www.jsonrpc.org/specification#response_object + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +pub struct Success { + #[serde(skip_serializing_if = "Option::is_none")] + pub jsonrpc: Option, + pub result: Value, + pub id: Id, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +pub struct Failure { + #[serde(skip_serializing_if = "Option::is_none")] + pub jsonrpc: Option, + pub error: Error, + pub id: Id, +} + +// Note that failure comes first because we're not using +// #[serde(deny_unknown_field)]: we want a request that contains +// both `result` and `error` to be a `Failure`. +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum Output { + Failure(Failure), + Success(Success), +} + +impl From for Result { + fn from(output: Output) -> Self { + match output { + Output::Success(success) => Ok(success.result), + Output::Failure(failure) => Err(failure.error), + } + } +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[serde(untagged)] +pub enum Response { + Single(Output), + Batch(Vec), +} + +impl From for Response { + fn from(failure: Failure) -> Self { + Response::Single(Output::Failure(failure)) + } +} + +impl From for Response { + fn from(success: Success) -> Self { + Response::Single(Output::Success(success)) + } +} + +#[test] +fn method_call_serialize() { + use serde_json; + + let m = MethodCall { + jsonrpc: Some(Version::V2), + method: "update".to_owned(), + params: Params::Array(vec![Value::from(1), Value::from(2)]), + id: Id::Num(1), + }; + + let serialized = serde_json::to_string(&m).unwrap(); + assert_eq!( + serialized, + r#"{"jsonrpc":"2.0","method":"update","params":[1,2],"id":1}"# + ); +} + +#[test] +fn notification_serialize() { + use serde_json; + + let n = Notification { + jsonrpc: Some(Version::V2), + method: "update".to_owned(), + params: Params::Array(vec![Value::from(1), Value::from(2)]), + }; + + let serialized = serde_json::to_string(&n).unwrap(); + assert_eq!( + serialized, + r#"{"jsonrpc":"2.0","method":"update","params":[1,2]}"# + ); +} + +#[test] +fn success_output_deserialize() { + use serde_json; + + let dso = r#"{"jsonrpc":"2.0","result":1,"id":1}"#; + + let deserialized: Output = serde_json::from_str(dso).unwrap(); + assert_eq!( + deserialized, + Output::Success(Success { + jsonrpc: Some(Version::V2), + result: Value::from(1), + id: Id::Num(1) + }) + ); +} + +#[test] +fn success_output_deserialize_with_extra_fields() { + use serde_json; + + // https://github.com/helix-editor/helix/issues/2786 + let dso = r#"{"jsonrpc":"2.0","result":1,"id":1,"requestMethod":"initialize"}"#; + + let deserialized: Output = serde_json::from_str(dso).unwrap(); + assert_eq!( + deserialized, + Output::Success(Success { + jsonrpc: Some(Version::V2), + result: Value::from(1), + id: Id::Num(1) + }) + ); +} diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 2bc554e6b..6a5f9d5ca 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -1,10 +1,10 @@ mod client; +pub mod jsonrpc; mod transport; pub use client::Client; pub use futures_executor::block_on; pub use jsonrpc::Call; -pub use jsonrpc_core as jsonrpc; pub use lsp::{Position, Url}; pub use lsp_types as lsp; diff --git a/helix-lsp/src/transport.rs b/helix-lsp/src/transport.rs index 6102c6c8e..8aaeae3d9 100644 --- a/helix-lsp/src/transport.rs +++ b/helix-lsp/src/transport.rs @@ -1,6 +1,5 @@ -use crate::{Error, Result}; +use crate::{jsonrpc, Error, Result}; use anyhow::Context; -use jsonrpc_core as jsonrpc; use log::{error, info}; use serde::{Deserialize, Serialize}; use serde_json::Value; From ad15e7b5e8918e1521683c7f5c63d77e00c58023 Mon Sep 17 00:00:00 2001 From: A-Walrus <58790821+A-Walrus@users.noreply.github.com> Date: Sat, 18 Jun 2022 19:44:21 +0300 Subject: [PATCH 324/861] Add "<<=" operator to Rust syntax highlighting (#2805) --- runtime/queries/rust/highlights.scm | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/queries/rust/highlights.scm b/runtime/queries/rust/highlights.scm index 99cb83813..4b0c018e2 100644 --- a/runtime/queries/rust/highlights.scm +++ b/runtime/queries/rust/highlights.scm @@ -311,6 +311,7 @@ ">>" "<<" ">>=" + "<<=" "@" ".." "..=" From 0623a72599f5ffe7adfd0ebe5445ad5eaa26ff91 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Sun, 24 Apr 2022 16:01:45 -0400 Subject: [PATCH 325/861] move config parsing back into main --- helix-term/src/application.rs | 21 +-------------------- helix-term/src/main.rs | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 0c8de2ab0..e8fbb7cc7 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -56,29 +56,10 @@ pub struct Application { } impl Application { - pub fn new(args: Args) -> Result { + pub fn new(args: Args, config: Config) -> Result { use helix_view::editor::Action; let config_dir = helix_loader::config_dir(); - if !config_dir.exists() { - std::fs::create_dir_all(&config_dir).ok(); - } - - let config = match std::fs::read_to_string(config_dir.join("config.toml")) { - Ok(config) => toml::from_str(&config) - .map(crate::keymap::merge_keys) - .unwrap_or_else(|err| { - eprintln!("Bad config: {}", err); - eprintln!("Press to continue with default config"); - use std::io::Read; - // This waits for an enter press. - let _ = std::io::stdin().read(&mut []); - Config::default() - }), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => Config::default(), - Err(err) => return Err(Error::new(err)), - }; - let theme_loader = std::sync::Arc::new(theme::Loader::new( &config_dir, &helix_loader::runtime_dir(), diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index 58a901316..cd0b364be 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -1,6 +1,7 @@ -use anyhow::{Context, Result}; +use anyhow::{Context, Error, Result}; use helix_term::application::Application; use helix_term::args::Args; +use helix_term::config::Config; use std::path::PathBuf; fn setup_logging(logpath: PathBuf, verbosity: u64) -> Result<()> { @@ -110,8 +111,28 @@ FLAGS: setup_logging(logpath, args.verbosity).context("failed to initialize logging")?; + let config_dir = helix_loader::config_dir(); + if !config_dir.exists() { + std::fs::create_dir_all(&config_dir).ok(); + } + + let config = match std::fs::read_to_string(config_dir.join("config.toml")) { + Ok(config) => toml::from_str(&config) + .map(helix_term::keymap::merge_keys) + .unwrap_or_else(|err| { + eprintln!("Bad config: {}", err); + eprintln!("Press to continue with default config"); + use std::io::Read; + // This waits for an enter press. + let _ = std::io::stdin().read(&mut []); + Config::default() + }), + Err(err) if err.kind() == std::io::ErrorKind::NotFound => Config::default(), + Err(err) => return Err(Error::new(err)), + }; + // TODO: use the thread local executor to spawn the application task separately from the work pool - let mut app = Application::new(args).context("unable to create new application")?; + let mut app = Application::new(args, config).context("unable to create new application")?; let exit_code = app.run().await?; From adb6cd537628308a23fe6ea86f1c7b419c4d8c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Tue, 26 Oct 2021 18:02:36 +0900 Subject: [PATCH 326/861] Simplify handle_terminal_events signature --- helix-term/src/application.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index e8fbb7cc7..075b9c355 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -213,7 +213,7 @@ impl Application { tokio::select! { biased; - event = reader.next() => { + Some(event) = reader.next() => { self.handle_terminal_events(event) } Some(signal) = self.signals.next() => { @@ -351,7 +351,7 @@ impl Application { } } - pub fn handle_terminal_events(&mut self, event: Option>) { + pub fn handle_terminal_events(&mut self, event: Result) { let mut cx = crate::compositor::Context { editor: &mut self.editor, jobs: &mut self.jobs, @@ -359,15 +359,14 @@ impl Application { }; // Handle key events let should_redraw = match event { - Some(Ok(Event::Resize(width, height))) => { + Ok(Event::Resize(width, height)) => { self.compositor.resize(width, height); self.compositor .handle_event(Event::Resize(width, height), &mut cx) } - Some(Ok(event)) => self.compositor.handle_event(event, &mut cx), - Some(Err(x)) => panic!("{}", x), - None => panic!(), + Ok(event) => self.compositor.handle_event(event, &mut cx), + Err(x) => panic!("{}", x), }; if should_redraw && !self.editor.should_close() { From 308cab3e5cd5e8d5a8c37498e725f51ab101a908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Tue, 26 Oct 2021 18:03:03 +0900 Subject: [PATCH 327/861] Integration testing harness --- helix-term/src/application.rs | 4 ++-- helix-term/tests/integration.rs | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 helix-term/tests/integration.rs diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 075b9c355..09b7836fd 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -41,7 +41,7 @@ type Signals = futures_util::stream::Empty<()>; pub struct Application { compositor: Compositor, - editor: Editor, + pub editor: Editor, config: Arc>, @@ -193,7 +193,7 @@ impl Application { scroll: None, }; - self.compositor.render(&mut cx); + // self.compositor.render(&mut cx); } pub async fn event_loop(&mut self) { diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs new file mode 100644 index 000000000..1ef618f7e --- /dev/null +++ b/helix-term/tests/integration.rs @@ -0,0 +1,24 @@ +use helix_term::{application::Application, args::Args, config::Config}; +use helix_view::current; + +use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; + +#[tokio::test] +async fn it_works() { + let args = Args::default(); + let config = Config::default(); + let mut app = Application::new(args, config).unwrap(); + + let inputs = &['i', 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']; + + for input in inputs { + // TODO: use input.parse:: + app.handle_terminal_events(Ok(Event::Key(KeyEvent { + code: KeyCode::Char(*input), + modifiers: KeyModifiers::NONE, + }))); + } + + let (_, doc) = current!(app.editor); + assert_eq!(doc.text(), "hello world\n"); +} From 502d3290fb88d8a871b0824adc7987a98104933d Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Mon, 17 Jan 2022 19:04:40 -0500 Subject: [PATCH 328/861] improve test harness * Use new macro syntax for encoding sequences of keys * Make convenience helpers for common test pattern * Use indoc for inline indented raw strings * Add feature flag for integration testing to disable rendering --- Cargo.lock | 285 +++++++++++++++++++++----------- helix-core/Cargo.toml | 1 + helix-loader/src/lib.rs | 10 +- helix-term/Cargo.toml | 5 + helix-term/src/application.rs | 20 ++- helix-term/tests/integration.rs | 163 ++++++++++++++++-- helix-view/src/editor.rs | 1 + 7 files changed, 359 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ddf267906..39afd1414 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.57" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" +checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" [[package]] name = "arc-swap" @@ -25,9 +25,9 @@ checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bitflags" @@ -66,9 +66,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cc" -version = "1.0.73" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" [[package]] name = "cfg-if" @@ -121,9 +121,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" dependencies = [ "cfg-if", "lazy_static", @@ -131,15 +131,15 @@ dependencies = [ [[package]] name = "crossterm" -version = "0.23.2" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17" +checksum = "77b75a27dc8d220f1f8521ea69cd55a34d720a200ebb3a624d9aa19193d3b432" dependencies = [ "bitflags", "crossterm_winapi", "futures-core", "libc", - "mio", + "mio 0.7.14", "parking_lot", "signal-hook", "signal-hook-mio", @@ -184,9 +184,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "encoding_rs" -version = "0.8.31" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" dependencies = [ "cfg-if", ] @@ -293,9 +293,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.6" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" dependencies = [ "cfg-if", "libc", @@ -452,6 +452,7 @@ dependencies = [ "helix-tui", "helix-view", "ignore", + "indoc", "log", "once_cell", "pulldown-cmark", @@ -460,6 +461,7 @@ dependencies = [ "serde_json", "signal-hook", "signal-hook-tokio", + "smallvec", "tokio", "tokio-stream", "toml", @@ -544,11 +546,20 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "indoc" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a75aeaaef0ce18b58056d306c27b07436fbb34b8816c53094b76dd81803136" +dependencies = [ + "unindent", +] + [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "lazy_static" @@ -558,9 +569,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" [[package]] name = "libloading" @@ -574,19 +585,18 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.17" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if", ] @@ -612,9 +622,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memmap2" @@ -625,6 +635,19 @@ dependencies = [ "libc", ] +[[package]] +name = "mio" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + [[package]] name = "mio" version = "0.8.3" @@ -634,14 +657,32 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.36.1", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", ] [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg", "num-traits", @@ -649,9 +690,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg", ] @@ -684,15 +725,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.3" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.32.0", ] [[package]] @@ -703,9 +744,9 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" [[package]] name = "pin-utils" @@ -715,11 +756,11 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ - "unicode-ident", + "unicode-xid", ] [[package]] @@ -744,18 +785,18 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.18" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" dependencies = [ "proc-macro2", ] [[package]] name = "rand" -version = "0.8.5" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "rand_core", ] @@ -771,29 +812,28 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom", "redox_syscall", - "thiserror", ] [[package]] name = "regex" -version = "1.5.6" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", @@ -808,15 +848,15 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "retain_mut" -version = "0.1.9" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" +checksum = "8c31b5c4033f8fdde8700e4657be2c497e7288f01515be52168c631e2e4d4086" [[package]] name = "ropey" @@ -830,9 +870,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "same-file" @@ -851,18 +891,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.137" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", @@ -871,9 +911,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" dependencies = [ "itoa", "ryu", @@ -882,9 +922,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.8" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" +checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" dependencies = [ "proc-macro2", "quote", @@ -903,12 +943,12 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4" dependencies = [ "libc", - "mio", + "mio 0.7.14", "signal-hook", ] @@ -941,9 +981,9 @@ checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3" [[package]] name = "slab" -version = "0.4.6" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "slotmap" @@ -995,9 +1035,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "str-buf" -version = "1.0.6" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" +checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" [[package]] name = "str_indices" @@ -1007,13 +1047,13 @@ checksum = "9d9199fa80c817e074620be84374a520062ebac833f358d74b37060ce4a0f2c0" [[package]] name = "syn" -version = "1.0.95" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" dependencies = [ "proc-macro2", "quote", - "unicode-ident", + "unicode-xid", ] [[package]] @@ -1029,18 +1069,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", "quote", @@ -1067,9 +1107,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" dependencies = [ "tinyvec_macros", ] @@ -1089,7 +1129,7 @@ dependencies = [ "bytes", "libc", "memchr", - "mio", + "mio 0.8.3", "num_cpus", "once_cell", "parking_lot", @@ -1133,9 +1173,9 @@ dependencies = [ [[package]] name = "tree-sitter" -version = "0.20.6" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3b781640108d29892e8b9684642d2cda5ea05951fd58f0fea1db9edeb9b71" +checksum = "4e34327f8eac545e3f037382471b2b19367725a242bba7bc45edb9efb49fe39a" dependencies = [ "cc", "regex", @@ -1152,9 +1192,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" [[package]] name = "unicode-general-category" @@ -1162,12 +1202,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1218098468b8085b19a2824104c70d976491d247ce194bbd9dc77181150cdfd6" -[[package]] -name = "unicode-ident" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" - [[package]] name = "unicode-linebreak" version = "0.1.2" @@ -1198,6 +1232,18 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "unindent" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" + [[package]] name = "url" version = "2.2.2" @@ -1242,9 +1288,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "which" -version = "4.2.5" +version = "4.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" +checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2" dependencies = [ "either", "lazy_static", @@ -1282,43 +1328,86 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +dependencies = [ + "windows_aarch64_msvc 0.32.0", + "windows_i686_gnu 0.32.0", + "windows_i686_msvc 0.32.0", + "windows_x86_64_gnu 0.32.0", + "windows_x86_64_msvc 0.32.0", +] + [[package]] name = "windows-sys" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] +[[package]] +name = "windows_aarch64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +[[package]] +name = "windows_i686_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" + [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +[[package]] +name = "windows_i686_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" + [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +[[package]] +name = "windows_x86_64_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +[[package]] +name = "windows_x86_64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 6574d144b..5eb3b621a 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -12,6 +12,7 @@ include = ["src/**/*", "README.md"] [features] unicode-lines = ["ropey/unicode_lines"] +integration = [] [dependencies] helix-loader = { version = "0.6", path = "../helix-loader" } diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index 767bff7a4..595ac7aa5 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -11,17 +11,17 @@ pub fn runtime_dir() -> std::path::PathBuf { return dir.into(); } + if let Ok(dir) = std::env::var("CARGO_MANIFEST_DIR") { + // this is the directory of the crate being run by cargo, we need the workspace path so we take the parent + return std::path::PathBuf::from(dir).parent().unwrap().join(RT_DIR); + } + const RT_DIR: &str = "runtime"; let conf_dir = config_dir().join(RT_DIR); if conf_dir.exists() { return conf_dir; } - if let Ok(dir) = std::env::var("CARGO_MANIFEST_DIR") { - // this is the directory of the crate being run by cargo, we need the workspace path so we take the parent - return std::path::PathBuf::from(dir).parent().unwrap().join(RT_DIR); - } - // fallback to location of the executable being run std::env::current_exe() .ok() diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 0f80c416a..05f8eed4c 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -17,6 +17,7 @@ app = true [features] unicode-lines = ["helix-core/unicode-lines"] +integration = [] [[bin]] name = "hx" @@ -73,3 +74,7 @@ signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } [build-dependencies] helix-loader = { version = "0.6", path = "../helix-loader" } + +[dev-dependencies] +smallvec = "1.8" +indoc = "1.0.3" diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 09b7836fd..21595eae7 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -187,13 +187,21 @@ impl Application { } fn render(&mut self) { - let mut cx = crate::compositor::Context { - editor: &mut self.editor, - jobs: &mut self.jobs, - scroll: None, - }; + #[cfg(feature = "integration")] + return; + + #[allow(unreachable_code)] + { + let compositor = &mut self.compositor; - // self.compositor.render(&mut cx); + let mut cx = crate::compositor::Context { + editor: &mut self.editor, + jobs: &mut self.jobs, + scroll: None, + }; + + compositor.render(&mut cx); + } } pub async fn event_loop(&mut self) { diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs index 1ef618f7e..31a0d218e 100644 --- a/helix-term/tests/integration.rs +++ b/helix-term/tests/integration.rs @@ -1,24 +1,153 @@ -use helix_term::{application::Application, args::Args, config::Config}; -use helix_view::current; +#[cfg(feature = "integration")] +mod integration { + use std::path::PathBuf; -use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; + use helix_core::{syntax::AutoPairConfig, Position, Selection, Tendril, Transaction}; + use helix_term::{application::Application, args::Args, config::Config}; + use helix_view::{current, doc, input::parse_macro}; -#[tokio::test] -async fn it_works() { - let args = Args::default(); - let config = Config::default(); - let mut app = Application::new(args, config).unwrap(); + use crossterm::event::{Event, KeyEvent}; + use indoc::indoc; - let inputs = &['i', 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']; + pub struct TestCase { + pub in_text: String, + pub in_selection: Selection, + pub in_keys: String, + pub out_text: String, + pub out_selection: Selection, + } + + fn test_key_sequence( + app: Option, + test_case: &TestCase, + test_fn: &dyn Fn(&mut Application), + ) -> anyhow::Result<()> { + let mut app = + app.unwrap_or_else(|| Application::new(Args::default(), Config::default()).unwrap()); + + let (view, doc) = current!(app.editor); + + doc.apply( + &Transaction::insert( + doc.text(), + &Selection::single(1, 0), + Tendril::from(&test_case.in_text), + ) + .with_selection(test_case.in_selection.clone()), + view.id, + ); + + let input_keys = parse_macro(&test_case.in_keys)? + .into_iter() + .map(|key_event| Event::Key(KeyEvent::from(key_event))); + + for key in input_keys { + app.handle_terminal_events(Ok(key)); + } + + test_fn(&mut app); + + Ok(()) + } + + /// Use this for very simple test cases where there is one input + /// document, selection, and sequence of key presses, and you just + /// want to verify the resulting document and selection. + fn test_key_sequence_text_result( + args: Args, + config: Config, + test_case: TestCase, + ) -> anyhow::Result<()> { + let app = Application::new(args, config).unwrap(); + + test_key_sequence(Some(app), &test_case, &|app| { + let doc = doc!(app.editor); + assert_eq!(&test_case.out_text, doc.text()); - for input in inputs { - // TODO: use input.parse:: - app.handle_terminal_events(Ok(Event::Key(KeyEvent { - code: KeyCode::Char(*input), - modifiers: KeyModifiers::NONE, - }))); + let mut selections: Vec<_> = doc.selections().values().cloned().collect(); + assert_eq!(1, selections.len()); + + let sel = selections.pop().unwrap(); + assert_eq!(test_case.out_selection, sel); + })?; + + Ok(()) + } + + #[tokio::test] + async fn hello_world() -> anyhow::Result<()> { + test_key_sequence_text_result( + Args::default(), + Config::default(), + TestCase { + in_text: String::new(), + in_selection: Selection::single(0, 1), + // TODO: fix incorrect selection on new doc + in_keys: String::from("ihello worldhl"), + out_text: String::from("hello world\n"), + out_selection: Selection::single(11, 12), + }, + )?; + + Ok(()) } - let (_, doc) = current!(app.editor); - assert_eq!(doc.text(), "hello world\n"); + #[tokio::test] + async fn auto_pairs_basic() -> anyhow::Result<()> { + test_key_sequence_text_result( + Args::default(), + Config::default(), + TestCase { + in_text: String::new(), + in_selection: Selection::single(0, 1), + in_keys: String::from("i(hl"), + out_text: String::from("()\n"), + out_selection: Selection::single(1, 2), + }, + )?; + + test_key_sequence_text_result( + Args::default(), + Config { + editor: helix_view::editor::Config { + auto_pairs: AutoPairConfig::Enable(false), + ..Default::default() + }, + ..Default::default() + }, + TestCase { + in_text: String::new(), + in_selection: Selection::single(0, 1), + in_keys: String::from("i(hl"), + out_text: String::from("(\n"), + out_selection: Selection::single(1, 2), + }, + )?; + + Ok(()) + } + + #[tokio::test] + async fn auto_indent_rs() -> anyhow::Result<()> { + test_key_sequence_text_result( + Args { + files: vec![(PathBuf::from("foo.c"), Position::default())], + ..Default::default() + }, + Config::default(), + TestCase { + in_text: String::from("void foo() {}"), + in_selection: Selection::single(12, 13), + in_keys: String::from("i"), + out_text: String::from(indoc! {r#" + void foo() { + + } + "#}), + out_selection: Selection::single(15, 16), + }, + )?; + + Ok(()) + } } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index ac19def10..76ac0b51d 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -769,6 +769,7 @@ impl Editor { Ok(self.new_file_from_document(action, Document::from(rope, Some(encoding)))) } + // ??? pub fn open(&mut self, path: PathBuf, action: Action) -> Result { let path = helix_core::path::get_canonicalized_path(&path)?; let id = self.document_by_path(&path).map(|doc| doc.id); From 0f3c10a021bbe79e20bde1f55b87465edeec476d Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Wed, 16 Mar 2022 23:34:21 -0400 Subject: [PATCH 329/861] Fix initial selection of Document in new view When a new View of a Document is created, a default cursor of 0, 0 is created, and it does not get normalized to a single width cursor until at least one movement of the cursor happens. This appears to have no practical negative effect that I could find, but it makes tests difficult to work with, since the initial selection is not what you expect it to be. This changes the initial selection of a new View to be the width of the first grapheme in the text. --- .gitignore | 1 - helix-core/src/auto_pairs.rs | 14 +--- helix-core/src/selection.rs | 10 ++- helix-loader/Cargo.toml | 1 - helix-loader/src/lib.rs | 4 +- helix-term/src/application.rs | 21 ++++++ helix-term/src/commands.rs | 17 +++-- helix-term/tests/integration.rs | 112 ++++++++++++++++++++++++-------- helix-view/src/document.rs | 34 +++++++++- helix-view/src/editor.rs | 24 ++----- 10 files changed, 173 insertions(+), 65 deletions(-) diff --git a/.gitignore b/.gitignore index 346d0946a..6a6fc782a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ target .direnv helix-term/rustfmt.toml -helix-syntax/languages/ result runtime/grammars diff --git a/helix-core/src/auto_pairs.rs b/helix-core/src/auto_pairs.rs index bcd47356f..1131178e3 100644 --- a/helix-core/src/auto_pairs.rs +++ b/helix-core/src/auto_pairs.rs @@ -1,9 +1,7 @@ //! When typing the opening character of one of the possible pairs defined below, //! this module provides the functionality to insert the paired closing character. -use crate::{ - graphemes, movement::Direction, Range, Rope, RopeGraphemes, Selection, Tendril, Transaction, -}; +use crate::{graphemes, movement::Direction, Range, Rope, Selection, Tendril, Transaction}; use std::collections::HashMap; use log::debug; @@ -149,14 +147,6 @@ fn prev_char(doc: &Rope, pos: usize) -> Option { doc.get_char(pos - 1) } -fn is_single_grapheme(doc: &Rope, range: &Range) -> bool { - let mut graphemes = RopeGraphemes::new(doc.slice(range.from()..range.to())); - let first = graphemes.next(); - let second = graphemes.next(); - debug!("first: {:#?}, second: {:#?}", first, second); - first.is_some() && second.is_none() -} - /// calculate what the resulting range should be for an auto pair insertion fn get_next_range( doc: &Rope, @@ -189,8 +179,8 @@ fn get_next_range( ); } - let single_grapheme = is_single_grapheme(doc, start_range); let doc_slice = doc.slice(..); + let single_grapheme = start_range.is_single_grapheme(doc_slice); // just skip over graphemes if len_inserted == 0 { diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index 1b2416f5b..83bab5e30 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -8,7 +8,7 @@ use crate::{ prev_grapheme_boundary, }, movement::Direction, - Assoc, ChangeSet, RopeSlice, + Assoc, ChangeSet, RopeGraphemes, RopeSlice, }; use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; @@ -339,6 +339,14 @@ impl Range { pub fn cursor_line(&self, text: RopeSlice) -> usize { text.char_to_line(self.cursor(text)) } + + /// Returns true if this Range covers a single grapheme in the given text + pub fn is_single_grapheme(&self, doc: RopeSlice) -> bool { + let mut graphemes = RopeGraphemes::new(doc.slice(self.from()..self.to())); + let first = graphemes.next(); + let second = graphemes.next(); + first.is_some() && second.is_none() + } } impl From<(usize, usize)> for Range { diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index 203844727..3d8a697cc 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -20,7 +20,6 @@ toml = "0.5" etcetera = "0.4" tree-sitter = "0.20" once_cell = "1.12" - log = "0.4" # TODO: these two should be on !wasm32 only diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index 595ac7aa5..ff4414b26 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -13,7 +13,9 @@ pub fn runtime_dir() -> std::path::PathBuf { if let Ok(dir) = std::env::var("CARGO_MANIFEST_DIR") { // this is the directory of the crate being run by cargo, we need the workspace path so we take the parent - return std::path::PathBuf::from(dir).parent().unwrap().join(RT_DIR); + let path = std::path::PathBuf::from(dir).parent().unwrap().join(RT_DIR); + log::debug!("runtime dir: {}", path.to_string_lossy()); + return path; } const RT_DIR: &str = "runtime"; diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 21595eae7..146194bff 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -55,8 +55,29 @@ pub struct Application { lsp_progress: LspProgressMap, } +#[cfg(feature = "integration")] +fn setup_integration_logging() { + // Separate file config so we can include year, month and day in file logs + let _ = fern::Dispatch::new() + .format(|out, message, record| { + out.finish(format_args!( + "{} {} [{}] {}", + chrono::Local::now().format("%Y-%m-%dT%H:%M:%S%.3f"), + record.target(), + record.level(), + message + )) + }) + .level(log::LevelFilter::Debug) + .chain(std::io::stdout()) + .apply(); +} + impl Application { pub fn new(args: Args, config: Config) -> Result { + #[cfg(feature = "integration")] + setup_integration_logging(); + use helix_view::editor::Action; let config_dir = helix_loader::config_dir(); diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c9c8e6a98..6b01cbe31 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2094,10 +2094,17 @@ fn insert_mode(cx: &mut Context) { let (view, doc) = current!(cx.editor); enter_insert_mode(doc); - let selection = doc - .selection(view.id) - .clone() - .transform(|range| Range::new(range.to(), range.from())); + log::trace!( + "entering insert mode with sel: {:?}, text: {:?}", + doc.selection(view.id), + doc.text().to_string() + ); + + let selection = doc.selection(view.id).clone().transform(|range| { + let new_range = Range::new(range.to(), range.from()); + new_range + }); + doc.set_selection(view.id, selection); } @@ -2444,8 +2451,8 @@ fn normal_mode(cx: &mut Context) { graphemes::prev_grapheme_boundary(text, range.to()), ) }); - doc.set_selection(view.id, selection); + doc.set_selection(view.id, selection); doc.restore_cursor = false; } } diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs index 31a0d218e..58883d40e 100644 --- a/helix-term/tests/integration.rs +++ b/helix-term/tests/integration.rs @@ -2,9 +2,9 @@ mod integration { use std::path::PathBuf; - use helix_core::{syntax::AutoPairConfig, Position, Selection, Tendril, Transaction}; + use helix_core::{syntax::AutoPairConfig, Position, Selection, Transaction}; use helix_term::{application::Application, args::Args, config::Config}; - use helix_view::{current, doc, input::parse_macro}; + use helix_view::{doc, input::parse_macro}; use crossterm::event::{Event, KeyEvent}; use indoc::indoc; @@ -25,14 +25,14 @@ mod integration { let mut app = app.unwrap_or_else(|| Application::new(Args::default(), Config::default()).unwrap()); - let (view, doc) = current!(app.editor); + let (view, doc) = helix_view::current!(app.editor); + let sel = doc.selection(view.id).clone(); + // replace the initial text with the input text doc.apply( - &Transaction::insert( - doc.text(), - &Selection::single(1, 0), - Tendril::from(&test_case.in_text), - ) + &Transaction::change_by_selection(&doc.text(), &sel, |_| { + (0, doc.text().len_chars(), Some((&test_case.in_text).into())) + }) .with_selection(test_case.in_selection.clone()), view.id, ); @@ -80,12 +80,12 @@ mod integration { Args::default(), Config::default(), TestCase { - in_text: String::new(), + in_text: "\n".into(), in_selection: Selection::single(0, 1), // TODO: fix incorrect selection on new doc - in_keys: String::from("ihello worldhl"), - out_text: String::from("hello world\n"), - out_selection: Selection::single(11, 12), + in_keys: "ihello world".into(), + out_text: "hello world\n".into(), + out_selection: Selection::single(12, 11), }, )?; @@ -93,16 +93,74 @@ mod integration { } #[tokio::test] - async fn auto_pairs_basic() -> anyhow::Result<()> { + async fn insert_mode_cursor_position() -> anyhow::Result<()> { test_key_sequence_text_result( Args::default(), Config::default(), TestCase { in_text: String::new(), + in_selection: Selection::single(0, 0), + in_keys: "i".into(), + out_text: String::new(), + out_selection: Selection::single(0, 0), + }, + )?; + + test_key_sequence_text_result( + Args::default(), + Config::default(), + TestCase { + in_text: "\n".into(), + in_selection: Selection::single(0, 1), + in_keys: "i".into(), + out_text: "\n".into(), + out_selection: Selection::single(1, 0), + }, + )?; + + test_key_sequence_text_result( + Args::default(), + Config::default(), + TestCase { + in_text: "\n".into(), in_selection: Selection::single(0, 1), - in_keys: String::from("i(hl"), - out_text: String::from("()\n"), - out_selection: Selection::single(1, 2), + in_keys: "ii".into(), + out_text: "\n".into(), + out_selection: Selection::single(1, 0), + }, + )?; + + Ok(()) + } + + #[tokio::test] + async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { + test_key_sequence_text_result( + Args::default(), + Config::default(), + TestCase { + in_text: "\n".into(), + in_selection: Selection::single(0, 1), + in_keys: "i".into(), + out_text: "\n".into(), + out_selection: Selection::single(1, 0), + }, + )?; + + Ok(()) + } + + #[tokio::test] + async fn auto_pairs_basic() -> anyhow::Result<()> { + test_key_sequence_text_result( + Args::default(), + Config::default(), + TestCase { + in_text: "\n".into(), + in_selection: Selection::single(0, 1), + in_keys: "i(".into(), + out_text: "()\n".into(), + out_selection: Selection::single(2, 1), }, )?; @@ -116,11 +174,11 @@ mod integration { ..Default::default() }, TestCase { - in_text: String::new(), + in_text: "\n".into(), in_selection: Selection::single(0, 1), - in_keys: String::from("i(hl"), - out_text: String::from("(\n"), - out_selection: Selection::single(1, 2), + in_keys: "i(".into(), + out_text: "(\n".into(), + out_selection: Selection::single(2, 1), }, )?; @@ -136,15 +194,17 @@ mod integration { }, Config::default(), TestCase { - in_text: String::from("void foo() {}"), - in_selection: Selection::single(12, 13), - in_keys: String::from("i"), - out_text: String::from(indoc! {r#" + in_text: "void foo() {}\n".into(), + in_selection: Selection::single(13, 12), + in_keys: "i".into(), + out_text: indoc! {r#" void foo() { } - "#}), - out_selection: Selection::single(15, 16), + "#} + .trim_start() + .into(), + out_selection: Selection::single(16, 15), }, )?; diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index a2d2af77c..00adaa1a7 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1,5 +1,6 @@ use anyhow::{anyhow, bail, Context, Error}; use helix_core::auto_pairs::AutoPairs; +use helix_core::Range; use serde::de::{self, Deserialize, Deserializer}; use serde::Serialize; use std::cell::Cell; @@ -83,7 +84,7 @@ impl Serialize for Mode { pub struct Document { pub(crate) id: DocumentId, text: Rope, - pub(crate) selections: HashMap, + selections: HashMap, path: Option, encoding: &'static encoding::Encoding, @@ -637,6 +638,37 @@ impl Document { .insert(view_id, selection.ensure_invariants(self.text().slice(..))); } + /// Find the origin selection of the text in a document, i.e. where + /// a single cursor would go if it were on the first grapheme. If + /// the text is empty, returns (0, 0). + pub fn origin(&self) -> Range { + if self.text().len_chars() == 0 { + return Range::new(0, 0); + } + + Range::new(0, 1).grapheme_aligned(self.text().slice(..)) + } + + /// Reset the view's selection on this document to the + /// [origin](Document::origin) cursor. + pub fn reset_selection(&mut self, view_id: ViewId) { + let origin = self.origin(); + self.set_selection(view_id, Selection::single(origin.anchor, origin.head)); + } + + /// Initializes a new selection for the given view if it does not + /// already have one. + pub fn ensure_view_init(&mut self, view_id: ViewId) { + if self.selections.get(&view_id).is_none() { + self.reset_selection(view_id); + } + } + + /// Remove a view's selection from this document. + pub fn remove_view(&mut self, view_id: ViewId) { + self.selections.remove(&view_id); + } + /// Apply a [`Transaction`] to the [`Document`] to change its text. fn apply_impl(&mut self, transaction: &Transaction, view_id: ViewId) -> bool { let old_doc = self.text().clone(); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 76ac0b51d..8607c65a2 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -32,12 +32,12 @@ use anyhow::{bail, Error}; pub use helix_core::diagnostic::Severity; pub use helix_core::register::Registers; +use helix_core::Position; use helix_core::{ auto_pairs::AutoPairs, syntax::{self, AutoPairConfig}, Change, }; -use helix_core::{Position, Selection}; use helix_dap as dap; use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer}; @@ -645,11 +645,8 @@ impl Editor { view.offset = Position::default(); let doc = self.documents.get_mut(&doc_id).unwrap(); + doc.ensure_view_init(view.id); - // initialize selection for view - doc.selections - .entry(view.id) - .or_insert_with(|| Selection::point(0)); // TODO: reuse align_view let pos = doc .selection(view.id) @@ -719,9 +716,7 @@ impl Editor { Action::Load => { let view_id = view!(self).id; let doc = self.documents.get_mut(&id).unwrap(); - if doc.selections().is_empty() { - doc.set_selection(view_id, Selection::point(0)); - } + doc.ensure_view_init(view_id); return; } Action::HorizontalSplit | Action::VerticalSplit => { @@ -736,7 +731,7 @@ impl Editor { ); // initialize selection for view let doc = self.documents.get_mut(&id).unwrap(); - doc.set_selection(view_id, Selection::point(0)); + doc.ensure_view_init(view_id); } } @@ -769,7 +764,7 @@ impl Editor { Ok(self.new_file_from_document(action, Document::from(rope, Some(encoding)))) } - // ??? + // ??? possible use for integration tests pub fn open(&mut self, path: PathBuf, action: Action) -> Result { let path = helix_core::path::get_canonicalized_path(&path)?; let id = self.document_by_path(&path).map(|doc| doc.id); @@ -791,12 +786,7 @@ impl Editor { pub fn close(&mut self, id: ViewId) { let view = self.tree.get(self.tree.focus); // remove selection - self.documents - .get_mut(&view.doc) - .unwrap() - .selections - .remove(&id); - + self.documents.get_mut(&view.doc).unwrap().remove_view(id); self.tree.remove(id); self._refresh(); } @@ -871,7 +861,7 @@ impl Editor { let view = View::new(doc_id, self.config().gutters.clone()); let view_id = self.tree.insert(view); let doc = self.documents.get_mut(&doc_id).unwrap(); - doc.set_selection(view_id, Selection::point(0)); + doc.ensure_view_init(view_id); } self._refresh(); From 84bbe6b8f3aa23f3f9f1d8b38844efba6af17b41 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Sat, 16 Apr 2022 22:05:45 -0400 Subject: [PATCH 330/861] refactor helpers, use new test helpers --- helix-term/tests/integration.rs | 198 +++++++++--------------- helix-term/tests/integration/helpers.rs | 87 +++++++++++ 2 files changed, 162 insertions(+), 123 deletions(-) create mode 100644 helix-term/tests/integration/helpers.rs diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs index 58883d40e..a32eebf5b 100644 --- a/helix-term/tests/integration.rs +++ b/helix-term/tests/integration.rs @@ -1,92 +1,22 @@ #[cfg(feature = "integration")] mod integration { + mod helpers; + use std::path::PathBuf; - use helix_core::{syntax::AutoPairConfig, Position, Selection, Transaction}; - use helix_term::{application::Application, args::Args, config::Config}; - use helix_view::{doc, input::parse_macro}; + use helix_core::{syntax::AutoPairConfig, Position, Selection}; + use helix_term::{args::Args, config::Config}; - use crossterm::event::{Event, KeyEvent}; use indoc::indoc; - pub struct TestCase { - pub in_text: String, - pub in_selection: Selection, - pub in_keys: String, - pub out_text: String, - pub out_selection: Selection, - } - - fn test_key_sequence( - app: Option, - test_case: &TestCase, - test_fn: &dyn Fn(&mut Application), - ) -> anyhow::Result<()> { - let mut app = - app.unwrap_or_else(|| Application::new(Args::default(), Config::default()).unwrap()); - - let (view, doc) = helix_view::current!(app.editor); - let sel = doc.selection(view.id).clone(); - - // replace the initial text with the input text - doc.apply( - &Transaction::change_by_selection(&doc.text(), &sel, |_| { - (0, doc.text().len_chars(), Some((&test_case.in_text).into())) - }) - .with_selection(test_case.in_selection.clone()), - view.id, - ); - - let input_keys = parse_macro(&test_case.in_keys)? - .into_iter() - .map(|key_event| Event::Key(KeyEvent::from(key_event))); - - for key in input_keys { - app.handle_terminal_events(Ok(key)); - } - - test_fn(&mut app); - - Ok(()) - } - - /// Use this for very simple test cases where there is one input - /// document, selection, and sequence of key presses, and you just - /// want to verify the resulting document and selection. - fn test_key_sequence_text_result( - args: Args, - config: Config, - test_case: TestCase, - ) -> anyhow::Result<()> { - let app = Application::new(args, config).unwrap(); - - test_key_sequence(Some(app), &test_case, &|app| { - let doc = doc!(app.editor); - assert_eq!(&test_case.out_text, doc.text()); - - let mut selections: Vec<_> = doc.selections().values().cloned().collect(); - assert_eq!(1, selections.len()); - - let sel = selections.pop().unwrap(); - assert_eq!(test_case.out_selection, sel); - })?; - - Ok(()) - } + use self::helpers::*; #[tokio::test] async fn hello_world() -> anyhow::Result<()> { test_key_sequence_text_result( Args::default(), Config::default(), - TestCase { - in_text: "\n".into(), - in_selection: Selection::single(0, 1), - // TODO: fix incorrect selection on new doc - in_keys: "ihello world".into(), - out_text: "hello world\n".into(), - out_selection: Selection::single(12, 11), - }, + ("#[\n|]#", "ihello world", "hello world#[|\n]#"), )?; Ok(()) @@ -109,42 +39,79 @@ mod integration { test_key_sequence_text_result( Args::default(), Config::default(), - TestCase { - in_text: "\n".into(), - in_selection: Selection::single(0, 1), - in_keys: "i".into(), - out_text: "\n".into(), - out_selection: Selection::single(1, 0), - }, + ("#[\n|]#", "i", "#[|\n]#"), )?; test_key_sequence_text_result( Args::default(), Config::default(), - TestCase { - in_text: "\n".into(), - in_selection: Selection::single(0, 1), - in_keys: "ii".into(), - out_text: "\n".into(), - out_selection: Selection::single(1, 0), - }, + ("#[\n|]#", "i", "#[|\n]#"), + )?; + + test_key_sequence_text_result( + Args::default(), + Config::default(), + ("#[\n|]#", "ii", "#[|\n]#"), )?; Ok(()) } + /// Range direction is preserved when escaping insert mode to normal #[tokio::test] async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { test_key_sequence_text_result( Args::default(), Config::default(), - TestCase { - in_text: "\n".into(), - in_selection: Selection::single(0, 1), - in_keys: "i".into(), - out_text: "\n".into(), - out_selection: Selection::single(1, 0), - }, + ("#[f|]#oo\n", "vll", "#[|foo]#\n"), + )?; + + test_key_sequence_text_result( + Args::default(), + Config::default(), + ( + indoc! {"\ + #[f|]#oo + #(b|)#ar" + }, + "vll", + indoc! {"\ + #[|foo]# + #(|bar)#" + }, + ), + )?; + + test_key_sequence_text_result( + Args::default(), + Config::default(), + ( + indoc! {"\ + #[f|]#oo + #(b|)#ar" + }, + "a", + indoc! {"\ + #[fo|]#o + #(ba|)#r" + }, + ), + )?; + + test_key_sequence_text_result( + Args::default(), + Config::default(), + ( + indoc! {"\ + #[f|]#oo + #(b|)#ar" + }, + "a", + indoc! {"\ + #[f|]#oo + #(b|)#ar" + }, + ), )?; Ok(()) @@ -155,13 +122,7 @@ mod integration { test_key_sequence_text_result( Args::default(), Config::default(), - TestCase { - in_text: "\n".into(), - in_selection: Selection::single(0, 1), - in_keys: "i(".into(), - out_text: "()\n".into(), - out_selection: Selection::single(2, 1), - }, + ("#[\n|]#", "i(", "(#[|)]#\n"), )?; test_key_sequence_text_result( @@ -173,39 +134,30 @@ mod integration { }, ..Default::default() }, - TestCase { - in_text: "\n".into(), - in_selection: Selection::single(0, 1), - in_keys: "i(".into(), - out_text: "(\n".into(), - out_selection: Selection::single(2, 1), - }, + ("#[\n|]#", "i(", "(#[|\n]#"), )?; Ok(()) } #[tokio::test] - async fn auto_indent_rs() -> anyhow::Result<()> { + async fn auto_indent_c() -> anyhow::Result<()> { test_key_sequence_text_result( Args { files: vec![(PathBuf::from("foo.c"), Position::default())], ..Default::default() }, Config::default(), - TestCase { - in_text: "void foo() {}\n".into(), - in_selection: Selection::single(13, 12), - in_keys: "i".into(), - out_text: indoc! {r#" + // switches to append mode? + ( + "void foo() {#[|}]#\n", + "i", + indoc! {"\ void foo() { - + #[|\n]#\ } - "#} - .trim_start() - .into(), - out_selection: Selection::single(16, 15), - }, + "}, + ), )?; Ok(()) diff --git a/helix-term/tests/integration/helpers.rs b/helix-term/tests/integration/helpers.rs new file mode 100644 index 000000000..d22bcc3ce --- /dev/null +++ b/helix-term/tests/integration/helpers.rs @@ -0,0 +1,87 @@ +use crossterm::event::{Event, KeyEvent}; +use helix_core::{test, Selection, Transaction}; +use helix_term::{application::Application, args::Args, config::Config}; +use helix_view::{doc, input::parse_macro}; + +#[derive(Clone, Debug)] +pub struct TestCase { + pub in_text: String, + pub in_selection: Selection, + pub in_keys: String, + pub out_text: String, + pub out_selection: Selection, +} + +impl> From<(S, S, S)> for TestCase { + fn from((input, keys, output): (S, S, S)) -> Self { + let (in_text, in_selection) = test::print(&input.into()); + let (out_text, out_selection) = test::print(&output.into()); + + TestCase { + in_text, + in_selection, + in_keys: keys.into(), + out_text, + out_selection, + } + } +} + +pub fn test_key_sequence>( + app: Option, + test_case: T, + test_fn: &dyn Fn(&mut Application), +) -> anyhow::Result<()> { + let test_case = test_case.into(); + let mut app = + app.unwrap_or_else(|| Application::new(Args::default(), Config::default()).unwrap()); + + let (view, doc) = helix_view::current!(app.editor); + let sel = doc.selection(view.id).clone(); + + // replace the initial text with the input text + doc.apply( + &Transaction::change_by_selection(&doc.text(), &sel, |_| { + (0, doc.text().len_chars(), Some((&test_case.in_text).into())) + }) + .with_selection(test_case.in_selection.clone()), + view.id, + ); + + let input_keys = parse_macro(&test_case.in_keys)? + .into_iter() + .map(|key_event| Event::Key(KeyEvent::from(key_event))); + + for key in input_keys { + app.handle_terminal_events(Ok(key)); + } + + test_fn(&mut app); + + Ok(()) +} + +/// Use this for very simple test cases where there is one input +/// document, selection, and sequence of key presses, and you just +/// want to verify the resulting document and selection. +pub fn test_key_sequence_text_result>( + args: Args, + config: Config, + test_case: T, +) -> anyhow::Result<()> { + let test_case = test_case.into(); + let app = Application::new(args, config).unwrap(); + + test_key_sequence(Some(app), test_case.clone(), &|app| { + let doc = doc!(app.editor); + assert_eq!(&test_case.out_text, doc.text()); + + let mut selections: Vec<_> = doc.selections().values().cloned().collect(); + assert_eq!(1, selections.len()); + + let sel = selections.pop().unwrap(); + assert_eq!(test_case.out_selection, sel); + })?; + + Ok(()) +} From 267605d147587e120d765fa62333dd986a3cb5e6 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Sun, 17 Apr 2022 00:19:22 -0400 Subject: [PATCH 331/861] reorganize tests into groups --- helix-term/src/application.rs | 2 +- helix-term/tests/integration.rs | 143 +------------------- helix-term/tests/integration/auto_indent.rs | 24 ++++ helix-term/tests/integration/auto_pairs.rs | 24 ++++ helix-term/tests/integration/movement.rs | 96 +++++++++++++ 5 files changed, 148 insertions(+), 141 deletions(-) create mode 100644 helix-term/tests/integration/auto_indent.rs create mode 100644 helix-term/tests/integration/auto_pairs.rs create mode 100644 helix-term/tests/integration/movement.rs diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 146194bff..44025ea02 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -68,7 +68,7 @@ fn setup_integration_logging() { message )) }) - .level(log::LevelFilter::Debug) + .level(log::LevelFilter::Info) .chain(std::io::stdout()) .apply(); } diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs index a32eebf5b..a388cf6bf 100644 --- a/helix-term/tests/integration.rs +++ b/helix-term/tests/integration.rs @@ -22,144 +22,7 @@ mod integration { Ok(()) } - #[tokio::test] - async fn insert_mode_cursor_position() -> anyhow::Result<()> { - test_key_sequence_text_result( - Args::default(), - Config::default(), - TestCase { - in_text: String::new(), - in_selection: Selection::single(0, 0), - in_keys: "i".into(), - out_text: String::new(), - out_selection: Selection::single(0, 0), - }, - )?; - - test_key_sequence_text_result( - Args::default(), - Config::default(), - ("#[\n|]#", "i", "#[|\n]#"), - )?; - - test_key_sequence_text_result( - Args::default(), - Config::default(), - ("#[\n|]#", "i", "#[|\n]#"), - )?; - - test_key_sequence_text_result( - Args::default(), - Config::default(), - ("#[\n|]#", "ii", "#[|\n]#"), - )?; - - Ok(()) - } - - /// Range direction is preserved when escaping insert mode to normal - #[tokio::test] - async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { - test_key_sequence_text_result( - Args::default(), - Config::default(), - ("#[f|]#oo\n", "vll", "#[|foo]#\n"), - )?; - - test_key_sequence_text_result( - Args::default(), - Config::default(), - ( - indoc! {"\ - #[f|]#oo - #(b|)#ar" - }, - "vll", - indoc! {"\ - #[|foo]# - #(|bar)#" - }, - ), - )?; - - test_key_sequence_text_result( - Args::default(), - Config::default(), - ( - indoc! {"\ - #[f|]#oo - #(b|)#ar" - }, - "a", - indoc! {"\ - #[fo|]#o - #(ba|)#r" - }, - ), - )?; - - test_key_sequence_text_result( - Args::default(), - Config::default(), - ( - indoc! {"\ - #[f|]#oo - #(b|)#ar" - }, - "a", - indoc! {"\ - #[f|]#oo - #(b|)#ar" - }, - ), - )?; - - Ok(()) - } - - #[tokio::test] - async fn auto_pairs_basic() -> anyhow::Result<()> { - test_key_sequence_text_result( - Args::default(), - Config::default(), - ("#[\n|]#", "i(", "(#[|)]#\n"), - )?; - - test_key_sequence_text_result( - Args::default(), - Config { - editor: helix_view::editor::Config { - auto_pairs: AutoPairConfig::Enable(false), - ..Default::default() - }, - ..Default::default() - }, - ("#[\n|]#", "i(", "(#[|\n]#"), - )?; - - Ok(()) - } - - #[tokio::test] - async fn auto_indent_c() -> anyhow::Result<()> { - test_key_sequence_text_result( - Args { - files: vec![(PathBuf::from("foo.c"), Position::default())], - ..Default::default() - }, - Config::default(), - // switches to append mode? - ( - "void foo() {#[|}]#\n", - "i", - indoc! {"\ - void foo() { - #[|\n]#\ - } - "}, - ), - )?; - - Ok(()) - } + mod auto_indent; + mod auto_pairs; + mod movement; } diff --git a/helix-term/tests/integration/auto_indent.rs b/helix-term/tests/integration/auto_indent.rs new file mode 100644 index 000000000..18138ccaf --- /dev/null +++ b/helix-term/tests/integration/auto_indent.rs @@ -0,0 +1,24 @@ +use super::*; + +#[tokio::test] +async fn auto_indent_c() -> anyhow::Result<()> { + test_key_sequence_text_result( + Args { + files: vec![(PathBuf::from("foo.c"), Position::default())], + ..Default::default() + }, + Config::default(), + // switches to append mode? + ( + "void foo() {#[|}]#\n", + "i", + indoc! {"\ + void foo() { + #[|\n]#\ + } + "}, + ), + )?; + + Ok(()) +} diff --git a/helix-term/tests/integration/auto_pairs.rs b/helix-term/tests/integration/auto_pairs.rs new file mode 100644 index 000000000..4da44d45e --- /dev/null +++ b/helix-term/tests/integration/auto_pairs.rs @@ -0,0 +1,24 @@ +use super::*; + +#[tokio::test] +async fn auto_pairs_basic() -> anyhow::Result<()> { + test_key_sequence_text_result( + Args::default(), + Config::default(), + ("#[\n|]#", "i(", "(#[|)]#\n"), + )?; + + test_key_sequence_text_result( + Args::default(), + Config { + editor: helix_view::editor::Config { + auto_pairs: AutoPairConfig::Enable(false), + ..Default::default() + }, + ..Default::default() + }, + ("#[\n|]#", "i(", "(#[|\n]#"), + )?; + + Ok(()) +} diff --git a/helix-term/tests/integration/movement.rs b/helix-term/tests/integration/movement.rs new file mode 100644 index 000000000..d2e01e71c --- /dev/null +++ b/helix-term/tests/integration/movement.rs @@ -0,0 +1,96 @@ +use super::*; + +#[tokio::test] +async fn insert_mode_cursor_position() -> anyhow::Result<()> { + test_key_sequence_text_result( + Args::default(), + Config::default(), + TestCase { + in_text: String::new(), + in_selection: Selection::single(0, 0), + in_keys: "i".into(), + out_text: String::new(), + out_selection: Selection::single(0, 0), + }, + )?; + + test_key_sequence_text_result( + Args::default(), + Config::default(), + ("#[\n|]#", "i", "#[|\n]#"), + )?; + + test_key_sequence_text_result( + Args::default(), + Config::default(), + ("#[\n|]#", "i", "#[|\n]#"), + )?; + + test_key_sequence_text_result( + Args::default(), + Config::default(), + ("#[\n|]#", "ii", "#[|\n]#"), + )?; + + Ok(()) +} + +/// Range direction is preserved when escaping insert mode to normal +#[tokio::test] +async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { + test_key_sequence_text_result( + Args::default(), + Config::default(), + ("#[f|]#oo\n", "vll", "#[|foo]#\n"), + )?; + + test_key_sequence_text_result( + Args::default(), + Config::default(), + ( + indoc! {"\ + #[f|]#oo + #(b|)#ar" + }, + "vll", + indoc! {"\ + #[|foo]# + #(|bar)#" + }, + ), + )?; + + test_key_sequence_text_result( + Args::default(), + Config::default(), + ( + indoc! {"\ + #[f|]#oo + #(b|)#ar" + }, + "a", + indoc! {"\ + #[fo|]#o + #(ba|)#r" + }, + ), + )?; + + test_key_sequence_text_result( + Args::default(), + Config::default(), + ( + indoc! {"\ + #[f|]#oo + #(b|)#ar" + }, + "a", + indoc! {"\ + #[f|]#oo + #(b|)#ar" + }, + ), + )?; + + Ok(()) +} From 36e5809f638028644d8a51e1ed2467ea402de170 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Sun, 17 Apr 2022 21:04:59 -0400 Subject: [PATCH 332/861] add test for ensuring the initial cursor on a newly opened file --- Cargo.lock | 42 ++++++++++++++++++++++++ helix-term/Cargo.toml | 1 + helix-term/tests/integration.rs | 1 + helix-term/tests/integration/helpers.rs | 13 ++++++++ helix-term/tests/integration/movement.rs | 30 +++++++++++++++++ 5 files changed, 87 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 39afd1414..6b49f722f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -221,6 +221,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + [[package]] name = "fern" version = "0.6.1" @@ -462,6 +471,7 @@ dependencies = [ "signal-hook", "signal-hook-tokio", "smallvec", + "tempfile", "tokio", "tokio-stream", "toml", @@ -555,6 +565,15 @@ dependencies = [ "unindent", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "itoa" version = "1.0.1" @@ -852,6 +871,15 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "retain_mut" version = "0.1.7" @@ -1056,6 +1084,20 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + [[package]] name = "textwrap" version = "0.15.0" diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 05f8eed4c..f1903f04b 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -78,3 +78,4 @@ helix-loader = { version = "0.6", path = "../helix-loader" } [dev-dependencies] smallvec = "1.8" indoc = "1.0.3" +tempfile = "3.3.0" diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs index a388cf6bf..4b0a2346e 100644 --- a/helix-term/tests/integration.rs +++ b/helix-term/tests/integration.rs @@ -25,4 +25,5 @@ mod integration { mod auto_indent; mod auto_pairs; mod movement; + mod write; } diff --git a/helix-term/tests/integration/helpers.rs b/helix-term/tests/integration/helpers.rs index d22bcc3ce..5a853ad1b 100644 --- a/helix-term/tests/integration/helpers.rs +++ b/helix-term/tests/integration/helpers.rs @@ -1,3 +1,5 @@ +use std::io::Write; + use crossterm::event::{Event, KeyEvent}; use helix_core::{test, Selection, Transaction}; use helix_term::{application::Application, args::Args, config::Config}; @@ -85,3 +87,14 @@ pub fn test_key_sequence_text_result>( Ok(()) } + +pub fn temp_file_with_contents>(content: S) -> tempfile::NamedTempFile { + let mut temp_file = tempfile::NamedTempFile::new().unwrap(); + temp_file + .as_file_mut() + .write_all(content.as_ref().as_bytes()) + .unwrap(); + temp_file.flush().unwrap(); + temp_file.as_file_mut().sync_all().unwrap(); + temp_file +} diff --git a/helix-term/tests/integration/movement.rs b/helix-term/tests/integration/movement.rs index d2e01e71c..fc2583c16 100644 --- a/helix-term/tests/integration/movement.rs +++ b/helix-term/tests/integration/movement.rs @@ -1,3 +1,5 @@ +use helix_term::application::Application; + use super::*; #[tokio::test] @@ -94,3 +96,31 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { Ok(()) } + +/// Ensure the very initial cursor in an opened file is the width of +/// the first grapheme +#[tokio::test] +async fn cursor_position_newly_opened_file() -> anyhow::Result<()> { + let test = |content: &str, expected_sel: Selection| { + let file = helpers::temp_file_with_contents(content); + + let mut app = Application::new( + Args { + files: vec![(file.path().to_path_buf(), Position::default())], + ..Default::default() + }, + Config::default(), + ) + .unwrap(); + + let (view, doc) = helix_view::current!(app.editor); + let sel = doc.selection(view.id).clone(); + assert_eq!(expected_sel, sel); + }; + + test("foo", Selection::single(0, 1)); + test("👨‍👩‍👧‍👦 foo", Selection::single(0, 7)); + test("", Selection::single(0, 0)); + + Ok(()) +} From ee705dcb3363aeb197f6125ab2f8285782333010 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Tue, 19 Apr 2022 01:21:31 -0400 Subject: [PATCH 333/861] use main application event loop Use the Application's main event loop to allow LSP, file writes, etc --- helix-core/src/auto_pairs.rs | 15 ++--- helix-term/src/application.rs | 30 ++++++--- helix-term/src/job.rs | 1 + helix-term/src/main.rs | 3 +- helix-term/tests/integration.rs | 3 +- helix-term/tests/integration/auto_indent.rs | 3 +- helix-term/tests/integration/auto_pairs.rs | 6 +- helix-term/tests/integration/helpers.rs | 64 +++++++++++++------ helix-term/tests/integration/movement.rs | 24 ++++--- helix-term/tests/integration/write.rs | 69 +++++++++++++++++++++ 10 files changed, 169 insertions(+), 49 deletions(-) create mode 100644 helix-term/tests/integration/write.rs diff --git a/helix-core/src/auto_pairs.rs b/helix-core/src/auto_pairs.rs index 1131178e3..ff680a771 100644 --- a/helix-core/src/auto_pairs.rs +++ b/helix-core/src/auto_pairs.rs @@ -4,7 +4,6 @@ use crate::{graphemes, movement::Direction, Range, Rope, Selection, Tendril, Transaction}; use std::collections::HashMap; -use log::debug; use smallvec::SmallVec; // Heavily based on https://github.com/codemirror/closebrackets/ @@ -123,7 +122,7 @@ impl Default for AutoPairs { #[must_use] pub fn hook(doc: &Rope, selection: &Selection, ch: char, pairs: &AutoPairs) -> Option { - debug!("autopairs hook selection: {:#?}", selection); + log::trace!("autopairs hook selection: {:#?}", selection); if let Some(pair) = pairs.get(ch) { if pair.same() { @@ -225,9 +224,11 @@ fn get_next_range( // other end of the grapheme to get to where the new characters // are inserted, then move the head to where it should be let prev_bound = graphemes::prev_grapheme_boundary(doc_slice, start_range.head); - debug!( + log::trace!( "prev_bound: {}, offset: {}, len_inserted: {}", - prev_bound, offset, len_inserted + prev_bound, + offset, + len_inserted ); prev_bound + offset + len_inserted }; @@ -302,7 +303,7 @@ fn handle_open(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction { }); let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index())); - debug!("auto pair transaction: {:#?}", t); + log::debug!("auto pair transaction: {:#?}", t); t } @@ -334,7 +335,7 @@ fn handle_close(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction { }); let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index())); - debug!("auto pair transaction: {:#?}", t); + log::debug!("auto pair transaction: {:#?}", t); t } @@ -374,7 +375,7 @@ fn handle_same(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction { }); let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index())); - debug!("auto pair transaction: {:#?}", t); + log::debug!("auto pair transaction: {:#?}", t); t } diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 44025ea02..15026bb64 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -1,4 +1,5 @@ use arc_swap::{access::Map, ArcSwap}; +use futures_util::Stream; use helix_core::{ config::{default_syntax_loader, user_syntax_loader}, pos_at_coords, syntax, Selection, @@ -27,7 +28,7 @@ use std::{ use anyhow::Error; use crossterm::{ - event::{DisableMouseCapture, EnableMouseCapture, Event, EventStream}, + event::{DisableMouseCapture, EnableMouseCapture, Event}, execute, terminal, tty::IsTty, }; @@ -68,7 +69,7 @@ fn setup_integration_logging() { message )) }) - .level(log::LevelFilter::Info) + .level(log::LevelFilter::Debug) .chain(std::io::stdout()) .apply(); } @@ -225,8 +226,10 @@ impl Application { } } - pub async fn event_loop(&mut self) { - let mut reader = EventStream::new(); + pub async fn event_loop(&mut self, input_stream: &mut S) + where + S: Stream> + Unpin, + { let mut last_render = Instant::now(); let deadline = Duration::from_secs(1) / 60; @@ -242,7 +245,7 @@ impl Application { tokio::select! { biased; - Some(event) = reader.next() => { + Some(event) = input_stream.next() => { self.handle_terminal_events(event) } Some(signal) = self.signals.next() => { @@ -749,7 +752,10 @@ impl Application { Ok(()) } - pub async fn run(&mut self) -> Result { + pub async fn run(&mut self, input_stream: &mut S) -> Result + where + S: Stream> + Unpin, + { self.claim_term().await?; // Exit the alternate screen and disable raw mode before panicking @@ -764,16 +770,20 @@ impl Application { hook(info); })); - self.event_loop().await; + self.event_loop(input_stream).await; + self.close().await?; + self.restore_term()?; + + Ok(self.editor.exit_code) + } + pub async fn close(&mut self) -> anyhow::Result<()> { self.jobs.finish().await; if self.editor.close_language_servers(None).await.is_err() { log::error!("Timed out waiting for language servers to shutdown"); }; - self.restore_term()?; - - Ok(self.editor.exit_code) + Ok(()) } } diff --git a/helix-term/src/job.rs b/helix-term/src/job.rs index a6a770211..d21099f73 100644 --- a/helix-term/src/job.rs +++ b/helix-term/src/job.rs @@ -95,6 +95,7 @@ impl Jobs { /// Blocks until all the jobs that need to be waited on are done. pub async fn finish(&mut self) { let wait_futures = std::mem::take(&mut self.wait_futures); + log::debug!("waiting on jobs..."); wait_futures.for_each(|_| future::ready(())).await } } diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index cd0b364be..7b26fb119 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -1,4 +1,5 @@ use anyhow::{Context, Error, Result}; +use crossterm::event::EventStream; use helix_term::application::Application; use helix_term::args::Args; use helix_term::config::Config; @@ -134,7 +135,7 @@ FLAGS: // TODO: use the thread local executor to spawn the application task separately from the work pool let mut app = Application::new(args, config).context("unable to create new application")?; - let exit_code = app.run().await?; + let exit_code = app.run(&mut EventStream::new()).await?; Ok(exit_code) } diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs index 4b0a2346e..b2b78e632 100644 --- a/helix-term/tests/integration.rs +++ b/helix-term/tests/integration.rs @@ -17,7 +17,8 @@ mod integration { Args::default(), Config::default(), ("#[\n|]#", "ihello world", "hello world#[|\n]#"), - )?; + ) + .await?; Ok(()) } diff --git a/helix-term/tests/integration/auto_indent.rs b/helix-term/tests/integration/auto_indent.rs index 18138ccaf..74d1ac587 100644 --- a/helix-term/tests/integration/auto_indent.rs +++ b/helix-term/tests/integration/auto_indent.rs @@ -18,7 +18,8 @@ async fn auto_indent_c() -> anyhow::Result<()> { } "}, ), - )?; + ) + .await?; Ok(()) } diff --git a/helix-term/tests/integration/auto_pairs.rs b/helix-term/tests/integration/auto_pairs.rs index 4da44d45e..52fee55e5 100644 --- a/helix-term/tests/integration/auto_pairs.rs +++ b/helix-term/tests/integration/auto_pairs.rs @@ -6,7 +6,8 @@ async fn auto_pairs_basic() -> anyhow::Result<()> { Args::default(), Config::default(), ("#[\n|]#", "i(", "(#[|)]#\n"), - )?; + ) + .await?; test_key_sequence_text_result( Args::default(), @@ -18,7 +19,8 @@ async fn auto_pairs_basic() -> anyhow::Result<()> { ..Default::default() }, ("#[\n|]#", "i(", "(#[|\n]#"), - )?; + ) + .await?; Ok(()) } diff --git a/helix-term/tests/integration/helpers.rs b/helix-term/tests/integration/helpers.rs index 5a853ad1b..df662f07d 100644 --- a/helix-term/tests/integration/helpers.rs +++ b/helix-term/tests/integration/helpers.rs @@ -1,9 +1,12 @@ -use std::io::Write; +use std::{io::Write, time::Duration}; +use anyhow::bail; use crossterm::event::{Event, KeyEvent}; use helix_core::{test, Selection, Transaction}; use helix_term::{application::Application, args::Args, config::Config}; use helix_view::{doc, input::parse_macro}; +use tokio::time::timeout; +use tokio_stream::wrappers::UnboundedReceiverStream; #[derive(Clone, Debug)] pub struct TestCase { @@ -29,10 +32,44 @@ impl> From<(S, S, S)> for TestCase { } } -pub fn test_key_sequence>( +pub async fn test_key_sequence( + app: &mut Application, + in_keys: &str, + test_fn: Option<&dyn Fn(&Application)>, +) -> anyhow::Result<()> { + let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); + + for key_event in parse_macro(&in_keys)?.into_iter() { + tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?; + } + + let mut rx_stream = UnboundedReceiverStream::new(rx); + let event_loop = app.event_loop(&mut rx_stream); + let result = timeout(Duration::from_millis(500), event_loop).await; + + if result.is_ok() { + bail!("application exited before test function could run"); + } + + if let Some(test) = test_fn { + test(app); + }; + + for key_event in parse_macro(":q!")?.into_iter() { + tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?; + } + + let event_loop = app.event_loop(&mut rx_stream); + timeout(Duration::from_millis(5000), event_loop).await?; + app.close().await?; + + Ok(()) +} + +pub async fn test_key_sequence_with_input_text>( app: Option, test_case: T, - test_fn: &dyn Fn(&mut Application), + test_fn: &dyn Fn(&Application), ) -> anyhow::Result<()> { let test_case = test_case.into(); let mut app = @@ -50,23 +87,13 @@ pub fn test_key_sequence>( view.id, ); - let input_keys = parse_macro(&test_case.in_keys)? - .into_iter() - .map(|key_event| Event::Key(KeyEvent::from(key_event))); - - for key in input_keys { - app.handle_terminal_events(Ok(key)); - } - - test_fn(&mut app); - - Ok(()) + test_key_sequence(&mut app, &test_case.in_keys, Some(test_fn)).await } /// Use this for very simple test cases where there is one input /// document, selection, and sequence of key presses, and you just /// want to verify the resulting document and selection. -pub fn test_key_sequence_text_result>( +pub async fn test_key_sequence_text_result>( args: Args, config: Config, test_case: T, @@ -74,7 +101,7 @@ pub fn test_key_sequence_text_result>( let test_case = test_case.into(); let app = Application::new(args, config).unwrap(); - test_key_sequence(Some(app), test_case.clone(), &|app| { + test_key_sequence_with_input_text(Some(app), test_case.clone(), &|app| { let doc = doc!(app.editor); assert_eq!(&test_case.out_text, doc.text()); @@ -83,9 +110,8 @@ pub fn test_key_sequence_text_result>( let sel = selections.pop().unwrap(); assert_eq!(test_case.out_selection, sel); - })?; - - Ok(()) + }) + .await } pub fn temp_file_with_contents>(content: S) -> tempfile::NamedTempFile { diff --git a/helix-term/tests/integration/movement.rs b/helix-term/tests/integration/movement.rs index fc2583c16..cac108522 100644 --- a/helix-term/tests/integration/movement.rs +++ b/helix-term/tests/integration/movement.rs @@ -14,25 +14,29 @@ async fn insert_mode_cursor_position() -> anyhow::Result<()> { out_text: String::new(), out_selection: Selection::single(0, 0), }, - )?; + ) + .await?; test_key_sequence_text_result( Args::default(), Config::default(), ("#[\n|]#", "i", "#[|\n]#"), - )?; + ) + .await?; test_key_sequence_text_result( Args::default(), Config::default(), ("#[\n|]#", "i", "#[|\n]#"), - )?; + ) + .await?; test_key_sequence_text_result( Args::default(), Config::default(), ("#[\n|]#", "ii", "#[|\n]#"), - )?; + ) + .await?; Ok(()) } @@ -44,7 +48,8 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { Args::default(), Config::default(), ("#[f|]#oo\n", "vll", "#[|foo]#\n"), - )?; + ) + .await?; test_key_sequence_text_result( Args::default(), @@ -60,7 +65,8 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { #(|bar)#" }, ), - )?; + ) + .await?; test_key_sequence_text_result( Args::default(), @@ -76,7 +82,8 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { #(ba|)#r" }, ), - )?; + ) + .await?; test_key_sequence_text_result( Args::default(), @@ -92,7 +99,8 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { #(b|)#ar" }, ), - )?; + ) + .await?; Ok(()) } diff --git a/helix-term/tests/integration/write.rs b/helix-term/tests/integration/write.rs new file mode 100644 index 000000000..47e562887 --- /dev/null +++ b/helix-term/tests/integration/write.rs @@ -0,0 +1,69 @@ +use std::{ + io::{Read, Write}, + ops::RangeInclusive, +}; + +use helix_term::application::Application; + +use super::*; + +#[tokio::test] +async fn test_write() -> anyhow::Result<()> { + let mut file = tempfile::NamedTempFile::new().unwrap(); + + test_key_sequence( + &mut Application::new( + Args { + files: vec![(file.path().to_path_buf(), Position::default())], + ..Default::default() + }, + Config::default(), + )?, + "ii can eat glass, it will not hurt me:w", + None, + ) + .await?; + + file.as_file_mut().flush()?; + file.as_file_mut().sync_all()?; + + let mut file_content = String::new(); + file.as_file_mut().read_to_string(&mut file_content)?; + assert_eq!("i can eat glass, it will not hurt me\n", file_content); + + Ok(()) +} + +#[tokio::test] +async fn test_write_concurrent() -> anyhow::Result<()> { + let mut file = tempfile::NamedTempFile::new().unwrap(); + let mut command = String::new(); + const RANGE: RangeInclusive = 1..=1000; + + for i in RANGE { + let cmd = format!("%c{}:w", i); + command.push_str(&cmd); + } + + test_key_sequence( + &mut Application::new( + Args { + files: vec![(file.path().to_path_buf(), Position::default())], + ..Default::default() + }, + Config::default(), + )?, + &command, + None, + ) + .await?; + + file.as_file_mut().flush()?; + file.as_file_mut().sync_all()?; + + let mut file_content = String::new(); + file.as_file_mut().read_to_string(&mut file_content)?; + assert_eq!(RANGE.end().to_string(), file_content); + + Ok(()) +} From 07fc80aece221233b4a986b0c5a03e2056cc1307 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Sat, 30 Apr 2022 20:44:54 -0400 Subject: [PATCH 334/861] tests for serialized writes --- helix-term/tests/integration.rs | 2 + helix-term/tests/integration/auto_indent.rs | 1 + helix-term/tests/integration/auto_pairs.rs | 2 + helix-term/tests/integration/commands.rs | 25 +++++++ helix-term/tests/integration/helpers.rs | 69 +++++++++++------- helix-term/tests/integration/movement.rs | 8 +++ helix-term/tests/integration/write.rs | 79 ++++++++++++++++----- helix-view/src/editor.rs | 5 ++ 8 files changed, 147 insertions(+), 44 deletions(-) create mode 100644 helix-term/tests/integration/commands.rs diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs index b2b78e632..54364e12f 100644 --- a/helix-term/tests/integration.rs +++ b/helix-term/tests/integration.rs @@ -17,6 +17,7 @@ mod integration { Args::default(), Config::default(), ("#[\n|]#", "ihello world", "hello world#[|\n]#"), + None, ) .await?; @@ -25,6 +26,7 @@ mod integration { mod auto_indent; mod auto_pairs; + mod commands; mod movement; mod write; } diff --git a/helix-term/tests/integration/auto_indent.rs b/helix-term/tests/integration/auto_indent.rs index 74d1ac587..fdfc7dfb5 100644 --- a/helix-term/tests/integration/auto_indent.rs +++ b/helix-term/tests/integration/auto_indent.rs @@ -18,6 +18,7 @@ async fn auto_indent_c() -> anyhow::Result<()> { } "}, ), + None, ) .await?; diff --git a/helix-term/tests/integration/auto_pairs.rs b/helix-term/tests/integration/auto_pairs.rs index 52fee55e5..d34cd0fd9 100644 --- a/helix-term/tests/integration/auto_pairs.rs +++ b/helix-term/tests/integration/auto_pairs.rs @@ -6,6 +6,7 @@ async fn auto_pairs_basic() -> anyhow::Result<()> { Args::default(), Config::default(), ("#[\n|]#", "i(", "(#[|)]#\n"), + None, ) .await?; @@ -19,6 +20,7 @@ async fn auto_pairs_basic() -> anyhow::Result<()> { ..Default::default() }, ("#[\n|]#", "i(", "(#[|\n]#"), + None, ) .await?; diff --git a/helix-term/tests/integration/commands.rs b/helix-term/tests/integration/commands.rs new file mode 100644 index 000000000..ec60ac968 --- /dev/null +++ b/helix-term/tests/integration/commands.rs @@ -0,0 +1,25 @@ +use helix_core::diagnostic::Severity; +use helix_term::application::Application; + +use super::*; + +#[tokio::test] +async fn test_write_quit_fail() -> anyhow::Result<()> { + test_key_sequence( + &mut Application::new( + Args { + files: vec![(PathBuf::from("/foo"), Position::default())], + ..Default::default() + }, + Config::default(), + )?, + "ihello:wq", + Some(&|app| { + assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); + }), + None, + ) + .await?; + + Ok(()) +} diff --git a/helix-term/tests/integration/helpers.rs b/helix-term/tests/integration/helpers.rs index df662f07d..60bfa3318 100644 --- a/helix-term/tests/integration/helpers.rs +++ b/helix-term/tests/integration/helpers.rs @@ -5,7 +5,6 @@ use crossterm::event::{Event, KeyEvent}; use helix_core::{test, Selection, Transaction}; use helix_term::{application::Application, args::Args, config::Config}; use helix_view::{doc, input::parse_macro}; -use tokio::time::timeout; use tokio_stream::wrappers::UnboundedReceiverStream; #[derive(Clone, Debug)] @@ -32,35 +31,48 @@ impl> From<(S, S, S)> for TestCase { } } +#[inline] pub async fn test_key_sequence( app: &mut Application, in_keys: &str, test_fn: Option<&dyn Fn(&Application)>, + timeout: Option, ) -> anyhow::Result<()> { + test_key_sequences(app, vec![(in_keys, test_fn)], timeout).await +} + +pub async fn test_key_sequences( + app: &mut Application, + inputs: Vec<(&str, Option<&dyn Fn(&Application)>)>, + timeout: Option, +) -> anyhow::Result<()> { + let timeout = timeout.unwrap_or(Duration::from_millis(500)); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); + let mut rx_stream = UnboundedReceiverStream::new(rx); - for key_event in parse_macro(&in_keys)?.into_iter() { - tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?; - } + for (in_keys, test_fn) in inputs { + for key_event in parse_macro(&in_keys)?.into_iter() { + tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?; + } - let mut rx_stream = UnboundedReceiverStream::new(rx); - let event_loop = app.event_loop(&mut rx_stream); - let result = timeout(Duration::from_millis(500), event_loop).await; + let event_loop = app.event_loop(&mut rx_stream); + let result = tokio::time::timeout(timeout, event_loop).await; - if result.is_ok() { - bail!("application exited before test function could run"); - } + if result.is_ok() { + bail!("application exited before test function could run"); + } - if let Some(test) = test_fn { - test(app); - }; + if let Some(test) = test_fn { + test(app); + }; + } for key_event in parse_macro(":q!")?.into_iter() { tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?; } let event_loop = app.event_loop(&mut rx_stream); - timeout(Duration::from_millis(5000), event_loop).await?; + tokio::time::timeout(timeout, event_loop).await?; app.close().await?; Ok(()) @@ -70,6 +82,7 @@ pub async fn test_key_sequence_with_input_text>( app: Option, test_case: T, test_fn: &dyn Fn(&Application), + timeout: Option, ) -> anyhow::Result<()> { let test_case = test_case.into(); let mut app = @@ -87,7 +100,7 @@ pub async fn test_key_sequence_with_input_text>( view.id, ); - test_key_sequence(&mut app, &test_case.in_keys, Some(test_fn)).await + test_key_sequence(&mut app, &test_case.in_keys, Some(test_fn), timeout).await } /// Use this for very simple test cases where there is one input @@ -97,20 +110,26 @@ pub async fn test_key_sequence_text_result>( args: Args, config: Config, test_case: T, + timeout: Option, ) -> anyhow::Result<()> { let test_case = test_case.into(); let app = Application::new(args, config).unwrap(); - test_key_sequence_with_input_text(Some(app), test_case.clone(), &|app| { - let doc = doc!(app.editor); - assert_eq!(&test_case.out_text, doc.text()); - - let mut selections: Vec<_> = doc.selections().values().cloned().collect(); - assert_eq!(1, selections.len()); - - let sel = selections.pop().unwrap(); - assert_eq!(test_case.out_selection, sel); - }) + test_key_sequence_with_input_text( + Some(app), + test_case.clone(), + &|app| { + let doc = doc!(app.editor); + assert_eq!(&test_case.out_text, doc.text()); + + let mut selections: Vec<_> = doc.selections().values().cloned().collect(); + assert_eq!(1, selections.len()); + + let sel = selections.pop().unwrap(); + assert_eq!(test_case.out_selection, sel); + }, + timeout, + ) .await } diff --git a/helix-term/tests/integration/movement.rs b/helix-term/tests/integration/movement.rs index cac108522..a1d294c6c 100644 --- a/helix-term/tests/integration/movement.rs +++ b/helix-term/tests/integration/movement.rs @@ -14,6 +14,7 @@ async fn insert_mode_cursor_position() -> anyhow::Result<()> { out_text: String::new(), out_selection: Selection::single(0, 0), }, + None, ) .await?; @@ -21,6 +22,7 @@ async fn insert_mode_cursor_position() -> anyhow::Result<()> { Args::default(), Config::default(), ("#[\n|]#", "i", "#[|\n]#"), + None, ) .await?; @@ -28,6 +30,7 @@ async fn insert_mode_cursor_position() -> anyhow::Result<()> { Args::default(), Config::default(), ("#[\n|]#", "i", "#[|\n]#"), + None, ) .await?; @@ -35,6 +38,7 @@ async fn insert_mode_cursor_position() -> anyhow::Result<()> { Args::default(), Config::default(), ("#[\n|]#", "ii", "#[|\n]#"), + None, ) .await?; @@ -48,6 +52,7 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { Args::default(), Config::default(), ("#[f|]#oo\n", "vll", "#[|foo]#\n"), + None, ) .await?; @@ -65,6 +70,7 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { #(|bar)#" }, ), + None, ) .await?; @@ -82,6 +88,7 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { #(ba|)#r" }, ), + None, ) .await?; @@ -99,6 +106,7 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { #(b|)#ar" }, ), + None, ) .await?; diff --git a/helix-term/tests/integration/write.rs b/helix-term/tests/integration/write.rs index 47e562887..27f97a452 100644 --- a/helix-term/tests/integration/write.rs +++ b/helix-term/tests/integration/write.rs @@ -1,9 +1,11 @@ use std::{ io::{Read, Write}, - ops::RangeInclusive, + time::Duration, }; +use helix_core::diagnostic::Severity; use helix_term::application::Application; +use helix_view::doc; use super::*; @@ -21,6 +23,7 @@ async fn test_write() -> anyhow::Result<()> { )?, "ii can eat glass, it will not hurt me:w", None, + Some(Duration::from_millis(1000)), ) .await?; @@ -35,35 +38,73 @@ async fn test_write() -> anyhow::Result<()> { } #[tokio::test] -async fn test_write_concurrent() -> anyhow::Result<()> { - let mut file = tempfile::NamedTempFile::new().unwrap(); - let mut command = String::new(); - const RANGE: RangeInclusive = 1..=1000; - - for i in RANGE { - let cmd = format!("%c{}:w", i); - command.push_str(&cmd); - } - - test_key_sequence( +async fn test_write_fail_mod_flag() -> anyhow::Result<()> { + test_key_sequences( &mut Application::new( Args { - files: vec![(file.path().to_path_buf(), Position::default())], + files: vec![(PathBuf::from("/foo"), Position::default())], ..Default::default() }, Config::default(), )?, - &command, + vec![ + ( + "", + Some(&|app| { + let doc = doc!(app.editor); + assert!(!doc.is_modified()); + }), + ), + ( + "ihello", + Some(&|app| { + let doc = doc!(app.editor); + assert!(doc.is_modified()); + }), + ), + ( + ":w", + Some(&|app| { + assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); + + let doc = doc!(app.editor); + assert!(doc.is_modified()); + }), + ), + ], None, ) .await?; - file.as_file_mut().flush()?; - file.as_file_mut().sync_all()?; + Ok(()) +} - let mut file_content = String::new(); - file.as_file_mut().read_to_string(&mut file_content)?; - assert_eq!(RANGE.end().to_string(), file_content); +#[tokio::test] +#[ignore] +async fn test_write_fail_new_path() -> anyhow::Result<()> { + test_key_sequences( + &mut Application::new(Args::default(), Config::default())?, + vec![ + ( + "", + Some(&|app| { + let doc = doc!(app.editor); + assert_eq!(None, app.editor.get_status()); + assert_eq!(None, doc.path()); + }), + ), + ( + ":w /foo", + Some(&|app| { + let doc = doc!(app.editor); + assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); + assert_eq!(None, doc.path()); + }), + ), + ], + Some(Duration::from_millis(1000)), + ) + .await?; Ok(()) } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 8607c65a2..d828f9ec3 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -571,6 +571,11 @@ impl Editor { self.status_msg = Some((error.into(), Severity::Error)); } + #[inline] + pub fn get_status(&self) -> Option<(&Cow<'static, str>, &Severity)> { + self.status_msg.as_ref().map(|(status, sev)| (status, sev)) + } + pub fn set_theme(&mut self, theme: Theme) { // `ui.selection` is the only scope required to be able to render a theme. if theme.find_scope_index("ui.selection").is_none() { From 40120967e9ba48d2e8b5fb4976a6ca1ce8993704 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Sat, 30 Apr 2022 20:47:53 -0400 Subject: [PATCH 335/861] tests for buffer-close --- helix-term/tests/integration/commands.rs | 80 +++++++++++++++++++++++- helix-term/tests/integration/helpers.rs | 12 ++-- helix-term/tests/integration/write.rs | 48 ++++++++++++-- helix-view/src/editor.rs | 9 +++ 4 files changed, 137 insertions(+), 12 deletions(-) diff --git a/helix-term/tests/integration/commands.rs b/helix-term/tests/integration/commands.rs index ec60ac968..7da180b94 100644 --- a/helix-term/tests/integration/commands.rs +++ b/helix-term/tests/integration/commands.rs @@ -1,3 +1,9 @@ +use std::{ + io::{Read, Write}, + ops::RangeInclusive, + time::Duration, +}; + use helix_core::diagnostic::Severity; use helix_term::application::Application; @@ -13,7 +19,7 @@ async fn test_write_quit_fail() -> anyhow::Result<()> { }, Config::default(), )?, - "ihello:wq", + Some("ihello:wq"), Some(&|app| { assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); }), @@ -23,3 +29,75 @@ async fn test_write_quit_fail() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test] +async fn test_buffer_close() -> anyhow::Result<()> { + test_key_sequences( + &mut Application::new(Args::default(), Config::default())?, + vec![ + ( + None, + Some(&|app| { + assert_eq!(1, app.editor.documents().count()); + assert!(!app.editor.is_err()); + }), + ), + ( + Some("ihello:new"), + Some(&|app| { + assert_eq!(2, app.editor.documents().count()); + assert!(!app.editor.is_err()); + }), + ), + ( + Some(":bufferclose"), + Some(&|app| { + assert_eq!(1, app.editor.documents().count()); + assert!(!app.editor.is_err()); + }), + ), + ], + None, + ) + .await?; + + // verify if writes are queued up, it finishes them before closing the buffer + let mut file = tempfile::NamedTempFile::new().unwrap(); + let mut command = String::new(); + const RANGE: RangeInclusive = 1..=10; + + for i in RANGE { + let cmd = format!("%c{}:w", i); + command.push_str(&cmd); + } + + command.push_str(":bufferclose"); + + test_key_sequence( + &mut Application::new( + Args { + files: vec![(file.path().to_path_buf(), Position::default())], + ..Default::default() + }, + Config::default(), + )?, + Some(&command), + Some(&|app| { + assert!(!app.editor.is_err(), "error: {:?}", app.editor.get_status()); + + let doc = app.editor.document_by_path(file.path()); + assert!(doc.is_none(), "found doc: {:?}", doc); + }), + Some(Duration::from_millis(5000)), + ) + .await?; + + file.as_file_mut().flush()?; + file.as_file_mut().sync_all()?; + + let mut file_content = String::new(); + file.as_file_mut().read_to_string(&mut file_content)?; + assert_eq!(RANGE.end().to_string(), file_content); + + Ok(()) +} diff --git a/helix-term/tests/integration/helpers.rs b/helix-term/tests/integration/helpers.rs index 60bfa3318..18a3517cf 100644 --- a/helix-term/tests/integration/helpers.rs +++ b/helix-term/tests/integration/helpers.rs @@ -34,7 +34,7 @@ impl> From<(S, S, S)> for TestCase { #[inline] pub async fn test_key_sequence( app: &mut Application, - in_keys: &str, + in_keys: Option<&str>, test_fn: Option<&dyn Fn(&Application)>, timeout: Option, ) -> anyhow::Result<()> { @@ -43,7 +43,7 @@ pub async fn test_key_sequence( pub async fn test_key_sequences( app: &mut Application, - inputs: Vec<(&str, Option<&dyn Fn(&Application)>)>, + inputs: Vec<(Option<&str>, Option<&dyn Fn(&Application)>)>, timeout: Option, ) -> anyhow::Result<()> { let timeout = timeout.unwrap_or(Duration::from_millis(500)); @@ -51,8 +51,10 @@ pub async fn test_key_sequences( let mut rx_stream = UnboundedReceiverStream::new(rx); for (in_keys, test_fn) in inputs { - for key_event in parse_macro(&in_keys)?.into_iter() { - tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?; + if let Some(in_keys) = in_keys { + for key_event in parse_macro(&in_keys)?.into_iter() { + tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?; + } } let event_loop = app.event_loop(&mut rx_stream); @@ -100,7 +102,7 @@ pub async fn test_key_sequence_with_input_text>( view.id, ); - test_key_sequence(&mut app, &test_case.in_keys, Some(test_fn), timeout).await + test_key_sequence(&mut app, Some(&test_case.in_keys), Some(test_fn), timeout).await } /// Use this for very simple test cases where there is one input diff --git a/helix-term/tests/integration/write.rs b/helix-term/tests/integration/write.rs index 27f97a452..365e6b8d8 100644 --- a/helix-term/tests/integration/write.rs +++ b/helix-term/tests/integration/write.rs @@ -1,5 +1,6 @@ use std::{ io::{Read, Write}, + ops::RangeInclusive, time::Duration, }; @@ -21,7 +22,7 @@ async fn test_write() -> anyhow::Result<()> { }, Config::default(), )?, - "ii can eat glass, it will not hurt me:w", + Some("ii can eat glass, it will not hurt me:w"), None, Some(Duration::from_millis(1000)), ) @@ -37,6 +38,41 @@ async fn test_write() -> anyhow::Result<()> { Ok(()) } +#[tokio::test] +async fn test_write_concurrent() -> anyhow::Result<()> { + let mut file = tempfile::NamedTempFile::new().unwrap(); + let mut command = String::new(); + const RANGE: RangeInclusive = 1..=5000; + + for i in RANGE { + let cmd = format!("%c{}:w", i); + command.push_str(&cmd); + } + + test_key_sequence( + &mut Application::new( + Args { + files: vec![(file.path().to_path_buf(), Position::default())], + ..Default::default() + }, + Config::default(), + )?, + Some(&command), + None, + Some(Duration::from_millis(10000)), + ) + .await?; + + file.as_file_mut().flush()?; + file.as_file_mut().sync_all()?; + + let mut file_content = String::new(); + file.as_file_mut().read_to_string(&mut file_content)?; + assert_eq!(RANGE.end().to_string(), file_content); + + Ok(()) +} + #[tokio::test] async fn test_write_fail_mod_flag() -> anyhow::Result<()> { test_key_sequences( @@ -49,21 +85,21 @@ async fn test_write_fail_mod_flag() -> anyhow::Result<()> { )?, vec![ ( - "", + None, Some(&|app| { let doc = doc!(app.editor); assert!(!doc.is_modified()); }), ), ( - "ihello", + Some("ihello"), Some(&|app| { let doc = doc!(app.editor); assert!(doc.is_modified()); }), ), ( - ":w", + Some(":w"), Some(&|app| { assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); @@ -86,7 +122,7 @@ async fn test_write_fail_new_path() -> anyhow::Result<()> { &mut Application::new(Args::default(), Config::default())?, vec![ ( - "", + None, Some(&|app| { let doc = doc!(app.editor); assert_eq!(None, app.editor.get_status()); @@ -94,7 +130,7 @@ async fn test_write_fail_new_path() -> anyhow::Result<()> { }), ), ( - ":w /foo", + Some(":w /foo"), Some(&|app| { let doc = doc!(app.editor); assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index d828f9ec3..e8603221b 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -576,6 +576,15 @@ impl Editor { self.status_msg.as_ref().map(|(status, sev)| (status, sev)) } + /// Returns true if the current status is an error + #[inline] + pub fn is_err(&self) -> bool { + self.status_msg + .as_ref() + .map(|(_, sev)| *sev == Severity::Error) + .unwrap_or(false) + } + pub fn set_theme(&mut self, theme: Theme) { // `ui.selection` is the only scope required to be able to render a theme. if theme.find_scope_index("ui.selection").is_none() { From 2386c81ebc118860107094591b76ef3864e120a8 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Sat, 23 Apr 2022 21:49:31 -0400 Subject: [PATCH 336/861] use idle timer instead of fixed timeout --- helix-term/src/application.rs | 37 +++++++++++++++--- helix-term/tests/integration.rs | 1 - helix-term/tests/integration/auto_indent.rs | 1 - helix-term/tests/integration/auto_pairs.rs | 2 - helix-term/tests/integration/commands.rs | 4 -- helix-term/tests/integration/helpers.rs | 42 ++++++++------------- helix-term/tests/integration/movement.rs | 8 ---- helix-term/tests/integration/write.rs | 5 --- 8 files changed, 46 insertions(+), 54 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 15026bb64..3b96c45af 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -40,6 +40,8 @@ use { #[cfg(windows)] type Signals = futures_util::stream::Empty<()>; +const LSP_DEADLINE: Duration = Duration::from_millis(16); + pub struct Application { compositor: Compositor, pub editor: Editor, @@ -54,6 +56,7 @@ pub struct Application { signals: Signals, jobs: Jobs, lsp_progress: LspProgressMap, + last_render: Instant, } #[cfg(feature = "integration")] @@ -203,6 +206,7 @@ impl Application { signals, jobs: Jobs::new(), lsp_progress: LspProgressMap::new(), + last_render: Instant::now(), }; Ok(app) @@ -230,58 +234,79 @@ impl Application { where S: Stream> + Unpin, { - let mut last_render = Instant::now(); - let deadline = Duration::from_secs(1) / 60; - self.render(); + self.last_render = Instant::now(); loop { if self.editor.should_close() { break; } + self.event_loop_until_idle(input_stream).await; + } + } + + pub async fn event_loop_until_idle(&mut self, input_stream: &mut S) -> bool + where + S: Stream> + Unpin, + { + loop { + if self.editor.should_close() { + return false; + } + use futures_util::StreamExt; tokio::select! { biased; Some(event) = input_stream.next() => { - self.handle_terminal_events(event) + self.handle_terminal_events(event); + self.editor.reset_idle_timer(); } Some(signal) = self.signals.next() => { self.handle_signals(signal).await; + self.editor.reset_idle_timer(); } Some((id, call)) = self.editor.language_servers.incoming.next() => { self.handle_language_server_message(call, id).await; // limit render calls for fast language server messages let last = self.editor.language_servers.incoming.is_empty(); - if last || last_render.elapsed() > deadline { + + if last || self.last_render.elapsed() > LSP_DEADLINE { self.render(); - last_render = Instant::now(); + self.last_render = Instant::now(); } + + self.editor.reset_idle_timer(); } Some(payload) = self.editor.debugger_events.next() => { let needs_render = self.editor.handle_debugger_message(payload).await; if needs_render { self.render(); } + self.editor.reset_idle_timer(); } Some(config_event) = self.editor.config_events.1.recv() => { self.handle_config_events(config_event); self.render(); + self.editor.reset_idle_timer(); } Some(callback) = self.jobs.futures.next() => { self.jobs.handle_callback(&mut self.editor, &mut self.compositor, callback); self.render(); + self.editor.reset_idle_timer(); } Some(callback) = self.jobs.wait_futures.next() => { self.jobs.handle_callback(&mut self.editor, &mut self.compositor, callback); self.render(); + self.editor.reset_idle_timer(); } _ = &mut self.editor.idle_timer => { // idle timeout self.editor.clear_idle_timer(); self.handle_idle_timeout(); + return true; } } } diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs index 54364e12f..061bd8fff 100644 --- a/helix-term/tests/integration.rs +++ b/helix-term/tests/integration.rs @@ -17,7 +17,6 @@ mod integration { Args::default(), Config::default(), ("#[\n|]#", "ihello world", "hello world#[|\n]#"), - None, ) .await?; diff --git a/helix-term/tests/integration/auto_indent.rs b/helix-term/tests/integration/auto_indent.rs index fdfc7dfb5..74d1ac587 100644 --- a/helix-term/tests/integration/auto_indent.rs +++ b/helix-term/tests/integration/auto_indent.rs @@ -18,7 +18,6 @@ async fn auto_indent_c() -> anyhow::Result<()> { } "}, ), - None, ) .await?; diff --git a/helix-term/tests/integration/auto_pairs.rs b/helix-term/tests/integration/auto_pairs.rs index d34cd0fd9..52fee55e5 100644 --- a/helix-term/tests/integration/auto_pairs.rs +++ b/helix-term/tests/integration/auto_pairs.rs @@ -6,7 +6,6 @@ async fn auto_pairs_basic() -> anyhow::Result<()> { Args::default(), Config::default(), ("#[\n|]#", "i(", "(#[|)]#\n"), - None, ) .await?; @@ -20,7 +19,6 @@ async fn auto_pairs_basic() -> anyhow::Result<()> { ..Default::default() }, ("#[\n|]#", "i(", "(#[|\n]#"), - None, ) .await?; diff --git a/helix-term/tests/integration/commands.rs b/helix-term/tests/integration/commands.rs index 7da180b94..4ab87b9b5 100644 --- a/helix-term/tests/integration/commands.rs +++ b/helix-term/tests/integration/commands.rs @@ -1,7 +1,6 @@ use std::{ io::{Read, Write}, ops::RangeInclusive, - time::Duration, }; use helix_core::diagnostic::Severity; @@ -23,7 +22,6 @@ async fn test_write_quit_fail() -> anyhow::Result<()> { Some(&|app| { assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); }), - None, ) .await?; @@ -57,7 +55,6 @@ async fn test_buffer_close() -> anyhow::Result<()> { }), ), ], - None, ) .await?; @@ -88,7 +85,6 @@ async fn test_buffer_close() -> anyhow::Result<()> { let doc = app.editor.document_by_path(file.path()); assert!(doc.is_none(), "found doc: {:?}", doc); }), - Some(Duration::from_millis(5000)), ) .await?; diff --git a/helix-term/tests/integration/helpers.rs b/helix-term/tests/integration/helpers.rs index 18a3517cf..29cb8cd88 100644 --- a/helix-term/tests/integration/helpers.rs +++ b/helix-term/tests/integration/helpers.rs @@ -36,17 +36,15 @@ pub async fn test_key_sequence( app: &mut Application, in_keys: Option<&str>, test_fn: Option<&dyn Fn(&Application)>, - timeout: Option, ) -> anyhow::Result<()> { - test_key_sequences(app, vec![(in_keys, test_fn)], timeout).await + test_key_sequences(app, vec![(in_keys, test_fn)]).await } pub async fn test_key_sequences( app: &mut Application, inputs: Vec<(Option<&str>, Option<&dyn Fn(&Application)>)>, - timeout: Option, ) -> anyhow::Result<()> { - let timeout = timeout.unwrap_or(Duration::from_millis(500)); + const TIMEOUT: Duration = Duration::from_millis(500); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); let mut rx_stream = UnboundedReceiverStream::new(rx); @@ -57,10 +55,7 @@ pub async fn test_key_sequences( } } - let event_loop = app.event_loop(&mut rx_stream); - let result = tokio::time::timeout(timeout, event_loop).await; - - if result.is_ok() { + if !app.event_loop_until_idle(&mut rx_stream).await { bail!("application exited before test function could run"); } @@ -74,7 +69,7 @@ pub async fn test_key_sequences( } let event_loop = app.event_loop(&mut rx_stream); - tokio::time::timeout(timeout, event_loop).await?; + tokio::time::timeout(TIMEOUT, event_loop).await?; app.close().await?; Ok(()) @@ -84,7 +79,6 @@ pub async fn test_key_sequence_with_input_text>( app: Option, test_case: T, test_fn: &dyn Fn(&Application), - timeout: Option, ) -> anyhow::Result<()> { let test_case = test_case.into(); let mut app = @@ -102,7 +96,7 @@ pub async fn test_key_sequence_with_input_text>( view.id, ); - test_key_sequence(&mut app, Some(&test_case.in_keys), Some(test_fn), timeout).await + test_key_sequence(&mut app, Some(&test_case.in_keys), Some(test_fn)).await } /// Use this for very simple test cases where there is one input @@ -112,26 +106,20 @@ pub async fn test_key_sequence_text_result>( args: Args, config: Config, test_case: T, - timeout: Option, ) -> anyhow::Result<()> { let test_case = test_case.into(); let app = Application::new(args, config).unwrap(); - test_key_sequence_with_input_text( - Some(app), - test_case.clone(), - &|app| { - let doc = doc!(app.editor); - assert_eq!(&test_case.out_text, doc.text()); - - let mut selections: Vec<_> = doc.selections().values().cloned().collect(); - assert_eq!(1, selections.len()); - - let sel = selections.pop().unwrap(); - assert_eq!(test_case.out_selection, sel); - }, - timeout, - ) + test_key_sequence_with_input_text(Some(app), test_case.clone(), &|app| { + let doc = doc!(app.editor); + assert_eq!(&test_case.out_text, doc.text()); + + let mut selections: Vec<_> = doc.selections().values().cloned().collect(); + assert_eq!(1, selections.len()); + + let sel = selections.pop().unwrap(); + assert_eq!(test_case.out_selection, sel); + }) .await } diff --git a/helix-term/tests/integration/movement.rs b/helix-term/tests/integration/movement.rs index a1d294c6c..cac108522 100644 --- a/helix-term/tests/integration/movement.rs +++ b/helix-term/tests/integration/movement.rs @@ -14,7 +14,6 @@ async fn insert_mode_cursor_position() -> anyhow::Result<()> { out_text: String::new(), out_selection: Selection::single(0, 0), }, - None, ) .await?; @@ -22,7 +21,6 @@ async fn insert_mode_cursor_position() -> anyhow::Result<()> { Args::default(), Config::default(), ("#[\n|]#", "i", "#[|\n]#"), - None, ) .await?; @@ -30,7 +28,6 @@ async fn insert_mode_cursor_position() -> anyhow::Result<()> { Args::default(), Config::default(), ("#[\n|]#", "i", "#[|\n]#"), - None, ) .await?; @@ -38,7 +35,6 @@ async fn insert_mode_cursor_position() -> anyhow::Result<()> { Args::default(), Config::default(), ("#[\n|]#", "ii", "#[|\n]#"), - None, ) .await?; @@ -52,7 +48,6 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { Args::default(), Config::default(), ("#[f|]#oo\n", "vll", "#[|foo]#\n"), - None, ) .await?; @@ -70,7 +65,6 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { #(|bar)#" }, ), - None, ) .await?; @@ -88,7 +82,6 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { #(ba|)#r" }, ), - None, ) .await?; @@ -106,7 +99,6 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { #(b|)#ar" }, ), - None, ) .await?; diff --git a/helix-term/tests/integration/write.rs b/helix-term/tests/integration/write.rs index 365e6b8d8..0cc41dbc5 100644 --- a/helix-term/tests/integration/write.rs +++ b/helix-term/tests/integration/write.rs @@ -1,7 +1,6 @@ use std::{ io::{Read, Write}, ops::RangeInclusive, - time::Duration, }; use helix_core::diagnostic::Severity; @@ -24,7 +23,6 @@ async fn test_write() -> anyhow::Result<()> { )?, Some("ii can eat glass, it will not hurt me:w"), None, - Some(Duration::from_millis(1000)), ) .await?; @@ -59,7 +57,6 @@ async fn test_write_concurrent() -> anyhow::Result<()> { )?, Some(&command), None, - Some(Duration::from_millis(10000)), ) .await?; @@ -108,7 +105,6 @@ async fn test_write_fail_mod_flag() -> anyhow::Result<()> { }), ), ], - None, ) .await?; @@ -138,7 +134,6 @@ async fn test_write_fail_new_path() -> anyhow::Result<()> { }), ), ], - Some(Duration::from_millis(1000)), ) .await?; From 2fbf83363028179fe8d3908b5d9911d8595163b1 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Mon, 25 Apr 2022 19:18:27 -0400 Subject: [PATCH 337/861] add integration feature to github tests --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1368d1bc4..d87d4a3b1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,7 +64,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --workspace + args: --workspace --features integration strategy: matrix: From 1533f489340fb63eee31c12122d6233cb5f6abaf Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Mon, 25 Apr 2022 20:25:16 -0400 Subject: [PATCH 338/861] use Results in integration tests for more error context --- helix-term/tests/integration/commands.rs | 2 +- helix-term/tests/integration/helpers.rs | 25 ++++++++++++++---------- helix-term/tests/integration/movement.rs | 15 +++++++------- helix-term/tests/integration/write.rs | 5 ++--- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/helix-term/tests/integration/commands.rs b/helix-term/tests/integration/commands.rs index 4ab87b9b5..0d2e14fda 100644 --- a/helix-term/tests/integration/commands.rs +++ b/helix-term/tests/integration/commands.rs @@ -59,7 +59,7 @@ async fn test_buffer_close() -> anyhow::Result<()> { .await?; // verify if writes are queued up, it finishes them before closing the buffer - let mut file = tempfile::NamedTempFile::new().unwrap(); + let mut file = tempfile::NamedTempFile::new()?; let mut command = String::new(); const RANGE: RangeInclusive = 1..=10; diff --git a/helix-term/tests/integration/helpers.rs b/helix-term/tests/integration/helpers.rs index 29cb8cd88..2a542404c 100644 --- a/helix-term/tests/integration/helpers.rs +++ b/helix-term/tests/integration/helpers.rs @@ -81,8 +81,10 @@ pub async fn test_key_sequence_with_input_text>( test_fn: &dyn Fn(&Application), ) -> anyhow::Result<()> { let test_case = test_case.into(); - let mut app = - app.unwrap_or_else(|| Application::new(Args::default(), Config::default()).unwrap()); + let mut app = match app { + Some(app) => app, + None => Application::new(Args::default(), Config::default())?, + }; let (view, doc) = helix_view::current!(app.editor); let sel = doc.selection(view.id).clone(); @@ -108,7 +110,7 @@ pub async fn test_key_sequence_text_result>( test_case: T, ) -> anyhow::Result<()> { let test_case = test_case.into(); - let app = Application::new(args, config).unwrap(); + let app = Application::new(args, config)?; test_key_sequence_with_input_text(Some(app), test_case.clone(), &|app| { let doc = doc!(app.editor); @@ -123,13 +125,16 @@ pub async fn test_key_sequence_text_result>( .await } -pub fn temp_file_with_contents>(content: S) -> tempfile::NamedTempFile { - let mut temp_file = tempfile::NamedTempFile::new().unwrap(); +pub fn temp_file_with_contents>( + content: S, +) -> anyhow::Result { + let mut temp_file = tempfile::NamedTempFile::new()?; + temp_file .as_file_mut() - .write_all(content.as_ref().as_bytes()) - .unwrap(); - temp_file.flush().unwrap(); - temp_file.as_file_mut().sync_all().unwrap(); - temp_file + .write_all(content.as_ref().as_bytes())?; + + temp_file.flush()?; + temp_file.as_file_mut().sync_all()?; + Ok(temp_file) } diff --git a/helix-term/tests/integration/movement.rs b/helix-term/tests/integration/movement.rs index cac108522..e0bfc3bfc 100644 --- a/helix-term/tests/integration/movement.rs +++ b/helix-term/tests/integration/movement.rs @@ -109,8 +109,8 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { /// the first grapheme #[tokio::test] async fn cursor_position_newly_opened_file() -> anyhow::Result<()> { - let test = |content: &str, expected_sel: Selection| { - let file = helpers::temp_file_with_contents(content); + let test = |content: &str, expected_sel: Selection| -> anyhow::Result<()> { + let file = helpers::temp_file_with_contents(content)?; let mut app = Application::new( Args { @@ -118,17 +118,18 @@ async fn cursor_position_newly_opened_file() -> anyhow::Result<()> { ..Default::default() }, Config::default(), - ) - .unwrap(); + )?; let (view, doc) = helix_view::current!(app.editor); let sel = doc.selection(view.id).clone(); assert_eq!(expected_sel, sel); + + Ok(()) }; - test("foo", Selection::single(0, 1)); - test("👨‍👩‍👧‍👦 foo", Selection::single(0, 7)); - test("", Selection::single(0, 0)); + test("foo", Selection::single(0, 1))?; + test("👨‍👩‍👧‍👦 foo", Selection::single(0, 7))?; + test("", Selection::single(0, 0))?; Ok(()) } diff --git a/helix-term/tests/integration/write.rs b/helix-term/tests/integration/write.rs index 0cc41dbc5..4f8f0eb51 100644 --- a/helix-term/tests/integration/write.rs +++ b/helix-term/tests/integration/write.rs @@ -11,7 +11,7 @@ use super::*; #[tokio::test] async fn test_write() -> anyhow::Result<()> { - let mut file = tempfile::NamedTempFile::new().unwrap(); + let mut file = tempfile::NamedTempFile::new()?; test_key_sequence( &mut Application::new( @@ -38,7 +38,7 @@ async fn test_write() -> anyhow::Result<()> { #[tokio::test] async fn test_write_concurrent() -> anyhow::Result<()> { - let mut file = tempfile::NamedTempFile::new().unwrap(); + let mut file = tempfile::NamedTempFile::new()?; let mut command = String::new(); const RANGE: RangeInclusive = 1..=5000; @@ -112,7 +112,6 @@ async fn test_write_fail_mod_flag() -> anyhow::Result<()> { } #[tokio::test] -#[ignore] async fn test_write_fail_new_path() -> anyhow::Result<()> { test_key_sequences( &mut Application::new(Args::default(), Config::default())?, From ed950fcc56c480dc5a54c7e07918dca9192db200 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Tue, 26 Apr 2022 19:18:20 -0400 Subject: [PATCH 339/861] Add more context; Editor::open doesn't need to own path --- helix-term/src/application.rs | 17 ++++++++++------- helix-term/src/commands.rs | 4 ++-- helix-term/src/commands/lsp.rs | 6 +++--- helix-term/src/commands/typed.rs | 12 ++++++------ helix-term/src/compositor.rs | 6 +++--- helix-term/src/ui/mod.rs | 2 +- helix-view/src/editor.rs | 4 ++-- helix-view/src/handlers/dap.rs | 2 +- 8 files changed, 28 insertions(+), 25 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 3b96c45af..65cf4b2e7 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -25,7 +25,7 @@ use std::{ time::{Duration, Instant}, }; -use anyhow::Error; +use anyhow::{Context, Error}; use crossterm::{ event::{DisableMouseCapture, EnableMouseCapture, Event}, @@ -122,7 +122,7 @@ impl Application { }); let syn_loader = std::sync::Arc::new(syntax::Loader::new(syn_loader_conf)); - let mut compositor = Compositor::new()?; + let mut compositor = Compositor::new().context("build compositor")?; let config = Arc::new(ArcSwap::from_pointee(config)); let mut editor = Editor::new( compositor.size(), @@ -141,26 +141,28 @@ impl Application { if args.load_tutor { let path = helix_loader::runtime_dir().join("tutor.txt"); - editor.open(path, Action::VerticalSplit)?; + editor.open(&path, Action::VerticalSplit)?; // Unset path to prevent accidentally saving to the original tutor file. doc_mut!(editor).set_path(None)?; } else if !args.files.is_empty() { let first = &args.files[0].0; // we know it's not empty if first.is_dir() { - std::env::set_current_dir(&first)?; + std::env::set_current_dir(&first).context("set current dir")?; editor.new_file(Action::VerticalSplit); let picker = ui::file_picker(".".into(), &config.load().editor); compositor.push(Box::new(overlayed(picker))); } else { let nr_of_files = args.files.len(); - editor.open(first.to_path_buf(), Action::VerticalSplit)?; + editor.open(first, Action::VerticalSplit)?; for (file, pos) in args.files { if file.is_dir() { return Err(anyhow::anyhow!( "expected a path to file, found a directory. (to open a directory pass it as first argument)" )); } else { - let doc_id = editor.open(file, Action::Load)?; + let doc_id = editor + .open(&file, Action::Load) + .context(format!("open '{}'", file.to_string_lossy()))?; // with Action::Load all documents have the same view let view_id = editor.tree.focus; let doc = editor.document_mut(doc_id).unwrap(); @@ -192,7 +194,8 @@ impl Application { #[cfg(windows)] let signals = futures_util::stream::empty(); #[cfg(not(windows))] - let signals = Signals::new(&[signal::SIGTSTP, signal::SIGCONT])?; + let signals = + Signals::new(&[signal::SIGTSTP, signal::SIGCONT]).context("build signal handler")?; let app = Self { compositor, diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 6b01cbe31..85dbfd562 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1024,7 +1024,7 @@ fn goto_file_impl(cx: &mut Context, action: Action) { for sel in paths { let p = sel.trim(); if !p.is_empty() { - if let Err(e) = cx.editor.open(PathBuf::from(p), action) { + if let Err(e) = cx.editor.open(&PathBuf::from(p), action) { cx.editor.set_error(format!("Open file failed: {:?}", e)); } } @@ -1849,7 +1849,7 @@ fn global_search(cx: &mut Context) { } }, move |cx, (line_num, path), action| { - match cx.editor.open(path.into(), action) { + match cx.editor.open(path, action) { Ok(_) => {} Err(e) => { cx.editor.set_error(format!( diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index b6bea8d61..ff61ee63f 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -61,7 +61,7 @@ fn jump_to_location( return; } }; - let _id = editor.open(path, action).expect("editor.open failed"); + let _id = editor.open(&path, action).expect("editor.open failed"); let (view, doc) = current!(editor); let definition_pos = location.range.start; // TODO: convert inside server @@ -114,7 +114,7 @@ fn sym_picker( return; } }; - if let Err(err) = cx.editor.open(path, action) { + if let Err(err) = cx.editor.open(&path, action) { let err = format!("failed to open document: {}: {}", uri, err); log::error!("{}", err); cx.editor.set_error(err); @@ -385,7 +385,7 @@ pub fn apply_workspace_edit( }; let current_view_id = view!(editor).id; - let doc_id = match editor.open(path, Action::Load) { + let doc_id = match editor.open(&path, Action::Load) { Ok(doc_id) => doc_id, Err(err) => { let err = format!("failed to open document: {}: {}", uri, err); diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index ae3e63af9..3c88b0ce2 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -50,7 +50,7 @@ fn open( 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 _ = 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); @@ -819,7 +819,7 @@ fn vsplit( } else { for arg in args { cx.editor - .open(PathBuf::from(arg.as_ref()), Action::VerticalSplit)?; + .open(&PathBuf::from(arg.as_ref()), Action::VerticalSplit)?; } } @@ -838,7 +838,7 @@ fn hsplit( } else { for arg in args { cx.editor - .open(PathBuf::from(arg.as_ref()), Action::HorizontalSplit)?; + .open(&PathBuf::from(arg.as_ref()), Action::HorizontalSplit)?; } } @@ -923,7 +923,7 @@ fn tutor( _event: PromptEvent, ) -> anyhow::Result<()> { let path = helix_loader::runtime_dir().join("tutor.txt"); - cx.editor.open(path, Action::Replace)?; + cx.editor.open(&path, Action::Replace)?; // Unset path to prevent accidentally saving to the original tutor file. doc_mut!(cx.editor).set_path(None)?; Ok(()) @@ -1150,7 +1150,7 @@ fn open_config( _event: PromptEvent, ) -> anyhow::Result<()> { cx.editor - .open(helix_loader::config_file(), Action::Replace)?; + .open(&helix_loader::config_file(), Action::Replace)?; Ok(()) } @@ -1159,7 +1159,7 @@ fn open_log( _args: &[Cow], _event: PromptEvent, ) -> anyhow::Result<()> { - cx.editor.open(helix_loader::log_file(), Action::Replace)?; + cx.editor.open(&helix_loader::log_file(), Action::Replace)?; Ok(()) } diff --git a/helix-term/src/compositor.rs b/helix-term/src/compositor.rs index e3cec643e..1d4212135 100644 --- a/helix-term/src/compositor.rs +++ b/helix-term/src/compositor.rs @@ -63,7 +63,7 @@ pub trait Component: Any + AnyComponent { } } -use anyhow::Error; +use anyhow::Context as AnyhowContext; use std::io::stdout; use tui::backend::{Backend, CrosstermBackend}; type Terminal = tui::terminal::Terminal>; @@ -76,9 +76,9 @@ pub struct Compositor { } impl Compositor { - pub fn new() -> Result { + pub fn new() -> anyhow::Result { let backend = CrosstermBackend::new(stdout()); - let terminal = Terminal::new(backend)?; + let terminal = Terminal::new(backend).context("build terminal")?; Ok(Self { layers: Vec::new(), terminal, diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 23d0dca0a..76ddaf89e 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -175,7 +175,7 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi path.strip_prefix(&root).unwrap_or(path).to_string_lossy() }, move |cx, path: &PathBuf, action| { - if let Err(e) = cx.editor.open(path.into(), action) { + if let Err(e) = cx.editor.open(path, action) { let err = if let Some(err) = e.source() { format!("{}", err) } else { diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index e8603221b..8ef4413ea 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -779,8 +779,8 @@ impl Editor { } // ??? possible use for integration tests - pub fn open(&mut self, path: PathBuf, action: Action) -> Result { - let path = helix_core::path::get_canonicalized_path(&path)?; + pub fn open(&mut self, path: &Path, action: Action) -> Result { + let path = helix_core::path::get_canonicalized_path(path)?; let id = self.document_by_path(&path).map(|doc| doc.id); let id = if let Some(id) = id { diff --git a/helix-view/src/handlers/dap.rs b/helix-view/src/handlers/dap.rs index b17ca3530..ae1ae64c8 100644 --- a/helix-view/src/handlers/dap.rs +++ b/helix-view/src/handlers/dap.rs @@ -62,7 +62,7 @@ pub fn jump_to_stack_frame(editor: &mut Editor, frame: &helix_dap::StackFrame) { return; }; - if let Err(e) = editor.open(path, Action::Replace) { + if let Err(e) = editor.open(&path, Action::Replace) { editor.set_error(format!("Unable to jump to stack frame: {}", e)); return; } From 652cdda8338bee55eeff58066cd20e68bb0b5a44 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Wed, 27 Apr 2022 00:07:59 -0400 Subject: [PATCH 340/861] use test terminal backend for integration tests --- helix-term/src/application.rs | 20 +++++++------------- helix-term/src/commands.rs | 8 ++++---- helix-term/src/compositor.rs | 20 +++++++++++++++++++- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 65cf4b2e7..886b531be 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -216,21 +216,15 @@ impl Application { } fn render(&mut self) { - #[cfg(feature = "integration")] - return; - - #[allow(unreachable_code)] - { - let compositor = &mut self.compositor; + let compositor = &mut self.compositor; - let mut cx = crate::compositor::Context { - editor: &mut self.editor, - jobs: &mut self.jobs, - scroll: None, - }; + let mut cx = crate::compositor::Context { + editor: &mut self.editor, + jobs: &mut self.jobs, + scroll: None, + }; - compositor.render(&mut cx); - } + compositor.render(&mut cx); } pub async fn event_loop(&mut self, input_stream: &mut S) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 85dbfd562..4dfa6ec8c 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2100,10 +2100,10 @@ fn insert_mode(cx: &mut Context) { doc.text().to_string() ); - let selection = doc.selection(view.id).clone().transform(|range| { - let new_range = Range::new(range.to(), range.from()); - new_range - }); + let selection = doc + .selection(view.id) + .clone() + .transform(|range| Range::new(range.to(), range.from())); doc.set_selection(view.id, selection); } diff --git a/helix-term/src/compositor.rs b/helix-term/src/compositor.rs index 1d4212135..61a3bfaf1 100644 --- a/helix-term/src/compositor.rs +++ b/helix-term/src/compositor.rs @@ -5,6 +5,9 @@ use helix_core::Position; use helix_view::graphics::{CursorKind, Rect}; use crossterm::event::Event; + +#[cfg(feature = "integration")] +use tui::backend::TestBackend; use tui::buffer::Buffer as Surface; pub type Callback = Box; @@ -64,10 +67,20 @@ pub trait Component: Any + AnyComponent { } use anyhow::Context as AnyhowContext; +use tui::backend::Backend; + +#[cfg(not(feature = "integration"))] +use tui::backend::CrosstermBackend; + +#[cfg(not(feature = "integration"))] use std::io::stdout; -use tui::backend::{Backend, CrosstermBackend}; + +#[cfg(not(feature = "integration"))] type Terminal = tui::terminal::Terminal>; +#[cfg(feature = "integration")] +type Terminal = tui::terminal::Terminal; + pub struct Compositor { layers: Vec>, terminal: Terminal, @@ -77,7 +90,12 @@ pub struct Compositor { impl Compositor { pub fn new() -> anyhow::Result { + #[cfg(not(feature = "integration"))] let backend = CrosstermBackend::new(stdout()); + + #[cfg(feature = "integration")] + let backend = TestBackend::new(120, 150); + let terminal = Terminal::new(backend).context("build terminal")?; Ok(Self { layers: Vec::new(), From cb0440be85338b2669a8341dee2861ea53da7ef7 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Wed, 27 Apr 2022 00:42:18 -0400 Subject: [PATCH 341/861] use env var for integration test log level --- .github/workflows/build.yml | 3 +++ helix-term/src/application.rs | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d87d4a3b1..50829caab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,6 +38,9 @@ jobs: test: name: Test Suite runs-on: ${{ matrix.os }} + env: + RUST_BACKTRACE: 1 + HELIX_LOG_LEVEL: info steps: - name: Checkout sources uses: actions/checkout@v3 diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 886b531be..f3aa955f1 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -61,6 +61,10 @@ pub struct Application { #[cfg(feature = "integration")] fn setup_integration_logging() { + let level = std::env::var("HELIX_LOG_LEVEL") + .map(|lvl| lvl.parse().unwrap()) + .unwrap_or(log::LevelFilter::Info); + // Separate file config so we can include year, month and day in file logs let _ = fern::Dispatch::new() .format(|out, message, record| { @@ -72,7 +76,7 @@ fn setup_integration_logging() { message )) }) - .level(log::LevelFilter::Debug) + .level(level) .chain(std::io::stdout()) .apply(); } From 4e34ee7d2e9dcf9b166abce20f5b2dd083ad2006 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Wed, 27 Apr 2022 00:48:17 -0400 Subject: [PATCH 342/861] don't read from stdin for integration tests --- helix-term/src/application.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index f3aa955f1..c611a691d 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -180,7 +180,7 @@ impl Application { let (view, doc) = current!(editor); align_view(doc, view, Align::Center); } - } else if stdin().is_tty() { + } else if stdin().is_tty() || cfg!(feature = "integration") { editor.new_file(Action::VerticalSplit); } else if cfg!(target_os = "macos") { // On Linux and Windows, we allow the output of a command to be piped into the new buffer. From 28e94fb2613fbedeef56c1bc6e21830277bb35bb Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Wed, 27 Apr 2022 08:44:20 -0400 Subject: [PATCH 343/861] need the full languages config for integration tests --- .github/workflows/build.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 50829caab..9d0383a71 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,9 +53,6 @@ jobs: - uses: Swatinem/rust-cache@v1 - - name: Copy minimal languages config - run: cp .github/workflows/languages.toml ./languages.toml - - name: Cache test tree-sitter grammar uses: actions/cache@v3 with: From ef8fe5a5ce536c65f34e479db79b94c8435aa3b2 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Fri, 29 Apr 2022 16:27:35 -0400 Subject: [PATCH 344/861] use system's appropriate line ending --- helix-term/tests/integration/auto_indent.rs | 7 ++++--- helix-term/tests/integration/helpers.rs | 17 +++++++++++++++++ helix-term/tests/integration/write.rs | 5 ++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/helix-term/tests/integration/auto_indent.rs b/helix-term/tests/integration/auto_indent.rs index 74d1ac587..8933cb6a3 100644 --- a/helix-term/tests/integration/auto_indent.rs +++ b/helix-term/tests/integration/auto_indent.rs @@ -10,13 +10,14 @@ async fn auto_indent_c() -> anyhow::Result<()> { Config::default(), // switches to append mode? ( - "void foo() {#[|}]#\n", + helpers::platform_line("void foo() {#[|}]#").as_ref(), "i", - indoc! {"\ + helpers::platform_line(indoc! {"\ void foo() { #[|\n]#\ } - "}, + "}) + .as_ref(), ), ) .await?; diff --git a/helix-term/tests/integration/helpers.rs b/helix-term/tests/integration/helpers.rs index 2a542404c..706e1afb0 100644 --- a/helix-term/tests/integration/helpers.rs +++ b/helix-term/tests/integration/helpers.rs @@ -138,3 +138,20 @@ pub fn temp_file_with_contents>( temp_file.as_file_mut().sync_all()?; Ok(temp_file) } + +/// Replaces all LF chars with the system's appropriate line feed +/// character, and if one doesn't exist already, appends the system's +/// appropriate line ending to the end of a string. +pub fn platform_line(input: &str) -> String { + let line_end = helix_core::DEFAULT_LINE_ENDING.as_str(); + + // we can assume that the source files in this code base will always + // be LF, so indoc strings will always insert LF + let mut output = input.replace("\n", line_end); + + if !output.ends_with(line_end) { + output.push_str(line_end); + } + + output +} diff --git a/helix-term/tests/integration/write.rs b/helix-term/tests/integration/write.rs index 4f8f0eb51..06af9dd84 100644 --- a/helix-term/tests/integration/write.rs +++ b/helix-term/tests/integration/write.rs @@ -31,7 +31,10 @@ async fn test_write() -> anyhow::Result<()> { let mut file_content = String::new(); file.as_file_mut().read_to_string(&mut file_content)?; - assert_eq!("i can eat glass, it will not hurt me\n", file_content); + assert_eq!( + helpers::platform_line("i can eat glass, it will not hurt me"), + file_content + ); Ok(()) } From acf931709a56e5af0ac101276fcfb3ba45f159f2 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Sat, 30 Apr 2022 00:35:00 -0400 Subject: [PATCH 345/861] use a read only file to ensure write failure --- helix-term/tests/integration/commands.rs | 4 +++- helix-term/tests/integration/helpers.rs | 12 ++++++++++++ helix-term/tests/integration/write.rs | 18 ++++++++++++++---- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/helix-term/tests/integration/commands.rs b/helix-term/tests/integration/commands.rs index 0d2e14fda..1ff7cc90c 100644 --- a/helix-term/tests/integration/commands.rs +++ b/helix-term/tests/integration/commands.rs @@ -10,10 +10,12 @@ use super::*; #[tokio::test] async fn test_write_quit_fail() -> anyhow::Result<()> { + let file = helpers::new_readonly_tempfile()?; + test_key_sequence( &mut Application::new( Args { - files: vec![(PathBuf::from("/foo"), Position::default())], + files: vec![(file.path().to_path_buf(), Position::default())], ..Default::default() }, Config::default(), diff --git a/helix-term/tests/integration/helpers.rs b/helix-term/tests/integration/helpers.rs index 706e1afb0..3fe1934f1 100644 --- a/helix-term/tests/integration/helpers.rs +++ b/helix-term/tests/integration/helpers.rs @@ -5,6 +5,7 @@ use crossterm::event::{Event, KeyEvent}; use helix_core::{test, Selection, Transaction}; use helix_term::{application::Application, args::Args, config::Config}; use helix_view::{doc, input::parse_macro}; +use tempfile::NamedTempFile; use tokio_stream::wrappers::UnboundedReceiverStream; #[derive(Clone, Debug)] @@ -155,3 +156,14 @@ pub fn platform_line(input: &str) -> String { output } + +/// Creates a new temporary file that is set to read only. Useful for +/// testing write failures. +pub fn new_readonly_tempfile() -> anyhow::Result { + let mut file = tempfile::NamedTempFile::new()?; + let metadata = file.as_file().metadata()?; + let mut perms = metadata.permissions(); + perms.set_readonly(true); + file.as_file_mut().set_permissions(perms)?; + Ok(file) +} diff --git a/helix-term/tests/integration/write.rs b/helix-term/tests/integration/write.rs index 06af9dd84..f3abbd91b 100644 --- a/helix-term/tests/integration/write.rs +++ b/helix-term/tests/integration/write.rs @@ -75,10 +75,12 @@ async fn test_write_concurrent() -> anyhow::Result<()> { #[tokio::test] async fn test_write_fail_mod_flag() -> anyhow::Result<()> { + let file = helpers::new_readonly_tempfile()?; + test_key_sequences( &mut Application::new( Args { - files: vec![(PathBuf::from("/foo"), Position::default())], + files: vec![(file.path().to_path_buf(), Position::default())], ..Default::default() }, Config::default(), @@ -116,6 +118,8 @@ async fn test_write_fail_mod_flag() -> anyhow::Result<()> { #[tokio::test] async fn test_write_fail_new_path() -> anyhow::Result<()> { + let file = helpers::new_readonly_tempfile()?; + test_key_sequences( &mut Application::new(Args::default(), Config::default())?, vec![ @@ -123,15 +127,21 @@ async fn test_write_fail_new_path() -> anyhow::Result<()> { None, Some(&|app| { let doc = doc!(app.editor); - assert_eq!(None, app.editor.get_status()); + assert_ne!( + Some(&Severity::Error), + app.editor.get_status().map(|status| status.1) + ); assert_eq!(None, doc.path()); }), ), ( - Some(":w /foo"), + Some(&format!(":w {}", file.path().to_string_lossy())), Some(&|app| { let doc = doc!(app.editor); - assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); + assert_eq!( + Some(&Severity::Error), + app.editor.get_status().map(|status| status.1) + ); assert_eq!(None, doc.path()); }), ), From 8d8d389536d1f948f25a38c33f278a5e2f8d1b28 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Sat, 30 Apr 2022 09:22:20 -0400 Subject: [PATCH 346/861] rename top level module to satisfy cargo fmt --- helix-term/tests/integration.rs | 2 +- helix-term/tests/{integration => test}/auto_indent.rs | 0 helix-term/tests/{integration => test}/auto_pairs.rs | 0 helix-term/tests/{integration => test}/commands.rs | 0 helix-term/tests/{integration => test}/helpers.rs | 0 helix-term/tests/{integration => test}/movement.rs | 0 helix-term/tests/{integration => test}/write.rs | 0 7 files changed, 1 insertion(+), 1 deletion(-) rename helix-term/tests/{integration => test}/auto_indent.rs (100%) rename helix-term/tests/{integration => test}/auto_pairs.rs (100%) rename helix-term/tests/{integration => test}/commands.rs (100%) rename helix-term/tests/{integration => test}/helpers.rs (100%) rename helix-term/tests/{integration => test}/movement.rs (100%) rename helix-term/tests/{integration => test}/write.rs (100%) diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs index 061bd8fff..376bc88b0 100644 --- a/helix-term/tests/integration.rs +++ b/helix-term/tests/integration.rs @@ -1,5 +1,5 @@ #[cfg(feature = "integration")] -mod integration { +mod test { mod helpers; use std::path::PathBuf; diff --git a/helix-term/tests/integration/auto_indent.rs b/helix-term/tests/test/auto_indent.rs similarity index 100% rename from helix-term/tests/integration/auto_indent.rs rename to helix-term/tests/test/auto_indent.rs diff --git a/helix-term/tests/integration/auto_pairs.rs b/helix-term/tests/test/auto_pairs.rs similarity index 100% rename from helix-term/tests/integration/auto_pairs.rs rename to helix-term/tests/test/auto_pairs.rs diff --git a/helix-term/tests/integration/commands.rs b/helix-term/tests/test/commands.rs similarity index 100% rename from helix-term/tests/integration/commands.rs rename to helix-term/tests/test/commands.rs diff --git a/helix-term/tests/integration/helpers.rs b/helix-term/tests/test/helpers.rs similarity index 100% rename from helix-term/tests/integration/helpers.rs rename to helix-term/tests/test/helpers.rs diff --git a/helix-term/tests/integration/movement.rs b/helix-term/tests/test/movement.rs similarity index 100% rename from helix-term/tests/integration/movement.rs rename to helix-term/tests/test/movement.rs diff --git a/helix-term/tests/integration/write.rs b/helix-term/tests/test/write.rs similarity index 100% rename from helix-term/tests/integration/write.rs rename to helix-term/tests/test/write.rs From 374724f5ac23b4b99022b4de58bcb17a1a3f99d5 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Sat, 30 Apr 2022 22:34:52 -0400 Subject: [PATCH 347/861] ignore failing write path tests until fixes are merged --- helix-term/tests/test/commands.rs | 6 ++++-- helix-term/tests/test/write.rs | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index 1ff7cc90c..cea31e25b 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -9,6 +9,7 @@ use helix_term::application::Application; use super::*; #[tokio::test] +#[ignore] async fn test_write_quit_fail() -> anyhow::Result<()> { let file = helpers::new_readonly_tempfile()?; @@ -31,7 +32,8 @@ async fn test_write_quit_fail() -> anyhow::Result<()> { } #[tokio::test] -async fn test_buffer_close() -> anyhow::Result<()> { +#[ignore] +async fn test_buffer_close_concurrent() -> anyhow::Result<()> { test_key_sequences( &mut Application::new(Args::default(), Config::default())?, vec![ @@ -63,7 +65,7 @@ async fn test_buffer_close() -> anyhow::Result<()> { // verify if writes are queued up, it finishes them before closing the buffer let mut file = tempfile::NamedTempFile::new()?; let mut command = String::new(); - const RANGE: RangeInclusive = 1..=10; + const RANGE: RangeInclusive = 1..=1000; for i in RANGE { let cmd = format!("%c{}:w", i); diff --git a/helix-term/tests/test/write.rs b/helix-term/tests/test/write.rs index f3abbd91b..3d724af5d 100644 --- a/helix-term/tests/test/write.rs +++ b/helix-term/tests/test/write.rs @@ -40,6 +40,7 @@ async fn test_write() -> anyhow::Result<()> { } #[tokio::test] +#[ignore] async fn test_write_concurrent() -> anyhow::Result<()> { let mut file = tempfile::NamedTempFile::new()?; let mut command = String::new(); @@ -74,6 +75,7 @@ async fn test_write_concurrent() -> anyhow::Result<()> { } #[tokio::test] +#[ignore] async fn test_write_fail_mod_flag() -> anyhow::Result<()> { let file = helpers::new_readonly_tempfile()?; @@ -117,6 +119,7 @@ async fn test_write_fail_mod_flag() -> anyhow::Result<()> { } #[tokio::test] +#[ignore] async fn test_write_fail_new_path() -> anyhow::Result<()> { let file = helpers::new_readonly_tempfile()?; From 526c9be8cadf99519e8f6a9911b3784ab7f2e142 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Mon, 16 May 2022 22:28:12 -0400 Subject: [PATCH 348/861] consolidate idle timer logic, make conditional --- helix-term/src/application.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index c611a691d..15b44a856 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -251,6 +251,9 @@ impl Application { where S: Stream> + Unpin, { + #[cfg(feature = "integration")] + let mut idle_handled = false; + loop { if self.editor.should_close() { return false; @@ -263,11 +266,9 @@ impl Application { Some(event) = input_stream.next() => { self.handle_terminal_events(event); - self.editor.reset_idle_timer(); } Some(signal) = self.signals.next() => { self.handle_signals(signal).await; - self.editor.reset_idle_timer(); } Some((id, call)) = self.editor.language_servers.incoming.next() => { self.handle_language_server_message(call, id).await; @@ -278,37 +279,46 @@ impl Application { self.render(); self.last_render = Instant::now(); } - - self.editor.reset_idle_timer(); } Some(payload) = self.editor.debugger_events.next() => { let needs_render = self.editor.handle_debugger_message(payload).await; if needs_render { self.render(); } - self.editor.reset_idle_timer(); } Some(config_event) = self.editor.config_events.1.recv() => { self.handle_config_events(config_event); self.render(); - self.editor.reset_idle_timer(); } Some(callback) = self.jobs.futures.next() => { self.jobs.handle_callback(&mut self.editor, &mut self.compositor, callback); self.render(); - self.editor.reset_idle_timer(); } Some(callback) = self.jobs.wait_futures.next() => { self.jobs.handle_callback(&mut self.editor, &mut self.compositor, callback); self.render(); - self.editor.reset_idle_timer(); } _ = &mut self.editor.idle_timer => { // idle timeout self.editor.clear_idle_timer(); self.handle_idle_timeout(); + + #[cfg(feature = "integration")] + { + idle_handled = true; + } + } + } + + // for integration tests only, reset the idle timer after every + // event to make a signal when test events are done processing + #[cfg(feature = "integration")] + { + if idle_handled { return true; } + + self.editor.reset_idle_timer(); } } } From 7c0bca186cdacf070355c1a4ab82121d6a4d2e27 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Sun, 22 May 2022 13:29:52 -0400 Subject: [PATCH 349/861] rename test helpers --- helix-term/tests/integration.rs | 8 +-- helix-term/tests/test/auto_indent.rs | 2 +- helix-term/tests/test/auto_pairs.rs | 9 +-- helix-term/tests/test/helpers.rs | 13 ++-- helix-term/tests/test/movement.rs | 103 +++++++++------------------ 5 files changed, 45 insertions(+), 90 deletions(-) diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs index 376bc88b0..11bc4e4c7 100644 --- a/helix-term/tests/integration.rs +++ b/helix-term/tests/integration.rs @@ -13,13 +13,7 @@ mod test { #[tokio::test] async fn hello_world() -> anyhow::Result<()> { - test_key_sequence_text_result( - Args::default(), - Config::default(), - ("#[\n|]#", "ihello world", "hello world#[|\n]#"), - ) - .await?; - + test(("#[\n|]#", "ihello world", "hello world#[|\n]#")).await?; Ok(()) } diff --git a/helix-term/tests/test/auto_indent.rs b/helix-term/tests/test/auto_indent.rs index 8933cb6a3..2f638893c 100644 --- a/helix-term/tests/test/auto_indent.rs +++ b/helix-term/tests/test/auto_indent.rs @@ -2,7 +2,7 @@ use super::*; #[tokio::test] async fn auto_indent_c() -> anyhow::Result<()> { - test_key_sequence_text_result( + test_with_config( Args { files: vec![(PathBuf::from("foo.c"), Position::default())], ..Default::default() diff --git a/helix-term/tests/test/auto_pairs.rs b/helix-term/tests/test/auto_pairs.rs index 52fee55e5..ec47a5b4a 100644 --- a/helix-term/tests/test/auto_pairs.rs +++ b/helix-term/tests/test/auto_pairs.rs @@ -2,14 +2,9 @@ use super::*; #[tokio::test] async fn auto_pairs_basic() -> anyhow::Result<()> { - test_key_sequence_text_result( - Args::default(), - Config::default(), - ("#[\n|]#", "i(", "(#[|)]#\n"), - ) - .await?; + test(("#[\n|]#", "i(", "(#[|)]#\n")).await?; - test_key_sequence_text_result( + test_with_config( Args::default(), Config { editor: helix_view::editor::Config { diff --git a/helix-term/tests/test/helpers.rs b/helix-term/tests/test/helpers.rs index 3fe1934f1..2bebe31be 100644 --- a/helix-term/tests/test/helpers.rs +++ b/helix-term/tests/test/helpers.rs @@ -41,6 +41,7 @@ pub async fn test_key_sequence( test_key_sequences(app, vec![(in_keys, test_fn)]).await } +#[allow(clippy::type_complexity)] pub async fn test_key_sequences( app: &mut Application, inputs: Vec<(Option<&str>, Option<&dyn Fn(&Application)>)>, @@ -51,7 +52,7 @@ pub async fn test_key_sequences( for (in_keys, test_fn) in inputs { if let Some(in_keys) = in_keys { - for key_event in parse_macro(&in_keys)?.into_iter() { + for key_event in parse_macro(in_keys)?.into_iter() { tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?; } } @@ -92,7 +93,7 @@ pub async fn test_key_sequence_with_input_text>( // replace the initial text with the input text doc.apply( - &Transaction::change_by_selection(&doc.text(), &sel, |_| { + &Transaction::change_by_selection(doc.text(), &sel, |_| { (0, doc.text().len_chars(), Some((&test_case.in_text).into())) }) .with_selection(test_case.in_selection.clone()), @@ -105,7 +106,7 @@ pub async fn test_key_sequence_with_input_text>( /// Use this for very simple test cases where there is one input /// document, selection, and sequence of key presses, and you just /// want to verify the resulting document and selection. -pub async fn test_key_sequence_text_result>( +pub async fn test_with_config>( args: Args, config: Config, test_case: T, @@ -126,6 +127,10 @@ pub async fn test_key_sequence_text_result>( .await } +pub async fn test>(test_case: T) -> anyhow::Result<()> { + test_with_config(Args::default(), Config::default(), test_case).await +} + pub fn temp_file_with_contents>( content: S, ) -> anyhow::Result { @@ -148,7 +153,7 @@ pub fn platform_line(input: &str) -> String { // we can assume that the source files in this code base will always // be LF, so indoc strings will always insert LF - let mut output = input.replace("\n", line_end); + let mut output = input.replace('\n', line_end); if !output.ends_with(line_end) { output.push_str(line_end); diff --git a/helix-term/tests/test/movement.rs b/helix-term/tests/test/movement.rs index e0bfc3bfc..5fb2ce25d 100644 --- a/helix-term/tests/test/movement.rs +++ b/helix-term/tests/test/movement.rs @@ -4,39 +4,18 @@ use super::*; #[tokio::test] async fn insert_mode_cursor_position() -> anyhow::Result<()> { - test_key_sequence_text_result( - Args::default(), - Config::default(), - TestCase { - in_text: String::new(), - in_selection: Selection::single(0, 0), - in_keys: "i".into(), - out_text: String::new(), - out_selection: Selection::single(0, 0), - }, - ) - .await?; - - test_key_sequence_text_result( - Args::default(), - Config::default(), - ("#[\n|]#", "i", "#[|\n]#"), - ) - .await?; - - test_key_sequence_text_result( - Args::default(), - Config::default(), - ("#[\n|]#", "i", "#[|\n]#"), - ) + test(TestCase { + in_text: String::new(), + in_selection: Selection::single(0, 0), + in_keys: "i".into(), + out_text: String::new(), + out_selection: Selection::single(0, 0), + }) .await?; - test_key_sequence_text_result( - Args::default(), - Config::default(), - ("#[\n|]#", "ii", "#[|\n]#"), - ) - .await?; + test(("#[\n|]#", "i", "#[|\n]#")).await?; + test(("#[\n|]#", "i", "#[|\n]#")).await?; + test(("#[\n|]#", "ii", "#[|\n]#")).await?; Ok(()) } @@ -44,62 +23,44 @@ async fn insert_mode_cursor_position() -> anyhow::Result<()> { /// Range direction is preserved when escaping insert mode to normal #[tokio::test] async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { - test_key_sequence_text_result( - Args::default(), - Config::default(), - ("#[f|]#oo\n", "vll", "#[|foo]#\n"), - ) - .await?; - - test_key_sequence_text_result( - Args::default(), - Config::default(), - ( - indoc! {"\ + test(("#[f|]#oo\n", "vll", "#[|foo]#\n")).await?; + test(( + indoc! {"\ #[f|]#oo #(b|)#ar" - }, - "vll", - indoc! {"\ + }, + "vll", + indoc! {"\ #[|foo]# #(|bar)#" - }, - ), - ) + }, + )) .await?; - test_key_sequence_text_result( - Args::default(), - Config::default(), - ( - indoc! {"\ + test(( + indoc! {"\ #[f|]#oo #(b|)#ar" - }, - "a", - indoc! {"\ + }, + "a", + indoc! {"\ #[fo|]#o #(ba|)#r" - }, - ), - ) + }, + )) .await?; - test_key_sequence_text_result( - Args::default(), - Config::default(), - ( - indoc! {"\ + test(( + indoc! {"\ #[f|]#oo #(b|)#ar" - }, - "a", - indoc! {"\ + }, + "a", + indoc! {"\ #[f|]#oo #(b|)#ar" - }, - ), - ) + }, + )) .await?; Ok(()) From fac36bc5eab804e823ddef01e50d1e36495c7967 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Mon, 23 May 2022 00:24:18 -0400 Subject: [PATCH 350/861] add test for write-quit happy path --- helix-term/tests/test/commands.rs | 3 ++ helix-term/tests/test/helpers.rs | 63 ++++++++++++++++++++++--------- helix-term/tests/test/write.rs | 37 ++++++++++++++++++ 3 files changed, 85 insertions(+), 18 deletions(-) diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index cea31e25b..27b4da580 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -25,6 +25,7 @@ async fn test_write_quit_fail() -> anyhow::Result<()> { Some(&|app| { assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); }), + false, ) .await?; @@ -59,6 +60,7 @@ async fn test_buffer_close_concurrent() -> anyhow::Result<()> { }), ), ], + false, ) .await?; @@ -89,6 +91,7 @@ async fn test_buffer_close_concurrent() -> anyhow::Result<()> { let doc = app.editor.document_by_path(file.path()); assert!(doc.is_none(), "found doc: {:?}", doc); }), + false, ) .await?; diff --git a/helix-term/tests/test/helpers.rs b/helix-term/tests/test/helpers.rs index 2bebe31be..894fb674a 100644 --- a/helix-term/tests/test/helpers.rs +++ b/helix-term/tests/test/helpers.rs @@ -37,41 +37,56 @@ pub async fn test_key_sequence( app: &mut Application, in_keys: Option<&str>, test_fn: Option<&dyn Fn(&Application)>, + should_exit: bool, ) -> anyhow::Result<()> { - test_key_sequences(app, vec![(in_keys, test_fn)]).await + test_key_sequences(app, vec![(in_keys, test_fn)], should_exit).await } #[allow(clippy::type_complexity)] pub async fn test_key_sequences( app: &mut Application, inputs: Vec<(Option<&str>, Option<&dyn Fn(&Application)>)>, + should_exit: bool, ) -> anyhow::Result<()> { const TIMEOUT: Duration = Duration::from_millis(500); let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); let mut rx_stream = UnboundedReceiverStream::new(rx); + let num_inputs = inputs.len(); - for (in_keys, test_fn) in inputs { + for (i, (in_keys, test_fn)) in inputs.into_iter().enumerate() { if let Some(in_keys) = in_keys { for key_event in parse_macro(in_keys)?.into_iter() { tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?; } } - if !app.event_loop_until_idle(&mut rx_stream).await { + let app_exited = !app.event_loop_until_idle(&mut rx_stream).await; + + // the app should not exit from any test until the last one + if i < num_inputs - 1 && app_exited { bail!("application exited before test function could run"); } + // verify if it exited on the last iteration if it should have and + // the inverse + if i == num_inputs - 1 && app_exited != should_exit { + bail!("expected app to exit: {} != {}", app_exited, should_exit); + } + if let Some(test) = test_fn { test(app); }; } - for key_event in parse_macro(":q!")?.into_iter() { - tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?; + if !should_exit { + for key_event in parse_macro(":q!")?.into_iter() { + tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?; + } + + let event_loop = app.event_loop(&mut rx_stream); + tokio::time::timeout(TIMEOUT, event_loop).await?; } - let event_loop = app.event_loop(&mut rx_stream); - tokio::time::timeout(TIMEOUT, event_loop).await?; app.close().await?; Ok(()) @@ -81,6 +96,7 @@ pub async fn test_key_sequence_with_input_text>( app: Option, test_case: T, test_fn: &dyn Fn(&Application), + should_exit: bool, ) -> anyhow::Result<()> { let test_case = test_case.into(); let mut app = match app { @@ -100,7 +116,13 @@ pub async fn test_key_sequence_with_input_text>( view.id, ); - test_key_sequence(&mut app, Some(&test_case.in_keys), Some(test_fn)).await + test_key_sequence( + &mut app, + Some(&test_case.in_keys), + Some(test_fn), + should_exit, + ) + .await } /// Use this for very simple test cases where there is one input @@ -114,16 +136,21 @@ pub async fn test_with_config>( let test_case = test_case.into(); let app = Application::new(args, config)?; - test_key_sequence_with_input_text(Some(app), test_case.clone(), &|app| { - let doc = doc!(app.editor); - assert_eq!(&test_case.out_text, doc.text()); - - let mut selections: Vec<_> = doc.selections().values().cloned().collect(); - assert_eq!(1, selections.len()); - - let sel = selections.pop().unwrap(); - assert_eq!(test_case.out_selection, sel); - }) + test_key_sequence_with_input_text( + Some(app), + test_case.clone(), + &|app| { + let doc = doc!(app.editor); + assert_eq!(&test_case.out_text, doc.text()); + + let mut selections: Vec<_> = doc.selections().values().cloned().collect(); + assert_eq!(1, selections.len()); + + let sel = selections.pop().unwrap(); + assert_eq!(test_case.out_selection, sel); + }, + false, + ) .await } diff --git a/helix-term/tests/test/write.rs b/helix-term/tests/test/write.rs index 3d724af5d..d22b3125a 100644 --- a/helix-term/tests/test/write.rs +++ b/helix-term/tests/test/write.rs @@ -23,6 +23,7 @@ async fn test_write() -> anyhow::Result<()> { )?, Some("ii can eat glass, it will not hurt me:w"), None, + false, ) .await?; @@ -31,6 +32,39 @@ async fn test_write() -> anyhow::Result<()> { let mut file_content = String::new(); file.as_file_mut().read_to_string(&mut file_content)?; + + assert_eq!( + helpers::platform_line("i can eat glass, it will not hurt me"), + file_content + ); + + Ok(()) +} + +#[tokio::test] +async fn test_write_quit() -> anyhow::Result<()> { + let mut file = tempfile::NamedTempFile::new()?; + + test_key_sequence( + &mut Application::new( + Args { + files: vec![(file.path().to_path_buf(), Position::default())], + ..Default::default() + }, + Config::default(), + )?, + Some("ii can eat glass, it will not hurt me:wq"), + None, + true, + ) + .await?; + + file.as_file_mut().flush()?; + file.as_file_mut().sync_all()?; + + let mut file_content = String::new(); + file.as_file_mut().read_to_string(&mut file_content)?; + assert_eq!( helpers::platform_line("i can eat glass, it will not hurt me"), file_content @@ -61,6 +95,7 @@ async fn test_write_concurrent() -> anyhow::Result<()> { )?, Some(&command), None, + false, ) .await?; @@ -112,6 +147,7 @@ async fn test_write_fail_mod_flag() -> anyhow::Result<()> { }), ), ], + false, ) .await?; @@ -149,6 +185,7 @@ async fn test_write_fail_new_path() -> anyhow::Result<()> { }), ), ], + false, ) .await?; From 41bf1d581137855596e00ad7702e8827325714b0 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Thu, 31 Mar 2022 10:58:50 -0400 Subject: [PATCH 351/861] fix(command): write-quit: do not quit if write fails During write-quit, if the file fails to be written for any reason, helix will still quit without saving the changes. This fixes this behavior by introducing fallibility to the asynchronous job queues. This will also benefit all contexts which may depend on these job queues. Fixes #1575 --- helix-term/src/application.rs | 2 +- helix-term/src/commands/typed.rs | 2 ++ helix-term/src/job.rs | 20 ++++++++++++++++---- helix-term/tests/test/commands.rs | 1 - 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 15b44a856..2790c9a49 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -814,7 +814,7 @@ impl Application { } pub async fn close(&mut self) -> anyhow::Result<()> { - self.jobs.finish().await; + self.jobs.finish().await?; if self.editor.close_language_servers(None).await.is_err() { log::error!("Timed out waiting for language servers to shutdown"); diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 3c88b0ce2..5b48ca488 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -233,6 +233,7 @@ fn write_impl( doc.detect_language(cx.editor.syn_loader.clone()); let _ = cx.editor.refresh_language_server(id); } + Ok(()) } @@ -422,6 +423,7 @@ fn write_quit( event: PromptEvent, ) -> anyhow::Result<()> { write_impl(cx, args.first(), false)?; + helix_lsp::block_on(cx.jobs.finish())?; quit(cx, &[], event) } diff --git a/helix-term/src/job.rs b/helix-term/src/job.rs index d21099f73..e51479925 100644 --- a/helix-term/src/job.rs +++ b/helix-term/src/job.rs @@ -2,7 +2,7 @@ use helix_view::Editor; use crate::compositor::Compositor; -use futures_util::future::{self, BoxFuture, Future, FutureExt}; +use futures_util::future::{BoxFuture, Future, FutureExt}; use futures_util::stream::{FuturesUnordered, StreamExt}; pub type Callback = Box; @@ -93,9 +93,21 @@ impl Jobs { } /// Blocks until all the jobs that need to be waited on are done. - pub async fn finish(&mut self) { - let wait_futures = std::mem::take(&mut self.wait_futures); + pub async fn finish(&mut self) -> anyhow::Result<()> { log::debug!("waiting on jobs..."); - wait_futures.for_each(|_| future::ready(())).await + let mut wait_futures = std::mem::take(&mut self.wait_futures); + while let (Some(job), tail) = wait_futures.into_future().await { + match job { + Ok(_) => { + wait_futures = tail; + } + Err(e) => { + self.wait_futures = tail; + return Err(e); + } + } + } + + Ok(()) } } diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index 27b4da580..01f13c5c0 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -9,7 +9,6 @@ use helix_term::application::Application; use super::*; #[tokio::test] -#[ignore] async fn test_write_quit_fail() -> anyhow::Result<()> { let file = helpers::new_readonly_tempfile()?; From 086b63ab1b5f004400721ef876b6f1441783f104 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Thu, 2 Jun 2022 00:13:08 -0400 Subject: [PATCH 352/861] add integration-test cargo alias --- .cargo/config | 1 + .github/workflows/build.yml | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.cargo/config b/.cargo/config index 35049cbcb..5d6155669 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,2 +1,3 @@ [alias] xtask = "run --package xtask --" +integration-test = "test --features integration --workspace --test integration" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9d0383a71..b24cdb8c9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,7 +64,12 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --workspace --features integration + args: --workspace + + - name: Run cargo integration-test + uses: actions-rs/cargo@v1 + with: + command: integration-test strategy: matrix: From 65bf6836b71e309a43d39b75a3fac7446604592b Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Sat, 4 Jun 2022 16:08:34 -0400 Subject: [PATCH 353/861] update docs for integration tests --- docs/CONTRIBUTING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index bdd771aaf..6da50fdd6 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -35,3 +35,10 @@ to `cargo install` anything either). [architecture.md]: ./architecture.md [docs]: https://docs.helix-editor.com/ [xtask]: https://github.com/matklad/cargo-xtask + +# Integration tests + +Integration tests for helix-term can be run with `cargo integration-test`. Code +contributors are strongly encouraged to write integration tests for their code. +Existing tests can be used as examples. Helpers can be found in +[helpers.rs][../helix-term/tests/test/helpers.rs]. From 665286c199b344c0bd65772156b5e460ff11d768 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Fri, 10 Jun 2022 23:35:34 -0400 Subject: [PATCH 354/861] factor new Application with file arg to function --- helix-term/src/application.rs | 4 +--- helix-term/tests/test/commands.rs | 16 ++-------------- helix-term/tests/test/helpers.rs | 14 +++++++++++++- helix-term/tests/test/movement.rs | 11 +---------- helix-term/tests/test/write.rs | 32 ++++--------------------------- 5 files changed, 21 insertions(+), 56 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 2790c9a49..48e9c2758 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -239,11 +239,9 @@ impl Application { self.last_render = Instant::now(); loop { - if self.editor.should_close() { + if !self.event_loop_until_idle(input_stream).await { break; } - - self.event_loop_until_idle(input_stream).await; } } diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index 01f13c5c0..0cd79bc7f 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -13,13 +13,7 @@ async fn test_write_quit_fail() -> anyhow::Result<()> { let file = helpers::new_readonly_tempfile()?; test_key_sequence( - &mut Application::new( - Args { - files: vec![(file.path().to_path_buf(), Position::default())], - ..Default::default() - }, - Config::default(), - )?, + &mut helpers::app_with_file(file.path())?, Some("ihello:wq"), Some(&|app| { assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); @@ -76,13 +70,7 @@ async fn test_buffer_close_concurrent() -> anyhow::Result<()> { command.push_str(":bufferclose"); test_key_sequence( - &mut Application::new( - Args { - files: vec![(file.path().to_path_buf(), Position::default())], - ..Default::default() - }, - Config::default(), - )?, + &mut helpers::app_with_file(file.path())?, Some(&command), Some(&|app| { assert!(!app.editor.is_err(), "error: {:?}", app.editor.get_status()); diff --git a/helix-term/tests/test/helpers.rs b/helix-term/tests/test/helpers.rs index 894fb674a..8f2501e61 100644 --- a/helix-term/tests/test/helpers.rs +++ b/helix-term/tests/test/helpers.rs @@ -1,4 +1,4 @@ -use std::{io::Write, time::Duration}; +use std::{io::Write, path::PathBuf, time::Duration}; use anyhow::bail; use crossterm::event::{Event, KeyEvent}; @@ -199,3 +199,15 @@ pub fn new_readonly_tempfile() -> anyhow::Result { file.as_file_mut().set_permissions(perms)?; Ok(file) } + +/// Creates a new Application with default config that opens the given file +/// path +pub fn app_with_file>(path: P) -> anyhow::Result { + Application::new( + Args { + files: vec![(path.into(), helix_core::Position::default())], + ..Default::default() + }, + Config::default(), + ) +} diff --git a/helix-term/tests/test/movement.rs b/helix-term/tests/test/movement.rs index 5fb2ce25d..088685dfc 100644 --- a/helix-term/tests/test/movement.rs +++ b/helix-term/tests/test/movement.rs @@ -1,5 +1,3 @@ -use helix_term::application::Application; - use super::*; #[tokio::test] @@ -72,14 +70,7 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { async fn cursor_position_newly_opened_file() -> anyhow::Result<()> { let test = |content: &str, expected_sel: Selection| -> anyhow::Result<()> { let file = helpers::temp_file_with_contents(content)?; - - let mut app = Application::new( - Args { - files: vec![(file.path().to_path_buf(), Position::default())], - ..Default::default() - }, - Config::default(), - )?; + let mut app = helpers::app_with_file(file.path())?; let (view, doc) = helix_view::current!(app.editor); let sel = doc.selection(view.id).clone(); diff --git a/helix-term/tests/test/write.rs b/helix-term/tests/test/write.rs index d22b3125a..39efa2ce9 100644 --- a/helix-term/tests/test/write.rs +++ b/helix-term/tests/test/write.rs @@ -14,13 +14,7 @@ async fn test_write() -> anyhow::Result<()> { let mut file = tempfile::NamedTempFile::new()?; test_key_sequence( - &mut Application::new( - Args { - files: vec![(file.path().to_path_buf(), Position::default())], - ..Default::default() - }, - Config::default(), - )?, + &mut helpers::app_with_file(file.path())?, Some("ii can eat glass, it will not hurt me:w"), None, false, @@ -46,13 +40,7 @@ async fn test_write_quit() -> anyhow::Result<()> { let mut file = tempfile::NamedTempFile::new()?; test_key_sequence( - &mut Application::new( - Args { - files: vec![(file.path().to_path_buf(), Position::default())], - ..Default::default() - }, - Config::default(), - )?, + &mut helpers::app_with_file(file.path())?, Some("ii can eat glass, it will not hurt me:wq"), None, true, @@ -86,13 +74,7 @@ async fn test_write_concurrent() -> anyhow::Result<()> { } test_key_sequence( - &mut Application::new( - Args { - files: vec![(file.path().to_path_buf(), Position::default())], - ..Default::default() - }, - Config::default(), - )?, + &mut helpers::app_with_file(file.path())?, Some(&command), None, false, @@ -115,13 +97,7 @@ async fn test_write_fail_mod_flag() -> anyhow::Result<()> { let file = helpers::new_readonly_tempfile()?; test_key_sequences( - &mut Application::new( - Args { - files: vec![(file.path().to_path_buf(), Position::default())], - ..Default::default() - }, - Config::default(), - )?, + &mut helpers::app_with_file(file.path())?, vec![ ( None, From 5f7c247430998fabceb55d4689118dd75e2bdfb1 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Mon, 13 Jun 2022 22:18:17 -0400 Subject: [PATCH 355/861] replace phrase in tests --- helix-term/tests/test/write.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/helix-term/tests/test/write.rs b/helix-term/tests/test/write.rs index 39efa2ce9..8869d881d 100644 --- a/helix-term/tests/test/write.rs +++ b/helix-term/tests/test/write.rs @@ -15,7 +15,7 @@ async fn test_write() -> anyhow::Result<()> { test_key_sequence( &mut helpers::app_with_file(file.path())?, - Some("ii can eat glass, it will not hurt me:w"), + Some("ithe gostak distims the doshes:w"), None, false, ) @@ -28,7 +28,7 @@ async fn test_write() -> anyhow::Result<()> { file.as_file_mut().read_to_string(&mut file_content)?; assert_eq!( - helpers::platform_line("i can eat glass, it will not hurt me"), + helpers::platform_line("the gostak distims the doshes"), file_content ); @@ -41,7 +41,7 @@ async fn test_write_quit() -> anyhow::Result<()> { test_key_sequence( &mut helpers::app_with_file(file.path())?, - Some("ii can eat glass, it will not hurt me:wq"), + Some("ithe gostak distims the doshes:wq"), None, true, ) @@ -54,7 +54,7 @@ async fn test_write_quit() -> anyhow::Result<()> { file.as_file_mut().read_to_string(&mut file_content)?; assert_eq!( - helpers::platform_line("i can eat glass, it will not hurt me"), + helpers::platform_line("the gostak distims the doshes"), file_content ); From e2878a6e21914541d546bf98c961f2d05e198e9d Mon Sep 17 00:00:00 2001 From: Joe Date: Mon, 20 Jun 2022 10:21:21 -0400 Subject: [PATCH 356/861] Add noctis bordo theme (#2830) --- runtime/themes/noctis_bordo.toml | 80 ++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 runtime/themes/noctis_bordo.toml diff --git a/runtime/themes/noctis_bordo.toml b/runtime/themes/noctis_bordo.toml new file mode 100644 index 000000000..3487d7840 --- /dev/null +++ b/runtime/themes/noctis_bordo.toml @@ -0,0 +1,80 @@ +# Author: Joseph Harrison-Lim + +"attributes" = { fg = "#7060eb", modifiers = ["bold"] } +"comment" = { fg = "base03", modifiers = ["italic"] } +"comment.block.documentation" = { fg = "base06", modifiers = ["italic"] } +"constant" = "base09" +"constant.character.escape" = "base0C" +"constant.numeric" = "#7060eb" +"constructor" = "base0D" +"function" = "base0D" +"keyword" = "base0E" +"keyword.control" = { fg = "base0E", modifiers = ["bold"] } +"keyword.directive" = "white" +"keyword.import" = { fg = "#df769b" } +"keyword.operator" = { fg = "base0E", modifiers = ["italic"] } +"label" = "base0E" +"namespace" = "base0E" +"operator" = "base05" +"string" = "base0B" +"type" = "base10" +"variable" = "base08" +"variable.other.member" = "base08" +"special" = "base0D" + +"ui.background" = { bg = "base00" } +"ui.virtual" = "base03" +"ui.menu" = { fg = "base05", bg = "base01" } +"ui.menu.selected" = { fg = "base0B", bg = "base01" } +"ui.popup" = { bg = "base01" } +"ui.window" = { bg = "base01" } +"ui.linenr" = { fg = "#715b63", bg = "base01" } +"ui.linenr.selected" = { fg = "base02", bg = "base01", modifiers = ["bold"] } +"ui.selection" = { fg = "base05", bg = "base02" } +"ui.statusline" = { fg = "base02", bg = "base01" } +"ui.cursor" = { fg = "base04", modifiers = ["reversed"] } +"ui.cursor.primary" = { fg = "base05", modifiers = ["reversed"] } +"ui.text" = "base05" +"ui.text.focus" = "base05" +"ui.cursor.match" = { fg = "base0A", modifiers = ["underlined"] } +"ui.help" = { fg = "base06", bg = "base01" } + +"markup.bold" = { fg = "base0A", modifiers = ["bold"] } +"markup.heading" = "base0D" +"markup.italic" = { fg = "base0E", modifiers = ["italic"] } +"markup.link.text" = "base08" +"markup.link.url" = { fg = "base09", modifiers = ["underlined"] } +"markup.list" = "base08" +"markup.quote" = "base0C" +"markup.raw" = "base0B" + +"diff.delta" = "base09" +"diff.plus" = "base0B" +"diff.minus" = "base08" + +"diagnostic" = { modifiers = ["underlined"] } +"ui.gutter" = { bg = "base01" } +"info" = "base0D" +"hint" = "base03" +"debug" = "base03" +"warning" = "base09" +"error" = "base08" + +[palette] +base00 = "#322a2d" # Default Background +base01 = "#2c2528" # Lighter Background (Used for status bars, line number and folding marks) +base02 = "#997582" # Selection Background +base03 = "#585858" # Comments, Invisibles, Line Highlighting +base04 = "#322a2d" # Dark Foreground (Used for status bars) +base05 = "#cbbec2" # Default Foreground, Caret, Delimiters, Operators +base06 = "#e8e8e8" # Light Foreground (Not often used) +base07 = "#f8f8f8" # Light Background (Not often used) +base08 = "#e4b781" # Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted +base09 = "#d5971a" # Integers, Boolean, Constants, XML Attributes, Markup Link Url +base0A = "#df769b" # Classes, Markup Bold, Search Text Background +base0B = "#49e9a6" # Strings, Inherited Class, Markup Code, Diff Inserted +base0C = "#16b673" # Support, Regular Expressions, Escape Characters, Markup Quotes +base0D = "#16a3b6" # Functions, Methods, Attribute IDs, Headings +base0E = "#ba8baf" # Keywords, Storage, Selector, Markup Italic, Diff Changed +base0F = "#d67e5c" # Deprecated, Opening/Closing Embedded Language Tags, e.g. +base10 = "#b0b0ff" # Types From 55f4f6951571d44862d5f1bc3ad7094953b788b6 Mon Sep 17 00:00:00 2001 From: lazytanuki <43273245+lazytanuki@users.noreply.github.com> Date: Mon, 20 Jun 2022 17:07:32 +0200 Subject: [PATCH 357/861] fix: do not color health summary when stdout is piped (#2836) * fix: do not color health summary when stdout is piped * fix: use crossterm instead of is-terminal --- helix-term/src/health.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/helix-term/src/health.rs b/helix-term/src/health.rs index bd74f4787..f64e121d5 100644 --- a/helix-term/src/health.rs +++ b/helix-term/src/health.rs @@ -1,4 +1,7 @@ -use crossterm::style::{Color, Print, Stylize}; +use crossterm::{ + style::{Color, Print, Stylize}, + tty::IsTty, +}; use helix_core::config::{default_syntax_loader, user_syntax_loader}; use helix_loader::grammar::load_runtime_file; use std::io::Write; @@ -106,17 +109,19 @@ pub fn languages_all() -> std::io::Result<()> { let terminal_cols = crossterm::terminal::size().map(|(c, _)| c).unwrap_or(80); let column_width = terminal_cols as usize / headings.len(); + let is_terminal = std::io::stdout().is_tty(); let column = |item: &str, color: Color| { - let data = format!( + let mut data = format!( "{:width$}", item.get(..column_width - 2) .map(|s| format!("{}…", s)) .unwrap_or_else(|| item.to_string()), width = column_width, - ) - .stylize() - .with(color); + ); + if is_terminal { + data = data.stylize().with(color).to_string(); + } // We can't directly use println!() because of // https://github.com/crossterm-rs/crossterm/issues/589 From cad4e03a00d6431ccde76a080de2a5b328d54d9d Mon Sep 17 00:00:00 2001 From: farwyler <1705805+farwyler@users.noreply.github.com> Date: Mon, 20 Jun 2022 17:55:51 +0200 Subject: [PATCH 358/861] adds missing tree-sitter-comment injection for js/ts (#2763) --- runtime/queries/javascript/injections.scm | 12 ++++++++++-- runtime/queries/jsdoc/injections.scm | 5 +++++ 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 runtime/queries/jsdoc/injections.scm diff --git a/runtime/queries/javascript/injections.scm b/runtime/queries/javascript/injections.scm index e84291115..af3aef105 100644 --- a/runtime/queries/javascript/injections.scm +++ b/runtime/queries/javascript/injections.scm @@ -22,7 +22,15 @@ ((regex_pattern) @injection.content (#set! injection.language "regex")) - ; Parse JSDoc annotations in comments +; Parse JSDoc annotations in multiline comments ((comment) @injection.content - (#set! injection.language "jsdoc")) + (#set! injection.language "jsdoc") + (#match? @injection.content "^/\\*+")) + +; Parse general tags in single line comments + +((comment) @injection.content + (#set! injection.language "comment") + (#match? @injection.content "^//")) + diff --git a/runtime/queries/jsdoc/injections.scm b/runtime/queries/jsdoc/injections.scm new file mode 100644 index 000000000..877b671d6 --- /dev/null +++ b/runtime/queries/jsdoc/injections.scm @@ -0,0 +1,5 @@ +; Parse general comment tags + +((document) @injection.content + (#set! injection.include-children) + (#set! injection.language "comment")) \ No newline at end of file From 8c64c3dfa3be911344ae0acaeee8018ffccde643 Mon Sep 17 00:00:00 2001 From: Mathis Brossier Date: Mon, 20 Jun 2022 20:41:34 +0200 Subject: [PATCH 359/861] mouse selection now uses character indexing (#2839) --- helix-term/src/ui/editor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index f074d9f1c..192fa1804 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -1046,7 +1046,7 @@ impl EditorView { let mut selection = doc.selection(view.id).clone(); let primary = selection.primary_mut(); - *primary = Range::new(primary.anchor, pos); + *primary = primary.put_cursor(doc.text().slice(..), pos, true); doc.set_selection(view.id, selection); EventResult::Consumed(None) } From 0ad10ce6f7159bc857eef1445a6c5cc28ae6a249 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 20 Jun 2022 18:15:50 -0500 Subject: [PATCH 360/861] rewrite language configuration docs (#2838) This change moves the configuration tables from the Adding Languages guide into the overall Languages section. It also adds more detailed documentation on the `language-server` configuration key and fixes a typo in the "mylang" example (the scope was `scope.mylang` instead of `source.mylang`). --- book/src/guides/adding_languages.md | 67 ++---------------- book/src/languages.md | 106 +++++++++++++++++++++++----- 2 files changed, 97 insertions(+), 76 deletions(-) diff --git a/book/src/guides/adding_languages.md b/book/src/guides/adding_languages.md index 0cd6c27bb..5be7a2644 100644 --- a/book/src/guides/adding_languages.md +++ b/book/src/guides/adding_languages.md @@ -2,40 +2,8 @@ ## Language configuration -To add a new language, you need to add a `language` entry to the -[`languages.toml`][languages.toml] found in the root of the repository; -this `languages.toml` file is included at compilation time, and is -distinct from the `languages.toml` file in the user's [configuration -directory](../configuration.md). - -```toml -[[language]] -name = "mylang" -scope = "scope.mylang" -injection-regex = "^mylang$" -file-types = ["mylang", "myl"] -comment-token = "#" -indent = { tab-width = 2, unit = " " } -language-server = { command = "mylang-lsp", args = ["--stdio"] } -``` - -These are the available keys and descriptions for the file. - -| Key | Description | -| ---- | ----------- | -| `name` | The name of the language | -| `scope` | A string like `source.js` that identifies the language. Currently, we strive to match the scope names used by popular TextMate grammars and by the Linguist library. Usually `source.` or `text.` in case of markup languages | -| `injection-regex` | regex pattern that will be tested against a language name in order to determine whether this language should be used for a potential [language injection][treesitter-language-injection] site. | -| `file-types` | The filetypes of the language, for example `["yml", "yaml"]`. Extensions and full file names are supported. | -| `shebangs` | The interpreters from the shebang line, for example `["sh", "bash"]` | -| `roots` | A set of marker files to look for when trying to find the workspace root. For example `Cargo.lock`, `yarn.lock` | -| `auto-format` | Whether to autoformat this language when saving | -| `diagnostic-severity` | Minimal severity of diagnostic for it to be displayed. (Allowed values: `Error`, `Warning`, `Info`, `Hint`) | -| `comment-token` | The token to use as a comment-token | -| `indent` | The indent to use. Has sub keys `tab-width` and `unit` | -| `language-server` | The Language Server to run. Has sub keys `command` and `args` | -| `config` | Language Server configuration | -| `grammar` | The tree-sitter grammar to use (defaults to the value of `name`) | +To add a new language, you need to add a `[[language]]` entry to the +`languages.toml` (see the [language configuration section]). When adding a new language or Language Server configuration for an existing language, run `cargo xtask docgen` to add the new configuration to the @@ -45,32 +13,12 @@ When adding a Language Server configuration, be sure to update the ## Grammar configuration -If a tree-sitter grammar is available for the language, add a new `grammar` +If a tree-sitter grammar is available for the language, add a new `[[grammar]]` entry to `languages.toml`. -```toml -[[grammar]] -name = "mylang" -source = { git = "https://github.com/example/mylang", rev = "a250c4582510ff34767ec3b7dcdd3c24e8c8aa68" } -``` - -Grammar configuration takes these keys: - -| Key | Description | -| --- | ----------- | -| `name` | The name of the tree-sitter grammar | -| `source` | The method of fetching the grammar - a table with a schema defined below | - -Where `source` is a table with either these keys when using a grammar from a -git repository: - -| Key | Description | -| --- | ----------- | -| `git` | A git remote URL from which the grammar should be cloned | -| `rev` | The revision (commit hash or tag) which should be fetched | -| `subpath` | A path within the grammar directory which should be built. Some grammar repositories host multiple grammars (for example `tree-sitter-typescript` and `tree-sitter-ocaml`) in subdirectories. This key is used to point `hx --grammar build` to the correct path for compilation. When omitted, the root of repository is used | - -Or a `path` key with an absolute path to a locally available grammar directory. +You may use the `source.path` key rather than `source.git` with an absolute path +to a locally available grammar for testing, but switch to `source.git` before +submitting a pull request. ## Queries @@ -91,8 +39,7 @@ the last matching query supersedes the ones before it. See - If a parser is segfaulting or you want to remove the parser, make sure to remove the compiled parser in `runtime/grammar/.so` -[treesitter-language-injection]: https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection -[languages.toml]: https://github.com/helix-editor/helix/blob/master/languages.toml +[language configuration section]: ../languages.md [neovim-query-precedence]: https://github.com/helix-editor/helix/pull/1170#issuecomment-997294090 [install-lsp-wiki]: https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers [lang-support]: ../lang-support.md diff --git a/book/src/languages.md b/book/src/languages.md index 8c27785e2..a9d5bea83 100644 --- a/book/src/languages.md +++ b/book/src/languages.md @@ -1,10 +1,17 @@ # Languages -Language-specific settings and settings for particular language servers can be configured in a `languages.toml` file placed in your [configuration directory](./configuration.md). Helix actually uses two `languages.toml` files, the [first one](https://github.com/helix-editor/helix/blob/master/languages.toml) is in the main helix repository; it contains the default settings for each language and is included in the helix binary at compile time. Users who want to see the available settings and options can either reference the helix repo's `languages.toml` file, or consult the table in the [adding languages](./guides/adding_languages.md) section. +Language-specific settings and settings for language servers are configured +in `languages.toml` files. -A local `languages.toml` can be created within a `.helix` directory. Its settings will be merged with both the global and default configs. +## `languages.toml` files -Changes made to the `languages.toml` file in a user's [configuration directory](./configuration.md) are merged with helix's defaults on start-up, such that a user's settings will take precedence over defaults in the event of a collision. For example, the default `languages.toml` sets rust's `auto-format` to `true`. If a user wants to disable auto-format, they can change the `languages.toml` in their [configuration directory](./configuration.md) to make the rust entry read like the example below; the new key/value pair `auto-format = false` will override the default when the two sets of settings are merged on start-up: +There are three possible `languages.toml` files. The first is compiled into +Helix and lives in the [Helix repository](https://github.com/helix-editor/helix/blob/master/languages.toml). +This provides the default configurations for languages and language servers. + +You may define a `languages.toml` in your [configuration directory](./configuration.md) +which overrides values from the built-in language configuration. For example +to disable auto-LSP-formatting in Rust: ```toml # in /helix/languages.toml @@ -14,9 +21,60 @@ name = "rust" auto-format = false ``` -## LSP formatting options +Language configuration may also be overridden local to a project by creating +a `languages.toml` file under a `.helix` directory. Its settings will be merged +with the language configuration in the configuration directory and the built-in +configuration. + +## Language configuration -Use `format` field to pass extra formatting options to [Document Formatting Requests](https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-16.md#document-formatting-request--leftwards_arrow_with_hook). +Each language is configured by adding a `[[language]]` section to a +`languages.toml` file. For example: + +```toml +[[language]] +name = "mylang" +scope = "source.mylang" +injection-regex = "^mylang$" +file-types = ["mylang", "myl"] +comment-token = "#" +indent = { tab-width = 2, unit = " " } +language-server = { command = "mylang-lsp", args = ["--stdio"] } +``` + +These configuration keys are available: + +| Key | Description | +| ---- | ----------- | +| `name` | The name of the language | +| `scope` | A string like `source.js` that identifies the language. Currently, we strive to match the scope names used by popular TextMate grammars and by the Linguist library. Usually `source.` or `text.` in case of markup languages | +| `injection-regex` | regex pattern that will be tested against a language name in order to determine whether this language should be used for a potential [language injection][treesitter-language-injection] site. | +| `file-types` | The filetypes of the language, for example `["yml", "yaml"]`. Extensions and full file names are supported. | +| `shebangs` | The interpreters from the shebang line, for example `["sh", "bash"]` | +| `roots` | A set of marker files to look for when trying to find the workspace root. For example `Cargo.lock`, `yarn.lock` | +| `auto-format` | Whether to autoformat this language when saving | +| `diagnostic-severity` | Minimal severity of diagnostic for it to be displayed. (Allowed values: `Error`, `Warning`, `Info`, `Hint`) | +| `comment-token` | The token to use as a comment-token | +| `indent` | The indent to use. Has sub keys `tab-width` and `unit` | +| `language-server` | The Language Server to run. See the Language Server configuration section below. | +| `config` | Language Server configuration | +| `grammar` | The tree-sitter grammar to use (defaults to the value of `name`) | + +### Language Server configuration + +The `language-server` field takes the following keys: + +| Key | Description | +| --- | ----------- | +| `command` | The name of the language server binary to execute. Binaries must be in `$PATH` | +| `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 | + +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 +[Document Formatting Requests](https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-16.md#document-formatting-request--leftwards_arrow_with_hook). +For example with typescript: ```toml [[language]] @@ -26,23 +84,37 @@ auto-format = true config = { format = { "semicolons" = "insert", "insertSpaceBeforeFunctionParenthesis" = true } } ``` -## Tree-sitter grammars +## Tree-sitter grammar configuration -Tree-sitter grammars can also be configured in `languages.toml`: +The source for a language's tree-sitter grammar is specified in a `[[grammar]]` +section in `languages.toml`. For example: ```toml -# in /helix/languages.toml - [[grammar]] -name = "rust" -source = { git = "https://github.com/tree-sitter/tree-sitter-rust", rev = "a250c4582510ff34767ec3b7dcdd3c24e8c8aa68" } - -[[grammar]] -name = "c" -source = { path = "/path/to/tree-sitter-c" } +name = "mylang" +source = { git = "https://github.com/example/mylang", rev = "a250c4582510ff34767ec3b7dcdd3c24e8c8aa68" } ``` -You may use a top-level `use-grammars` key to control which grammars are fetched and built. +Grammar configuration takes these keys: + +| Key | Description | +| --- | ----------- | +| `name` | The name of the tree-sitter grammar | +| `source` | The method of fetching the grammar - a table with a schema defined below | + +Where `source` is a table with either these keys when using a grammar from a +git repository: + +| Key | Description | +| --- | ----------- | +| `git` | A git remote URL from which the grammar should be cloned | +| `rev` | The revision (commit hash or tag) which should be fetched | +| `subpath` | A path within the grammar directory which should be built. Some grammar repositories host multiple grammars (for example `tree-sitter-typescript` and `tree-sitter-ocaml`) in subdirectories. This key is used to point `hx --grammar build` to the correct path for compilation. When omitted, the root of repository is used | + +### Choosing grammars + +You may use a top-level `use-grammars` key to control which grammars are +fetched and built when using `hx --grammar fetch` and `hx --grammar build`. ```toml # Note: this key must come **before** the [[language]] and [[grammar]] sections @@ -52,3 +124,5 @@ use-grammars = { except = [ "yaml", "json" ] } ``` When omitted, all grammars are fetched and built. + +[treesitter-language-injection]: https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection From 009f8c4d3bdf56c9c5b0ba9489864d4d242a6e01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Jun 2022 08:08:45 +0530 Subject: [PATCH 361/861] build(deps): bump anyhow from 1.0.57 to 1.0.58 (#2843) Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.57 to 1.0.58. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.57...1.0.58) --- updated-dependencies: - dependency-name: anyhow dependency-type: direct:production update-type: version-update:semver-patch ... 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 ddf267906..6257c9ea1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" [[package]] name = "arc-swap" From 43027d91046f79d6dc495b351cdcbfd3819cd9e1 Mon Sep 17 00:00:00 2001 From: A-Walrus <58790821+A-Walrus@users.noreply.github.com> Date: Tue, 21 Jun 2022 05:39:43 +0300 Subject: [PATCH 362/861] Display highest severity diagnostic in gutter (#2835) * Display highest severity diagnostic in gutter * Improve gutter diagnostic performance Very slight improvement (doesn't really make a difference), iterates over the diagnostics of the line once instead of twice. * Add comment justifying unwrap --- helix-view/src/gutter.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index eb6796bec..05fec7589 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -26,7 +26,18 @@ pub fn diagnostic<'doc>( Box::new(move |line: usize, _selected: bool, out: &mut String| { use helix_core::diagnostic::Severity; if let Ok(index) = diagnostics.binary_search_by_key(&line, |d| d.line) { - let diagnostic = &diagnostics[index]; + let after = diagnostics[index..].iter().take_while(|d| d.line == line); + + let before = diagnostics[..index] + .iter() + .rev() + .take_while(|d| d.line == line); + + let diagnostics_on_line = after.chain(before); + + // This unwrap is safe because the iterator cannot be empty as it contains at least the item found by the binary search. + let diagnostic = diagnostics_on_line.max_by_key(|d| d.severity).unwrap(); + write!(out, "●").unwrap(); return Some(match diagnostic.severity { Some(Severity::Error) => error, From 67f6c85792dbdbe0ff3f9328874c7ab23ff5569b Mon Sep 17 00:00:00 2001 From: "Connor Lay (Clay)" Date: Sat, 18 Jun 2022 14:24:01 -0700 Subject: [PATCH 363/861] text-objects: add test capture & elixir queries --- book/src/guides/textobject.md | 2 ++ book/src/keymap.md | 2 ++ book/src/usage.md | 1 + helix-term/src/commands.rs | 12 ++++++++++++ helix-term/src/keymap/default.rs | 2 ++ runtime/queries/elixir/textobjects.scm | 8 +++++++- 6 files changed, 26 insertions(+), 1 deletion(-) diff --git a/book/src/guides/textobject.md b/book/src/guides/textobject.md index cccd4bbf0..8a2173547 100644 --- a/book/src/guides/textobject.md +++ b/book/src/guides/textobject.md @@ -20,6 +20,8 @@ The following [captures][tree-sitter-captures] are recognized: | `function.around` | | `class.inside` | | `class.around` | +| `test.inside` | +| `test.around` | | `parameter.inside` | | `comment.inside` | | `comment.around` | diff --git a/book/src/keymap.md b/book/src/keymap.md index fef76efb6..7efbdd237 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -282,6 +282,8 @@ Mappings in the style of [vim-unimpaired](https://github.com/tpope/vim-unimpaire | `[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` | | `]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/book/src/usage.md b/book/src/usage.md index ad21a94c9..ba631b623 100644 --- a/book/src/usage.md +++ b/book/src/usage.md @@ -143,6 +143,7 @@ Currently supported: `word`, `surround`, `function`, `class`, `parameter`. | `c` | Class | | `a` | Argument/parameter | | `o` | Comment | +| `t` | Test | > 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 c9c8e6a98..046351a36 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -395,6 +395,8 @@ impl MappableCommand { goto_prev_parameter, "Goto previous parameter", goto_next_comment, "Goto next comment", goto_prev_comment, "Goto previous comment", + goto_next_test, "Goto next test", + goto_prev_test, "Goto previous test", goto_next_paragraph, "Goto next paragraph", goto_prev_paragraph, "Goto previous paragraph", dap_launch, "Launch debug target", @@ -4098,6 +4100,14 @@ fn goto_prev_comment(cx: &mut Context) { goto_ts_object_impl(cx, "comment", Direction::Backward) } +fn goto_next_test(cx: &mut Context) { + goto_ts_object_impl(cx, "test", Direction::Forward) +} + +fn goto_prev_test(cx: &mut Context) { + goto_ts_object_impl(cx, "test", Direction::Backward) +} + fn select_textobject_around(cx: &mut Context) { select_textobject(cx, textobject::TextObject::Around); } @@ -4141,6 +4151,7 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) { 'f' => textobject_treesitter("function", range), 'a' => textobject_treesitter("parameter", range), 'o' => textobject_treesitter("comment", range), + 't' => textobject_treesitter("test", range), 'p' => textobject::textobject_paragraph(text, range, objtype, count), 'm' => textobject::textobject_surround_closest(text, range, objtype, count), // TODO: cancel new ranges if inconsistent surround matches across lines @@ -4170,6 +4181,7 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) { ("f", "Function (tree-sitter)"), ("a", "Argument/parameter (tree-sitter)"), ("o", "Comment (tree-sitter)"), + ("t", "Test (tree-sitter)"), ("m", "Matching delimiter under 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 0f0b09dd5..c36951172 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -104,6 +104,7 @@ pub fn default() -> HashMap { "c" => goto_prev_class, "a" => goto_prev_parameter, "o" => goto_prev_comment, + "t" => goto_prev_test, "p" => goto_prev_paragraph, "space" => add_newline_above, }, @@ -114,6 +115,7 @@ pub fn default() -> HashMap { "c" => goto_next_class, "a" => goto_next_parameter, "o" => goto_next_comment, + "t" => goto_next_test, "p" => goto_next_paragraph, "space" => add_newline_below, }, diff --git a/runtime/queries/elixir/textobjects.scm b/runtime/queries/elixir/textobjects.scm index 52a6f66de..227a52f4e 100644 --- a/runtime/queries/elixir/textobjects.scm +++ b/runtime/queries/elixir/textobjects.scm @@ -16,7 +16,7 @@ (pair value: (_) @function.inside))?)? (do_block (_)* @function.inside)?) - (#match? @_keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp|test|describe|setup)$")) @function.around + (#match? @_keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$")) @function.around (anonymous_function (stab_clause right: (body) @function.inside)) @function.around @@ -25,3 +25,9 @@ target: (identifier) @_keyword (do_block (_)* @class.inside)) (#match? @_keyword "^(defmodule|defprotocol|defimpl)$")) @class.around + +((call + target: (identifier) @_keyword + (arguments ((string) . (_)?)) + (do_block (_)* @test.inside)?) + (#match? @_keyword "^(test|describe)$")) @test.around From 9f676dab57e6421dd4c33a7ccf16e12cfb9b62cf Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 19 Jun 2022 21:36:33 -0500 Subject: [PATCH 364/861] add test textobjects queries for erlang,gleam,go,python,rust --- runtime/queries/erlang/textobjects.scm | 8 ++++++++ runtime/queries/gleam/textobjects.scm | 5 +++++ runtime/queries/go/textobjects.scm | 5 +++++ runtime/queries/python/textobjects.scm | 5 +++++ runtime/queries/rust/textobjects.scm | 14 ++++++++++++++ 5 files changed, 37 insertions(+) diff --git a/runtime/queries/erlang/textobjects.scm b/runtime/queries/erlang/textobjects.scm index c46b5c6f6..013629f88 100644 --- a/runtime/queries/erlang/textobjects.scm +++ b/runtime/queries/erlang/textobjects.scm @@ -6,3 +6,11 @@ (stab_clause body: (_) @function.inside)) @function.around (comment (comment_content) @comment.inside) @comment.around + +; EUnit test names. +; (CommonTest cases are not recognizable by syntax alone.) +((function_clause + name: (atom) @_name + pattern: (arguments (_)? @parameter.inside) + body: (_) @test.inside) @test.around + (#match? @_name "_test$")) diff --git a/runtime/queries/gleam/textobjects.scm b/runtime/queries/gleam/textobjects.scm index b382f4bd0..19cd0dcf9 100644 --- a/runtime/queries/gleam/textobjects.scm +++ b/runtime/queries/gleam/textobjects.scm @@ -4,3 +4,8 @@ (anonymous_function body: (function_body) @function.inside) @function.around + +((function + name: (identifier) @_name + body: (function_body) @test.inside) @test.around + (#match? @_name "_test$")) diff --git a/runtime/queries/go/textobjects.scm b/runtime/queries/go/textobjects.scm index a48ccce18..df1b0866f 100644 --- a/runtime/queries/go/textobjects.scm +++ b/runtime/queries/go/textobjects.scm @@ -26,3 +26,8 @@ (comment) @comment.inside (comment)+ @comment.around + +((function_declaration + name: (identifier) @_name + body: (block)? @test.inside) @test.around + (#match? @_name "^Test")) diff --git a/runtime/queries/python/textobjects.scm b/runtime/queries/python/textobjects.scm index 5c6a61d17..966e47446 100644 --- a/runtime/queries/python/textobjects.scm +++ b/runtime/queries/python/textobjects.scm @@ -16,3 +16,8 @@ (comment) @comment.inside (comment)+ @comment.around + +((function_definition + name: (identifier) @_name + body: (block)? @test.inside) @test.around + (#match? @_name "^test_")) diff --git a/runtime/queries/rust/textobjects.scm b/runtime/queries/rust/textobjects.scm index ba86050b5..94c8c9f8b 100644 --- a/runtime/queries/rust/textobjects.scm +++ b/runtime/queries/rust/textobjects.scm @@ -77,3 +77,17 @@ (line_comment)+ @comment.around (block_comment) @comment.around + +(; #[test] + (attribute_item + (meta_item + (identifier) @_test_attribute)) + ; allow other attributes like #[should_panic] and comments + [ + (attribute_item) + (line_comment) + ]* + ; the test function + (function_item + body: (_) @test.inside) @test.around + (#eq? @_test_attribute "test")) From fa4934cff9aa5b86b907e218313a7b370962ae67 Mon Sep 17 00:00:00 2001 From: Mathspy Date: Tue, 21 Jun 2022 12:35:25 -0400 Subject: [PATCH 365/861] Default rulers color to red (#2669) * Default rulers color to red Currently if the theme a user is using doesn't have `ui.virtual.rulers` set and they set up a ruler it just fails silently making it really hard to figure out what went wrong. Did they set incorrectly set the ruler? Are they using an outdated version of Helix that doesn't support rulers? This happened to me today, I even switched to the default theme with the assumption that maybe my theme just doesn't have the rulers setup properly and it still didn't work. Not sure if this is a good idea or not, feel free to suggest better alternatives! * Use builtin Style methods instead of Bevy style defaults Co-authored-by: Michael Davis * Only default the style if there's no ui or ui.virtual * Update themes style from ui.virtual to ui.virtual.whitespace * Revert ui.virtual change in onelight theme * Prefer unwrap_or_else Co-authored-by: Michael Davis --- helix-term/src/ui/editor.rs | 6 ++++-- runtime/themes/base16_default_dark.toml | 2 +- runtime/themes/base16_default_light.toml | 2 +- runtime/themes/base16_terminal.toml | 2 +- runtime/themes/bogster.toml | 2 +- runtime/themes/boo_berry.toml | 2 +- runtime/themes/catppuccin.toml | 2 +- runtime/themes/dark_plus.toml | 2 +- runtime/themes/dracula.toml | 2 +- runtime/themes/everforest_dark.toml | 2 +- runtime/themes/everforest_light.toml | 2 +- runtime/themes/gruvbox.toml | 2 +- runtime/themes/gruvbox_light.toml | 2 +- runtime/themes/ingrid.toml | 2 +- runtime/themes/monokai.toml | 2 +- runtime/themes/monokai_pro.toml | 2 +- runtime/themes/monokai_pro_machine.toml | 2 +- runtime/themes/monokai_pro_octagon.toml | 2 +- runtime/themes/monokai_pro_ristretto.toml | 2 +- runtime/themes/monokai_pro_spectrum.toml | 2 +- runtime/themes/nord.toml | 2 +- runtime/themes/rose_pine.toml | 2 +- runtime/themes/rose_pine_dawn.toml | 2 +- runtime/themes/serika-dark.toml | 2 +- runtime/themes/serika-light.toml | 2 +- runtime/themes/snazzy.toml | 2 +- runtime/themes/solarized_dark.toml | 2 +- runtime/themes/solarized_light.toml | 2 +- runtime/themes/spacebones_light.toml | 2 +- 29 files changed, 32 insertions(+), 30 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 192fa1804..a8027d1b8 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -20,7 +20,7 @@ use helix_core::{ use helix_view::{ document::{Mode, SCRATCH_BUFFER_NAME}, editor::{CompleteAction, CursorShapeConfig}, - graphics::{CursorKind, Modifier, Rect, Style}, + graphics::{Color, CursorKind, Modifier, Rect, Style}, input::KeyEvent, keyboard::{KeyCode, KeyModifiers}, Document, Editor, Theme, View, @@ -170,7 +170,9 @@ impl EditorView { theme: &Theme, ) { let editor_rulers = &editor.config().rulers; - let ruler_theme = theme.get("ui.virtual.ruler"); + let ruler_theme = theme + .try_get("ui.virtual.ruler") + .unwrap_or_else(|| Style::default().bg(Color::Red)); let rulers = doc .language_config() diff --git a/runtime/themes/base16_default_dark.toml b/runtime/themes/base16_default_dark.toml index 7516e492e..33252330e 100644 --- a/runtime/themes/base16_default_dark.toml +++ b/runtime/themes/base16_default_dark.toml @@ -1,7 +1,7 @@ # Author: RayGervais "ui.background" = { bg = "base00" } -"ui.virtual" = "base03" +"ui.virtual.whitespace" = "base03" "ui.menu" = { fg = "base05", bg = "base01" } "ui.menu.selected" = { fg = "base01", bg = "base04" } "ui.linenr" = { fg = "base03", bg = "base01" } diff --git a/runtime/themes/base16_default_light.toml b/runtime/themes/base16_default_light.toml index 368474591..bc2b8e671 100644 --- a/runtime/themes/base16_default_light.toml +++ b/runtime/themes/base16_default_light.toml @@ -12,7 +12,7 @@ "ui.statusline" = { fg = "base04", bg = "base01" } "ui.cursor" = { fg = "base04", modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "base05", modifiers = ["reversed"] } -"ui.virtual" = "base03" +"ui.virtual.whitespace" = "base03" "ui.text" = "base05" "operator" = "base05" "ui.text.focus" = "base05" diff --git a/runtime/themes/base16_terminal.toml b/runtime/themes/base16_terminal.toml index 928488168..3a1d48457 100644 --- a/runtime/themes/base16_terminal.toml +++ b/runtime/themes/base16_terminal.toml @@ -13,7 +13,7 @@ "ui.help" = { fg = "white", bg = "black" } "ui.cursor" = { fg = "light-gray", modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "light-gray", modifiers = ["reversed"] } -"ui.virtual" = "light-gray" +"ui.virtual.whitespace" = "light-gray" "variable" = "light-red" "constant.numeric" = "yellow" "constant" = "yellow" diff --git a/runtime/themes/bogster.toml b/runtime/themes/bogster.toml index df3a7f315..76e24648b 100644 --- a/runtime/themes/bogster.toml +++ b/runtime/themes/bogster.toml @@ -53,7 +53,7 @@ "ui.text" = { fg = "#e5ded6" } "ui.text.focus" = { fg = "#e5ded6", modifiers= ["bold"] } -"ui.virtual" = "#627d9d" +"ui.virtual.whitespace" = "#627d9d" "ui.selection" = { bg = "#313f4e" } # "ui.cursor.match" # TODO might want to override this because dimmed is not widely supported diff --git a/runtime/themes/boo_berry.toml b/runtime/themes/boo_berry.toml index 5cd253974..a79b75c59 100644 --- a/runtime/themes/boo_berry.toml +++ b/runtime/themes/boo_berry.toml @@ -44,7 +44,7 @@ "ui.menu" = { fg = "lilac", bg = "berry_saturated" } "ui.menu.selected" = { fg = "mint", bg = "berry_saturated" } "ui.selection" = { bg = "berry_saturated" } -"ui.virtual" = { fg = "berry_desaturated" } +"ui.virtual.whitespace" = { fg = "berry_desaturated" } "diff.plus" = { fg = "mint" } "diff.delta" = { fg = "gold" } diff --git a/runtime/themes/catppuccin.toml b/runtime/themes/catppuccin.toml index da9be4fbd..eaa4ba517 100644 --- a/runtime/themes/catppuccin.toml +++ b/runtime/themes/catppuccin.toml @@ -48,7 +48,7 @@ label = "peach" "ui.text" = { fg = "pink" } "ui.text.focus" = { fg = "white" } -"ui.virtual" = { fg = "gray_0" } +"ui.virtual.whitespace" = { fg = "gray_0" } "ui.selection" = { bg = "#540099" } "ui.selection.primary" = { bg = "#540099" } diff --git a/runtime/themes/dark_plus.toml b/runtime/themes/dark_plus.toml index c785dd388..957ca61d4 100644 --- a/runtime/themes/dark_plus.toml +++ b/runtime/themes/dark_plus.toml @@ -78,7 +78,7 @@ "ui.text" = { fg = "text" } "ui.text.focus" = { fg = "white" } -"ui.virtual" = { fg = "dark_gray" } +"ui.virtual.whitespace" = { fg = "dark_gray" } "ui.virtual.ruler" = { bg = "borders" } "warning" = { fg = "gold2" } diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index e32c3117b..72b37d027 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -36,7 +36,7 @@ "ui.text" = { fg = "foreground" } "ui.text.focus" = { fg = "cyan" } "ui.window" = { fg = "foreground" } -"ui.virtual" = { fg = "comment" } +"ui.virtual.whitespace" = { fg = "comment" } "error" = { fg = "red" } "warning" = { fg = "cyan" } diff --git a/runtime/themes/everforest_dark.toml b/runtime/themes/everforest_dark.toml index 5b6d1b7cf..ef74ea9e8 100644 --- a/runtime/themes/everforest_dark.toml +++ b/runtime/themes/everforest_dark.toml @@ -70,7 +70,7 @@ "ui.menu" = { fg = "fg", bg = "bg2" } "ui.menu.selected" = { fg = "bg0", bg = "green" } "ui.selection" = { bg = "bg3" } -"ui.virtual" = "grey0" +"ui.virtual.whitespace" = "grey0" "hint" = "blue" "info" = "aqua" diff --git a/runtime/themes/everforest_light.toml b/runtime/themes/everforest_light.toml index b03701653..60557ba0c 100644 --- a/runtime/themes/everforest_light.toml +++ b/runtime/themes/everforest_light.toml @@ -70,7 +70,7 @@ "ui.menu" = { fg = "fg", bg = "bg2" } "ui.menu.selected" = { fg = "bg0", bg = "green" } "ui.selection" = { bg = "bg3" } -"ui.virtual" = "grey0" +"ui.virtual.whitespace" = "grey0" "hint" = "blue" "info" = "aqua" diff --git a/runtime/themes/gruvbox.toml b/runtime/themes/gruvbox.toml index 6de35244a..48fb14fa1 100644 --- a/runtime/themes/gruvbox.toml +++ b/runtime/themes/gruvbox.toml @@ -53,7 +53,7 @@ "ui.cursor.match" = { bg = "bg2" } "ui.menu" = { fg = "fg1", bg = "bg2" } "ui.menu.selected" = { fg = "bg2", bg = "blue1", modifiers = ["bold"] } -"ui.virtual" = "bg2" +"ui.virtual.whitespace" = "bg2" "diagnostic" = { modifiers = ["underlined"] } diff --git a/runtime/themes/gruvbox_light.toml b/runtime/themes/gruvbox_light.toml index 2930dff0d..02a32dec4 100644 --- a/runtime/themes/gruvbox_light.toml +++ b/runtime/themes/gruvbox_light.toml @@ -54,7 +54,7 @@ "ui.cursor.match" = { bg = "bg2" } "ui.menu" = { fg = "fg1", bg = "bg2" } "ui.menu.selected" = { fg = "bg2", bg = "blue1", modifiers = ["bold"] } -"ui.virtual" = "bg2" +"ui.virtual.whitespace" = "bg2" "diagnostic" = { modifiers = ["underlined"] } diff --git a/runtime/themes/ingrid.toml b/runtime/themes/ingrid.toml index 79b749b14..587137045 100644 --- a/runtime/themes/ingrid.toml +++ b/runtime/themes/ingrid.toml @@ -53,7 +53,7 @@ "ui.text" = { fg = "#7B91B3" } "ui.text.focus" = { fg = "#250E07", modifiers= ["bold"] } -"ui.virtual" = "#A6B6CE" +"ui.virtual.whitespace" = "#A6B6CE" "ui.selection" = { bg = "#540099" } # "ui.cursor.match" # TODO might want to override this because dimmed is not widely supported diff --git a/runtime/themes/monokai.toml b/runtime/themes/monokai.toml index 3fb1fadc3..5a8906154 100644 --- a/runtime/themes/monokai.toml +++ b/runtime/themes/monokai.toml @@ -32,7 +32,7 @@ "attribute" = { fg = "fn_declaration" } "comment" = { fg = "#88846F" } -"ui.virtual" = "#88846F" +"ui.virtual.whitespace" = "#88846F" "string" = { fg = "#e6db74" } "constant.character" = { fg = "#e6db74" } diff --git a/runtime/themes/monokai_pro.toml b/runtime/themes/monokai_pro.toml index 5580a33c6..7c457d458 100644 --- a/runtime/themes/monokai_pro.toml +++ b/runtime/themes/monokai_pro.toml @@ -6,7 +6,7 @@ "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } "ui.menu" = { fg = "base8", bg = "base3" } "ui.menu.selected" = { fg = "base2", bg = "yellow" } -"ui.virtual" = "base5" +"ui.virtual.whitespace" = "base5" "info" = "base8" "hint" = "base8" diff --git a/runtime/themes/monokai_pro_machine.toml b/runtime/themes/monokai_pro_machine.toml index abbe5bdca..bfc7031d3 100644 --- a/runtime/themes/monokai_pro_machine.toml +++ b/runtime/themes/monokai_pro_machine.toml @@ -6,7 +6,7 @@ "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } "ui.menu" = { fg = "base8", bg = "base3" } "ui.menu.selected" = { fg = "base2", bg = "yellow" } -"ui.virtual" = "base5" +"ui.virtual.whitespace" = "base5" "info" = "base8" "hint" = "base8" diff --git a/runtime/themes/monokai_pro_octagon.toml b/runtime/themes/monokai_pro_octagon.toml index b249cfe21..889e76249 100644 --- a/runtime/themes/monokai_pro_octagon.toml +++ b/runtime/themes/monokai_pro_octagon.toml @@ -6,7 +6,7 @@ "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } "ui.menu" = { fg = "base8", bg = "base3" } "ui.menu.selected" = { fg = "base2", bg = "yellow" } -"ui.virtual" = "base5" +"ui.virtual.whitespace" = "base5" "info" = "base8" "hint" = "base8" diff --git a/runtime/themes/monokai_pro_ristretto.toml b/runtime/themes/monokai_pro_ristretto.toml index cd4cbd8e9..f8ad8422e 100644 --- a/runtime/themes/monokai_pro_ristretto.toml +++ b/runtime/themes/monokai_pro_ristretto.toml @@ -6,7 +6,7 @@ "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } "ui.menu" = { fg = "base8", bg = "base3" } "ui.menu.selected" = { fg = "base2", bg = "yellow" } -"ui.virtual" = "base5" +"ui.virtual.whitespace" = "base5" "info" = "base8" "hint" = "base8" diff --git a/runtime/themes/monokai_pro_spectrum.toml b/runtime/themes/monokai_pro_spectrum.toml index 4160a15e1..9f5864fcc 100644 --- a/runtime/themes/monokai_pro_spectrum.toml +++ b/runtime/themes/monokai_pro_spectrum.toml @@ -6,7 +6,7 @@ "ui.text.focus" = { fg = "yellow", modifiers= ["bold"] } "ui.menu" = { fg = "base8", bg = "base3" } "ui.menu.selected" = { fg = "base2", bg = "yellow" } -"ui.virtual" = "base5" +"ui.virtual.whitespace" = "base5" "info" = "base8" "hint" = "base8" diff --git a/runtime/themes/nord.toml b/runtime/themes/nord.toml index a61c17157..3b994bb59 100644 --- a/runtime/themes/nord.toml +++ b/runtime/themes/nord.toml @@ -4,7 +4,7 @@ "ui.text.focus" = { fg = "nord8", modifiers= ["bold"] } "ui.menu" = { fg = "nord6", bg = "#232d38" } "ui.menu.selected" = { fg = "nord8", bg = "nord2" } -"ui.virtual" = "gray" +"ui.virtual.whitespace" = "gray" "info" = "nord8" "hint" = "nord8" diff --git a/runtime/themes/rose_pine.toml b/runtime/themes/rose_pine.toml index f05758801..09b1e25c9 100644 --- a/runtime/themes/rose_pine.toml +++ b/runtime/themes/rose_pine.toml @@ -14,7 +14,7 @@ "ui.text" = { fg = "text" } "ui.text.focus" = { fg = "foam", modifiers = ["bold"]} "ui.text.info" = {fg = "pine", modifiers = ["bold"]} -"ui.virtual" = "highlight" +"ui.virtual.whitespace" = "highlight" "operator" = "rose" "variable" = "text" "constant.numeric" = "iris" diff --git a/runtime/themes/rose_pine_dawn.toml b/runtime/themes/rose_pine_dawn.toml index 5ad304e38..9ba0959db 100644 --- a/runtime/themes/rose_pine_dawn.toml +++ b/runtime/themes/rose_pine_dawn.toml @@ -14,7 +14,7 @@ "ui.text" = { fg = "text" } "ui.text.focus" = { fg = "foam", modifiers = ["bold"]} "ui.text.info" = {fg = "pine", modifiers = ["bold"]} -"ui.virtual" = "highlight" +"ui.virtual.whitespace" = "highlight" "operator" = "rose" "variable" = "text" "number" = "iris" diff --git a/runtime/themes/serika-dark.toml b/runtime/themes/serika-dark.toml index 3dd982d19..3b4bc60f5 100644 --- a/runtime/themes/serika-dark.toml +++ b/runtime/themes/serika-dark.toml @@ -50,7 +50,7 @@ "ui.menu" = { fg = "fg", bg = "bg2" } "ui.menu.selected" = { fg = "bg0", bg = "bg_yellow" } "ui.selection" = { bg = "bg3" } -"ui.virtual" = "grey2" +"ui.virtual.whitespace" = "grey2" "hint" = "blue" "info" = "aqua" diff --git a/runtime/themes/serika-light.toml b/runtime/themes/serika-light.toml index 67c8328b7..3b0f8fb47 100644 --- a/runtime/themes/serika-light.toml +++ b/runtime/themes/serika-light.toml @@ -50,7 +50,7 @@ "ui.menu" = { fg = "bg0", bg = "bg3" } "ui.menu.selected" = { fg = "bg0", bg = "bg_yellow" } "ui.selection" = { fg = "bg0", bg = "bg3" } -"ui.virtual" = { fg = "bg2" } +"ui.virtual.whitespace" = { fg = "bg2" } "hint" = "blue" "info" = "aqua" diff --git a/runtime/themes/snazzy.toml b/runtime/themes/snazzy.toml index c0547f33b..da47fd636 100644 --- a/runtime/themes/snazzy.toml +++ b/runtime/themes/snazzy.toml @@ -38,7 +38,7 @@ "ui.text" = { fg = "foreground" } "ui.text.focus" = { fg = "cyan" } "ui.window" = { fg = "foreground" } -"ui.virtual" = { fg = "comment" } +"ui.virtual.whitespace" = { fg = "comment" } "error" = { fg = "red" } "warning" = { fg = "cyan" } diff --git a/runtime/themes/solarized_dark.toml b/runtime/themes/solarized_dark.toml index f15e1fa0d..d8126f6ea 100644 --- a/runtime/themes/solarized_dark.toml +++ b/runtime/themes/solarized_dark.toml @@ -39,7 +39,7 @@ # 背景 "ui.background" = { bg = "base03" } -"ui.virtual" = { fg = "base01" } +"ui.virtual.whitespace" = { fg = "base01" } # 行号栏 "ui.linenr" = { fg = "base0", bg = "base02" } diff --git a/runtime/themes/solarized_light.toml b/runtime/themes/solarized_light.toml index eec4220db..cd1028bda 100644 --- a/runtime/themes/solarized_light.toml +++ b/runtime/themes/solarized_light.toml @@ -40,7 +40,7 @@ # background "ui.background" = { bg = "base03" } -"ui.virtual" = { fg = "base01" } +"ui.virtual.whitespace" = { fg = "base01" } # 行号栏 # line number column diff --git a/runtime/themes/spacebones_light.toml b/runtime/themes/spacebones_light.toml index 80a193751..b088e2d3e 100644 --- a/runtime/themes/spacebones_light.toml +++ b/runtime/themes/spacebones_light.toml @@ -64,7 +64,7 @@ "ui.cursor.match" = { bg = "bg3" } "ui.menu" = { fg = "fg1", bg = "bg2" } "ui.menu.selected" = { fg = "#655370", bg = "#d1dcdf", modifiers = ["bold"] } -"ui.virtual" = "bg2" +"ui.virtual.whitespace" = "bg2" "diagnostic" = { modifiers = ["underlined"] } From 6a3f7f2c399f0b92cef97b0c85ebe976fd7cfcac Mon Sep 17 00:00:00 2001 From: Matthew Toohey Date: Tue, 21 Jun 2022 12:36:36 -0400 Subject: [PATCH 366/861] feat: make `move_vertically` aware of tabs and wide characters (#2620) * feat: make `move_vertically` aware of tabs and wide characters * refactor: replace unnecessary checked_sub with comparison * refactor: leave pos_at_coords unchanged and introduce separate pos_at_visual_coords * style: include comment to explain `pos_at_visual_coords` breaking condition * refactor: use `pos_at_visual_coords` in `text_pos_at_screen_coords` * feat: make `copy_selection_on_line` aware of wide characters --- helix-core/src/lib.rs | 4 +- helix-core/src/movement.rs | 43 ++++++++------- helix-core/src/position.rs | 106 +++++++++++++++++++++++++++++++++++-- helix-term/src/commands.rs | 26 ++++----- helix-view/src/view.rs | 53 +++++-------------- 5 files changed, 153 insertions(+), 79 deletions(-) diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 627b73bb0..735a62c1b 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -63,7 +63,9 @@ pub type Tendril = SmartString; pub use {regex, tree_sitter}; pub use graphemes::RopeGraphemes; -pub use position::{coords_at_pos, pos_at_coords, visual_coords_at_pos, Position}; +pub use position::{ + coords_at_pos, pos_at_coords, pos_at_visual_coords, visual_coords_at_pos, Position, +}; pub use selection::{Range, Selection}; pub use smallvec::{smallvec, SmallVec}; pub use syntax::Syntax; diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs index f60b3c83f..2155f77a4 100644 --- a/helix-core/src/movement.rs +++ b/helix-core/src/movement.rs @@ -5,16 +5,15 @@ use tree_sitter::{Node, QueryCursor}; use crate::{ chars::{categorize_char, char_is_line_ending, CharCategory}, - coords_at_pos, graphemes::{ next_grapheme_boundary, nth_next_grapheme_boundary, nth_prev_grapheme_boundary, prev_grapheme_boundary, }, line_ending::rope_is_line_ending, - pos_at_coords, + pos_at_visual_coords, syntax::LanguageConfiguration, textobject::TextObject, - Position, Range, RopeSlice, + visual_coords_at_pos, Position, Range, RopeSlice, }; #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -35,6 +34,7 @@ pub fn move_horizontally( dir: Direction, count: usize, behaviour: Movement, + _: usize, ) -> Range { let pos = range.cursor(slice); @@ -54,15 +54,12 @@ pub fn move_vertically( dir: Direction, count: usize, behaviour: Movement, + tab_width: usize, ) -> Range { let pos = range.cursor(slice); // Compute the current position's 2d coordinates. - // TODO: switch this to use `visual_coords_at_pos` rather than - // `coords_at_pos` as this will cause a jerky movement when the visual - // position does not match, like moving from a line with tabs/CJK to - // a line without - let Position { row, col } = coords_at_pos(slice, pos); + let Position { row, col } = visual_coords_at_pos(slice, pos, tab_width); let horiz = range.horiz.unwrap_or(col as u32); // Compute the new position. @@ -71,7 +68,7 @@ pub fn move_vertically( Direction::Backward => row.saturating_sub(count), }; let new_col = col.max(horiz as usize); - let new_pos = pos_at_coords(slice, Position::new(new_row, new_col), true); + let new_pos = pos_at_visual_coords(slice, Position::new(new_row, new_col), tab_width); // Special-case to avoid moving to the end of the last non-empty line. if behaviour == Movement::Extend && slice.line(new_row).len_chars() == 0 { @@ -446,6 +443,8 @@ pub fn goto_treesitter_object( mod test { use ropey::Rope; + use crate::{coords_at_pos, pos_at_coords}; + use super::*; const SINGLE_LINE_SAMPLE: &str = "This is a simple alphabetic line"; @@ -472,7 +471,7 @@ mod test { assert_eq!( coords_at_pos( slice, - move_vertically(slice, range, Direction::Forward, 1, Movement::Move).head + move_vertically(slice, range, Direction::Forward, 1, Movement::Move, 4).head ), (1, 3).into() ); @@ -496,7 +495,7 @@ mod test { ]; for ((direction, amount), coordinates) in moves_and_expected_coordinates { - range = move_horizontally(slice, range, direction, amount, Movement::Move); + range = move_horizontally(slice, range, direction, amount, Movement::Move, 0); assert_eq!(coords_at_pos(slice, range.head), coordinates.into()) } } @@ -522,7 +521,7 @@ mod test { ]; for ((direction, amount), coordinates) in moves_and_expected_coordinates { - range = move_horizontally(slice, range, direction, amount, Movement::Move); + range = move_horizontally(slice, range, direction, amount, Movement::Move, 0); assert_eq!(coords_at_pos(slice, range.head), coordinates.into()); assert_eq!(range.head, range.anchor); } @@ -544,7 +543,7 @@ mod test { ]; for (direction, amount) in moves { - range = move_horizontally(slice, range, direction, amount, Movement::Extend); + range = move_horizontally(slice, range, direction, amount, Movement::Extend, 0); assert_eq!(range.anchor, original_anchor); } } @@ -568,7 +567,7 @@ mod test { ]; for ((direction, amount), coordinates) in moves_and_expected_coordinates { - range = move_vertically(slice, range, direction, amount, Movement::Move); + range = move_vertically(slice, range, direction, amount, Movement::Move, 4); assert_eq!(coords_at_pos(slice, range.head), coordinates.into()); assert_eq!(range.head, range.anchor); } @@ -602,8 +601,8 @@ mod test { for ((axis, direction, amount), coordinates) in moves_and_expected_coordinates { range = match axis { - Axis::H => move_horizontally(slice, range, direction, amount, Movement::Move), - Axis::V => move_vertically(slice, range, direction, amount, Movement::Move), + Axis::H => move_horizontally(slice, range, direction, amount, Movement::Move, 0), + Axis::V => move_vertically(slice, range, direction, amount, Movement::Move, 4), }; assert_eq!(coords_at_pos(slice, range.head), coordinates.into()); assert_eq!(range.head, range.anchor); @@ -627,18 +626,18 @@ mod test { let moves_and_expected_coordinates = [ // Places cursor at the fourth kana. ((Axis::H, Direction::Forward, 4), (0, 4)), - // Descent places cursor at the 4th character. - ((Axis::V, Direction::Forward, 1usize), (1, 4)), - // Moving back 1 character. - ((Axis::H, Direction::Backward, 1usize), (1, 3)), + // Descent places cursor at the 8th character. + ((Axis::V, Direction::Forward, 1usize), (1, 8)), + // Moving back 2 characters. + ((Axis::H, Direction::Backward, 2usize), (1, 6)), // Jumping back up 1 line. ((Axis::V, Direction::Backward, 1usize), (0, 3)), ]; for ((axis, direction, amount), coordinates) in moves_and_expected_coordinates { range = match axis { - Axis::H => move_horizontally(slice, range, direction, amount, Movement::Move), - Axis::V => move_vertically(slice, range, direction, amount, Movement::Move), + Axis::H => move_horizontally(slice, range, direction, amount, Movement::Move, 0), + Axis::V => move_vertically(slice, range, direction, amount, Movement::Move, 4), }; assert_eq!(coords_at_pos(slice, range.head), coordinates.into()); assert_eq!(range.head, range.anchor); diff --git a/helix-core/src/position.rs b/helix-core/src/position.rs index ce37300a4..f456eb988 100644 --- a/helix-core/src/position.rs +++ b/helix-core/src/position.rs @@ -109,9 +109,6 @@ pub fn visual_coords_at_pos(text: RopeSlice, pos: usize, tab_width: usize) -> Po /// with left-side block-cursor positions, as this prevents the the block cursor /// from jumping to the next line. Otherwise you typically want it to be `false`, /// such as when dealing with raw anchor/head positions. -/// -/// TODO: this should be changed to work in terms of visual row/column, not -/// graphemes. pub fn pos_at_coords(text: RopeSlice, coords: Position, limit_before_line_ending: bool) -> usize { let Position { mut row, col } = coords; if limit_before_line_ending { @@ -135,6 +132,43 @@ pub fn pos_at_coords(text: RopeSlice, coords: Position, limit_before_line_ending line_start + col_char_offset } +/// Convert visual (line, column) coordinates to a character index. +/// +/// If the `line` coordinate is beyond the end of the file, the EOF +/// position will be returned. +/// +/// If the `column` coordinate is past the end of the given line, the +/// line-end position (in this case, just before the line ending +/// character) will be returned. +pub fn pos_at_visual_coords(text: RopeSlice, coords: Position, tab_width: usize) -> usize { + let Position { mut row, col } = coords; + row = row.min(text.len_lines() - 1); + let line_start = text.line_to_char(row); + let line_end = line_end_char_index(&text, row); + + let mut col_char_offset = 0; + let mut cols_remaining = col; + for grapheme in RopeGraphemes::new(text.slice(line_start..line_end)) { + let grapheme_width = if grapheme == "\t" { + tab_width - ((col - cols_remaining) % tab_width) + } else { + let grapheme = Cow::from(grapheme); + grapheme_width(&grapheme) + }; + + // If pos is in the middle of a wider grapheme (tab for example) + // return the starting offset. + if grapheme_width > cols_remaining { + break; + } + + cols_remaining -= grapheme_width; + col_char_offset += grapheme.chars().count(); + } + + line_start + col_char_offset +} + #[cfg(test)] mod test { use super::*; @@ -305,4 +339,70 @@ mod test { assert_eq!(pos_at_coords(slice, (0, 10).into(), true), 0); assert_eq!(pos_at_coords(slice, (10, 10).into(), true), 0); } + + #[test] + fn test_pos_at_visual_coords() { + let text = Rope::from("ḧëḷḷö\nẅöṛḷḋ"); + let slice = text.slice(..); + assert_eq!(pos_at_visual_coords(slice, (0, 0).into(), 4), 0); + assert_eq!(pos_at_visual_coords(slice, (0, 5).into(), 4), 5); // position on \n + assert_eq!(pos_at_visual_coords(slice, (0, 6).into(), 4), 5); // position after \n + assert_eq!(pos_at_visual_coords(slice, (1, 0).into(), 4), 6); // position on w + assert_eq!(pos_at_visual_coords(slice, (1, 1).into(), 4), 7); // position on o + assert_eq!(pos_at_visual_coords(slice, (1, 4).into(), 4), 10); // position on d + + // Test with wide characters. + let text = Rope::from("今日はいい\n"); + let slice = text.slice(..); + assert_eq!(pos_at_visual_coords(slice, (0, 0).into(), 4), 0); + assert_eq!(pos_at_visual_coords(slice, (0, 1).into(), 4), 0); + assert_eq!(pos_at_visual_coords(slice, (0, 2).into(), 4), 1); + assert_eq!(pos_at_visual_coords(slice, (0, 3).into(), 4), 1); + assert_eq!(pos_at_visual_coords(slice, (0, 4).into(), 4), 2); + assert_eq!(pos_at_visual_coords(slice, (0, 5).into(), 4), 2); + assert_eq!(pos_at_visual_coords(slice, (0, 6).into(), 4), 3); + assert_eq!(pos_at_visual_coords(slice, (0, 7).into(), 4), 3); + assert_eq!(pos_at_visual_coords(slice, (0, 8).into(), 4), 4); + assert_eq!(pos_at_visual_coords(slice, (0, 9).into(), 4), 4); + // assert_eq!(pos_at_visual_coords(slice, (0, 10).into(), 4, false), 5); + // assert_eq!(pos_at_visual_coords(slice, (0, 10).into(), 4, true), 5); + assert_eq!(pos_at_visual_coords(slice, (1, 0).into(), 4), 6); + + // Test with grapheme clusters. + let text = Rope::from("a̐éö̲\r\n"); + let slice = text.slice(..); + assert_eq!(pos_at_visual_coords(slice, (0, 0).into(), 4), 0); + assert_eq!(pos_at_visual_coords(slice, (0, 1).into(), 4), 2); + assert_eq!(pos_at_visual_coords(slice, (0, 2).into(), 4), 4); + assert_eq!(pos_at_visual_coords(slice, (0, 3).into(), 4), 7); // \r\n is one char here + assert_eq!(pos_at_visual_coords(slice, (0, 4).into(), 4), 7); + assert_eq!(pos_at_visual_coords(slice, (1, 0).into(), 4), 9); + + // Test with wide-character grapheme clusters. + let text = Rope::from("किमपि"); + // 2 - 1 - 2 codepoints + // TODO: delete handling as per https://news.ycombinator.com/item?id=20058454 + let slice = text.slice(..); + assert_eq!(pos_at_visual_coords(slice, (0, 0).into(), 4), 0); + assert_eq!(pos_at_visual_coords(slice, (0, 1).into(), 4), 0); + assert_eq!(pos_at_visual_coords(slice, (0, 2).into(), 4), 2); + assert_eq!(pos_at_visual_coords(slice, (0, 3).into(), 4), 3); + + // Test with tabs. + let text = Rope::from("\tHello\n"); + let slice = text.slice(..); + assert_eq!(pos_at_visual_coords(slice, (0, 0).into(), 4), 0); + assert_eq!(pos_at_visual_coords(slice, (0, 1).into(), 4), 0); + assert_eq!(pos_at_visual_coords(slice, (0, 2).into(), 4), 0); + assert_eq!(pos_at_visual_coords(slice, (0, 3).into(), 4), 0); + assert_eq!(pos_at_visual_coords(slice, (0, 4).into(), 4), 1); + assert_eq!(pos_at_visual_coords(slice, (0, 5).into(), 4), 2); + + // Test out of bounds. + let text = Rope::new(); + let slice = text.slice(..); + assert_eq!(pos_at_visual_coords(slice, (10, 0).into(), 4), 0); + assert_eq!(pos_at_visual_coords(slice, (0, 10).into(), 4), 0); + assert_eq!(pos_at_visual_coords(slice, (10, 10).into(), 4), 0); + } } diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 046351a36..d7937ff59 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -16,14 +16,14 @@ use helix_core::{ line_ending::{get_line_ending_of_str, line_end_char_index, str_is_line_ending}, match_brackets, movement::{self, Direction}, - object, pos_at_coords, + object, pos_at_coords, pos_at_visual_coords, regex::{self, Regex, RegexBuilder}, search::{self, CharMatcher}, selection, shellwords, surround, textobject, tree_sitter::Node, unicode::width::UnicodeWidthChar, - LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, Selection, SmallVec, Tendril, - Transaction, + visual_coords_at_pos, LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, Selection, + SmallVec, Tendril, Transaction, }; use helix_view::{ clipboard::ClipboardType, @@ -511,7 +511,7 @@ fn no_op(_cx: &mut Context) {} fn move_impl(cx: &mut Context, move_fn: F, dir: Direction, behaviour: Movement) where - F: Fn(RopeSlice, Range, Direction, usize, Movement) -> Range, + F: Fn(RopeSlice, Range, Direction, usize, Movement, usize) -> Range, { let count = cx.count(); let (view, doc) = current!(cx.editor); @@ -520,7 +520,7 @@ where let selection = doc .selection(view.id) .clone() - .transform(|range| move_fn(text, range, dir, count, behaviour)); + .transform(|range| move_fn(text, range, dir, count, behaviour, doc.tab_width())); doc.set_selection(view.id, selection); } @@ -1412,9 +1412,10 @@ fn copy_selection_on_line(cx: &mut Context, direction: Direction) { range.head }; - // TODO: this should use visual offsets / pos_at_screen_coords - let head_pos = coords_at_pos(text, head); - let anchor_pos = coords_at_pos(text, range.anchor); + let tab_width = doc.tab_width(); + + let head_pos = visual_coords_at_pos(text, head, tab_width); + let anchor_pos = visual_coords_at_pos(text, range.anchor, tab_width); let height = std::cmp::max(head_pos.row, anchor_pos.row) - std::cmp::min(head_pos.row, anchor_pos.row) @@ -1444,12 +1445,13 @@ fn copy_selection_on_line(cx: &mut Context, direction: Direction) { break; } - let anchor = pos_at_coords(text, Position::new(anchor_row, anchor_pos.col), true); - let head = pos_at_coords(text, Position::new(head_row, head_pos.col), true); + let anchor = + pos_at_visual_coords(text, Position::new(anchor_row, anchor_pos.col), tab_width); + let head = pos_at_visual_coords(text, Position::new(head_row, head_pos.col), tab_width); // skip lines that are too short - if coords_at_pos(text, anchor).col == anchor_pos.col - && coords_at_pos(text, head).col == head_pos.col + if visual_coords_at_pos(text, anchor, tab_width).col == anchor_pos.col + && visual_coords_at_pos(text, head, tab_width).col == head_pos.col { if is_primary { primary_index = ranges.len(); diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index a496fe330..bfae12a44 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -1,15 +1,9 @@ -use std::borrow::Cow; - use crate::{ graphics::Rect, gutter::{self, Gutter}, Document, DocumentId, ViewId, }; -use helix_core::{ - graphemes::{grapheme_width, RopeGraphemes}, - line_ending::line_end_char_index, - visual_coords_at_pos, Position, RopeSlice, Selection, -}; +use helix_core::{pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection}; use std::fmt; @@ -251,44 +245,21 @@ impl View { return None; } - let line_number = (row - inner.y) as usize + self.offset.row; - - if line_number > text.len_lines() - 1 { + let text_row = (row - inner.y) as usize + self.offset.row; + if text_row > text.len_lines() - 1 { return Some(text.len_chars()); } - let mut pos = text.line_to_char(line_number); - - let current_line = text.line(line_number); - - let target = (column - inner.x) as usize + self.offset.col; - let mut col = 0; - - // TODO: extract this part as pos_at_visual_coords - for grapheme in RopeGraphemes::new(current_line) { - if col >= target { - break; - } - - let width = if grapheme == "\t" { - tab_width - (col % tab_width) - } else { - let grapheme = Cow::from(grapheme); - grapheme_width(&grapheme) - }; - - // If pos is in the middle of a wider grapheme (tab for example) - // return the starting offset. - if col + width > target { - break; - } + let text_col = (column - inner.x) as usize + self.offset.col; - col += width; - // TODO: use byte pos that converts back to char pos? - pos += grapheme.chars().count(); - } - - Some(pos.min(line_end_char_index(&text.slice(..), line_number))) + Some(pos_at_visual_coords( + *text, + Position { + row: text_row, + col: text_col, + }, + tab_width, + )) } /// Translates a screen position to position in the text document. From 8c4c923e803fe5c0d4da4dcc3223c0fc8001bd7a Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sat, 2 Apr 2022 14:09:13 +0530 Subject: [PATCH 367/861] Add indent guides support --- helix-term/src/ui/editor.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index a8027d1b8..7455f6256 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -401,6 +401,23 @@ impl EditorView { let text_style = theme.get("ui.text"); let whitespace_style = theme.get("ui.virtual.whitespace"); + let mut is_in_indent_area = true; + let mut last_line_indent_level = 0; + let indent_style = theme + .try_get("ui.virtual.indent-guide") + .unwrap_or_else(|| theme.get("comment")); + + let draw_indent_guides = |indent_level, line, surface: &mut Surface| { + for i in 0..(indent_level / tab_width as u16) { + surface.set_string( + viewport.x + (i * tab_width as u16) - offset.col as u16, + viewport.y + line, + "│", + indent_style, + ); + } + }; + 'outer: for event in highlights { match event { HighlightEvent::HighlightStart(span) => { @@ -453,8 +470,18 @@ impl EditorView { ); } + // This is an empty line; draw indent guides at previous line's + // indent level to avoid breaking the guides on blank lines. + if visual_x == 0 { + draw_indent_guides(last_line_indent_level, line, surface); + } else if is_in_indent_area { + // A line with whitespace only + draw_indent_guides(visual_x, line, surface); + } + visual_x = 0; line += 1; + is_in_indent_area = true; // TODO: with proper iter this shouldn't be necessary if line >= viewport.height { @@ -499,6 +526,11 @@ impl EditorView { }, ); } + if is_in_indent_area && !(grapheme == " " || grapheme == "\t") { + draw_indent_guides(visual_x, line, surface); + is_in_indent_area = false; + last_line_indent_level = visual_x; + } visual_x = visual_x.saturating_add(width as u16); } From 924b4ebb39df71d8499e7d38015c2423a89a3e49 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sat, 2 Apr 2022 16:40:13 +0530 Subject: [PATCH 368/861] Add theme scopes for indent guides --- book/src/themes.md | 1 + runtime/themes/onedark.toml | 3 +++ theme.toml | 2 ++ 3 files changed, 6 insertions(+) diff --git a/book/src/themes.md b/book/src/themes.md index 4c0eda228..57a8d5d1f 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -228,6 +228,7 @@ These scopes are used for theming the editor interface. | `ui.text.info` | The key: command text in `ui.popup.info` boxes | | `ui.virtual.ruler` | Ruler columns (see the [`editor.rulers` config][rulers-config])| | `ui.virtual.whitespace` | Visible white-space characters | +| `ui.virtual.indent-guide` | Vertical indent width guides | | `ui.menu` | Code and command completion menus | | `ui.menu.selected` | Selected autocomplete item | | `ui.selection` | For selections in the editing area | diff --git a/runtime/themes/onedark.toml b/runtime/themes/onedark.toml index 280f6914d..d0cbb9494 100644 --- a/runtime/themes/onedark.toml +++ b/runtime/themes/onedark.toml @@ -47,6 +47,8 @@ diagnostic = { modifiers = ["underlined"] } "error" = { fg = "red", modifiers = ["bold"] } "ui.background" = { bg = "black" } +"ui.virtual" = { fg = "faint-gray" } +"ui.virtual.indent-guide" = { fg = "faint-gray" } "ui.virtual.whitespace" = { fg = "light-gray" } "ui.virtual.ruler" = { bg = "gray" } @@ -85,5 +87,6 @@ white = "#ABB2BF" black = "#282C34" light-black = "#2C323C" gray = "#3E4452" +faint-gray = "#3B4048" light-gray = "#5C6370" linenr = "#4B5263" diff --git a/theme.toml b/theme.toml index 7a518b2fe..8e550f922 100644 --- a/theme.toml +++ b/theme.toml @@ -56,6 +56,8 @@ label = "honey" "ui.text.focus" = { fg = "white" } "ui.virtual" = { fg = "comet" } +"ui.virtual.indent-guide" = { fg = "comet" } + "ui.selection" = { bg = "#540099" } "ui.selection.primary" = { bg = "#540099" } # TODO: namespace ui.cursor as ui.selection.cursor? From 8ad0b83e306ff6dfc1499d3e6d25b2fd36a096a4 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Tue, 31 May 2022 22:43:08 +0530 Subject: [PATCH 369/861] Make indent guides configurable --- book/src/configuration.md | 17 +++++++++++++++++ helix-term/src/ui/editor.rs | 20 ++++++++++++-------- helix-term/src/ui/picker.rs | 2 +- helix-view/src/editor.rs | 19 +++++++++++++++++++ 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index 4d7e440a0..3fa9b307a 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -167,3 +167,20 @@ nbsp = "⍽" tab = "→" newline = "⏎" ``` + +### `[editor.indent-guides]` Section + +Options for rendering vertical indent guides. + +| Key | Description | Default | +| --- | --- | --- | +| `render` | Whether to render indent guides. | `false` | +| `character` | Literal character to use for rendering the indent guide | `│` | + +Example: + +```toml +[editor.indent-guides] +render = true +character = "╎" +``` diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 7455f6256..ec25ce948 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -131,7 +131,7 @@ impl EditorView { surface, theme, highlights, - &editor.config().whitespace, + &editor.config(), ); Self::render_gutter(editor, doc, view, view.area, surface, theme, is_focused); Self::render_rulers(editor, doc, view, inner, surface, theme); @@ -373,8 +373,9 @@ impl EditorView { surface: &mut Surface, theme: &Theme, highlights: H, - whitespace: &helix_view::editor::WhitespaceConfig, + config: &helix_view::editor::Config, ) { + let whitespace = &config.whitespace; use helix_view::editor::WhitespaceRenderValue; // It's slightly more efficient to produce a full RopeSlice from the Rope, then slice that a bunch @@ -397,22 +398,25 @@ impl EditorView { } else { " ".to_string() }; + let indent_guide_char = config.indent_guides.character.to_string(); let text_style = theme.get("ui.text"); let whitespace_style = theme.get("ui.virtual.whitespace"); let mut is_in_indent_area = true; let mut last_line_indent_level = 0; - let indent_style = theme - .try_get("ui.virtual.indent-guide") - .unwrap_or_else(|| theme.get("comment")); + let indent_style = theme.get("ui.virtual.indent-guide"); let draw_indent_guides = |indent_level, line, surface: &mut Surface| { + if !config.indent_guides.render { + return; + } + for i in 0..(indent_level / tab_width as u16) { surface.set_string( viewport.x + (i * tab_width as u16) - offset.col as u16, viewport.y + line, - "│", + &indent_guide_char, indent_style, ); } @@ -491,7 +495,7 @@ impl EditorView { let grapheme = Cow::from(grapheme); let is_whitespace; - let (grapheme, width) = if grapheme == "\t" { + let (display_grapheme, width) = if grapheme == "\t" { is_whitespace = true; // make sure we display tab as appropriate amount of spaces let visual_tab_width = tab_width - (visual_x as usize % tab_width); @@ -518,7 +522,7 @@ impl EditorView { surface.set_string( viewport.x + visual_x - offset.col as u16, viewport.y + line, - grapheme, + display_grapheme, if is_whitespace { style.patch(whitespace_style) } else { diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 9ffe45c1b..95ec84058 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -240,7 +240,7 @@ impl Component for FilePicker { surface, &cx.editor.theme, highlights, - &cx.editor.config().whitespace, + &cx.editor.config(), ); // highlight the line diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index ac19def10..b9de57e16 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -156,6 +156,8 @@ pub struct Config { pub rulers: Vec, #[serde(default)] pub whitespace: WhitespaceConfig, + /// Vertical indent width guides. + pub indent_guides: IndentGuidesConfig, } #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] @@ -364,6 +366,22 @@ impl Default for WhitespaceCharacters { } } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(default)] +pub struct IndentGuidesConfig { + pub render: bool, + pub character: char, +} + +impl Default for IndentGuidesConfig { + fn default() -> Self { + Self { + render: false, + character: '│', + } + } +} + impl Default for Config { fn default() -> Self { Self { @@ -391,6 +409,7 @@ impl Default for Config { lsp: LspConfig::default(), rulers: Vec::new(), whitespace: WhitespaceConfig::default(), + indent_guides: IndentGuidesConfig::default(), } } } From 8b67acf130e12cf8aaa439fe19ea7b8917db300b Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Tue, 21 Jun 2022 22:16:50 +0530 Subject: [PATCH 370/861] Format keys identically in statusline and command palette (#2790) The command palette previously used + as a delimiter for denoting a single key in a key sequence, (like C+w). This was at odds with how the statusline displayed them with pending keys (like ). This patch changes the palette formatting to the statusline formatting --- helix-term/src/commands.rs | 5 ++--- helix-term/src/ui/editor.rs | 8 +------- helix-view/src/input.rs | 27 ++++++++++++++++++++++++++- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index d7937ff59..d4fa34e0f 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2237,9 +2237,8 @@ pub fn command_palette(cx: &mut Context) { .iter() .map(|bind| { bind.iter() - .map(|key| key.to_string()) - .collect::>() - .join("+") + .map(|key| key.key_sequence_format()) + .collect::() }) .collect::>() .join(", ") diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index ec25ce948..dc6362c6e 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -13,7 +13,6 @@ use helix_core::{ }, movement::Direction, syntax::{self, HighlightEvent}, - unicode::segmentation::UnicodeSegmentation, unicode::width::UnicodeWidthStr, LineEnding, Position, Range, Selection, Transaction, }; @@ -1391,12 +1390,7 @@ impl Component for EditorView { disp.push_str(&count.to_string()) } for key in self.keymaps.pending() { - let s = key.to_string(); - if s.graphemes(true).count() > 1 { - disp.push_str(&format!("<{}>", s)); - } else { - disp.push_str(&s); - } + disp.push_str(&key.key_sequence_format()); } if let Some(pseudo_pending) = &cx.editor.pseudo_pending { disp.push_str(pseudo_pending.as_str()) diff --git a/helix-view/src/input.rs b/helix-view/src/input.rs index 5b8679305..093006c4f 100644 --- a/helix-view/src/input.rs +++ b/helix-view/src/input.rs @@ -1,6 +1,6 @@ //! Input event handling, currently backed by crossterm. use anyhow::{anyhow, Error}; -use helix_core::unicode::width::UnicodeWidthStr; +use helix_core::unicode::{segmentation::UnicodeSegmentation, width::UnicodeWidthStr}; use serde::de::{self, Deserialize, Deserializer}; use std::fmt; @@ -22,6 +22,31 @@ impl KeyEvent { _ => None, } } + + /// Format the key in such a way that a concatenated sequence + /// of keys can be read easily. + /// + /// ``` + /// # use std::str::FromStr; + /// # use helix_view::input::KeyEvent; + /// + /// let k = KeyEvent::from_str("w").unwrap().key_sequence_format(); + /// assert_eq!(k, "w"); + /// + /// let k = KeyEvent::from_str("C-w").unwrap().key_sequence_format(); + /// assert_eq!(k, ""); + /// + /// let k = KeyEvent::from_str(" ").unwrap().key_sequence_format(); + /// assert_eq!(k, ""); + /// ``` + pub fn key_sequence_format(&self) -> String { + let s = self.to_string(); + if s.graphemes(true).count() > 1 { + format!("<{}>", s) + } else { + s + } + } } pub(crate) mod keys { From ce85b9716df5e1ea804994202687f19cd711ae1b Mon Sep 17 00:00:00 2001 From: ath3 <45574139+ath3@users.noreply.github.com> Date: Tue, 21 Jun 2022 18:48:01 +0200 Subject: [PATCH 371/861] Enable shellwords for Windows (with escaping disabled) (#2767) --- helix-core/src/shellwords.rs | 52 ++++++++++++++++++++++++++------ helix-term/src/commands/typed.rs | 10 +----- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/helix-core/src/shellwords.rs b/helix-core/src/shellwords.rs index 13f6f3e99..4323039ab 100644 --- a/helix-core/src/shellwords.rs +++ b/helix-core/src/shellwords.rs @@ -24,9 +24,13 @@ pub fn shellwords(input: &str) -> Vec> { state = match state { Normal => match c { '\\' => { - escaped.push_str(&input[start..i]); - start = i + 1; - NormalEscaped + if cfg!(unix) { + escaped.push_str(&input[start..i]); + start = i + 1; + NormalEscaped + } else { + Normal + } } '"' => { end = i; @@ -45,9 +49,13 @@ pub fn shellwords(input: &str) -> Vec> { NormalEscaped => Normal, Quoted => match c { '\\' => { - escaped.push_str(&input[start..i]); - start = i + 1; - QuoteEscaped + if cfg!(unix) { + escaped.push_str(&input[start..i]); + start = i + 1; + QuoteEscaped + } else { + Quoted + } } '\'' => { end = i; @@ -58,9 +66,13 @@ pub fn shellwords(input: &str) -> Vec> { QuoteEscaped => Quoted, Dquoted => match c { '\\' => { - escaped.push_str(&input[start..i]); - start = i + 1; - DquoteEscaped + if cfg!(unix) { + escaped.push_str(&input[start..i]); + start = i + 1; + DquoteEscaped + } else { + Dquoted + } } '"' => { end = i; @@ -99,6 +111,25 @@ mod test { use super::*; #[test] + #[cfg(windows)] + fn test_normal() { + let input = r#":o single_word twó wörds \three\ \"with\ escaping\\"#; + let result = shellwords(input); + let expected = vec![ + Cow::from(":o"), + Cow::from("single_word"), + Cow::from("twó"), + Cow::from("wörds"), + Cow::from("\\three\\"), + Cow::from("\\"), + Cow::from("with\\ escaping\\\\"), + ]; + // TODO test is_owned and is_borrowed, once they get stabilized. + assert_eq!(expected, result); + } + + #[test] + #[cfg(unix)] fn test_normal() { let input = r#":o single_word twó wörds \three\ \"with\ escaping\\"#; let result = shellwords(input); @@ -114,6 +145,7 @@ mod test { } #[test] + #[cfg(unix)] fn test_quoted() { let quoted = r#":o 'single_word' 'twó wörds' '' ' ''\three\' \"with\ escaping\\' 'quote incomplete"#; @@ -129,6 +161,7 @@ mod test { } #[test] + #[cfg(unix)] fn test_dquoted() { let dquoted = r#":o "single_word" "twó wörds" "" " ""\three\' \"with\ escaping\\" "dquote incomplete"#; let result = shellwords(dquoted); @@ -143,6 +176,7 @@ mod test { } #[test] + #[cfg(unix)] fn test_mixed() { let dquoted = r#":o single_word 'twó wörds' "\three\' \"with\ escaping\\""no space before"'and after' $#%^@ "%^&(%^" ')(*&^%''a\\\\\b' '"#; let result = shellwords(dquoted); diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index ae3e63af9..58256c7d4 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1802,15 +1802,7 @@ pub fn command_mode(cx: &mut Context) { // Handle typable commands if let Some(cmd) = typed::TYPABLE_COMMAND_MAP.get(parts[0]) { - let args = if cfg!(unix) { - shellwords::shellwords(input) - } else { - // Windows doesn't support POSIX, so fallback for now - parts - .into_iter() - .map(|part| part.into()) - .collect::>() - }; + let args = shellwords::shellwords(input); if let Err(e) = (cmd.fun)(cx, &args[1..], event) { cx.editor.set_error(format!("{}", e)); From 8e8367eea6ff146c7e1097af153398832691e078 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Tue, 21 Jun 2022 22:22:08 +0530 Subject: [PATCH 372/861] Refactor Margin for fine grained control (#2727) --- helix-term/src/commands/lsp.rs | 6 +-- helix-term/src/ui/info.rs | 5 +-- helix-term/src/ui/markdown.rs | 5 +-- helix-term/src/ui/picker.rs | 5 +-- helix-term/src/ui/popup.rs | 9 ++--- helix-term/src/ui/prompt.rs | 5 +-- helix-tui/src/layout.rs | 16 +++----- helix-view/src/graphics.rs | 67 ++++++++++++++++++++++++++++++---- 8 files changed, 75 insertions(+), 43 deletions(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index b6bea8d61..3ee3c54a1 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -287,10 +287,8 @@ pub fn code_action(cx: &mut Context) { }); picker.move_down(); // pre-select the first item - let popup = Popup::new("code-action", picker).margin(helix_view::graphics::Margin { - vertical: 1, - horizontal: 1, - }); + let popup = + Popup::new("code-action", picker).margin(helix_view::graphics::Margin::all(1)); compositor.replace_or_push("code-action", popup); }, ) diff --git a/helix-term/src/ui/info.rs b/helix-term/src/ui/info.rs index 272244c1c..cc6b7483f 100644 --- a/helix-term/src/ui/info.rs +++ b/helix-term/src/ui/info.rs @@ -27,10 +27,7 @@ impl Component for Info { .borders(Borders::ALL) .border_style(popup_style); - let margin = Margin { - vertical: 0, - horizontal: 1, - }; + let margin = Margin::horizontal(1); let inner = block.inner(area).inner(&margin); block.render(area, surface); diff --git a/helix-term/src/ui/markdown.rs b/helix-term/src/ui/markdown.rs index 037e2f134..e3ce2cd5d 100644 --- a/helix-term/src/ui/markdown.rs +++ b/helix-term/src/ui/markdown.rs @@ -323,10 +323,7 @@ impl Component for Markdown { .wrap(Wrap { trim: false }) .scroll((cx.scroll.unwrap_or_default() as u16, 0)); - let margin = Margin { - vertical: 1, - horizontal: 1, - }; + let margin = Margin::all(1); par.render(area.inner(&margin), surface); } diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 95ec84058..ebff98274 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -200,10 +200,7 @@ impl Component for FilePicker { // calculate the inner area inside the box let inner = block.inner(preview_area); // 1 column gap on either side - let margin = Margin { - vertical: 0, - horizontal: 1, - }; + let margin = Margin::horizontal(1); let inner = inner.inner(&margin); block.render(preview_area, surface); diff --git a/helix-term/src/ui/popup.rs b/helix-term/src/ui/popup.rs index 185ec15da..f5b795264 100644 --- a/helix-term/src/ui/popup.rs +++ b/helix-term/src/ui/popup.rs @@ -27,10 +27,7 @@ impl Popup { Self { contents, position: None, - margin: Margin { - vertical: 0, - horizontal: 0, - }, + margin: Margin::none(), size: (0, 0), child_size: (0, 0), scroll: 0, @@ -163,8 +160,8 @@ impl Component for Popup { self.child_size = (width, height); self.size = ( - (width + self.margin.horizontal * 2).min(max_width), - (height + self.margin.vertical * 2).min(max_height), + (width + self.margin.width()).min(max_width), + (height + self.margin.height()).min(max_height), ); // re-clamp scroll offset diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 64154bae3..7744a1614 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -430,10 +430,7 @@ impl Prompt { .borders(Borders::ALL) .border_style(background); - let inner = block.inner(area).inner(&Margin { - vertical: 0, - horizontal: 1, - }); + let inner = block.inner(area).inner(&Margin::horizontal(1)); block.render(area, surface); text.render(inner, surface, cx); diff --git a/helix-tui/src/layout.rs b/helix-tui/src/layout.rs index e6a84aa04..7c72a7789 100644 --- a/helix-tui/src/layout.rs +++ b/helix-tui/src/layout.rs @@ -68,10 +68,7 @@ impl Default for Layout { fn default() -> Layout { Layout { direction: Direction::Vertical, - margin: Margin { - horizontal: 0, - vertical: 0, - }, + margin: Margin::none(), constraints: Vec::new(), } } @@ -87,20 +84,19 @@ impl Layout { } pub fn margin(mut self, margin: u16) -> Layout { - self.margin = Margin { - horizontal: margin, - vertical: margin, - }; + self.margin = Margin::all(margin); self } pub fn horizontal_margin(mut self, horizontal: u16) -> Layout { - self.margin.horizontal = horizontal; + self.margin.left = horizontal; + self.margin.right = horizontal; self } pub fn vertical_margin(mut self, vertical: u16) -> Layout { - self.margin.vertical = vertical; + self.margin.top = vertical; + self.margin.bottom = vertical; self } diff --git a/helix-view/src/graphics.rs b/helix-view/src/graphics.rs index 6d0a92928..7033b7a41 100644 --- a/helix-view/src/graphics.rs +++ b/helix-view/src/graphics.rs @@ -27,8 +27,61 @@ impl Default for CursorKind { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Margin { - pub vertical: u16, - pub horizontal: u16, + pub left: u16, + pub right: u16, + pub top: u16, + pub bottom: u16, +} + +impl Margin { + pub fn none() -> Self { + Self { + left: 0, + right: 0, + top: 0, + bottom: 0, + } + } + + /// Set uniform margin for all sides. + pub fn all(value: u16) -> Self { + Self { + left: value, + right: value, + top: value, + bottom: value, + } + } + + /// Set the margin of left and right sides to specified value. + pub fn horizontal(value: u16) -> Self { + Self { + left: value, + right: value, + top: 0, + bottom: 0, + } + } + + /// Set the margin of top and bottom sides to specified value. + pub fn vertical(value: u16) -> Self { + Self { + left: 0, + right: 0, + top: value, + bottom: value, + } + } + + /// Get the total width of the margin (left + right) + pub fn width(&self) -> u16 { + self.left + self.right + } + + /// Get the total height of the margin (top + bottom) + pub fn height(&self) -> u16 { + self.top + self.bottom + } } /// A simple rectangle used in the computation of the layout and to give widgets an hint about the @@ -141,14 +194,14 @@ impl Rect { } pub fn inner(self, margin: &Margin) -> Rect { - if self.width < 2 * margin.horizontal || self.height < 2 * margin.vertical { + if self.width < margin.width() || self.height < margin.height() { Rect::default() } else { Rect { - x: self.x + margin.horizontal, - y: self.y + margin.vertical, - width: self.width - 2 * margin.horizontal, - height: self.height - 2 * margin.vertical, + x: self.x + margin.left, + y: self.y + margin.top, + width: self.width - margin.width(), + height: self.height - margin.height(), } } } From a17626a822b36d4de3146c2d410f976e19dd189c Mon Sep 17 00:00:00 2001 From: Termina94 <47091253+Termina94@users.noreply.github.com> Date: Tue, 21 Jun 2022 17:52:25 +0100 Subject: [PATCH 373/861] add history suggest to global search (#2717) Co-authored-by: Dean Revell --- helix-term/src/commands.rs | 6 ++++-- helix-view/src/tree.rs | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index d4fa34e0f..68c585b06 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1747,11 +1747,13 @@ fn global_search(cx: &mut Context) { let smart_case = config.search.smart_case; let file_picker_config = config.file_picker.clone(); - let completions = search_completions(cx, None); + let reg = cx.register.unwrap_or('/'); + + let completions = search_completions(cx, Some(reg)); ui::regex_prompt( cx, "global-search:".into(), - None, + Some(reg), move |_editor: &Editor, input: &str| { completions .iter() diff --git a/helix-view/src/tree.rs b/helix-view/src/tree.rs index e6dba9163..3ba85b560 100644 --- a/helix-view/src/tree.rs +++ b/helix-view/src/tree.rs @@ -233,7 +233,6 @@ impl Tree { { if let Some(pos) = container.children.iter().position(|&child| child == index) { container.children.remove(pos); - // TODO: if container now only has one child, remove it and place child in parent if container.children.is_empty() && parent_id != self.root { // if container now empty, remove it From 23b5b1e25aca1dbed87fef18cc72b16852ba40a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Tue, 21 Jun 2022 05:47:48 +0900 Subject: [PATCH 374/861] Remove a couple more unwraps --- helix-term/src/commands.rs | 9 ++++++--- helix-term/src/commands/lsp.rs | 11 +++++++++-- helix-term/src/commands/typed.rs | 6 ++++-- helix-term/src/ui/mod.rs | 3 +-- helix-term/src/ui/prompt.rs | 2 +- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 9239b49ff..a07b51091 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1683,8 +1683,7 @@ fn search_next_or_prev_impl(cx: &mut Context, movement: Movement, direction: Dir let scrolloff = config.scrolloff; let (view, doc) = current!(cx.editor); let registers = &cx.editor.registers; - if let Some(query) = registers.read('/') { - let query = query.last().unwrap(); + if let Some(query) = registers.read('/').and_then(|query| query.last()) { let contents = doc.text().slice(..).to_string(); let search_config = &config.search; let case_insensitive = if search_config.smart_case { @@ -2124,7 +2123,11 @@ fn append_mode(cx: &mut Context) { // Make sure there's room at the end of the document if the last // selection butts up against it. let end = text.len_chars(); - let last_range = doc.selection(view.id).iter().last().unwrap(); + let last_range = doc + .selection(view.id) + .iter() + .last() + .expect("selection should always have at least one range"); if !last_range.is_empty() && last_range.head == end { let transaction = Transaction::change( doc.text(), diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index b8c5e5d1f..6f75fb497 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -61,7 +61,14 @@ fn jump_to_location( return; } }; - let _id = editor.open(&path, action).expect("editor.open failed"); + match editor.open(&path, action) { + Ok(_) => (), + Err(err) => { + let err = format!("failed to open path: {:?}: {:?}", location.uri, err); + editor.set_error(err); + return; + } + } let (view, doc) = current!(editor); let definition_pos = location.range.start; // TODO: convert inside server @@ -491,7 +498,7 @@ fn goto_impl( locations: Vec, offset_encoding: OffsetEncoding, ) { - let cwdir = std::env::current_dir().expect("couldn't determine current directory"); + let cwdir = std::env::current_dir().unwrap_or_default(); match locations.as_slice() { [location] => { diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 19c6a5dc1..70f5fa9fe 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1,3 +1,5 @@ +use std::ops::Deref; + use super::*; use helix_view::editor::{Action, ConfigEvent}; @@ -961,7 +963,7 @@ fn get_option( let key = &args[0].to_lowercase(); let key_error = || anyhow::anyhow!("Unknown key `{}`", key); - let config = serde_json::to_value(&cx.editor.config().clone()).unwrap(); + let config = serde_json::json!(cx.editor.config().deref()); let pointer = format!("/{}", key.replace('.', "/")); let value = config.pointer(&pointer).ok_or_else(key_error)?; @@ -984,7 +986,7 @@ fn set_option( let key_error = || anyhow::anyhow!("Unknown key `{}`", key); let field_error = |_| anyhow::anyhow!("Could not parse field `{}`", arg); - let mut config = serde_json::to_value(&cx.editor.config().clone()).unwrap(); + let mut config = serde_json::json!(&cx.editor.config().deref()); let pointer = format!("/{}", key.replace('.', "/")); let value = config.pointer_mut(&pointer).ok_or_else(key_error)?; diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 76ddaf89e..47a68a18f 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -263,8 +263,7 @@ pub mod completers { pub fn setting(_editor: &Editor, input: &str) -> Vec { static KEYS: Lazy> = Lazy::new(|| { - serde_json::to_value(Config::default()) - .unwrap() + serde_json::json!(Config::default()) .as_object() .unwrap() .keys() diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 7744a1614..beba8ce9a 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -443,7 +443,7 @@ impl Prompt { let input: Cow = if self.line.is_empty() { // latest value in the register list self.history_register - .and_then(|reg| cx.editor.registers.first(reg).cloned()) // TODO: can we avoid cloning? + .and_then(|reg| cx.editor.registers.first(reg)) .map(|entry| entry.into()) .unwrap_or_else(|| Cow::from("")) } else { From 5b3b6ffc9e9b34fbbb39ad33cd29c8dec78ac231 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jun 2022 03:42:22 +0900 Subject: [PATCH 375/861] build(deps): bump regex from 1.5.4 to 1.5.5 (#2851) Bumps [regex](https://github.com/rust-lang/regex) from 1.5.4 to 1.5.5. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.5.4...1.5.5) --- updated-dependencies: - dependency-name: regex dependency-type: direct:production ... 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 2adaf792c..af08f905e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -850,9 +850,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", From 8c86cd56cb90cab495e2a8eac90cadc2954abf10 Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Tue, 21 Jun 2022 23:59:46 +0300 Subject: [PATCH 376/861] build(nix): update flake deps, add default.nix file --- default.nix | 8 ++++++++ flake.lock | 32 ++++++++++++++++---------------- flake.nix | 2 +- shell.nix | 6 +++--- 4 files changed, 28 insertions(+), 20 deletions(-) create mode 100644 default.nix diff --git a/default.nix b/default.nix new file mode 100644 index 000000000..50e7e6819 --- /dev/null +++ b/default.nix @@ -0,0 +1,8 @@ +# Flake's default package for non-flake-enabled nix instances +let + compat = builtins.fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/b4a34015c698c7793d592d66adbab377907a2be8.tar.gz"; + sha256 = "sha256:1qc703yg0babixi6wshn5wm2kgl5y1drcswgszh4xxzbrwkk9sv7"; + }; +in + (import compat {src = ./.;}).defaultNix.default diff --git a/flake.lock b/flake.lock index 50a7b77b0..df059e476 100644 --- a/flake.lock +++ b/flake.lock @@ -19,11 +19,11 @@ "devshell": { "flake": false, "locked": { - "lastModified": 1653917170, - "narHash": "sha256-FyxOnEE/V4PNEcMU62ikY4FfYPo349MOhMM97HS0XEo=", + "lastModified": 1654858401, + "narHash": "sha256-53bw34DtVJ2bnF6WEwy6Tym+qY0pNEiEwARUlvmTZjs=", "owner": "numtide", "repo": "devshell", - "rev": "fc7a3e3adde9bbcab68af6d1e3c6eb738e296a92", + "rev": "f55e05c6d3bbe9acc7363bc8fc739518b2f02976", "type": "github" }, "original": { @@ -73,11 +73,11 @@ ] }, "locked": { - "lastModified": 1654451959, - "narHash": "sha256-yWztC96o8Dw65jDbmNUxV1i61T3uLqvqhC3ziwnB/Fk=", + "lastModified": 1655826285, + "narHash": "sha256-dyrNTVBefSZWKdFNnAW+zUkO5bVo1colvLje4l1XXwA=", "owner": "nix-community", "repo": "dream2nix", - "rev": "90b353682ef927bd39b59085e0dc6b7454888de7", + "rev": "f23add2b9c313c63dea5cff71523a850d29ffddb", "type": "github" }, "original": { @@ -108,16 +108,16 @@ "nixpkgs": [ "nixpkgs" ], - "rustOverlay": [ + "rust-overlay": [ "rust-overlay" ] }, "locked": { - "lastModified": 1654531591, - "narHash": "sha256-DtDAwkl2Pn8w1BW1z2OssT/bWjVhMZQBBpr2uDY7tHY=", + "lastModified": 1655826649, + "narHash": "sha256-C4/7CdB/mzuD9ayWvEA3Jcog6INCq+oUJZxUsIP/GvE=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "c935099d6851d0ff94098e9a12f42147524f0c5b", + "rev": "5cf1685c021c47631a2fb16533c00c8d68afd09e", "type": "github" }, "original": { @@ -128,11 +128,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1654230545, - "narHash": "sha256-8Vlwf0x8ow6pPOK2a04bT+pxIeRnM1+O0Xv9/CuDzRs=", + "lastModified": 1655624069, + "narHash": "sha256-7g1zwTdp35GMTERnSzZMWJ7PG3QdDE8VOX3WsnOkAtM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "236cc2971ac72acd90f0ae3a797f9f83098b17ec", + "rev": "0d68d7c857fe301d49cdcd56130e0beea4ecd5aa", "type": "github" }, "original": { @@ -157,11 +157,11 @@ ] }, "locked": { - "lastModified": 1654483484, - "narHash": "sha256-Ki/sMgrUEj+31P3YMzZZp5Nea7+MQVVTdaRWQVS1PL4=", + "lastModified": 1655779671, + "narHash": "sha256-6feeiGa6fb7ZPVHR71uswkmN1701TAJpwYQA8QffmRk=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "6bc59b9c4ad1cc1089219e935aa727a96d948c5d", + "rev": "8159585609a772b041cce6019d5c21d240709244", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 54637ab9e..c8bd02aa7 100644 --- a/flake.nix +++ b/flake.nix @@ -10,7 +10,7 @@ nixCargoIntegration = { url = "github:yusdacra/nix-cargo-integration"; inputs.nixpkgs.follows = "nixpkgs"; - inputs.rustOverlay.follows = "rust-overlay"; + inputs.rust-overlay.follows = "rust-overlay"; }; }; diff --git a/shell.nix b/shell.nix index d5e1a215b..6bebcc418 100644 --- a/shell.nix +++ b/shell.nix @@ -1,8 +1,8 @@ # Flake's devShell for non-flake-enabled nix instances let - compat = builtins.fetchGit { - url = "https://github.com/edolstra/flake-compat.git"; - rev = "b4a34015c698c7793d592d66adbab377907a2be8"; + compat = builtins.fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/b4a34015c698c7793d592d66adbab377907a2be8.tar.gz"; + sha256 = "sha256:1qc703yg0babixi6wshn5wm2kgl5y1drcswgszh4xxzbrwkk9sv7"; }; in (import compat {src = ./.;}).shellNix.default From b365f2d6143c7a73de703425e00b32b8184d6a02 Mon Sep 17 00:00:00 2001 From: Erin van der Veen Date: Wed, 22 Jun 2022 13:01:54 +0200 Subject: [PATCH 377/861] update tree-sitter-nickel to include ' in ident (#2859) see https://github.com/nickel-lang/tree-sitter-nickel/pull/9 and https://github.com/tweag/nickel/pull/737 --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index ba9419b3e..e0a570805 100644 --- a/languages.toml +++ b/languages.toml @@ -425,7 +425,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "nickel" -source = { git = "https://github.com/nickel-lang/tree-sitter-nickel", rev = "c4dd1420b6cfeb6103d38eb1ce5195eb81197edc" } +source = { git = "https://github.com/nickel-lang/tree-sitter-nickel", rev = "9a502ea2e774df3d743a48310bb40e1cc097c86e" } [[language]] name = "nix" From 301065fe4d062dacc2b23b0f55780b3b6f2f52b5 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Wed, 22 Jun 2022 23:30:12 +0530 Subject: [PATCH 378/861] Fix scrollbar length proportional to total menu items (#2860) The scrollbar length used to increase with more entries in the menu, which was counter-intuitive to how scrollbars worked in most applications. Turns out there was a typo in the floor division implementation :) --- helix-term/src/ui/menu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index d67a429e3..477b218ad 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -288,7 +288,7 @@ impl Component for Menu { let win_height = area.height as usize; const fn div_ceil(a: usize, b: usize) -> usize { - (a + b - 1) / a + (a + b - 1) / b } let scroll_height = std::cmp::min(div_ceil(win_height.pow(2), len), win_height as usize); From c107f4ea49edd61a3c6e8b971b20604cdab96325 Mon Sep 17 00:00:00 2001 From: Seth Bromberger Date: Wed, 22 Jun 2022 11:53:36 -0700 Subject: [PATCH 379/861] fixes #2856 by resetting style on diagnostic (#2861) --- helix-term/src/ui/editor.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index dc6362c6e..debce9b44 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -665,15 +665,13 @@ impl EditorView { let mut lines = Vec::new(); for diagnostic in diagnostics { - let text = Text::styled( - &diagnostic.message, - match diagnostic.severity { - Some(Severity::Error) => error, - Some(Severity::Warning) | None => warning, - Some(Severity::Info) => info, - Some(Severity::Hint) => hint, - }, - ); + let style = Style::reset().patch(match diagnostic.severity { + Some(Severity::Error) => error, + Some(Severity::Warning) | None => warning, + Some(Severity::Info) => info, + Some(Severity::Hint) => hint, + }); + let text = Text::styled(&diagnostic.message, style); lines.extend(text.lines); } From 886cff3bcc5f8e1d81e55afdbbf7ad8ff00ffc7b Mon Sep 17 00:00:00 2001 From: farwyler <1705805+farwyler@users.noreply.github.com> Date: Fri, 24 Jun 2022 15:56:18 +0200 Subject: [PATCH 380/861] Redetect indent and line endings after language server replaces documents (#2778) * redetect indent and line endings after language server replaces document * removes nested if * always redetect indent and line endings after format This reverts commit 764d14f55894dc7213e48022dfa0f91829b8ef59. --- helix-term/src/commands.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index a07b51091..43bc0c7c5 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2343,6 +2343,7 @@ async fn make_format_callback( if doc.version() == doc_version { doc.apply(&Transaction::from(format), view_id); doc.append_changes_to_history(view_id); + doc.detect_indent_and_line_ending(); if let Modified::SetUnmodified = modified { doc.reset_modified(); } From d948ace67b10f162fd00106b9be2c1c680f33861 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 24 Jun 2022 08:58:04 -0500 Subject: [PATCH 381/861] check selection's visible width when copying on mouse click (#2711) * check selection's visible width when copying on mouse click Mouse-click-up copies the selection produced by dragging. The event is ignored if the selection has a width of 1 though so you don't copy when clicking rather than dragging. The current check copies text when it has a visible width of 1 but is actually multiple characters in the rope like a CRLF line-ending. With this change we check the unicode width of the character(s) in the selection rather than the range length, so clicking on a CRLF line-ending does not copy. * use range.fragment to simplify getting the primary selection width --- helix-term/src/ui/editor.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index debce9b44..70f600708 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -1127,9 +1127,14 @@ impl EditorView { } let (view, doc) = current!(cxt.editor); - let range = doc.selection(view.id).primary(); - if range.to() - range.from() <= 1 { + if doc + .selection(view.id) + .primary() + .fragment(doc.text().slice(..)) + .width() + <= 1 + { return EventResult::Ignored(None); } From 3dbad0442fc3038dd0b0f6bd07ba0e40d2d92000 Mon Sep 17 00:00:00 2001 From: Saber Haj Rabiee Date: Fri, 24 Jun 2022 08:14:48 -0700 Subject: [PATCH 382/861] fixes showing the last prompt on empty input (#2870) --- helix-core/src/register.rs | 4 ++++ helix-term/src/ui/prompt.rs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/helix-core/src/register.rs b/helix-core/src/register.rs index 7fa34644b..1cff77ba3 100644 --- a/helix-core/src/register.rs +++ b/helix-core/src/register.rs @@ -73,6 +73,10 @@ impl Registers { self.read(name).and_then(|entries| entries.first()) } + pub fn last(&self, name: char) -> Option<&String> { + self.read(name).and_then(|entries| entries.last()) + } + pub fn inner(&self) -> &HashMap { &self.inner } diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index beba8ce9a..55b08032d 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -443,7 +443,7 @@ impl Prompt { let input: Cow = if self.line.is_empty() { // latest value in the register list self.history_register - .and_then(|reg| cx.editor.registers.first(reg)) + .and_then(|reg| cx.editor.registers.last(reg)) .map(|entry| entry.into()) .unwrap_or_else(|| Cow::from("")) } else { @@ -522,7 +522,7 @@ impl Component for Prompt { let input: Cow = if self.line.is_empty() { // latest value in the register list self.history_register - .and_then(|reg| cx.editor.registers.first(reg).cloned()) + .and_then(|reg| cx.editor.registers.last(reg).cloned()) .map(|entry| entry.into()) .unwrap_or_else(|| Cow::from("")) } else { From 33e6df870710a48e89875b6f7471b9ee5f54af50 Mon Sep 17 00:00:00 2001 From: Hekno25 <87552206+Hekno25@users.noreply.github.com> Date: Fri, 24 Jun 2022 16:21:26 -0500 Subject: [PATCH 383/861] feat: add wgsl_analyzer as wgsl language server (#2872) --- book/src/generated/lang-support.md | 2 +- languages.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 0ed4062d4..7d0ac2020 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -98,6 +98,6 @@ | vala | ✓ | | | `vala-language-server` | | verilog | ✓ | ✓ | | `svlangserver` | | vue | ✓ | | | `vls` | -| wgsl | ✓ | | | | +| wgsl | ✓ | | | `wgsl_analyzer` | | yaml | ✓ | | ✓ | `yaml-language-server` | | zig | ✓ | | ✓ | `zls` | diff --git a/languages.toml b/languages.toml index e0a570805..62513141c 100644 --- a/languages.toml +++ b/languages.toml @@ -787,6 +787,7 @@ scope = "source.wgsl" file-types = ["wgsl"] roots = [] comment-token = "//" +language-server = { command = "wgsl_analyzer" } indent = { tab-width = 4, unit = " " } [[grammar]] From 18435899b2310f5605153acfb7108e01f70caa79 Mon Sep 17 00:00:00 2001 From: two-six Date: Sat, 25 Jun 2022 19:09:04 +0200 Subject: [PATCH 384/861] [Theme] Acme (#2876) --- runtime/themes/acme.toml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 runtime/themes/acme.toml diff --git a/runtime/themes/acme.toml b/runtime/themes/acme.toml new file mode 100644 index 000000000..263cbf90e --- /dev/null +++ b/runtime/themes/acme.toml @@ -0,0 +1,28 @@ +# Author: Two-Six + +"ui.background" = {bg="acme_bg"} +"ui.text" = "black" +"ui.selection" = {bg="selected"} +"ui.statusline" = {bg="acme_bar_bg"} +"ui.statusline.inactive" = {bg="acme_bar_inactive"} +"ui.virtual" = "indent" +"ui.cursor.match" = {bg="acme_bar_bg"} +"ui.cursor" = {bg="cursor", fg="white"} +"string" = "red" +"comment" = "green" +"ui.menu.selected" = {bg="selected"} +"diagnostic.error" = {bg="white", modifiers=["bold"]} +"diagnostic.warning" = {bg="white", modifiers=["bold"]} +"diagnostic.hint" = {bg="white", modifiers=["bold"]} + +[palette] +white = "#ffffff" +acme_bg = "#ffffea" +black = "#000000" +selected = "#eeee9e" +acme_bar_bg = "#aeeeee" +acme_bar_inactive = "#eaffff" +cursor = "#444444" +red = "#a0342f" +green = "#065905" +indent = "#aaaaaa" From e1b1a5ebc01311ff1ef34e205015570a2856481d Mon Sep 17 00:00:00 2001 From: Triton171 Date: Sat, 25 Jun 2022 20:12:30 +0200 Subject: [PATCH 385/861] Fix edge-case in tree-sitter expand_selection selection command (#2877) Co-authored-by: Triton171 --- helix-core/src/object.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/helix-core/src/object.rs b/helix-core/src/object.rs index b06f41444..d2d4fe70a 100644 --- a/helix-core/src/object.rs +++ b/helix-core/src/object.rs @@ -2,12 +2,11 @@ use crate::{Range, RopeSlice, Selection, Syntax}; use tree_sitter::Node; pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { - select_node_impl(syntax, text, selection, |descendant, from, to| { - if descendant.start_byte() == from && descendant.end_byte() == to { - descendant.parent() - } else { - Some(descendant) + select_node_impl(syntax, text, selection, |mut node, from, to| { + while node.start_byte() == from && node.end_byte() == to { + node = node.parent()?; } + Some(node) }) } From ba85779902877340d17f27dce1aeced98abfaeb6 Mon Sep 17 00:00:00 2001 From: Amit Beka Date: Sat, 25 Jun 2022 23:28:26 +0300 Subject: [PATCH 386/861] book: fix the description of dot repeat (#2878) Co-authored-by: amitbeka <---> --- 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 7efbdd237..e6abb9c92 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -52,7 +52,7 @@ | `A` | Insert at the end of the line | `append_to_line` | | `o` | Open new line below selection | `open_below` | | `O` | Open new line above selection | `open_above` | -| `.` | Repeat last change | N/A | +| `.` | Repeat last insert | N/A | | `u` | Undo change | `undo` | | `U` | Redo change | `redo` | | `Alt-u` | Move backward in history | `earlier` | From 16ccc7ead88faf060236cbff72dee52c58e37156 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sun, 26 Jun 2022 14:26:35 +0530 Subject: [PATCH 387/861] Add single width left margin for completion popup (#2728) * Add single width left margin for completion popup * Clear with ui.menu style before rendering menu When rendering a completion popup, the popup component will clear the area with ui.popup and then the menu component would draw over it using a table component. We remove the left edge of the area before passing it to the table component (so that it will be left as padding), and the table component uses ui.menu as the style. If ui.menu and ui.popup are different the left edge of the popup will look different from the rest of the popup. We avoid this by clearing the whole area with ui.menu in Menu::render --- helix-term/src/ui/menu.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index 477b218ad..fa56008d6 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -48,6 +48,8 @@ pub struct Menu { } impl Menu { + const LEFT_PADDING: usize = 1; + // TODO: it's like a slimmed down picker, share code? (picker = menu + prompt with different // rendering) pub fn new( @@ -150,6 +152,7 @@ impl Menu { len += 1; // +1: reserve some space for scrollbar } + len += Self::LEFT_PADDING; let width = len.min(viewport.0 as usize); self.widths = max_lens @@ -271,6 +274,7 @@ impl Component for Menu { .try_get("ui.menu") .unwrap_or_else(|| theme.get("ui.text")); let selected = theme.get("ui.menu.selected"); + surface.clear_with(area, style); let scroll = self.scroll; @@ -306,7 +310,7 @@ impl Component for Menu { use tui::widgets::TableState; table.render_table( - area, + area.clip_left(Self::LEFT_PADDING as u16), surface, &mut TableState { offset: scroll, @@ -314,6 +318,12 @@ impl Component for Menu { }, ); + if let Some(cursor) = self.cursor { + let offset_from_top = cursor - scroll; + let cell = &mut surface[(area.x, area.y + offset_from_top as u16)]; + cell.set_style(selected); + } + let fits = len <= win_height; for (i, _) in (scroll..(scroll + win_height).min(len)).enumerate() { From 24351c20d41c26df0c695940e6790525858ab1c1 Mon Sep 17 00:00:00 2001 From: Kihaya Sugiura Date: Mon, 27 Jun 2022 02:04:53 +0900 Subject: [PATCH 388/861] languages: Fix ruby rakefile and gemfile file type (#2875) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 62513141c..aba5fd44c 100644 --- a/languages.toml +++ b/languages.toml @@ -446,7 +446,7 @@ source = { git = "https://github.com/cstrahan/tree-sitter-nix", rev = "6b71a810c name = "ruby" scope = "source.ruby" injection-regex = "ruby" -file-types = ["rb", "rake", "rakefile", "irb", "gemfile", "gemspec"] +file-types = ["rb", "rake", "rakefile", "irb", "gemfile", "gemspec", "Rakefile", "Gemfile"] shebangs = ["ruby"] roots = [] comment-token = "#" From c113531db9f9dbe522adea584b4c18083af578e7 Mon Sep 17 00:00:00 2001 From: Ramojus <41536253+Ramojus@users.noreply.github.com> Date: Mon, 27 Jun 2022 07:40:08 +0300 Subject: [PATCH 389/861] add meliora theme (#2884) --- runtime/themes/meliora.toml | 90 +++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 runtime/themes/meliora.toml diff --git a/runtime/themes/meliora.toml b/runtime/themes/meliora.toml new file mode 100644 index 000000000..fa474abbb --- /dev/null +++ b/runtime/themes/meliora.toml @@ -0,0 +1,90 @@ +# Author: Ramojus + +"comment" = { fg = "comment" } +"constant" = { fg = "magenta" } +"function" = { fg = "blue" } +"keyword.control.import" = { fg = "orange" } +"keyword.control" = { fg = "red" } +"keyword.function" = { fg = "red" } +"keyword" = { fg = "orange" } +"operator" = { fg = "secondary_white" } +"punctuation" = { fg = "secondary_white" } +"string" = { fg = "yellow" } +"string.regexp" = { fg = "orange" } +"tag" = { fg = "red" } +"type" = { fg = "secondary_white" } +"namespace" = { fg = "blue" } +"variable" = { fg = "white" } +"label" = { fg = "orange" } + +"diff.plus" = { fg = "blue" } +"diff.delta" = { fg = "magenta" } +"diff.minus" = { fg = "red" } + +"ui.cursor" = { bg = "light_grey", fg = "black"} +"ui.cursor.match" = { bg = "dark_grey" } +"ui.cursor.primary" = { bg = "secondary_white", fg = "black" } + +"ui.linenr" = { fg = "grey", bg = "dark_black"} +"ui.linenr.selected" = { fg = "dark_white", bg = "dark_black"} +"ui.gutter" = { bg = "dark_black" } + +"ui.background" = { fg = "light_grey", bg = "black" } +"ui.background.separator" = { fg = "dark_grey" } +"ui.help" = { fg = "white", bg = "light_black2" } +"ui.menu" = { fg = "dark_white", bg = "light_black" } +"ui.menu.selected" = { bg = "orange" , fg = "black" } +"ui.popup" = { fg = "dark_white", bg = "light_black" } +"ui.window" = { fg = "light_black2" } + +"ui.selection" = { bg = "light_black2" } +"ui.selection.primary" = { bg = "light_black2" } + +"ui.statusline" = { fg = "dark_white", bg = "light_black2" } +"ui.statusline.inactive" = { fg = "dark_white2", bg = "light_black" } + +"ui.text" = { fg = "white" } +"ui.text.focus" = { fg = "orange" } + +"ui.virtual.ruler" = { bg = "light_black" } +"ui.virtual.indent-guide" = { fg = "light_black" } +"ui.virtual.whitespace" = { fg = "dark_grey" } + +"diagnostic" = { modifiers = ["underlined"] } +"error" = { fg = "red" } +"warning" = { fg = "orange" } +"info" = { fg = "blue" } +"hint" = { fg = "magenta" } +"special" = { fg = "yellow" } + +"markup.heading" = { fg = "orange" } +"markup.list" = { fg = "blue" } +"markup.bold" = { fg = "magenta" } +"markup.italic" = { fg = "blue" } +"markup.link.url" = { fg = "comment" , modifiers = ["underlined"] } +"markup.link.text" = { fg = "comment" } +"markup.quote" = { fg = "yellow" } +"markup.raw" = { fg = "blue" } + +[palette] +red = "#d29595" +orange = "#cbab8a" +yellow = "#c9b58e" +blue = "#a49db9" +magenta = "#b494af" + +comment = "#707035" + +black = "#1c1917" +light_black = "#292725" +light_black2 = "#302D2B" +dark_black = "#191514" +dark_light_black = "#211d1c" + +white = "#dad7d5" +dark_white = "#aaa7a6" +dark_white2 = "#949290" +dark_grey = "#4c4b49" +grey = "#605e5d" +light_grey = "#6a6867" +secondary_white = "#c2b4a8" From a26943de4e421a453371aa53b3bb11a2baabff56 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Mon, 27 Jun 2022 13:22:31 +0530 Subject: [PATCH 390/861] Right align scrollbar with track in completion popup (#2754) - Align the scollbar to the right edge of the popup rather than at a margin of one. - Add a scrollbar track and a new scope `ui.menu.scroll`. --- book/src/themes.md | 1 + helix-term/src/ui/menu.rs | 26 +++++++++++++++++++------- runtime/themes/onedark.toml | 1 + theme.toml | 1 + 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/book/src/themes.md b/book/src/themes.md index 57a8d5d1f..ea52835d4 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -231,6 +231,7 @@ These scopes are used for theming the editor interface. | `ui.virtual.indent-guide` | Vertical indent width guides | | `ui.menu` | Code and command completion menus | | `ui.menu.selected` | Selected autocomplete item | +| `ui.menu.scroll` | `fg` sets thumb color, `bg` sets track color of scrollbar | | `ui.selection` | For selections in the editing area | | `ui.selection.primary` | | | `warning` | Diagnostics warning (gutter) | diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index fa56008d6..0519374a3 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -310,7 +310,7 @@ impl Component for Menu { use tui::widgets::TableState; table.render_table( - area.clip_left(Self::LEFT_PADDING as u16), + area.clip_left(Self::LEFT_PADDING as u16).clip_right(1), surface, &mut TableState { offset: scroll, @@ -320,20 +320,32 @@ impl Component for Menu { if let Some(cursor) = self.cursor { let offset_from_top = cursor - scroll; - let cell = &mut surface[(area.x, area.y + offset_from_top as u16)]; - cell.set_style(selected); + let left = &mut surface[(area.left(), area.y + offset_from_top as u16)]; + left.set_style(selected); + let right = &mut surface[( + area.right().saturating_sub(1), + area.y + offset_from_top as u16, + )]; + right.set_style(selected); } let fits = len <= win_height; + let scroll_style = theme.get("ui.menu.scroll"); for (i, _) in (scroll..(scroll + win_height).min(len)).enumerate() { + let cell = &mut surface[(area.x + area.width - 1, area.y + i as u16)]; + + if !fits { + // Draw scroll track + cell.set_symbol("▐"); // right half block + cell.set_fg(scroll_style.bg.unwrap_or(helix_view::theme::Color::Reset)); + } + let is_marked = i >= scroll_line && i < scroll_line + scroll_height; if !fits && is_marked { - let cell = &mut surface[(area.x + area.width - 2, area.y + i as u16)]; - cell.set_symbol("▐"); - // cell.set_style(selected); - // cell.set_style(if is_marked { selected } else { style }); + // Draw scroll thumb + cell.set_fg(scroll_style.fg.unwrap_or(helix_view::theme::Color::Reset)); } } } diff --git a/runtime/themes/onedark.toml b/runtime/themes/onedark.toml index d0cbb9494..a4d05ca8e 100644 --- a/runtime/themes/onedark.toml +++ b/runtime/themes/onedark.toml @@ -73,6 +73,7 @@ diagnostic = { modifiers = ["underlined"] } "ui.window" = { bg = "gray" } "ui.menu" = { fg = "white", bg = "gray" } "ui.menu.selected" = { fg = "black", bg = "blue" } +"ui.menu.scroll" = { fg = "white", bg = "light-gray" } [palette] diff --git a/theme.toml b/theme.toml index 8e550f922..3fc694e4c 100644 --- a/theme.toml +++ b/theme.toml @@ -69,6 +69,7 @@ label = "honey" "ui.menu" = { fg = "lavender", bg = "revolver" } "ui.menu.selected" = { fg = "revolver", bg = "white" } +"ui.menu.scroll" = { fg = "lavender", bg = "comet" } diagnostic = { modifiers = ["underlined"] } # "diagnostic.hint" = { fg = "revolver", bg = "lilac" } From 8dc86beabd9334d013291656313cb33a88754c42 Mon Sep 17 00:00:00 2001 From: Tobias Menzi Date: Mon, 27 Jun 2022 10:09:34 +0200 Subject: [PATCH 391/861] Implement cursorline (#2170) * Implement cursorline * Binary search possible lines --- book/src/configuration.md | 1 + helix-term/src/ui/editor.rs | 41 +++++++++++++++++++++++++++++++++++++ helix-view/src/editor.rs | 3 +++ 3 files changed, 45 insertions(+) diff --git a/book/src/configuration.md b/book/src/configuration.md index 3fa9b307a..af85379f8 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -37,6 +37,7 @@ hidden = false | `scroll-lines` | Number of lines to scroll per scroll wheel step. | `3` | | `shell` | Shell to use when running external commands. | Unix: `["sh", "-c"]`
Windows: `["cmd", "/C"]` | | `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` | | `gutters` | Gutters to display: Available are `diagnostics` and `line-numbers`, note that `diagnostics` also includes other features like breakpoints | `["diagnostics", "line-numbers"]` | | `auto-completion` | Enable automatic pop up of auto-completion. | `true` | | `auto-format` | Enable automatic formatting on save. | `true` | diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 70f600708..2f44dae9c 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -112,6 +112,10 @@ impl EditorView { } } + if editor.config().cursorline { + Self::highlight_cursorline(doc, view, surface, theme); + } + let highlights = Self::doc_syntax_highlights(doc, view.offset, inner.height, theme); let highlights = syntax::merge(highlights, Self::doc_diagnostics_highlights(doc, theme)); let highlights: Box> = if is_focused { @@ -686,6 +690,43 @@ impl EditorView { ); } + /// Apply the highlighting on the lines where a cursor is active + pub fn highlight_cursorline(doc: &Document, view: &View, surface: &mut Surface, theme: &Theme) { + let text = doc.text().slice(..); + let last_line = view.last_line(doc); + + let primary_line = doc.selection(view.id).primary().cursor_line(text); + + // The secondary_lines do contain the primary_line, it doesn't matter + // as the else-if clause in the loop later won't test for the + // secondary_lines if primary_line == line. + // It's used inside a loop so the collect isn't needless: + // https://github.com/rust-lang/rust-clippy/issues/6164 + #[allow(clippy::needless_collect)] + let secondary_lines: Vec<_> = doc + .selection(view.id) + .iter() + .map(|range| range.cursor_line(text)) + .collect(); + + let primary_style = theme.get("ui.cursorline.primary"); + let secondary_style = theme.get("ui.cursorline.secondary"); + + for line in view.offset.row..(last_line + 1) { + let area = Rect::new( + view.area.x, + view.area.y + (line - view.offset.row) as u16, + view.area.width, + 1, + ); + if primary_line == line { + surface.set_style(area, primary_style); + } else if secondary_lines.binary_search(&line).is_ok() { + surface.set_style(area, secondary_style); + } + } + } + pub fn render_statusline( &self, doc: &Document, diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index c5a458d7f..a9741a33f 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -121,6 +121,8 @@ pub struct Config { pub shell: Vec, /// Line number mode. pub line_number: LineNumber, + /// Highlight the lines cursors are currently on. Defaults to false. + pub cursorline: bool, /// Gutters. Default ["diagnostics", "line-numbers"] pub gutters: Vec, /// Middle click paste support. Defaults to true. @@ -394,6 +396,7 @@ impl Default for Config { vec!["sh".to_owned(), "-c".to_owned()] }, line_number: LineNumber::Absolute, + cursorline: false, gutters: vec![GutterType::Diagnostics, GutterType::LineNumbers], middle_click_paste: true, auto_pairs: AutoPairConfig::default(), From 33d287a9ad4e72311cf74c7070406626f8cad4bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 27 Jun 2022 17:27:24 +0900 Subject: [PATCH 392/861] Add a default cursorline style for the primary selection --- theme.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/theme.toml b/theme.toml index 3fc694e4c..ab7c995a8 100644 --- a/theme.toml +++ b/theme.toml @@ -65,6 +65,7 @@ label = "honey" "ui.cursor.insert" = { bg = "white" } "ui.cursor.match" = { fg = "#212121", bg = "#6C6999" } "ui.cursor" = { modifiers = ["reversed"] } +"ui.cursorline.primary" = { bg = "bossanova" } "ui.highlight" = { bg = "bossanova" } "ui.menu" = { fg = "lavender", bg = "revolver" } From 24f03097e3b4aef62aa56bb27e0853b60a4cb417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 27 Jun 2022 17:27:44 +0900 Subject: [PATCH 393/861] Remove some more unwraps --- helix-lsp/src/client.rs | 6 +++--- helix-lsp/src/jsonrpc.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 8ee9c9d71..cf6706b58 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -271,8 +271,8 @@ impl Client { // ------------------------------------------------------------------------------------------- pub(crate) async fn initialize(&self) -> Result { - if self.config.is_some() { - log::info!("Using custom LSP config: {}", self.config.as_ref().unwrap()); + if let Some(config) = &self.config { + log::info!("Using custom LSP config: {}", config); } #[allow(deprecated)] @@ -896,8 +896,8 @@ impl Client { 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"; - log::warn!("rename_symbol failed: {}", err); return Err(anyhow!(err)); } }; diff --git a/helix-lsp/src/jsonrpc.rs b/helix-lsp/src/jsonrpc.rs index b9b3fd2c0..ed63da137 100644 --- a/helix-lsp/src/jsonrpc.rs +++ b/helix-lsp/src/jsonrpc.rs @@ -310,7 +310,7 @@ fn method_call_serialize() { id: Id::Num(1), }; - let serialized = serde_json::to_string(&m).unwrap(); + let serialized = serde_json::json!(&m); assert_eq!( serialized, r#"{"jsonrpc":"2.0","method":"update","params":[1,2],"id":1}"# @@ -327,7 +327,7 @@ fn notification_serialize() { params: Params::Array(vec![Value::from(1), Value::from(2)]), }; - let serialized = serde_json::to_string(&n).unwrap(); + let serialized = serde_json::json!(&n); assert_eq!( serialized, r#"{"jsonrpc":"2.0","method":"update","params":[1,2]}"# From 425de09d217002d3b7c6cad864015277cfe041a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 27 Jun 2022 17:35:23 +0900 Subject: [PATCH 394/861] Fix tests again --- helix-lsp/src/jsonrpc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helix-lsp/src/jsonrpc.rs b/helix-lsp/src/jsonrpc.rs index ed63da137..b9b3fd2c0 100644 --- a/helix-lsp/src/jsonrpc.rs +++ b/helix-lsp/src/jsonrpc.rs @@ -310,7 +310,7 @@ fn method_call_serialize() { id: Id::Num(1), }; - let serialized = serde_json::json!(&m); + let serialized = serde_json::to_string(&m).unwrap(); assert_eq!( serialized, r#"{"jsonrpc":"2.0","method":"update","params":[1,2],"id":1}"# @@ -327,7 +327,7 @@ fn notification_serialize() { params: Params::Array(vec![Value::from(1), Value::from(2)]), }; - let serialized = serde_json::json!(&n); + let serialized = serde_json::to_string(&n).unwrap(); assert_eq!( serialized, r#"{"jsonrpc":"2.0","method":"update","params":[1,2]}"# From fde9e034d4a7bd16d3c9780600874323e4e91628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 27 Jun 2022 17:51:22 +0900 Subject: [PATCH 395/861] Only draw cursorline in the currently focused buffer --- helix-term/src/ui/editor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 2f44dae9c..f71f716ec 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -112,7 +112,7 @@ impl EditorView { } } - if editor.config().cursorline { + if is_focused && editor.config().cursorline { Self::highlight_cursorline(doc, view, surface, theme); } From 096abdd19bb422cba607d43d05b195b37a7f95e9 Mon Sep 17 00:00:00 2001 From: lazytanuki <43273245+lazytanuki@users.noreply.github.com> Date: Mon, 27 Jun 2022 13:19:56 +0200 Subject: [PATCH 396/861] feat: highlight / select symbol under cursor using LSP textDocument/documentHighlight (#2738) * feat: highlight symbol under cursor using LSP textDocument/documentHighlight * fix: please clippy * fix: shorter description and code style --- helix-lsp/src/client.rs | 20 +++++++++++++++ helix-term/src/commands.rs | 1 + helix-term/src/commands/lsp.rs | 43 ++++++++++++++++++++++++++++++++ helix-term/src/keymap/default.rs | 1 + 4 files changed, 65 insertions(+) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index cf6706b58..aa8335414 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -759,6 +759,26 @@ impl Client { Ok(response.unwrap_or_default()) } + pub fn text_document_document_highlight( + &self, + text_document: lsp::TextDocumentIdentifier, + position: lsp::Position, + work_done_token: Option, + ) -> impl Future> { + let params = lsp::DocumentHighlightParams { + text_document_position_params: lsp::TextDocumentPositionParams { + text_document, + position, + }, + work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token }, + partial_result_params: lsp::PartialResultParams { + partial_result_token: None, + }, + }; + + self.call::(params) + } + fn goto_request< T: lsp::request::Request< Params = lsp::GotoDefinitionParams, diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 43bc0c7c5..0a28444bd 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -263,6 +263,7 @@ impl MappableCommand { code_action, "Perform code action", buffer_picker, "Open buffer picker", symbol_picker, "Open symbol picker", + select_references_to_symbol_under_cursor, "Select symbol references", workspace_symbol_picker, "Open workspace symbol picker", last_picker, "Open last picker", prepend_to_line, "Insert at start of line", diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 6f75fb497..c1cdb1642 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -655,6 +655,7 @@ pub fn signature_help(cx: &mut Context) { }, ); } + pub fn hover(cx: &mut Context) { let (view, doc) = current!(cx.editor); let language_server = language_server!(cx.editor, doc); @@ -704,6 +705,7 @@ pub fn hover(cx: &mut Context) { }, ); } + pub fn rename_symbol(cx: &mut Context) { ui::prompt( cx, @@ -729,3 +731,44 @@ pub fn rename_symbol(cx: &mut Context) { }, ); } + +pub fn select_references_to_symbol_under_cursor(cx: &mut Context) { + let (view, doc) = current!(cx.editor); + let language_server = language_server!(cx.editor, doc); + let offset_encoding = language_server.offset_encoding(); + + let pos = doc.position(view.id, offset_encoding); + + let future = language_server.text_document_document_highlight(doc.identifier(), pos, None); + + cx.callback( + future, + move |editor, _compositor, response: Option>| { + let document_highlights = match response { + Some(highlights) if !highlights.is_empty() => highlights, + _ => return, + }; + let (view, doc) = current!(editor); + let language_server = language_server!(editor, doc); + let offset_encoding = language_server.offset_encoding(); + let text = doc.text(); + let pos = doc.selection(view.id).primary().head; + + // We must find the range that contains our primary cursor to prevent our primary cursor to move + let mut primary_index = 0; + let ranges = document_highlights + .iter() + .filter_map(|highlight| lsp_range_to_range(text, highlight.range, offset_encoding)) + .enumerate() + .map(|(i, range)| { + if range.contains(pos) { + primary_index = i; + } + range + }) + .collect(); + let selection = Selection::new(ranges, primary_index); + doc.set_selection(view.id, selection); + }, + ); +} diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index c36951172..e5bb0482d 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -259,6 +259,7 @@ pub fn default() -> HashMap { "/" => global_search, "k" => hover, "r" => rename_symbol, + "h" => select_references_to_symbol_under_cursor, "?" => command_palette, }, "z" => { "View" From db2aa57074c1eeab45899b270b660d12953915b8 Mon Sep 17 00:00:00 2001 From: ramojus <41536253+Ramojus@users.noreply.github.com> Date: Mon, 27 Jun 2022 15:49:09 +0300 Subject: [PATCH 397/861] update meliora theme (#2890) --- runtime/themes/meliora.toml | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/runtime/themes/meliora.toml b/runtime/themes/meliora.toml index fa474abbb..72ade8ac5 100644 --- a/runtime/themes/meliora.toml +++ b/runtime/themes/meliora.toml @@ -26,30 +26,31 @@ "ui.cursor.primary" = { bg = "secondary_white", fg = "black" } "ui.linenr" = { fg = "grey", bg = "dark_black"} -"ui.linenr.selected" = { fg = "dark_white", bg = "dark_black"} +"ui.linenr.selected" = { fg = "dark_white", bg = "dark_light_black"} "ui.gutter" = { bg = "dark_black" } "ui.background" = { fg = "light_grey", bg = "black" } "ui.background.separator" = { fg = "dark_grey" } -"ui.help" = { fg = "white", bg = "light_black2" } +"ui.help" = { fg = "white", bg = "light_black3" } "ui.menu" = { fg = "dark_white", bg = "light_black" } "ui.menu.selected" = { bg = "orange" , fg = "black" } "ui.popup" = { fg = "dark_white", bg = "light_black" } -"ui.window" = { fg = "light_black2" } +"ui.window" = { fg = "light_black3" } -"ui.selection" = { bg = "light_black2" } -"ui.selection.primary" = { bg = "light_black2" } +"ui.selection" = { bg = "light_black3" } +"ui.selection.primary" = { bg = "light_black3", modifiers = ["bold"] } +"ui.cursorline.primary" = { bg = "light_black" } -"ui.statusline" = { fg = "dark_white", bg = "light_black2" } +"ui.statusline" = { fg = "dark_white", bg = "light_black3" } "ui.statusline.inactive" = { fg = "dark_white2", bg = "light_black" } "ui.text" = { fg = "white" } "ui.text.focus" = { fg = "orange" } -"ui.virtual.ruler" = { bg = "light_black" } -"ui.virtual.indent-guide" = { fg = "light_black" } -"ui.virtual.whitespace" = { fg = "dark_grey" } - +"ui.virtual.ruler" = { bg = "light_black2" } +"ui.virtual.indent-guide" = { fg = "dark_grey2" } +"ui.virtual.whitespace" = { fg = "grey" } + "diagnostic" = { modifiers = ["underlined"] } "error" = { fg = "red" } "warning" = { fg = "orange" } @@ -75,16 +76,18 @@ magenta = "#b494af" comment = "#707035" +light_black = "#252220" +light_black2 = "#292725" +light_black3 = "#302D2B" black = "#1c1917" -light_black = "#292725" -light_black2 = "#302D2B" dark_black = "#191514" dark_light_black = "#211d1c" white = "#dad7d5" dark_white = "#aaa7a6" dark_white2 = "#949290" -dark_grey = "#4c4b49" -grey = "#605e5d" light_grey = "#6a6867" +grey = "#605e5d" +dark_grey = "#4c4b49" +dark_grey2 = "#383735" secondary_white = "#c2b4a8" From 23ce5f1837d34649d1c973d3cd55b7a1a49885b2 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Mon, 27 Jun 2022 21:06:41 +0530 Subject: [PATCH 398/861] Add cursorline scope for onedark theme (#2892) --- runtime/themes/onedark.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/themes/onedark.toml b/runtime/themes/onedark.toml index a4d05ca8e..aec7ba960 100644 --- a/runtime/themes/onedark.toml +++ b/runtime/themes/onedark.toml @@ -58,6 +58,7 @@ diagnostic = { modifiers = ["underlined"] } "ui.selection" = { bg = "light-gray" } "ui.selection.primary" = { bg = "gray" } +"ui.cursorline.primary" = { bg = "light-black" } "ui.linenr" = { fg = "linenr" } "ui.linenr.selected" = { fg = "white" } From 3108a11d350ab89f827d30664b9c00ca751b6abc Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Mon, 27 Jun 2022 21:35:07 +0530 Subject: [PATCH 399/861] Refactor handling of mouse events (#2893) - Simplified match statements by destructuring MouseEvent struct at the top and then matching on event.kind. - Extracted out closures for calculating (1) position and view of mouse click and (2) gutter coordinates and view of mouse click. --- helix-term/src/ui/editor.rs | 107 +++++++++++++----------------------- 1 file changed, 38 insertions(+), 69 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index f71f716ec..32f70c8b1 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -1051,22 +1051,33 @@ impl EditorView { cxt: &mut commands::Context, ) -> EventResult { let config = cxt.editor.config(); - match event { - MouseEvent { - kind: MouseEventKind::Down(MouseButton::Left), - row, - column, - modifiers, - .. - } => { - let editor = &mut cxt.editor; + let MouseEvent { + kind, + row, + column, + modifiers, + .. + } = event; + + let pos_and_view = |editor: &Editor, row, column| { + editor.tree.views().find_map(|(view, _focus)| { + view.pos_at_screen_coords(&editor.documents[&view.doc], row, column) + .map(|pos| (pos, view.id)) + }) + }; + + let gutter_coords_and_view = |editor: &Editor, row, column| { + editor.tree.views().find_map(|(view, _focus)| { + view.gutter_coords_at_screen_coords(row, column) + .map(|coords| (coords, view.id)) + }) + }; - let result = editor.tree.views().find_map(|(view, _focus)| { - view.pos_at_screen_coords(&editor.documents[&view.doc], row, column) - .map(|pos| (pos, view.id)) - }); + match kind { + MouseEventKind::Down(MouseButton::Left) => { + let editor = &mut cxt.editor; - if let Some((pos, view_id)) = result { + if let Some((pos, view_id)) = pos_and_view(editor, row, column) { let doc = editor.document_mut(editor.tree.get(view_id).doc).unwrap(); if modifiers == crossterm::event::KeyModifiers::ALT { @@ -1081,12 +1092,7 @@ impl EditorView { return EventResult::Consumed(None); } - let result = editor.tree.views().find_map(|(view, _focus)| { - view.gutter_coords_at_screen_coords(row, column) - .map(|coords| (coords, view.id)) - }); - - if let Some((coords, view_id)) = result { + if let Some((coords, view_id)) = gutter_coords_and_view(editor, row, column) { editor.tree.focus = view_id; let view = editor.tree.get(view_id); @@ -1107,12 +1113,7 @@ impl EditorView { EventResult::Ignored(None) } - MouseEvent { - kind: MouseEventKind::Drag(MouseButton::Left), - row, - column, - .. - } => { + MouseEventKind::Drag(MouseButton::Left) => { let (view, doc) = current!(cxt.editor); let pos = match view.pos_at_screen_coords(doc, row, column) { @@ -1124,15 +1125,11 @@ impl EditorView { let primary = selection.primary_mut(); *primary = primary.put_cursor(doc.text().slice(..), pos, true); doc.set_selection(view.id, selection); + EventResult::Consumed(None) } - MouseEvent { - kind: MouseEventKind::ScrollUp | MouseEventKind::ScrollDown, - row, - column, - .. - } => { + MouseEventKind::ScrollUp | MouseEventKind::ScrollDown => { let current_view = cxt.editor.tree.focus; let direction = match event.kind { @@ -1141,13 +1138,8 @@ impl EditorView { _ => unreachable!(), }; - let result = cxt.editor.tree.views().find_map(|(view, _focus)| { - view.pos_at_screen_coords(&cxt.editor.documents[&view.doc], row, column) - .map(|_| view.id) - }); - - match result { - Some(view_id) => cxt.editor.tree.focus = view_id, + match pos_and_view(cxt.editor, row, column) { + Some((_, view_id)) => cxt.editor.tree.focus = view_id, None => return EventResult::Ignored(None), } @@ -1159,10 +1151,7 @@ impl EditorView { EventResult::Consumed(None) } - MouseEvent { - kind: MouseEventKind::Up(MouseButton::Left), - .. - } => { + MouseEventKind::Up(MouseButton::Left) => { if !config.middle_click_paste { return EventResult::Ignored(None); } @@ -1184,19 +1173,8 @@ impl EditorView { EventResult::Consumed(None) } - MouseEvent { - kind: MouseEventKind::Up(MouseButton::Right), - row, - column, - modifiers, - .. - } => { - let result = cxt.editor.tree.views().find_map(|(view, _focus)| { - view.gutter_coords_at_screen_coords(row, column) - .map(|coords| (coords, view.id)) - }); - - if let Some((coords, view_id)) = result { + MouseEventKind::Up(MouseButton::Right) => { + if let Some((coords, view_id)) = gutter_coords_and_view(cxt.editor, row, column) { cxt.editor.tree.focus = view_id; let view = cxt.editor.tree.get(view_id); @@ -1213,16 +1191,11 @@ impl EditorView { return EventResult::Consumed(None); } } + EventResult::Ignored(None) } - MouseEvent { - kind: MouseEventKind::Up(MouseButton::Middle), - row, - column, - modifiers, - .. - } => { + MouseEventKind::Up(MouseButton::Middle) => { let editor = &mut cxt.editor; if !config.middle_click_paste { return EventResult::Ignored(None); @@ -1235,16 +1208,12 @@ impl EditorView { return EventResult::Consumed(None); } - let result = editor.tree.views().find_map(|(view, _focus)| { - view.pos_at_screen_coords(&editor.documents[&view.doc], row, column) - .map(|pos| (pos, view.id)) - }); - - if let Some((pos, view_id)) = result { + if let Some((pos, view_id)) = pos_and_view(editor, row, column) { let doc = editor.document_mut(editor.tree.get(view_id).doc).unwrap(); doc.set_selection(view_id, Selection::point(pos)); editor.tree.focus = view_id; commands::MappableCommand::paste_primary_clipboard_before.execute(cxt); + return EventResult::Consumed(None); } From fd644ccfa24b8141c1b8ea32349a0844fe7c884a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jun 2022 07:52:27 +0800 Subject: [PATCH 400/861] build(deps): bump tree-sitter from 0.20.4 to 0.20.8 (#2895) Bumps [tree-sitter](https://github.com/tree-sitter/tree-sitter) from 0.20.4 to 0.20.8. - [Release notes](https://github.com/tree-sitter/tree-sitter/releases) - [Commits](https://github.com/tree-sitter/tree-sitter/commits) --- updated-dependencies: - dependency-name: tree-sitter dependency-type: direct:production update-type: version-update:semver-patch ... 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 af08f905e..0567a4af1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1215,9 +1215,9 @@ dependencies = [ [[package]] name = "tree-sitter" -version = "0.20.4" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e34327f8eac545e3f037382471b2b19367725a242bba7bc45edb9efb49fe39a" +checksum = "268bf3e3ca0c09e5d21b59c2638e12cb6dcf7ea2681250a696a2d0936cb57ba0" dependencies = [ "cc", "regex", From 6f932375bf47ebc1d4da1e5445fdbc82ea53453f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jun 2022 07:55:25 +0800 Subject: [PATCH 401/861] build(deps): bump serde_json from 1.0.79 to 1.0.81 (#2896) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.79 to 1.0.81. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.79...v1.0.81) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... 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 0567a4af1..11b269739 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -939,9 +939,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ "itoa", "ryu", From 64cf4c859b67c98042e2d66f26be0ce4a7afc6e0 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 27 Jun 2022 22:18:38 -0500 Subject: [PATCH 402/861] support Bazel languages (#2903) --- book/src/generated/lang-support.md | 1 + languages.toml | 12 +++++++++++- runtime/queries/starlark/highlights.scm | 1 + runtime/queries/starlark/injections.scm | 2 ++ runtime/queries/starlark/textobjects.scm | 1 + 5 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/starlark/highlights.scm create mode 100644 runtime/queries/starlark/injections.scm create mode 100644 runtime/queries/starlark/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 7d0ac2020..5ea18ae84 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -85,6 +85,7 @@ | solidity | ✓ | | | `solc` | | sql | ✓ | | | | | sshclientconfig | ✓ | | | | +| starlark | ✓ | ✓ | | | | svelte | ✓ | | ✓ | `svelteserver` | | swift | ✓ | | | `sourcekit-lsp` | | tablegen | ✓ | ✓ | ✓ | | diff --git a/languages.toml b/languages.toml index aba5fd44c..0e6cbb9cb 100644 --- a/languages.toml +++ b/languages.toml @@ -461,7 +461,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-ruby", rev = "dfff6 name = "bash" scope = "source.bash" injection-regex = "bash" -file-types = ["sh", "bash", "zsh", ".bash_login", ".bash_logout", ".bash_profile", ".bashrc", ".profile", ".zshenv", ".zlogin", ".zlogout", ".zprofile", ".zshrc", "APKBUILD", "PKGBUILD", "eclass", "ebuild"] +file-types = ["sh", "bash", "zsh", ".bash_login", ".bash_logout", ".bash_profile", ".bashrc", ".profile", ".zshenv", ".zlogin", ".zlogout", ".zprofile", ".zshrc", "APKBUILD", "PKGBUILD", "eclass", "ebuild", "bazelrc"] shebangs = ["sh", "bash", "dash"] roots = [] comment-token = "#" @@ -1478,3 +1478,13 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "clojure" source = { git = "https://github.com/sogaiu/tree-sitter-clojure", rev = "e57c569ae332ca365da623712ae1f50f84daeae2" } + +[[language]] +name = "starlark" +scope = "source.starlark" +injection-regex = "(starlark|bzl|bazel)" +file-types = ["bzl", "bazel", "BUILD"] +roots = [] +comment-token = "#" +indent = { tab-width = 4, unit = " " } +grammar = "python" diff --git a/runtime/queries/starlark/highlights.scm b/runtime/queries/starlark/highlights.scm new file mode 100644 index 000000000..0b920cbf9 --- /dev/null +++ b/runtime/queries/starlark/highlights.scm @@ -0,0 +1 @@ +; inherits: python diff --git a/runtime/queries/starlark/injections.scm b/runtime/queries/starlark/injections.scm new file mode 100644 index 000000000..321c90add --- /dev/null +++ b/runtime/queries/starlark/injections.scm @@ -0,0 +1,2 @@ +((comment) @injection.content + (#set! injection.language "comment")) diff --git a/runtime/queries/starlark/textobjects.scm b/runtime/queries/starlark/textobjects.scm new file mode 100644 index 000000000..0b920cbf9 --- /dev/null +++ b/runtime/queries/starlark/textobjects.scm @@ -0,0 +1 @@ +; inherits: python From 64de0b7288036c5ad759e6ce2dfdef9d40d267ad Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 27 Jun 2022 22:25:09 -0500 Subject: [PATCH 403/861] add docs for cursorline scopes (#2904) --- book/src/themes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/book/src/themes.md b/book/src/themes.md index ea52835d4..6c6393de0 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -234,6 +234,8 @@ These scopes are used for theming the editor interface. | `ui.menu.scroll` | `fg` sets thumb color, `bg` sets track color of scrollbar | | `ui.selection` | For selections in the editing area | | `ui.selection.primary` | | +| `ui.cursorline.primary` | The line of the primary cursor | +| `ui.cursorline.secondary` | The lines of any other cursors | | `warning` | Diagnostics warning (gutter) | | `error` | Diagnostics error (gutter) | | `info` | Diagnostics info (gutter) | From 2963fdbed157b4b967dd371c9e436b88d71cd424 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jun 2022 18:25:08 +0900 Subject: [PATCH 404/861] build(deps): bump cc from 1.0.72 to 1.0.73 (#2897) Bumps [cc](https://github.com/alexcrichton/cc-rs) from 1.0.72 to 1.0.73. - [Release notes](https://github.com/alexcrichton/cc-rs/releases) - [Commits](https://github.com/alexcrichton/cc-rs/compare/1.0.72...1.0.73) --- updated-dependencies: - dependency-name: cc dependency-type: direct:production update-type: version-update:semver-patch ... 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 11b269739..97aa3ea05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,9 +66,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cc" -version = "1.0.72" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" [[package]] name = "cfg-if" From 247ebd6689a5477eef73d69d54648ee8d66bd2c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jun 2022 18:25:17 +0900 Subject: [PATCH 405/861] build(deps): bump indoc from 1.0.3 to 1.0.6 (#2898) Bumps [indoc](https://github.com/dtolnay/indoc) from 1.0.3 to 1.0.6. - [Release notes](https://github.com/dtolnay/indoc/releases) - [Commits](https://github.com/dtolnay/indoc/compare/1.0.3...1.0.6) --- updated-dependencies: - dependency-name: indoc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 13 ++----------- helix-term/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 97aa3ea05..78e5cccdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -558,12 +558,9 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a75aeaaef0ce18b58056d306c27b07436fbb34b8816c53094b76dd81803136" -dependencies = [ - "unindent", -] +checksum = "05a0bd019339e5d968b37855180087b7b9d512c5046fbd244cf8c95687927d6e" [[package]] name = "instant" @@ -1280,12 +1277,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" -[[package]] -name = "unindent" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" - [[package]] name = "url" version = "2.2.2" diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index f1903f04b..3da5a74ec 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -77,5 +77,5 @@ helix-loader = { version = "0.6", path = "../helix-loader" } [dev-dependencies] smallvec = "1.8" -indoc = "1.0.3" +indoc = "1.0.6" tempfile = "3.3.0" From d900b8bb23d0c962b2b0321adeb607394dc1ad70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jun 2022 19:36:28 +0900 Subject: [PATCH 406/861] build(deps): bump thiserror from 1.0.30 to 1.0.31 (#2899) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.30 to 1.0.31. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.30...1.0.31) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... 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 78e5cccdc..b8d784970 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1108,18 +1108,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", From ac1d8fa505e926d981682317e4e3d289bec4eb49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jun 2022 19:36:38 +0900 Subject: [PATCH 407/861] build(deps): bump smallvec from 1.8.0 to 1.8.1 (#2901) Bumps [smallvec](https://github.com/servo/rust-smallvec) from 1.8.0 to 1.8.1. - [Release notes](https://github.com/servo/rust-smallvec/releases) - [Commits](https://github.com/servo/rust-smallvec/compare/v1.8.0...v1.8.1) --- updated-dependencies: - dependency-name: smallvec dependency-type: direct:production update-type: version-update:semver-patch ... 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 b8d784970..6d94b6d7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1021,9 +1021,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" [[package]] name = "smartstring" From 030de46e6b9568f27fd89b1543d978b21da7464e Mon Sep 17 00:00:00 2001 From: PabloMansanet Date: Tue, 28 Jun 2022 21:30:27 +0900 Subject: [PATCH 408/861] Fix recursive macro crash and empty macro lockout (#2902) --- helix-term/src/commands.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 0a28444bd..d1bec0cef 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4655,8 +4655,6 @@ fn replay_macro(cx: &mut Context) { return; } - cx.editor.macro_replaying.push(reg); - let keys: Vec = if let Some([keys_str]) = cx.editor.registers.read(reg) { match helix_view::input::parse_macro(keys_str) { Ok(keys) => keys, @@ -4670,6 +4668,10 @@ fn replay_macro(cx: &mut Context) { return; }; + // Once the macro has been fully validated, it's marked as being under replay + // to ensure we don't fall into infinite recursion. + cx.editor.macro_replaying.push(reg); + let count = cx.count(); cx.callback = Some(Box::new(move |compositor, cx| { for _ in 0..count { @@ -4677,7 +4679,9 @@ fn replay_macro(cx: &mut Context) { compositor.handle_event(crossterm::event::Event::Key(key.into()), cx); } } + // The macro under replay is cleared at the end of the callback, not in the + // macro replay context, or it will not correctly protect the user from + // replaying recursively. + cx.editor.macro_replaying.pop(); })); - - cx.editor.macro_replaying.pop(); } From 07e7a13a9e6b0a6c0bb456504b62572ec6be9eb2 Mon Sep 17 00:00:00 2001 From: Seth Bromberger Date: Tue, 28 Jun 2022 10:59:10 -0400 Subject: [PATCH 409/861] fixes background reset (#2900) * fixes background reset * moves creation of default style out of loop * patches with background_style * removes commented code --- helix-term/src/ui/editor.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 32f70c8b1..948803eb0 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -668,13 +668,16 @@ impl EditorView { let hint = theme.get("hint"); let mut lines = Vec::new(); + let background_style = theme.get("ui.background"); for diagnostic in diagnostics { - let style = Style::reset().patch(match diagnostic.severity { - Some(Severity::Error) => error, - Some(Severity::Warning) | None => warning, - Some(Severity::Info) => info, - Some(Severity::Hint) => hint, - }); + let style = Style::reset() + .patch(background_style) + .patch(match diagnostic.severity { + Some(Severity::Error) => error, + Some(Severity::Warning) | None => warning, + Some(Severity::Info) => info, + Some(Severity::Hint) => hint, + }); let text = Text::styled(&diagnostic.message, style); lines.extend(text.lines); } From bf1db737d4ab9030e56283c45bba525ef81e1daa Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 29 Jun 2022 03:53:56 -0500 Subject: [PATCH 410/861] nix: update nixCargoIntegration (#2907) This fixes the aarch64-darwin build - the newer revision uses the cCompiler override to compile tree-sitter with clang instead of gcc (which fails). --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index df059e476..4f0841a7f 100644 --- a/flake.lock +++ b/flake.lock @@ -19,11 +19,11 @@ "devshell": { "flake": false, "locked": { - "lastModified": 1654858401, - "narHash": "sha256-53bw34DtVJ2bnF6WEwy6Tym+qY0pNEiEwARUlvmTZjs=", + "lastModified": 1655976588, + "narHash": "sha256-VreHyH6ITkf/1EX/8h15UqhddJnUleb0HgbC3gMkAEQ=", "owner": "numtide", "repo": "devshell", - "rev": "f55e05c6d3bbe9acc7363bc8fc739518b2f02976", + "rev": "899ca4629020592a13a46783587f6e674179d1db", "type": "github" }, "original": { @@ -73,11 +73,11 @@ ] }, "locked": { - "lastModified": 1655826285, - "narHash": "sha256-dyrNTVBefSZWKdFNnAW+zUkO5bVo1colvLje4l1XXwA=", + "lastModified": 1655975833, + "narHash": "sha256-g8sdfuglIZ24oWVbntVzniNTJW+Z3n9DNL9w9Tt+UCE=", "owner": "nix-community", "repo": "dream2nix", - "rev": "f23add2b9c313c63dea5cff71523a850d29ffddb", + "rev": "4e75e665ec3a1cddae5266bed0dd72fce0b74a23", "type": "github" }, "original": { @@ -113,11 +113,11 @@ ] }, "locked": { - "lastModified": 1655826649, - "narHash": "sha256-C4/7CdB/mzuD9ayWvEA3Jcog6INCq+oUJZxUsIP/GvE=", + "lastModified": 1656453541, + "narHash": "sha256-ZCPVnS6zJOZJvIlwU3rKR8MBVm6A3F4/0mA7G1lQ3D0=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "5cf1685c021c47631a2fb16533c00c8d68afd09e", + "rev": "9eb74345b30cd2e536d9dac9d4435d3c475605c7", "type": "github" }, "original": { From 6ac6080969dcd344597995c4b98a43406658aa8a Mon Sep 17 00:00:00 2001 From: Stuart Hinson Date: Wed, 29 Jun 2022 10:08:05 -0400 Subject: [PATCH 411/861] primary cursorline for Dracula theme (#2915) --- runtime/themes/dracula.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index 72b37d027..6cc037b8e 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -23,6 +23,7 @@ "ui.cursor" = { fg = "background", bg = "orange", modifiers = ["dim"] } "ui.cursor.match" = { fg = "green", modifiers = ["underlined"] } "ui.cursor.primary" = { fg = "background", bg = "cyan", modifier = ["dim"] } +"ui.cursorline.primary" = { bg = "background_dark" } "ui.help" = { fg = "foreground", bg = "background_dark" } "ui.linenr" = { fg = "comment" } "ui.linenr.selected" = { fg = "foreground" } From 15ac1142cf28196fc1b7749f5eae0c04186305d9 Mon Sep 17 00:00:00 2001 From: Ben Lee-Cohen Date: Wed, 29 Jun 2022 10:13:49 -0400 Subject: [PATCH 412/861] Adding a cursorline for the Nord theme (#2916) --- runtime/themes/nord.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/themes/nord.toml b/runtime/themes/nord.toml index 3b994bb59..f7ef079b0 100644 --- a/runtime/themes/nord.toml +++ b/runtime/themes/nord.toml @@ -1,6 +1,7 @@ # Author : RayGervais "ui.linenr.selected" = { fg = "nord4" } +"ui.cursorline.primary" = { bg = "nord1" } "ui.text.focus" = { fg = "nord8", modifiers= ["bold"] } "ui.menu" = { fg = "nord6", bg = "#232d38" } "ui.menu.selected" = { fg = "nord8", bg = "nord2" } From 94fc41a41920fc705f01637e7902f06a1c32d998 Mon Sep 17 00:00:00 2001 From: Jens Getreu Date: Wed, 29 Jun 2022 21:14:16 +0200 Subject: [PATCH 413/861] Add cursorline to Autumn theme (#2918) Co-authored-by: Jens Getreu --- runtime/themes/autumn.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runtime/themes/autumn.toml b/runtime/themes/autumn.toml index 68e41f5af..c4e0cfd62 100644 --- a/runtime/themes/autumn.toml +++ b/runtime/themes/autumn.toml @@ -13,13 +13,15 @@ "ui.linenr" = { fg = "my_gray4", bg = "my_gray2" } "ui.popup" = { bg = "my_gray2" } "ui.window" = { fg = "my_gray4", bg = "my_gray2" } -"ui.linenr.selected" = { fg = "my_gray6", bg = "my_gray2", modifiers = ["bold"]} +"ui.linenr.selected" = { fg = "my_gray6", bg = "my_gray1"} "ui.selection" = { bg = "my_gray3" } "comment" = { fg = "my_gray4", modifiers = ["italic"] } "ui.statusline" = { fg = "my_gray6", bg = "my_gray2" } "ui.statusline.inactive" = { fg = 'my_gray4', bg = 'my_gray2' } "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" @@ -64,6 +66,7 @@ "error" = "my_red" [palette] +my_black = "#242424" # Cursorline my_gray0 = "#292929" # Default Background my_gray1 = "#2e2e2e" # Ruler my_gray2 = "#3a3a3a" # Lighter Background (Used for status bars, line number and folding marks) From ed89f8897eab84bf7614a718d5d1e3ec5c57086c Mon Sep 17 00:00:00 2001 From: Falco Hirschenberger Date: Thu, 30 Jun 2022 11:16:18 +0200 Subject: [PATCH 414/861] Add workspace and document diagnostics picker (#2013) * Add workspace and document diagnostics picker fixes #1891 * Fix some of @archseer's annotations * Add From<&Spans> impl for String * More descriptive parameter names. * Adding From> impls for Span and Spans * Add new keymap entries to docs * Avoid some clones * Fix api change * Update helix-term/src/application.rs Co-authored-by: Bjorn Ove Hay Andersen * Fix a clippy hint * Sort diagnostics first by URL and then by severity. * Sort diagnostics first by URL and then by severity. * Ignore missing lsp severity entries * Add truncated filepath * Typo * Strip cwd from paths and use url-path without schema * Make tests a doctest * Better variable names Co-authored-by: Falco Hirschenberger Co-authored-by: Bjorn Ove Hay Andersen --- book/src/keymap.md | 2 + helix-core/src/path.rs | 51 ++++++++++++ helix-term/src/application.rs | 28 +++++-- helix-term/src/commands.rs | 12 +-- helix-term/src/commands/lsp.rs | 135 ++++++++++++++++++++++++++++++- helix-term/src/keymap/default.rs | 2 + helix-term/src/ui/mod.rs | 4 +- helix-term/src/ui/picker.rs | 61 +++++++------- helix-tui/src/text.rs | 23 +++++- helix-tui/src/widgets/block.rs | 2 +- helix-view/src/editor.rs | 3 + xtask/src/main.rs | 2 +- 12 files changed, 273 insertions(+), 52 deletions(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index e6abb9c92..b979cfd89 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -241,6 +241,8 @@ This layer is a kludge of mappings, mostly pickers. | `k` | Show documentation for item under cursor in a [popup](#popup) (**LSP**) | `hover` | | `s` | Open document symbol picker (**LSP**) | `symbol_picker` | | `S` | Open workspace symbol picker (**LSP**) | `workspace_symbol_picker` | +| `g` | Open document diagnosics picker (**LSP**) | `diagnostics_picker` | +| `G` | Open workspace diagnostics picker (**LSP**) | `workspace_diagnosics_picker` | `r` | Rename symbol (**LSP**) | `rename_symbol` | | `a` | Apply code action (**LSP**) | `code_action` | | `'` | Open last fuzzy picker | `last_picker` | diff --git a/helix-core/src/path.rs b/helix-core/src/path.rs index cb50e136c..d59a6baad 100644 --- a/helix-core/src/path.rs +++ b/helix-core/src/path.rs @@ -90,3 +90,54 @@ pub fn get_relative_path(path: &Path) -> PathBuf { }; fold_home_dir(path) } + +/// Returns a truncated filepath where the basepart of the path is reduced to the first +/// char of the folder and the whole filename appended. +/// +/// Also strip the current working directory from the beginning of the path. +/// Note that this function does not check if the truncated path is unambiguous. +/// +/// ``` +/// use helix_core::path::get_truncated_path; +/// use std::path::Path; +/// +/// assert_eq!( +/// get_truncated_path("/home/cnorris/documents/jokes.txt").as_path(), +/// Path::new("/h/c/d/jokes.txt") +/// ); +/// assert_eq!( +/// get_truncated_path("jokes.txt").as_path(), +/// Path::new("jokes.txt") +/// ); +/// assert_eq!( +/// get_truncated_path("/jokes.txt").as_path(), +/// Path::new("/jokes.txt") +/// ); +/// assert_eq!( +/// get_truncated_path("/h/c/d/jokes.txt").as_path(), +/// Path::new("/h/c/d/jokes.txt") +/// ); +/// assert_eq!(get_truncated_path("").as_path(), Path::new("")); +/// ``` +/// +pub fn get_truncated_path>(path: P) -> PathBuf { + let cwd = std::env::current_dir().unwrap_or_default(); + let path = path + .as_ref() + .strip_prefix(cwd) + .unwrap_or_else(|_| path.as_ref()); + let file = path.file_name().unwrap_or_default(); + let base = path.parent().unwrap_or_else(|| Path::new("")); + let mut ret = PathBuf::new(); + for d in base { + ret.push( + d.to_string_lossy() + .chars() + .next() + .unwrap_or_default() + .to_string(), + ); + } + ret.push(file); + ret +} diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 48e9c2758..23f4610f6 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -495,7 +495,7 @@ impl Application { )); } } - Notification::PublishDiagnostics(params) => { + Notification::PublishDiagnostics(mut params) => { let path = params.uri.to_file_path().unwrap(); let doc = self.editor.document_by_path_mut(&path); @@ -505,12 +505,9 @@ impl Application { let diagnostics = params .diagnostics - .into_iter() + .iter() .filter_map(|diagnostic| { - use helix_core::{ - diagnostic::{Range, Severity::*}, - Diagnostic, - }; + use helix_core::diagnostic::{Diagnostic, Range, Severity::*}; use lsp::DiagnosticSeverity; let language_server = doc.language_server().unwrap(); @@ -561,7 +558,7 @@ impl Application { Some(Diagnostic { range: Range { start, end }, line: diagnostic.range.start.line as usize, - message: diagnostic.message, + message: diagnostic.message.clone(), severity, // code // source @@ -571,6 +568,23 @@ impl Application { doc.set_diagnostics(diagnostics); } + + // Sort diagnostics first by URL and then by severity. + // Note: The `lsp::DiagnosticSeverity` enum is already defined in decreasing order + params.diagnostics.sort_unstable_by(|a, b| { + if let (Some(a), Some(b)) = (a.severity, b.severity) { + a.partial_cmp(&b).unwrap() + } else { + std::cmp::Ordering::Equal + } + }); + + // Insert the original lsp::Diagnostics here because we may have no open document + // for diagnosic message and so we can't calculate the exact position. + // When using them later in the diagnostics picker, we calculate them on-demand. + self.editor + .diagnostics + .insert(params.uri, params.diagnostics); } Notification::ShowMessage(params) => { log::warn!("unhandled window/showMessage: {:?}", params); diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index d1bec0cef..bc8e65302 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4,6 +4,7 @@ pub(crate) mod typed; pub use dap::*; pub use lsp::*; +use tui::text::Spans; pub use typed::*; use helix_core::{ @@ -265,6 +266,8 @@ impl MappableCommand { symbol_picker, "Open symbol picker", select_references_to_symbol_under_cursor, "Select symbol references", workspace_symbol_picker, "Open workspace symbol picker", + diagnostics_picker, "Open diagnostic picker", + workspace_diagnostics_picker, "Open workspace diagnostic picker", last_picker, "Open last picker", prepend_to_line, "Insert at start of line", append_to_line, "Insert at end of line", @@ -2170,7 +2173,7 @@ fn buffer_picker(cx: &mut Context) { } impl BufferMeta { - fn format(&self) -> Cow { + fn format(&self) -> Spans { let path = self .path .as_deref() @@ -2193,7 +2196,7 @@ fn buffer_picker(cx: &mut Context) { } else { format!(" ({})", flags.join("")) }; - Cow::Owned(format!("{} {}{}", self.id, path, flag)) + format!("{} {}{}", self.id, path, flag).into() } } @@ -2260,10 +2263,9 @@ pub fn command_palette(cx: &mut Context) { let picker = Picker::new( commands, move |command| match command { - MappableCommand::Typable { doc, name, .. } => match keymap.get(name as &String) - { + MappableCommand::Typable { doc, name, .. } => match keymap.get(name) { Some(bindings) => format!("{} ({})", doc, fmt_binding(bindings)).into(), - None => doc.into(), + None => doc.as_str().into(), }, MappableCommand::Static { doc, name, .. } => match keymap.get(*name) { Some(bindings) => format!("{} ({})", doc, fmt_binding(bindings)).into(), diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index c1cdb1642..d11c44cd4 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -1,20 +1,25 @@ use helix_lsp::{ - block_on, lsp, + block_on, + lsp::{self, DiagnosticSeverity, NumberOrString}, util::{diagnostic_to_lsp_diagnostic, lsp_pos_to_pos, lsp_range_to_range, range_to_lsp_range}, OffsetEncoding, }; +use tui::text::{Span, Spans}; use super::{align_view, push_jump, Align, Context, Editor}; -use helix_core::Selection; -use helix_view::editor::Action; +use helix_core::{path, Selection}; +use helix_view::{ + editor::Action, + theme::{Modifier, Style}, +}; use crate::{ compositor::{self, Compositor}, ui::{self, overlay::overlayed, FileLocation, FilePicker, Popup, PromptEvent}, }; -use std::borrow::Cow; +use std::{borrow::Cow, collections::BTreeMap}; /// Gets the language server that is attached to a document, and /// if it's not active displays a status message. Using this macro @@ -145,6 +150,97 @@ fn sym_picker( .truncate_start(false) } +fn diag_picker( + cx: &Context, + diagnostics: BTreeMap>, + current_path: Option, + offset_encoding: OffsetEncoding, +) -> FilePicker<(lsp::Url, lsp::Diagnostic)> { + // TODO: drop current_path comparison and instead use workspace: bool flag? + + // flatten the map to a vec of (url, diag) pairs + let mut flat_diag = Vec::new(); + for (url, diags) in diagnostics { + flat_diag.reserve(diags.len()); + for diag in diags { + flat_diag.push((url.clone(), diag)); + } + } + + let hint = cx.editor.theme.get("hint"); + let info = cx.editor.theme.get("info"); + let warning = cx.editor.theme.get("warning"); + let error = cx.editor.theme.get("error"); + + FilePicker::new( + flat_diag, + move |(url, diag)| { + let mut style = diag + .severity + .map(|s| match s { + DiagnosticSeverity::HINT => hint, + DiagnosticSeverity::INFORMATION => info, + DiagnosticSeverity::WARNING => warning, + DiagnosticSeverity::ERROR => error, + _ => Style::default(), + }) + .unwrap_or_default(); + + // remove background as it is distracting in the picker list + style.bg = None; + + let code = diag + .code + .as_ref() + .map(|c| match c { + NumberOrString::Number(n) => n.to_string(), + NumberOrString::String(s) => s.to_string(), + }) + .unwrap_or_default(); + + let truncated_path = path::get_truncated_path(url.path()) + .to_string_lossy() + .into_owned(); + + Spans::from(vec![ + Span::styled( + diag.source.clone().unwrap_or_default(), + style.add_modifier(Modifier::BOLD), + ), + Span::raw(": "), + Span::styled(truncated_path, style), + Span::raw(" - "), + Span::styled(code, style.add_modifier(Modifier::BOLD)), + Span::raw(": "), + Span::styled(&diag.message, style), + ]) + }, + move |cx, (url, diag), action| { + if current_path.as_ref() == Some(url) { + let (view, doc) = current!(cx.editor); + push_jump(view, doc); + } else { + let path = url.to_file_path().unwrap(); + cx.editor.open(&path, action).expect("editor.open failed"); + } + + let (view, doc) = current!(cx.editor); + + if let Some(range) = lsp_range_to_range(doc.text(), diag.range, offset_encoding) { + // we flip the range so that the cursor sits on the start of the symbol + // (for example start of the function). + doc.set_selection(view.id, Selection::single(range.head, range.anchor)); + align_view(doc, view, Align::Center); + } + }, + move |_editor, (url, diag)| { + let location = lsp::Location::new(url.clone(), diag.range); + Some(location_to_file_location(&location)) + }, + ) + .truncate_start(false) +} + pub fn symbol_picker(cx: &mut Context) { fn nested_to_flat( list: &mut Vec, @@ -215,6 +311,37 @@ pub fn workspace_symbol_picker(cx: &mut Context) { ) } +pub fn diagnostics_picker(cx: &mut Context) { + let doc = doc!(cx.editor); + let language_server = language_server!(cx.editor, doc); + if let Some(current_url) = doc.url() { + let offset_encoding = language_server.offset_encoding(); + let diagnostics = cx + .editor + .diagnostics + .get(¤t_url) + .cloned() + .unwrap_or_default(); + let picker = diag_picker( + cx, + [(current_url.clone(), diagnostics)].into(), + Some(current_url), + offset_encoding, + ); + cx.push_layer(Box::new(overlayed(picker))); + } +} + +pub fn workspace_diagnostics_picker(cx: &mut Context) { + let doc = doc!(cx.editor); + let language_server = language_server!(cx.editor, doc); + let current_url = doc.url(); + let offset_encoding = language_server.offset_encoding(); + let diagnostics = cx.editor.diagnostics.clone(); + let picker = diag_picker(cx, diagnostics, current_url, offset_encoding); + cx.push_layer(Box::new(overlayed(picker))); +} + impl ui::menu::Item for lsp::CodeActionOrCommand { fn label(&self) -> &str { match self { diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index e5bb0482d..29b0b6706 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -207,6 +207,8 @@ pub fn default() -> HashMap { "b" => buffer_picker, "s" => symbol_picker, "S" => workspace_symbol_picker, + "g" => diagnostics_picker, + "G" => workspace_diagnostics_picker, "a" => code_action, "'" => last_picker, "d" => { "Debug (experimental)" sticky=true diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 47a68a18f..c1e5c9889 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -23,6 +23,8 @@ pub use text::Text; use helix_core::regex::Regex; use helix_core::regex::RegexBuilder; use helix_view::{Document, Editor, View}; +use tui; +use tui::text::Spans; use std::path::PathBuf; @@ -172,7 +174,7 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi files, move |path: &PathBuf| { // format_fn - path.strip_prefix(&root).unwrap_or(path).to_string_lossy() + Spans::from(path.strip_prefix(&root).unwrap_or(path).to_string_lossy()) }, move |cx, path: &PathBuf, action| { if let Err(e) = cx.editor.open(path, action) { diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index ebff98274..1581b0a15 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -6,6 +6,7 @@ use crate::{ use crossterm::event::Event; use tui::{ buffer::Buffer as Surface, + text::Spans, widgets::{Block, BorderType, Borders}, }; @@ -15,7 +16,6 @@ use tui::widgets::Widget; use std::time::Instant; use std::{ - borrow::Cow, cmp::Reverse, collections::HashMap, io::Read, @@ -87,7 +87,7 @@ impl Preview<'_, '_> { impl FilePicker { pub fn new( options: Vec, - format_fn: impl Fn(&T) -> Cow + 'static, + format_fn: impl Fn(&T) -> Spans + 'static, callback_fn: impl Fn(&mut Context, &T, Action) + 'static, preview_fn: impl Fn(&Editor, &T) -> Option + 'static, ) -> Self { @@ -299,14 +299,14 @@ pub struct Picker { /// Whether to truncate the start (default true) pub truncate_start: bool, - format_fn: Box Cow>, + format_fn: Box Spans>, callback_fn: Box, } impl Picker { pub fn new( options: Vec, - format_fn: impl Fn(&T) -> Cow + 'static, + format_fn: impl Fn(&T) -> Spans + 'static, callback_fn: impl Fn(&mut Context, &T, Action) + 'static, ) -> Self { let prompt = Prompt::new( @@ -372,9 +372,8 @@ impl Picker { self.matches.retain_mut(|(index, score)| { let option = &self.options[*index]; // TODO: maybe using format_fn isn't the best idea here - let text = (self.format_fn)(option); - - match self.matcher.fuzzy_match(&text, pattern) { + let line: String = (self.format_fn)(option).into(); + match self.matcher.fuzzy_match(&line, pattern) { Some(s) => { // Update the score *score = s; @@ -401,10 +400,10 @@ impl Picker { } // TODO: maybe using format_fn isn't the best idea here - let text = (self.format_fn)(option); + let line: String = (self.format_fn)(option).into(); self.matcher - .fuzzy_match(&text, pattern) + .fuzzy_match(&line, pattern) .map(|score| (index, score)) }), ); @@ -611,30 +610,34 @@ impl Component for Picker { surface.set_string(inner.x.saturating_sub(2), inner.y + i as u16, ">", selected); } - let formatted = (self.format_fn)(option); - + let spans = (self.format_fn)(option); let (_score, highlights) = self .matcher - .fuzzy_indices(&formatted, self.prompt.line()) + .fuzzy_indices(&String::from(&spans), self.prompt.line()) .unwrap_or_default(); - surface.set_string_truncated( - inner.x, - inner.y + i as u16, - &formatted, - inner.width as usize, - |idx| { - if highlights.contains(&idx) { - highlighted - } else if is_active { - selected - } else { - text_style - } - }, - true, - self.truncate_start, - ); + spans.0.into_iter().fold(inner, |pos, span| { + let new_x = surface + .set_string_truncated( + pos.x, + pos.y + i as u16, + &span.content, + pos.width as usize, + |idx| { + if highlights.contains(&idx) { + highlighted.patch(span.style) + } else if is_active { + selected.patch(span.style) + } else { + text_style.patch(span.style) + } + }, + true, + self.truncate_start, + ) + .0; + pos.clip_left(new_x - pos.x) + }); } } diff --git a/helix-tui/src/text.rs b/helix-tui/src/text.rs index 8a974ddba..b4278c864 100644 --- a/helix-tui/src/text.rs +++ b/helix-tui/src/text.rs @@ -194,6 +194,12 @@ impl<'a> From<&'a str> for Span<'a> { } } +impl<'a> From> for Span<'a> { + fn from(s: Cow<'a, str>) -> Span<'a> { + Span::raw(s) + } +} + /// A string composed of clusters of graphemes, each with their own style. #[derive(Debug, Default, Clone, PartialEq)] pub struct Spans<'a>(pub Vec>); @@ -229,6 +235,12 @@ impl<'a> From<&'a str> for Spans<'a> { } } +impl<'a> From> for Spans<'a> { + fn from(s: Cow<'a, str>) -> Spans<'a> { + Spans(vec![Span::raw(s)]) + } +} + impl<'a> From>> for Spans<'a> { fn from(spans: Vec>) -> Spans<'a> { Spans(spans) @@ -243,10 +255,13 @@ impl<'a> From> for Spans<'a> { impl<'a> From> for String { fn from(line: Spans<'a>) -> String { - line.0.iter().fold(String::new(), |mut acc, s| { - acc.push_str(s.content.as_ref()); - acc - }) + line.0.iter().map(|s| &*s.content).collect() + } +} + +impl<'a> From<&Spans<'a>> for String { + fn from(line: &Spans<'a>) -> String { + line.0.iter().map(|s| &*s.content).collect() } } diff --git a/helix-tui/src/widgets/block.rs b/helix-tui/src/widgets/block.rs index 3c05a2a3c..bd025a316 100644 --- a/helix-tui/src/widgets/block.rs +++ b/helix-tui/src/widgets/block.rs @@ -77,7 +77,7 @@ impl<'a> Block<'a> { )] pub fn title_style(mut self, style: Style) -> Block<'a> { if let Some(t) = self.title { - let title = String::from(t); + let title = String::from(&t); self.title = Some(Spans::from(Span::styled(title, style))); } self diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index a9741a33f..c160dd377 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -39,6 +39,7 @@ use helix_core::{ Change, }; use helix_dap as dap; +use helix_lsp::lsp; use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer}; @@ -462,6 +463,7 @@ pub struct Editor { pub macro_replaying: Vec, pub theme: Theme, pub language_servers: helix_lsp::Registry, + pub diagnostics: BTreeMap>, pub debugger: Option, pub debugger_events: SelectAll>, @@ -533,6 +535,7 @@ impl Editor { macro_replaying: Vec::new(), theme: theme_loader.default(), language_servers, + diagnostics: BTreeMap::new(), debugger: None, debugger_events: SelectAll::new(), breakpoints: HashMap::new(), diff --git a/xtask/src/main.rs b/xtask/src/main.rs index a4c69d701..f66fb4f42 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -106,7 +106,7 @@ pub mod md_gen { .collect::>() .join(", "); - let doc = cmd.doc.replace("\n", "
"); + let doc = cmd.doc.replace('\n', "
"); md.push_str(&md_table_row(&[names.to_owned(), doc.to_owned()])); } From d06800f1dd47315f5738c529d40d1e0952ee2115 Mon Sep 17 00:00:00 2001 From: Mathspy Date: Thu, 30 Jun 2022 05:26:00 -0400 Subject: [PATCH 415/861] Add mode specific styles (#2676) * Add mode specific styles In similar vein to neovim's lualine and similar statusline packages this allows helix users to style their mode based on which mode it is thus making each mode more visually distinct at a glance * Add an example based on rosepine * Add editor.colors-mode config * Document statusline mode styles --- book/src/configuration.md | 1 + book/src/themes.md | 7 +++++-- helix-term/src/ui/editor.rs | 21 ++++++++++++++------- helix-view/src/editor.rs | 3 +++ runtime/themes/rose_pine.toml | 3 +++ 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index af85379f8..1cc8602ad 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -46,6 +46,7 @@ hidden = false | `auto-info` | Whether to display infoboxes | `true` | | `true-color` | Set to `true` to override automatic detection of terminal truecolor support in the event of a false negative. | `false` | | `rulers` | List of column positions at which to display the rulers. Can be overridden by language specific `rulers` in `languages.toml` file. | `[]` | +| `color-modes` | Whether to color the mode indicator with different colors depending on the mode itself | `false` | ### `[editor.lsp]` Section diff --git a/book/src/themes.md b/book/src/themes.md index 6c6393de0..06f920d3c 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -219,6 +219,9 @@ These scopes are used for theming the editor interface. | `ui.linenr.selected` | Line number for the line the cursor is on | | `ui.statusline` | Statusline | | `ui.statusline.inactive` | Statusline (unfocused document) | +| `ui.statusline.normal` | Statusline mode during normal mode ([only if `editor.color-modes` is enabled][editor-section]) | +| `ui.statusline.insert` | Statusline mode during insert mode ([only if `editor.color-modes` is enabled][editor-section]) | +| `ui.statusline.select` | Statusline mode during select mode ([only if `editor.color-modes` is enabled][editor-section]) | | `ui.popup` | Documentation popups (e.g space-k) | | `ui.popup.info` | Prompt for multiple key options | | `ui.window` | Border lines separating splits | @@ -226,7 +229,7 @@ These scopes are used for theming the editor interface. | `ui.text` | Command prompts, popup text, etc. | | `ui.text.focus` | | | `ui.text.info` | The key: command text in `ui.popup.info` boxes | -| `ui.virtual.ruler` | Ruler columns (see the [`editor.rulers` config][rulers-config])| +| `ui.virtual.ruler` | Ruler columns (see the [`editor.rulers` config][editor-section])| | `ui.virtual.whitespace` | Visible white-space characters | | `ui.virtual.indent-guide` | Vertical indent width guides | | `ui.menu` | Code and command completion menus | @@ -246,4 +249,4 @@ These scopes are used for theming the editor interface. | `diagnostic.warning` | Diagnostics warning (editing area) | | `diagnostic.error` | Diagnostics error (editing area) | -[rulers-config]: ./configuration.md#editor-section +[editor-section]: ./configuration.md#editor-section diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 948803eb0..a7c67a219 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -161,7 +161,7 @@ impl EditorView { .area .clip_top(view.area.height.saturating_sub(1)) .clip_bottom(1); // -1 from bottom to remove commandline - self.render_statusline(doc, view, statusline_area, surface, theme, is_focused); + self.render_statusline(editor, doc, view, statusline_area, surface, is_focused); } pub fn render_rulers( @@ -732,11 +732,11 @@ impl EditorView { pub fn render_statusline( &self, + editor: &Editor, doc: &Document, view: &View, viewport: Rect, surface: &mut Surface, - theme: &Theme, is_focused: bool, ) { use tui::text::{Span, Spans}; @@ -745,10 +745,11 @@ impl EditorView { // Left side of the status line. //------------------------------- - let mode = match doc.mode() { - Mode::Insert => "INS", - Mode::Select => "SEL", - Mode::Normal => "NOR", + let theme = &editor.theme; + let (mode, mode_style) = match doc.mode() { + Mode::Insert => (" INS ", theme.get("ui.statusline.insert")), + Mode::Select => (" SEL ", theme.get("ui.statusline.select")), + Mode::Normal => (" NOR ", theme.get("ui.statusline.normal")), }; let progress = doc .language_server() @@ -767,7 +768,13 @@ impl EditorView { // statusline surface.set_style(viewport.with_height(1), base_style); if is_focused { - surface.set_string(viewport.x + 1, viewport.y, mode, base_style); + let color_modes = editor.config().color_modes; + surface.set_string( + viewport.x, + viewport.y, + mode, + if color_modes { mode_style } else { base_style }, + ); } surface.set_string(viewport.x + 5, viewport.y, progress, base_style); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index c160dd377..1ed27e996 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -161,6 +161,8 @@ pub struct Config { pub whitespace: WhitespaceConfig, /// Vertical indent width guides. pub indent_guides: IndentGuidesConfig, + /// Whether to color modes with different colors. Defaults to `false`. + pub color_modes: bool, } #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] @@ -414,6 +416,7 @@ impl Default for Config { rulers: Vec::new(), whitespace: WhitespaceConfig::default(), indent_guides: IndentGuidesConfig::default(), + color_modes: false, } } } diff --git a/runtime/themes/rose_pine.toml b/runtime/themes/rose_pine.toml index 09b1e25c9..fd53abd58 100644 --- a/runtime/themes/rose_pine.toml +++ b/runtime/themes/rose_pine.toml @@ -9,6 +9,9 @@ "ui.selection" = { bg = "highlight" } "comment" = "subtle" "ui.statusline" = {fg = "foam", bg = "surface" } +"ui.statusline.insert" = {fg = "base", bg = "foam", modifiers = ["bold"]} +"ui.statusline.normal" = {fg = "base", bg = "rose", modifiers = ["bold"]} +"ui.statusline.select" = {fg = "base", bg = "iris", modifiers = ["bold"]} "ui.statusline.inactive" = { fg = "iris", bg = "surface" } "ui.cursor" = { fg = "rose", modifiers = ["reversed"] } "ui.text" = { fg = "text" } From f2768da1f6312efe6f87f80a6541da5225c2fc7c Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Thu, 30 Jun 2022 17:52:31 -0400 Subject: [PATCH 416/861] add mode colors to solarized (#2926) --- runtime/themes/solarized_dark.toml | 6 +++++- runtime/themes/solarized_light.toml | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/runtime/themes/solarized_dark.toml b/runtime/themes/solarized_dark.toml index d8126f6ea..002e99bc7 100644 --- a/runtime/themes/solarized_dark.toml +++ b/runtime/themes/solarized_dark.toml @@ -48,6 +48,10 @@ # 状态栏 "ui.statusline" = { fg = "base03", bg = "base0" } +"ui.statusline.normal" = { bg = "blue" } +"ui.statusline.insert" = { bg = "green" } +"ui.statusline.select" = { bg = "yellow" } + # 非活动状态栏 "ui.statusline.inactive" = { fg = "base1", bg = "base01" } @@ -55,7 +59,7 @@ "ui.popup" = { bg = "base02" } # 影响 补全选中 cmd弹出信息选中 "ui.menu.selected" = { fg = "base02", bg = "base2"} -"ui.menu" = { fg = "base1" } +"ui.menu" = { fg = "base0", bg = "base02" } # ?? "ui.window" = { fg = "base3" } # 命令行 补全的帮助信息 diff --git a/runtime/themes/solarized_light.toml b/runtime/themes/solarized_light.toml index cd1028bda..fa58cc8cf 100644 --- a/runtime/themes/solarized_light.toml +++ b/runtime/themes/solarized_light.toml @@ -52,6 +52,10 @@ # 状态栏 # status bar "ui.statusline" = { fg = "base03", bg = "base0" } +"ui.statusline.normal" = { bg = "blue" } +"ui.statusline.insert" = { bg = "green" } +"ui.statusline.select" = { bg = "yellow" } + # 非活动状态栏 # inactive status bar "ui.statusline.inactive" = { fg = "base1", bg = "base01" } From 26501afe13bcb513a5dec764daccdcfd166a7114 Mon Sep 17 00:00:00 2001 From: Sora Date: Fri, 1 Jul 2022 00:14:55 +0200 Subject: [PATCH 417/861] Update cursorline for tokyonight + tokyonight_storm (#2927) Co-authored-by: s0LA1337 --- runtime/themes/tokyonight.toml | 1 + runtime/themes/tokyonight_storm.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/runtime/themes/tokyonight.toml b/runtime/themes/tokyonight.toml index 14cc40e2d..4f1ea1cfe 100644 --- a/runtime/themes/tokyonight.toml +++ b/runtime/themes/tokyonight.toml @@ -30,6 +30,7 @@ "ui.cursor" = { modifiers = ["reversed"] } "ui.cursor.match" = { fg = "orange", modifiers = ["bold"] } "ui.cursor.primary" = { modifiers = ["reversed"] } +"ui.cursorline.primary" = { bg = "background_menu" } "ui.help" = { fg = "foreground", bg = "background_menu" } "ui.linenr" = { fg = "foreground_gutter" } "ui.linenr.selected" = { fg = "foreground" } diff --git a/runtime/themes/tokyonight_storm.toml b/runtime/themes/tokyonight_storm.toml index 6c6fd9c8d..c47ac54ba 100644 --- a/runtime/themes/tokyonight_storm.toml +++ b/runtime/themes/tokyonight_storm.toml @@ -30,6 +30,7 @@ "ui.cursor" = { modifiers = ["reversed"] } "ui.cursor.match" = { fg = "orange", modifiers = ["bold"] } "ui.cursor.primary" = { modifiers = ["reversed"] } +"ui.cursorline.primary" = { bg = "background_menu" } "ui.help" = { fg = "foreground", bg = "background_menu" } "ui.linenr" = { fg = "foreground_gutter" } "ui.linenr.selected" = { fg = "foreground" } From d523280e8533e8d57eda0b9fbc0f076b07002a2b Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 14 Jun 2022 09:39:45 -0500 Subject: [PATCH 418/861] erlang: highlight nullary macros as constants --- runtime/queries/erlang/highlights.scm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/runtime/queries/erlang/highlights.scm b/runtime/queries/erlang/highlights.scm index 0cb60ca99..94f1e9f5a 100644 --- a/runtime/queries/erlang/highlights.scm +++ b/runtime/queries/erlang/highlights.scm @@ -38,8 +38,8 @@ (arguments . [ - (atom) @keyword.directive - (variable) @keyword.directive + (atom) @constant + (variable) @constant (call function: [(variable) (atom)] @keyword.directive) @@ -99,6 +99,11 @@ (comment) @comment ; Macros +(macro + "?"+ @constant + name: (_) @constant + !arguments) + (macro "?"+ @keyword.directive name: (_) @keyword.directive) From bd527c84e64f8a30bb1ae8c4dd634d6deba20825 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 15 Jun 2022 15:25:11 -0500 Subject: [PATCH 419/861] erlang: highlight unary '#' as punctuation.bracket The '#' character may either be interpreted as a map when used like so: %% Example 1 #{a => b} Or as an operator which updates an existing map when the left-hand side is an expression: %% Example 2 MyMap#{a => b} This commit changes the highlight to `punctuation.bracket` when used as a character in a literal map (example 1) and keeps the `operator` highlight when used for updating (example 2). --- runtime/queries/erlang/highlights.scm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/queries/erlang/highlights.scm b/runtime/queries/erlang/highlights.scm index 94f1e9f5a..ce84697b5 100644 --- a/runtime/queries/erlang/highlights.scm +++ b/runtime/queries/erlang/highlights.scm @@ -92,7 +92,7 @@ (binary_operator operator: _ @operator) (unary_operator operator: _ @operator) -["/" ":" "#" "->"] @operator +["/" ":" "->"] @operator (tripledot) @comment.discard @@ -123,6 +123,6 @@ ; Punctuation ["," "." "-" ";"] @punctuation.delimiter -["(" ")" "{" "}" "[" "]" "<<" ">>"] @punctuation.bracket +["(" ")" "#" "{" "}" "[" "]" "<<" ">>"] @punctuation.bracket ; (ERROR) @error From ca82cd86e62392f74d86d2abc647a6fc84d56539 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 28 Jun 2022 20:09:12 -0500 Subject: [PATCH 420/861] markdown: highlight punctuation --- runtime/queries/markdown/highlights.scm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runtime/queries/markdown/highlights.scm b/runtime/queries/markdown/highlights.scm index 44b19741c..aee568c8d 100644 --- a/runtime/queries/markdown/highlights.scm +++ b/runtime/queries/markdown/highlights.scm @@ -47,3 +47,7 @@ (hard_line_break) ] @constant.character.escape +(thematic_break) @punctuation.delimiter + +(inline_link ["[" "]" "(" ")"] @punctuation.bracket) +(image ["[" "]" "(" ")"] @punctuation.bracket) From beb19fe1bd52abd32b56f51d47bf54f744a0d19f Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 28 Jun 2022 20:09:30 -0500 Subject: [PATCH 421/861] bash: expand injection-regex to common shells --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 0e6cbb9cb..7a4b28c4c 100644 --- a/languages.toml +++ b/languages.toml @@ -460,7 +460,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-ruby", rev = "dfff6 [[language]] name = "bash" scope = "source.bash" -injection-regex = "bash" +injection-regex = "(shell|bash|zsh|sh)" file-types = ["sh", "bash", "zsh", ".bash_login", ".bash_logout", ".bash_profile", ".bashrc", ".profile", ".zshenv", ".zlogin", ".zlogout", ".zprofile", ".zshrc", "APKBUILD", "PKGBUILD", "eclass", "ebuild", "bazelrc"] shebangs = ["sh", "bash", "dash"] roots = [] From 78c944ebc3c62c673f203785cdb39498e52115b7 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 28 Jun 2022 20:10:19 -0500 Subject: [PATCH 422/861] rust: fix highlight corner-cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add punctuation highlights for commas as in function parameters * remove stray `variable.parameter` highlight * I couldn't find any regressions from this and it fixes an edge case I ran into (but sadly did not record 😓) * highlight `fn` as `keyword.function` * the theme docs have `fn` as an example so it seems fitting --- runtime/queries/rust/highlights.scm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime/queries/rust/highlights.scm b/runtime/queries/rust/highlights.scm index 4b0c018e2..5897991ee 100644 --- a/runtime/queries/rust/highlights.scm +++ b/runtime/queries/rust/highlights.scm @@ -57,6 +57,7 @@ "::" "." ";" + "," ] @punctuation.delimiter [ @@ -95,8 +96,6 @@ value: (identifier)? @variable field: (field_identifier) @variable.other.member)) -(arguments - (identifier) @variable.parameter) (parameter pattern: (identifier) @variable.parameter) (closure_parameters @@ -141,7 +140,6 @@ "mod" "extern" - "fn" "struct" "enum" "impl" @@ -160,6 +158,8 @@ "async" ] @keyword +"fn" @keyword.function + (mutable_specifier) @keyword.storage.modifier.mut (reference_type "&" @keyword.storage.modifier.ref) From 7cf88f2bacb92e1054294137cc4d82792f4b60a4 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 22 Jun 2022 08:57:22 -0500 Subject: [PATCH 423/861] edoc: prevent rogue punctuation highlights Punctuation highlights would show up outside of where they were valid, for example using parentheses in some text. This change prevents that by gating the captures to being under the named nodes in which they are valid. --- runtime/queries/edoc/highlights.scm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime/queries/edoc/highlights.scm b/runtime/queries/edoc/highlights.scm index 3a309960f..4267cb9e0 100644 --- a/runtime/queries/edoc/highlights.scm +++ b/runtime/queries/edoc/highlights.scm @@ -39,9 +39,9 @@ ; could be @constant.numeric.integer but this looks similar to a capture (arity) @operator -[":" "/"] @operator -["(" ")"] @punctuation.delimiter -["{" "}"] @function.macro +(expression [":" "/"] @operator) +(expression ["(" ")"] @punctuation.delimiter) +(macro ["{" "}"] @function.macro) [ (quote_marker) From 016e97314cd37c245368678179f1157f83a13821 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 28 Jun 2022 10:09:42 -0500 Subject: [PATCH 424/861] html: highlight punctuation * `/>` as in self-closing tags like `
` * `=` as in the separator between attribute name and value `` --- runtime/queries/html/highlights.scm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/runtime/queries/html/highlights.scm b/runtime/queries/html/highlights.scm index 2c70a9c3e..fff015b5c 100644 --- a/runtime/queries/html/highlights.scm +++ b/runtime/queries/html/highlights.scm @@ -2,11 +2,18 @@ (erroneous_end_tag_name) @tag.error (doctype) @constant (attribute_name) @attribute -(attribute_value) @string (comment) @comment +[ + "\"" + (attribute_value) +] @string + [ "<" ">" "" ] @punctuation.bracket + +"=" @punctuation.delimiter From e4e8a39bf79734e70248303782d9b97ef4b3540d Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 28 Jun 2022 13:08:31 -0500 Subject: [PATCH 425/861] replace module captures with namespace `module` is undocumented and does not exist in other themes. The equivalent existing scope based on usage (Elixir for example) is `namespace`. --- runtime/queries/erlang/highlights.scm | 10 +++++----- runtime/queries/heex/highlights.scm | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/runtime/queries/erlang/highlights.scm b/runtime/queries/erlang/highlights.scm index ce84697b5..f491b9c5f 100644 --- a/runtime/queries/erlang/highlights.scm +++ b/runtime/queries/erlang/highlights.scm @@ -2,14 +2,14 @@ ; module declaration (attribute name: (atom) @keyword - (arguments (atom) @module) + (arguments (atom) @namespace) (#eq? @keyword "module")) (attribute name: (atom) @keyword (arguments . - (atom) @module) + (atom) @namespace) (#eq? @keyword "import")) (attribute @@ -54,15 +54,15 @@ (attribute name: (atom) @keyword - module: (atom) @module (#eq? @keyword "(spec|callback)")) + module: (atom) @namespace ; Functions (function_clause name: (atom) @function) -(call module: (atom) @module) +(call module: (atom) @namespace) (call function: (atom) @function) (stab_clause name: (atom) @function) -(function_capture module: (atom) @module) +(function_capture module: (atom) @namespace) (function_capture function: (atom) @function) ; Records diff --git a/runtime/queries/heex/highlights.scm b/runtime/queries/heex/highlights.scm index c42a689fc..6d8816de9 100644 --- a/runtime/queries/heex/highlights.scm +++ b/runtime/queries/heex/highlights.scm @@ -55,7 +55,7 @@ ; HEEx components are highlighted as Elixir modules and functions (component_name [ - (module) @module + (module) @namespace (function) @function "." @punctuation.delimiter ]) From 4a0dab8bc28ba674822a69cff72440773890a7e4 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 28 Jun 2022 13:08:59 -0500 Subject: [PATCH 426/861] erlang: fix '#match?' for specs/callbacks --- runtime/queries/erlang/highlights.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/queries/erlang/highlights.scm b/runtime/queries/erlang/highlights.scm index f491b9c5f..31a594b69 100644 --- a/runtime/queries/erlang/highlights.scm +++ b/runtime/queries/erlang/highlights.scm @@ -54,8 +54,8 @@ (attribute name: (atom) @keyword - (#eq? @keyword "(spec|callback)")) module: (atom) @namespace + (#match? @keyword "(spec|callback)")) ; Functions (function_clause name: (atom) @function) From 199a2460cabaf2e876d58f3549c4fbfe5ddf16e0 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 28 Jun 2022 16:19:48 -0500 Subject: [PATCH 427/861] make: add injection-regex --- languages.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 7a4b28c4c..f1b6c980c 100644 --- a/languages.toml +++ b/languages.toml @@ -727,7 +727,8 @@ source = { git = "https://github.com/uyha/tree-sitter-cmake", rev = "f6616f1e417 name = "make" scope = "source.make" file-types = ["Makefile", "makefile", "mk", "justfile", ".justfile"] -roots =[] +injection-regex = "(make|makefile|Makefile|mk|just)" +roots = [] comment-token = "#" indent = { tab-width = 4, unit = "\t" } From d8f036f0a9fd7248e53ff965f7f9f950a672808b Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 28 Jun 2022 20:08:09 -0500 Subject: [PATCH 428/861] erlang: update parser for fix on remote calls --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index f1b6c980c..2f209b4ff 100644 --- a/languages.toml +++ b/languages.toml @@ -1052,7 +1052,7 @@ language-server = { command = "erlang_ls" } [[grammar]] name = "erlang" -source = { git = "https://github.com/the-mikedavis/tree-sitter-erlang", rev = "c0ebc82600caaf4339f2b00691f958e9df97c065" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-erlang", rev = "0e7d677d11a7379686c53c616825714ccb728059" } [[language]] name = "kotlin" From a890c4a64dee8521bc80adfe77c56e703a7e4512 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 28 Jun 2022 20:31:11 -0500 Subject: [PATCH 429/861] tsq: update parser to fix escaping double quotes This includes a fix for the new HTML highlights introduced a few parent commits back: ["\"" (attribute_name)] @string Would get tripped up and the entire line would be highlighted as a string. Now `\"` is a valid escape. I'm switching to my fork as the primary repo as the upstream hasn't been touched in over a year (mostly because stability afaict) but it has no watchers currently so I'm not hopeful that my PR will be merged. --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 2f209b4ff..b8581080a 100644 --- a/languages.toml +++ b/languages.toml @@ -707,7 +707,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "tsq" -source = { git = "https://github.com/tree-sitter/tree-sitter-tsq", rev = "b665659d3238e6036e22ed0e24935e60efb39415" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-tsq", rev = "ea68fc2b571ca1c8f70936855130c380f518ff35" } [[language]] name = "cmake" From bf1aa8876c5e9e7ccf6ab4ae66997c45ac3c4b95 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 28 Jun 2022 20:59:03 -0500 Subject: [PATCH 430/861] git-commit: fix highlight edge cases * branch message with current branch and diverged branch has been added to the parser * scissors used in verbose commits are marked as a punctuation delimiter * we could use comment instead since they're visually the same but IMO this works better --- languages.toml | 2 +- runtime/queries/git-commit/highlights.scm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/languages.toml b/languages.toml index b8581080a..122cadfe8 100644 --- a/languages.toml +++ b/languages.toml @@ -908,7 +908,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "git-commit" -source = { git = "https://github.com/the-mikedavis/tree-sitter-git-commit", rev = "7ae23de633de41f8f5b802f6f05b6596df6d00c1" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-git-commit", rev = "318dd72abfaa7b8044c1d1fbeabcd06deaaf038f" } [[language]] name = "git-diff" diff --git a/runtime/queries/git-commit/highlights.scm b/runtime/queries/git-commit/highlights.scm index 0b50d4190..bdb776d6d 100644 --- a/runtime/queries/git-commit/highlights.scm +++ b/runtime/queries/git-commit/highlights.scm @@ -10,5 +10,5 @@ (change kind: "modified" @diff.delta) (change kind: "renamed" @diff.delta.moved) -[":" "->"] @punctuation.delimeter +[":" "->" (scissors)] @punctuation.delimeter (comment) @comment From 19acbfe02d6a6ff9496d46e02661b67e65b94923 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 29 Jun 2022 08:55:00 -0500 Subject: [PATCH 431/861] erlang: highlight records with macro names You might use a macro like `?MODULE` to name a record: -record(?MODULE, {a, b, c}). With this fix, the record fields correctly get `variable.other.member` highlights. --- runtime/queries/erlang/highlights.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/queries/erlang/highlights.scm b/runtime/queries/erlang/highlights.scm index 31a594b69..cb128905a 100644 --- a/runtime/queries/erlang/highlights.scm +++ b/runtime/queries/erlang/highlights.scm @@ -16,7 +16,7 @@ name: (atom) @keyword (arguments . - (atom) @type + [(atom) @type (macro)] [ (tuple (atom) @variable.other.member) (tuple From c8dba2f4c699b50384802a0fb4e0dadf87ea1677 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 29 Jun 2022 12:44:01 -0500 Subject: [PATCH 432/861] erlang: highlight modules in behaviour attributes --- runtime/queries/erlang/highlights.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/queries/erlang/highlights.scm b/runtime/queries/erlang/highlights.scm index cb128905a..8e4a640d6 100644 --- a/runtime/queries/erlang/highlights.scm +++ b/runtime/queries/erlang/highlights.scm @@ -3,7 +3,7 @@ (attribute name: (atom) @keyword (arguments (atom) @namespace) - (#eq? @keyword "module")) + (#match? @keyword "(module|behaviou?r)")) (attribute name: (atom) @keyword From c5600c9c0154df1ed20eb0eb16dfaa8c09447a2f Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Thu, 30 Jun 2022 17:46:34 -0500 Subject: [PATCH 433/861] markdown: limit raw block highlight to code fence content --- languages.toml | 2 +- runtime/queries/markdown/highlights.scm | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/languages.toml b/languages.toml index 122cadfe8..0b4a1dec5 100644 --- a/languages.toml +++ b/languages.toml @@ -855,7 +855,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "markdown" -source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "ad8c32917a16dfbb387d1da567bf0c3fb6fffde2" } +source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "ab15701d8f3f68aeb74e30573b7d669a6ef2a7ed" } [[language]] name = "dart" diff --git a/runtime/queries/markdown/highlights.scm b/runtime/queries/markdown/highlights.scm index aee568c8d..096c29542 100644 --- a/runtime/queries/markdown/highlights.scm +++ b/runtime/queries/markdown/highlights.scm @@ -8,11 +8,9 @@ (atx_heading (atx_h5_marker) @markup.heading.marker (heading_content) @markup.heading.5) (atx_heading (atx_h6_marker) @markup.heading.marker (heading_content) @markup.heading.6) -(code_fence_content) @none - [ (indented_code_block) - (fenced_code_block) + (code_fence_content) ] @markup.raw.block (block_quote) @markup.quote @@ -26,6 +24,8 @@ (link_destination) @markup.link.url (link_label) @markup.link.label +(info_string) @label + [ (link_text) (image_description) @@ -51,3 +51,4 @@ (inline_link ["[" "]" "(" ")"] @punctuation.bracket) (image ["[" "]" "(" ")"] @punctuation.bracket) +(fenced_code_block_delimiter) @punctuation.bracket From 7baa8e837b8d1174289ea1594560f7f91974dd0c Mon Sep 17 00:00:00 2001 From: Jens Getreu Date: Fri, 1 Jul 2022 11:06:16 +0200 Subject: [PATCH 434/861] Add `color-modes` to Autumn theme (#2928) Co-authored-by: Jens Getreu --- runtime/themes/autumn.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/themes/autumn.toml b/runtime/themes/autumn.toml index c4e0cfd62..d96d32eaa 100644 --- a/runtime/themes/autumn.toml +++ b/runtime/themes/autumn.toml @@ -18,6 +18,9 @@ "comment" = { fg = "my_gray4", modifiers = ["italic"] } "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" } From 051a7f06064a545d05276a2aae622e54548a095a Mon Sep 17 00:00:00 2001 From: Erasin Date: Fri, 1 Jul 2022 17:07:46 +0800 Subject: [PATCH 435/861] add cursorline to one light theme (#2925) --- runtime/themes/onelight.toml | 61 +++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/runtime/themes/onelight.toml b/runtime/themes/onelight.toml index c89e20f93..82121108f 100644 --- a/runtime/themes/onelight.toml +++ b/runtime/themes/onelight.toml @@ -4,15 +4,15 @@ "attribute" = { fg = "yellow" } "comment" = { fg = "gray", modifiers = ["italic"] } -"constant" = { fg = "red" } +"constant" = { fg = "cyan" } "constant.numeric" = { fg = "gold" } "constant.builtin" = { fg = "gold" } "constant.character.escape" = { fg = "gold" } -"constructor" = { fg = "blue" } +"constructor" = { fg = "yellow" } -"function" = { fg = "light-blue" } -"function.builtin" = { fg = "gray" } +"function" = { fg = "blue" } +"function.builtin" = { fg = "cyan" } "function.macro" = { fg = "red" } "keyword" = { fg = "purple" } @@ -21,7 +21,7 @@ "keyword.directive" = { fg = "purple" } "keyword.operator" = { fg = "purple" } -"tag" = "yellow" +"tag" = "cyan" "label" = { fg = "cyan" } "namespace" = { fg = "red" } "operator" = { fg = "red" } @@ -31,15 +31,15 @@ "module" = { fg = "cyan" } "type" = { fg = "yellow" } -"type.builtin" = "blue" +"type.builtin" = { fg = "purple" } -"punctuation" = "gray" -"punctuation.delimiter" = "black" -# "punctuation.bracket" = "black" +"punctuation" = { fg = "gray" } +"punctuation.delimiter" = { fg = "black" } +# "punctuation.bracket" = { fg="black" } -# "variable" = { fg = "blue" } +"variable" = { fg = "black" } "variable.builtin" = { fg = "light-blue" } -"variable.parameter" = { fg = "blue" } +"variable.parameter" = { fg = "red" } "variable.other.member" = { fg = "red" } "markup.heading" = { fg = "red" } @@ -52,11 +52,11 @@ "markup.link.url" = { fg = "cyan", modifiers = ["underlined"] } "markup.link.text" = { fg = "light-blue" } "markup.heading.1" = { fg = "red", modifiers = ["bold"] } -"markup.heading.2" = { fg = "glod", modifiers = ["bold"] } +"markup.heading.2" = { fg = "gold", modifiers = ["bold"] } "markup.heading.3" = { fg = "yellow", modifiers = ["bold"] } "markup.heading.4" = { fg = "green", modifiers = ["bold"] } "markup.heading.5" = { fg = "blue", modifiers = ["bold"] } -"markup.heading.6" = { fg = "black", modifiers = ["bold"] } +"markup.heading.6" = { fg = "purple", modifiers = ["bold"] } "diff.plus" = "green" "diff.delta" = "gold" @@ -70,20 +70,24 @@ "ui.background" = { bg = "white" } -"ui.cursor" = { fg = "white", bg = "black" } +"ui.cursor" = { fg = "white", bg = "gray" } "ui.cursor.primary" = { fg = "white", bg = "black" } -"ui.cursor.match" = { fg = "white", bg = "purple" } +"ui.cursor.match" = { bg = "light-gray" } + +"ui.cursorline.primary" = { fg = "white", bg = "grey-200" } +"ui.cursorline.secondary" = { fg = "white", bg = "light-white" } "ui.highlight" = { bg = "light-white" } -"ui.selection" = { bg = "light-white" } -"ui.selection.primary" = { bg = "light-white", modifiers = ["dim"] } +"ui.selection" = { modifiers = ["reversed"] } +"ui.selection.primary" = { bg = "light-white" } -"ui.virtual" = { fg = "light-white"} +"ui.virtual" = { fg = "light-white" } +"ui.virtual.indent-guide" = { fg = "grey-500" } "ui.virtual.ruler" = { bg = "light-white" } -"ui.virtual.whitespace" = {fg = "light-white" } +"ui.virtual.whitespace" = { fg = "light-white" } -"ui.linenr" = { fg = "linenr" } +"ui.linenr" = { fg = "grey-500" } "ui.linenr.selected" = { fg = "black", modifiers = ["reversed"] } "ui.statusline" = { fg = "black", bg = "light-white" } @@ -93,22 +97,23 @@ "ui.text.focus" = { fg = "red", bg = "light-white", modifiers = ["bold"] } "ui.help" = { fg = "black", bg = "light-white" } -"ui.popup" = { bg = "light-white" } -"ui.window" = { bg = "light-white" } -"ui.menu" = { fg = "black", bg = "light-white" } +"ui.popup" = { fg = "black", bg = "grey-200" } +"ui.window" = { fg = "black", bg = "grey-200" } +"ui.menu" = { fg = "black", bg = "grey-200" } "ui.menu.selected" = { fg = "white", bg = "light-blue" } [palette] white = "#FAFAFA" yellow = "#A06600" -blue = "#5556FF" -light-blue = "#2F77FA" +blue = "#0061FF" +light-blue = "#1877F2" red = "#DC003F" purple = "#B500A9" green = "#24A443" -gold = "#D19A66" +gold = "#D35400" cyan = "#0086C1" black = "#282C34" -light-white = "#EAEAEB" +light-white = "#E0E0E0" gray = "#5C6370" -linenr = "#9D9D9F" +grey-200 = "#EEEEEE" +grey-500 = "#9E9E9E" From 444bc24a261ce02618cb73425d3847e554c83156 Mon Sep 17 00:00:00 2001 From: two-six Date: Fri, 1 Jul 2022 11:08:27 +0200 Subject: [PATCH 436/861] [Theme] Nord Light (#2908) * add theme * updated nord_light * update to colors * last update to colors --- runtime/themes/nord_light.toml | 67 ++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 runtime/themes/nord_light.toml diff --git a/runtime/themes/nord_light.toml b/runtime/themes/nord_light.toml new file mode 100644 index 000000000..9afb1dee4 --- /dev/null +++ b/runtime/themes/nord_light.toml @@ -0,0 +1,67 @@ +# Author: Two-Six + +"ui.background" = {bg="nord6"} +"ui.text" = "nord0" +"ui.selection" = {bg="nord7", fg="nord6"} +"ui.statusline" = {bg="nord4"} +"ui.statusline.inactive" = {bg="nord8"} +"ui.virtual" = "nord8" +"ui.cursor.match" = {bg="nord8"} +"ui.cursor" = {bg="nord10", fg="nord6"} +"ui.cursorline.primary" = {bg="nord5"} +"ui.linenr" = {fg="nord7"} +"ui.linenr.selected" = {fg="nord0", bg="nord5"} +"ui.menu" = {bg="nord4"} +"ui.menu.selected" = {bg="nord5"} +"ui.popup" = {bg="nord4"} + +"diagnostic.error" = {fg="nord11", modifiers=["bold"]} +"diagnostic.warning" = {bg="nord13", modifiers=["bold"]} +"diagnostic.hint" = {fg="nord13", modifiers=["bold"]} + +"constant.numeric" = {fg="nord15"} +"constant.builtin" = {fg="nord15"} + +"keyword" = {fg="nord2"} +"keyword.control" = {fg="nord2"} +"keyword.function" = {fg="nord2"} + +"function" = {fg="nord3"} +"function.macro" = {fg="nord10", modifiers=["bold"]} +"function.method" = {fg="nord0"} +"function.builtin" = {fg="nord10"} + +"variable.builtin" = {fg="nord3"} +"variable.other" = {fg="nord3"} +"variable" = {fg="nord0"} + +"string" = "nord14" +"comment" = "nord7" +"namespace" = {fg="nord10"} +"attribute" = {fg="nord10"} +"type" = {fg="nord10"} + +"markup.heading" = {fg="nord0", modifiers=["bold"]} +"markup.raw" = {fg="nord10"} +"markup.link.url" = {fg="nord3"} +"markup.link.text" = {fg="nord12"} +"markup.quote" = {fg="nord3", modifiers=["italic"]} + + +[palette] +nord0 = "#2E3440" +nord1 = "#3B4252" +nord2 = "#434C5E" +nord3 = "#4C566A" +nord4 = "#D8DEE9" +nord5 = "#E5E9F0" +nord6 = "#ECEFF4" +nord7 = "#8FBCBB" +nord8 = "#88C0D0" +nord9 = "#81A1C1" +nord10 = "#5E81AC" +nord11 = "#BF616A" +nord12 = "#D08770" +nord13 = "#EBCB8B" +nord14 = "#A3BE8C" +nord15 = "#B48EAD" From edee2f4c347c53c4ba0ee7d8e4624e12e64d90fe Mon Sep 17 00:00:00 2001 From: Sora Date: Fri, 1 Jul 2022 11:08:48 +0200 Subject: [PATCH 437/861] Fix backwards character deletion on other whitespaces (#2855) * delete_backwards_char accepts any type of whitespace * Fix inconsistency, where unicode whitespaces are treated as normal whitespaces * Changed back to direct whitespace match * Only accept explicit whitespace / tabs Co-authored-by: s0LA1337 --- helix-term/src/commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index bc8e65302..59ca2e3bd 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2948,7 +2948,7 @@ pub mod insert { let line_start_pos = text.line_to_char(range.cursor_line(text)); // consider to delete by indent level if all characters before `pos` are indent units. let fragment = Cow::from(text.slice(line_start_pos..pos)); - if !fragment.is_empty() && fragment.chars().all(|ch| ch.is_whitespace()) { + if !fragment.is_empty() && fragment.chars().all(|ch| ch == ' ' || ch == '\t') { if text.get_char(pos.saturating_sub(1)) == Some('\t') { // fast path, delete one char ( From 15d96c843aca5b87fde26faf6c556265402c32c1 Mon Sep 17 00:00:00 2001 From: Benjamin Rich Date: Fri, 1 Jul 2022 05:27:18 -0400 Subject: [PATCH 438/861] Add new key bindings to view mode (#2803) * Make view mode more pager-like Addresses #2721 * Remove view mode bindings for J and K --- helix-term/src/keymap/default.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index 29b0b6706..9b1447581 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -273,8 +273,13 @@ pub fn default() -> HashMap { "j" | "down" => scroll_down, "C-b" | "pageup" => page_up, "C-f" | "pagedown" => page_down, - "C-u" => half_page_up, - "C-d" => half_page_down, + "C-u" | "backspace" => half_page_up, + "C-d" | "space" => half_page_down, + + "/" => search, + "?" => rsearch, + "n" => search_next, + "N" => search_prev, }, "Z" => { "View" sticky=true "z" | "c" => align_view_center, @@ -285,8 +290,13 @@ pub fn default() -> HashMap { "j" | "down" => scroll_down, "C-b" | "pageup" => page_up, "C-f" | "pagedown" => page_down, - "C-u" => half_page_up, - "C-d" => half_page_down, + "C-u" | "backspace" => half_page_up, + "C-d" | "space" => half_page_down, + + "/" => search, + "?" => rsearch, + "n" => search_next, + "N" => search_prev, }, "\"" => select_register, From f10b6f6ee2bbf4d6d9356e27be25b25bdb85b9cd Mon Sep 17 00:00:00 2001 From: plexom <48958093+plexom@users.noreply.github.com> Date: Fri, 1 Jul 2022 11:27:32 +0200 Subject: [PATCH 439/861] adds --vsplit and --hsplit arguments (#2773) * adds --vsplit and --hsplit arguments * moved comment * fixed lint (third time's a charm) * changed vsplit and hsplit from two separate bools to type Option, and some cleanup --- contrib/completion/hx.bash | 2 +- contrib/completion/hx.fish | 3 ++- contrib/completion/hx.zsh | 2 ++ helix-term/src/application.rs | 21 ++++++++++++++++++--- helix-term/src/args.rs | 4 ++++ helix-term/src/main.rs | 2 ++ 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/contrib/completion/hx.bash b/contrib/completion/hx.bash index 6371bedb6..87c340284 100644 --- a/contrib/completion/hx.bash +++ b/contrib/completion/hx.bash @@ -16,7 +16,7 @@ _hx() { COMPREPLY=($(compgen -W "$languages" -- $2)) ;; *) - COMPREPLY=($(compgen -fd -W "-h --help --tutor -V --version -v -vv -vvv --health -g --grammar" -- $2)) + COMPREPLY=($(compgen -fd -W "-h --help --tutor -V --version -v -vv -vvv --health -g --grammar --vsplit --hsplit" -- $2)) ;; esac } && complete -F _hx hx diff --git a/contrib/completion/hx.fish b/contrib/completion/hx.fish index 4ec690d8b..df2fb500c 100644 --- a/contrib/completion/hx.fish +++ b/contrib/completion/hx.fish @@ -9,4 +9,5 @@ complete -c hx -l health -x -a "$langs" -d "Checks for errors in editor setup" complete -c hx -s g -l grammar -x -a "fetch build" -d "Fetches or builds tree-sitter grammars" complete -c hx -s v -o vv -o vvv -d "Increases logging verbosity" complete -c hx -s V -l version -d "Prints version information" - +complete -c hx -l vsplit -d "Splits all given files vertically into different windows" +complete -c hx -l hsplit -d "Splits all given files horizontally into different windows" diff --git a/contrib/completion/hx.zsh b/contrib/completion/hx.zsh index 16631519b..f9d58d3c6 100644 --- a/contrib/completion/hx.zsh +++ b/contrib/completion/hx.zsh @@ -14,6 +14,8 @@ _hx() { "--health[Checks for errors in editor setup]:language:->health" \ "-g[Fetches or builds tree-sitter grammars]:action:->grammar" \ "--grammar[Fetches or builds tree-sitter grammars]:action:->grammar" \ + "--vsplit[Splits all given files vertically into different windows]" \ + "--hsplit[Splits all given files horizontally into different windows]" \ "*:file:_files" case "$state" in diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 23f4610f6..805f660f6 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -5,7 +5,7 @@ use helix_core::{ pos_at_coords, syntax, Selection, }; use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap}; -use helix_view::{align_view, editor::ConfigEvent, theme, Align, Editor}; +use helix_view::{align_view, editor::ConfigEvent, theme, tree::Layout, Align, Editor}; use serde_json::json; use crate::{ @@ -158,16 +158,31 @@ impl Application { } else { let nr_of_files = args.files.len(); editor.open(first, Action::VerticalSplit)?; - for (file, pos) in args.files { + // Because the line above already opens the first file, we can + // simply skip opening it a second time by using .skip(1) here. + for (file, pos) in args.files.into_iter().skip(1) { if file.is_dir() { return Err(anyhow::anyhow!( "expected a path to file, found a directory. (to open a directory pass it as first argument)" )); } else { + // If the user passes in either `--vsplit` or + // `--hsplit` as a command line argument, all the given + // files will be opened according to the selected + // option. If neither of those two arguments are passed + // in, just load the files normally. + let action = match args.split { + Some(Layout::Vertical) => Action::VerticalSplit, + Some(Layout::Horizontal) => Action::HorizontalSplit, + None => Action::Load, + }; let doc_id = editor - .open(&file, Action::Load) + .open(&file, action) .context(format!("open '{}'", file.to_string_lossy()))?; // with Action::Load all documents have the same view + // NOTE: this isn't necessarily true anymore. If + // `--vsplit` or `--hsplit` are used, the file which is + // opened last is focused on. let view_id = editor.tree.focus; let doc = editor.document_mut(doc_id).unwrap(); let pos = Selection::point(pos_at_coords(doc.text().slice(..), pos, true)); diff --git a/helix-term/src/args.rs b/helix-term/src/args.rs index b99c7d1a2..c3019ea7c 100644 --- a/helix-term/src/args.rs +++ b/helix-term/src/args.rs @@ -1,5 +1,6 @@ use anyhow::Result; use helix_core::Position; +use helix_view::tree::Layout; use std::path::{Path, PathBuf}; #[derive(Default)] @@ -11,6 +12,7 @@ pub struct Args { pub load_tutor: bool, pub fetch_grammars: bool, pub build_grammars: bool, + pub split: Option, pub verbosity: u64, pub files: Vec<(PathBuf, Position)>, } @@ -28,6 +30,8 @@ impl Args { "--version" => args.display_version = true, "--help" => args.display_help = true, "--tutor" => args.load_tutor = true, + "--vsplit" => args.split = Some(Layout::Vertical), + "--hsplit" => args.split = Some(Layout::Horizontal), "--health" => { args.health = true; args.health_arg = argv.next_if(|opt| !opt.starts_with('-')); diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index 7b26fb119..eb186d78e 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -67,6 +67,8 @@ FLAGS: -v Increases logging verbosity each use for up to 3 times (default file: {}) -V, --version Prints version information + --vsplit Splits all given files vertically into different windows + --hsplit Splits all given files horizontally into different windows ", env!("CARGO_PKG_NAME"), env!("VERSION_AND_GIT_HASH"), From d8abd1eaf398f462122efbc937cda9d8178a5754 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Fri, 1 Jul 2022 10:33:52 +0100 Subject: [PATCH 440/861] Sort themes, language & files by score & then name (#2675) * Sort themes by score & then name Previously the themes were appearing unordered after typing ':theme '. This sorts them first by fuzzy score and then by name so that they generally appear in a more ordered fashion in the initial list. The sort by name does not really pay off when there is a score so an alternative approach would be to sort by name if there is string to fuzzy match against and otherwise sort by score. I've lowercased the names as that avoids lower case & upper case letters being sorted into separate groups. There might be a preferable approach to that though. * Sort language & files by score then name And change to use sort_unstable_by instead of sort_unstable_by_key as it allows us to avoid some allocations. I don't fully understand the flow of the 'filename_impl' function but this seems to deliver the desired results. * Remove unnecessary reference Co-authored-by: Michael Davis Co-authored-by: Michael Davis --- helix-term/src/ui/mod.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index c1e5c9889..948a5f2b6 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -257,7 +257,9 @@ pub mod completers { }) .collect(); - matches.sort_unstable_by_key(|(_file, score)| Reverse(*score)); + matches.sort_unstable_by(|(name1, score1), (name2, score2)| { + (Reverse(*score1), name1).cmp(&(Reverse(*score2), name2)) + }); names = matches.into_iter().map(|(name, _)| ((0..), name)).collect(); names @@ -312,7 +314,9 @@ pub mod completers { }) .collect(); - matches.sort_unstable_by_key(|(_language, score)| Reverse(*score)); + matches.sort_unstable_by(|(language1, score1), (language2, score2)| { + (Reverse(*score1), language1).cmp(&(Reverse(*score2), language2)) + }); matches .into_iter() @@ -428,13 +432,18 @@ pub mod completers { let range = (input.len().saturating_sub(file_name.len()))..; - matches.sort_unstable_by_key(|(_file, score)| Reverse(*score)); + matches.sort_unstable_by(|(file1, score1), (file2, score2)| { + (Reverse(*score1), file1).cmp(&(Reverse(*score2), file2)) + }); + files = matches .into_iter() .map(|(file, _)| (range.clone(), file)) .collect(); // TODO: complete to longest common match + } else { + files.sort_unstable_by(|(_, path1), (_, path2)| path1.cmp(path2)); } files From 9ae70cc410bd042b5cf119c571db323436caf08b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Fri, 1 Jul 2022 19:16:16 +0900 Subject: [PATCH 441/861] Disable tree-sitter python indents, use fallback for now There's been a lot of complaints about the state of python indentation and the fallback actually works better until the solution proposed in https://github.com/helix-editor/helix/issues/763#issuecomment-1137894973= is implemented. --- runtime/queries/python/{indents.scm => indents.scm_} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename runtime/queries/python/{indents.scm => indents.scm_} (100%) diff --git a/runtime/queries/python/indents.scm b/runtime/queries/python/indents.scm_ similarity index 100% rename from runtime/queries/python/indents.scm rename to runtime/queries/python/indents.scm_ From 8a19196ad55cd8461b0a621ecfe373b0b3407ec5 Mon Sep 17 00:00:00 2001 From: nosa <96927121+n0s4@users.noreply.github.com> Date: Fri, 1 Jul 2022 11:18:39 +0100 Subject: [PATCH 442/861] Updated for #2676 , but I took the opportunity to do some other changes. (#2929) - Misspelling of 'modifiers' for markdown.heading.1 and 2. - Errors are now just underlined instead of in red. - Diagnostics are dimmed, as well as whitespace. - Add constant.builtin. --- runtime/themes/night_owl.toml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/runtime/themes/night_owl.toml b/runtime/themes/night_owl.toml index 337fae86e..d99273558 100644 --- a/runtime/themes/night_owl.toml +++ b/runtime/themes/night_owl.toml @@ -1,11 +1,11 @@ # Author : Joe Mckay joemckay3006@gmail.com # Palette from https://github.com/haishanh/night-owl.vim -'warning' = { fg = 'peach' } -'error' = { fg = 'red' } -'info' = { fg = 'blue' } -'hint' = { fg = 'paleblue' } -'diagnostic' = { fg = 'background', bg = 'red' } +'warning' = { fg = 'peach', modifiers = ['dim'] } +'error' = { fg = 'red', modifiers = ['dim'] } +'info' = { fg = 'blue', modifiers = ['dim'] } +'hint' = { fg = 'paleblue', modifiers = ['dim'] } +'diagnostic' = { modifiers = ['underlined'] } # UI 'ui.background' = { fg = 'foreground', bg = 'background' } @@ -22,18 +22,22 @@ 'ui.linenr.selected' = { fg = 'greyE', bg = 'background2' } 'ui.statusline' = { fg = 'greyE', bg = 'background2' } 'ui.statusline.inactive' = { fg = 'grey7', bg = 'background2' } +'ui.statusline.normal' = { bg = 'slate' } +'ui.statusline.insert' = { bg = 'peach' } +'ui.statusline.select' = { bg = 'green' } 'ui.menu' = { fg = 'foreground', bg = 'selection' } 'ui.menu.selected' = { fg = 'foreground', bg = 'pink' } 'ui.popup' = { fg = 'foreground', bg = 'background2' } 'ui.popup.info' = { fg = 'gold', bg = 'background2'} 'ui.help' = { fg = 'gold', bg = 'background2'} 'ui.virtual.ruler' = { bg = 'grey4' } -'ui.virtual.whitespace' = { fg = 'slate' } +'ui.virtual.whitespace' = { fg = 'grey4' } # SYNTAX 'type' = { fg = 'green' } 'constructor' = { fg = 'blue' } 'constant' = { fg = 'foreground' } +'constant.builtin' = { fg = 'paleblue' } 'constant.character.escape' = { fg = 'peach' } 'string' = { fg = 'gold' } 'string.regexp' = { fg = 'green' } @@ -63,8 +67,8 @@ # MARKUP 'markup.heading' = { fg = 'blue', modifiers = ['bold'] } 'markup.heading.marker' = { fg = 'grey4', modifiers = ['dim'] } -'markup.heading.1' = { fg = 'blue', modifers = ['bold'] } -'markup.heading.2' = { fg = 'paleblue', modifers = ['bold'] } +'markup.heading.1' = { fg = 'blue', modifiers = ['bold'] } +'markup.heading.2' = { fg = 'paleblue', modifiers = ['bold'] } 'markup.heading.3' = { fg = 'green', modifiers = ['bold'] } 'markup.heading.4' = { fg = 'pink', modifiers = ['bold'] } 'markup.heading.5' = { fg = 'peach', modifiers = ['bold'] } From a1c1abca2b2bbe82e76bbc2c0a8bc522aacbe0f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Fri, 1 Jul 2022 21:24:10 +0900 Subject: [PATCH 443/861] fix CI --- book/src/generated/lang-support.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 5ea18ae84..c82a6443b 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -71,7 +71,7 @@ | prisma | ✓ | | | `prisma-language-server` | | prolog | | | | `swipl` | | protobuf | ✓ | | ✓ | | -| python | ✓ | ✓ | ✓ | `pylsp` | +| python | ✓ | ✓ | | `pylsp` | | r | ✓ | | | `R` | | racket | | | | `racket` | | regex | ✓ | | | | From cc3aded1858189941cd0d78e32b267c66abfcee3 Mon Sep 17 00:00:00 2001 From: ramojus <41536253+Ramojus@users.noreply.github.com> Date: Fri, 1 Jul 2022 15:24:33 +0300 Subject: [PATCH 444/861] add statusline mode colors to meliora theme (#2933) --- runtime/themes/meliora.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runtime/themes/meliora.toml b/runtime/themes/meliora.toml index 72ade8ac5..ecc19f46e 100644 --- a/runtime/themes/meliora.toml +++ b/runtime/themes/meliora.toml @@ -1,4 +1,4 @@ -# Author: Ramojus +# Author: Ramojus Lapinskas "comment" = { fg = "comment" } "constant" = { fg = "magenta" } @@ -43,6 +43,9 @@ "ui.statusline" = { fg = "dark_white", bg = "light_black3" } "ui.statusline.inactive" = { fg = "dark_white2", bg = "light_black" } +"ui.statusline.normal" = { bg = "dark_white2", fg = "black" } +"ui.statusline.insert" = { bg = "blue", fg = "black" } +"ui.statusline.select" = { bg = "orange", fg = "black" } "ui.text" = { fg = "white" } "ui.text.focus" = { fg = "orange" } From 290b3ebbbe0c365eee436b9de9d6d6fc2b4339e9 Mon Sep 17 00:00:00 2001 From: nosa <96927121+n0s4@users.noreply.github.com> Date: Fri, 1 Jul 2022 20:09:59 +0100 Subject: [PATCH 446/861] Update night_owl for cursorline (#2938) --- runtime/themes/night_owl.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/themes/night_owl.toml b/runtime/themes/night_owl.toml index d99273558..825bd4120 100644 --- a/runtime/themes/night_owl.toml +++ b/runtime/themes/night_owl.toml @@ -32,6 +32,7 @@ 'ui.help' = { fg = 'gold', bg = 'background2'} 'ui.virtual.ruler' = { bg = 'grey4' } 'ui.virtual.whitespace' = { fg = 'grey4' } +'ui.cursorline.primary' = { bg = 'background2' } # SYNTAX 'type' = { fg = 'green' } From 6e2aaed5c2cbcedc9ee4e225510cae4f357888aa Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sat, 2 Jul 2022 16:51:27 +0530 Subject: [PATCH 447/861] Reuse menu::Item trait in picker (#2814) * Refactor menu::Item to accomodate external state Will be useful for storing editor state when reused by pickers. * Add some type aliases for readability * Reuse menu::Item trait in picker This opens the way for merging the menu and picker code in the future, since a picker is essentially a menu + prompt. More excitingly, this change will also allow aligning items in the picker, which would be useful (for example) in the command palette for aligning the descriptions to the left and the keybinds to the right in two separate columns. The item formatting of each picker has been kept as is, even though there is room for improvement now that we can format the data into columns, since that is better tackled in a separate PR. * Rename menu::Item::EditorData to Data * Call and inline filter_text() in sort_text() completion * Rename diagnostic picker's Item::Data --- helix-dap/src/client.rs | 2 +- helix-dap/src/types.rs | 2 + helix-term/src/commands.rs | 149 +++++++++++++-------- helix-term/src/commands/dap.rs | 54 +++++--- helix-term/src/commands/lsp.rs | 222 +++++++++++++++++++------------- helix-term/src/keymap.rs | 11 +- helix-term/src/ui/completion.rs | 23 ++-- helix-term/src/ui/menu.rs | 54 +++++--- helix-term/src/ui/mod.rs | 7 +- helix-term/src/ui/picker.rs | 38 +++--- helix-tui/src/text.rs | 6 + 11 files changed, 350 insertions(+), 218 deletions(-) diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs index 9498c64c1..371cf3032 100644 --- a/helix-dap/src/client.rs +++ b/helix-dap/src/client.rs @@ -34,7 +34,7 @@ pub struct Client { pub caps: Option, // thread_id -> frames pub stack_frames: HashMap>, - pub thread_states: HashMap, + pub thread_states: ThreadStates, pub thread_id: Option, /// Currently active frame for the current thread. pub active_frame: Option, diff --git a/helix-dap/src/types.rs b/helix-dap/src/types.rs index 2c3df9c33..fd8456a43 100644 --- a/helix-dap/src/types.rs +++ b/helix-dap/src/types.rs @@ -14,6 +14,8 @@ impl std::fmt::Display for ThreadId { } } +pub type ThreadStates = HashMap; + pub trait Request { type Arguments: serde::de::DeserializeOwned + serde::Serialize; type Result: serde::de::DeserializeOwned + serde::Serialize; diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 59ca2e3bd..df4867fc7 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -45,6 +45,7 @@ use movement::Movement; use crate::{ args, compositor::{self, Component, Compositor}, + keymap::ReverseKeymap, ui::{self, overlay::overlayed, FilePicker, Picker, Popup, Prompt, PromptEvent}, }; @@ -1744,8 +1745,42 @@ fn search_selection(cx: &mut Context) { } fn global_search(cx: &mut Context) { - let (all_matches_sx, all_matches_rx) = - tokio::sync::mpsc::unbounded_channel::<(usize, PathBuf)>(); + #[derive(Debug)] + struct FileResult { + path: PathBuf, + /// 0 indexed lines + line_num: usize, + } + + impl FileResult { + fn new(path: &Path, line_num: usize) -> Self { + Self { + path: path.to_path_buf(), + line_num, + } + } + } + + impl ui::menu::Item for FileResult { + type Data = Option; + + fn label(&self, current_path: &Self::Data) -> Spans { + let relative_path = helix_core::path::get_relative_path(&self.path) + .to_string_lossy() + .into_owned(); + if current_path + .as_ref() + .map(|p| p == &self.path) + .unwrap_or(false) + { + format!("{} (*)", relative_path).into() + } else { + relative_path.into() + } + } + } + + let (all_matches_sx, all_matches_rx) = tokio::sync::mpsc::unbounded_channel::(); let config = cx.editor.config(); let smart_case = config.search.smart_case; let file_picker_config = config.file_picker.clone(); @@ -1809,7 +1844,7 @@ fn global_search(cx: &mut Context) { entry.path(), sinks::UTF8(|line_num, _| { all_matches_sx - .send((line_num as usize - 1, entry.path().to_path_buf())) + .send(FileResult::new(entry.path(), line_num as usize - 1)) .unwrap(); Ok(true) @@ -1836,7 +1871,7 @@ fn global_search(cx: &mut Context) { let current_path = doc_mut!(cx.editor).path().cloned(); let show_picker = async move { - let all_matches: Vec<(usize, PathBuf)> = + let all_matches: Vec = UnboundedReceiverStream::new(all_matches_rx).collect().await; let call: job::Callback = Box::new(move |editor: &mut Editor, compositor: &mut Compositor| { @@ -1847,17 +1882,8 @@ fn global_search(cx: &mut Context) { let picker = FilePicker::new( all_matches, - move |(_line_num, path)| { - let relative_path = helix_core::path::get_relative_path(path) - .to_string_lossy() - .into_owned(); - if current_path.as_ref().map(|p| p == path).unwrap_or(false) { - format!("{} (*)", relative_path).into() - } else { - relative_path.into() - } - }, - move |cx, (line_num, path), action| { + current_path, + move |cx, FileResult { path, line_num }, action| { match cx.editor.open(path, action) { Ok(_) => {} Err(e) => { @@ -1879,7 +1905,9 @@ fn global_search(cx: &mut Context) { doc.set_selection(view.id, Selection::single(start, end)); align_view(doc, view, Align::Center); }, - |_editor, (line_num, path)| Some((path.clone(), Some((*line_num, *line_num)))), + |_editor, FileResult { path, line_num }| { + Some((path.clone(), Some((*line_num, *line_num)))) + }, ); compositor.push(Box::new(overlayed(picker))); }); @@ -2172,8 +2200,10 @@ fn buffer_picker(cx: &mut Context) { is_current: bool, } - impl BufferMeta { - fn format(&self) -> Spans { + impl ui::menu::Item for BufferMeta { + type Data = (); + + fn label(&self, _data: &Self::Data) -> Spans { let path = self .path .as_deref() @@ -2213,7 +2243,7 @@ fn buffer_picker(cx: &mut Context) { .iter() .map(|(_, doc)| new_meta(doc)) .collect(), - BufferMeta::format, + (), |cx, meta, action| { cx.editor.switch(meta.id, action); }, @@ -2230,6 +2260,38 @@ fn buffer_picker(cx: &mut Context) { cx.push_layer(Box::new(overlayed(picker))); } +impl ui::menu::Item for MappableCommand { + type Data = ReverseKeymap; + + fn label(&self, keymap: &Self::Data) -> Spans { + // formats key bindings, multiple bindings are comma separated, + // individual key presses are joined with `+` + let fmt_binding = |bindings: &Vec>| -> String { + bindings + .iter() + .map(|bind| { + bind.iter() + .map(|key| key.to_string()) + .collect::>() + .join("+") + }) + .collect::>() + .join(", ") + }; + + match self { + MappableCommand::Typable { doc, name, .. } => match keymap.get(name as &String) { + Some(bindings) => format!("{} ({})", doc, fmt_binding(bindings)).into(), + None => doc.as_str().into(), + }, + MappableCommand::Static { doc, name, .. } => match keymap.get(*name) { + Some(bindings) => format!("{} ({})", doc, fmt_binding(bindings)).into(), + None => (*doc).into(), + }, + } + } +} + pub fn command_palette(cx: &mut Context) { cx.callback = Some(Box::new( move |compositor: &mut Compositor, cx: &mut compositor::Context| { @@ -2246,44 +2308,17 @@ pub fn command_palette(cx: &mut Context) { } })); - // formats key bindings, multiple bindings are comma separated, - // individual key presses are joined with `+` - let fmt_binding = |bindings: &Vec>| -> String { - bindings - .iter() - .map(|bind| { - bind.iter() - .map(|key| key.key_sequence_format()) - .collect::() - }) - .collect::>() - .join(", ") - }; - - let picker = Picker::new( - commands, - move |command| match command { - MappableCommand::Typable { doc, name, .. } => match keymap.get(name) { - Some(bindings) => format!("{} ({})", doc, fmt_binding(bindings)).into(), - None => doc.as_str().into(), - }, - MappableCommand::Static { doc, name, .. } => match keymap.get(*name) { - Some(bindings) => format!("{} ({})", doc, fmt_binding(bindings)).into(), - None => (*doc).into(), - }, - }, - move |cx, command, _action| { - let mut ctx = Context { - register: None, - count: std::num::NonZeroUsize::new(1), - editor: cx.editor, - callback: None, - on_next_key_callback: None, - jobs: cx.jobs, - }; - command.execute(&mut ctx); - }, - ); + let picker = Picker::new(commands, keymap, move |cx, command, _action| { + let mut ctx = Context { + register: None, + count: std::num::NonZeroUsize::new(1), + editor: cx.editor, + callback: None, + on_next_key_callback: None, + jobs: cx.jobs, + }; + command.execute(&mut ctx); + }); compositor.push(Box::new(overlayed(picker))); }, )); diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index b897b2d58..9f6f4c15c 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -4,13 +4,15 @@ use crate::{ job::{Callback, Jobs}, ui::{self, overlay::overlayed, FilePicker, Picker, Popup, Prompt, PromptEvent, Text}, }; -use helix_core::syntax::{DebugArgumentValue, DebugConfigCompletion}; +use dap::{StackFrame, Thread, ThreadStates}; +use helix_core::syntax::{DebugArgumentValue, DebugConfigCompletion, DebugTemplate}; use helix_dap::{self as dap, Client}; use helix_lsp::block_on; use helix_view::editor::Breakpoint; use serde_json::{to_value, Value}; use tokio_stream::wrappers::UnboundedReceiverStream; +use tui::text::Spans; use std::collections::HashMap; use std::future::Future; @@ -20,6 +22,38 @@ use anyhow::{anyhow, bail}; use helix_view::handlers::dap::{breakpoints_changed, jump_to_stack_frame, select_thread_id}; +impl ui::menu::Item for StackFrame { + type Data = (); + + fn label(&self, _data: &Self::Data) -> Spans { + self.name.as_str().into() // TODO: include thread_states in the label + } +} + +impl ui::menu::Item for DebugTemplate { + type Data = (); + + fn label(&self, _data: &Self::Data) -> Spans { + self.name.as_str().into() + } +} + +impl ui::menu::Item for Thread { + type Data = ThreadStates; + + fn label(&self, thread_states: &Self::Data) -> Spans { + format!( + "{} ({})", + self.name, + thread_states + .get(&self.id) + .map(|state| state.as_str()) + .unwrap_or("unknown") + ) + .into() + } +} + fn thread_picker( cx: &mut Context, callback_fn: impl Fn(&mut Editor, &dap::Thread) + Send + 'static, @@ -41,17 +75,7 @@ fn thread_picker( let thread_states = debugger.thread_states.clone(); let picker = FilePicker::new( threads, - move |thread| { - format!( - "{} ({})", - thread.name, - thread_states - .get(&thread.id) - .map(|state| state.as_str()) - .unwrap_or("unknown") - ) - .into() - }, + thread_states, move |cx, thread, _action| callback_fn(cx.editor, thread), move |editor, thread| { let frames = editor.debugger.as_ref()?.stack_frames.get(&thread.id)?; @@ -243,7 +267,7 @@ pub fn dap_launch(cx: &mut Context) { cx.push_layer(Box::new(overlayed(Picker::new( templates, - |template| template.name.as_str().into(), + (), |cx, template, _action| { let completions = template.completion.clone(); let name = template.name.clone(); @@ -475,7 +499,7 @@ pub fn dap_variables(cx: &mut Context) { for scope in scopes.iter() { // use helix_view::graphics::Style; - use tui::text::{Span, Spans}; + use tui::text::Span; let response = block_on(debugger.variables(scope.variables_reference)); variables.push(Spans::from(Span::styled( @@ -652,7 +676,7 @@ pub fn dap_switch_stack_frame(cx: &mut Context) { let picker = FilePicker::new( frames, - |frame| frame.name.as_str().into(), // TODO: include thread_states in the label + (), move |cx, frame, _action| { let debugger = debugger!(cx.editor); // TODO: this should be simpler to find diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index d11c44cd4..7f82394ac 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -19,7 +19,8 @@ use crate::{ ui::{self, overlay::overlayed, FileLocation, FilePicker, Popup, PromptEvent}, }; -use std::{borrow::Cow, collections::BTreeMap}; +use std::collections::BTreeMap; +use std::{borrow::Cow, path::PathBuf}; /// Gets the language server that is attached to a document, and /// if it's not active displays a status message. Using this macro @@ -39,6 +40,112 @@ macro_rules! language_server { }; } +impl ui::menu::Item for lsp::Location { + /// Current working directory. + type Data = PathBuf; + + fn label(&self, cwdir: &Self::Data) -> Spans { + let file: Cow<'_, str> = (self.uri.scheme() == "file") + .then(|| { + self.uri + .to_file_path() + .map(|path| { + // strip root prefix + path.strip_prefix(&cwdir) + .map(|path| path.to_path_buf()) + .unwrap_or(path) + }) + .map(|path| Cow::from(path.to_string_lossy().into_owned())) + .ok() + }) + .flatten() + .unwrap_or_else(|| self.uri.as_str().into()); + let line = self.range.start.line; + format!("{}:{}", file, line).into() + } +} + +impl ui::menu::Item for lsp::SymbolInformation { + /// Path to currently focussed document + type Data = Option; + + fn label(&self, current_doc_path: &Self::Data) -> Spans { + if current_doc_path.as_ref() == Some(&self.location.uri) { + self.name.as_str().into() + } else { + match self.location.uri.to_file_path() { + Ok(path) => { + let relative_path = helix_core::path::get_relative_path(path.as_path()) + .to_string_lossy() + .into_owned(); + format!("{} ({})", &self.name, relative_path).into() + } + Err(_) => format!("{} ({})", &self.name, &self.location.uri).into(), + } + } + } +} + +struct DiagnosticStyles { + hint: Style, + info: Style, + warning: Style, + error: Style, +} + +struct PickerDiagnostic { + url: lsp::Url, + diag: lsp::Diagnostic, +} + +impl ui::menu::Item for PickerDiagnostic { + type Data = DiagnosticStyles; + + fn label(&self, styles: &Self::Data) -> Spans { + let mut style = self + .diag + .severity + .map(|s| match s { + DiagnosticSeverity::HINT => styles.hint, + DiagnosticSeverity::INFORMATION => styles.info, + DiagnosticSeverity::WARNING => styles.warning, + DiagnosticSeverity::ERROR => styles.error, + _ => Style::default(), + }) + .unwrap_or_default(); + + // remove background as it is distracting in the picker list + style.bg = None; + + let code = self + .diag + .code + .as_ref() + .map(|c| match c { + NumberOrString::Number(n) => n.to_string(), + NumberOrString::String(s) => s.to_string(), + }) + .unwrap_or_default(); + + let truncated_path = path::get_truncated_path(self.url.path()) + .to_string_lossy() + .into_owned(); + + Spans::from(vec![ + Span::styled( + self.diag.source.clone().unwrap_or_default(), + style.add_modifier(Modifier::BOLD), + ), + Span::raw(": "), + Span::styled(truncated_path, style), + Span::raw(" - "), + Span::styled(code, style.add_modifier(Modifier::BOLD)), + Span::raw(": "), + Span::styled(&self.diag.message, style), + ]) + } +} + fn location_to_file_location(location: &lsp::Location) -> FileLocation { let path = location.uri.to_file_path().unwrap(); let line = Some(( @@ -93,29 +200,14 @@ fn sym_picker( offset_encoding: OffsetEncoding, ) -> FilePicker { // TODO: drop current_path comparison and instead use workspace: bool flag? - let current_path2 = current_path.clone(); FilePicker::new( symbols, - move |symbol| { - if current_path.as_ref() == Some(&symbol.location.uri) { - symbol.name.as_str().into() - } else { - match symbol.location.uri.to_file_path() { - Ok(path) => { - let relative_path = helix_core::path::get_relative_path(path.as_path()) - .to_string_lossy() - .into_owned(); - format!("{} ({})", &symbol.name, relative_path).into() - } - Err(_) => format!("{} ({})", &symbol.name, &symbol.location.uri).into(), - } - } - }, + current_path.clone(), move |cx, symbol, action| { let (view, doc) = current!(cx.editor); push_jump(view, doc); - if current_path2.as_ref() != Some(&symbol.location.uri) { + if current_path.as_ref() != Some(&symbol.location.uri) { let uri = &symbol.location.uri; let path = match uri.to_file_path() { Ok(path) => path, @@ -155,7 +247,7 @@ fn diag_picker( diagnostics: BTreeMap>, current_path: Option, offset_encoding: OffsetEncoding, -) -> FilePicker<(lsp::Url, lsp::Diagnostic)> { +) -> FilePicker { // TODO: drop current_path comparison and instead use workspace: bool flag? // flatten the map to a vec of (url, diag) pairs @@ -163,59 +255,24 @@ fn diag_picker( for (url, diags) in diagnostics { flat_diag.reserve(diags.len()); for diag in diags { - flat_diag.push((url.clone(), diag)); + flat_diag.push(PickerDiagnostic { + url: url.clone(), + diag, + }); } } - let hint = cx.editor.theme.get("hint"); - let info = cx.editor.theme.get("info"); - let warning = cx.editor.theme.get("warning"); - let error = cx.editor.theme.get("error"); + let styles = DiagnosticStyles { + hint: cx.editor.theme.get("hint"), + info: cx.editor.theme.get("info"), + warning: cx.editor.theme.get("warning"), + error: cx.editor.theme.get("error"), + }; FilePicker::new( flat_diag, - move |(url, diag)| { - let mut style = diag - .severity - .map(|s| match s { - DiagnosticSeverity::HINT => hint, - DiagnosticSeverity::INFORMATION => info, - DiagnosticSeverity::WARNING => warning, - DiagnosticSeverity::ERROR => error, - _ => Style::default(), - }) - .unwrap_or_default(); - - // remove background as it is distracting in the picker list - style.bg = None; - - let code = diag - .code - .as_ref() - .map(|c| match c { - NumberOrString::Number(n) => n.to_string(), - NumberOrString::String(s) => s.to_string(), - }) - .unwrap_or_default(); - - let truncated_path = path::get_truncated_path(url.path()) - .to_string_lossy() - .into_owned(); - - Spans::from(vec![ - Span::styled( - diag.source.clone().unwrap_or_default(), - style.add_modifier(Modifier::BOLD), - ), - Span::raw(": "), - Span::styled(truncated_path, style), - Span::raw(" - "), - Span::styled(code, style.add_modifier(Modifier::BOLD)), - Span::raw(": "), - Span::styled(&diag.message, style), - ]) - }, - move |cx, (url, diag), action| { + styles, + move |cx, PickerDiagnostic { url, diag }, action| { if current_path.as_ref() == Some(url) { let (view, doc) = current!(cx.editor); push_jump(view, doc); @@ -233,7 +290,7 @@ fn diag_picker( align_view(doc, view, Align::Center); } }, - move |_editor, (url, diag)| { + move |_editor, PickerDiagnostic { url, diag }| { let location = lsp::Location::new(url.clone(), diag.range); Some(location_to_file_location(&location)) }, @@ -343,10 +400,11 @@ pub fn workspace_diagnostics_picker(cx: &mut Context) { } impl ui::menu::Item for lsp::CodeActionOrCommand { - fn label(&self) -> &str { + type Data = (); + fn label(&self, _data: &Self::Data) -> Spans { match self { - lsp::CodeActionOrCommand::CodeAction(action) => action.title.as_str(), - lsp::CodeActionOrCommand::Command(command) => command.title.as_str(), + lsp::CodeActionOrCommand::CodeAction(action) => action.title.as_str().into(), + lsp::CodeActionOrCommand::Command(command) => command.title.as_str().into(), } } } @@ -391,7 +449,7 @@ pub fn code_action(cx: &mut Context) { return; } - let mut picker = ui::Menu::new(actions, move |editor, code_action, event| { + let mut picker = ui::Menu::new(actions, (), move |editor, code_action, event| { if event != PromptEvent::Validate { return; } @@ -619,6 +677,7 @@ pub fn apply_workspace_edit( } } } + fn goto_impl( editor: &mut Editor, compositor: &mut Compositor, @@ -637,26 +696,7 @@ fn goto_impl( _locations => { let picker = FilePicker::new( locations, - move |location| { - let file: Cow<'_, str> = (location.uri.scheme() == "file") - .then(|| { - location - .uri - .to_file_path() - .map(|path| { - // strip root prefix - path.strip_prefix(&cwdir) - .map(|path| path.to_path_buf()) - .unwrap_or(path) - }) - .map(|path| Cow::from(path.to_string_lossy().into_owned())) - .ok() - }) - .flatten() - .unwrap_or_else(|| location.uri.as_str().into()); - let line = location.range.start.line; - format!("{}:{}", file, line).into() - }, + cwdir, move |cx, location, action| { jump_to_location(cx.editor, location, offset_encoding, action) }, diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index db9588330..592048898 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -208,18 +208,17 @@ pub struct Keymap { root: KeyTrie, } +/// A map of command names to keybinds that will execute the command. +pub type ReverseKeymap = HashMap>>; + impl Keymap { pub fn new(root: KeyTrie) -> Self { Keymap { root } } - pub fn reverse_map(&self) -> HashMap>> { + pub fn reverse_map(&self) -> ReverseKeymap { // recursively visit all nodes in keymap - fn map_node( - cmd_map: &mut HashMap>>, - node: &KeyTrie, - keys: &mut Vec, - ) { + fn map_node(cmd_map: &mut ReverseKeymap, node: &KeyTrie, keys: &mut Vec) { match node { KeyTrie::Leaf(cmd) => match cmd { MappableCommand::Typable { name, .. } => { diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index 38005aad0..a36374154 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -2,6 +2,7 @@ use crate::compositor::{Component, Context, EventResult}; use crossterm::event::{Event, KeyCode, KeyEvent}; use helix_view::editor::CompleteAction; use tui::buffer::Buffer as Surface; +use tui::text::Spans; use std::borrow::Cow; @@ -15,19 +16,25 @@ use helix_lsp::{lsp, util}; use lsp::CompletionItem; impl menu::Item for CompletionItem { - fn sort_text(&self) -> &str { - self.filter_text.as_ref().unwrap_or(&self.label).as_str() + type Data = (); + fn sort_text(&self, data: &Self::Data) -> Cow { + self.filter_text(data) } - fn filter_text(&self) -> &str { - self.filter_text.as_ref().unwrap_or(&self.label).as_str() + #[inline] + fn filter_text(&self, _data: &Self::Data) -> Cow { + self.filter_text + .as_ref() + .unwrap_or(&self.label) + .as_str() + .into() } - fn label(&self) -> &str { - self.label.as_str() + fn label(&self, _data: &Self::Data) -> Spans { + self.label.as_str().into() } - fn row(&self) -> menu::Row { + fn row(&self, _data: &Self::Data) -> menu::Row { menu::Row::new(vec![ menu::Cell::from(self.label.as_str()), menu::Cell::from(match self.kind { @@ -85,7 +92,7 @@ impl Completion { start_offset: usize, trigger_offset: usize, ) -> Self { - let menu = Menu::new(items, move |editor: &mut Editor, item, event| { + let menu = Menu::new(items, (), move |editor: &mut Editor, item, event| { fn item_to_transaction( doc: &Document, item: &CompletionItem, diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index 0519374a3..6bb641391 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -1,9 +1,11 @@ +use std::{borrow::Cow, path::PathBuf}; + use crate::{ compositor::{Callback, Component, Compositor, Context, EventResult}, ctrl, key, shift, }; use crossterm::event::Event; -use tui::{buffer::Buffer as Surface, widgets::Table}; +use tui::{buffer::Buffer as Surface, text::Spans, widgets::Table}; pub use tui::widgets::{Cell, Row}; @@ -14,22 +16,41 @@ use helix_view::{graphics::Rect, Editor}; use tui::layout::Constraint; pub trait Item { - fn label(&self) -> &str; + /// Additional editor state that is used for label calculation. + type Data; + + fn label(&self, data: &Self::Data) -> Spans; + + fn sort_text(&self, data: &Self::Data) -> Cow { + let label: String = self.label(data).into(); + label.into() + } - fn sort_text(&self) -> &str { - self.label() + fn filter_text(&self, data: &Self::Data) -> Cow { + let label: String = self.label(data).into(); + label.into() } - fn filter_text(&self) -> &str { - self.label() + + fn row(&self, data: &Self::Data) -> Row { + Row::new(vec![Cell::from(self.label(data))]) } +} - fn row(&self) -> Row { - Row::new(vec![Cell::from(self.label())]) +impl Item for PathBuf { + /// Root prefix to strip. + type Data = PathBuf; + + fn label(&self, root_path: &Self::Data) -> Spans { + self.strip_prefix(&root_path) + .unwrap_or(self) + .to_string_lossy() + .into() } } pub struct Menu { options: Vec, + editor_data: T::Data, cursor: Option, @@ -54,10 +75,12 @@ impl Menu { // rendering) pub fn new( options: Vec, + editor_data: ::Data, callback_fn: impl Fn(&mut Editor, Option<&T>, MenuEvent) + 'static, ) -> Self { let mut menu = Self { options, + editor_data, matcher: Box::new(Matcher::default()), matches: Vec::new(), cursor: None, @@ -83,16 +106,17 @@ impl Menu { .iter() .enumerate() .filter_map(|(index, option)| { - let text = option.filter_text(); + let text: String = option.filter_text(&self.editor_data).into(); // TODO: using fuzzy_indices could give us the char idx for match highlighting self.matcher - .fuzzy_match(text, pattern) + .fuzzy_match(&text, pattern) .map(|score| (index, score)) }), ); // matches.sort_unstable_by_key(|(_, score)| -score); - self.matches - .sort_unstable_by_key(|(index, _score)| self.options[*index].sort_text()); + self.matches.sort_unstable_by_key(|(index, _score)| { + self.options[*index].sort_text(&self.editor_data) + }); // reset cursor position self.cursor = None; @@ -127,10 +151,10 @@ impl Menu { let n = self .options .first() - .map(|option| option.row().cells.len()) + .map(|option| option.row(&self.editor_data).cells.len()) .unwrap_or_default(); let max_lens = self.options.iter().fold(vec![0; n], |mut acc, option| { - let row = option.row(); + let row = option.row(&self.editor_data); // maintain max for each column for (acc, cell) in acc.iter_mut().zip(row.cells.iter()) { let width = cell.content.width(); @@ -300,7 +324,7 @@ impl Component for Menu { let scroll_line = (win_height - scroll_height) * scroll / std::cmp::max(1, len.saturating_sub(win_height)); - let rows = options.iter().map(|option| option.row()); + let rows = options.iter().map(|option| option.row(&self.editor_data)); let table = Table::new(rows) .style(style) .highlight_style(selected) diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 948a5f2b6..8d2bd3251 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -23,8 +23,6 @@ pub use text::Text; use helix_core::regex::Regex; use helix_core::regex::RegexBuilder; use helix_view::{Document, Editor, View}; -use tui; -use tui::text::Spans; use std::path::PathBuf; @@ -172,10 +170,7 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi FilePicker::new( files, - move |path: &PathBuf| { - // format_fn - Spans::from(path.strip_prefix(&root).unwrap_or(path).to_string_lossy()) - }, + root, move |cx, path: &PathBuf, action| { if let Err(e) = cx.editor.open(path, action) { let err = if let Some(err) = e.source() { diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 1581b0a15..01fea7186 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -6,7 +6,6 @@ use crate::{ use crossterm::event::Event; use tui::{ buffer::Buffer as Surface, - text::Spans, widgets::{Block, BorderType, Borders}, }; @@ -30,6 +29,8 @@ use helix_view::{ Document, Editor, }; +use super::menu::Item; + 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; @@ -37,7 +38,7 @@ pub const MAX_FILE_SIZE_FOR_PREVIEW: u64 = 10 * 1024 * 1024; /// File path and range of lines (used to align and highlight lines) pub type FileLocation = (PathBuf, Option<(usize, usize)>); -pub struct FilePicker { +pub struct FilePicker { picker: Picker, pub truncate_start: bool, /// Caches paths to documents @@ -84,15 +85,15 @@ impl Preview<'_, '_> { } } -impl FilePicker { +impl FilePicker { pub fn new( options: Vec, - format_fn: impl Fn(&T) -> Spans + 'static, + editor_data: T::Data, callback_fn: impl Fn(&mut Context, &T, Action) + 'static, preview_fn: impl Fn(&Editor, &T) -> Option + 'static, ) -> Self { let truncate_start = true; - let mut picker = Picker::new(options, format_fn, callback_fn); + let mut picker = Picker::new(options, editor_data, callback_fn); picker.truncate_start = truncate_start; Self { @@ -163,7 +164,7 @@ impl FilePicker { } } -impl Component for FilePicker { +impl Component for FilePicker { fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) { // +---------+ +---------+ // |prompt | |preview | @@ -280,8 +281,9 @@ impl Component for FilePicker { } } -pub struct Picker { +pub struct Picker { options: Vec, + editor_data: T::Data, // filter: String, matcher: Box, /// (index, score) @@ -299,14 +301,13 @@ pub struct Picker { /// Whether to truncate the start (default true) pub truncate_start: bool, - format_fn: Box Spans>, callback_fn: Box, } -impl Picker { +impl Picker { pub fn new( options: Vec, - format_fn: impl Fn(&T) -> Spans + 'static, + editor_data: T::Data, callback_fn: impl Fn(&mut Context, &T, Action) + 'static, ) -> Self { let prompt = Prompt::new( @@ -318,6 +319,7 @@ impl Picker { let mut picker = Self { options, + editor_data, matcher: Box::new(Matcher::default()), matches: Vec::new(), filters: Vec::new(), @@ -325,7 +327,6 @@ impl Picker { prompt, previous_pattern: String::new(), truncate_start: true, - format_fn: Box::new(format_fn), callback_fn: Box::new(callback_fn), completion_height: 0, }; @@ -371,9 +372,9 @@ impl Picker { #[allow(unstable_name_collisions)] self.matches.retain_mut(|(index, score)| { let option = &self.options[*index]; - // TODO: maybe using format_fn isn't the best idea here - let line: String = (self.format_fn)(option).into(); - match self.matcher.fuzzy_match(&line, pattern) { + let text = option.sort_text(&self.editor_data); + + match self.matcher.fuzzy_match(&text, pattern) { Some(s) => { // Update the score *score = s; @@ -399,11 +400,10 @@ impl Picker { self.filters.binary_search(&index).ok()?; } - // TODO: maybe using format_fn isn't the best idea here - let line: String = (self.format_fn)(option).into(); + let text = option.filter_text(&self.editor_data); self.matcher - .fuzzy_match(&line, pattern) + .fuzzy_match(&text, pattern) .map(|score| (index, score)) }), ); @@ -477,7 +477,7 @@ impl Picker { // - on input change: // - score all the names in relation to input -impl Component for Picker { +impl Component for Picker { fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> { self.completion_height = viewport.1.saturating_sub(4); Some(viewport) @@ -610,7 +610,7 @@ impl Component for Picker { surface.set_string(inner.x.saturating_sub(2), inner.y + i as u16, ">", selected); } - let spans = (self.format_fn)(option); + let spans = option.label(&self.editor_data); let (_score, highlights) = self .matcher .fuzzy_indices(&String::from(&spans), self.prompt.line()) diff --git a/helix-tui/src/text.rs b/helix-tui/src/text.rs index b4278c864..602090e55 100644 --- a/helix-tui/src/text.rs +++ b/helix-tui/src/text.rs @@ -402,6 +402,12 @@ impl<'a> From<&'a str> for Text<'a> { } } +impl<'a> From> for Text<'a> { + fn from(s: Cow<'a, str>) -> Text<'a> { + Text::raw(s) + } +} + impl<'a> From> for Text<'a> { fn from(span: Span<'a>) -> Text<'a> { Text { From 9f43dbc45d254ff860f7d33db201b2f0a6073195 Mon Sep 17 00:00:00 2001 From: ChrHorn Date: Sat, 2 Jul 2022 13:59:46 +0200 Subject: [PATCH 448/861] Highlight whole row in picker menus (#2939) --- helix-term/src/ui/picker.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 01fea7186..f4dd234a4 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -607,7 +607,16 @@ impl Component for Picker { for (i, (_index, option)) in files.take(rows as usize).enumerate() { let is_active = i == (self.cursor - offset); if is_active { - surface.set_string(inner.x.saturating_sub(2), inner.y + i as u16, ">", selected); + surface.set_string( + inner.x.saturating_sub(3), + inner.y + i as u16, + " > ", + selected, + ); + surface.set_style( + Rect::new(inner.x, inner.y + i as u16, inner.width, 1), + selected, + ); } let spans = option.label(&self.editor_data); From 4c30a3609aa8fbcca97609d281f5df449c234674 Mon Sep 17 00:00:00 2001 From: rsteube Date: Sun, 3 Jul 2022 23:19:12 +0200 Subject: [PATCH 449/861] languages: added elvish (#2948) --- book/src/generated/lang-support.md | 1 + languages.toml | 14 +++++ runtime/queries/elvish/highlights.scm | 76 +++++++++++++++++++++++++++ runtime/queries/elvish/injections.scm | 2 + 4 files changed, 93 insertions(+) create mode 100644 runtime/queries/elvish/highlights.scm create mode 100644 runtime/queries/elvish/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index c82a6443b..3c56a6f40 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -18,6 +18,7 @@ | ejs | ✓ | | | | | elixir | ✓ | ✓ | | `elixir-ls` | | elm | ✓ | | | `elm-language-server` | +| elvish | ✓ | | | `elvish` | | erb | ✓ | | | | | erlang | ✓ | ✓ | | `erlang_ls` | | fish | ✓ | ✓ | ✓ | | diff --git a/languages.toml b/languages.toml index 0b4a1dec5..c9ecc76fd 100644 --- a/languages.toml +++ b/languages.toml @@ -1489,3 +1489,17 @@ roots = [] comment-token = "#" indent = { tab-width = 4, unit = " " } grammar = "python" + +[[language]] +name = "elvish" +scope = "source.elvish" +file-types = ["elv"] +roots = [] +comment-token = "#" +indent = { tab-width = 2, unit = " " } +language-server = { command = "elvish", args = ["-lsp"] } +grammar = "elvish" + +[[grammar]] +name = "elvish" +source = { git = "https://github.com/ckafi/tree-sitter-elvish", rev = "e50787cadd3bc54f6d9c0704493a79078bb8a4e5" } diff --git a/runtime/queries/elvish/highlights.scm b/runtime/queries/elvish/highlights.scm new file mode 100644 index 000000000..fd70488df --- /dev/null +++ b/runtime/queries/elvish/highlights.scm @@ -0,0 +1,76 @@ +;; SPDX-License-Identifier: 0BSD +;; SPDX-FileCopyrightText: 2022 Tobias Frilling + +(comment) @comment + +(if "if" @keyword.control.conditional) +(if (elif "elif" @keyword.control.conditional)) +(if (else "else" @keyword.control.conditional)) + +(while "while" @keyword.control.repeat) +(while (else "else" @keyword.control.repeat)) +(for "for" @keyword.control.repeat) +(for (else "else" @keyword.control.repeat)) + +(try "try" @keyword.control.exception) +(try (catch "catch" @keyword.control.exception)) +(try (else "else" @keyword.control.exception)) +(try (finally "finally" @keyword.control.exception)) + +(import "use" @keyword.control.import) +(import (bareword) @string.special) + +(wildcard ["*" "**" "?"] @string.special) + +(command argument: (bareword) @variable.parameter) +(command head: (identifier) @function) +((command head: (identifier) @keyword.control.return) + (#eq? @keyword.control.return "return")) +((command (identifier) @keyword.operator) + (#match? @keyword.operator "(and|or|coalesce)")) +((command head: _ @function) + (#match? @function "([+]|[-]|[*]|[/]|[%]|[<]|[<][=]|[=][=]|[!][=]|[>]|[>][=]|[<][s]|[<][=][s]|[=][=][s]|[!][=][s]|[>][s]|[>][=][s])")) + +(pipeline "|" @operator) +(redirection [">" "<" ">>" "<>"] @operator) + +(io_port) @constant.numeric + +(function_definition + "fn" @keyword.function + (identifier) @function) + +(parameter_list) @variable.parameter +(parameter_list "|" @punctuation.bracket) + +(variable_declaration + "var" @keyword + (lhs (identifier) @variable)) + +(variable_assignment + "set" @keyword + (lhs (identifier) @variable)) + +(temporary_assignment + "tmp" @keyword + (lhs (identifier) @variable)) + +(variable_deletion + "del" @keyword + (identifier) @variable) + + +(number) @constant.numeric +(string) @string + +((variable (identifier) @function) + (#match? @function ".+\\~$")) +((variable (identifier) @constant.builtin.boolean) + (#match? @constant.builtin.boolean "(true|false)")) +((variable (identifier) @constant.builtin) + (#match? @constant.builtin "(_|after-chdir|args|before-chdir|buildinfo|nil|notify-bg-job-success|num-bg-jobs|ok|paths|pid|pwd|value-out-indicator|version)")) +(variable (identifier) @variable) + +["$" "@"] @punctuation.special +["(" ")" "[" "]" "{" "}"] @punctuation.bracket +";" @punctuation.delimiter diff --git a/runtime/queries/elvish/injections.scm b/runtime/queries/elvish/injections.scm new file mode 100644 index 000000000..321c90add --- /dev/null +++ b/runtime/queries/elvish/injections.scm @@ -0,0 +1,2 @@ +((comment) @injection.content + (#set! injection.language "comment")) From e58d28a9728fd5d451c98c48bd20c57fb9eec7dc Mon Sep 17 00:00:00 2001 From: 0rphee <79347623+0rphee@users.noreply.github.com> Date: Sun, 3 Jul 2022 22:44:17 -0500 Subject: [PATCH 450/861] Add Haskell roots (#2954) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index c9ecc76fd..7c63c051a 100644 --- a/languages.toml +++ b/languages.toml @@ -660,7 +660,7 @@ name = "haskell" scope = "source.haskell" injection-regex = "haskell" file-types = ["hs"] -roots = [] +roots = ["Setup.hs", "stack.yaml", "*.cabal"] comment-token = "--" language-server = { command = "haskell-language-server-wrapper", args = ["--lsp"] } indent = { tab-width = 2, unit = " " } From 244825b9e1959939e1c08fe942a288d10eb6da69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B7=9D=E7=94=B0=20=E6=81=B5=E6=B0=8F=20=28Kawada=20Keis?= =?UTF-8?q?hi=20a=2Ek=2Ea=20megumish=29?= Date: Tue, 5 Jul 2022 02:32:46 +0900 Subject: [PATCH 451/861] Add runtime `xcopy` command on powershell in docs (#2958) --- README.md | 9 +++++---- book/src/install.md | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 032ecf675..48c24de7c 100644 --- a/README.md +++ b/README.md @@ -49,10 +49,11 @@ tree-sitter grammars may be manually fetched and built with `hx --grammar fetch` Helix also needs its runtime files so make sure to copy/symlink the `runtime/` directory into the config directory (for example `~/.config/helix/runtime` on Linux/macOS, or `%AppData%/helix/runtime` on Windows). -| OS | command | -|-----------|-----------| -|windows |`xcopy runtime %AppData%/helix/runtime`| -|linux/macos|`ln -s $PWD/runtime ~/.config/helix/runtime` +| OS | command | +|-------------------|-----------| +|windows(cmd.exe) |`xcopy runtime %AppData%/helix/runtime` | +|windows(powershell)|`xcopy runtime $Env:AppData\helix\runtime` | +|linux/macos |`ln -s $PWD/runtime ~/.config/helix/runtime`| This location can be overridden via the `HELIX_RUNTIME` environment variable. diff --git a/book/src/install.md b/book/src/install.md index bf59ea234..045e22556 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -61,10 +61,11 @@ Helix also needs it's runtime files so make sure to copy/symlink the `runtime/` config directory (for example `~/.config/helix/runtime` on Linux/macOS). This location can be overridden via the `HELIX_RUNTIME` environment variable. -| OS | command | -|-----------|-----------| -|windows |`xcopy runtime %AppData%/helix/runtime`| -|linux/macos|`ln -s $PWD/runtime ~/.config/helix/runtime` +| OS | command | +|-------------------|-----------| +|windows(cmd.exe) |`xcopy runtime %AppData%/helix/runtime` | +|windows(powershell)|`xcopy runtime $Env:AppData\helix\runtime` | +|linux/macos |`ln -s $PWD/runtime ~/.config/helix/runtime`| ## Finishing up the installation From 2ac1de305e10238a2e7ed8c0d66f3fa78566dbaa Mon Sep 17 00:00:00 2001 From: A-Walrus <58790821+A-Walrus@users.noreply.github.com> Date: Tue, 5 Jul 2022 01:51:15 +0300 Subject: [PATCH 452/861] Fix backwards selection duplication widening bug (#2945) * Fix backwards selection duplication widening bug * Add integration tests * Make tests line-ending agnostic Make tests line-ending agnostic Use indoc to fix tests Fix line-ending on test input --- helix-term/src/commands.rs | 8 +++---- helix-term/tests/test/commands.rs | 40 +++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index df4867fc7..c9e350628 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1411,16 +1411,16 @@ fn copy_selection_on_line(cx: &mut Context, direction: Direction) { let is_primary = *range == selection.primary(); // The range is always head exclusive - let head = if range.anchor < range.head { - range.head - 1 + let (head, anchor) = if range.anchor < range.head { + (range.head - 1, range.anchor) } else { - range.head + (range.head, range.anchor - 1) }; let tab_width = doc.tab_width(); let head_pos = visual_coords_at_pos(text, head, tab_width); - let anchor_pos = visual_coords_at_pos(text, range.anchor, tab_width); + let anchor_pos = visual_coords_at_pos(text, anchor, tab_width); let height = std::cmp::max(head_pos.row, anchor_pos.row) - std::cmp::min(head_pos.row, anchor_pos.row) diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index 0cd79bc7f..f7ce9af08 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -91,3 +91,43 @@ async fn test_buffer_close_concurrent() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test] +async fn test_selection_duplication() -> anyhow::Result<()> { + // Forward + test(( + platform_line(indoc! {"\ + #[lo|]#rem + ipsum + dolor + "}) + .as_str(), + "CC", + platform_line(indoc! {"\ + #(lo|)#rem + #(ip|)#sum + #[do|]#lor + "}) + .as_str(), + )) + .await?; + + // Backward + test(( + platform_line(indoc! {"\ + #[|lo]#rem + ipsum + dolor + "}) + .as_str(), + "CC", + platform_line(indoc! {"\ + #(|lo)#rem + #(|ip)#sum + #[|do]#lor + "}) + .as_str(), + )) + .await?; + Ok(()) +} From f392e354399c5158ad5e6d94b7170ac5040f30c6 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Mon, 4 Jul 2022 19:06:44 -0400 Subject: [PATCH 453/861] feat(theme): solarized: add cursorline, ruler, indent guide (#2962) --- runtime/themes/solarized_dark.toml | 7 +++++++ runtime/themes/solarized_light.toml | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/runtime/themes/solarized_dark.toml b/runtime/themes/solarized_dark.toml index 002e99bc7..aa6dbbf8d 100644 --- a/runtime/themes/solarized_dark.toml +++ b/runtime/themes/solarized_dark.toml @@ -80,9 +80,15 @@ # 主光标/selectio "ui.cursor.primary" = { fg = "base03", bg = "base1" } "ui.cursor.select" = { fg = "base02", bg = "cyan" } +"ui.cursorline.primary" = { bg = "base02" } +"ui.cursorline.secondary" = { bg = "base025" } + "ui.selection" = { bg = "base0175" } "ui.selection.primary" = { bg = "base015" } +"ui.virtual.indent-guide" = { fg = "base02" } +"ui.virtual.ruler" = { fg = "red" } + # normal模式的光标 "ui.cursor" = {fg = "base02", bg = "cyan"} "ui.cursor.insert" = {fg = "base03", bg = "base3"} @@ -98,6 +104,7 @@ [palette] # 深色 越来越深 base03 = "#002b36" +base025 = "#03303b" base02 = "#073642" base0175 = "#16404b" base015 = "#2c4f59" diff --git a/runtime/themes/solarized_light.toml b/runtime/themes/solarized_light.toml index fa58cc8cf..79fd83642 100644 --- a/runtime/themes/solarized_light.toml +++ b/runtime/themes/solarized_light.toml @@ -94,9 +94,16 @@ # main cursor/selection "ui.cursor.primary" = { fg = "base03", bg = "base1" } "ui.cursor.select" = { fg = "base02", bg = "cyan" } + +"ui.cursorline.primary" = { bg = "base02" } +"ui.cursorline.secondary" = { bg = "base025" } + "ui.selection" = { bg = "base0175" } "ui.selection.primary" = { bg = "base015" } +"ui.virtual.indent-guide" = { fg = "base02" } +"ui.virtual.ruler" = { fg = "red" } + # normal模式的光标 # normal mode cursor "ui.cursor" = {fg = "base02", bg = "cyan"} @@ -135,4 +142,5 @@ base01 = '#93a1a1' base015 = '#c5c8bd' base0175 = '#dddbcc' base02 = '#eee8d5' +base025 = '#f5eedb' base03 = '#fdf6e3' From a679efa8ce068ffa8f62b164f4a6ce958f6bb99c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 08:20:12 +0530 Subject: [PATCH 454/861] build(deps): bump serde from 1.0.136 to 1.0.138 (#2967) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.136 to 1.0.138. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.136...v1.0.138) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6d94b6d7b..cfcb9fe02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -772,11 +772,11 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -916,18 +916,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" dependencies = [ "proc-macro2", "quote", @@ -1072,13 +1072,13 @@ checksum = "9d9199fa80c817e074620be84374a520062ebac833f358d74b37060ce4a0f2c0" [[package]] name = "syn" -version = "1.0.86" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -1241,6 +1241,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1218098468b8085b19a2824104c70d976491d247ce194bbd9dc77181150cdfd6" +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + [[package]] name = "unicode-linebreak" version = "0.1.2" @@ -1271,12 +1277,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - [[package]] name = "url" version = "2.2.2" From c88d736d5c1384f0d3391295a4876892d79dba51 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 11:04:03 +0800 Subject: [PATCH 455/861] build(deps): bump once_cell from 1.12.0 to 1.13.0 (#2969) Bumps [once_cell](https://github.com/matklad/once_cell) from 1.12.0 to 1.13.0. - [Release notes](https://github.com/matklad/once_cell/releases) - [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md) - [Commits](https://github.com/matklad/once_cell/compare/v1.12.0...v1.13.0) --- updated-dependencies: - dependency-name: once_cell dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- helix-core/Cargo.toml | 2 +- helix-loader/Cargo.toml | 2 +- helix-term/Cargo.toml | 2 +- helix-view/Cargo.toml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cfcb9fe02..a4720f712 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -725,9 +725,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" [[package]] name = "parking_lot" diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 5eb3b621a..3ce0e4832 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -26,7 +26,7 @@ unicode-general-category = "0.5" # slab = "0.4.2" slotmap = "1.0" tree-sitter = "0.20" -once_cell = "1.12" +once_cell = "1.13" arc-swap = "1" regex = "1" diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index 3d8a697cc..46144a309 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -19,7 +19,7 @@ serde = { version = "1.0", features = ["derive"] } toml = "0.5" etcetera = "0.4" tree-sitter = "0.20" -once_cell = "1.12" +once_cell = "1.13" log = "0.4" # TODO: these two should be on !wasm32 only diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 3da5a74ec..29c34e404 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -31,7 +31,7 @@ helix-dap = { version = "0.6", path = "../helix-dap" } helix-loader = { version = "0.6", path = "../helix-loader" } anyhow = "1" -once_cell = "1.12" +once_cell = "1.13" which = "4.2" diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index 77634ce58..6d0811ba5 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -22,7 +22,7 @@ helix-dap = { version = "0.6", path = "../helix-dap" } crossterm = { version = "0.23", optional = true } # Conversion traits -once_cell = "1.12" +once_cell = "1.13" url = "2" arc-swap = { version = "1.5.0" } From 700431d6652988784d7914c501451ef9d2fbae15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 19:19:27 +0900 Subject: [PATCH 456/861] build(deps): bump encoding_rs from 0.8.30 to 0.8.31 (#2963) Bumps [encoding_rs](https://github.com/hsivonen/encoding_rs) from 0.8.30 to 0.8.31. - [Release notes](https://github.com/hsivonen/encoding_rs/releases) - [Commits](https://github.com/hsivonen/encoding_rs/compare/v0.8.30...v0.8.31) --- updated-dependencies: - dependency-name: encoding_rs dependency-type: direct:production update-type: version-update:semver-patch ... 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 a4720f712..7617d2dbe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,9 +184,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "encoding_rs" -version = "0.8.30" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" dependencies = [ "cfg-if", ] From b98567f248cbdc623b3fea03b8193542173a74c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 19:24:07 +0900 Subject: [PATCH 457/861] build(deps): bump which from 4.2.4 to 4.2.5 (#2964) Bumps [which](https://github.com/harryfei/which-rs) from 4.2.4 to 4.2.5. - [Release notes](https://github.com/harryfei/which-rs/releases) - [Commits](https://github.com/harryfei/which-rs/compare/4.2.4...4.2.5) --- updated-dependencies: - dependency-name: which dependency-type: direct:production update-type: version-update:semver-patch ... 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 7617d2dbe..2c2d8f5f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1321,9 +1321,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "which" -version = "4.2.4" +version = "4.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" dependencies = [ "either", "lazy_static", From 1fc8cbeb688c25b17f6471a9688cf78df07c4581 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 19:24:37 +0900 Subject: [PATCH 458/861] build(deps): bump log from 0.4.14 to 0.4.17 (#2965) Bumps [log](https://github.com/rust-lang/log) from 0.4.14 to 0.4.17. - [Release notes](https://github.com/rust-lang/log/releases) - [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/log/compare/0.4.14...0.4.17) --- updated-dependencies: - dependency-name: log dependency-type: direct:production update-type: version-update:semver-patch ... 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 2c2d8f5f3..7e81b4648 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -610,9 +610,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] From ba255e3e3e550e1e3bac95e592e6c7df7746a4de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 19:25:56 +0900 Subject: [PATCH 459/861] build(deps): bump serde_json from 1.0.81 to 1.0.82 (#2966) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.81 to 1.0.82. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.81...v1.0.82) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... 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 7e81b4648..c11429c10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -936,9 +936,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" dependencies = [ "itoa", "ryu", From f3467399b7a454a6fc8f42a87f898e37a6c0abad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 19:30:33 +0900 Subject: [PATCH 460/861] build(deps): bump crossterm from 0.23.0 to 0.24.0 (#2968) Bumps [crossterm](https://github.com/crossterm-rs/crossterm) from 0.23.0 to 0.24.0. - [Release notes](https://github.com/crossterm-rs/crossterm/releases) - [Changelog](https://github.com/crossterm-rs/crossterm/blob/master/CHANGELOG.md) - [Commits](https://github.com/crossterm-rs/crossterm/compare/0.23...0.24) --- updated-dependencies: - dependency-name: crossterm dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 45 +++++++------------------------------------ helix-term/Cargo.toml | 2 +- helix-tui/Cargo.toml | 2 +- helix-view/Cargo.toml | 2 +- 4 files changed, 10 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c11429c10..f3b2bc8e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,15 +131,15 @@ dependencies = [ [[package]] name = "crossterm" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77b75a27dc8d220f1f8521ea69cd55a34d720a200ebb3a624d9aa19193d3b432" +checksum = "ab9f7409c70a38a56216480fba371ee460207dd8926ccf5b4160591759559170" dependencies = [ "bitflags", "crossterm_winapi", "futures-core", "libc", - "mio 0.7.14", + "mio", "parking_lot", "signal-hook", "signal-hook-mio", @@ -651,19 +651,6 @@ dependencies = [ "libc", ] -[[package]] -name = "mio" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" -dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "winapi", -] - [[package]] name = "mio" version = "0.8.3" @@ -676,24 +663,6 @@ dependencies = [ "windows-sys 0.36.1", ] -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", -] - -[[package]] -name = "ntapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" -dependencies = [ - "winapi", -] - [[package]] name = "num-integer" version = "0.1.44" @@ -968,12 +937,12 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" dependencies = [ "libc", - "mio 0.7.14", + "mio", "signal-hook", ] @@ -1168,7 +1137,7 @@ dependencies = [ "bytes", "libc", "memchr", - "mio 0.8.3", + "mio", "num_cpus", "once_cell", "parking_lot", diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 29c34e404..4c2c2da72 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -37,7 +37,7 @@ which = "4.2" tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] } tui = { path = "../helix-tui", package = "helix-tui", default-features = false, features = ["crossterm"] } -crossterm = { version = "0.23", features = ["event-stream"] } +crossterm = { version = "0.24", features = ["event-stream"] } signal-hook = "0.3" tokio-stream = "0.1" futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false } diff --git a/helix-tui/Cargo.toml b/helix-tui/Cargo.toml index e4cfbe4cd..25e32b500 100644 --- a/helix-tui/Cargo.toml +++ b/helix-tui/Cargo.toml @@ -19,7 +19,7 @@ default = ["crossterm"] bitflags = "1.3" cassowary = "0.3" unicode-segmentation = "1.9" -crossterm = { version = "0.23", optional = true } +crossterm = { version = "0.24", optional = true } serde = { version = "1", "optional" = true, features = ["derive"]} helix-view = { version = "0.6", path = "../helix-view", features = ["term"] } helix-core = { version = "0.6", path = "../helix-core" } diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index 6d0811ba5..91921dd3c 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -19,7 +19,7 @@ anyhow = "1" helix-core = { version = "0.6", path = "../helix-core" } helix-lsp = { version = "0.6", path = "../helix-lsp" } helix-dap = { version = "0.6", path = "../helix-dap" } -crossterm = { version = "0.23", optional = true } +crossterm = { version = "0.24", optional = true } # Conversion traits once_cell = "1.13" From f3e8b0f34bcf4a66dabeef40998442ef8f95967a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 19:31:01 +0900 Subject: [PATCH 461/861] build(deps): bump smallvec from 1.8.1 to 1.9.0 (#2976) Bumps [smallvec](https://github.com/servo/rust-smallvec) from 1.8.1 to 1.9.0. - [Release notes](https://github.com/servo/rust-smallvec/releases) - [Commits](https://github.com/servo/rust-smallvec/compare/v1.8.1...v1.9.0) --- updated-dependencies: - dependency-name: smallvec dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- helix-core/Cargo.toml | 2 +- helix-term/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f3b2bc8e7..00d8c4755 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -990,9 +990,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] name = "smartstring" diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 3ce0e4832..b7a1f3323 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -18,7 +18,7 @@ integration = [] helix-loader = { version = "0.6", path = "../helix-loader" } ropey = { version = "1.5", default-features = false, features = ["simd"] } -smallvec = "1.8" +smallvec = "1.9" smartstring = "1.0.1" unicode-segmentation = "1.9" unicode-width = "0.1" diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 4c2c2da72..c94e6502f 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -76,6 +76,6 @@ signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } helix-loader = { version = "0.6", path = "../helix-loader" } [dev-dependencies] -smallvec = "1.8" +smallvec = "1.9" indoc = "1.0.6" tempfile = "3.3.0" From 2e709859c4ab35237374e3c8e64c9d3767be4134 Mon Sep 17 00:00:00 2001 From: Jens Getreu Date: Tue, 5 Jul 2022 08:08:35 +0200 Subject: [PATCH 462/861] Autumn theme: slightly adjust contrast --- runtime/themes/autumn.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/runtime/themes/autumn.toml b/runtime/themes/autumn.toml index d96d32eaa..024ca6501 100644 --- a/runtime/themes/autumn.toml +++ b/runtime/themes/autumn.toml @@ -69,13 +69,13 @@ "error" = "my_red" [palette] -my_black = "#242424" # Cursorline -my_gray0 = "#292929" # Default Background -my_gray1 = "#2e2e2e" # Ruler -my_gray2 = "#3a3a3a" # Lighter Background (Used for status bars, line number and folding marks) -my_gray3 = "#525252" # Selection Background +my_black = "#212121" # Cursorline +my_gray0 = "#262626" # Default Background +my_gray1 = "#2b2b2b" # Ruler +my_gray2 = "#323232" # Lighter Background (Used for status bars, line number and folding marks) +my_gray3 = "#505050" # Selection Background my_gray4 = "#7c7c7c" # Comments, Invisibles, Line Highlighting -my_gray5 = "#aaaaaa" # Dark Foreground (Used for status bars) +my_gray5 = "#a8a8a8" # Dark Foreground (Used for status bars) my_gray6 = "#c0c0c0" # Light Foreground (Not often used) my_gray7 = "#e8e8e8" # Light Background (Not often used) my_white = "#F3F2CC" # Default Foreground, Caret, Delimiters, Operators From 936ed3a226a5b94c470f5b40ad7df1b0a3ae4793 Mon Sep 17 00:00:00 2001 From: Jens Getreu Date: Tue, 5 Jul 2022 08:21:33 +0200 Subject: [PATCH 463/861] Add Autumn night theme Under some light conditions, one prefers a high contrast theme. --- runtime/themes/autumn_night.toml | 90 ++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 runtime/themes/autumn_night.toml diff --git a/runtime/themes/autumn_night.toml b/runtime/themes/autumn_night.toml new file mode 100644 index 000000000..381e21d98 --- /dev/null +++ b/runtime/themes/autumn_night.toml @@ -0,0 +1,90 @@ +# The structure is based on `base16_default_dark` by Ray Gervais. Most of +# the colors come from the so called Autumn theme, a color scheme inspired by +# the colors you can find in the autumn. Originally it was designed as a +# color scheme for the Komodo IDE and then ported to Vim by Kenneth Love +# and Chris Jones. Later, Yorick Peterse improved their work. See: +# +# 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_gray4", bg = "my_gray2" } +"ui.popup" = { bg = "my_gray2" } +"ui.window" = { fg = "my_gray4", bg = "my_gray2" } +"ui.linenr.selected" = { fg = "my_gray6", bg = "my_gray1"} +"ui.selection" = { bg = "my_gray3" } +"comment" = { fg = "my_gray4", modifiers = ["italic"] } +"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" +"attributes" = "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_gray2" } +"hint" = "my_gray5" +"debug" = "my_yellow2" +"info" = "my_yellow2" +"warning" = "my_yellow2" +"error" = "my_red" + +[palette] +my_black = "#111111" # Cursorline +my_gray0 = "#090909" # Default Background +my_gray1 = "#0e0e0e" # Ruler +my_gray2 = "#1a1a1a" # Lighter Background (Used for status bars, line number and folding marks) +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_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 +my_white3 = "#F3F2CC" # Classes, Markup Bold, Search Text Background +my_turquoise = "#86c1b9" # Support, Regular Expressions, Escape Characters +my_turquoise2 = "#72a59e" # URL +my_green = "#99be70" # Strings, Inherited Class, Markup Code, Diff Inserted +my_brown = "#cfba8b" # Member variables, Quotes +my_yellow1 = "#FAD566" # Functions, Methods, Attribute IDs, Headings +my_yellow2 = "#ffff9f" # Debug, Info +my_red = "#F05E48" # Keywords, Storage, Selector, Diff Changed From 44f596334aeda7c540fbe12d2653c86dae686470 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 4 Jul 2022 09:30:36 -0500 Subject: [PATCH 464/861] DAP: Skip serializing `Option`s when `None` DAP follows the same strict TypeScript interface syntax as LSP which states: > The document uses TypeScript interfaces in strict mode to describe > these. This means for example that a `null` value has to be explicitly > listed and that a mandatory property must be listed even if a falsify > value might exist. So we have to skip serializing any fields that end in `?` instead of passing `null`. --- helix-dap/src/types.rs | 174 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 168 insertions(+), 6 deletions(-) diff --git a/helix-dap/src/types.rs b/helix-dap/src/types.rs index fd8456a43..71b2aa834 100644 --- a/helix-dap/src/types.rs +++ b/helix-dap/src/types.rs @@ -27,9 +27,11 @@ pub trait Request { pub struct ColumnDescriptor { pub attribute_name: String, pub label: String, + #[serde(skip_serializing_if = "Option::is_none")] pub format: Option, - #[serde(rename = "type")] + #[serde(rename = "type", skip_serializing_if = "Option::is_none")] pub ty: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub width: Option, } @@ -38,52 +40,94 @@ pub struct ColumnDescriptor { pub struct ExceptionBreakpointsFilter { pub filter: String, pub label: String, + #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub default: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_condition: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub condition_description: Option, } #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct DebuggerCapabilities { + #[serde(skip_serializing_if = "Option::is_none")] pub supports_configuration_done_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_function_breakpoints: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_conditional_breakpoints: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_hit_conditional_breakpoints: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_evaluate_for_hovers: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_step_back: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_set_variable: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_restart_frame: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_goto_targets_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_step_in_targets_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_completions_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_modules_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_restart_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_exception_options: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_value_formatting_options: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_exception_info_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub support_terminate_debuggee: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub support_suspend_debuggee: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_delayed_stack_trace_loading: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_loaded_sources_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_log_points: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_terminate_threads_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_set_expression: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_terminate_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_data_breakpoints: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_read_memory_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_write_memory_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_disassemble_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_cancel_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_breakpoint_locations_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_clipboard_context: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_stepping_granularity: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_instruction_breakpoints: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_exception_filter_options: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub exception_breakpoint_filters: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub completion_trigger_characters: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub additional_module_columns: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub supported_checksum_algorithms: Option>, } @@ -97,13 +141,21 @@ pub struct Checksum { #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Source { + #[serde(skip_serializing_if = "Option::is_none")] pub name: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub path: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub source_reference: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub presentation_hint: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub origin: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub sources: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub adapter_data: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub checksums: Option>, } @@ -111,36 +163,56 @@ pub struct Source { #[serde(rename_all = "camelCase")] pub struct SourceBreakpoint { pub line: usize, + #[serde(skip_serializing_if = "Option::is_none")] pub column: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub condition: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub hit_condition: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub log_message: Option, } #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Breakpoint { + #[serde(skip_serializing_if = "Option::is_none")] pub id: Option, pub verified: bool, + #[serde(skip_serializing_if = "Option::is_none")] pub message: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub source: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub line: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub column: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub end_line: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub end_column: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub instruction_reference: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub offset: Option, } #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct StackFrameFormat { + #[serde(skip_serializing_if = "Option::is_none")] pub parameters: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub parameter_types: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub parameter_names: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub parameter_values: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub line: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub module: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub include_all: Option, } @@ -149,14 +221,21 @@ pub struct StackFrameFormat { pub struct StackFrame { pub id: usize, pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] pub source: Option, pub line: usize, pub column: usize, + #[serde(skip_serializing_if = "Option::is_none")] pub end_line: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub end_column: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub can_restart: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub instruction_pointer_reference: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub module_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub presentation_hint: Option, } @@ -171,29 +250,41 @@ pub struct Thread { #[serde(rename_all = "camelCase")] pub struct Scope { pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] pub presentation_hint: Option, pub variables_reference: usize, + #[serde(skip_serializing_if = "Option::is_none")] pub named_variables: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub indexed_variables: Option, pub expensive: bool, + #[serde(skip_serializing_if = "Option::is_none")] pub source: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub line: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub column: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub end_line: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub end_column: Option, } #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct ValueFormat { + #[serde(skip_serializing_if = "Option::is_none")] pub hex: Option, } #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct VariablePresentationHint { + #[serde(skip_serializing_if = "Option::is_none")] pub kind: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub attributes: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub visibility: Option, } @@ -202,13 +293,18 @@ pub struct VariablePresentationHint { pub struct Variable { pub name: String, pub value: String, - #[serde(rename = "type")] + #[serde(rename = "type", skip_serializing_if = "Option::is_none")] pub ty: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub presentation_hint: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub evaluate_name: Option, pub variables_reference: usize, + #[serde(skip_serializing_if = "Option::is_none")] pub named_variables: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub indexed_variables: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub memory_reference: Option, } @@ -217,13 +313,21 @@ pub struct Variable { pub struct Module { pub id: String, // TODO: || number pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] pub path: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub is_optimized: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub is_user_code: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub version: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub symbol_status: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub symbol_file_path: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub date_time_stamp: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub address_range: Option, } @@ -232,22 +336,31 @@ pub mod requests { #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct InitializeArguments { - #[serde(rename = "clientID")] + #[serde(rename = "clientID", skip_serializing_if = "Option::is_none")] pub client_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub client_name: Option, #[serde(rename = "adapterID")] pub adapter_id: String, + #[serde(skip_serializing_if = "Option::is_none")] pub locale: Option, - #[serde(rename = "linesStartAt1")] + #[serde(rename = "linesStartAt1", skip_serializing_if = "Option::is_none")] pub lines_start_at_one: Option, - #[serde(rename = "columnsStartAt1")] + #[serde(rename = "columnsStartAt1", skip_serializing_if = "Option::is_none")] pub columns_start_at_one: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub path_format: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_variable_type: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_variable_paging: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_run_in_terminal_request: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_memory_references: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_progress_reporting: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supports_invalidated_event: Option, } @@ -300,14 +413,17 @@ pub mod requests { #[serde(rename_all = "camelCase")] pub struct SetBreakpointsArguments { pub source: Source, + #[serde(skip_serializing_if = "Option::is_none")] pub breakpoints: Option>, // lines is deprecated + #[serde(skip_serializing_if = "Option::is_none")] pub source_modified: Option, } #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct SetBreakpointsResponse { + #[serde(skip_serializing_if = "Option::is_none")] pub breakpoints: Option>, } @@ -329,6 +445,7 @@ pub mod requests { #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct ContinueResponse { + #[serde(skip_serializing_if = "Option::is_none")] pub all_threads_continued: Option, } @@ -345,14 +462,18 @@ pub mod requests { #[serde(rename_all = "camelCase")] pub struct StackTraceArguments { pub thread_id: ThreadId, + #[serde(skip_serializing_if = "Option::is_none")] pub start_frame: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub levels: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub format: Option, } #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct StackTraceResponse { + #[serde(skip_serializing_if = "Option::is_none")] pub total_frames: Option, pub stack_frames: Vec, } @@ -406,9 +527,13 @@ pub mod requests { #[serde(rename_all = "camelCase")] pub struct VariablesArguments { pub variables_reference: usize, + #[serde(skip_serializing_if = "Option::is_none")] pub filter: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub start: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub count: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub format: Option, } @@ -431,7 +556,9 @@ pub mod requests { #[serde(rename_all = "camelCase")] pub struct StepInArguments { pub thread_id: ThreadId, + #[serde(skip_serializing_if = "Option::is_none")] pub target_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub granularity: Option, } @@ -448,6 +575,7 @@ pub mod requests { #[serde(rename_all = "camelCase")] pub struct StepOutArguments { pub thread_id: ThreadId, + #[serde(skip_serializing_if = "Option::is_none")] pub granularity: Option, } @@ -464,6 +592,7 @@ pub mod requests { #[serde(rename_all = "camelCase")] pub struct NextArguments { pub thread_id: ThreadId, + #[serde(skip_serializing_if = "Option::is_none")] pub granularity: Option, } @@ -495,8 +624,11 @@ pub mod requests { #[serde(rename_all = "camelCase")] pub struct EvaluateArguments { pub expression: String, + #[serde(skip_serializing_if = "Option::is_none")] pub frame_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub context: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub format: Option, } @@ -504,12 +636,16 @@ pub mod requests { #[serde(rename_all = "camelCase")] pub struct EvaluateResponse { pub result: String, - #[serde(rename = "type")] + #[serde(rename = "type", skip_serializing_if = "Option::is_none")] pub ty: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub presentation_hint: Option, pub variables_reference: usize, + #[serde(skip_serializing_if = "Option::is_none")] pub named_variables: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub indexed_variables: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub memory_reference: Option, } @@ -533,6 +669,7 @@ pub mod requests { #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct SetExceptionBreakpointsResponse { + #[serde(skip_serializing_if = "Option::is_none")] pub breakpoints: Option>, } @@ -550,17 +687,23 @@ pub mod requests { #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct RunInTerminalResponse { + #[serde(skip_serializing_if = "Option::is_none")] pub process_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub shell_process_id: Option, } #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct RunInTerminalArguments { + #[serde(skip_serializing_if = "Option::is_none")] pub kind: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub cwd: Option, pub args: Vec, + #[serde(skip_serializing_if = "Option::is_none")] pub env: Option>>, } @@ -607,11 +750,17 @@ pub mod events { #[serde(rename_all = "camelCase")] pub struct Stopped { pub reason: String, + #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub thread_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub preserve_focus_hint: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub text: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub all_threads_stopped: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub hit_breakpoint_ids: Option>, } @@ -619,6 +768,7 @@ pub mod events { #[serde(rename_all = "camelCase")] pub struct Continued { pub thread_id: ThreadId, + #[serde(skip_serializing_if = "Option::is_none")] pub all_threads_continued: Option, } @@ -631,6 +781,7 @@ pub mod events { #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Terminated { + #[serde(skip_serializing_if = "Option::is_none")] pub restart: Option, } @@ -645,12 +796,19 @@ pub mod events { #[serde(rename_all = "camelCase")] pub struct Output { pub output: String, + #[serde(skip_serializing_if = "Option::is_none")] pub category: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub group: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub line: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub column: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub variables_reference: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub source: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub data: Option, } @@ -679,9 +837,13 @@ pub mod events { #[serde(rename_all = "camelCase")] pub struct Process { pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] pub system_process_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub is_local_process: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub start_method: Option, // TODO: use enum + #[serde(skip_serializing_if = "Option::is_none")] pub pointer_size: Option, } From 85411bed83615895f4138fa080c07c257631d7f7 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 4 Jul 2022 09:32:28 -0500 Subject: [PATCH 465/861] DAP: Make `cwd` required in RunTerminalArguments The spec has `cwd` in `RunInTerminalRequestArguments` as non-optional: https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_RunInTerminal --- helix-dap/src/types.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/helix-dap/src/types.rs b/helix-dap/src/types.rs index 71b2aa834..45f45cca5 100644 --- a/helix-dap/src/types.rs +++ b/helix-dap/src/types.rs @@ -700,8 +700,7 @@ pub mod requests { pub kind: Option, #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub cwd: Option, + pub cwd: String, pub args: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub env: Option>>, From b26e7e2e8fc900b5637d9772ecb74874e8794ecc Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 5 Jul 2022 06:44:16 -0400 Subject: [PATCH 466/861] Add live preview to theme picker (#1798) * Add theme picker with live preview * Add live theme preview to :theme command * cargo fmt * Fix clippy warnings * Remove picker variant * Remove unused import * Cleanup * Change current_theme to last_theme * Fix accidental comment flash deletion * Typo * Remove theme cache * Add some comments * Refactor some theme handling TIL flatmap on Option is called and_then * Remove unnecessary renames * Constrain last_theme theme preview lifecycle * Switch to bitflag implementation * Better handling of last_theme * Sort theme names * Better memory juggling * Missed a branch * Remove name from theme, switch bitand to & * cargo fmt * Update helix-view/src/editor.rs * Switch boolean to enum * Remove bitflag impl * cargo fmt * Remove un-needed type arg * cargo fmt --- helix-term/src/application.rs | 16 +- helix-term/src/commands/typed.rs | 472 ++++++++++++++++++++++++------- helix-term/src/ui/mod.rs | 1 + helix-term/src/ui/picker.rs | 2 +- helix-view/src/editor.rs | 41 ++- helix-view/src/theme.rs | 8 + 6 files changed, 422 insertions(+), 118 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 805f660f6..df14f5e3d 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -108,13 +108,7 @@ impl Application { .ok() .filter(|theme| (true_color || theme.is_16_color())) }) - .unwrap_or_else(|| { - if true_color { - theme_loader.default() - } else { - theme_loader.base16_default() - } - }); + .unwrap_or_else(|| theme_loader.default_theme(true_color)); let syn_loader_conf = user_syntax_loader().unwrap_or_else(|err| { eprintln!("Bad language config: {}", err); @@ -373,13 +367,7 @@ impl Application { }) .ok() .filter(|theme| (true_color || theme.is_16_color())) - .unwrap_or_else(|| { - if true_color { - self.theme_loader.default() - } else { - self.theme_loader.base16_default() - } - }), + .unwrap_or_else(|| self.theme_loader.default_theme(true_color)), ); } diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 70f5fa9fe..4e1ac0da9 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -15,11 +15,11 @@ pub struct TypableCommand { pub completer: Option, } -fn quit( - cx: &mut compositor::Context, - args: &[Cow], - _event: PromptEvent, -) -> anyhow::Result<()> { +fn quit(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(args.is_empty(), ":quit takes no arguments"); // last view and we have unsaved changes @@ -35,8 +35,12 @@ fn quit( fn force_quit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(args.is_empty(), ":quit! takes no arguments"); cx.editor.close(view!(cx.editor).id); @@ -44,11 +48,11 @@ fn force_quit( Ok(()) } -fn open( - cx: &mut compositor::Context, - args: &[Cow], - _event: PromptEvent, -) -> anyhow::Result<()> { +fn open(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(!args.is_empty(), "wrong argument count"); for arg in args { let (path, pos) = args::parse_file(arg); @@ -114,8 +118,12 @@ fn buffer_gather_paths_impl(editor: &mut Editor, args: &[Cow]) -> Vec], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let document_ids = buffer_gather_paths_impl(cx.editor, args); buffer_close_by_ids_impl(cx.editor, &document_ids, false) } @@ -123,8 +131,12 @@ fn buffer_close( fn force_buffer_close( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let document_ids = buffer_gather_paths_impl(cx.editor, args); buffer_close_by_ids_impl(cx.editor, &document_ids, true) } @@ -141,8 +153,12 @@ fn buffer_gather_others_impl(editor: &mut Editor) -> Vec { fn buffer_close_others( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let document_ids = buffer_gather_others_impl(cx.editor); buffer_close_by_ids_impl(cx.editor, &document_ids, false) } @@ -150,8 +166,12 @@ fn buffer_close_others( fn force_buffer_close_others( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let document_ids = buffer_gather_others_impl(cx.editor); buffer_close_by_ids_impl(cx.editor, &document_ids, true) } @@ -163,8 +183,12 @@ fn buffer_gather_all_impl(editor: &mut Editor) -> Vec { fn buffer_close_all( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let document_ids = buffer_gather_all_impl(cx.editor); buffer_close_by_ids_impl(cx.editor, &document_ids, false) } @@ -172,8 +196,12 @@ fn buffer_close_all( fn force_buffer_close_all( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let document_ids = buffer_gather_all_impl(cx.editor); buffer_close_by_ids_impl(cx.editor, &document_ids, true) } @@ -181,8 +209,12 @@ fn force_buffer_close_all( fn buffer_next( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + goto_buffer(cx.editor, Direction::Forward); Ok(()) } @@ -190,8 +222,12 @@ fn buffer_next( fn buffer_previous( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + goto_buffer(cx.editor, Direction::Backward); Ok(()) } @@ -242,24 +278,36 @@ fn write_impl( fn write( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_impl(cx, args.first(), false) } fn force_write( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_impl(cx, args.first(), true) } fn new_file( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor.new_file(Action::Replace); Ok(()) @@ -268,8 +316,12 @@ fn new_file( fn format( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let doc = doc!(cx.editor); if let Some(format) = doc.format() { let callback = @@ -282,8 +334,12 @@ fn format( fn set_indent_style( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + use IndentStyle::*; // If no argument, report current indent style. @@ -321,8 +377,12 @@ fn set_indent_style( fn set_line_ending( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + use LineEnding::*; // If no argument, report current line ending setting. @@ -391,8 +451,12 @@ fn set_line_ending( fn earlier( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let uk = args.join(" ").parse::().map_err(|s| anyhow!(s))?; let (view, doc) = current!(cx.editor); @@ -407,8 +471,12 @@ fn earlier( fn later( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let uk = args.join(" ").parse::().map_err(|s| anyhow!(s))?; let (view, doc) = current!(cx.editor); let success = doc.later(view.id, uk); @@ -424,6 +492,10 @@ fn write_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_impl(cx, args.first(), false)?; helix_lsp::block_on(cx.jobs.finish())?; quit(cx, &[], event) @@ -434,6 +506,10 @@ fn force_write_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_impl(cx, args.first(), true)?; force_quit(cx, &[], event) } @@ -463,10 +539,14 @@ pub(super) fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()> fn write_all_impl( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, quit: bool, force: bool, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let mut errors = String::new(); let auto_format = cx.editor.config().auto_format; let jobs = &mut cx.jobs; @@ -520,6 +600,10 @@ fn write_all( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_all_impl(cx, args, event, false, false) } @@ -528,6 +612,10 @@ fn write_all_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_all_impl(cx, args, event, true, false) } @@ -536,6 +624,10 @@ fn force_write_all_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_all_impl(cx, args, event, true, true) } @@ -556,24 +648,36 @@ fn quit_all_impl(editor: &mut Editor, force: bool) -> anyhow::Result<()> { fn quit_all( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + quit_all_impl(cx.editor, false) } fn force_quit_all( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + quit_all_impl(cx.editor, true) } fn cquit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let exit_code = args .first() .and_then(|code| code.parse::().ok()) @@ -586,8 +690,12 @@ fn cquit( fn force_cquit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let exit_code = args .first() .and_then(|code| code.parse::().ok()) @@ -600,35 +708,61 @@ fn force_cquit( fn theme( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, -) -> anyhow::Result<()> { - let theme = args.first().context("Theme not provided")?; - let theme = cx - .editor - .theme_loader - .load(theme) - .with_context(|| format!("Failed setting theme {}", theme))?; - let true_color = cx.editor.config().true_color || crate::true_color(); - if !(true_color || theme.is_16_color()) { - bail!("Unsupported theme: theme requires true color support"); - } - cx.editor.set_theme(theme); + event: PromptEvent, +) -> anyhow::Result<()> { + let true_color = cx.editor.config.load().true_color || crate::true_color(); + match event { + PromptEvent::Abort => { + cx.editor.unset_theme_preview(); + } + PromptEvent::Update => { + if let Some(theme_name) = args.first() { + if let Ok(theme) = cx.editor.theme_loader.load(theme_name) { + if !(true_color || theme.is_16_color()) { + bail!("Unsupported theme: theme requires true color support"); + } + cx.editor.set_theme_preview(theme); + }; + }; + } + PromptEvent::Validate => { + let theme_name = args.first().with_context(|| "Theme name not provided")?; + let theme = cx + .editor + .theme_loader + .load(theme_name) + .with_context(|| "Theme does not exist")?; + if !(true_color || theme.is_16_color()) { + bail!("Unsupported theme: theme requires true color support"); + } + cx.editor.set_theme(theme); + } + }; + Ok(()) } fn yank_main_selection_to_clipboard( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Clipboard) } fn yank_joined_to_clipboard( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let doc = doc!(cx.editor); let default_sep = Cow::Borrowed(doc.line_ending.as_str()); let separator = args.first().unwrap_or(&default_sep); @@ -638,16 +772,24 @@ fn yank_joined_to_clipboard( fn yank_main_selection_to_primary_clipboard( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Selection) } fn yank_joined_to_primary_clipboard( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let doc = doc!(cx.editor); let default_sep = Cow::Borrowed(doc.line_ending.as_str()); let separator = args.first().unwrap_or(&default_sep); @@ -657,32 +799,48 @@ fn yank_joined_to_primary_clipboard( fn paste_clipboard_after( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Clipboard, 1) } fn paste_clipboard_before( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Clipboard, 1) } fn paste_primary_clipboard_after( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Selection, 1) } fn paste_primary_clipboard_before( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Selection, 1) } @@ -710,24 +868,36 @@ fn replace_selections_with_clipboard_impl( fn replace_selections_with_clipboard( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + replace_selections_with_clipboard_impl(cx, ClipboardType::Clipboard) } fn replace_selections_with_primary_clipboard( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + replace_selections_with_clipboard_impl(cx, ClipboardType::Selection) } fn show_clipboard_provider( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor .set_status(cx.editor.clipboard_provider.name().to_string()); Ok(()) @@ -736,8 +906,12 @@ fn show_clipboard_provider( fn change_current_directory( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let dir = helix_core::path::expand_tilde( args.first() .context("target directory not provided")? @@ -760,8 +934,12 @@ fn change_current_directory( fn show_current_directory( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let cwd = std::env::current_dir().context("Couldn't get the new working directory")?; cx.editor .set_status(format!("Current working directory is {}", cwd.display())); @@ -772,8 +950,12 @@ fn show_current_directory( fn set_encoding( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let doc = doc_mut!(cx.editor); if let Some(label) = args.first() { doc.set_encoding(label) @@ -788,8 +970,12 @@ fn set_encoding( fn reload( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let scrolloff = cx.editor.config().scrolloff; let (view, doc) = current!(cx.editor); doc.reload(view.id).map(|_| { @@ -800,8 +986,12 @@ fn reload( fn tree_sitter_scopes( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); @@ -814,8 +1004,12 @@ fn tree_sitter_scopes( fn vsplit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let id = view!(cx.editor).doc; if args.is_empty() { @@ -833,8 +1027,12 @@ fn vsplit( fn hsplit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let id = view!(cx.editor).doc; if args.is_empty() { @@ -852,8 +1050,12 @@ fn hsplit( fn vsplit_new( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor.new_file(Action::VerticalSplit); Ok(()) @@ -862,8 +1064,12 @@ fn vsplit_new( fn hsplit_new( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor.new_file(Action::HorizontalSplit); Ok(()) @@ -872,8 +1078,12 @@ fn hsplit_new( fn debug_eval( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + if let Some(debugger) = cx.editor.debugger.as_mut() { let (frame, thread_id) = match (debugger.active_frame, debugger.thread_id) { (Some(frame), Some(thread_id)) => (frame, thread_id), @@ -894,8 +1104,12 @@ fn debug_eval( fn debug_start( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let mut args = args.to_owned(); let name = match args.len() { 0 => None, @@ -907,8 +1121,12 @@ fn debug_start( fn debug_remote( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let mut args = args.to_owned(); let address = match args.len() { 0 => None, @@ -924,8 +1142,12 @@ fn debug_remote( fn tutor( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let path = helix_loader::runtime_dir().join("tutor.txt"); cx.editor.open(&path, Action::Replace)?; // Unset path to prevent accidentally saving to the original tutor file. @@ -936,8 +1158,12 @@ fn tutor( pub(super) fn goto_line_number( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(!args.is_empty(), "Line number required"); let line = args[0].parse::()?; @@ -954,8 +1180,12 @@ pub(super) fn goto_line_number( fn get_option( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + if args.len() != 1 { anyhow::bail!("Bad arguments. Usage: `:get key`"); } @@ -976,8 +1206,12 @@ fn get_option( fn set_option( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + if args.len() != 2 { anyhow::bail!("Bad arguments. Usage: `:set key field`"); } @@ -1009,8 +1243,12 @@ fn set_option( fn language( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + if args.len() != 1 { anyhow::bail!("Bad arguments. Usage: `:set-language language`"); } @@ -1023,19 +1261,23 @@ fn language( Ok(()) } -fn sort( - cx: &mut compositor::Context, - args: &[Cow], - _event: PromptEvent, -) -> anyhow::Result<()> { +fn sort(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + sort_impl(cx, args, false) } fn sort_reverse( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + sort_impl(cx, args, true) } @@ -1076,8 +1318,12 @@ fn sort_impl( fn reflow( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let (view, doc) = current!(cx.editor); const DEFAULT_MAX_LEN: usize = 79; @@ -1115,8 +1361,12 @@ fn reflow( fn tree_sitter_subtree( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let (view, doc) = current!(cx.editor); if let Some(syntax) = doc.syntax() { @@ -1151,8 +1401,12 @@ fn tree_sitter_subtree( fn open_config( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor .open(&helix_loader::config_file(), Action::Replace)?; Ok(()) @@ -1161,8 +1415,12 @@ fn open_config( fn open_log( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor.open(&helix_loader::log_file(), Action::Replace)?; Ok(()) } @@ -1170,8 +1428,12 @@ fn open_log( fn refresh_config( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor.config_events.0.send(ConfigEvent::Refresh)?; Ok(()) } @@ -1179,8 +1441,12 @@ fn refresh_config( fn append_output( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(!args.is_empty(), "Shell command required"); shell(cx, &args.join(" "), &ShellBehavior::Append); Ok(()) @@ -1189,18 +1455,22 @@ fn append_output( fn insert_output( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(!args.is_empty(), "Shell command required"); shell(cx, &args.join(" "), &ShellBehavior::Insert); Ok(()) } -fn pipe( - cx: &mut compositor::Context, - args: &[Cow], - _event: PromptEvent, -) -> anyhow::Result<()> { +fn pipe(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(!args.is_empty(), "Shell command required"); shell(cx, &args.join(" "), &ShellBehavior::Replace); Ok(()) @@ -1209,8 +1479,12 @@ fn pipe( fn run_shell_command( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let shell = &cx.editor.config().shell; let (output, success) = shell_impl(shell, &args.join(" "), None)?; if success { @@ -1270,14 +1544,14 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ aliases: &["bc", "bclose"], doc: "Close the current buffer.", fun: buffer_close, - completer: Some(completers::buffer), + completer: Some(completers::buffer), }, TypableCommand { name: "buffer-close!", aliases: &["bc!", "bclose!"], doc: "Close the current buffer forcefully (ignoring unsaved changes).", fun: force_buffer_close, - completer: Some(completers::buffer), + completer: Some(completers::buffer), }, TypableCommand { name: "buffer-close-others", @@ -1561,7 +1835,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Display tree sitter scopes, primarily for theming and development.", fun: tree_sitter_scopes, completer: None, - }, + }, TypableCommand { name: "debug-start", aliases: &["dbg"], @@ -1787,10 +2061,6 @@ pub fn command_mode(cx: &mut Context) { } }, // completion move |cx: &mut compositor::Context, input: &str, event: PromptEvent| { - if event != PromptEvent::Validate { - return; - } - let parts = input.split_whitespace().collect::>(); if parts.is_empty() { return; @@ -1811,10 +2081,10 @@ pub fn command_mode(cx: &mut Context) { if let Err(e) = (cmd.fun)(cx, &args[1..], event) { cx.editor.set_error(format!("{}", e)); } - } else { + } else if event == PromptEvent::Validate { cx.editor .set_error(format!("no such command: '{}'", parts[0])); - }; + } }, ); prompt.doc_fn = Box::new(|input: &str| { diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 8d2bd3251..ca4cedb55 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -237,6 +237,7 @@ pub mod completers { )); names.push("default".into()); names.push("base16_default".into()); + names.sort(); let mut names: Vec<_> = names .into_iter() diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index f4dd234a4..375723e56 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -490,7 +490,7 @@ impl Component for Picker { _ => return EventResult::Ignored(None), }; - let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _| { + let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _cx| { // remove the layer compositor.last_picker = compositor.pop(); }))); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 1ed27e996..a2943af98 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -464,7 +464,6 @@ pub struct Editor { pub registers: Registers, pub macro_recording: Option<(char, Vec)>, pub macro_replaying: Vec, - pub theme: Theme, pub language_servers: helix_lsp::Registry, pub diagnostics: BTreeMap>, @@ -476,6 +475,12 @@ pub struct Editor { pub syn_loader: Arc, pub theme_loader: Arc, + /// last_theme is used for theme previews. We store the current theme here, + /// and if previewing is cancelled, we can return to it. + pub last_theme: Option, + /// The currently applied editor theme. While previewing a theme, the previewed theme + /// is set here. + pub theme: Theme, pub status_msg: Option<(Cow<'static, str>, Severity)>, pub autoinfo: Option, @@ -500,6 +505,11 @@ pub enum ConfigEvent { Update(Box), } +enum ThemeAction { + Set, + Preview, +} + #[derive(Debug, Clone)] pub struct CompleteAction { pub trigger_offset: usize, @@ -544,6 +554,7 @@ impl Editor { breakpoints: HashMap::new(), syn_loader, theme_loader, + last_theme: None, registers: Registers::default(), clipboard_provider: get_clipboard_provider(), status_msg: None, @@ -613,7 +624,22 @@ impl Editor { .unwrap_or(false) } + pub fn unset_theme_preview(&mut self) { + if let Some(last_theme) = self.last_theme.take() { + self.set_theme(last_theme); + } + // None likely occurs when the user types ":theme" and then exits before previewing + } + + pub fn set_theme_preview(&mut self, theme: Theme) { + self.set_theme_impl(theme, ThemeAction::Preview); + } + pub fn set_theme(&mut self, theme: Theme) { + self.set_theme_impl(theme, ThemeAction::Set); + } + + fn set_theme_impl(&mut self, theme: Theme, preview: ThemeAction) { // `ui.selection` is the only scope required to be able to render a theme. if theme.find_scope_index("ui.selection").is_none() { self.set_error("Invalid theme: `ui.selection` required"); @@ -623,7 +649,18 @@ impl Editor { let scopes = theme.scopes(); self.syn_loader.set_scopes(scopes.to_vec()); - self.theme = theme; + match preview { + ThemeAction::Preview => { + let last_theme = std::mem::replace(&mut self.theme, theme); + // only insert on first preview: this will be the last theme the user has saved + self.last_theme.get_or_insert(last_theme); + } + ThemeAction::Set => { + self.last_theme = None; + self.theme = theme; + } + } + self._refresh(); } diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 3f45aac6e..fa5fa7028 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -77,6 +77,14 @@ impl Loader { names } + pub fn default_theme(&self, true_color: bool) -> Theme { + if true_color { + self.default() + } else { + self.base16_default() + } + } + /// Returns the default theme pub fn default(&self) -> Theme { DEFAULT_THEME.clone() From d78354c537e00ddb0976efad1df49c90a224f107 Mon Sep 17 00:00:00 2001 From: Matthew Toohey Date: Tue, 5 Jul 2022 07:00:38 -0400 Subject: [PATCH 467/861] add language `idris` (#2971) --- book/src/generated/lang-support.md | 1 + languages.toml | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 3c56a6f40..85e42b159 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -40,6 +40,7 @@ | hcl | ✓ | | ✓ | `terraform-ls` | | heex | ✓ | | | | | html | ✓ | | | `vscode-html-language-server` | +| idris | | | | `idris2-lsp` | | iex | ✓ | | | | | java | ✓ | | | `jdtls` | | javascript | ✓ | | ✓ | `typescript-language-server` | diff --git a/languages.toml b/languages.toml index 7c63c051a..9da454a08 100644 --- a/languages.toml +++ b/languages.toml @@ -1503,3 +1503,14 @@ grammar = "elvish" [[grammar]] name = "elvish" source = { git = "https://github.com/ckafi/tree-sitter-elvish", rev = "e50787cadd3bc54f6d9c0704493a79078bb8a4e5" } + +[[language]] +name = "idris" +scope = "source.idr" +injection-regex = "idr" +file-types = ["idr"] +shebangs = [] +roots = [] +comment-token = "--" +indent = { tab-width = 2, unit = " " } +language-server = { command = "idris2-lsp" } From aacd0c8aa542ac0316569ae062966362222ff4bf Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 5 Jul 2022 06:01:05 -0500 Subject: [PATCH 468/861] Update TSQ queries (#2960) A few changes to make TSQ highlights better: * A parsing error has been fixed in the grammar itself * Previously tree-sitter-tsq did not parse the variables in predicates like `(#set! injection.language "javascript")` * Theme nodes as `tag` * The newly added node to the parser (from the above fix) is `variable` which takes over the `variable` capture from nodes * Highlight known predicates as `function` and unsupported predicates as `error` * This may help when translating queries from nvim-treesitter. For example `#any-of?` is a common one used in nvim-treesitter queries but not implemented in Helix or tree-sitter-cli. * Inject tree-sitter-regex into `#match?` predicates --- languages.toml | 2 +- runtime/queries/tsq/highlights.scm | 9 ++++++--- runtime/queries/tsq/injections.scm | 6 ++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/languages.toml b/languages.toml index 9da454a08..f8b2d579d 100644 --- a/languages.toml +++ b/languages.toml @@ -707,7 +707,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "tsq" -source = { git = "https://github.com/the-mikedavis/tree-sitter-tsq", rev = "ea68fc2b571ca1c8f70936855130c380f518ff35" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-tsq", rev = "48b5e9f82ae0a4727201626f33a17f69f8e0ff86" } [[language]] name = "cmake" diff --git a/runtime/queries/tsq/highlights.scm b/runtime/queries/tsq/highlights.scm index fd5917fb1..c655b994f 100644 --- a/runtime/queries/tsq/highlights.scm +++ b/runtime/queries/tsq/highlights.scm @@ -6,7 +6,7 @@ ; highlight inheritance comments ((query . (comment) @keyword.directive) - (#match? @keyword.directive "^;\ +inherits *:")) + (#match? @keyword.directive "^; +inherits *:")) [ "(" @@ -40,8 +40,11 @@ (capture) @label -(predicate_name) @function +((predicate_name) @function + (#match? @function "^#(eq\\?|match\\?|is\\?|is-not\\?|not-same-line\\?|not-kind-eq\\?|set!|select-adjacent!|strip!)$")) +(predicate_name) @error (escape_sequence) @constant.character.escape -(node_name) @variable +(node_name) @tag +(variable) @variable diff --git a/runtime/queries/tsq/injections.scm b/runtime/queries/tsq/injections.scm index 321c90add..644045570 100644 --- a/runtime/queries/tsq/injections.scm +++ b/runtime/queries/tsq/injections.scm @@ -1,2 +1,8 @@ ((comment) @injection.content (#set! injection.language "comment")) + +((predicate + (predicate_name) @_predicate + (string) @injection.content) + (#eq? @_predicate "#match?") + (#set! injection.language "regex")) From b61221107068160c241858a530f6fa4144566122 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 5 Jul 2022 22:12:28 +0800 Subject: [PATCH 469/861] Update tree-sitter-ledger (#2936) --- languages.toml | 2 +- runtime/queries/ledger/highlights.scm | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index f8b2d579d..d7462bb8c 100644 --- a/languages.toml +++ b/languages.toml @@ -570,7 +570,7 @@ indent = { tab-width = 4, unit = " " } [[grammar]] name = "ledger" -source = { git = "https://github.com/cbarrete/tree-sitter-ledger", rev = "0cdeb0e51411a3ba5493662952c3039de08939ca" } +source = { git = "https://github.com/cbarrete/tree-sitter-ledger", rev = "1f864fb2bf6a87fe1b48545cc6adc6d23090adf7" } [[language]] name = "ocaml" diff --git a/runtime/queries/ledger/highlights.scm b/runtime/queries/ledger/highlights.scm index 02a9ea9a7..301076c79 100644 --- a/runtime/queries/ledger/highlights.scm +++ b/runtime/queries/ledger/highlights.scm @@ -11,6 +11,7 @@ ((account) @variable.other.member) ((commodity) @text.literal) +((tag) @tag) "include" @keyword.local.import From 1378b911b63f4fdab7beba77de6d54f1dd070553 Mon Sep 17 00:00:00 2001 From: A-Walrus <58790821+A-Walrus@users.noreply.github.com> Date: Wed, 6 Jul 2022 05:49:54 +0300 Subject: [PATCH 470/861] Fix some typos (#2978) --- book/src/keymap.md | 4 ++-- docs/architecture.md | 2 +- helix-core/src/indent.rs | 2 +- helix-term/src/ui/markdown.rs | 2 +- runtime/queries/elm/highlights.scm | 2 +- runtime/queries/git-commit/highlights.scm | 2 +- runtime/queries/kotlin/highlights.scm | 2 +- runtime/queries/lean/highlights.scm | 2 +- runtime/queries/make/highlights.scm | 2 +- runtime/queries/solidity/highlights.scm | 6 +++--- runtime/queries/verilog/highlights.scm | 2 +- runtime/queries/verilog/textobjects.scm | 2 +- runtime/themes/nord.toml | 2 +- runtime/themes/pop-dark.toml | 2 +- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index b979cfd89..5daeec3fa 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -241,8 +241,8 @@ This layer is a kludge of mappings, mostly pickers. | `k` | Show documentation for item under cursor in a [popup](#popup) (**LSP**) | `hover` | | `s` | Open document symbol picker (**LSP**) | `symbol_picker` | | `S` | Open workspace symbol picker (**LSP**) | `workspace_symbol_picker` | -| `g` | Open document diagnosics picker (**LSP**) | `diagnostics_picker` | -| `G` | Open workspace diagnostics picker (**LSP**) | `workspace_diagnosics_picker` +| `g` | Open document diagnostics picker (**LSP**) | `diagnostics_picker` | +| `G` | Open workspace diagnostics picker (**LSP**) | `workspace_diagnostics_picker` | `r` | Rename symbol (**LSP**) | `rename_symbol` | | `a` | Apply code action (**LSP**) | `code_action` | | `'` | Open last fuzzy picker | `last_picker` | diff --git a/docs/architecture.md b/docs/architecture.md index 74f973b0d..5d33cbac0 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -32,7 +32,7 @@ represented by a `Selection`. Each `Range` in the selection consists of a moving a selection with a single range, with the head and the anchor in the same position. -Ropes are modified by constructing an OT-like `Transaction`. It's represents +Ropes are modified by constructing an OT-like `Transaction`. It represents a single coherent change to the document and can be applied to the rope. A transaction can be inverted to produce an undo. Selections and marks can be mapped over a transaction to translate to a position in the new text state after diff --git a/helix-core/src/indent.rs b/helix-core/src/indent.rs index 529139b81..137b8822d 100644 --- a/helix-core/src/indent.rs +++ b/helix-core/src/indent.rs @@ -453,7 +453,7 @@ fn query_indents( /// /// ```ignore /// some_function( -/// parm1, +/// param1, /// || { /// // Here we get 2 indent levels because the 'parameters' and the 'block' node begin on different lines /// }, diff --git a/helix-term/src/ui/markdown.rs b/helix-term/src/ui/markdown.rs index e3ce2cd5d..a5c78c41d 100644 --- a/helix-term/src/ui/markdown.rs +++ b/helix-term/src/ui/markdown.rs @@ -204,7 +204,7 @@ impl Markdown { tags.push(Tag::Item); - // get the approriate bullet for the current list + // get the appropriate bullet for the current list let bullet = list_stack .last() .unwrap_or(&None) // use the '- ' bullet in case the list stack would be empty diff --git a/runtime/queries/elm/highlights.scm b/runtime/queries/elm/highlights.scm index 3c8fd12d8..d02b3a5c6 100644 --- a/runtime/queries/elm/highlights.scm +++ b/runtime/queries/elm/highlights.scm @@ -49,7 +49,7 @@ ] @keyword -(import) @keyword.contol.import +(import) @keyword.control.import (module) @keyword.other (number_constant_expr) @constant.numeric diff --git a/runtime/queries/git-commit/highlights.scm b/runtime/queries/git-commit/highlights.scm index bdb776d6d..20f58ee57 100644 --- a/runtime/queries/git-commit/highlights.scm +++ b/runtime/queries/git-commit/highlights.scm @@ -10,5 +10,5 @@ (change kind: "modified" @diff.delta) (change kind: "renamed" @diff.delta.moved) -[":" "->" (scissors)] @punctuation.delimeter +[":" "->" (scissors)] @punctuation.delimiter (comment) @comment diff --git a/runtime/queries/kotlin/highlights.scm b/runtime/queries/kotlin/highlights.scm index 7b90fcf92..208a673f3 100644 --- a/runtime/queries/kotlin/highlights.scm +++ b/runtime/queries/kotlin/highlights.scm @@ -217,7 +217,7 @@ (function_declaration . (simple_identifier) @function) -; TODO: Seperate labeled returns/breaks/continue/super/this +; TODO: Separate labeled returns/breaks/continue/super/this ; Must be implemented in the parser first (label) @label diff --git a/runtime/queries/lean/highlights.scm b/runtime/queries/lean/highlights.scm index a64feb1d3..ca19b8353 100644 --- a/runtime/queries/lean/highlights.scm +++ b/runtime/queries/lean/highlights.scm @@ -197,7 +197,7 @@ (interpolated_string) @string ; (escape_sequence) @string.escape -; Reset highlighing in string interpolation +; Reset highlighting in string interpolation (interpolation) @none (interpolation diff --git a/runtime/queries/make/highlights.scm b/runtime/queries/make/highlights.scm index 50380bafa..5aef8e0f6 100644 --- a/runtime/queries/make/highlights.scm +++ b/runtime/queries/make/highlights.scm @@ -155,7 +155,7 @@ (word) @clean @constant.builtin (#match? @clean "^(AR|AS|CC|CXX|CPP|FC|M2C|PC|CO|GET|LEX|YACC|LINT|MAKEINFO|TEX|TEXI2DVI|WEAVE|CWEAVE|TANGLE|CTANGLE|RM|ARFLAGS|ASFLAGS|CFLAGS|CXXFLAGS|COFLAGS|CPPFLAGS|FFLAGS|GFLAGS|LDFLAGS|LDLIBS|LFLAGS|YFLAGS|PFLAGS|RFLAGS|LINTFLAGS|PRE_INSTALL|POST_INSTALL|NORMAL_INSTALL|PRE_UNINSTALL|POST_UNINSTALL|NORMAL_UNINSTALL|MAKEFILE_LIST|MAKE_RESTARTS|MAKE_TERMOUT|MAKE_TERMERR|\.DEFAULT_GOAL|\.RECIPEPREFIX|\.EXTRA_PREREQS\.VARIABLES|\.FEATURES|\.INCLUDE_DIRS|\.LOADED)$")) -;; Standart targets +;; Standard targets (targets (word) @constant.macro (#match? @constant.macro "^(all|install|install-html|install-dvi|install-pdf|install-ps|uninstall|install-strip|clean|distclean|mostlyclean|maintainer-clean|TAGS|info|dvi|html|pdf|ps|dist|check|installcheck|installdirs)$")) diff --git a/runtime/queries/solidity/highlights.scm b/runtime/queries/solidity/highlights.scm index 61c89ac8a..544cf3d94 100644 --- a/runtime/queries/solidity/highlights.scm +++ b/runtime/queries/solidity/highlights.scm @@ -50,7 +50,7 @@ name: (identifier) @function) (yul_evm_builtin) @function.builtin -; Use contructor coloring for special functions +; Use constructor coloring for special functions (constructor_definition "constructor" @constructor) (fallback_receive_definition "receive" @constructor) (fallback_receive_definition "fallback" @constructor) @@ -64,7 +64,7 @@ (call_expression . (identifier) @function) ; Function parameters -(event_paramater name: (identifier) @variable.parameter) +(event_paramater name: (identifier) @variable.parameter) ; TODO fix spelling once fixed upstream (function_definition function_name: (identifier) @variable.parameter) @@ -131,7 +131,7 @@ (import_directive "as" @keyword) (import_directive "from" @keyword) -(event_paramater "indexed" @keyword) +(event_paramater "indexed" @keyword) ; TODO fix spelling once fixed upstream ; Punctuation diff --git a/runtime/queries/verilog/highlights.scm b/runtime/queries/verilog/highlights.scm index 97ec06e3a..a194ac33b 100644 --- a/runtime/queries/verilog/highlights.scm +++ b/runtime/queries/verilog/highlights.scm @@ -1,7 +1,7 @@ ; Keywords [ - ; block delimeters + ; block delimiters (module_keyword) "endmodule" "program" diff --git a/runtime/queries/verilog/textobjects.scm b/runtime/queries/verilog/textobjects.scm index 3b1c0fe50..f940832ab 100644 --- a/runtime/queries/verilog/textobjects.scm +++ b/runtime/queries/verilog/textobjects.scm @@ -3,4 +3,4 @@ (function_body_declaration (function_identifier (function_identifier - (simple_identifier) @function.inside)))) @funtions.around \ No newline at end of file + (simple_identifier) @function.inside)))) @function.around \ No newline at end of file diff --git a/runtime/themes/nord.toml b/runtime/themes/nord.toml index f7ef079b0..11195ece3 100644 --- a/runtime/themes/nord.toml +++ b/runtime/themes/nord.toml @@ -41,7 +41,7 @@ "constant.builtin" = "nord4" "namespace" = "nord4" -# nord5 - suble UI text +# nord5 - subtle UI text # nord6 - base text, punctuation "ui.text" = { fg = "nord6" } diff --git a/runtime/themes/pop-dark.toml b/runtime/themes/pop-dark.toml index e662f9575..172e8391a 100644 --- a/runtime/themes/pop-dark.toml +++ b/runtime/themes/pop-dark.toml @@ -71,7 +71,7 @@ namespace = { fg = 'orangeL' } 'variable.other.member' = { fg = 'orangeH' } 'variable.function' = { fg = 'blueL' } 'punctuation' = { fg = 'blueL' } -'punctuation.delimeter' = { fg = 'blueH' } +'punctuation.delimiter' = { fg = 'blueH' } 'punctuation.bracket' = { fg = 'orangeN' } 'keyword' = { fg = 'blueH' } 'keyword.control' = { fg = 'blueL' } From e0cf19c61205ff3589fe60550e64d4102d6a2dc5 Mon Sep 17 00:00:00 2001 From: Erin van der Veen Date: Wed, 6 Jul 2022 13:05:51 +0200 Subject: [PATCH 471/861] Update tree-sitter-nickel (#2987) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index d7462bb8c..56abf3f8a 100644 --- a/languages.toml +++ b/languages.toml @@ -425,7 +425,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "nickel" -source = { git = "https://github.com/nickel-lang/tree-sitter-nickel", rev = "9a502ea2e774df3d743a48310bb40e1cc097c86e" } +source = { git = "https://github.com/nickel-lang/tree-sitter-nickel", rev = "9d83db400b6c11260b9106f131f93ddda8131933" } [[language]] name = "nix" From c4e022971df6179647206592b6d7e452c12161d0 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Tue, 5 Jul 2022 09:05:11 +0530 Subject: [PATCH 472/861] Remove source from diagnostic picker display It is usually the name of the LSP and doesn't add much useful information. --- helix-term/src/commands/lsp.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 7f82394ac..2378ef16f 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -132,11 +132,6 @@ impl ui::menu::Item for PickerDiagnostic { .into_owned(); Spans::from(vec![ - Span::styled( - self.diag.source.clone().unwrap_or_default(), - style.add_modifier(Modifier::BOLD), - ), - Span::raw(": "), Span::styled(truncated_path, style), Span::raw(" - "), Span::styled(code, style.add_modifier(Modifier::BOLD)), From 2c37e25cb552f1b64ad6815bb03c40d6d5aacb24 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Tue, 5 Jul 2022 09:16:47 +0530 Subject: [PATCH 473/861] Display diagnostic text before code in picker --- helix-term/src/commands/lsp.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 2378ef16f..81e16b22f 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -132,11 +132,12 @@ impl ui::menu::Item for PickerDiagnostic { .into_owned(); Spans::from(vec![ - Span::styled(truncated_path, style), - Span::raw(" - "), - Span::styled(code, style.add_modifier(Modifier::BOLD)), + Span::raw(truncated_path), Span::raw(": "), Span::styled(&self.diag.message, style), + Span::raw(" ("), + Span::styled(code, style.add_modifier(Modifier::BOLD)), + Span::raw(")"), ]) } } From 0c104685c024a03cd857c0adcedea55b694eb604 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Tue, 5 Jul 2022 17:42:14 +0530 Subject: [PATCH 474/861] Sub sort diagnostics by line number --- helix-term/src/application.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index df14f5e3d..d3899075c 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -572,15 +572,11 @@ impl Application { doc.set_diagnostics(diagnostics); } - // Sort diagnostics first by URL and then by severity. + // Sort diagnostics first by severity and then by line numbers. // Note: The `lsp::DiagnosticSeverity` enum is already defined in decreasing order - params.diagnostics.sort_unstable_by(|a, b| { - if let (Some(a), Some(b)) = (a.severity, b.severity) { - a.partial_cmp(&b).unwrap() - } else { - std::cmp::Ordering::Equal - } - }); + params + .diagnostics + .sort_unstable_by_key(|d| (d.severity, d.range.start)); // Insert the original lsp::Diagnostics here because we may have no open document // for diagnosic message and so we can't calculate the exact position. From a43bcc876568b87f0e326612f5385d8c4922cb14 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Tue, 5 Jul 2022 17:54:57 +0530 Subject: [PATCH 475/861] Display error code only if not none --- helix-term/src/commands/lsp.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 81e16b22f..a73148cc3 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -125,6 +125,7 @@ impl ui::menu::Item for PickerDiagnostic { NumberOrString::Number(n) => n.to_string(), NumberOrString::String(s) => s.to_string(), }) + .map(|code| format!(" ({})", code)) .unwrap_or_default(); let truncated_path = path::get_truncated_path(self.url.path()) @@ -135,9 +136,7 @@ impl ui::menu::Item for PickerDiagnostic { Span::raw(truncated_path), Span::raw(": "), Span::styled(&self.diag.message, style), - Span::raw(" ("), - Span::styled(code, style.add_modifier(Modifier::BOLD)), - Span::raw(")"), + Span::styled(code, style), ]) } } From af35c624070e3db5746c35601e98f346d91df280 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Tue, 5 Jul 2022 18:31:25 +0530 Subject: [PATCH 476/861] Show file path only in workspace diagnostic picker --- helix-term/src/commands/lsp.rs | 42 +++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index a73148cc3..630c47e13 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -9,10 +9,7 @@ use tui::text::{Span, Spans}; use super::{align_view, push_jump, Align, Context, Editor}; use helix_core::{path, Selection}; -use helix_view::{ - editor::Action, - theme::{Modifier, Style}, -}; +use helix_view::{editor::Action, theme::Style}; use crate::{ compositor::{self, Compositor}, @@ -99,9 +96,9 @@ struct PickerDiagnostic { } impl ui::menu::Item for PickerDiagnostic { - type Data = DiagnosticStyles; + type Data = (DiagnosticStyles, DiagnosticsFormat); - fn label(&self, styles: &Self::Data) -> Spans { + fn label(&self, (styles, format): &Self::Data) -> Spans { let mut style = self .diag .severity @@ -128,13 +125,18 @@ impl ui::menu::Item for PickerDiagnostic { .map(|code| format!(" ({})", code)) .unwrap_or_default(); - let truncated_path = path::get_truncated_path(self.url.path()) - .to_string_lossy() - .into_owned(); + let path = match format { + DiagnosticsFormat::HideSourcePath => String::new(), + DiagnosticsFormat::ShowSourcePath => { + let path = path::get_truncated_path(self.url.path()) + .to_string_lossy() + .into_owned(); + format!("{}: ", path) + } + }; Spans::from(vec![ - Span::raw(truncated_path), - Span::raw(": "), + Span::raw(path), Span::styled(&self.diag.message, style), Span::styled(code, style), ]) @@ -237,10 +239,17 @@ fn sym_picker( .truncate_start(false) } +#[derive(Copy, Clone, PartialEq)] +enum DiagnosticsFormat { + ShowSourcePath, + HideSourcePath, +} + fn diag_picker( cx: &Context, diagnostics: BTreeMap>, current_path: Option, + format: DiagnosticsFormat, offset_encoding: OffsetEncoding, ) -> FilePicker { // TODO: drop current_path comparison and instead use workspace: bool flag? @@ -266,7 +275,7 @@ fn diag_picker( FilePicker::new( flat_diag, - styles, + (styles, format), move |cx, PickerDiagnostic { url, diag }, action| { if current_path.as_ref() == Some(url) { let (view, doc) = current!(cx.editor); @@ -378,6 +387,7 @@ pub fn diagnostics_picker(cx: &mut Context) { cx, [(current_url.clone(), diagnostics)].into(), Some(current_url), + DiagnosticsFormat::HideSourcePath, offset_encoding, ); cx.push_layer(Box::new(overlayed(picker))); @@ -390,7 +400,13 @@ pub fn workspace_diagnostics_picker(cx: &mut Context) { let current_url = doc.url(); let offset_encoding = language_server.offset_encoding(); let diagnostics = cx.editor.diagnostics.clone(); - let picker = diag_picker(cx, diagnostics, current_url, offset_encoding); + let picker = diag_picker( + cx, + diagnostics, + current_url, + DiagnosticsFormat::ShowSourcePath, + offset_encoding, + ); cx.push_layer(Box::new(overlayed(picker))); } From e35abe38f31149785ea04dc8a8fc1d2649ba70af Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Wed, 6 Jul 2022 20:35:36 +0800 Subject: [PATCH 477/861] Remove broken ledger tag highlight (#2988) --- runtime/queries/ledger/highlights.scm | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime/queries/ledger/highlights.scm b/runtime/queries/ledger/highlights.scm index 301076c79..02a9ea9a7 100644 --- a/runtime/queries/ledger/highlights.scm +++ b/runtime/queries/ledger/highlights.scm @@ -11,7 +11,6 @@ ((account) @variable.other.member) ((commodity) @text.literal) -((tag) @tag) "include" @keyword.local.import From 230ba264bf78d9b4ecd42440f0cbb20529f9c235 Mon Sep 17 00:00:00 2001 From: Jake Langford Date: Wed, 6 Jul 2022 13:54:07 +0000 Subject: [PATCH 478/861] Introduce storage highlighting for typescript/javascript (#2961) --- book/src/themes.md | 4 +++- runtime/queries/javascript/highlights.scm | 19 +++++++++++++------ runtime/queries/typescript/highlights.scm | 16 +++++++++++----- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/book/src/themes.md b/book/src/themes.md index 06f920d3c..ad8864b20 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -151,7 +151,9 @@ We use a similar set of scopes as - `operator` - `or`, `in` - `directive` - Preprocessor directives (`#if` in C) - `function` - `fn`, `func` - - `storage` - Keywords that affect the storage of a variable, function or data structure `static`, `mut`, `const`, `ref` + - `storage` - Keywords describing how things are stored + - `type` - The type of something, `class`, `function`, `var`, `let`, etc. + - `modifier` - Storage modifiers like `static`, `mut`, `const`, `ref`, etc. - `operator` - `||`, `+=`, `>` diff --git a/runtime/queries/javascript/highlights.scm b/runtime/queries/javascript/highlights.scm index 2616dffa1..9a759081a 100644 --- a/runtime/queries/javascript/highlights.scm +++ b/runtime/queries/javascript/highlights.scm @@ -163,19 +163,14 @@ [ "as" "async" - "class" - "const" "debugger" "delete" - "export" "extends" "from" "function" "get" - "import" "in" "instanceof" - "let" "new" "of" "set" @@ -183,11 +178,17 @@ "target" "try" "typeof" - "var" "void" "with" ] @keyword +[ + "class" + "let" + "const" + "var" +] @keyword.storage.type + [ "switch" "case" @@ -206,3 +207,9 @@ "do" "await" ] @keyword.control + +[ + "import" + "export" +] @keyword.control.import + diff --git a/runtime/queries/typescript/highlights.scm b/runtime/queries/typescript/highlights.scm index a3212a3db..a424d100f 100644 --- a/runtime/queries/typescript/highlights.scm +++ b/runtime/queries/typescript/highlights.scm @@ -22,15 +22,21 @@ [ "abstract" "declare" - "enum" "export" "implements" - "interface" "keyof" "namespace" +] @keyword + +[ + "type" + "interface" + "enum" +] @keyword.storage.type + +[ + "public" "private" "protected" - "public" - "type" "readonly" -] @keyword +] @keyword.storage.modifier \ No newline at end of file From b7a3531b8f6aa0f7423293fbf071488b1ef12da2 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sat, 9 Jul 2022 01:54:09 +0530 Subject: [PATCH 479/861] theme(onedark): Remove bg for window separator (#3011) --- runtime/themes/onedark.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/onedark.toml b/runtime/themes/onedark.toml index aec7ba960..b4cc6f8b1 100644 --- a/runtime/themes/onedark.toml +++ b/runtime/themes/onedark.toml @@ -71,7 +71,7 @@ diagnostic = { modifiers = ["underlined"] } "ui.help" = { bg = "gray" } "ui.popup" = { bg = "gray" } -"ui.window" = { bg = "gray" } +"ui.window" = { fg = "gray" } "ui.menu" = { fg = "white", bg = "gray" } "ui.menu.selected" = { fg = "black", bg = "blue" } "ui.menu.scroll" = { fg = "white", bg = "light-gray" } From 21b66ba0686e745c7e32a4b79cc7edcc3b3fa349 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sat, 9 Jul 2022 04:01:15 +0530 Subject: [PATCH 480/861] lsp: Add workspace/applyEdit to client capabilites (#3012) The functionality already existed, but the capability wasn't being reported correctly to the server: https://github.com/helix-editor/helix/blob/230ba264bf78d9b4ecd42440f0cbb20529f9c235/helix-term/src/application.rs#L716-L728 --- helix-lsp/src/client.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index aa8335414..9187a61ec 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -294,6 +294,7 @@ impl Client { dynamic_registration: Some(false), }), workspace_folders: Some(true), + apply_edit: Some(true), ..Default::default() }), text_document: Some(lsp::TextDocumentClientCapabilities { From 6100b1ba082db5c9fddd74d0ffea044231004920 Mon Sep 17 00:00:00 2001 From: Amit Beka Date: Sat, 9 Jul 2022 19:08:47 +0300 Subject: [PATCH 481/861] book: add wiki links to the title page and install page (#3017) Co-authored-by: amitbeka <---> --- book/src/install.md | 7 ++++++- book/src/title-page.md | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/book/src/install.md b/book/src/install.md index 045e22556..3006c389c 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -76,8 +76,13 @@ hx --health For more information on the information displayed in the healthcheck results refer to [Healthcheck](https://github.com/helix-editor/helix/wiki/Healthcheck). -## Building tree-sitter grammars +### Building tree-sitter grammars Tree-sitter grammars must be fetched and compiled if not pre-packaged. Fetch grammars with `hx --grammar fetch` (requires `git`) and compile them with `hx --grammar build` (requires a C++ compiler). + +### Installing language servers + +Language servers can optionally be installed if you want their features (auto-complete, diagnostics etc.). +Follow the [instructions on the wiki page](https://github.com/helix-editor/helix/wiki/How-to-install-the-default-language-servers) to add your language servers of choice. diff --git a/book/src/title-page.md b/book/src/title-page.md index c182a753c..f24d3d33f 100644 --- a/book/src/title-page.md +++ b/book/src/title-page.md @@ -6,6 +6,7 @@ Docs for bleeding edge master can be found at See the [usage] section for a quick overview of the editor, [keymap] section for all available keybindings and the [configuration] section for defining custom keybindings, setting themes, etc. +For everything else (e.g., how to install supported language servers), see the [Helix Wiki]. Refer the [FAQ] for common questions. @@ -13,3 +14,4 @@ Refer the [FAQ] for common questions. [usage]: ./usage.md [keymap]: ./keymap.md [configuration]: ./configuration.md +[Helix Wiki]: https://github.com/helix-editor/helix/wiki \ No newline at end of file From fefa4d8c5938c4e74b6eb01c6fb8379548c20ab4 Mon Sep 17 00:00:00 2001 From: Timothy DeHerrera Date: Sat, 9 Jul 2022 09:09:37 -0700 Subject: [PATCH 482/861] nix flake: make the binary cache "just work" (#2999) --- book/src/install.md | 8 ++++++-- flake.nix | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/book/src/install.md b/book/src/install.md index 3006c389c..ea46976f2 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -22,8 +22,12 @@ the project root. The flake can also be used to spin up a reproducible developme shell for working on Helix with `nix develop`. Flake outputs are cached for each push to master using -[Cachix](https://www.cachix.org/). With Cachix -[installed](https://docs.cachix.org/installation), `cachix use helix` will +[Cachix](https://www.cachix.org/). The flake is configured to +automatically make use of this cache assuming the user accepts +the new settings on first use. + +If you are using a version of Nix without flakes enabled you can +[install Cachix cli](https://docs.cachix.org/installation); `cachix use helix` will configure Nix to use cached outputs when possible. ### Arch Linux diff --git a/flake.nix b/flake.nix index c8bd02aa7..d0d454af1 100644 --- a/flake.nix +++ b/flake.nix @@ -96,4 +96,9 @@ }; }; }; + + nixConfig = { + extra-substituters = ["https://helix.cachix.org"]; + extra-trusted-public-keys = ["helix.cachix.org-1:ejp9KQpR1FBI2onstMQ34yogDm4OgU2ru6lIwPvuCVs="]; + }; } From 718c3baebecf4a970bc32724c564fa506ed40065 Mon Sep 17 00:00:00 2001 From: Timothy DeHerrera Date: Sat, 9 Jul 2022 09:17:44 -0700 Subject: [PATCH 483/861] nix: pass makeWrapperArgs to wrapProgram (#3003) --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index d0d454af1..fdeed2aaf 100644 --- a/flake.nix +++ b/flake.nix @@ -63,7 +63,7 @@ postFixup = '' if [ -f "$out/bin/hx" ]; then - wrapProgram "$out/bin/hx" --set HELIX_RUNTIME "${runtimeDir}" + wrapProgram "$out/bin/hx" ''${makeWrapperArgs[@]} --set HELIX_RUNTIME "${runtimeDir}" fi ''; }; From e109022bfd34b9297905b9da5904f6aa2279e74f Mon Sep 17 00:00:00 2001 From: Slug <106496265+GreasySlug@users.noreply.github.com> Date: Sun, 10 Jul 2022 17:54:06 +0900 Subject: [PATCH 484/861] fix: error that caused usize to overflow (#3024) * fix: error that caused usize to overflow * update: changed check_sub to saturating_sub --- helix-term/src/commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c9e350628..193d5d405 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1414,7 +1414,7 @@ fn copy_selection_on_line(cx: &mut Context, direction: Direction) { let (head, anchor) = if range.anchor < range.head { (range.head - 1, range.anchor) } else { - (range.head, range.anchor - 1) + (range.head, range.anchor.saturating_sub(1)) }; let tab_width = doc.tab_width(); From 0cb0c306183be94b9d42c3fae22b805850f87584 Mon Sep 17 00:00:00 2001 From: Austen LeBeau Date: Sun, 10 Jul 2022 11:27:44 -0500 Subject: [PATCH 485/861] add fortran language (#3025) --- book/src/generated/lang-support.md | 1 + languages.toml | 14 ++ runtime/queries/fortran/folds.scm | 11 ++ runtime/queries/fortran/highlights.scm | 171 +++++++++++++++++++++++++ runtime/queries/fortran/indents.scm | 27 ++++ 5 files changed, 224 insertions(+) create mode 100644 runtime/queries/fortran/folds.scm create mode 100644 runtime/queries/fortran/highlights.scm create mode 100644 runtime/queries/fortran/indents.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 85e42b159..085d92a8f 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -22,6 +22,7 @@ | erb | ✓ | | | | | erlang | ✓ | ✓ | | `erlang_ls` | | fish | ✓ | ✓ | ✓ | | +| fortran | ✓ | | ✓ | `fortls` | | gdscript | ✓ | | ✓ | | | git-attributes | ✓ | | | | | git-commit | ✓ | | | | diff --git a/languages.toml b/languages.toml index 56abf3f8a..3be20ab35 100644 --- a/languages.toml +++ b/languages.toml @@ -1514,3 +1514,17 @@ roots = [] comment-token = "--" indent = { tab-width = 2, unit = " " } language-server = { command = "idris2-lsp" } + +[[language]] +name = "fortran" +scope = "source.fortran" +injection-regex = "fortran" +file-types = ["f", "for", "f90", "f95", "f03"] +roots = ["fpm.toml"] +comment-token = "!" +indent = { tab-width = 4, unit = " "} +language-server = { command = "fortls", args = ["--lowercase_intrinsics"] } + +[[grammar]] +name = "fortran" +source = { git = "https://github.com/stadelmanma/tree-sitter-fortran", rev = "f0f2f100952a353e64e26b0fa710b4c296d7af13" } \ No newline at end of file diff --git a/runtime/queries/fortran/folds.scm b/runtime/queries/fortran/folds.scm new file mode 100644 index 000000000..f62d9dd7b --- /dev/null +++ b/runtime/queries/fortran/folds.scm @@ -0,0 +1,11 @@ +;; by @oponkork +[ + (if_statement) + (where_statement) + (enum_statement) + (do_loop_statement) + (derived_type_definition) + (function) + (subroutine) + (interface) +] @fold \ No newline at end of file diff --git a/runtime/queries/fortran/highlights.scm b/runtime/queries/fortran/highlights.scm new file mode 100644 index 000000000..90f4ecd0e --- /dev/null +++ b/runtime/queries/fortran/highlights.scm @@ -0,0 +1,171 @@ +[ + (intrinsic_type) + "dimension" + "intent" + "in" + "out" + "inout" + "type" + "endtype" + "attributes" + "global" + "device" + "host" + "grid_global" + "pointer" +] @keyword.storage.modifier + +[ + "contains" + "public" + "private" +] @keyword.directive + +[ +"implicit" +(none) +] @attribute + +[ + "function" + "endfunction" + "endprogram" + "subroutine" + "endsubroutine" +] @keyword.storage + +[ + "module" + "endmodule" + "bind" + "call" + "class" + "continue" + "cycle" + "enumerator" + "equivalence" + "exit" + "format" + "goto" + "include" + "interface" + "endinterface" + "only" + "parameter" + "procedure" + "print" + "program" + "endprogram" + "read" + "return" + "result" + "stop" + "use" + "write" + "enum" + "endenum" + (default) + (procedure_qualifier) +] @keyword + +[ + "if" + "then" + "else" + "elseif" + "endif" + "where" + "endwhere" +] @keyword.control.conditional + +[ + "do" + "enddo" + "while" + "forall" +] @keyword.control.repeat + +[ + "*" + "**" + "+" + "-" + "/" + "=" + "<" + ">" + "<=" + ">=" + "==" + "/=" +] @operator + +[ + "\\.and\\." + "\\.or\\." + "\\.lt\\." + "\\.gt\\." + "\\.ge\\." + "\\.le\\." + "\\.eq\\." + "\\.eqv\\." + "\\.neqv\\." +] @keyword.operator + + ;; Brackets + [ + "(" + ")" + "[" + "]" + ] @punctuation.bracket + + ;; Delimiter + [ + "::" + "," + "%" + ] @punctuation.delimiter + +(parameters + (identifier) @variable.parameter) + +(program_statement + (name) @namespace) + +(module_statement + (name) @namespace) + +(function_statement + (name) @function) + +(subroutine_statement + (name) @function) + +(end_program_statement + (name) @namespace) + +(end_module_statement + (name) @namespace) + +(end_function_statement + (name) @function) + +(end_subroutine_statement + (name) @function) + +(subroutine_call + (name) @function) + +(keyword_argument + name: (identifier) @keyword) + +(derived_type_member_expression + (type_member) @variable.other.member) + +(identifier) @variable +(string_literal) @string +(number_literal) @constant.numeric +(boolean_literal) @constant.builtin.boolean +(comment) @comment + diff --git a/runtime/queries/fortran/indents.scm b/runtime/queries/fortran/indents.scm new file mode 100644 index 000000000..daa8bac10 --- /dev/null +++ b/runtime/queries/fortran/indents.scm @@ -0,0 +1,27 @@ +[ + (module) + (program) + (subroutine) + (function) + ; (interface) + (if_statement) + (do_loop_statement) + (where_statement) + (derived_type_definition) + (enum) +] @indent + +[ + (end_module_statement) + (end_program_statement) + (end_subroutine_statement) + (end_function_statement) + ; (end_interface_statement) + (end_if_statement) + (end_do_loop_statement) + (else_clause) + (elseif_clause) + (end_type_statement) + (end_enum_statement) + (end_where_statement) +] @outdent \ No newline at end of file From 930f98053ec88c07ccf4256ee8a5e6f14147e1b8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Jul 2022 07:44:00 +0530 Subject: [PATCH 486/861] build(deps): bump serde from 1.0.138 to 1.0.139 (#3040) 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 00d8c4755..a70b6e731 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -885,18 +885,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.138" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" +checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.138" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" +checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" dependencies = [ "proc-macro2", "quote", From fb625697854e3a9d99aa4cfe952f2050b7e82ce0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Jul 2022 11:17:24 +0900 Subject: [PATCH 487/861] build(deps): bump regex from 1.5.5 to 1.6.0 (#3041) Bumps [regex](https://github.com/rust-lang/regex) from 1.5.5 to 1.6.0. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.5.5...1.6.0) --- updated-dependencies: - dependency-name: regex dependency-type: direct:production update-type: version-update:semver-minor ... 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 a70b6e731..237768b40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -816,9 +816,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.5" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -833,9 +833,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "remove_dir_all" From e97b8607c18c16f14ab17825ac20739c4d83b779 Mon Sep 17 00:00:00 2001 From: Philipp Mildenberger Date: Tue, 12 Jul 2022 17:06:53 +0200 Subject: [PATCH 488/861] Added ungrammar language support (#3048) --- book/src/generated/lang-support.md | 1 + languages.toml | 15 ++++++++++++++- runtime/queries/ungrammar/highlights.scm | 17 +++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/ungrammar/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 085d92a8f..978f42a71 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -98,6 +98,7 @@ | tsx | ✓ | | | `typescript-language-server` | | twig | ✓ | | | | | typescript | ✓ | | ✓ | `typescript-language-server` | +| ungrammar | ✓ | | | | | v | ✓ | | | `vls` | | vala | ✓ | | | `vala-language-server` | | verilog | ✓ | ✓ | | `svlangserver` | diff --git a/languages.toml b/languages.toml index 3be20ab35..20493e4c1 100644 --- a/languages.toml +++ b/languages.toml @@ -1527,4 +1527,17 @@ language-server = { command = "fortls", args = ["--lowercase_intrinsics"] } [[grammar]] name = "fortran" -source = { git = "https://github.com/stadelmanma/tree-sitter-fortran", rev = "f0f2f100952a353e64e26b0fa710b4c296d7af13" } \ No newline at end of file +source = { git = "https://github.com/stadelmanma/tree-sitter-fortran", rev = "f0f2f100952a353e64e26b0fa710b4c296d7af13" } + +[[language]] +name = "ungrammar" +scope = "source.ungrammar" +injection-regex = "ungrammar" +file-types = ["ungram", "ungrammar"] +roots = [] +comment-token = "//" +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "ungrammar" +source = { git = "https://github.com/Philipp-M/tree-sitter-ungrammar", rev = "0113de880a58ea14f2a75802e9b99fcc25003d9c" } diff --git a/runtime/queries/ungrammar/highlights.scm b/runtime/queries/ungrammar/highlights.scm new file mode 100644 index 000000000..cffbdbfdb --- /dev/null +++ b/runtime/queries/ungrammar/highlights.scm @@ -0,0 +1,17 @@ +(ERROR) @error + +(line_comment) @comment + +(identifier) @variable + +(token) @string + +[ + "=" + "|" + ":" + "(" + ")" + "?" + "*" +] @operator From 5f69beb87f611a339b5a95aa80d19947eeef8f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20S=2E=20Szczygie=C5=82?= Date: Tue, 12 Jul 2022 17:13:57 +0200 Subject: [PATCH 489/861] Add textobjects.scm to GLSL (#3051) --- book/src/generated/lang-support.md | 2 +- runtime/queries/glsl/textobjects.scm | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/glsl/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 978f42a71..64cb32c31 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -31,7 +31,7 @@ | git-ignore | ✓ | | | | | git-rebase | ✓ | | | | | gleam | ✓ | ✓ | | | -| glsl | ✓ | | ✓ | | +| glsl | ✓ | ✓ | ✓ | | | go | ✓ | ✓ | ✓ | `gopls` | | gomod | ✓ | | | `gopls` | | gowork | ✓ | | | `gopls` | diff --git a/runtime/queries/glsl/textobjects.scm b/runtime/queries/glsl/textobjects.scm new file mode 100644 index 000000000..a5a5208ca --- /dev/null +++ b/runtime/queries/glsl/textobjects.scm @@ -0,0 +1 @@ +; inherits: c From 7951ebfd4d790b5dce39eb30944f5542eba80ea0 Mon Sep 17 00:00:00 2001 From: 0rphee <79347623+0rphee@users.noreply.github.com> Date: Tue, 12 Jul 2022 12:42:17 -0500 Subject: [PATCH 490/861] [Theme] Noctis (#3043) --- runtime/themes/noctis.toml | 197 +++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 runtime/themes/noctis.toml diff --git a/runtime/themes/noctis.toml b/runtime/themes/noctis.toml new file mode 100644 index 000000000..fe598cf41 --- /dev/null +++ b/runtime/themes/noctis.toml @@ -0,0 +1,197 @@ +# Author : 0rphee <0rph3e@proton.me> + +# Template written with the help of https://github.com/n0s4/helix-theme-template +# Keep in mind that I made this to fit Haskell and Python syntax, it may not work so well with other languages. + +## GENERAL ============================== + +"warning" = { fg ="yellow", modifiers = ["bold"] } # Editor warnings. +"error" = { fg = "red", modifiers = ["bold"] } # Editor errors, like mis-typing a command. +"info" = { fg = "mid-blue", bg = "mid-green" } # Code diagnostic info in gutter (LSP). +# ? Difference between info and hint ? +"hint" = { fg = "light-green", modifiers = ["bold"] } # Code diagnostics hint in gutter (LSP). +"diagnostic" = { modifiers = ["underlined"] } # Code diagnostics in editing area (LSP). + +# UI ============================== +# For styling helix itself. + +'ui.background' = { bg = "dark-green"} # Default background color. +'ui.window' = { fg = "mid-green" } # Window border between splits. + +'ui.gutter' = { } # Left gutter for diagnostics and breakpoints. + +'ui.text' = { fg = "white" } # Default text color. +'ui.text.focus' = { fg = "white", bg = "mid-green", modifiers = ["bold"] } # Selection highlight in buffer-picker or file-picker. +'ui.text.info' = { } # Info popup contents (space mode menu). + +'ui.cursor' = { fg = "light-blue", modifiers = ["reversed"] } # Fallback cursor colour, non-primary cursors when there are multiple (shift-c). +'ui.cursor.primary' = { fg = "light-blue", modifiers = ["reversed"] } # The primary cursor when there are multiple (shift-c). +'ui.cursor.insert' = { fg = "light-blue" } # The cursor in insert mode (i). +'ui.cursor.select' = { fg = "light-blue" } # The cursor in select mode (v). +'ui.cursor.match' = { fg = "red", modifiers = ["bold", "reversed"] } # The matching parentheses of that under the cursor. + +'ui.selection' = { bg = "mid-green" } # All currently selected text. +'ui.selection.primary' = { bg = "mid-green" } # The primary selection when there are multiple. +'ui.cursorline.primary' = { bg = 'mid-green' } + +'ui.linenr' = { bg = "dark-green", fg = "gray" } # Line numbers. +'ui.linenr.selected' = { bg = "mid-green", fg = "light-green", modifiers = [ "bold" ] } # Current line number. + +'ui.virtual' = { fg = "mid-green" } # Namespace for additions to the editing area. +'ui.virtual.ruler' = { bg = "mid-green" } # Vertical rulers (colored columns in editing area). +'ui.virtual.whitespace' = { fg = "gray"} # Whitespace markers in editing area. +'ui.virtual.indent-guide' = { fg = "gray" } # Indentation guides. + +'ui.statusline' = { fg = "white", bg = "autocomp-green"} # Status line. +'ui.statusline.inactive' = { fg = "white", bg = "mid-green"} # Status line in unfocused windows. + +'ui.help' = { bg = "mid-green", fg = "white"} # `:command` descriptions above the command line. + +'ui.highlight' = { bg = "mid-green"} # selected contents of symbol pickers (spc-s, spc-S) and current line in buffer picker (spc-b). + +'ui.menu' = { fg = "gray", bg = "mid-green" } # Autocomplete menu. +'ui.menu.selected' = { fg = "white", bg = "autocomp-green" } # Selected autocomplete item. + +'ui.popup' = { bg = "mid-green" } # Documentation popups (space-k). +# 'ui.ppopup.info' = { bg = "midgreen", fg = "gray", modifiers = ["bold"] } # Info popups box (space mode menu). + +# SYNTAX HIGHLIGHTING ============================== +# All the keys here are Treesitter scopes. + +'property' = { fg = "red" } # Regex group names. +'special' = { fg = "mid-blue"} # Special symbols e.g `?` in Rust, `...` in Hare. +'attribute' = { fg = "yellow" } # Class attributes, html tag attributes. + +'type' = { fg = "orange"} # Variable type, like integer or string, including program defined classes, structs etc.. +#'type.builtin' = { } # Primitive types of the language (string, int, float). +#'type.enum.variant' = { } # A variant of an enum. + +'constructor' = { fg = "mid-blue", modifiers = ["bold"]} # Constructor method for a class or struct. And in some cases applies to module names + +'constant' = { fg = "light-blue" } # Constant value +'constant.builtin' = { fg = "mid-blue", modifiers = ["bold"] } # Special constants like `true`, `false`, `none`, etc. +'constant.builtin.boolean' = { } # True or False. +'constant.character' = { fg = "light-green"} # Constant of character type. +'constant.character.escape' = { fg = "purple", modifiers = ["bold"] } # escape codes like \n. +'constant.numeric' = { fg = "purple"} # constant integer or float value. +# 'constant.numeric.integer' = { } # constant integer value. +# 'constant.numeric.float' = { } # constant float value. + +'string' = { fg = "light-green" } # String literal. +'string.regexp' = { } # Regular expression literal. +'string.special' = { fg = "light-blue" } # Strings containing a path, URL, etc. +'string.special.path' = { } # String containing a file path. +'string.special.url' = { } # String containing a web URL. +'string.special.symbol' = { } # Erlang/Elixir atoms, Ruby symbols, Clojure keywords. + +'comment' = { fg = "gray", modifiers = ["italic"] } # This is a comment. +'comment.line' = { } # Line comments, like this. +'comment.block' = { } # Block comments, like /* this */ in some languages. +'comment.block.documentation' = { } # Doc comments, e.g '///' in rust. + +'variable' = { fg = "white" } # Variable names. +'variable.builtin' = { } # Language reserved variables: `this`, `self`, `super`, etc. +'variable.parameter' = { } # Funtion parameters. +'variable.other.member' = { } # Fields of composite data types (e.g. structs, unions). +'variable.function' = { } # ? + +'label' = { fg = "purple" } # Loop labels in rust. + +'punctuation' = { fg = "yellow", modifiers = ["bold"] } # (){}[]:;,. +# 'punctuation.delimeter' = { fg = "yellow" } # Commas and colons. +# 'punctuation.bracket' = { fg = "yellow" } # Parentheses, angle brackets, etc. + +'keyword' = { fg = "pink", modifiers = ["bold"] } # Language reserved keywords. +'keyword.control' = { fg = "pink", modifiers = ["bold"] } # Control keywords. +'keyword.control.conditional' = { fg = "pink", modifiers = ["bold"] } # 'if', 'else', 'elif'. +'keyword.control.repeat' = { } # 'for', 'while', 'loop'. +'keyword.control.import' = { fg = "pink", modifiers = ["italic"] } # 'import', 'export' ('use'?). +'keyword.control.return' = { } # 'return' in most languages. +'keyword.control.exception' = {fg = "pink", modifiers = ["bold"] } # 'raise' in python. +'keyword.operator' = { } # 'or', 'and', 'in'. +'keyword.directive' = { fg = "purple" } # Preprocessor directives (#if in C). +'keyword.function' = { } # The keyword to define a funtion: 'def', 'fun', 'fn'. + +'operator' = { fg = "pink", modifiers = ["bold"] } # Logical (&&, ||) and - I assume - Mathematical (+, %) operators + +'function' = { fg = "dark-blue"} +'function.builtin' = { fg = "dark-blue" } +'function.method' = { fg = "dark-blue" } # Class / Struct methods. +'function.macro' = { fg = "purple" } # Like macros in rust. +# 'function.special' = { fg = "yellow" } # Preprocessor in C. + +'tag' = { fg = "yellow"} # As in for html. + +'namespace' = { fg = "mid-blue" } # * Namespace keyword in java, C#, etc. + + +# Markup ============================== +# Colors for markup languages, like Markdown or XML. + +'markup.heading' = { } # Markdown headings +'markup.heading.1' = { } # Markdown heading 1 color. +'markup.heading.2' = { } # Markdown heading 2 color. +'markup.heading.3' = { } # Markdown heading 3 color. +'markup.heading.4' = { } # Markdown heading 4 color. +'markup.heading.5' = { } # Markdown heading 5 color. +'markup.heading.6' = { } # Markdown heading 6 color. +'markup.heading.marker' = { fg = "red" } # Hashtag color on Markdown headings. + +'markup.list' = { fg = "red" } +'markup.list.numbered' = { } # Numbered list. +'markup.list.unnumbered' = { } # Bullet point list. + +'markup.bold' = { modifiers = ["bold"] } # Bold text. +'markup.italic' = { modifiers = ["italic"] } # Italicised text. + +'markup.link' = { fg = "light-blue", modifiers = ["underlined"] } +'markup.link.url' = { } # Urls pointed to by links. +'markup.link.label' = { } # Non-URL link references. +'markup.link.text' = { fg = "purple"} # URL and image descriptions in links. + +'markup.quote' = { } # `> Quotes` in Markdown. + + +# Markup - Interface ============================== +# "These scopes are used for theming the editor interface." + +'markup.normal' = { } +'markup.normal.completion' = { } # For completion doc popup ui. +'markup.normal.raw' = { } # For hover popup ui. + +'markup.heading.completion' = { } # Headings for completion doc popup ui. +'markup.heading.raw' = { } # Headings for hover popup ui. + +'markup.raw' = { } # Code block in Markdown. +'markup.raw.block' = { } # Multiline (```) codeblock in Markdown. +'markup.raw.inline' = { } # `Inline code block` in Markdown. +'markup.raw.inline.completion' = { } # ? +'markup.raw.inline.hover' = { } # ? + +# Diff ============================== +# Version control changes. + +'diff.plus' = "light-green" # { } # Additions. +'diff.minus' = "yelllow" # { } # Deletions. +'diff.delta' = "red" # { } # Modifications. +'diff.delta.moved' = { } # Renamed or moved files / changes. + + +[palette] # Define your custom colors here. +dark-green = "#00262a" # backgrounds +mid-green = "#073a40" # highlights +autocomp-green = "#0d6772" # lighter than mid-green +light-green = "#48e9a7" # strings + +pink = "#df769b" +yellow = "#ffd800" +purple = "#6f60ea" +white = "#b1cace" +orange = "#e4b782" +gray = "#5b858b" # mainly for comments/background text +red = "#e34e1b" + +dark-blue = "#19a2b7" +mid-blue = "#47ace8" +light-blue = "#87efff" + From 3cced1e3c825b0ae527f43358b29d9595c54065b Mon Sep 17 00:00:00 2001 From: Termina94 <47091253+Termina94@users.noreply.github.com> Date: Tue, 12 Jul 2022 21:18:41 +0100 Subject: [PATCH 491/861] Add cursorline colour to darkplus theme (#3054) Co-authored-by: Dean Revell --- runtime/themes/dark_plus.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/themes/dark_plus.toml b/runtime/themes/dark_plus.toml index 957ca61d4..b622df2f9 100644 --- a/runtime/themes/dark_plus.toml +++ b/runtime/themes/dark_plus.toml @@ -72,6 +72,7 @@ "ui.linenr" = { fg = "dark_gray" } "ui.linenr.selected" = { fg = "light_gray2" } +"ui.cursorline.primary" = { bg = "dark_gray3" } "ui.statusline" = { fg = "white", bg = "blue" } "ui.statusline.inactive" = { fg = "white", bg = "blue" } @@ -100,6 +101,7 @@ light_gray2 = "#c6c6c6" light_gray3 = "#eeeeee" dark_gray = "#858585" dark_gray2 = "#1e1e1e" +dark_gray3= "#282828" blue = "#007acc" blue2 = "#569CD6" blue3 = "#6796E6" From e6a6e251c5cb2c373584187c3d4d17b3eaac6b6a Mon Sep 17 00:00:00 2001 From: Bob Date: Wed, 13 Jul 2022 23:00:24 +0800 Subject: [PATCH 492/861] respect count for repeating motion (#3057) --- helix-term/src/commands.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 193d5d405..cb223faf0 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1224,9 +1224,12 @@ fn extend_prev_char(cx: &mut Context) { } fn repeat_last_motion(cx: &mut Context) { + let count = cx.count(); let last_motion = cx.editor.last_motion.take(); if let Some(m) = &last_motion { - m.run(cx.editor); + for _ in 0..count { + m.run(cx.editor); + } cx.editor.last_motion = last_motion; } } From 4418924ec34c28e43ce34809edaac4ce4fd9f72c Mon Sep 17 00:00:00 2001 From: Bob Date: Wed, 13 Jul 2022 23:01:42 +0800 Subject: [PATCH 493/861] respect count for selecting next/previous match (#3056) --- helix-term/src/commands.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index cb223faf0..dad3db869 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1687,6 +1687,7 @@ fn searcher(cx: &mut Context, direction: Direction) { } fn search_next_or_prev_impl(cx: &mut Context, movement: Movement, direction: Direction) { + let count = cx.count(); let config = cx.editor.config(); let scrolloff = config.scrolloff; let (view, doc) = current!(cx.editor); @@ -1705,16 +1706,18 @@ fn search_next_or_prev_impl(cx: &mut Context, movement: Movement, direction: Dir .multi_line(true) .build() { - search_impl( - doc, - view, - &contents, - ®ex, - movement, - direction, - scrolloff, - wrap_around, - ); + for _ in 0..count { + search_impl( + doc, + view, + &contents, + ®ex, + movement, + direction, + scrolloff, + wrap_around, + ); + } } else { let error = format!("Invalid regex: {}", query); cx.editor.set_error(error); From 8681fb6d9ee06610fac2baafb4ca34f93f9c7f4d Mon Sep 17 00:00:00 2001 From: Bob Date: Thu, 14 Jul 2022 08:08:09 +0800 Subject: [PATCH 494/861] respect count in treesitter movement (#3058) --- helix-core/src/movement.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs index 2155f77a4..fa8cdf3ad 100644 --- a/helix-core/src/movement.rs +++ b/helix-core/src/movement.rs @@ -396,9 +396,9 @@ pub fn goto_treesitter_object( dir: Direction, slice_tree: Node, lang_config: &LanguageConfiguration, - _count: usize, + count: usize, ) -> Range { - let get_range = move || -> Option { + let get_range = move |range: Range| -> Option { let byte_pos = slice.char_to_byte(range.cursor(slice)); let cap_name = |t: TextObject| format!("{}.{}", object_name, t); @@ -436,7 +436,7 @@ pub fn goto_treesitter_object( // head of range should be at beginning Some(Range::new(end_char, start_char)) }; - get_range().unwrap_or(range) + (0..count).fold(range, |range, _| get_range(range).unwrap_or(range)) } #[cfg(test)] From 333ab278374863296ebef5154340f33482e13edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Cortier?= Date: Fri, 15 Jul 2022 09:59:00 -0400 Subject: [PATCH 495/861] feat(term): uniformize word-wise movement and deletion (#2500) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ctrl-based shortcuts are common in numerous applications. This change: - Adds Ctrl+{Left/Right/Backspace/Delete} for word-wise movement/deletion in prompt, picker, … - Removes Alt-Left and Alt-Right in prompt, picker, … - Adds Alt-Delete in insert mode for forward word deletion In some terminals, Alt-Backspace might not work because it is ambigous. See: https://github.com/helix-editor/helix/pull/2193#issuecomment-1105042501 Hence, Alt alternative is not removed. --- book/src/keymap.md | 93 ++++++++++++++++---------------- helix-term/src/application.rs | 2 +- helix-term/src/keymap/default.rs | 1 + helix-term/src/ui/prompt.rs | 8 +-- 4 files changed, 52 insertions(+), 52 deletions(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index 5daeec3fa..de2980376 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -298,30 +298,30 @@ convenience. These can be helpful for making simple modifications without escaping to normal mode, but beware that you will not have an undo-able "save point" until you return to normal mode. -| Key | Description | Command | -| ----- | ----------- | ------- | -| `Escape` | Switch to normal mode | `normal_mode` | -| `Ctrl-x` | Autocomplete | `completion` | -| `Ctrl-r` | Insert a register content | `insert_register` | -| `Ctrl-w`, `Alt-Backspace` | Delete previous word | `delete_word_backward` | -| `Alt-d` | Delete next word | `delete_word_forward` | -| `Alt-b`, `Ctrl-Left` | Backward a word | `move_prev_word_end` | -| `Ctrl-b`, `Left` | Backward a char | `move_char_left` | -| `Alt-f`, `Ctrl-Right` | Forward a word | `move_next_word_start` | -| `Ctrl-f`, `Right` | Forward a char | `move_char_right` | -| `Ctrl-e`, `End` | Move to line end | `goto_line_end_newline` | -| `Ctrl-a`, `Home` | Move to line start | `goto_line_start` | -| `Ctrl-u` | Delete to start of line | `kill_to_line_start` | -| `Ctrl-k` | Delete to end of line | `kill_to_line_end` | -| `Ctrl-j`, `Enter` | Insert new line | `insert_newline` | -| `Backspace`, `Ctrl-h` | Delete previous char | `delete_char_backward` | -| `Delete`, `Ctrl-d` | Delete next char | `delete_char_forward` | -| `Ctrl-p`, `Up` | Move to previous line | `move_line_up` | -| `Ctrl-n`, `Down` | Move to next line | `move_line_down` | -| `PageUp` | Move one page up | `page_up` | -| `PageDown` | Move one page down | `page_down` | -| `Alt->` | Go to end of buffer | `goto_file_end` | -| `Alt-<` | Go to start of buffer | `goto_file_start` | +| Key | Description | Command | +| ----- | ----------- | ------- | +| `Escape` | Switch to normal mode | `normal_mode` | +| `Ctrl-x` | Autocomplete | `completion` | +| `Ctrl-r` | Insert a register content | `insert_register` | +| `Ctrl-w`, `Alt-Backspace`, `Ctrl-Backspace` | Delete previous word | `delete_word_backward` | +| `Alt-d`, `Alt-Delete`, `Ctrl-Delete` | Delete next word | `delete_word_forward` | +| `Alt-b`, `Ctrl-Left` | Backward a word | `move_prev_word_end` | +| `Ctrl-b`, `Left` | Backward a char | `move_char_left` | +| `Alt-f`, `Ctrl-Right` | Forward a word | `move_next_word_start` | +| `Ctrl-f`, `Right` | Forward a char | `move_char_right` | +| `Ctrl-e`, `End` | Move to line end | `goto_line_end_newline` | +| `Ctrl-a`, `Home` | Move to line start | `goto_line_start` | +| `Ctrl-u` | Delete to start of line | `kill_to_line_start` | +| `Ctrl-k` | Delete to end of line | `kill_to_line_end` | +| `Ctrl-j`, `Enter` | Insert new line | `insert_newline` | +| `Backspace`, `Ctrl-h` | Delete previous char | `delete_char_backward` | +| `Delete`, `Ctrl-d` | Delete next char | `delete_char_forward` | +| `Ctrl-p`, `Up` | Move to previous line | `move_line_up` | +| `Ctrl-n`, `Down` | Move to next line | `move_line_down` | +| `PageUp` | Move one page up | `page_up` | +| `PageDown` | Move one page down | `page_down` | +| `Alt->` | Go to end of buffer | `goto_file_end` | +| `Alt-<` | Go to start of buffer | `goto_file_start` | ## Select / extend mode @@ -358,26 +358,25 @@ Keys to use within picker. Remapping currently not supported. Keys to use within prompt, Remapping currently not supported. -| Key | Description | -| ----- | ------------- | -| `Escape`, `Ctrl-c` | Close prompt | -| `Alt-b`, `Alt-Left` | Backward a word | -| `Ctrl-b`, `Left` | Backward a char | -| `Alt-f`, `Alt-Right` | Forward a word | -| `Ctrl-f`, `Right` | Forward a char | -| `Ctrl-e`, `End` | Move prompt end | -| `Ctrl-a`, `Home` | Move prompt start | -| `Ctrl-w` | Delete previous word | -| `Alt-d` | Delete next word | -| `Ctrl-u` | Delete to start of line | -| `Ctrl-k` | Delete to end of line | -| `backspace`, `Ctrl-h` | Delete previous char | -| `delete`, `Ctrl-d` | Delete next char | -| `Ctrl-s` | Insert a word under doc cursor, may be changed to Ctrl-r Ctrl-w later | -| `Ctrl-p`, `Up` | Select previous history | -| `Ctrl-n`, `Down` | Select next history | -| `Ctrl-r` | Insert the content of the register selected by following input char | -| `Tab` | Select next completion item | -| `BackTab` | Select previous completion item | -| `Enter` | Open selected | - +| Key | Description | +| ----- | ------------- | +| `Escape`, `Ctrl-c` | Close prompt | +| `Alt-b`, `Ctrl-Left` | Backward a word | +| `Ctrl-b`, `Left` | Backward a char | +| `Alt-f`, `Ctrl-Right` | Forward a word | +| `Ctrl-f`, `Right` | Forward a char | +| `Ctrl-e`, `End` | Move prompt end | +| `Ctrl-a`, `Home` | Move prompt start | +| `Ctrl-w`, `Alt-Backspace`, `Ctrl-Backspace` | Delete previous word | +| `Alt-d`, `Alt-Delete`, `Ctrl-Delete` | Delete next word | +| `Ctrl-u` | Delete to start of line | +| `Ctrl-k` | Delete to end of line | +| `backspace`, `Ctrl-h` | Delete previous char | +| `delete`, `Ctrl-d` | Delete next char | +| `Ctrl-s` | Insert a word under doc cursor, may be changed to Ctrl-r Ctrl-w later | +| `Ctrl-p`, `Up` | Select previous history | +| `Ctrl-n`, `Down` | Select next history | +| `Ctrl-r` | Insert the content of the register selected by following input char | +| `Tab` | Select next completion item | +| `BackTab` | Select previous completion item | +| `Enter` | Open selected | diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index d3899075c..f4f0876cf 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -350,7 +350,7 @@ impl Application { } fn refresh_config(&mut self) { - let config = Config::load(helix_loader::config_file()).unwrap_or_else(|err| { + let config = Config::load_default().unwrap_or_else(|err| { self.editor.set_error(err.to_string()); Config::default() }); diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index 9b1447581..b8c1a4007 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -351,6 +351,7 @@ pub fn default() -> HashMap { "C-w" => delete_word_backward, "A-backspace" => delete_word_backward, "A-d" => delete_word_forward, + "A-del" => delete_word_forward, "C-s" => commit_undo_checkpoint, "left" => move_char_left, diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 55b08032d..36ee62c35 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -477,14 +477,14 @@ impl Component for Prompt { (self.callback_fn)(cx, &self.line, PromptEvent::Abort); return close_fn; } - alt!('b') | alt!(Left) => self.move_cursor(Movement::BackwardWord(1)), - alt!('f') | alt!(Right) => self.move_cursor(Movement::ForwardWord(1)), + alt!('b') | ctrl!(Left) => self.move_cursor(Movement::BackwardWord(1)), + alt!('f') | ctrl!(Right) => self.move_cursor(Movement::ForwardWord(1)), ctrl!('b') | key!(Left) => self.move_cursor(Movement::BackwardChar(1)), ctrl!('f') | key!(Right) => self.move_cursor(Movement::ForwardChar(1)), ctrl!('e') | key!(End) => self.move_end(), ctrl!('a') | key!(Home) => self.move_start(), - ctrl!('w') => self.delete_word_backwards(cx), - alt!('d') => self.delete_word_forwards(cx), + ctrl!('w') | alt!(Backspace) | ctrl!(Backspace) => self.delete_word_backwards(cx), + alt!('d') | alt!(Delete) | ctrl!(Delete) => self.delete_word_forwards(cx), ctrl!('k') => self.kill_to_end_of_line(cx), ctrl!('u') => self.kill_to_start_of_line(cx), ctrl!('h') | key!(Backspace) => { From bcacc703d737300e3e315b0b8a4716cdf306da87 Mon Sep 17 00:00:00 2001 From: Alex Kim <45559664+alex-kim-dev@users.noreply.github.com> Date: Fri, 15 Jul 2022 19:51:34 +0500 Subject: [PATCH 496/861] fix wrong value for cursor shape config in the docs (#3081) --- book/src/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index 1cc8602ad..0a6e5fdd0 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -60,7 +60,7 @@ hidden = false Defines the shape of cursor in each mode. Note that due to limitations of the terminal environment, only the primary cursor can change shape. -Valid values for these options are `block`, `bar`, `underline`, or `none`. +Valid values for these options are `block`, `bar`, `underline`, or `hidden`. | Key | Description | Default | | --- | ----------- | ------- | From 0c9594e41ea18f71a0b1de386396575e6f73fc12 Mon Sep 17 00:00:00 2001 From: Joe Date: Sun, 17 Jul 2022 05:55:20 -0400 Subject: [PATCH 497/861] Add SCSS language support (#3074) --- book/src/generated/lang-support.md | 1 + languages.toml | 13 +++++ runtime/queries/scss/highlights.scm | 86 +++++++++++++++++++++++++++++ runtime/queries/scss/injections.scm | 2 + 4 files changed, 102 insertions(+) create mode 100644 runtime/queries/scss/highlights.scm create mode 100644 runtime/queries/scss/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 64cb32c31..aecf80acb 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -85,6 +85,7 @@ | rust | ✓ | ✓ | ✓ | `rust-analyzer` | | scala | ✓ | | ✓ | `metals` | | scheme | ✓ | | | | +| scss | ✓ | | | `vscode-css-language-server` | | solidity | ✓ | | | `solc` | | sql | ✓ | | | | | sshclientconfig | ✓ | | | | diff --git a/languages.toml b/languages.toml index 20493e4c1..cd87d79ba 100644 --- a/languages.toml +++ b/languages.toml @@ -381,6 +381,19 @@ indent = { tab-width = 2, unit = " " } name = "css" source = { git = "https://github.com/tree-sitter/tree-sitter-css", rev = "94e10230939e702b4fa3fa2cb5c3bc7173b95d07" } +[[language]] +name = "scss" +scope = "source.scss" +injection-regex = "scss" +file-types = ["scss"] +roots = [] +language-server = { command = "vscode-css-language-server", args = ["--stdio"] } +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "scss" +source = { git = "https://github.com/serenadeai/tree-sitter-scss.git", rev = "c478c6868648eff49eb04a4df90d703dc45b312a" } + [[language]] name = "html" scope = "text.html.basic" diff --git a/runtime/queries/scss/highlights.scm b/runtime/queries/scss/highlights.scm new file mode 100644 index 000000000..89cce4944 --- /dev/null +++ b/runtime/queries/scss/highlights.scm @@ -0,0 +1,86 @@ +(comment) @comment + +"~" @operator +">" @operator +"+" @operator +"-" @operator +"*" @operator +"/" @operator +"=" @operator +"^=" @operator +"|=" @operator +"~=" @operator +"$=" @operator +"*=" @operator + +"in" @operator +"and" @operator +"or" @operator +"not" @operator +"only" @operator + +"@apply" @constant.builtin +"@at-root" @constant.builtin +"@charset" @constant.builtin +"@debug" @constant.builtin +"@each" @keyword.control.repeat +"@else" @keyword.control.conditional +"@error" @constant.builtin +"@extend" @constant.builtin +"@for" @keyword.control.repeat +"@forward" @keyword.control.import +"@function" @function.method +"@if" @keyword.control.conditional +"@import" @keyword.control.import +"@include" @keyword.control.import +"@keyframes" @constant.builtin +"@media" @constant.builtin +"@mixin" @constant.builtin +"@namespace" @namespace +"@return" @keyword.control.return +"@supports" @constant.builtin +"@use" @keyword.control.import +"@warn" @constant.builtin +"@while" @keyword.control.repeat + +((property_name) @variable + (match? @variable "^--")) +((plain_value) @variable + (match? @variable "^--")) + +(tag_name) @tag +(universal_selector) @tag +(attribute_selector (plain_value) @string) +(nesting_selector) @variable.other.member +(pseudo_element_selector) @attribute +(pseudo_class_selector) @attribute + +(identifier) @variable +(class_name) @variable +(id_name) @variable +(namespace_name) @variable +(property_name) @variable.other.member +(feature_name) @variable +(variable) @variable +(variable_name) @variable.other.member +(variable_value) @variable.other.member +(argument_name) @variable.parameter +(selectors) @variable.other.member + +(attribute_name) @attribute + +(function_name) @function + +(to) @keyword +(from) @keyword +(important) @keyword + +(string_value) @string +(color_value) @string.special + +(integer_value) @constant.numeric.integer +(float_value) @constant.numeric.float +(unit) @type + +"#" @punctuation.delimiter +"," @punctuation.delimiter diff --git a/runtime/queries/scss/injections.scm b/runtime/queries/scss/injections.scm new file mode 100644 index 000000000..321c90add --- /dev/null +++ b/runtime/queries/scss/injections.scm @@ -0,0 +1,2 @@ +((comment) @injection.content + (#set! injection.language "comment")) From 43761d426cb0c508bfcea93c4bf1d08949e6c7c1 Mon Sep 17 00:00:00 2001 From: Joe Date: Sun, 17 Jul 2022 12:11:05 -0400 Subject: [PATCH 498/861] Remove .git extension from SCSS tree-sitter repo url (#3089) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index cd87d79ba..f9dac467e 100644 --- a/languages.toml +++ b/languages.toml @@ -392,7 +392,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "scss" -source = { git = "https://github.com/serenadeai/tree-sitter-scss.git", rev = "c478c6868648eff49eb04a4df90d703dc45b312a" } +source = { git = "https://github.com/serenadeai/tree-sitter-scss", rev = "c478c6868648eff49eb04a4df90d703dc45b312a" } [[language]] name = "html" From dbf68e0370981dc4ad0fa74596b57347f7048fab Mon Sep 17 00:00:00 2001 From: "Mr. E" <2804556+etienne-k@users.noreply.github.com> Date: Mon, 18 Jul 2022 02:57:01 +0200 Subject: [PATCH 499/861] Customizable/configurable status line (#2434) * feat(statusline): add the file type (language id) to the status line * refactor(statusline): move the statusline implementation into an own struct * refactor(statusline): split the statusline implementation into different functions * refactor(statusline): Append elements using a consistent API This is a preparation for the configurability which is about to be implemented. * refactor(statusline): implement render_diagnostics() This avoid cluttering the render() function and will simplify configurability. * feat(statusline): make the status line configurable * refactor(statusline): make clippy happy * refactor(statusline): avoid intermediate StatusLineObject Use a more functional approach to obtain render functions and write to the buffers, and avoid an intermediate StatusLineElement object. * fix(statusline): avoid rendering the left elements twice * refactor(statusline): make clippy happy again * refactor(statusline): rename `buffer` into `parts` * refactor(statusline): ensure the match is exhaustive * fix(statusline): avoid an overflow when calculating the maximal center width * chore(statusline): Describe the statusline configurability in the book * chore(statusline): Correct and add documentation * refactor(statusline): refactor some code following the code review Avoid very small helper functions for the diagnositcs and inline them instead. Rename the config field `status_line` to `statusline` to remain consistent with `bufferline`. * chore(statusline): adjust documentation following the config field refactoring * revert(statusline): revert regression introduced by c0a1870 * chore(statusline): slight adjustment in the configuration documentation * feat(statusline): integrate changes from #2676 after rebasing * refactor(statusline): remove the StatusLine struct Because none of the functions need `Self` and all of them are in an own file, there is no explicit need for the struct. * fix(statusline): restore the configurability of color modes The configuration was ignored after reintegrating the changes of #2676 in 8d28f95. * fix(statusline): remove the spinner padding * refactor(statusline): remove unnecessary format!() --- book/src/configuration.md | 32 +++- helix-term/src/ui/editor.rs | 163 +---------------- helix-term/src/ui/mod.rs | 1 + helix-term/src/ui/statusline.rs | 310 ++++++++++++++++++++++++++++++++ helix-view/src/editor.rs | 51 ++++++ 5 files changed, 401 insertions(+), 156 deletions(-) create mode 100644 helix-term/src/ui/statusline.rs diff --git a/book/src/configuration.md b/book/src/configuration.md index 0a6e5fdd0..4c849f262 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -48,13 +48,43 @@ hidden = false | `rulers` | List of column positions at which to display the rulers. Can be overridden by language specific `rulers` in `languages.toml` file. | `[]` | | `color-modes` | Whether to color the mode indicator with different colors depending on the mode itself | `false` | +### `[editor.statusline]` Section + +Allows configuring the statusline at the bottom of the editor. + +The configuration distinguishes between three areas of the status line: + +`[ ... ... LEFT ... ... | ... ... ... ... CENTER ... ... ... ... | ... ... RIGHT ... ... ]` + +Statusline elements can be defined as follows: + +```toml +[editor.statusline] +left = ["mode", "spinner"] +center = ["file-name"] +right = ["diagnostics", "selections", "position", "file-encoding", "file-type"] +``` + +The following elements can be configured: + +| Key | Description | +| ------ | ----------- | +| `mode` | The current editor mode (`NOR`/`INS`/`SEL`) | +| `spinner` | A progress spinner indicating LSP activity | +| `file-name` | The path/name of the opened file | +| `file-encoding` | The encoding of the opened file if it differs from UTF-8 | +| `file-type` | The type of the opened file | +| `diagnostics` | The number of warnings and/or errors | +| `selections` | The number of active selections | +| `position` | The cursor position | + ### `[editor.lsp]` Section | Key | Description | Default | | --- | ----------- | ------- | | `display-messages` | Display LSP progress messages below statusline[^1] | `false` | -[^1]: A progress spinner is always shown in the statusline beside the file path. +[^1]: By default, a progress spinner is shown in the statusline beside the file path. ### `[editor.cursor-shape]` Section diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index a7c67a219..9b8bf8eb5 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -7,7 +7,6 @@ use crate::{ }; use helix_core::{ - coords_at_pos, encoding, graphemes::{ ensure_grapheme_boundary_next_byte, next_grapheme_boundary, prev_grapheme_boundary, }, @@ -17,7 +16,7 @@ use helix_core::{ LineEnding, Position, Range, Selection, Transaction, }; use helix_view::{ - document::{Mode, SCRATCH_BUFFER_NAME}, + document::Mode, editor::{CompleteAction, CursorShapeConfig}, graphics::{Color, CursorKind, Modifier, Rect, Style}, input::KeyEvent, @@ -29,6 +28,8 @@ use std::borrow::Cow; use crossterm::event::{Event, MouseButton, MouseEvent, MouseEventKind}; use tui::buffer::Buffer as Surface; +use super::statusline; + pub struct EditorView { pub keymaps: Keymaps, on_next_key: Option>, @@ -161,7 +162,11 @@ impl EditorView { .area .clip_top(view.area.height.saturating_sub(1)) .clip_bottom(1); // -1 from bottom to remove commandline - self.render_statusline(editor, doc, view, statusline_area, surface, is_focused); + + let mut context = + statusline::RenderContext::new(editor, doc, view, is_focused, &self.spinners); + + statusline::render(&mut context, statusline_area, surface); } pub fn render_rulers( @@ -730,158 +735,6 @@ impl EditorView { } } - pub fn render_statusline( - &self, - editor: &Editor, - doc: &Document, - view: &View, - viewport: Rect, - surface: &mut Surface, - is_focused: bool, - ) { - use tui::text::{Span, Spans}; - - //------------------------------- - // Left side of the status line. - //------------------------------- - - let theme = &editor.theme; - let (mode, mode_style) = match doc.mode() { - Mode::Insert => (" INS ", theme.get("ui.statusline.insert")), - Mode::Select => (" SEL ", theme.get("ui.statusline.select")), - Mode::Normal => (" NOR ", theme.get("ui.statusline.normal")), - }; - let progress = doc - .language_server() - .and_then(|srv| { - self.spinners - .get(srv.id()) - .and_then(|spinner| spinner.frame()) - }) - .unwrap_or(""); - - let base_style = if is_focused { - theme.get("ui.statusline") - } else { - theme.get("ui.statusline.inactive") - }; - // statusline - surface.set_style(viewport.with_height(1), base_style); - if is_focused { - let color_modes = editor.config().color_modes; - surface.set_string( - viewport.x, - viewport.y, - mode, - if color_modes { mode_style } else { base_style }, - ); - } - surface.set_string(viewport.x + 5, viewport.y, progress, base_style); - - //------------------------------- - // Right side of the status line. - //------------------------------- - - let mut right_side_text = Spans::default(); - - // Compute the individual info strings and add them to `right_side_text`. - - // Diagnostics - let diags = doc.diagnostics().iter().fold((0, 0), |mut counts, diag| { - use helix_core::diagnostic::Severity; - match diag.severity { - Some(Severity::Warning) => counts.0 += 1, - Some(Severity::Error) | None => counts.1 += 1, - _ => {} - } - counts - }); - let (warnings, errors) = diags; - let warning_style = theme.get("warning"); - let error_style = theme.get("error"); - for i in 0..2 { - let (count, style) = match i { - 0 => (warnings, warning_style), - 1 => (errors, error_style), - _ => unreachable!(), - }; - if count == 0 { - continue; - } - let style = base_style.patch(style); - right_side_text.0.push(Span::styled("●", style)); - right_side_text - .0 - .push(Span::styled(format!(" {} ", count), base_style)); - } - - // Selections - let sels_count = doc.selection(view.id).len(); - right_side_text.0.push(Span::styled( - format!( - " {} sel{} ", - sels_count, - if sels_count == 1 { "" } else { "s" } - ), - base_style, - )); - - // Position - let pos = coords_at_pos( - doc.text().slice(..), - doc.selection(view.id) - .primary() - .cursor(doc.text().slice(..)), - ); - right_side_text.0.push(Span::styled( - format!(" {}:{} ", pos.row + 1, pos.col + 1), // Convert to 1-indexing. - base_style, - )); - - let enc = doc.encoding(); - if enc != encoding::UTF_8 { - right_side_text - .0 - .push(Span::styled(format!(" {} ", enc.name()), base_style)); - } - - // Render to the statusline. - surface.set_spans( - viewport.x - + viewport - .width - .saturating_sub(right_side_text.width() as u16), - viewport.y, - &right_side_text, - right_side_text.width() as u16, - ); - - //------------------------------- - // Middle / File path / Title - //------------------------------- - let title = { - let rel_path = doc.relative_path(); - let path = rel_path - .as_ref() - .map(|p| p.to_string_lossy()) - .unwrap_or_else(|| SCRATCH_BUFFER_NAME.into()); - format!("{}{}", path, if doc.is_modified() { "[+]" } else { "" }) - }; - - surface.set_string_truncated( - viewport.x + 8, // 8: 1 space + 3 char mode string + 1 space + 1 spinner + 1 space - viewport.y, - &title, - viewport - .width - .saturating_sub(6) - .saturating_sub(right_side_text.width() as u16 + 1) as usize, // "+ 1": a space between the title and the selection info - |_| base_style, - true, - true, - ); - } - /// Handle events by looking them up in `self.keymaps`. Returns None /// if event was handled (a command was executed or a subkeymap was /// activated). Only KeymapResult::{NotFound, Cancelled} is returned diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index ca4cedb55..c7d409e96 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -8,6 +8,7 @@ mod picker; mod popup; mod prompt; mod spinner; +mod statusline; mod text; pub use completion::Completion; diff --git a/helix-term/src/ui/statusline.rs b/helix-term/src/ui/statusline.rs new file mode 100644 index 000000000..895043cd1 --- /dev/null +++ b/helix-term/src/ui/statusline.rs @@ -0,0 +1,310 @@ +use helix_core::{coords_at_pos, encoding}; +use helix_view::{ + document::{Mode, SCRATCH_BUFFER_NAME}, + graphics::Rect, + theme::Style, + Document, Editor, View, +}; + +use crate::ui::ProgressSpinners; + +use helix_view::editor::StatusLineElement as StatusLineElementID; +use tui::buffer::Buffer as Surface; +use tui::text::{Span, Spans}; + +pub struct RenderContext<'a> { + pub editor: &'a Editor, + pub doc: &'a Document, + pub view: &'a View, + pub focused: bool, + pub spinners: &'a ProgressSpinners, + pub parts: RenderBuffer<'a>, +} + +impl<'a> RenderContext<'a> { + pub fn new( + editor: &'a Editor, + doc: &'a Document, + view: &'a View, + focused: bool, + spinners: &'a ProgressSpinners, + ) -> Self { + RenderContext { + editor, + doc, + view, + focused, + spinners, + parts: RenderBuffer::default(), + } + } +} + +#[derive(Default)] +pub struct RenderBuffer<'a> { + pub left: Spans<'a>, + pub center: Spans<'a>, + pub right: Spans<'a>, +} + +pub fn render(context: &mut RenderContext, viewport: Rect, surface: &mut Surface) { + let base_style = if context.focused { + context.editor.theme.get("ui.statusline") + } else { + context.editor.theme.get("ui.statusline.inactive") + }; + + surface.set_style(viewport.with_height(1), base_style); + + let write_left = |context: &mut RenderContext, text, style| { + append(&mut context.parts.left, text, &base_style, style) + }; + let write_center = |context: &mut RenderContext, text, style| { + append(&mut context.parts.center, text, &base_style, style) + }; + let write_right = |context: &mut RenderContext, text, style| { + append(&mut context.parts.right, text, &base_style, style) + }; + + // Left side of the status line. + + let element_ids = &context.editor.config().statusline.left; + element_ids + .iter() + .map(|element_id| get_render_function(*element_id)) + .for_each(|render| render(context, write_left)); + + surface.set_spans( + viewport.x, + viewport.y, + &context.parts.left, + context.parts.left.width() as u16, + ); + + // Right side of the status line. + + let element_ids = &context.editor.config().statusline.right; + element_ids + .iter() + .map(|element_id| get_render_function(*element_id)) + .for_each(|render| render(context, write_right)); + + surface.set_spans( + viewport.x + + viewport + .width + .saturating_sub(context.parts.right.width() as u16), + viewport.y, + &context.parts.right, + context.parts.right.width() as u16, + ); + + // Center of the status line. + + let element_ids = &context.editor.config().statusline.center; + element_ids + .iter() + .map(|element_id| get_render_function(*element_id)) + .for_each(|render| render(context, write_center)); + + // Width of the empty space between the left and center area and between the center and right area. + let spacing = 1u16; + + let edge_width = context.parts.left.width().max(context.parts.right.width()) as u16; + let center_max_width = viewport.width.saturating_sub(2 * edge_width + 2 * spacing); + let center_width = center_max_width.min(context.parts.center.width() as u16); + + surface.set_spans( + viewport.x + viewport.width / 2 - center_width / 2, + viewport.y, + &context.parts.center, + center_width, + ); +} + +fn append(buffer: &mut Spans, text: String, base_style: &Style, style: Option