From 6acd2000284095ac6ec06aaa5c34d843a833800a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20C=2E=20M=C3=BCller?= Date: Thu, 23 Mar 2023 22:26:41 -0400 Subject: [PATCH 001/260] Fix spelling of diagnostics (#6418) --- 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 bf3149937..e2dfc89ef 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -305,7 +305,7 @@ Example: min-width = 1 ``` -#### `[editor.gutters.diagnotics]` Section +#### `[editor.gutters.diagnostics]` Section Currently unused From 9a651188998bbc1584519ebf658cb5c2c31f4b21 Mon Sep 17 00:00:00 2001 From: Alexis-Lapierre <128792625+Alexis-Lapierre@users.noreply.github.com> Date: Fri, 24 Mar 2023 19:13:01 +0100 Subject: [PATCH 002/260] Recognize .cts and .mts file type as TypeScript (#6424) TypeScript can use three type of file extensions: - .ts for regular TypeScript - .cts for CommonJS modules - .mts for ES modules Official documentation on supported file extensions: https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 2bf9218e5..670f3adf9 100644 --- a/languages.toml +++ b/languages.toml @@ -453,7 +453,7 @@ includeInlayVariableTypeHints = true name = "typescript" scope = "source.ts" injection-regex = "(ts|typescript)" -file-types = ["ts"] +file-types = ["ts", "mts", "cts"] shebangs = [] roots = [] # TODO: highlights-params From 2f64c768dff1e6b3784d88a5604bd2f1b96b2b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Dzivjak?= Date: Sat, 25 Mar 2023 14:40:19 +0100 Subject: [PATCH 003/260] feat(languages): highlight .svg as xml (#6431) Add "svg" as a file type for xml. Fixes: https://github.com/helix-editor/helix/issues/6337 --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 670f3adf9..a56de1f4b 100644 --- a/languages.toml +++ b/languages.toml @@ -2068,7 +2068,7 @@ source = { git = "https://github.com/Unoqwy/tree-sitter-kdl", rev = "e1cd292c6d1 name = "xml" scope = "source.xml" injection-regex = "xml" -file-types = ["xml", "mobileconfig", "plist", "xib", "storyboard"] +file-types = ["xml", "mobileconfig", "plist", "xib", "storyboard", "svg"] indent = { tab-width = 2, unit = " " } roots = [] From 851ac6cdd3c5a865d43968ea81d98b5b7c859728 Mon Sep 17 00:00:00 2001 From: Erasin Wang Date: Sun, 26 Mar 2023 00:41:31 +0800 Subject: [PATCH 004/260] Add theme keys for (un)checked markup list items (#6434) --- book/src/themes.md | 2 ++ runtime/queries/markdown/highlights.scm | 3 +++ runtime/themes/onelight.toml | 4 +++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/book/src/themes.md b/book/src/themes.md index 994542c5a..7accb67f0 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -228,6 +228,8 @@ We use a similar set of scopes as - `list` - `unnumbered` - `numbered` + - `checked` + - `unchecked` - `bold` - `italic` - `strikethrough` diff --git a/runtime/queries/markdown/highlights.scm b/runtime/queries/markdown/highlights.scm index 80c9f9583..72bb68dc2 100644 --- a/runtime/queries/markdown/highlights.scm +++ b/runtime/queries/markdown/highlights.scm @@ -39,6 +39,9 @@ (list_marker_parenthesis) ] @markup.list.numbered +(task_list_marker_checked) @markup.list.checked +(task_list_marker_unchecked) @markup.list.unchecked + (thematic_break) @punctuation.special [ diff --git a/runtime/themes/onelight.toml b/runtime/themes/onelight.toml index a9d7a0d32..e35abdb37 100644 --- a/runtime/themes/onelight.toml +++ b/runtime/themes/onelight.toml @@ -80,9 +80,11 @@ "markup.list" = { fg = "light-blue" } "markup.list.unnumbered" = { fg = "light-blue" } "markup.list.numbered" = { fg = "light-blue" } +"markup.list.checked" = { fg = "green" } +"markup.list.unchecked" = { fg = "blue" } "markup.bold" = { fg = "yellow", modifiers = ["bold"] } "markup.italic" = { fg = "purple", modifiers = ["italic"] } -"markup.strikethrough" = { modifiers = ["crossed_out"] } +"markup.strikethrough" = { fg = "red", modifiers = ["crossed_out"] } "markup.link" = { fg = "light-blue" } "markup.link.url" = { fg = "cyan", modifiers = ["underlined"] } "markup.link.text" = { fg = "light-blue" } From 685ae2365a89346ef276dceb52c3cae40260d1fd Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Sat, 25 Mar 2023 12:10:54 -0500 Subject: [PATCH 005/260] Add vhdl language support (#5826) Simple highlight query file with keywords and builtin types matching. Many VHDL types however are defined in std libraries which do not currently get matched on. This is because the grammar doesn't consider them builtin types. --- book/src/generated/lang-support.md | 1 + languages.toml | 14 ++ runtime/queries/vhdl/highlights.scm | 338 ++++++++++++++++++++++++++++ 3 files changed, 353 insertions(+) create mode 100644 runtime/queries/vhdl/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 3c18956ae..524c2adf6 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -145,6 +145,7 @@ | v | ✓ | ✓ | ✓ | `v` | | vala | ✓ | | | `vala-language-server` | | verilog | ✓ | ✓ | | `svlangserver` | +| vhdl | ✓ | | | `vhdl_ls` | | vhs | ✓ | | | | | vue | ✓ | | | `vls` | | wast | ✓ | | | | diff --git a/languages.toml b/languages.toml index a56de1f4b..f6a54e872 100644 --- a/languages.toml +++ b/languages.toml @@ -2369,3 +2369,17 @@ language-server = { command = "cs", args = ["launch", "com.disneystreaming.smith [[grammar]] name = "smithy" source = { git = "https://github.com/indoorvivants/tree-sitter-smithy", rev = "cf8c7eb9faf7c7049839585eac19c94af231e6a0" } + +[[language]] +name = "vhdl" +scope = "source.vhdl" +file-types = ["vhd", "vhdl"] +roots = [] +comment-token = "--" +language-server = { command = "vhdl_ls", args = [] } +indent = { tab-width = 2, unit = " " } +injection-regex = "vhdl" + +[[grammar]] +name = "vhdl" +source = { git = "https://github.com/teburd/tree-sitter-vhdl", rev = "c57313adee2231100db0a7880033f6865deeadb2" } diff --git a/runtime/queries/vhdl/highlights.scm b/runtime/queries/vhdl/highlights.scm new file mode 100644 index 000000000..59cef41cd --- /dev/null +++ b/runtime/queries/vhdl/highlights.scm @@ -0,0 +1,338 @@ +(comment) @comment + +; Keywords +[ + ; vhdl 08 + "abs" + "access" + "after" + "alias" + "all" + "and" + "architecture" + "array" + "assert" + "attribute" + "begin" + "block" + "body" + "buffer" + "bus" + "case" + "component" + "configuration" + "constant" + "disconnect" + "downto" + "else" + "elsif" + "end" + "entity" + "exit" + "file" + "for" + "function" + "generic" + "group" + "guarded" + "if" + "impure" + "in" + "inertial" + "inout" + "is" + "label" + "library" + "linkage" + "literal" + "loop" + "map" + "mod" + "nand" + "new" + "next" + "nor" + "not" + "null" + "of" + "on" + "open" + "or" + "others" + "out" + "package" + "port" + "postponed" + "procedure" + "process" + "protected" + "pure" + "range" + "record" + "register" + "reject" + "rem" + "report" + "return" + "rol" + "ror" + "select" + "severity" + "shared" + "signal" + "sla" + "sll" + "sra" + "srl" + "subtype" + "then" + "to" + "transport" + "type" + "unaffected" + "units" + "until" + "use" + "variable" + "wait" + "when" + "while" + "with" + "xnor" + "xor" + ; vhdl 08 + "context" + "force" + "property" + "release" + "sequence" +] @keyword + +[ + ; vhdl 02 + "boolean" + "bit" + "bit_vector" + ;"character" + ;"severity_level" + ;"integer" + ;"real" + ;"time" + ;"natural" + ;"positive" + "string" + ;"line" + ;"text" + ;"side" + ;"unsigned" + ;"signed" + ;"delay_length" + ;"file_open_kind" + ;"file_open_status" + ;"std_logic" + ;"std_logic_vector" + ;"std_ulogic" + ;"std_ulogic_vector" + ; vhdl 08 + ;"boolean_vector" + ;"integer_vector" + ;"real_vector" + ;"time_vector" + ; math types + ;"complex" + ;"complex_polar" + ;"positive_real" + ;"principal_value" +] @type.builtin + +[ + ; vhdl 02 + "base" + "left" + "right" + "high" + "low" + "pos" + "val" + "succ" + "pred" + "leftof" + "rightof" + "range" + "reverse_range" + "length" + "delayed" + "stable" + "quiet" + "transaction" + "event" + "active" + "last_event" + "last_active" + "last_value" + "driving" + "driving_value" + "ascending" + "value" + "image" + "simple_name" + "instance_name" + "path_name" + ;"foreign" + ; vhdl 08 + "instance_name" + "path_name" +] @attribute + +;[ + ; vhdl 02 + ;"now" + ;"resolved" + ;"rising_edge" + ;"falling_edge" + ;"read" + ;"readline" + ;"hread" + ;"oread" + ;"write" + ;"writeline" + ;"hwrite" + ;"owrite" + ;"endfile" + ;"resize" + ;"is_X" + ;"std_match" + ;"shift_left" + ;"shift_right" + ;"rotate_left" + ;"rotate_right" + ;"to_unsigned" + ;"to_signed" + ;"to_integer" + ;"to_stdLogicVector" + ;"to_stdULogic" + ;"to_stdULogicVector" + ;"to_bit" + ;"to_bitVector" + ;"to_X01" + ;"to_X01Z" + ;"to_UX01" + ;"to_01" + ;"conv_unsigned" + ;"conv_signed" + ;"conv_integer" + ;"conv_std_logic_vector" + ;"shl" + ;"shr" + ;"ext" + ;"sxt" + ;"deallocate" + ; vhdl 08 + ;"finish" + ;"flush" + ;"justify" + ;"maximum" + ;"minimum" + ;"resolution_limit" + ;"stop" + ;"swrite" + ;"tee" + ;"to_binarystring" + ;"to_bstring" + ;"to_hexstring" + ;"to_hstring" + ;"to_octalstring" + ;"to_ostring" + ;"to_string" + ; vhdl math + ;"arccos" + ;"arccosh" + ;"arcsin" + ;"arcsinh" + ;"arctan" + ;"arctanh" + ;"arg" + ;"cbrt" + ;"ceil" + ;"cmplx" + ;"complex_to_polar" + ;"conj" + ;"cos" + ;"cosh" + ;"exp" + ;"floor" + ;"get_principal_value" + ;"log" + ;"log10" + ;"log2" + ;"polar_to_complex" + ;"realmax" + ;"realmin" + ;"round" + ;"sign" + ;"sin" + ;"sinh" + ;"sqrt" + ;"tan" + ;"tanh" + ;"trunc" + ;"uniform" +;] @function.builtin + +; Operators +[ + "+" + "-" + "*" + "/" + "**" + "abs" + "not" + "mod" + "rem" + "&" + "sll" + "srl" + "sla" + "sra" + "rol" + "ror" + "=" + "/=" + "?=" + "?/=" + "?<" + "?<=" + "?>" + "?>=" + "<" + "<=" + ">" + ">=" + "and" + "or" + "nand" + "nor" + "xor" + "xnor" + ":=" + "<=" + "??" +] @operator + +[ + ";" + "," +] @punctuation.delimiter + +[ + "(" + ")" + "'" +] @punctuation.bracket + +(full_type_declaration "type" name: (identifier) @type) +(signal_declaration "signal" (identifier_list) @variable) +(variable_declaration "variable" (identifier_list) @variable) +(constant_declaration "constant" (identifier_list) @variable) + From abef92a9b341209aeae8802d30fc8c1f971a43df Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Sun, 26 Mar 2023 11:44:07 +0200 Subject: [PATCH 006/260] log failures in the git integration (#6441) --- Cargo.lock | 1 + helix-vcs/Cargo.toml | 1 + helix-vcs/src/git.rs | 55 ++++++++++++++++++++++++--------------- helix-vcs/src/git/test.rs | 12 ++++----- helix-vcs/src/lib.rs | 31 ++++++++++++++++------ 5 files changed, 65 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c86b5aac0..0bef317e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1220,6 +1220,7 @@ dependencies = [ name = "helix-vcs" version = "0.6.0" dependencies = [ + "anyhow", "arc-swap", "gix", "helix-core", diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml index 5ad6c91b7..b32c028bd 100644 --- a/helix-vcs/Cargo.toml +++ b/helix-vcs/Cargo.toml @@ -19,6 +19,7 @@ arc-swap = { version = "1.6.0" } gix = { version = "0.41.0", default-features = false , optional = true } imara-diff = "0.1.5" +anyhow = "1" log = "0.4" diff --git a/helix-vcs/src/git.rs b/helix-vcs/src/git.rs index 1732bdd0d..00a2c596d 100644 --- a/helix-vcs/src/git.rs +++ b/helix-vcs/src/git.rs @@ -1,3 +1,4 @@ +use anyhow::{bail, Context, Result}; use arc_swap::ArcSwap; use std::path::Path; use std::sync::Arc; @@ -14,7 +15,7 @@ mod test; pub struct Git; impl Git { - fn open_repo(path: &Path, ceiling_dir: Option<&Path>) -> Option { + fn open_repo(path: &Path, ceiling_dir: Option<&Path>) -> Result { // custom open options let mut git_open_opts_map = gix::sec::trust::Mapping::::default(); @@ -45,26 +46,31 @@ impl Git { open_options.ceiling_dirs = vec![ceiling_dir.to_owned()]; } - ThreadSafeRepository::discover_with_environment_overrides_opts( + let res = ThreadSafeRepository::discover_with_environment_overrides_opts( path, open_options, git_open_opts_map, - ) - .ok() + )?; + + Ok(res) } } impl DiffProvider for Git { - fn get_diff_base(&self, file: &Path) -> Option> { + fn get_diff_base(&self, file: &Path) -> Result> { debug_assert!(!file.exists() || file.is_file()); debug_assert!(file.is_absolute()); // TODO cache repository lookup - let repo = Git::open_repo(file.parent()?, None)?.to_thread_local(); - let head = repo.head_commit().ok()?; + + let repo_dir = file.parent().context("file has no parent directory")?; + let repo = Git::open_repo(repo_dir, None) + .context("failed to open git repo")? + .to_thread_local(); + let head = repo.head_commit()?; let file_oid = find_file_in_commit(&repo, &head, file)?; - let file_object = repo.find_object(file_oid).ok()?; + let file_object = repo.find_object(file_oid)?; let mut data = file_object.detach().data; // convert LF to CRLF if configured to avoid showing every line as changed if repo @@ -87,35 +93,42 @@ impl DiffProvider for Git { } data = normalized_file } - Some(data) + Ok(data) } - fn get_current_head_name(&self, file: &Path) -> Option>>> { + fn get_current_head_name(&self, file: &Path) -> Result>>> { debug_assert!(!file.exists() || file.is_file()); debug_assert!(file.is_absolute()); - let repo = Git::open_repo(file.parent()?, None)?.to_thread_local(); - let head_ref = repo.head_ref().ok()?; - let head_commit = repo.head_commit().ok()?; + let repo_dir = file.parent().context("file has no parent directory")?; + let repo = Git::open_repo(repo_dir, None) + .context("failed to open git repo")? + .to_thread_local(); + let head_ref = repo.head_ref()?; + let head_commit = repo.head_commit()?; let name = match head_ref { Some(reference) => reference.name().shorten().to_string(), None => head_commit.id.to_hex_with_len(8).to_string(), }; - Some(Arc::new(ArcSwap::from_pointee(name.into_boxed_str()))) + Ok(Arc::new(ArcSwap::from_pointee(name.into_boxed_str()))) } } /// Finds the object that contains the contents of a file at a specific commit. -fn find_file_in_commit(repo: &Repository, commit: &Commit, file: &Path) -> Option { - let repo_dir = repo.work_dir()?; - let rel_path = file.strip_prefix(repo_dir).ok()?; - let tree = commit.tree().ok()?; - let tree_entry = tree.lookup_entry_by_path(rel_path).ok()??; +fn find_file_in_commit(repo: &Repository, commit: &Commit, file: &Path) -> Result { + let repo_dir = repo.work_dir().context("repo has no worktree")?; + let rel_path = file.strip_prefix(repo_dir)?; + let tree = commit.tree()?; + let tree_entry = tree + .lookup_entry_by_path(rel_path)? + .context("file is untracked")?; match tree_entry.mode() { // not a file, everything is new, do not show diff - EntryMode::Tree | EntryMode::Commit | EntryMode::Link => None, + mode @ (EntryMode::Tree | EntryMode::Commit | EntryMode::Link) => { + bail!("entry at {} is not a file but a {mode:?}", file.display()) + } // found a file - EntryMode::Blob | EntryMode::BlobExecutable => Some(tree_entry.object_id()), + EntryMode::Blob | EntryMode::BlobExecutable => Ok(tree_entry.object_id()), } } diff --git a/helix-vcs/src/git/test.rs b/helix-vcs/src/git/test.rs index 6b1aba7f5..9c67d2c33 100644 --- a/helix-vcs/src/git/test.rs +++ b/helix-vcs/src/git/test.rs @@ -54,7 +54,7 @@ fn missing_file() { let file = temp_git.path().join("file.txt"); File::create(&file).unwrap().write_all(b"foo").unwrap(); - assert_eq!(Git.get_diff_base(&file), None); + assert!(Git.get_diff_base(&file).is_err()); } #[test] @@ -64,7 +64,7 @@ fn unmodified_file() { let contents = b"foo".as_slice(); File::create(&file).unwrap().write_all(contents).unwrap(); create_commit(temp_git.path(), true); - assert_eq!(Git.get_diff_base(&file), Some(Vec::from(contents))); + assert_eq!(Git.get_diff_base(&file).unwrap(), Vec::from(contents)); } #[test] @@ -76,7 +76,7 @@ fn modified_file() { create_commit(temp_git.path(), true); File::create(&file).unwrap().write_all(b"bar").unwrap(); - assert_eq!(Git.get_diff_base(&file), Some(Vec::from(contents))); + assert_eq!(Git.get_diff_base(&file).unwrap(), Vec::from(contents)); } /// Test that `get_file_head` does not return content for a directory. @@ -95,7 +95,7 @@ fn directory() { std::fs::remove_dir_all(&dir).unwrap(); File::create(&dir).unwrap().write_all(b"bar").unwrap(); - assert_eq!(Git.get_diff_base(&dir), None); + assert!(Git.get_diff_base(&dir).is_err()); } /// Test that `get_file_head` does not return content for a symlink. @@ -116,6 +116,6 @@ fn symlink() { symlink("file.txt", &file_link).unwrap(); create_commit(temp_git.path(), true); - assert_eq!(Git.get_diff_base(&file_link), None); - assert_eq!(Git.get_diff_base(&file), Some(Vec::from(contents))); + assert!(Git.get_diff_base(&file_link).is_err()); + assert_eq!(Git.get_diff_base(&file).unwrap(), Vec::from(contents)); } diff --git a/helix-vcs/src/lib.rs b/helix-vcs/src/lib.rs index 6f5e40d0c..4d3a3623b 100644 --- a/helix-vcs/src/lib.rs +++ b/helix-vcs/src/lib.rs @@ -1,3 +1,4 @@ +use anyhow::{bail, Result}; use arc_swap::ArcSwap; use std::{path::Path, sync::Arc}; @@ -18,19 +19,19 @@ pub trait DiffProvider { /// if this provider is used. /// The data is returned as raw byte without any decoding or encoding performed /// to ensure all file encodings are handled correctly. - fn get_diff_base(&self, file: &Path) -> Option>; - fn get_current_head_name(&self, file: &Path) -> Option>>>; + fn get_diff_base(&self, file: &Path) -> Result>; + fn get_current_head_name(&self, file: &Path) -> Result>>>; } #[doc(hidden)] pub struct Dummy; impl DiffProvider for Dummy { - fn get_diff_base(&self, _file: &Path) -> Option> { - None + fn get_diff_base(&self, _file: &Path) -> Result> { + bail!("helix was compiled without git support") } - fn get_current_head_name(&self, _file: &Path) -> Option>>> { - None + fn get_current_head_name(&self, _file: &Path) -> Result>>> { + bail!("helix was compiled without git support") } } @@ -42,13 +43,27 @@ impl DiffProviderRegistry { pub fn get_diff_base(&self, file: &Path) -> Option> { self.providers .iter() - .find_map(|provider| provider.get_diff_base(file)) + .find_map(|provider| match provider.get_diff_base(file) { + Ok(res) => Some(res), + Err(err) => { + log::error!("{err:#?}"); + log::error!("failed to open diff base for {}", file.display()); + None + } + }) } pub fn get_current_head_name(&self, file: &Path) -> Option>>> { self.providers .iter() - .find_map(|provider| provider.get_current_head_name(file)) + .find_map(|provider| match provider.get_current_head_name(file) { + Ok(res) => Some(res), + Err(err) => { + log::error!("{err:#?}"); + log::error!("failed to obtain current head name for {}", file.display()); + None + } + }) } } From 5d7c90c5cfd6887fc0a43ee695d91f0166955a64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20C=2E=20M=C3=BCller?= Date: Sun, 26 Mar 2023 17:49:37 -0400 Subject: [PATCH 007/260] Add language support for rego (OpenPolicyAgent) (#6415) --- book/src/generated/lang-support.md | 1 + languages.toml | 15 +++++++ runtime/queries/rego/highlights.scm | 68 +++++++++++++++++++++++++++++ runtime/queries/rego/injections.scm | 2 + 4 files changed, 86 insertions(+) create mode 100644 runtime/queries/rego/highlights.scm create mode 100644 runtime/queries/rego/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 524c2adf6..996bdb435 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -112,6 +112,7 @@ | r | ✓ | | | `R` | | racket | ✓ | | | `racket` | | regex | ✓ | | | | +| rego | ✓ | | | `regols` | | rescript | ✓ | ✓ | | `rescript-language-server` | | rmarkdown | ✓ | | ✓ | `R` | | ron | ✓ | | ✓ | | diff --git a/languages.toml b/languages.toml index f6a54e872..fe94d6999 100644 --- a/languages.toml +++ b/languages.toml @@ -2383,3 +2383,18 @@ injection-regex = "vhdl" [[grammar]] name = "vhdl" source = { git = "https://github.com/teburd/tree-sitter-vhdl", rev = "c57313adee2231100db0a7880033f6865deeadb2" } + +[[language]] +name = "rego" +roots = [] +scope = "source.rego" +injection-regex = "rego" +file-types = ["rego"] +auto-format = true +comment-token = "#" +language-server = { command = "regols" } +grammar = "rego" + +[[grammar]] +name = "rego" +source = { git = "https://github.com/FallenAngel97/tree-sitter-rego", rev = "b2667c975f07b33be3ceb83bea5cfbad88095866" } diff --git a/runtime/queries/rego/highlights.scm b/runtime/queries/rego/highlights.scm new file mode 100644 index 000000000..0ff6de552 --- /dev/null +++ b/runtime/queries/rego/highlights.scm @@ -0,0 +1,68 @@ +[ + (import) +] @keyword.control.import + +[ + (package) +] @namespace + +[ + (with) + (as) + (every) + (some) + (in) + (default) + "null" +] @keyword.control + +[ + (not) + (if) + (contains) + (else) +] @keyword.control.conditional + +[ + (boolean) +] @constant.builtin.boolean + +[ + (assignment_operator) + (bool_operator) + (arith_operator) + (bin_operator) +] @operator + +[ + (string) + (raw_string) +] @string + +(term (ref (var))) @variable + +(comment) @comment.line + +(number) @constant.numeric.integer + +(expr_call func_name: (fn_name (var) @function .)) + +(expr_call func_arguments: (fn_args (expr) @variable.parameter)) + +(rule_args (term) @variable.parameter) + +[ + (open_paren) + (close_paren) + (open_bracket) + (close_bracket) + (open_curly) + (close_curly) +] @punctuation.bracket + +(rule (rule_head (var) @function.method)) + +(rule + (rule_head (term (ref (var) @namespace))) + (rule_body (query (literal (expr (expr_infix (expr (term (ref (var)) @_output)))))) (#eq? @_output @namespace)) +) diff --git a/runtime/queries/rego/injections.scm b/runtime/queries/rego/injections.scm new file mode 100644 index 000000000..321c90add --- /dev/null +++ b/runtime/queries/rego/injections.scm @@ -0,0 +1,2 @@ +((comment) @injection.content + (#set! injection.language "comment")) From c8fde8b6f99b07faca7e6f93162d887ee132e0f6 Mon Sep 17 00:00:00 2001 From: JJ Date: Sun, 26 Mar 2023 15:06:48 -0700 Subject: [PATCH 008/260] Initial Nim language support (#6123) --- book/src/generated/lang-support.md | 1 + languages.toml | 23 ++ runtime/queries/nim/highlights.scm | 315 ++++++++++++++++++++++++++++ runtime/queries/nim/indents.scm | 54 +++++ runtime/queries/nim/textobjects.scm | 19 ++ 5 files changed, 412 insertions(+) create mode 100644 runtime/queries/nim/highlights.scm create mode 100644 runtime/queries/nim/indents.scm create mode 100644 runtime/queries/nim/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 996bdb435..5cd0c8c1f 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -88,6 +88,7 @@ | msbuild | ✓ | | ✓ | | | nasm | ✓ | ✓ | | | | nickel | ✓ | | ✓ | `nls` | +| nim | ✓ | ✓ | ✓ | `nimlangserver` | | nix | ✓ | | | `nil` | | nu | ✓ | | | | | ocaml | ✓ | | ✓ | `ocamllsp` | diff --git a/languages.toml b/languages.toml index fe94d6999..ae4135f00 100644 --- a/languages.toml +++ b/languages.toml @@ -2398,3 +2398,26 @@ grammar = "rego" [[grammar]] name = "rego" source = { git = "https://github.com/FallenAngel97/tree-sitter-rego", rev = "b2667c975f07b33be3ceb83bea5cfbad88095866" } + +[[language]] +name = "nim" +scope = "source.nim" +injection-regex = "nim" +file-types = ["nim", "nims", "nimble"] +shebangs = [] +roots = [] +comment-token = "#" +indent = { tab-width = 2, unit = " " } +language-server = { command = "nimlangserver" } + +[language.auto-pairs] +'(' = ')' +'[' = ']' +'"' = '"' +"'" = "'" +'{' = '}' + +# Nim's tree-sitter grammar is in heavy development. +[[grammar]] +name = "nim" +source = { git = "https://github.com/aMOPel/tree-sitter-nim", rev = "240239b232550e431d67de250d1b5856209e7f06" } diff --git a/runtime/queries/nim/highlights.scm b/runtime/queries/nim/highlights.scm new file mode 100644 index 000000000..1d3256853 --- /dev/null +++ b/runtime/queries/nim/highlights.scm @@ -0,0 +1,315 @@ +;; Constants, Comments, and Literals + +(comment) @comment.line +(multilineComment) @comment.block +(docComment) @comment.block.documentation +(multilineDocComment) @comment.block.documentation +; comments + +[(literal) (generalizedLit)] @constant +[(nil_lit)] @constant.builtin +[(bool_lit)] @constant.builtin.boolean +[(char_lit)] @constant.character +[(char_esc_seq) (str_esc_seq)] @constant.character.escape +[(custom_numeric_lit)] @constant.numeric +[(int_lit) (int_suffix)] @constant.numeric.integer +[(float_lit) (float_suffix)] @constant.numeric.float +; literals +; note: somewhat irritatingly for testing, lits have the same syntax highlighting as types + +[ + (str_lit) + (triplestr_lit) + (rstr_lit) + (generalized_str_lit) + (generalized_triplestr_lit) + (interpolated_str_lit) + (interpolated_triplestr_lit) +] @string +; [] @string.regexp +; string literals + +[ + "." + "," + ";" + ":" +] @punctuation.delimiter +[ + "(" + ")" + "[" + "]" + "{" + "}" + "{." + ".}" + "#[" + "]#" +] @punctuation.bracket +(interpolated_str_lit "&" @punctuation.special) +(interpolated_str_lit "{" @punctuation.special) +(interpolated_str_lit "}" @punctuation.special) +; punctuation + +[ + "and" + "or" + "xor" + "not" + "in" + "notin" + "is" + "isnot" + "div" + "mod" + "shl" + "shr" +] @keyword.operator +; operators: we list them explicitly to deliminate them from symbolic operators + +[(operator) (opr) "="] @operator +; all operators (must come after @keyword.operator) + +(pragma) @attribute +; pragmas + + +;; Imports and Exports + +(importStmt + (keyw) @keyword.control.import + (expr (primary (symbol) @namespace))? + (expr (primary (arrayConstr (exprColonExprList (exprColonExpr (expr (primary (symbol) @namespace)))))))?) +(exportStmt + (keyw) @keyword.control.import + (expr (primary (symbol) @namespace))? + (expr (primary (arrayConstr (exprColonExprList (exprColonExpr (expr (primary (symbol) @namespace)))))))?) +(fromStmt + (keyw) @keyword.control.import + (expr (primary (symbol) @namespace))? + (expr (primary (arrayConstr (exprColonExprList (exprColonExpr (expr (primary (symbol) @namespace)))))))?) +(includeStmt + (keyw) @keyword.control.import + (expr (primary (symbol) @namespace))? + (expr (primary (arrayConstr (exprColonExprList (exprColonExpr (expr (primary (symbol) @namespace)))))))?) +(importExceptStmt + (keyw) @keyword.control.import + (expr (primary (symbol) @namespace))? + (expr (primary (arrayConstr (exprColonExprList (exprColonExpr (expr (primary (symbol) @namespace)))))))?) +; import statements +; yeah, this is a bit gross. + + +;; Control Flow + +(ifStmt (keyw) @keyword.control.conditional) +(whenStmt (keyw) @keyword.control.conditional) +(elifStmt (keyw) @keyword.control.conditional) +(elseStmt (keyw) @keyword.control.conditional) +(caseStmt (keyw) @keyword.control.conditional) +(ofBranch (keyw) @keyword.control.conditional) +(inlineIfStmt (keyw) @keyword.control.conditional) +(inlineWhenStmt (keyw) @keyword.control.conditional) +; conditional statements +; todo: do block + +(forStmt + . (keyw) @keyword.control.repeat + . (symbol) @variable + . (keyw) @keyword.control.repeat) +(whileStmt (keyw) @keyword.control.repeat) +; loop statements + +(returnStmt (keyw) @keyword.control.repeat) +(yieldStmt (keyw) @keyword.control.repeat) +(discardStmt (keyw) @keyword.control.repeat) +(breakStmt (keyw) @keyword.control.repeat) +(continueStmt (keyw) @keyword.control.repeat) +; control flow statements + +(raiseStmt (keyw) @keyword.control.exception) +(tryStmt (keyw) @keyword.control.exception) +(tryExceptStmt (keyw) @keyword.control.exception) +(tryFinallyStmt (keyw) @keyword.control.exception) +(inlineTryStmt (keyw) @keyword.control.exception) +; (inlineTryExceptStmt (keyw) @keyword.control.exception) +; (inlineTryFinallyStmt (keyw) @keyword.control.exception) +; exception handling statements + +(staticStmt (keyw) @keyword) +(deferStmt (keyw) @keyword) +(asmStmt (keyw) @keyword) +(bindStmt (keyw) @keyword) +(mixinStmt (keyw) @keyword) +; miscellaneous blocks + +(blockStmt + (keyw) @keyword.control + (symbol) @label) +; block statements + + +;; Types and Type Declarations + +(typeDef + (keyw) @keyword.storage.type + (symbol) @type) +; names of new types type declarations + +(exprColonEqExpr + . (expr (primary (symbol) @variable)) + . (expr (primary (symbol) @type))) +; variables in inline tuple declarations + +(primarySuffix + (indexSuffix + (exprColonEqExprList + (exprColonEqExpr + (expr + (primary + (symbol) @type)))))) +; nested types in brackets, i.e. seq[string] + +(primaryTypeDef (symbol) @type) +; primary types of type declarations (NOT nested types) + +(primaryTypeDef (primaryPrefix (keyw) @type)) +; for consistency + +(primaryTypeDesc (symbol) @type) +; type annotations, on declarations or in objects + +(primaryTypeDesc (primaryPrefix (keyw) @type)) +; var types etc + +(genericParamList (genericParam (symbol) @type)) +; types in generic blocks + +(enumDecl (keyw) @keyword.storage.type) +(enumElement (symbol) @type.enum.variant) +; enum declarations and elements + +(tupleDecl (keyw) @keyword.storage.type) +; tuple declarations + +(objectDecl (keyw) @keyword.storage.type) +(objectPart (symbol) @variable.other.member) +; object declarations and fields + +(objectCase + (keyw) @keyword.control.conditional + (symbol) @variable.other.member) +(objectBranch (keyw) @keyword.control.conditional) +(objectElif (keyw) @keyword.control.conditional) +(objectElse (keyw) @keyword.control.conditional) +(objectWhen (keyw) @keyword.control.conditional) +; variant objects + +(conceptDecl (keyw) @keyword.storage.type) +(conceptParam (keyw) @type) +(conceptParam (symbol) @variable) +; concept declarations, parameters, and qualifiers on those parameters + +((expr + (primary (symbol)) + (operator) @operator + (primary (symbol) @type)) + (#match? @operator "is")) +((exprStmt + (primary (symbol)) + (operator) @operator + (primary (symbol) @type)) + (#match? @operator "is")) +; symbols likely to be types: "x is t" means t is either a type or a type variable + +; distinct? + + +;; Functions + +(routine + . (keyw) @keyword.function + . (symbol) @function) +; function declarations + +(routineExpr (keyw) @keyword.function) +; discarded function + +(routineExprTypeDesc (keyw) @keyword.function) +; function declarations as types + +(primary + . (symbol) @function.call + . (primarySuffix (functionCall))) +; regular function calls + +(primary + . (symbol) @function.call + . (primarySuffix (cmdCall))) +; function calls without parenthesis + +(primary + (primarySuffix (qualifiedSuffix (symbol) @function.call)) + . (primarySuffix (functionCall))) +; uniform function call syntax calls + +(primary + (primarySuffix (qualifiedSuffix (symbol) @function.call)) + . (primarySuffix (cmdCall))) +; just in case + +(primary + (symbol) @constructor + (primarySuffix (objectConstr))) +; object constructor + +; does not appear to be a way to distinguish these without verbatium matching +; [] @function.builtin +; [] @function.method +; [] @function.macro +; [] @function.special + + +;; Variables + +(paramList (paramColonEquals (symbol) @variable.parameter)) +; parameter identifiers + +(identColon (ident) @variable.other.member) +; named parts of tuples + +(symbolColonExpr (symbol) @variable) +; object constructor parameters + +(symbolEqExpr (symbol) @variable) +; named parameters + +(variable + (keyw) @keyword.storage.type + (declColonEquals (symbol) @variable)) +; let, var, const expressions + +((primary (symbol) @variable.builtin) + (#match? @variable.builtin "result")) +; `result` is an implicit builtin variable inside function scopes + +((primary (symbol) @type) + (#match? @type "^[A-Z]")) +; assume PascalCase identifiers to be types + +((primary + (primarySuffix + (qualifiedSuffix + (symbol) @type))) + (#match? @type "^[A-Z]")) +; assume PascalCase member variables to be enum entries + +(primary (symbol) @variable) +; overzealous, matches variables + +(primary (primarySuffix (qualifiedSuffix (symbol) @variable.other.member))) +; overzealous, matches member variables: i.e. x in foo.x + +(keyw) @keyword +; more specific matches are done above whenever possible diff --git a/runtime/queries/nim/indents.scm b/runtime/queries/nim/indents.scm new file mode 100644 index 000000000..677435407 --- /dev/null +++ b/runtime/queries/nim/indents.scm @@ -0,0 +1,54 @@ +[ + (typeDef) + (ifStmt) + (whenStmt) + (elifStmt) + (elseStmt) + (ofBranch) ; note: not caseStmt + (whileStmt) + (tryStmt) + (tryExceptStmt) + (tryFinallyStmt) + (forStmt) + (blockStmt) + (staticStmt) + (deferStmt) + (asmStmt) + ; exprStmt? +] @indent +;; increase the indentation level + +[ + (ifStmt) + (whenStmt) + (elifStmt) + (elseStmt) + (ofBranch) ; note: not caseStmt + (whileStmt) + (tryStmt) + (tryExceptStmt) + (tryFinallyStmt) + (forStmt) + (blockStmt) + (staticStmt) + (deferStmt) + (asmStmt) + ; exprStmt? +] @extend +;; ??? + +[ + (returnStmt) + (raiseStmt) + (yieldStmt) + (breakStmt) + (continueStmt) +] @extend.prevent-once +;; end a level of indentation while staying indented + +[ + ")" ; tuples + "]" ; arrays, seqs + "}" ; sets +] @outdent +;; end a level of indentation and unindent the line diff --git a/runtime/queries/nim/textobjects.scm b/runtime/queries/nim/textobjects.scm new file mode 100644 index 000000000..943aa7f08 --- /dev/null +++ b/runtime/queries/nim/textobjects.scm @@ -0,0 +1,19 @@ +(routine + (block) @function.inside) @function.around + +; @class.inside (types?) +; @class.around + +; paramListSuffix is strange and i do not understand it +(paramList + (paramColonEquals) @parameter.inside) @parameter.around + +(comment) @comment.inside +(multilineComment) @comment.inside +(docComment) @comment.inside +(multilineDocComment) @comment.inside + +(comment)+ @comment.around +(multilineComment) @comment.around +(docComment)+ @comment.around +(multilineDocComment) @comment.around From 0ab96cc2576cf8d78d54bcc42e0e7f5285321030 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Wed, 22 Mar 2023 18:41:56 +0100 Subject: [PATCH 009/260] remove incorrect assert This assert was added during early development of #5420 and makes no sense with the current code. We simply forgot to remove it. --- helix-term/src/ui/document.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/helix-term/src/ui/document.rs b/helix-term/src/ui/document.rs index d41762649..39c209505 100644 --- a/helix-term/src/ui/document.rs +++ b/helix-term/src/ui/document.rs @@ -175,7 +175,6 @@ pub fn render_text<'t>( text_annotations, ); row_off += offset.vertical_offset; - assert_eq!(0, offset.vertical_offset); let (mut formatter, mut first_visible_char_idx) = DocumentFormatter::new_at_prev_checkpoint(text, text_fmt, text_annotations, offset.anchor); From 72b93116784ec944f49c7f6a335b0aa663f1430e Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Mon, 6 Mar 2023 16:25:41 +0100 Subject: [PATCH 010/260] fix view anchors not at start of a visual line The top of a view is marked by a char idx anchor. That char idx is usually the first character of the visual line it's on. We use a char index instead of a line index because the view may start in the middle of a line with soft wrapping. However, it's possible to temporarily endup in a state where this anchor is not the first character of the first visual line. This is pretty rare because edits usually happen inside/after the view. In most cases we handle this case correctly. However, if the cursor is before the anchor (but still in view) there can be crashes or visual artifacts. This is caused by the fact that visual_offset_from_anchor (and the positioning code in view.rs) incorrectly assumed that the (cursor) position is always after the view anchor if the cursor is in view. But if the anchor is not the first character of the first visual line this is not the case anymore. In that case crashes and visual artifacts are possible. This commit fixes that problem by changing `visual_offset_from_anchor` (and callsites) to properly consider that case. --- helix-core/src/lib.rs | 2 +- helix-core/src/position.rs | 40 ++++++++++++++++---- helix-view/src/view.rs | 76 +++++++++++++++++++------------------- 3 files changed, 70 insertions(+), 48 deletions(-) diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index e3f862a60..4d50e48bf 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -98,7 +98,7 @@ pub use {regex, tree_sitter}; pub use graphemes::RopeGraphemes; pub use position::{ char_idx_at_visual_offset, coords_at_pos, pos_at_coords, visual_offset_from_anchor, - visual_offset_from_block, Position, + visual_offset_from_block, Position, VisualOffsetError, }; #[allow(deprecated)] pub use position::{pos_at_visual_coords, visual_coords_at_pos}; diff --git a/helix-core/src/position.rs b/helix-core/src/position.rs index 7b8dc326e..c3233a340 100644 --- a/helix-core/src/position.rs +++ b/helix-core/src/position.rs @@ -137,6 +137,12 @@ pub fn visual_offset_from_block( (last_pos, block_start) } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum VisualOffsetError { + PosBeforeAnchorRow, + PosAfterMaxRow, +} + /// Returns the visual offset from the start of the visual line /// that contains anchor. pub fn visual_offset_from_anchor( @@ -146,28 +152,46 @@ pub fn visual_offset_from_anchor( text_fmt: &TextFormat, annotations: &TextAnnotations, max_rows: usize, -) -> Option<(Position, usize)> { +) -> Result<(Position, usize), VisualOffsetError> { let (formatter, block_start) = DocumentFormatter::new_at_prev_checkpoint(text, text_fmt, annotations, anchor); let mut char_pos = block_start; let mut anchor_line = None; + let mut found_pos = None; let mut last_pos = Position::default(); + if pos < block_start { + return Err(VisualOffsetError::PosBeforeAnchorRow); + } + for (grapheme, vpos) in formatter { last_pos = vpos; char_pos += grapheme.doc_chars(); - if char_pos > anchor && anchor_line.is_none() { - anchor_line = Some(last_pos.row); - } if char_pos > pos { - last_pos.row -= anchor_line.unwrap(); - return Some((last_pos, block_start)); + if let Some(anchor_line) = anchor_line { + last_pos.row -= anchor_line; + return Ok((last_pos, block_start)); + } else { + found_pos = Some(last_pos); + } + } + if char_pos > anchor && anchor_line.is_none() { + if let Some(mut found_pos) = found_pos { + return if found_pos.row == last_pos.row { + found_pos.row = 0; + Ok((found_pos, block_start)) + } else { + Err(VisualOffsetError::PosBeforeAnchorRow) + }; + } else { + anchor_line = Some(last_pos.row); + } } if let Some(anchor_line) = anchor_line { if vpos.row >= anchor_line + max_rows { - return None; + return Err(VisualOffsetError::PosAfterMaxRow); } } } @@ -175,7 +199,7 @@ pub fn visual_offset_from_anchor( let anchor_line = anchor_line.unwrap_or(last_pos.row); last_pos.row -= anchor_line; - Some((last_pos, block_start)) + Ok((last_pos, block_start)) } /// Convert (line, column) coordinates to a character index. diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 0ac7ca3b1..ee6fc1275 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -7,9 +7,13 @@ use crate::{ }; use helix_core::{ - char_idx_at_visual_offset, doc_formatter::TextFormat, syntax::Highlight, - text_annotations::TextAnnotations, visual_offset_from_anchor, visual_offset_from_block, - Position, RopeSlice, Selection, Transaction, + char_idx_at_visual_offset, + doc_formatter::TextFormat, + syntax::Highlight, + text_annotations::TextAnnotations, + visual_offset_from_anchor, visual_offset_from_block, Position, RopeSlice, Selection, + Transaction, + VisualOffsetError::{PosAfterMaxRow, PosBeforeAnchorRow}, }; use std::{ @@ -213,46 +217,38 @@ impl View { // - 1 so we have at least one gap in the middle. // a height of 6 with padding of 3 on each side will keep shifting the view back and forth // as we type - let scrolloff = scrolloff.min(viewport.height.saturating_sub(1) as usize / 2); + let scrolloff = if CENTERING { + 0 + } else { + scrolloff.min(viewport.height.saturating_sub(1) as usize / 2) + }; let cursor = doc.selection(self.id).primary().cursor(doc_text); let mut offset = self.offset; + let off = visual_offset_from_anchor( + doc_text, + offset.anchor, + cursor, + &text_fmt, + &annotations, + vertical_viewport_end, + ); - let (visual_off, mut at_top) = if cursor >= offset.anchor { - let off = visual_offset_from_anchor( - doc_text, - offset.anchor, - cursor, - &text_fmt, - &annotations, - vertical_viewport_end, - ); - (off, false) - } else if CENTERING { - // cursor out of view - return None; - } else { - (None, true) - }; - - let new_anchor = match visual_off { - Some((visual_pos, _)) if visual_pos.row < scrolloff + offset.vertical_offset => { - if CENTERING && visual_pos.row < offset.vertical_offset { + let (new_anchor, at_top) = match off { + Ok((visual_pos, _)) if visual_pos.row < scrolloff + offset.vertical_offset => { + if CENTERING { // cursor out of view return None; } - at_top = true; - true + (true, true) } - Some((visual_pos, _)) if visual_pos.row + scrolloff + 1 >= vertical_viewport_end => { - if CENTERING && visual_pos.row >= vertical_viewport_end { - // cursor out of view - return None; - } - true + Ok((visual_pos, _)) if visual_pos.row + scrolloff >= vertical_viewport_end => { + (true, false) } - Some(_) => false, - None => true, + Ok((_, _)) => (false, false), + Err(_) if CENTERING => return None, + Err(PosBeforeAnchorRow) => (true, true), + Err(PosAfterMaxRow) => (true, false), }; if new_anchor { @@ -269,8 +265,8 @@ impl View { offset.horizontal_offset = 0; } else { // determine the current visual column of the text - let col = visual_off - .unwrap_or_else(|| { + let col = off + .unwrap_or_else(|_| { visual_offset_from_block( doc_text, offset.anchor, @@ -360,8 +356,9 @@ impl View { ); match pos { - Some((Position { row, .. }, _)) => row.saturating_sub(self.offset.vertical_offset), - None => visual_height.saturating_sub(1), + Ok((Position { row, .. }, _)) => row.saturating_sub(self.offset.vertical_offset), + Err(PosAfterMaxRow) => visual_height.saturating_sub(1), + Err(PosBeforeAnchorRow) => 0, } } @@ -390,7 +387,8 @@ impl View { &text_fmt, &annotations, viewport.height as usize, - )? + ) + .ok()? .0; if pos.row < self.offset.vertical_offset { return None; From 7cf448eb5bfd604e1342a1d0f5685e3231f6c1a9 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Wed, 22 Mar 2023 18:38:32 +0100 Subject: [PATCH 011/260] use partition_point instead of binary_search_by Using `partition_point` ensures we always find the first entry. With binary search it is "random" (deterministic but implementation specific) which index is retruned if there are multiple equal elements. `partition_point` was added to the standard library to cover extactly the usecase here. --- helix-core/src/text_annotations.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/helix-core/src/text_annotations.rs b/helix-core/src/text_annotations.rs index 3e48de4d8..e60931845 100644 --- a/helix-core/src/text_annotations.rs +++ b/helix-core/src/text_annotations.rs @@ -1,5 +1,4 @@ use std::cell::Cell; -use std::convert::identity; use std::ops::Range; use std::rc::Rc; @@ -113,9 +112,7 @@ impl Layer { pub fn reset_pos(&self, char_idx: usize, get_char_idx: impl Fn(&A) -> usize) { let new_index = self .annotations - .binary_search_by_key(&char_idx, get_char_idx) - .unwrap_or_else(identity); - + .partition_point(|annot| get_char_idx(annot) < char_idx); self.current_index.set(new_index); } From d6c8e0c946d768abdb2d688cb7cd67683ac51240 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Wed, 22 Mar 2023 16:30:51 +0100 Subject: [PATCH 012/260] allow scrolling past virtual text line Virtual text lines (either caused by softwrapped inlay hints that take multiple or line annotations) currently block scrolling downwards. if the visual offset passed to char_idx_at_visual_offset or visual_offset_from_block is within a virtual text line then the char position before the virtual text and a visual offset are returned. We previously ignored that visual offset and as a result the cursor would be stuck at the start of the virtual text. This commit fixes that by simply moving the cursor to the next char (so past the virtual text) if this visual offset is non-zero --- helix-term/src/commands.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 1c1edece1..d53df831e 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1489,18 +1489,19 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction) { &annotations, ); - let head; + let mut head; match direction { Forward => { - head = char_idx_at_visual_offset( + let off; + (head, off) = char_idx_at_visual_offset( doc_text, view.offset.anchor, (view.offset.vertical_offset + scrolloff) as isize, 0, &text_fmt, &annotations, - ) - .0; + ); + head += (off != 0) as usize; if head <= cursor { return; } From 15e751b9a291b8732468235af95142bfbd0c9be2 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Wed, 22 Mar 2023 16:45:22 +0100 Subject: [PATCH 013/260] make scrolloff calculation consistent While scrolling (with the `scroll`) command scrolloff was calculated slightly differently than in `ensure_cursor_in_view` which could cause the cursor to get stuck while scrolling --- 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 d53df831e..4a7b78839 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1470,7 +1470,7 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction) { let cursor = range.cursor(text); let height = view.inner_height(); - let scrolloff = config.scrolloff.min(height / 2); + let scrolloff = config.scrolloff.min(height.saturating_sub(1) as usize / 2); let offset = match direction { Forward => offset as isize, Backward => -(offset as isize), @@ -1510,7 +1510,7 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction) { head = char_idx_at_visual_offset( doc_text, view.offset.anchor, - (view.offset.vertical_offset + height - scrolloff) as isize, + (view.offset.vertical_offset + height - scrolloff - 1) as isize, 0, &text_fmt, &annotations, From 9fac574178bb6b66675ffc72819a79dee25112df Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Mon, 6 Mar 2023 16:34:54 +0100 Subject: [PATCH 014/260] do not ignore mouse scrolling when on top of virtual text --- helix-term/src/ui/editor.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 0b6ab0465..4cac0fa8b 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -1038,10 +1038,15 @@ impl EditorView { .. } = *event; - let pos_and_view = |editor: &Editor, row, column| { + let pos_and_view = |editor: &Editor, row, column, ignore_virtual_text| { editor.tree.views().find_map(|(view, _focus)| { - view.pos_at_screen_coords(&editor.documents[&view.doc], row, column, true) - .map(|pos| (pos, view.id)) + view.pos_at_screen_coords( + &editor.documents[&view.doc], + row, + column, + ignore_virtual_text, + ) + .map(|pos| (pos, view.id)) }) }; @@ -1056,7 +1061,7 @@ impl EditorView { MouseEventKind::Down(MouseButton::Left) => { let editor = &mut cxt.editor; - if let Some((pos, view_id)) = pos_and_view(editor, row, column) { + if let Some((pos, view_id)) = pos_and_view(editor, row, column, true) { let doc = doc_mut!(editor, &view!(editor, view_id).doc); if modifiers == KeyModifiers::ALT { @@ -1120,7 +1125,7 @@ impl EditorView { _ => unreachable!(), }; - match pos_and_view(cxt.editor, row, column) { + match pos_and_view(cxt.editor, row, column, false) { Some((_, view_id)) => cxt.editor.tree.focus = view_id, None => return EventResult::Ignored(None), } @@ -1191,7 +1196,7 @@ impl EditorView { return EventResult::Consumed(None); } - if let Some((pos, view_id)) = pos_and_view(editor, row, column) { + if let Some((pos, view_id)) = pos_and_view(editor, row, column, true) { let doc = doc_mut!(editor, &view!(editor, view_id).doc); doc.set_selection(view_id, Selection::point(pos)); cxt.editor.focus(view_id); From 2af14a24abbd8de510f69e6569c18601533dc912 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Wed, 22 Mar 2023 16:23:29 +0100 Subject: [PATCH 015/260] respect line annotations in char_idx_at_visual_row_offset char_idx_at_visual_row_offset asssumed that a single line/block break always corresponded to a vertical offset of 1. However conceal can hide the line break (in which case the certical offset would be 0) and line annotations (or softwrapped inlay hints at the end of the line) can insert addtional vertical lines. To correctly account for these cases we simply compute the visual offset of the start of the next block from the previous block instead of the visual offset of the block end. This means that the line breaks at the end of the block (however many there may be) are automatically included and we don't need to manually add 1 to the `row_offset` anymore. --- helix-core/src/position.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/helix-core/src/position.rs b/helix-core/src/position.rs index c3233a340..3902b4d49 100644 --- a/helix-core/src/position.rs +++ b/helix-core/src/position.rs @@ -317,10 +317,11 @@ pub fn char_idx_at_visual_offset<'a>( text_fmt: &TextFormat, annotations: &TextAnnotations, ) -> (usize, usize) { + let mut pos = anchor; // convert row relative to visual line containing anchor to row relative to a block containing anchor (anchor may change) loop { let (visual_pos_in_block, block_char_offset) = - visual_offset_from_block(text, anchor, anchor, text_fmt, annotations); + visual_offset_from_block(text, anchor, pos, text_fmt, annotations); row_offset += visual_pos_in_block.row as isize; anchor = block_char_offset; if row_offset >= 0 { @@ -332,10 +333,10 @@ pub fn char_idx_at_visual_offset<'a>( break; } // the row_offset is negative so we need to look at the previous block - // set the anchor to the last char before the current block - // this char index is also always a line earlier so increase the row_offset by 1 + // set the anchor to the last char before the current block so that we can compute + // the distance of this block from the start of the previous block + pos = anchor; anchor -= 1; - row_offset += 1; } char_idx_at_visual_block_offset( From d7431db55cd076dbacfde2cebaed315509923df5 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 27 Mar 2023 01:27:38 -0500 Subject: [PATCH 016/260] Update tree-sitter-git-commit, add comment textobject (#6439) The update includes a fix for comments in commit messages where there was no space separating the '#' and the comment text. The comment textobject can be useful occasionally to jump to the summary part of the commit edit message. --- book/src/generated/lang-support.md | 2 +- languages.toml | 2 +- runtime/queries/git-commit/textobjects.scm | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 runtime/queries/git-commit/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 5cd0c8c1f..003ed4a4a 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -41,7 +41,7 @@ | fortran | ✓ | | ✓ | `fortls` | | gdscript | ✓ | ✓ | ✓ | | | git-attributes | ✓ | | | | -| git-commit | ✓ | | | | +| git-commit | ✓ | ✓ | | | | git-config | ✓ | | | | | git-ignore | ✓ | | | | | git-rebase | ✓ | | | | diff --git a/languages.toml b/languages.toml index ae4135f00..7c6c278e6 100644 --- a/languages.toml +++ b/languages.toml @@ -1194,7 +1194,7 @@ text-width = 72 [[grammar]] name = "git-commit" -source = { git = "https://github.com/the-mikedavis/tree-sitter-git-commit", rev = "318dd72abfaa7b8044c1d1fbeabcd06deaaf038f" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-git-commit", rev = "7421fd81840950c0ff4191733cee3b6ac06cb295" } [[language]] name = "diff" diff --git a/runtime/queries/git-commit/textobjects.scm b/runtime/queries/git-commit/textobjects.scm new file mode 100644 index 000000000..4465c8768 --- /dev/null +++ b/runtime/queries/git-commit/textobjects.scm @@ -0,0 +1,2 @@ +(comment) @comment.inside +(comment)+ @comment.around From 5323020c3f02b178f2b6807f13d89bf7f40d3cce Mon Sep 17 00:00:00 2001 From: Philip Giuliani Date: Mon, 27 Mar 2023 19:24:17 +0200 Subject: [PATCH 017/260] Add .arb as a supported extension with json highlighting (#6452) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 7c6c278e6..0a0e29bae 100644 --- a/languages.toml +++ b/languages.toml @@ -160,7 +160,7 @@ indent = { tab-width = 2, unit = " " } name = "json" scope = "source.json" injection-regex = "json" -file-types = ["json", "jsonc"] +file-types = ["json", "jsonc", "arb"] roots = [] language-server = { command = "vscode-json-language-server", args = ["--stdio"] } auto-format = true From 198ff2c3f9c56afe4649cc0ecbb09ded5fd4a7c7 Mon Sep 17 00:00:00 2001 From: Philipp Mildenberger Date: Tue, 28 Mar 2023 01:33:55 +0200 Subject: [PATCH 018/260] Fix clippy lints (#6454) --- helix-core/src/position.rs | 4 ++-- helix-term/src/commands.rs | 4 ++-- helix-tui/src/widgets/block.rs | 9 ++------- helix-view/src/editor.rs | 9 ++------- 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/helix-core/src/position.rs b/helix-core/src/position.rs index 3902b4d49..04bf8c31f 100644 --- a/helix-core/src/position.rs +++ b/helix-core/src/position.rs @@ -309,8 +309,8 @@ pub fn pos_at_visual_coords(text: RopeSlice, coords: Position, tab_width: usize) /// on the visual line is returned if the visual line contains any text: /// If the visual line at the specified offset is a virtual line generated by a `LineAnnotation` /// the previous char_index is returned, together with the remaining vertical offset (`virtual_lines`) -pub fn char_idx_at_visual_offset<'a>( - text: RopeSlice<'a>, +pub fn char_idx_at_visual_offset( + text: RopeSlice, mut anchor: usize, mut row_offset: isize, column: usize, diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 4a7b78839..2f41a2dc8 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -501,7 +501,7 @@ impl std::str::FromStr for MappableCommand { fn from_str(s: &str) -> Result { if let Some(suffix) = s.strip_prefix(':') { - let mut typable_command = suffix.split(' ').into_iter().map(|arg| arg.trim()); + let mut typable_command = suffix.split(' ').map(|arg| arg.trim()); let name = typable_command .next() .ok_or_else(|| anyhow!("Expected typable command name"))?; @@ -1470,7 +1470,7 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction) { let cursor = range.cursor(text); let height = view.inner_height(); - let scrolloff = config.scrolloff.min(height.saturating_sub(1) as usize / 2); + let scrolloff = config.scrolloff.min(height.saturating_sub(1) / 2); let offset = match direction { Forward => offset as isize, Backward => -(offset as isize), diff --git a/helix-tui/src/widgets/block.rs b/helix-tui/src/widgets/block.rs index 98f84abe2..a6fdde4c0 100644 --- a/helix-tui/src/widgets/block.rs +++ b/helix-tui/src/widgets/block.rs @@ -7,8 +7,9 @@ use crate::{ use helix_view::graphics::{Rect, Style}; /// Border render type. Defaults to [`BorderType::Plain`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub enum BorderType { + #[default] Plain, Rounded, Double, @@ -26,12 +27,6 @@ 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. /// diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 7207baf38..ee535b5c0 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -532,10 +532,11 @@ impl Default for CursorShapeConfig { } /// bufferline render modes -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum BufferLine { /// Don't render bufferline + #[default] Never, /// Always render Always, @@ -543,12 +544,6 @@ pub enum BufferLine { Multiple, } -impl Default for BufferLine { - fn default() -> Self { - BufferLine::Never - } -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum LineNumber { From fc22ed4ac566a4c9d2b058ad56ea87773bd46915 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 19:14:00 -0500 Subject: [PATCH 019/260] build(deps): bump regex from 1.7.1 to 1.7.3 (#6458) Bumps [regex](https://github.com/rust-lang/regex) from 1.7.1 to 1.7.3. - [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.7.1...1.7.3) --- updated-dependencies: - dependency-name: regex 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 0bef317e9..c8cc225f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1718,9 +1718,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "aho-corasick", "memchr", @@ -1735,9 +1735,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "ropey" From fadccd64c04ca87915e03122747969e2a3257db1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 19:15:14 -0500 Subject: [PATCH 020/260] build(deps): bump chrono from 0.4.23 to 0.4.24 (#6460) Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.23 to 0.4.24. - [Release notes](https://github.com/chronotope/chrono/releases) - [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md) - [Commits](https://github.com/chronotope/chrono/compare/v0.4.23...v0.4.24) --- updated-dependencies: - dependency-name: chrono 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 c8cc225f6..5270e76f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,9 +149,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" dependencies = [ "iana-time-zone", "num-integer", From 038d7727cec0f5a414f409bb4971b4afeb6a6718 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 19:19:55 -0500 Subject: [PATCH 021/260] build(deps): bump toml from 0.7.2 to 0.7.3 (#6459) Bumps [toml](https://github.com/toml-rs/toml) from 0.7.2 to 0.7.3. - [Release notes](https://github.com/toml-rs/toml/releases) - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.7.2...toml-v0.7.3) --- 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 | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5270e76f8..13ae863ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1540,15 +1540,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "nom8" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" -dependencies = [ - "memchr", -] - [[package]] name = "num-integer" version = "0.1.45" @@ -2148,9 +2139,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" dependencies = [ "serde", "serde_spanned", @@ -2169,15 +2160,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.3" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6a7712b49e1775fb9a7b998de6635b299237f48b404dde71704f2e0e7f37e5" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" dependencies = [ "indexmap", - "nom8", "serde", "serde_spanned", "toml_datetime", + "winnow", ] [[package]] @@ -2480,6 +2471,15 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +[[package]] +name = "winnow" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +dependencies = [ + "memchr", +] + [[package]] name = "xtask" version = "0.6.0" From 03087882f37bac4d0a9e6d73a6e9faf1be08fbe0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 19:26:41 -0500 Subject: [PATCH 022/260] build(deps): bump anyhow from 1.0.69 to 1.0.70 (#6462) Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.69 to 1.0.70. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.69...1.0.70) --- 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 13ae863ae..b6a775e73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,9 +51,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" [[package]] name = "arc-swap" From 67b7b5b10912da7aca105cd13221191f68574b48 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 19:27:35 -0500 Subject: [PATCH 023/260] build(deps): bump tokio from 1.26.0 to 1.27.0 (#6461) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.26.0 to 1.27.0. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.26.0...tokio-1.27.0) --- 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 | 15 +++++++-------- helix-lsp/Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6a775e73..8b2765d78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1923,9 +1923,9 @@ checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" [[package]] name = "socket2" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -2097,14 +2097,13 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.26.0" +version = "1.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" +checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" dependencies = [ "autocfg", "bytes", "libc", - "memchr", "mio", "num_cpus", "parking_lot", @@ -2117,13 +2116,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.8.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn 1.0.104", + "syn 2.0.4", ] [[package]] diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index 9d76822dc..33ec5f309 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -24,6 +24,6 @@ lsp-types = { version = "0.94" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" -tokio = { version = "1.26", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } +tokio = { version = "1.27", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } tokio-stream = "0.1.12" which = "4.4" From cefc9986d8de3c6d626f18d5d58b1530b8dff30f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 19:27:54 -0500 Subject: [PATCH 024/260] build(deps): bump thiserror from 1.0.39 to 1.0.40 (#6463) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.39 to 1.0.40. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.39...1.0.40) --- 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 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b2765d78..98563fed7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2015,22 +2015,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 1.0.104", + "syn 2.0.4", ] [[package]] From 6a323c0b1b8fd2491dcbca38b5a1f62bf9581da4 Mon Sep 17 00:00:00 2001 From: Ivan <116971836+seshotake@users.noreply.github.com> Date: Tue, 28 Mar 2023 17:54:17 +0300 Subject: [PATCH 025/260] Update catppuccin theme (#6464) --- runtime/themes/catppuccin_mocha.toml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/runtime/themes/catppuccin_mocha.toml b/runtime/themes/catppuccin_mocha.toml index 87cfe41d1..126613bc7 100644 --- a/runtime/themes/catppuccin_mocha.toml +++ b/runtime/themes/catppuccin_mocha.toml @@ -13,7 +13,7 @@ "string.regexp" = "peach" "string.special" = "blue" -"comment" = { fg = "surface2", modifiers = ["italic"] } +"comment" = { fg = "overlay1", modifiers = ["italic"] } "variable" = "text" "variable.parameter" = { fg = "maroon", modifiers = ["italic"] } @@ -26,15 +26,16 @@ "punctuation.special" = "sky" "keyword" = "mauve" +"keyword.storage.modifier.ref" = "teal" "keyword.control.conditional" = { fg = "mauve", modifiers = ["italic"] } "operator" = "sky" "function" = "blue" -"function.builtin" = "peach" "function.macro" = "mauve" "tag" = "mauve" +"attribute" = "blue" "namespace" = { fg = "blue", modifiers = ["italic"] } @@ -51,7 +52,7 @@ "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } "markup.strikethrough" = { modifiers = ["crossed_out"] } -"markup.link.url" = { fg = "rosewater", modifiers = ["italic", "underlined"] } +"markup.link.url" = { fg = "rosewater", modifiers = ["underlined"] } "markup.link.text" = "blue" "markup.raw" = "flamingo" @@ -66,7 +67,7 @@ "ui.linenr" = { fg = "surface1" } "ui.linenr.selected" = { fg = "lavender" } -"ui.statusline" = { fg = "text", bg = "mantle" } +"ui.statusline" = { fg = "subtext1", bg = "mantle" } "ui.statusline.inactive" = { fg = "surface2", bg = "mantle" } "ui.statusline.normal" = { fg = "base", bg = "lavender", modifiers = ["bold"] } "ui.statusline.insert" = { fg = "base", bg = "green", modifiers = ["bold"] } @@ -76,12 +77,9 @@ "ui.window" = { fg = "crust" } "ui.help" = { fg = "overlay2", bg = "surface0" } -"ui.bufferline" = { fg = "surface1", bg = "mantle" } -"ui.bufferline.active" = { fg = "text", bg = "base", modifiers = [ - "bold", - "italic", -] } -"ui.bufferline.background" = { bg = "surface0" } +"ui.bufferline" = { fg = "subtext0", bg = "mantle" } +"ui.bufferline.active" = { fg = "mauve", bg = "base", underline = { color = "mauve", style = "line" } } +"ui.bufferline.background" = { bg = "crust" } "ui.text" = "text" "ui.text.focus" = { fg = "text", bg = "surface0", modifiers = ["bold"] } From bbcdcd04a5f6c02c14d73d6bd0f53099b1fcb765 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 28 Mar 2023 22:51:11 -0500 Subject: [PATCH 026/260] tui: Handle keyboard enhancement check failure (#6438) If the terminal doesn't send the primary device attributes response to the query, the `terminal::supports_keyboard_enhancement` function from crossterm may timeout and return an Err. We should interpret this error to mean that the terminal doesn't support the keyboard enhancement protocol rather than an error in claiming the terminal. --- helix-tui/src/backend/crossterm.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/helix-tui/src/backend/crossterm.rs b/helix-tui/src/backend/crossterm.rs index 4b230f539..4d44f187d 100644 --- a/helix-tui/src/backend/crossterm.rs +++ b/helix-tui/src/backend/crossterm.rs @@ -78,21 +78,20 @@ where } #[inline] - fn supports_keyboard_enhancement_protocol(&self) -> io::Result { - self.supports_keyboard_enhancement_protocol - .get_or_try_init(|| { + fn supports_keyboard_enhancement_protocol(&self) -> bool { + *self.supports_keyboard_enhancement_protocol + .get_or_init(|| { use std::time::Instant; let now = Instant::now(); - let support = terminal::supports_keyboard_enhancement(); + let supported = matches!(terminal::supports_keyboard_enhancement(), Ok(true)); log::debug!( "The keyboard enhancement protocol is {}supported in this terminal (checked in {:?})", - if matches!(support, Ok(true)) { "" } else { "not " }, + if supported { "" } else { "not " }, Instant::now().duration_since(now) ); - support + supported }) - .copied() } } @@ -125,7 +124,7 @@ where if config.enable_mouse_capture { execute!(self.buffer, EnableMouseCapture)?; } - if self.supports_keyboard_enhancement_protocol()? { + if self.supports_keyboard_enhancement_protocol() { execute!( self.buffer, PushKeyboardEnhancementFlags( @@ -143,7 +142,7 @@ where if config.enable_mouse_capture { execute!(self.buffer, DisableMouseCapture)?; } - if self.supports_keyboard_enhancement_protocol()? { + if self.supports_keyboard_enhancement_protocol() { execute!(self.buffer, PopKeyboardEnhancementFlags)?; } execute!( From d59b80514e15d26f280a9b0dbd18afac08578638 Mon Sep 17 00:00:00 2001 From: Filip Dutescu Date: Wed, 29 Mar 2023 06:52:19 +0300 Subject: [PATCH 027/260] feat(debug): highlight current line (#5957) Add new theme highlight keys, for setting the colour of the breakpoint character and the current line at which execution has been paused at. The two new keys are `ui.highlight.frameline` and `ui.debug.breakpoint`. Highlight according to those keys, both the line at which debugging is paused at and the breakpoint indicator. Add an indicator for the current line at which execution is paused at, themed by the `ui.debug.active` theme scope. Update various themes to showcase how the new functionality works. Better icons are dependent on #2869, and as such will be handled in the future, once it lands. Closes: #5952 Signed-off-by: Filip Dutescu --- book/src/themes.md | 3 ++ helix-dap/src/client.rs | 6 +++ helix-term/src/ui/editor.rs | 52 +++++++++--------------- helix-view/src/editor.rs | 7 ++++ helix-view/src/gutter.rs | 60 +++++++++++++++++++--------- runtime/themes/acme.toml | 2 + runtime/themes/autumn.toml | 2 + runtime/themes/ayu_dark.toml | 2 + runtime/themes/ayu_light.toml | 2 + runtime/themes/ayu_mirage.toml | 2 + runtime/themes/dracula.toml | 2 + runtime/themes/dracula_at_night.toml | 2 + runtime/themes/onedark.toml | 3 ++ runtime/themes/onedarker.toml | 2 + theme.toml | 4 +- 15 files changed, 98 insertions(+), 53 deletions(-) diff --git a/book/src/themes.md b/book/src/themes.md index 7accb67f0..56d0372ca 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -278,8 +278,11 @@ These scopes are used for theming the editor interface: | `ui.cursor.primary.normal` | | | `ui.cursor.primary.insert` | | | `ui.cursor.primary.select` | | +| `ui.debug.breakpoint` | Breakpoint indicator, found in the gutter | +| `ui.debug.active` | Indicator for the line at which debugging execution is paused at, found in the gutter | | `ui.gutter` | Gutter | | `ui.gutter.selected` | Gutter for the line the cursor is on | +| `ui.highlight.frameline` | Line at which debugging execution is paused at | | `ui.linenr` | Line numbers | | `ui.linenr.selected` | Line number for the line the cursor is on | | `ui.statusline` | Statusline | diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs index ff727d00a..7efb72d80 100644 --- a/helix-dap/src/client.rs +++ b/helix-dap/src/client.rs @@ -512,4 +512,10 @@ impl Client { self.call::(args) } + + pub fn current_stack_frame(&self) -> Option<&StackFrame> { + self.stack_frames + .get(&self.thread_id?)? + .get(self.active_frame?) + } } diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 4cac0fa8b..d4b141a04 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -93,40 +93,6 @@ impl EditorView { let mut line_decorations: Vec> = Vec::new(); let mut translated_positions: Vec = Vec::new(); - // DAP: Highlight current stack frame position - let stack_frame = editor.debugger.as_ref().and_then(|debugger| { - if let (Some(frame), Some(thread_id)) = (debugger.active_frame, debugger.thread_id) { - debugger - .stack_frames - .get(&thread_id) - .and_then(|bt| bt.get(frame)) - } else { - None - } - }); - if let Some(frame) = stack_frame { - if doc.path().is_some() - && frame - .source - .as_ref() - .and_then(|source| source.path.as_ref()) - == doc.path() - { - let line = frame.line - 1; // convert to 0-indexing - let style = theme.get("ui.highlight"); - let line_decoration = move |renderer: &mut TextRenderer, pos: LinePos| { - if pos.doc_line != line { - return; - } - renderer - .surface - .set_style(Rect::new(area.x, pos.visual_line, area.width, 1), style); - }; - - line_decorations.push(Box::new(line_decoration)); - } - } - if is_focused && config.cursorline { line_decorations.push(Self::cursorline_decorator(doc, view, theme)) } @@ -135,6 +101,23 @@ impl EditorView { Self::highlight_cursorcolumn(doc, view, surface, theme, inner, &text_annotations); } + // Set DAP highlights, if needed. + if let Some(frame) = editor.current_stack_frame() { + let dap_line = frame.line.saturating_sub(1) as usize; + let style = theme.get("ui.highlight.frameline"); + let line_decoration = move |renderer: &mut TextRenderer, pos: LinePos| { + if pos.doc_line != dap_line { + return; + } + renderer.surface.set_style( + Rect::new(inner.x, inner.y + pos.visual_line, inner.width, 1), + style, + ); + }; + + line_decorations.push(Box::new(line_decoration)); + } + let mut highlights = Self::doc_syntax_highlights(doc, view.offset.anchor, inner.height, theme); let overlay_highlights = Self::overlay_syntax_highlights( @@ -422,6 +405,7 @@ impl EditorView { let primary_selection_scope = theme .find_scope_index_exact("ui.selection.primary") .unwrap_or(selection_scope); + let base_cursor_scope = theme .find_scope_index_exact("ui.cursor") .unwrap_or(selection_scope); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index ee535b5c0..c939aa5cd 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -10,6 +10,7 @@ use crate::{ view::ViewPosition, Align, Document, DocumentId, View, ViewId, }; +use dap::StackFrame; use helix_vcs::DiffProviderRegistry; use futures_util::stream::select_all::SelectAll; @@ -1652,6 +1653,12 @@ impl Editor { doc.restore_cursor = false; } } + + pub fn current_stack_frame(&self) -> Option<&StackFrame> { + self.debugger + .as_ref() + .and_then(|debugger| debugger.current_stack_frame()) + } } fn try_restore_indent(doc: &mut Document, view: &mut View) { diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 36e8e16a4..3ecae9195 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -2,7 +2,7 @@ use std::fmt::Write; use crate::{ editor::GutterType, - graphics::{Color, Style, UnderlineStyle}, + graphics::{Style, UnderlineStyle}, Document, Editor, Theme, View, }; @@ -245,9 +245,9 @@ pub fn breakpoints<'doc>( theme: &Theme, _is_focused: bool, ) -> GutterFn<'doc> { - let warning = theme.get("warning"); let error = theme.get("error"); let info = theme.get("info"); + let breakpoint_style = theme.get("ui.debug.breakpoint"); let breakpoints = doc.path().and_then(|path| editor.breakpoints.get(path)); @@ -265,30 +265,52 @@ pub fn breakpoints<'doc>( .iter() .find(|breakpoint| breakpoint.line == line)?; - let mut style = if breakpoint.condition.is_some() && breakpoint.log_message.is_some() { + let style = if breakpoint.condition.is_some() && breakpoint.log_message.is_some() { error.underline_style(UnderlineStyle::Line) } else if breakpoint.condition.is_some() { error } else if breakpoint.log_message.is_some() { info } else { - warning + breakpoint_style }; - if !breakpoint.verified { - // Faded colors - style = if let Some(Color::Rgb(r, g, b)) = style.fg { - style.fg(Color::Rgb( - ((r as f32) * 0.4).floor() as u8, - ((g as f32) * 0.4).floor() as u8, - ((b as f32) * 0.4).floor() as u8, - )) - } else { - style.fg(Color::Gray) - } - }; + let sym = if breakpoint.verified { "●" } else { "◯" }; + write!(out, "{}", sym).unwrap(); + Some(style) + }, + ) +} + +fn execution_pause_indicator<'doc>( + editor: &'doc Editor, + doc: &'doc Document, + theme: &Theme, + is_focused: bool, +) -> GutterFn<'doc> { + let style = theme.get("ui.debug.active"); + let current_stack_frame = editor.current_stack_frame(); + let frame_line = current_stack_frame.map(|frame| frame.line - 1); + let frame_source_path = current_stack_frame.map(|frame| { + frame + .source + .as_ref() + .and_then(|source| source.path.as_ref()) + }); + let should_display_for_current_doc = + doc.path().is_some() && frame_source_path.unwrap_or(None) == doc.path(); + + Box::new( + move |line: usize, _selected: bool, first_visual_line: bool, out: &mut String| { + if !first_visual_line + || !is_focused + || line != frame_line? + || !should_display_for_current_doc + { + return None; + } - let sym = if breakpoint.verified { "▲" } else { "⊚" }; + let sym = "▶"; write!(out, "{}", sym).unwrap(); Some(style) }, @@ -304,9 +326,11 @@ pub fn diagnostics_or_breakpoints<'doc>( ) -> GutterFn<'doc> { let mut diagnostics = diagnostic(editor, doc, view, theme, is_focused); let mut breakpoints = breakpoints(editor, doc, view, theme, is_focused); + let mut execution_pause_indicator = execution_pause_indicator(editor, doc, theme, is_focused); Box::new(move |line, selected, first_visual_line: bool, out| { - breakpoints(line, selected, first_visual_line, out) + execution_pause_indicator(line, selected, first_visual_line, out) + .or_else(|| breakpoints(line, selected, first_visual_line, out)) .or_else(|| diagnostics(line, selected, first_visual_line, out)) }) } diff --git a/runtime/themes/acme.toml b/runtime/themes/acme.toml index e1d66ff8f..650924741 100644 --- a/runtime/themes/acme.toml +++ b/runtime/themes/acme.toml @@ -12,6 +12,8 @@ "ui.virtual.ruler" = { bg = "acme_bar_bg" } "ui.cursor.match" = {bg="acme_bar_bg"} "ui.cursor" = {bg="cursor", fg="white"} +"ui.debug" = {fg="orange"} +"ui.highlight.frameline" = {bg="#da8581"} "string" = "red" "comment" = "green" "ui.help" = {fg="black", bg="acme_bg"} diff --git a/runtime/themes/autumn.toml b/runtime/themes/autumn.toml index 1430e0a8e..4474b0d41 100644 --- a/runtime/themes/autumn.toml +++ b/runtime/themes/autumn.toml @@ -26,6 +26,8 @@ "ui.cursor.primary" = { fg = "my_white", modifiers = ["reversed"] } "ui.cursorline.primary" = { bg = "my_black" } "ui.cursorline.secondary" = { bg = "my_black" } +"ui.highlight.frameline" = { bg = "#8b6904" } +"ui.debug" = { fg = "my_yellow1", bg = "my_gray0" } "ui.text" = "my_white" "operator" = "my_white" "ui.text.focus" = "my_white" diff --git a/runtime/themes/ayu_dark.toml b/runtime/themes/ayu_dark.toml index 37060a244..211d423f4 100644 --- a/runtime/themes/ayu_dark.toml +++ b/runtime/themes/ayu_dark.toml @@ -61,6 +61,8 @@ "diagnostic.error"= { underline = { color = "red", style="curl"} } "ui.bufferline" = { fg = "gray", bg = "background" } "ui.bufferline.active" = { fg = "foreground", bg = "dark_gray" } +"ui.debug" = { fg = "orange", bg = "background" } +"ui.highlight.frameline" = { bg = "#0067a3" } "special" = "orange" diff --git a/runtime/themes/ayu_light.toml b/runtime/themes/ayu_light.toml index 58b25484c..4b0ba1db7 100644 --- a/runtime/themes/ayu_light.toml +++ b/runtime/themes/ayu_light.toml @@ -61,6 +61,8 @@ "diagnostic.error"= { underline = { color = "red", style = "curl" } } "ui.bufferline" = { fg = "gray", bg = "background" } "ui.bufferline.active" = { fg = "foreground", bg = "dark_gray" } +"ui.debug" = { fg = "orange", bg = "background" } +"ui.highlight.frameline" = { bg = "#cfe0f2" } "special" = "orange" diff --git a/runtime/themes/ayu_mirage.toml b/runtime/themes/ayu_mirage.toml index 4c1f8fa65..5afe0acd9 100644 --- a/runtime/themes/ayu_mirage.toml +++ b/runtime/themes/ayu_mirage.toml @@ -61,6 +61,8 @@ "diagnostic.error"= { underline = { color = "red", style = "curl" } } "ui.bufferline" = { fg = "gray", bg = "background" } "ui.bufferline.active" = { fg = "foreground", bg = "dark_gray" } +"ui.debug" = { fg = "orange", bg = "background" } +"ui.highlight.frameline" = { bg = "#0067a3" } "special" = "orange" diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index 8bde4708d..b08357dbe 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -25,6 +25,8 @@ "ui.cursor.primary" = { fg = "background", bg = "cyan", modifiers = ["dim"] } "ui.cursorline.primary" = { bg = "background_dark" } "ui.help" = { fg = "foreground", bg = "background_dark" } +"ui.debug" = { fg = "red" } +"ui.highlight.frameline" = { fg = "black", bg = "red" } "ui.linenr" = { fg = "comment" } "ui.linenr.selected" = { fg = "foreground" } "ui.menu" = { fg = "foreground", bg = "background_dark" } diff --git a/runtime/themes/dracula_at_night.toml b/runtime/themes/dracula_at_night.toml index 9f10ec90f..b2e3b9a9f 100644 --- a/runtime/themes/dracula_at_night.toml +++ b/runtime/themes/dracula_at_night.toml @@ -25,6 +25,8 @@ "ui.cursor.match" = { fg = "green", modifiers = ["underlined"] } "ui.cursor.primary" = { fg = "background", bg = "cyan", modifiers = ["dim"] } "ui.help" = { fg = "foreground", bg = "background_dark" } +"ui.debug" = { fg = "red" } +"ui.highlight.frameline" = { fg = "black", bg = "red" } "ui.linenr" = { fg = "comment" } "ui.linenr.selected" = { fg = "foreground" } "ui.menu" = { fg = "foreground", bg = "background_dark" } diff --git a/runtime/themes/onedark.toml b/runtime/themes/onedark.toml index 81ca04630..6df5f797b 100644 --- a/runtime/themes/onedark.toml +++ b/runtime/themes/onedark.toml @@ -64,6 +64,7 @@ "ui.cursorline.primary" = { bg = "light-black" } "ui.highlight" = { bg = "gray" } +"ui.highlight.frameline" = { bg = "#97202a" } "ui.linenr" = { fg = "linenr" } "ui.linenr.selected" = { fg = "white" } @@ -84,6 +85,8 @@ "ui.menu.selected" = { fg = "black", bg = "blue" } "ui.menu.scroll" = { fg = "white", bg = "light-gray" } +"ui.debug" = { fg = "red" } + [palette] yellow = "#E5C07B" diff --git a/runtime/themes/onedarker.toml b/runtime/themes/onedarker.toml index 33f900cc0..7169fd025 100644 --- a/runtime/themes/onedarker.toml +++ b/runtime/themes/onedarker.toml @@ -78,6 +78,8 @@ "ui.text.focus" = { fg = "white", bg = "light-black", modifiers = ["bold"] } "ui.help" = { fg = "white", bg = "gray" } +"ui.debug" = { fg = "red" } +"ui.highlight.frameline" = { bg = "#97202a" } "ui.popup" = { bg = "gray" } "ui.window" = { fg = "gray" } "ui.menu" = { fg = "white", bg = "gray" } diff --git a/theme.toml b/theme.toml index b67eaecc3..dd1a5d889 100644 --- a/theme.toml +++ b/theme.toml @@ -69,7 +69,9 @@ label = "honey" "ui.cursor" = { modifiers = ["reversed"] } "ui.cursorline.primary" = { bg = "bossanova" } "ui.highlight" = { bg = "bossanova" } - +"ui.highlight.frameline" = { bg = "#634450" } +"ui.debug" = { fg = "#634450" } +"ui.debug.breakpoint" = { fg = "apricot" } "ui.menu" = { fg = "lavender", bg = "revolver" } "ui.menu.selected" = { fg = "revolver", bg = "white" } "ui.menu.scroll" = { fg = "lavender", bg = "comet" } From 2d10a429ebf7abe5af184b6227346377dc0523e8 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Tue, 31 Jan 2023 00:31:21 +0100 Subject: [PATCH 028/260] add workspace config and manual LSP root management fixup documentation Co-authored-by: LeoniePhiline <22329650+LeoniePhiline@users.noreply.github.com> fixup typo Co-authored-by: LeoniePhiline <22329650+LeoniePhiline@users.noreply.github.com> --- book/src/configuration.md | 4 + book/src/generated/typable-cmd.md | 1 + book/src/languages.md | 1 + helix-core/src/lib.rs | 47 +---------- helix-core/src/syntax.rs | 6 +- helix-loader/src/config.rs | 8 +- helix-loader/src/lib.rs | 44 ++++------ helix-lsp/src/client.rs | 12 ++- helix-lsp/src/lib.rs | 56 +++++++++++- helix-term/src/commands.rs | 6 +- helix-term/src/commands/typed.rs | 26 +++++- helix-term/src/config.rs | 136 ++++++++++++++++++++++++------ helix-term/src/keymap.rs | 79 ++++++++--------- helix-term/src/main.rs | 27 +++--- helix-term/tests/test/helpers.rs | 12 ++- helix-view/src/editor.rs | 12 +-- 16 files changed, 295 insertions(+), 182 deletions(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index e2dfc89ef..2af0e6326 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -30,6 +30,9 @@ You can use a custom configuration file by specifying it with the `-c` or Additionally, you can reload the configuration file by sending the USR1 signal to the Helix process on Unix operating systems, such as by using the command `pkill -USR1 hx`. +Finally, you can have a `config.toml` local to a project by putting it under a `.helix` directory in your repository. +Its settings will be merged with the configuration directory `config.toml` and the built-in configuration. + ## Editor ### `[editor]` Section @@ -58,6 +61,7 @@ signal to the Helix process on Unix operating systems, such as by using the comm | `bufferline` | Renders a line at the top of the editor displaying open buffers. Can be `always`, `never` or `multiple` (only shown if more than one buffer is in use) | `never` | | `color-modes` | Whether to color the mode indicator with different colors depending on the mode itself | `false` | | `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap_at_text_width` is set | `80` | +| `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml` | `[]` | ### `[editor.statusline]` Section diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 8b367aad8..9d15b83c9 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -70,6 +70,7 @@ | `:tree-sitter-subtree`, `:ts-subtree` | Display tree sitter subtree under cursor, primarily for debugging queries. | | `:config-reload` | Refresh user config. | | `:config-open` | Open the user config.toml file. | +| `:config-open-workspace` | Open the workspace config.toml file. | | `:log-open` | Open the helix log file. | | `:insert-output` | Run shell command, inserting output before each selection. | | `:append-output` | Run shell command, appending output after each selection. | diff --git a/book/src/languages.md b/book/src/languages.md index 5ed69505d..a7fa35a64 100644 --- a/book/src/languages.md +++ b/book/src/languages.md @@ -64,6 +64,7 @@ These configuration keys are available: | `grammar` | The tree-sitter grammar to use (defaults to the value of `name`) | | `formatter` | The formatter for the language, it will take precedence over the lsp when defined. The formatter must be able to take the original file as input from stdin and write the formatted file to stdout | | `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap_at_text_width` is set, defaults to `editor.text-width` | +| `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml`. Overwrites the setting of the same name in `config.toml` if set. | `` | ### File-type detection and the `file-types` key diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 4d50e48bf..b67e2c8a3 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -36,55 +36,12 @@ pub mod unicode { pub use unicode_width as width; } +pub use helix_loader::find_workspace; + pub fn find_first_non_whitespace_char(line: RopeSlice) -> Option { line.chars().position(|ch| !ch.is_whitespace()) } -/// Find project root. -/// -/// Order of detection: -/// * Top-most folder containing a root marker in current git repository -/// * 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]) -> std::path::PathBuf { - 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() { - if root_markers - .iter() - .any(|marker| ancestor.join(marker).exists()) - { - top_marker = Some(ancestor); - } - - if ancestor.join(".git").exists() { - // Top marker is repo root if not root marker was detected yet - if top_marker.is_none() { - top_marker = Some(ancestor); - } - // Don't go higher than repo if we're in one - break; - } - } - - // Return the found top marker or the current_dir as fallback - top_marker.map_or(current_dir, |a| a.to_path_buf()) -} - pub use ropey::{self, str_utils, Rope, RopeBuilder, RopeSlice}; // pub use tendril::StrTendril as Tendril; diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index e494ee9b1..408469675 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -20,7 +20,7 @@ use std::{ fmt, hash::{Hash, Hasher}, mem::{replace, transmute}, - path::Path, + path::{Path, PathBuf}, str::FromStr, sync::Arc, }; @@ -127,6 +127,10 @@ pub struct LanguageConfiguration { pub auto_pairs: Option, pub rulers: Option>, // if set, override editor's rulers + + /// Hardcoded LSP root directories relative to the workspace root, like `examples` or `tools/fuzz`. + /// Falling back to the current working directory if none are configured. + pub workspace_lsp_roots: Option>, } #[derive(Debug, PartialEq, Eq, Hash)] diff --git a/helix-loader/src/config.rs b/helix-loader/src/config.rs index 0f329d217..8924c8fb2 100644 --- a/helix-loader/src/config.rs +++ b/helix-loader/src/config.rs @@ -9,9 +9,8 @@ pub fn default_lang_config() -> toml::Value { /// User configured languages.toml file, merged with the default config. pub fn user_lang_config() -> Result { - let config = crate::local_config_dirs() + let config = [crate::config_dir(), crate::find_workspace().join(".helix")] .into_iter() - .chain([crate::config_dir()].into_iter()) .map(|path| path.join("languages.toml")) .filter_map(|file| { std::fs::read_to_string(file) @@ -20,8 +19,7 @@ pub fn user_lang_config() -> Result { }) .collect::, _>>()? .into_iter() - .chain([default_lang_config()].into_iter()) - .fold(toml::Value::Table(toml::value::Table::default()), |a, b| { + .fold(default_lang_config(), |a, b| { // combines for example // b: // [[language]] @@ -38,7 +36,7 @@ pub fn user_lang_config() -> Result { // language-server = { command = "/usr/bin/taplo" } // // thus it overrides the third depth-level of b with values of a if they exist, but otherwise merges their values - crate::merge_toml_values(b, a, 3) + crate::merge_toml_values(a, b, 3) }); Ok(config) diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index 04b44b5aa..51bde716f 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -42,7 +42,7 @@ fn prioritize_runtime_dirs() -> Vec { let mut rt_dirs = Vec::new(); 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 - let path = std::path::PathBuf::from(dir).parent().unwrap().join(RT_DIR); + let path = PathBuf::from(dir).parent().unwrap().join(RT_DIR); log::debug!("runtime dir: {}", path.to_string_lossy()); rt_dirs.push(path); } @@ -113,15 +113,6 @@ pub fn config_dir() -> PathBuf { path } -pub fn local_config_dirs() -> Vec { - let directories = find_local_config_dirs() - .into_iter() - .map(|path| path.join(".helix")) - .collect(); - log::debug!("Located configuration folders: {:?}", directories); - directories -} - pub fn cache_dir() -> PathBuf { // TODO: allow env var override let strategy = choose_base_strategy().expect("Unable to find the config directory!"); @@ -137,6 +128,10 @@ pub fn config_file() -> PathBuf { .unwrap_or_else(|| config_dir().join("config.toml")) } +pub fn workspace_config_file() -> PathBuf { + find_workspace().join(".helix").join("config.toml") +} + pub fn lang_config_file() -> PathBuf { config_dir().join("languages.toml") } @@ -145,22 +140,6 @@ pub fn log_file() -> PathBuf { cache_dir().join("helix.log") } -pub fn find_local_config_dirs() -> Vec { - let current_dir = std::env::current_dir().expect("unable to determine current directory"); - let mut directories = Vec::new(); - - for ancestor in current_dir.ancestors() { - if ancestor.join(".git").exists() { - directories.push(ancestor.to_path_buf()); - // Don't go higher than repo if we're in one - break; - } else if ancestor.join(".helix").is_dir() { - directories.push(ancestor.to_path_buf()); - } - } - directories -} - /// Merge two TOML documents, merging values from `right` onto `left` /// /// When an array exists in both `left` and `right`, `right`'s array is @@ -302,3 +281,16 @@ mod merge_toml_tests { ) } } + +/// Finds the current workspace folder. +/// Used as a ceiling dir for root resolve, for the filepicker and other related +pub fn find_workspace() -> PathBuf { + let current_dir = std::env::current_dir().expect("unable to determine current directory"); + for ancestor in current_dir.ancestors() { + if ancestor.join(".git").exists() || ancestor.join(".helix").exists() { + return ancestor.to_owned(); + } + } + + current_dir +} diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index f93e58263..34e4c346b 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -1,22 +1,22 @@ use crate::{ - jsonrpc, + find_root, jsonrpc, transport::{Payload, Transport}, Call, Error, OffsetEncoding, Result, }; -use helix_core::{find_root, ChangeSet, Rope}; +use helix_core::{ChangeSet, Rope}; use helix_loader::{self, VERSION_AND_GIT_HASH}; use lsp::PositionEncodingKind; 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::{ atomic::{AtomicU64, Ordering}, Arc, }; +use std::{collections::HashMap, path::PathBuf}; use tokio::{ io::{BufReader, BufWriter}, process::{Child, Command}, @@ -49,6 +49,7 @@ impl Client { config: Option, server_environment: HashMap, root_markers: &[String], + manual_roots: &[PathBuf], id: usize, req_timeout: u64, doc_path: Option<&std::path::PathBuf>, @@ -77,8 +78,11 @@ impl Client { Transport::start(reader, writer, stderr, id); let root_path = find_root( - doc_path.and_then(|x| x.parent().and_then(|x| x.to_str())), + doc_path + .and_then(|x| x.parent().and_then(|x| x.to_str())) + .unwrap_or("."), root_markers, + manual_roots, ); let root_uri = lsp::Url::from_file_path(root_path.clone()).ok(); diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 5609a624f..e4b009466 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -10,11 +10,15 @@ pub use lsp::{Position, Url}; pub use lsp_types as lsp; use futures_util::stream::select_all::SelectAll; -use helix_core::syntax::{LanguageConfiguration, LanguageServerConfiguration}; +use helix_core::{ + find_workspace, + syntax::{LanguageConfiguration, LanguageServerConfiguration}, +}; use tokio::sync::mpsc::UnboundedReceiver; use std::{ collections::{hash_map::Entry, HashMap}, + path::PathBuf, sync::{ atomic::{AtomicUsize, Ordering}, Arc, @@ -641,6 +645,7 @@ impl Registry { &mut self, language_config: &LanguageConfiguration, doc_path: Option<&std::path::PathBuf>, + root_dirs: &[PathBuf], ) -> Result>> { let config = match &language_config.language_server { Some(config) => config, @@ -656,7 +661,7 @@ impl Registry { let id = self.counter.fetch_add(1, Ordering::Relaxed); let NewClientResult(client, incoming) = - start_client(id, language_config, config, doc_path)?; + start_client(id, language_config, config, doc_path, root_dirs)?; self.incoming.push(UnboundedReceiverStream::new(incoming)); let (_, old_client) = entry.insert((id, client.clone())); @@ -684,6 +689,7 @@ impl Registry { &mut self, language_config: &LanguageConfiguration, doc_path: Option<&std::path::PathBuf>, + root_dirs: &[PathBuf], ) -> Result>> { let config = match &language_config.language_server { Some(config) => config, @@ -697,7 +703,7 @@ impl Registry { let id = self.counter.fetch_add(1, Ordering::Relaxed); let NewClientResult(client, incoming) = - start_client(id, language_config, config, doc_path)?; + start_client(id, language_config, config, doc_path, root_dirs)?; self.incoming.push(UnboundedReceiverStream::new(incoming)); entry.insert((id, client.clone())); @@ -798,6 +804,7 @@ fn start_client( config: &LanguageConfiguration, ls_config: &LanguageServerConfiguration, doc_path: Option<&std::path::PathBuf>, + root_dirs: &[PathBuf], ) -> Result { let (client, incoming, initialize_notify) = Client::start( &ls_config.command, @@ -805,6 +812,7 @@ fn start_client( config.config.clone(), ls_config.environment.clone(), &config.roots, + config.workspace_lsp_roots.as_deref().unwrap_or(root_dirs), id, ls_config.timeout, doc_path, @@ -842,6 +850,48 @@ fn start_client( Ok(NewClientResult(client, incoming)) } +/// Find an LSP root of a file using the following mechansim: +/// * start at `file` (either an absolute path or relative to CWD) +/// * find the top most directory containing a root_marker +/// * inside the current workspace +/// * stop the search at the first root_dir that contains `file` or the workspace (obtained from `helix_core::find_workspace`) +/// * root_dirs only apply inside the workspace. For files outside of the workspace they are ignored +/// * outside the current workspace: keep searching to the top of the file hiearchy +pub fn find_root(file: &str, root_markers: &[String], root_dirs: &[PathBuf]) -> PathBuf { + let file = std::path::Path::new(file); + let workspace = find_workspace(); + let file = if file.is_absolute() { + file.to_path_buf() + } else { + let current_dir = std::env::current_dir().expect("unable to determine current directory"); + current_dir.join(file) + }; + + let inside_workspace = file.strip_prefix(&workspace).is_ok(); + + let mut top_marker = None; + for ancestor in file.ancestors() { + if root_markers + .iter() + .any(|marker| ancestor.join(marker).exists()) + { + top_marker = Some(ancestor); + } + + if inside_workspace + && (ancestor == workspace + || root_dirs + .iter() + .any(|root_dir| root_dir == ancestor.strip_prefix(&workspace).unwrap())) + { + return top_marker.unwrap_or(ancestor).to_owned(); + } + } + + // If no root was found use the workspace as a fallback + workspace +} + #[cfg(test)] mod tests { use super::{lsp, util::*, OffsetEncoding}; diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 2f41a2dc8..e4d0d753f 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -12,7 +12,7 @@ pub use typed::*; use helix_core::{ char_idx_at_visual_offset, comment, doc_formatter::TextFormat, - encoding, find_first_non_whitespace_char, find_root, graphemes, + encoding, find_first_non_whitespace_char, find_workspace, graphemes, history::UndoKind, increment, indent, indent::IndentStyle, @@ -2419,9 +2419,7 @@ fn append_mode(cx: &mut Context) { } fn file_picker(cx: &mut Context) { - // We don't specify language markers, root will be the root of the current - // git repo or the current dir if we're not in a repo - let root = find_root(None, &[]); + let root = find_workspace(); let picker = ui::file_picker(root, &cx.editor.config()); cx.push_layer(Box::new(overlayed(picker))); } diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 2c72686da..ca55151ad 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1371,13 +1371,16 @@ fn lsp_restart( return Ok(()); } + let editor_config = cx.editor.config.load(); let (_view, doc) = current!(cx.editor); let config = doc .language_config() .context("LSP not defined for the current document")?; let scope = config.scope.clone(); - cx.editor.language_servers.restart(config, doc.path())?; + cx.editor + .language_servers + .restart(config, doc.path(), &editor_config.workspace_lsp_roots)?; // This collect is needed because refresh_language_server would need to re-borrow editor. let document_ids_to_refresh: Vec = cx @@ -1970,6 +1973,20 @@ fn open_config( Ok(()) } +fn open_workspace_config( + cx: &mut compositor::Context, + _args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + + cx.editor + .open(&helix_loader::workspace_config_file(), Action::Replace)?; + Ok(()) +} + fn open_log( cx: &mut compositor::Context, _args: &[Cow], @@ -2646,6 +2663,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: open_config, signature: CommandSignature::none(), }, + TypableCommand { + name: "config-open-workspace", + aliases: &[], + doc: "Open the workspace config.toml file.", + fun: open_workspace_config, + signature: CommandSignature::none(), + }, TypableCommand { name: "log-open", aliases: &[], diff --git a/helix-term/src/config.rs b/helix-term/src/config.rs index 4407a882f..9776ef7a4 100644 --- a/helix-term/src/config.rs +++ b/helix-term/src/config.rs @@ -1,27 +1,34 @@ -use crate::keymap::{default::default, merge_keys, Keymap}; +use crate::keymap; +use crate::keymap::{merge_keys, Keymap}; +use helix_loader::merge_toml_values; use helix_view::document::Mode; use serde::Deserialize; use std::collections::HashMap; use std::fmt::Display; +use std::fs; use std::io::Error as IOError; -use std::path::PathBuf; use toml::de::Error as TomlError; -#[derive(Debug, Clone, PartialEq, Deserialize)] -#[serde(deny_unknown_fields)] +#[derive(Debug, Clone, PartialEq)] pub struct Config { pub theme: Option, - #[serde(default = "default")] pub keys: HashMap, - #[serde(default)] pub editor: helix_view::editor::Config, } +#[derive(Debug, Clone, PartialEq, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigRaw { + pub theme: Option, + pub keys: Option>, + pub editor: Option, +} + impl Default for Config { fn default() -> Config { Config { theme: None, - keys: default(), + keys: keymap::default(), editor: helix_view::editor::Config::default(), } } @@ -33,6 +40,12 @@ pub enum ConfigLoadError { Error(IOError), } +impl Default for ConfigLoadError { + fn default() -> Self { + ConfigLoadError::Error(IOError::new(std::io::ErrorKind::NotFound, "place holder")) + } +} + impl Display for ConfigLoadError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -43,17 +56,72 @@ impl Display for ConfigLoadError { } impl Config { - pub fn load(config_path: PathBuf) -> Result { - match std::fs::read_to_string(config_path) { - Ok(config) => toml::from_str(&config) - .map(merge_keys) - .map_err(ConfigLoadError::BadConfig), - Err(err) => Err(ConfigLoadError::Error(err)), - } + pub fn load( + global: Result, + local: Result, + ) -> Result { + let global_config: Result = + global.and_then(|file| toml::from_str(&file).map_err(ConfigLoadError::BadConfig)); + let local_config: Result = + local.and_then(|file| toml::from_str(&file).map_err(ConfigLoadError::BadConfig)); + let res = match (global_config, local_config) { + (Ok(global), Ok(local)) => { + let mut keys = keymap::default(); + if let Some(global_keys) = global.keys { + merge_keys(&mut keys, global_keys) + } + if let Some(local_keys) = local.keys { + merge_keys(&mut keys, local_keys) + } + + let editor = match (global.editor, local.editor) { + (None, None) => helix_view::editor::Config::default(), + (None, Some(val)) | (Some(val), None) => { + val.try_into().map_err(ConfigLoadError::BadConfig)? + } + (Some(global), Some(local)) => merge_toml_values(global, local, 3) + .try_into() + .map_err(ConfigLoadError::BadConfig)?, + }; + + Config { + theme: local.theme.or(global.theme), + keys, + editor, + } + } + // if any configs are invalid return that first + (_, Err(ConfigLoadError::BadConfig(err))) + | (Err(ConfigLoadError::BadConfig(err)), _) => { + return Err(ConfigLoadError::BadConfig(err)) + } + (Ok(config), Err(_)) | (Err(_), Ok(config)) => { + let mut keys = keymap::default(); + if let Some(keymap) = config.keys { + merge_keys(&mut keys, keymap); + } + Config { + theme: config.theme, + keys, + editor: config.editor.map_or_else( + || Ok(helix_view::editor::Config::default()), + |val| val.try_into().map_err(ConfigLoadError::BadConfig), + )?, + } + } + // these are just two io errors return the one for the global config + (Err(err), Err(_)) => return Err(err), + }; + + Ok(res) } pub fn load_default() -> Result { - Config::load(helix_loader::config_file()) + let global_config = + fs::read_to_string(helix_loader::config_file()).map_err(ConfigLoadError::Error); + let local_config = fs::read_to_string(helix_loader::workspace_config_file()) + .map_err(ConfigLoadError::Error); + Config::load(global_config, local_config) } } @@ -61,6 +129,12 @@ impl Config { mod tests { use super::*; + impl Config { + fn load_test(config: &str) -> Config { + Config::load(Ok(config.to_owned()), Err(ConfigLoadError::default())).unwrap() + } + } + #[test] fn parsing_keymaps_config_file() { use crate::keymap; @@ -77,18 +151,24 @@ mod tests { A-F12 = "move_next_word_end" "#; + let mut keys = keymap::default(); + merge_keys( + &mut keys, + hashmap! { + Mode::Insert => Keymap::new(keymap!({ "Insert mode" + "y" => move_line_down, + "S-C-a" => delete_selection, + })), + Mode::Normal => Keymap::new(keymap!({ "Normal mode" + "A-F12" => move_next_word_end, + })), + }, + ); + assert_eq!( - toml::from_str::(sample_keymaps).unwrap(), + Config::load_test(sample_keymaps), Config { - keys: hashmap! { - Mode::Insert => Keymap::new(keymap!({ "Insert mode" - "y" => move_line_down, - "S-C-a" => delete_selection, - })), - Mode::Normal => Keymap::new(keymap!({ "Normal mode" - "A-F12" => move_next_word_end, - })), - }, + keys, ..Default::default() } ); @@ -97,11 +177,11 @@ mod tests { #[test] fn keys_resolve_to_correct_defaults() { // From serde default - let default_keys = toml::from_str::("").unwrap().keys; - assert_eq!(default_keys, default()); + let default_keys = Config::load_test("").keys; + assert_eq!(default_keys, keymap::default()); // From the Default trait let default_keys = Config::default().keys; - assert_eq!(default_keys, default()); + assert_eq!(default_keys, keymap::default()); } } diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index e94a5f66b..3033c6a48 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -2,7 +2,6 @@ pub mod default; pub mod macros; pub use crate::commands::MappableCommand; -use crate::config::Config; use arc_swap::{ access::{DynAccess, DynGuard}, ArcSwap, @@ -16,7 +15,7 @@ use std::{ sync::Arc, }; -use default::default; +pub use default::default; use macros::key; #[derive(Debug, Clone)] @@ -417,12 +416,10 @@ impl Default for Keymaps { } /// Merge default config keys with user overwritten keys for custom user config. -pub fn merge_keys(mut config: Config) -> Config { - let mut delta = std::mem::replace(&mut config.keys, default()); - for (mode, keys) in &mut config.keys { +pub fn merge_keys(dst: &mut HashMap, mut delta: HashMap) { + for (mode, keys) in dst { keys.merge(delta.remove(mode).unwrap_or_default()) } - config } #[cfg(test)] @@ -449,26 +446,24 @@ mod tests { #[test] fn merge_partial_keys() { - let config = Config { - keys: hashmap! { - Mode::Normal => Keymap::new( - keymap!({ "Normal mode" - "i" => normal_mode, - "无" => insert_mode, - "z" => jump_backward, - "g" => { "Merge into goto mode" - "$" => goto_line_end, - "g" => delete_char_forward, - }, - }) - ) - }, - ..Default::default() + let keymap = hashmap! { + Mode::Normal => Keymap::new( + keymap!({ "Normal mode" + "i" => normal_mode, + "无" => insert_mode, + "z" => jump_backward, + "g" => { "Merge into goto mode" + "$" => goto_line_end, + "g" => delete_char_forward, + }, + }) + ) }; - let mut merged_config = merge_keys(config.clone()); - assert_ne!(config, merged_config); + let mut merged_keyamp = default(); + merge_keys(&mut merged_keyamp, keymap.clone()); + assert_ne!(keymap, merged_keyamp); - let mut keymap = Keymaps::new(Box::new(Constant(merged_config.keys.clone()))); + let mut keymap = Keymaps::new(Box::new(Constant(merged_keyamp.clone()))); assert_eq!( keymap.get(Mode::Normal, key!('i')), KeymapResult::Matched(MappableCommand::normal_mode), @@ -486,7 +481,7 @@ mod tests { "Leaf should replace node" ); - let keymap = merged_config.keys.get_mut(&Mode::Normal).unwrap(); + let keymap = merged_keyamp.get_mut(&Mode::Normal).unwrap(); // Assumes that `g` is a node in default keymap assert_eq!( keymap.root().search(&[key!('g'), key!('$')]).unwrap(), @@ -506,30 +501,28 @@ mod tests { "Old leaves in subnode should be present in merged node" ); - assert!(merged_config.keys.get(&Mode::Normal).unwrap().len() > 1); - assert!(merged_config.keys.get(&Mode::Insert).unwrap().len() > 0); + assert!(merged_keyamp.get(&Mode::Normal).unwrap().len() > 1); + assert!(merged_keyamp.get(&Mode::Insert).unwrap().len() > 0); } #[test] fn order_should_be_set() { - let config = Config { - keys: hashmap! { - Mode::Normal => Keymap::new( - keymap!({ "Normal mode" - "space" => { "" - "s" => { "" - "v" => vsplit, - "c" => hsplit, - }, + let keymap = hashmap! { + Mode::Normal => Keymap::new( + keymap!({ "Normal mode" + "space" => { "" + "s" => { "" + "v" => vsplit, + "c" => hsplit, }, - }) - ) - }, - ..Default::default() + }, + }) + ) }; - let mut merged_config = merge_keys(config.clone()); - assert_ne!(config, merged_config); - let keymap = merged_config.keys.get_mut(&Mode::Normal).unwrap(); + let mut merged_keyamp = default(); + merge_keys(&mut merged_keyamp, keymap.clone()); + assert_ne!(keymap, merged_keyamp); + let keymap = merged_keyamp.get_mut(&Mode::Normal).unwrap(); // Make sure mapping works assert_eq!( keymap diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index aac5c5379..e0c3f6e70 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -3,7 +3,7 @@ use crossterm::event::EventStream; use helix_loader::VERSION_AND_GIT_HASH; use helix_term::application::Application; use helix_term::args::Args; -use helix_term::config::Config; +use helix_term::config::{Config, ConfigLoadError}; use std::path::PathBuf; fn setup_logging(logpath: PathBuf, verbosity: u64) -> Result<()> { @@ -126,18 +126,19 @@ FLAGS: helix_loader::initialize_config_file(args.config_file.clone()); - let config = match std::fs::read_to_string(helix_loader::config_file()) { - 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; - 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 config = match Config::load_default() { + Ok(config) => config, + Err(ConfigLoadError::Error(err)) if err.kind() == std::io::ErrorKind::NotFound => { + Config::default() + } + Err(ConfigLoadError::Error(err)) => return Err(Error::new(err)), + Err(ConfigLoadError::BadConfig(err)) => { + eprintln!("Bad config: {}", err); + eprintln!("Press to continue with default config"); + use std::io::Read; + let _ = std::io::stdin().read(&mut []); + Config::default() + } }; let syn_loader_conf = helix_core::config::user_syntax_loader().unwrap_or_else(|err| { diff --git a/helix-term/tests/test/helpers.rs b/helix-term/tests/test/helpers.rs index ccd07bfa5..30fe7d0ed 100644 --- a/helix-term/tests/test/helpers.rs +++ b/helix-term/tests/test/helpers.rs @@ -1,6 +1,7 @@ use std::{ fs::File, io::{Read, Write}, + mem::replace, path::PathBuf, time::Duration, }; @@ -222,10 +223,11 @@ pub fn temp_file_with_contents>( /// Generates a config with defaults more suitable for integration tests pub fn test_config() -> Config { - merge_keys(Config { + Config { editor: test_editor_config(), + keys: helix_term::keymap::default(), ..Default::default() - }) + } } pub fn test_editor_config() -> helix_view::editor::Config { @@ -300,8 +302,10 @@ impl AppBuilder { // Remove this attribute once `with_config` is used in a test: #[allow(dead_code)] - pub fn with_config(mut self, config: Config) -> Self { - self.config = helix_term::keymap::merge_keys(config); + pub fn with_config(mut self, mut config: Config) -> Self { + let keys = replace(&mut config.keys, helix_term::keymap::default()); + merge_keys(&mut config.keys, keys); + self.config = config; self } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index c939aa5cd..727e1261d 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -282,6 +282,8 @@ pub struct Config { /// Whether to color modes with different colors. Defaults to `false`. pub color_modes: bool, pub soft_wrap: SoftWrap, + /// Workspace specific lsp ceiling dirs + pub workspace_lsp_roots: Vec, } #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -747,6 +749,7 @@ impl Default for Config { soft_wrap: SoftWrap::default(), text_width: 80, completion_replace: false, + workspace_lsp_roots: Vec::new(), } } } @@ -1087,15 +1090,14 @@ impl Editor { } // if doc doesn't have a URL it's a scratch buffer, ignore it - let (lang, path) = { - let doc = self.document(doc_id)?; - (doc.language.clone(), doc.path().cloned()) - }; + let doc = self.document(doc_id)?; + let (lang, path) = (doc.language.clone(), doc.path().cloned()); + let root_dirs = &doc.config.load().workspace_lsp_roots; // try to find a language server based on the language name let language_server = lang.as_ref().and_then(|language| { self.language_servers - .get(language, path.as_ref()) + .get(language, path.as_ref(), root_dirs) .map_err(|e| { log::error!( "Failed to initialize the LSP for `{}` {{ {} }}", From 5b3dd6a678ba138ea21d7d5dd8d3c8a53c7a6d3b Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Tue, 7 Feb 2023 15:59:04 +0100 Subject: [PATCH 029/260] implement proper lsp-workspace support fix typo Co-authored-by: LeoniePhiline <22329650+LeoniePhiline@users.noreply.github.com> --- Cargo.lock | 1 + book/src/languages.md | 2 +- helix-loader/src/config.rs | 61 ++++++------ helix-loader/src/lib.rs | 15 ++- helix-lsp/Cargo.toml | 1 + helix-lsp/src/client.rs | 177 +++++++++++++++++++++++++++++----- helix-lsp/src/lib.rs | 116 +++++++++++++--------- helix-term/src/application.rs | 2 +- helix-term/src/commands.rs | 2 +- 9 files changed, 270 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 98563fed7..e6ee9d540 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1149,6 +1149,7 @@ dependencies = [ "helix-parsec", "log", "lsp-types", + "parking_lot", "serde", "serde_json", "thiserror", diff --git a/book/src/languages.md b/book/src/languages.md index a7fa35a64..f44509fc8 100644 --- a/book/src/languages.md +++ b/book/src/languages.md @@ -64,7 +64,7 @@ These configuration keys are available: | `grammar` | The tree-sitter grammar to use (defaults to the value of `name`) | | `formatter` | The formatter for the language, it will take precedence over the lsp when defined. The formatter must be able to take the original file as input from stdin and write the formatted file to stdout | | `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap_at_text_width` is set, defaults to `editor.text-width` | -| `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml`. Overwrites the setting of the same name in `config.toml` if set. | `` | +| `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml`. Overwrites the setting of the same name in `config.toml` if set. | ### File-type detection and the `file-types` key diff --git a/helix-loader/src/config.rs b/helix-loader/src/config.rs index 8924c8fb2..d092d20f7 100644 --- a/helix-loader/src/config.rs +++ b/helix-loader/src/config.rs @@ -9,35 +9,38 @@ pub fn default_lang_config() -> toml::Value { /// User configured languages.toml file, merged with the default config. pub fn user_lang_config() -> Result { - let config = [crate::config_dir(), crate::find_workspace().join(".helix")] - .into_iter() - .map(|path| path.join("languages.toml")) - .filter_map(|file| { - std::fs::read_to_string(file) - .map(|config| toml::from_str(&config)) - .ok() - }) - .collect::, _>>()? - .into_iter() - .fold(default_lang_config(), |a, b| { - // combines for example - // b: - // [[language]] - // name = "toml" - // language-server = { command = "taplo", args = ["lsp", "stdio"] } - // - // a: - // [[language]] - // language-server = { command = "/usr/bin/taplo" } - // - // into: - // [[language]] - // name = "toml" - // language-server = { command = "/usr/bin/taplo" } - // - // thus it overrides the third depth-level of b with values of a if they exist, but otherwise merges their values - crate::merge_toml_values(a, b, 3) - }); + let config = [ + crate::config_dir(), + crate::find_workspace().0.join(".helix"), + ] + .into_iter() + .map(|path| path.join("languages.toml")) + .filter_map(|file| { + std::fs::read_to_string(file) + .map(|config| toml::from_str(&config)) + .ok() + }) + .collect::, _>>()? + .into_iter() + .fold(default_lang_config(), |a, b| { + // combines for example + // b: + // [[language]] + // name = "toml" + // language-server = { command = "taplo", args = ["lsp", "stdio"] } + // + // a: + // [[language]] + // language-server = { command = "/usr/bin/taplo" } + // + // into: + // [[language]] + // name = "toml" + // language-server = { command = "/usr/bin/taplo" } + // + // thus it overrides the third depth-level of b with values of a if they exist, but otherwise merges their values + crate::merge_toml_values(a, b, 3) + }); Ok(config) } diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index 51bde716f..6c7169758 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -129,7 +129,7 @@ pub fn config_file() -> PathBuf { } pub fn workspace_config_file() -> PathBuf { - find_workspace().join(".helix").join("config.toml") + find_workspace().0.join(".helix").join("config.toml") } pub fn lang_config_file() -> PathBuf { @@ -283,14 +283,19 @@ mod merge_toml_tests { } /// Finds the current workspace folder. -/// Used as a ceiling dir for root resolve, for the filepicker and other related -pub fn find_workspace() -> PathBuf { +/// Used as a ceiling dir for LSP root resolution, the filepicker and potentially as a future filewatching root +/// +/// This function starts searching the FS upward from the CWD +/// and returns the first directory that contains either `.git` or `.helix`. +/// If no workspace was found returns (CWD, true). +/// Otherwise (workspace, false) is returned +pub fn find_workspace() -> (PathBuf, bool) { let current_dir = std::env::current_dir().expect("unable to determine current directory"); for ancestor in current_dir.ancestors() { if ancestor.join(".git").exists() || ancestor.join(".helix").exists() { - return ancestor.to_owned(); + return (ancestor.to_owned(), false); } } - current_dir + (current_dir, true) } diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index 33ec5f309..f85265152 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -27,3 +27,4 @@ thiserror = "1.0" tokio = { version = "1.27", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } tokio-stream = "0.1.12" which = "4.4" +parking_lot = "0.12.1" diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 34e4c346b..3dab6bc55 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -1,13 +1,17 @@ use crate::{ - find_root, jsonrpc, + find_lsp_workspace, jsonrpc, transport::{Payload, Transport}, Call, Error, OffsetEncoding, Result, }; -use helix_core::{ChangeSet, Rope}; +use helix_core::{find_workspace, ChangeSet, Rope}; use helix_loader::{self, VERSION_AND_GIT_HASH}; -use lsp::PositionEncodingKind; +use lsp::{ + notification::DidChangeWorkspaceFolders, DidChangeWorkspaceFoldersParams, OneOf, + PositionEncodingKind, WorkspaceFolder, WorkspaceFoldersChangeEvent, +}; use lsp_types as lsp; +use parking_lot::Mutex; use serde::Deserialize; use serde_json::Value; use std::future::Future; @@ -26,6 +30,17 @@ use tokio::{ }, }; +fn workspace_for_uri(uri: lsp::Url) -> WorkspaceFolder { + lsp::WorkspaceFolder { + name: uri + .path_segments() + .and_then(|segments| segments.last()) + .map(|basename| basename.to_string()) + .unwrap_or_default(), + uri, + } +} + #[derive(Debug)] pub struct Client { id: usize, @@ -36,11 +51,120 @@ pub struct Client { config: Option, root_path: std::path::PathBuf, root_uri: Option, - workspace_folders: Vec, + workspace_folders: Mutex>, + initalize_notify: Arc, + /// workspace folders added while the server is still initalizing req_timeout: u64, } impl Client { + pub fn try_add_doc( + self: &Arc, + root_markers: &[String], + manual_roots: &[PathBuf], + doc_path: Option<&std::path::PathBuf>, + may_support_workspace: bool, + ) -> bool { + let (workspace, workspace_is_cwd) = find_workspace(); + let root = find_lsp_workspace( + doc_path + .and_then(|x| x.parent().and_then(|x| x.to_str())) + .unwrap_or("."), + root_markers, + manual_roots, + &workspace, + workspace_is_cwd, + ); + let root_uri = root + .as_ref() + .and_then(|root| lsp::Url::from_file_path(root).ok()); + + if self.root_path == root.unwrap_or(workspace) + || root_uri.as_ref().map_or(false, |root_uri| { + self.workspace_folders + .lock() + .iter() + .any(|workspace| &workspace.uri == root_uri) + }) + { + // workspace URI is already registered so we can use this client + return true; + } + + // this server definitly doesn't support multiple workspace, no need to check capabilities + if !may_support_workspace { + return false; + } + + let Some(capabilities) = self.capabilities.get() else { + let client = Arc::clone(self); + // initalization hasn't finished yet, deal with this new root later + // TODO: In the edgecase that a **new root** is added + // for an LSP that **doesn't support workspace_folders** before initaliation is finished + // the new roots are ignored. + // That particular edgecase would require retroactively spawning new LSP + // clients and therefore also require us to retroactively update the corresponding + // documents LSP client handle. It's doable but a pretty weird edgecase so let's + // wait and see if anyone ever runs into it. + tokio::spawn(async move { + client.initalize_notify.notified().await; + if let Some(workspace_folders_caps) = client + .capabilities() + .workspace + .as_ref() + .and_then(|cap| cap.workspace_folders.as_ref()) + .filter(|cap| cap.supported.unwrap_or(false)) + { + client.add_workspace_folder( + root_uri, + &workspace_folders_caps.change_notifications, + ); + } + }); + return true; + }; + + if let Some(workspace_folders_caps) = capabilities + .workspace + .as_ref() + .and_then(|cap| cap.workspace_folders.as_ref()) + .filter(|cap| cap.supported.unwrap_or(false)) + { + self.add_workspace_folder(root_uri, &workspace_folders_caps.change_notifications); + true + } else { + // the server doesn't support multi workspaces, we need a new client + false + } + } + + fn add_workspace_folder( + &self, + root_uri: Option, + change_notifications: &Option>, + ) { + // root_uri is None just means that there isn't really any LSP workspace + // associated with this file. For servers that support multiple workspaces + // there is just one server so we can always just use that shared instance. + // No need to add a new workspace root here as there is no logical root for this file + // let the server deal with this + let Some(root_uri) = root_uri else { + return; + }; + + // server supports workspace folders, let's add the new root to the list + self.workspace_folders + .lock() + .push(workspace_for_uri(root_uri.clone())); + if &Some(OneOf::Left(false)) == change_notifications { + // server specifically opted out of DidWorkspaceChange notifications + // let's assume the server will request the workspace folders itself + // and that we can therefore reuse the client (but are done now) + return; + } + tokio::spawn(self.did_change_workspace(vec![workspace_for_uri(root_uri)], Vec::new())); + } + #[allow(clippy::type_complexity)] #[allow(clippy::too_many_arguments)] pub fn start( @@ -76,30 +200,25 @@ impl Client { let (server_rx, server_tx, initialize_notify) = Transport::start(reader, writer, stderr, id); - - let root_path = find_root( + let (workspace, workspace_is_cwd) = find_workspace(); + let root = find_lsp_workspace( doc_path .and_then(|x| x.parent().and_then(|x| x.to_str())) .unwrap_or("."), root_markers, manual_roots, + &workspace, + workspace_is_cwd, ); - let root_uri = lsp::Url::from_file_path(root_path.clone()).ok(); + // `root_uri` and `workspace_folder` can be empty in case there is no workspace + // `root_url` can not, use `workspace` as a fallback + let root_path = root.clone().unwrap_or_else(|| workspace.clone()); + let root_uri = root.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, - }] - }) + .map(|root| vec![workspace_for_uri(root)]) .unwrap_or_default(); let client = Self { @@ -110,10 +229,10 @@ impl Client { capabilities: OnceCell::new(), config, req_timeout, - root_path, root_uri, - workspace_folders, + workspace_folders: Mutex::new(workspace_folders), + initalize_notify: initialize_notify.clone(), }; Ok((client, server_rx, initialize_notify)) @@ -169,8 +288,10 @@ impl Client { self.config.as_ref() } - pub fn workspace_folders(&self) -> &[lsp::WorkspaceFolder] { - &self.workspace_folders + pub async fn workspace_folders( + &self, + ) -> parking_lot::MutexGuard<'_, Vec> { + self.workspace_folders.lock() } /// Execute a RPC request on the language server. @@ -298,7 +419,7 @@ impl Client { #[allow(deprecated)] let params = lsp::InitializeParams { process_id: Some(std::process::id()), - workspace_folders: Some(self.workspace_folders.clone()), + workspace_folders: Some(self.workspace_folders.lock().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: self.root_path.to_str().map(|path| path.to_owned()), @@ -469,6 +590,16 @@ impl Client { ) } + pub fn did_change_workspace( + &self, + added: Vec, + removed: Vec, + ) -> impl Future> { + self.notify::(DidChangeWorkspaceFoldersParams { + event: WorkspaceFoldersChangeEvent { added, removed }, + }) + } + // ------------------------------------------------------------------------------------------- // Text document // ------------------------------------------------------------------------------------------- diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index e4b009466..d56148a41 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -10,15 +10,12 @@ pub use lsp::{Position, Url}; pub use lsp_types as lsp; use futures_util::stream::select_all::SelectAll; -use helix_core::{ - find_workspace, - syntax::{LanguageConfiguration, LanguageServerConfiguration}, -}; +use helix_core::syntax::{LanguageConfiguration, LanguageServerConfiguration}; use tokio::sync::mpsc::UnboundedReceiver; use std::{ collections::{hash_map::Entry, HashMap}, - path::PathBuf, + path::{Path, PathBuf}, sync::{ atomic::{AtomicUsize, Ordering}, Arc, @@ -609,7 +606,7 @@ impl Notification { #[derive(Debug)] pub struct Registry { - inner: HashMap)>, + inner: HashMap)>>, counter: AtomicUsize, pub incoming: SelectAll>, @@ -633,12 +630,16 @@ impl Registry { pub fn get_by_id(&self, id: usize) -> Option<&Client> { self.inner .values() + .flatten() .find(|(client_id, _)| client_id == &id) .map(|(_, client)| client.as_ref()) } pub fn remove_by_id(&mut self, id: usize) { - self.inner.retain(|_, (client_id, _)| client_id != &id) + self.inner.retain(|_, clients| { + clients.retain(|&(client_id, _)| client_id != id); + !clients.is_empty() + }) } pub fn restart( @@ -664,11 +665,13 @@ impl Registry { start_client(id, language_config, config, doc_path, root_dirs)?; self.incoming.push(UnboundedReceiverStream::new(incoming)); - let (_, old_client) = entry.insert((id, client.clone())); + let old_clients = entry.insert(vec![(id, client.clone())]); - tokio::spawn(async move { - let _ = old_client.force_shutdown().await; - }); + for (_, old_client) in old_clients { + tokio::spawn(async move { + let _ = old_client.force_shutdown().await; + }); + } Ok(Some(client)) } @@ -678,10 +681,12 @@ impl Registry { pub fn stop(&mut self, language_config: &LanguageConfiguration) { let scope = language_config.scope.clone(); - if let Some((_, client)) = self.inner.remove(&scope) { - tokio::spawn(async move { - let _ = client.force_shutdown().await; - }); + if let Some(clients) = self.inner.remove(&scope) { + for (_, client) in clients { + tokio::spawn(async move { + let _ = client.force_shutdown().await; + }); + } } } @@ -696,24 +701,25 @@ impl Registry { None => return Ok(None), }; - match self.inner.entry(language_config.scope.clone()) { - Entry::Occupied(entry) => Ok(Some(entry.get().1.clone())), - Entry::Vacant(entry) => { - // initialize a new client - let id = self.counter.fetch_add(1, Ordering::Relaxed); - - let NewClientResult(client, incoming) = - start_client(id, language_config, config, doc_path, root_dirs)?; - self.incoming.push(UnboundedReceiverStream::new(incoming)); - - entry.insert((id, client.clone())); - Ok(Some(client)) - } + let clients = self.inner.entry(language_config.scope.clone()).or_default(); + // check if we already have a client for this documents root that we can reuse + if let Some((_, client)) = clients.iter_mut().enumerate().find(|(i, (_, client))| { + client.try_add_doc(&language_config.roots, root_dirs, doc_path, *i == 0) + }) { + return Ok(Some(client.1.clone())); } + // initialize a new client + let id = self.counter.fetch_add(1, Ordering::Relaxed); + + let NewClientResult(client, incoming) = + start_client(id, language_config, config, doc_path, root_dirs)?; + clients.push((id, client.clone())); + self.incoming.push(UnboundedReceiverStream::new(incoming)); + Ok(Some(client)) } pub fn iter_clients(&self) -> impl Iterator> { - self.inner.values().map(|(_, client)| client) + self.inner.values().flatten().map(|(_, client)| client) } } @@ -850,16 +856,23 @@ fn start_client( Ok(NewClientResult(client, incoming)) } -/// Find an LSP root of a file using the following mechansim: -/// * start at `file` (either an absolute path or relative to CWD) -/// * find the top most directory containing a root_marker -/// * inside the current workspace -/// * stop the search at the first root_dir that contains `file` or the workspace (obtained from `helix_core::find_workspace`) -/// * root_dirs only apply inside the workspace. For files outside of the workspace they are ignored -/// * outside the current workspace: keep searching to the top of the file hiearchy -pub fn find_root(file: &str, root_markers: &[String], root_dirs: &[PathBuf]) -> PathBuf { +/// Find an LSP workspace of a file using the following mechanism: +/// * if the file is outside `workspace` return `None` +/// * start at `file` and search the file tree upward +/// * stop the search at the first `root_dirs` entry that contains `file` +/// * if no `root_dirs` matchs `file` stop at workspace +/// * Returns the top most directory that contains a `root_marker` +/// * If no root marker and we stopped at a `root_dirs` entry, return the directory we stopped at +/// * If we stopped at `workspace` instead and `workspace_is_cwd == false` return `None` +/// * If we stopped at `workspace` instead and `workspace_is_cwd == true` return `workspace` +pub fn find_lsp_workspace( + file: &str, + root_markers: &[String], + root_dirs: &[PathBuf], + workspace: &Path, + workspace_is_cwd: bool, +) -> Option { let file = std::path::Path::new(file); - let workspace = find_workspace(); let file = if file.is_absolute() { file.to_path_buf() } else { @@ -867,7 +880,9 @@ pub fn find_root(file: &str, root_markers: &[String], root_dirs: &[PathBuf]) -> current_dir.join(file) }; - let inside_workspace = file.strip_prefix(&workspace).is_ok(); + if !file.starts_with(workspace) { + return None; + } let mut top_marker = None; for ancestor in file.ancestors() { @@ -878,18 +893,25 @@ pub fn find_root(file: &str, root_markers: &[String], root_dirs: &[PathBuf]) -> top_marker = Some(ancestor); } - if inside_workspace - && (ancestor == workspace - || root_dirs - .iter() - .any(|root_dir| root_dir == ancestor.strip_prefix(&workspace).unwrap())) + if root_dirs + .iter() + .any(|root_dir| root_dir == ancestor.strip_prefix(workspace).unwrap()) { - return top_marker.unwrap_or(ancestor).to_owned(); + // if the worskapce is the cwd do not search any higher for workspaces + // but specify + return Some(top_marker.unwrap_or(workspace).to_owned()); + } + if ancestor == workspace { + // if the workspace is the CWD, let the LSP decide what the workspace + // is + return top_marker + .or_else(|| (!workspace_is_cwd).then_some(workspace)) + .map(Path::to_owned); } } - // If no root was found use the workspace as a fallback - workspace + debug_assert!(false, "workspace must be an ancestor of "); + None } #[cfg(test)] diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 95faa01b0..4d903eec4 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -1018,7 +1018,7 @@ impl Application { let language_server = self.editor.language_servers.get_by_id(server_id).unwrap(); - Ok(json!(language_server.workspace_folders())) + Ok(json!(&*language_server.workspace_folders().await)) } Ok(MethodCall::WorkspaceConfiguration(params)) => { let result: Vec<_> = params diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index e4d0d753f..0f53fdc94 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2419,7 +2419,7 @@ fn append_mode(cx: &mut Context) { } fn file_picker(cx: &mut Context) { - let root = find_workspace(); + let root = find_workspace().0; let picker = ui::file_picker(root, &cx.editor.config()); cx.push_layer(Box::new(overlayed(picker))); } From d04288e0f3d292ce47fc0246bcbdc50a9d57ad5e Mon Sep 17 00:00:00 2001 From: jazzfool <56189047+jazzfool@users.noreply.github.com> Date: Fri, 31 Mar 2023 03:21:40 +1100 Subject: [PATCH 030/260] Canonicalize paths before stripping current dir as prefix (#6290) Co-authored-by: jazzfool --- Cargo.lock | 1 + helix-core/Cargo.toml | 1 + helix-core/src/path.rs | 29 +++++++++++++++++++++---- helix-term/tests/integration.rs | 2 -- helix-term/tests/test/commands/write.rs | 10 ++++----- helix-term/tests/test/splits.rs | 8 ++++--- 6 files changed, 37 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e6ee9d540..278ab535e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1082,6 +1082,7 @@ dependencies = [ "arc-swap", "bitflags 2.0.2", "chrono", + "dunce", "encoding_rs", "etcetera", "hashbrown 0.13.2", diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 9dfef9ae2..e5c5f8f1a 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -32,6 +32,7 @@ regex = "1" bitflags = "2.0" ahash = "0.8.3" hashbrown = { version = "0.13.2", features = ["raw"] } +dunce = "1.0" log = "0.4" serde = { version = "1.0", features = ["derive"] } diff --git a/helix-core/src/path.rs b/helix-core/src/path.rs index d59a6baad..efa46c46e 100644 --- a/helix-core/src/path.rs +++ b/helix-core/src/path.rs @@ -40,6 +40,21 @@ pub fn expand_tilde(path: &Path) -> PathBuf { /// needs to improve on. /// Copied from cargo: pub fn get_normalized_path(path: &Path) -> PathBuf { + // normalization strategy is to canonicalize first ancestor path that exists (i.e., canonicalize as much as possible), + // then run handrolled normalization on the non-existent remainder + let (base, path) = path + .ancestors() + .find_map(|base| { + let canonicalized_base = dunce::canonicalize(base).ok()?; + let remainder = path.strip_prefix(base).ok()?.into(); + Some((canonicalized_base, remainder)) + }) + .unwrap_or_else(|| (PathBuf::new(), PathBuf::from(path))); + + if path.as_os_str().is_empty() { + return base; + } + let mut components = path.components().peekable(); let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { components.next(); @@ -63,7 +78,7 @@ pub fn get_normalized_path(path: &Path) -> PathBuf { } } } - ret + base.join(ret) } /// Returns the canonical, absolute form of a path with all intermediate components normalized. @@ -82,13 +97,19 @@ pub fn get_canonicalized_path(path: &Path) -> std::io::Result { } pub fn get_relative_path(path: &Path) -> PathBuf { + let path = PathBuf::from(path); let path = if path.is_absolute() { - let cwdir = std::env::current_dir().expect("couldn't determine current directory"); - path.strip_prefix(cwdir).unwrap_or(path) + let cwdir = std::env::current_dir() + .map(|path| get_normalized_path(&path)) + .expect("couldn't determine current directory"); + get_normalized_path(&path) + .strip_prefix(cwdir) + .map(PathBuf::from) + .unwrap_or(path) } else { path }; - fold_home_dir(path) + fold_home_dir(&path) } /// Returns a truncated filepath where the basepart of the path is reduced to the first diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs index cec374afa..d77eefed0 100644 --- a/helix-term/tests/integration.rs +++ b/helix-term/tests/integration.rs @@ -2,8 +2,6 @@ mod test { mod helpers; - use std::path::PathBuf; - use helix_core::{syntax::AutoPairConfig, Selection}; use helix_term::config::Config; diff --git a/helix-term/tests/test/commands/write.rs b/helix-term/tests/test/commands/write.rs index 0ea66a12d..26515b7ae 100644 --- a/helix-term/tests/test/commands/write.rs +++ b/helix-term/tests/test/commands/write.rs @@ -3,7 +3,7 @@ use std::{ ops::RangeInclusive, }; -use helix_core::diagnostic::Severity; +use helix_core::{diagnostic::Severity, path::get_normalized_path}; use helix_view::doc; use super::*; @@ -23,7 +23,7 @@ async fn test_write_quit_fail() -> anyhow::Result<()> { assert_eq!(1, docs.len()); let doc = docs.pop().unwrap(); - assert_eq!(Some(file.path()), doc.path().map(PathBuf::as_path)); + assert_eq!(Some(&get_normalized_path(file.path())), doc.path()); assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); }), false, @@ -269,7 +269,7 @@ async fn test_write_scratch_to_new_path() -> anyhow::Result<()> { assert_eq!(1, docs.len()); let doc = docs.pop().unwrap(); - assert_eq!(Some(&file.path().to_path_buf()), doc.path()); + assert_eq!(Some(&get_normalized_path(file.path())), doc.path()); }), false, ) @@ -341,7 +341,7 @@ async fn test_write_new_path() -> anyhow::Result<()> { Some(&|app| { let doc = doc!(app.editor); assert!(!app.editor.is_err()); - assert_eq!(file1.path(), doc.path().unwrap()); + assert_eq!(&get_normalized_path(file1.path()), doc.path().unwrap()); }), ), ( @@ -349,7 +349,7 @@ async fn test_write_new_path() -> anyhow::Result<()> { Some(&|app| { let doc = doc!(app.editor); assert!(!app.editor.is_err()); - assert_eq!(file2.path(), doc.path().unwrap()); + assert_eq!(&get_normalized_path(file2.path()), doc.path().unwrap()); assert!(app.editor.document_by_path(file1.path()).is_none()); }), ), diff --git a/helix-term/tests/test/splits.rs b/helix-term/tests/test/splits.rs index 96ced21a5..1d70f24a6 100644 --- a/helix-term/tests/test/splits.rs +++ b/helix-term/tests/test/splits.rs @@ -1,5 +1,7 @@ use super::*; +use helix_core::path::get_normalized_path; + #[tokio::test(flavor = "multi_thread")] async fn test_split_write_quit_all() -> anyhow::Result<()> { let mut file1 = tempfile::NamedTempFile::new()?; @@ -25,21 +27,21 @@ async fn test_split_write_quit_all() -> anyhow::Result<()> { let doc1 = docs .iter() - .find(|doc| doc.path().unwrap() == file1.path()) + .find(|doc| doc.path().unwrap() == &get_normalized_path(file1.path())) .unwrap(); assert_eq!("hello1", doc1.text().to_string()); let doc2 = docs .iter() - .find(|doc| doc.path().unwrap() == file2.path()) + .find(|doc| doc.path().unwrap() == &get_normalized_path(file2.path())) .unwrap(); assert_eq!("hello2", doc2.text().to_string()); let doc3 = docs .iter() - .find(|doc| doc.path().unwrap() == file3.path()) + .find(|doc| doc.path().unwrap() == &get_normalized_path(file3.path())) .unwrap(); assert_eq!("hello3", doc3.text().to_string()); From fc9229c8468d408c427281c093b703bbf1db352f Mon Sep 17 00:00:00 2001 From: Clara Hobbs Date: Thu, 30 Mar 2023 21:32:27 -0400 Subject: [PATCH 031/260] Add injection for markdown strings (#6489) --- runtime/queries/julia/injections.scm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/runtime/queries/julia/injections.scm b/runtime/queries/julia/injections.scm index ce4011f20..fd174a4a0 100644 --- a/runtime/queries/julia/injections.scm +++ b/runtime/queries/julia/injections.scm @@ -26,3 +26,9 @@ prefix: (identifier) @function.macro) @injection.content (#eq? @function.macro "re") (#set! injection.language "regex")) + +( + (prefixed_string_literal + prefix: (identifier) @function.macro) @injection.content + (#eq? @function.macro "md") + (#set! injection.language "markdown")) From d284444eb402d76090ef0743d21fa51b9eee058d Mon Sep 17 00:00:00 2001 From: Clara Hobbs Date: Thu, 30 Mar 2023 21:32:36 -0400 Subject: [PATCH 032/260] Add indents.scm for Julia (#6490) * Add indents.scm for Julia * Update documentation for new indent support --- book/src/generated/lang-support.md | 2 +- runtime/queries/julia/indents.scm | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/julia/indents.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 003ed4a4a..48667f2e5 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -68,7 +68,7 @@ | json | ✓ | | ✓ | `vscode-json-language-server` | | jsonnet | ✓ | | | `jsonnet-language-server` | | jsx | ✓ | ✓ | ✓ | `typescript-language-server` | -| julia | ✓ | | | `julia` | +| julia | ✓ | | ✓ | `julia` | | kdl | ✓ | | | | | kotlin | ✓ | | | `kotlin-language-server` | | latex | ✓ | ✓ | | `texlab` | diff --git a/runtime/queries/julia/indents.scm b/runtime/queries/julia/indents.scm new file mode 100644 index 000000000..08f55aa7f --- /dev/null +++ b/runtime/queries/julia/indents.scm @@ -0,0 +1,16 @@ +[ + (struct_definition) + (macro_definition) + (function_definition) + (compound_expression) + (let_statement) + (if_statement) + (for_statement) + (while_statement) + (do_clause) + (parameter_list) +] @indent + +[ + "end" +] @outdent From 565445be6058fc07dd7397a4e32db0c3bf9ba545 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Thu, 30 Mar 2023 20:32:49 -0500 Subject: [PATCH 033/260] Update tree-sitter-git-commit (#6493) The last update introduced a bug with comments where a comment would be recognized as a message if there were multiple newlines between the last message or subject and the comment, causing a noticeable change in highlighting. This change fixes that behavior. --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 0a0e29bae..a8fdc4a83 100644 --- a/languages.toml +++ b/languages.toml @@ -1194,7 +1194,7 @@ text-width = 72 [[grammar]] name = "git-commit" -source = { git = "https://github.com/the-mikedavis/tree-sitter-git-commit", rev = "7421fd81840950c0ff4191733cee3b6ac06cb295" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-git-commit", rev = "bd0ca5a6065f2cada3ac6a82a66db3ceff55fa6b" } [[language]] name = "diff" From a863fd89e149ae698f1c7d1d493cc4197abd430a Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Thu, 30 Mar 2023 15:51:32 +0200 Subject: [PATCH 034/260] update dependencies --- Cargo.lock | 478 ++++++++++++++++++++++++------------------- helix-vcs/Cargo.toml | 2 +- 2 files changed, 274 insertions(+), 206 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 278ab535e..b7ed2c9c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,9 +81,9 @@ checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1" [[package]] name = "bstr" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" +checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" dependencies = [ "memchr", "once_cell", @@ -102,9 +102,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecount" @@ -114,9 +114,9 @@ checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cassowary" @@ -238,9 +238,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.82" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453" +checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" dependencies = [ "cc", "cxxbridge-flags", @@ -250,9 +250,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.82" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0" +checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" dependencies = [ "cc", "codespan-reporting", @@ -260,24 +260,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 1.0.104", + "syn 2.0.11", ] [[package]] name = "cxxbridge-flags" -version = "1.0.82" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71" +checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" [[package]] name = "cxxbridge-macro" -version = "1.0.82" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" +checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 1.0.104", + "syn 2.0.11", ] [[package]] @@ -329,9 +329,9 @@ checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "encoding_rs" @@ -353,13 +353,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.2.8" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys", ] [[package]] @@ -395,32 +395,32 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] [[package]] name = "fern" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd7b0849075e79ee9a1836df22c717d1eba30451796fdc631b04565dd11e2a" +checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee" dependencies = [ "log", ] [[package]] name = "filetime" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if", "libc", - "redox_syscall", - "windows-sys 0.42.0", + "redox_syscall 0.2.16", + "windows-sys", ] [[package]] @@ -506,9 +506,9 @@ dependencies = [ [[package]] name = "gix" -version = "0.41.0" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1853c840375a04e02315cb225b6d802291abfabbf08e500727c98a8670f1bf1" +checksum = "c256ea71cc1967faaefdaad15f334146b7c806f12460dcafd3afed845c8c78dd" dependencies = [ "gix-actor", "gix-attributes", @@ -604,9 +604,9 @@ dependencies = [ [[package]] name = "gix-config" -version = "0.19.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aa7d7dd60256b7a0c0506a1d708ec92767c2662ee57b3301b538eaa3e064f8a" +checksum = "7fbad5ce54a8fc997acc50febd89ec80fa6e97cb7f8d0654cb229936407489d8" dependencies = [ "bstr", "gix-config-value", @@ -615,6 +615,7 @@ dependencies = [ "gix-path", "gix-ref", "gix-sec", + "log", "memchr", "nom", "once_cell", @@ -625,9 +626,9 @@ dependencies = [ [[package]] name = "gix-config-value" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d4a4ba0531e46fe558459557a5b29fb86c3e4b2666c1c0861d93c7c678331" +checksum = "d09154c0c8677e4da0ec35e896f56ee3e338e741b9599fae06075edd83a4081c" dependencies = [ "bitflags 1.3.2", "bstr", @@ -666,9 +667,9 @@ dependencies = [ [[package]] name = "gix-diff" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585b0834d4b6791a848637c4e109545fda9b0f29b591ba55edb33ceda6e7856b" +checksum = "103a0fa79b0d438f5ecb662502f052e530ace4fe1fe8e1c83c0c6da76d728e67" dependencies = [ "gix-hash", "gix-object", @@ -678,9 +679,9 @@ dependencies = [ [[package]] name = "gix-discover" -version = "0.16.0" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b58931ab475a977deff03417e041a66e4bcb76c4e5797e7ec2fcb272ebce01c" +checksum = "6eba8ba458cb8f4a6c33409b0fe650b1258655175a7ffd1d24fafd3ed31d880b" dependencies = [ "bstr", "dunce", @@ -693,9 +694,9 @@ dependencies = [ [[package]] name = "gix-features" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6a9dfa7b3c1a99315203e8b97f8f99f3bd95731590607abeaa5ca31bc41fe3" +checksum = "0b76f9a80f6dd7be66442ae86e1f534effad9546676a392acc95e269d0c21c22" dependencies = [ "crc32fast", "flate2", @@ -741,9 +742,9 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "546ee7855d5d8731288f05a63c07ab41b59cb406660a825ed3fe89d7223823df" +checksum = "717ab601ece7921f59fe86849dbe27d44a46ebb883b5885732c4f30df4996177" dependencies = [ "bitflags 1.3.2", "bstr", @@ -804,9 +805,9 @@ dependencies = [ [[package]] name = "gix-odb" -version = "0.43.0" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa63fce01e5bce663bb24ad01fa2b77266e91b1d1982aab3f67cb0aed8af8169" +checksum = "e83af2e3e36005bfe010927f0dff41fb5acc3e3d89c6f1174135b3a34086bda2" dependencies = [ "arc-swap", "gix-features", @@ -822,9 +823,9 @@ dependencies = [ [[package]] name = "gix-pack" -version = "0.33.0" +version = "0.33.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bc9d22f0d0620d013003ab05ead5c60124b6e1101bc245be9be4fd7e2330cb" +checksum = "9401911c7fe032ad7b31c6a6b5be59cb283d1d6c999417a8215056efe6d635f3" dependencies = [ "clru", "gix-chunk", @@ -844,9 +845,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6c104a66dec149cb8f7aaafc6ab797654cf82d67f050fd0cb7e7294e328354b" +checksum = "32370dce200bb951df013e03dff35b4233fc7a89458642b047629b91734a7e19" dependencies = [ "bstr", "thiserror", @@ -854,9 +855,9 @@ dependencies = [ [[package]] name = "gix-prompt" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20cebf73229debaa82574c4fd20dcaf00fa8d4bfce823a862c4e990d7a0b5b4" +checksum = "0f3034d4d935aef2c7bf719aaa54b88c520e82413118d886ae880a31d5bdee57" dependencies = [ "gix-command", "gix-config-value", @@ -878,9 +879,9 @@ dependencies = [ [[package]] name = "gix-ref" -version = "0.27.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3de7cd1050fa82be4240994defc1f1f2fd9def5d8815dcd005f5ddc5e3dc7511" +checksum = "e4e909396ed3b176823991ccc391c276ae2a015e54edaafa3566d35123cfac9d" dependencies = [ "gix-actor", "gix-features", @@ -911,9 +912,9 @@ dependencies = [ [[package]] name = "gix-revision" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed98e4a0254953c64bc913bd23146a1de662067d5cf974cbdde396958b39e5b0" +checksum = "b12fc4bbc3161a5b2d68079fce93432cef8771ff88ca017abb01187fddfc41a1" dependencies = [ "bstr", "gix-date", @@ -933,14 +934,14 @@ dependencies = [ "dirs", "gix-path", "libc", - "windows", + "windows 0.43.0", ] [[package]] name = "gix-tempfile" -version = "5.0.1" +version = "5.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aed73ef9642f779d609fd19acc332ac1597b978ee87ec11743a68eefaed65bfa" +checksum = "c2ceb30a610e3f5f2d5f9a5114689fde507ba9417705a8cf3429604275b2153c" dependencies = [ "libc", "once_cell", @@ -978,9 +979,9 @@ dependencies = [ [[package]] name = "gix-validate" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69ddb780ea1465255e66818d75b7098371c58dbc9560da4488a44b9f5c7e443" +checksum = "7bd629d3680773e1785e585d76fd4295b740b559cad9141517300d99a0c8c049" dependencies = [ "bstr", "thiserror", @@ -988,9 +989,9 @@ dependencies = [ [[package]] name = "gix-worktree" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "992b8fdade33e079dc61c29f2388ab8e049965ebf7be40efa7f8b80e3c4543fe" +checksum = "54ec9a000b4f24af706c3cc680c7cda235656cbe3216336522f5692773b8a301" dependencies = [ "bstr", "gix-attributes", @@ -1266,13 +1267,19 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.4.3" @@ -1290,16 +1297,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.53" +version = "0.1.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "716f12fbcfac6ffab0a5e9ec51d0a0ff70503742bb2dc7b99396394c9dc323f0" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "winapi", + "windows 0.47.0", ] [[package]] @@ -1351,9 +1358,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", @@ -1386,25 +1393,26 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.4" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" +checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" dependencies = [ + "hermit-abi 0.3.1", "libc", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -1433,18 +1441,18 @@ dependencies = [ [[package]] name = "link-cplusplus" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" dependencies = [ "cc", ] [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "cd550e73688e6d578f0ac2119e32b797a327631a42f9433e59d02e139c8df60d" [[package]] name = "lock_api" @@ -1486,9 +1494,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] @@ -1510,21 +1518,21 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] name = "nix" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ "bitflags 1.3.2", "cfg-if", @@ -1534,9 +1542,9 @@ dependencies = [ [[package]] name = "nom" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -1563,11 +1571,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] @@ -1598,15 +1606,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.4" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -1629,18 +1637,18 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" dependencies = [ "unicode-ident", ] [[package]] name = "prodash" -version = "23.1.1" +version = "23.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d73c6b64cb5b99eb63ca97d378685712617ec0172ff5c04cd47a489d3e2c51f8" +checksum = "9516b775656bc3e8985e19cd4b8c0c0de045095074e453d2c0a513b5f978392d" [[package]] name = "pulldown-cmark" @@ -1698,6 +1706,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -1705,7 +1722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] @@ -1744,23 +1761,23 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.7" +version = "0.37.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" +checksum = "0e78cc525325c06b4a7ff02db283472f3c042b7ff0c391f96c6d5ac6f4f91b75" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "same-file" @@ -1779,35 +1796,35 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scratch" -version = "1.0.2" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "serde" -version = "1.0.158" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.158" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" +checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote", - "syn 2.0.4", + "syn 2.0.11", ] [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" dependencies = [ "itoa", "ryu", @@ -1816,13 +1833,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.9" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" +checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 1.0.104", + "syn 2.0.11", ] [[package]] @@ -1863,9 +1880,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] @@ -1884,9 +1901,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -1947,15 +1964,15 @@ checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" [[package]] name = "str_indices" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9199fa80c817e074620be84374a520062ebac833f358d74b37060ce4a0f2c0" +checksum = "5f026164926842ec52deb1938fae44f83dfdb82d0a5b0270c5bd5935ab74d6dd" [[package]] name = "syn" -version = "1.0.104" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -1964,9 +1981,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.4" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c622ae390c9302e214c31013517c2061ecb2699935882c60a9b37f82f8625ae" +checksum = "21e3787bb71465627110e7d87ed4faaa36c1f61042ee67badb9e2ef173accc40" dependencies = [ "proc-macro2", "quote", @@ -1975,22 +1992,22 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -2032,15 +2049,16 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.4", + "syn 2.0.11", ] [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -2055,9 +2073,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ "itoa", "libc", @@ -2075,9 +2093,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" dependencies = [ "time-core", ] @@ -2093,9 +2111,9 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" @@ -2113,7 +2131,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] @@ -2124,7 +2142,7 @@ checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.4", + "syn 2.0.11", ] [[package]] @@ -2192,9 +2210,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-bom" @@ -2210,9 +2228,9 @@ checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-linebreak" @@ -2265,12 +2283,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] @@ -2282,9 +2299,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2292,24 +2309,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.104", + "syn 1.0.109", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2317,22 +2334,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn 1.0.104", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "which" @@ -2382,28 +2399,22 @@ version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] -name = "windows-sys" -version = "0.42.0" +name = "windows" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "2649ff315bee4c98757f15dac226efe3d81927adbb6e882084bb1ee3e0c330a7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-targets 0.47.0", ] [[package]] @@ -2412,65 +2423,122 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "2f8996d3f43b4b2d44327cd71b7b0efd1284ab60e6e9d0e8b630e18555d87d3e" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.47.0", + "windows_aarch64_msvc 0.47.0", + "windows_i686_gnu 0.47.0", + "windows_i686_msvc 0.47.0", + "windows_x86_64_gnu 0.47.0", + "windows_x86_64_gnullvm 0.47.0", + "windows_x86_64_msvc 0.47.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "831d567d53d4f3cb1db332b68e6e2b6260228eb4d99a777d8b2e8ed794027c90" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a42d54a417c60ce4f0e31661eed628f0fa5aca73448c093ec4d45fab4c51cdf" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1925beafdbb22201a53a483db861a5644123157c1c3cee83323a2ed565d71e3" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "3a8ef8f2f1711b223947d9b69b596cf5a4e452c930fb58b6fc3fdae7d0ec6b31" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acaa0c2cf0d2ef99b61c308a0c3dbae430a51b7345dedec470bd8f53f5a3642" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a0628f71be1d11e17ca4a0e9e15b3a5180f6fbf1c2d55e3ba3f850378052c1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "9d6e62c256dc6d40b8c8707df17df8d774e60e39db723675241e7c15e910bce7" [[package]] name = "winnow" diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml index b32c028bd..8a226a0bb 100644 --- a/helix-vcs/Cargo.toml +++ b/helix-vcs/Cargo.toml @@ -17,7 +17,7 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p parking_lot = "0.12" arc-swap = { version = "1.6.0" } -gix = { version = "0.41.0", default-features = false , optional = true } +gix = { version = "0.43.0", default-features = false , optional = true } imara-diff = "0.1.5" anyhow = "1" From e72be529968071abcd5fce1d9a06e8e2e2bbaacf Mon Sep 17 00:00:00 2001 From: mWalrus Date: Wed, 22 Mar 2023 15:38:34 +0100 Subject: [PATCH 035/260] Truncate paths in the file picker (#6410) --- helix-term/src/ui/menu.rs | 1 + helix-term/src/ui/picker.rs | 1 + helix-tui/src/buffer.rs | 25 +++++++++++++++++++++++++ helix-tui/src/widgets/table.rs | 20 ++++++++++++++++---- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index 30625acee..bdad2e408 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -347,6 +347,7 @@ impl Component for Menu { offset: scroll, selected: self.cursor, }, + false, ); if let Some(cursor) = self.cursor { diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 3294a2a1d..e73088e52 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -885,6 +885,7 @@ impl Component for Picker { offset: 0, selected: Some(cursor), }, + self.truncate_start, ); } diff --git a/helix-tui/src/buffer.rs b/helix-tui/src/buffer.rs index b1fd44787..2c212b125 100644 --- a/helix-tui/src/buffer.rs +++ b/helix-tui/src/buffer.rs @@ -433,6 +433,31 @@ impl Buffer { (x_offset as u16, y) } + pub fn set_spans_truncated(&mut self, x: u16, y: u16, spans: &Spans, width: u16) -> (u16, u16) { + let mut remaining_width = width; + let mut alt_x = x; + let (text, styles) = + spans + .0 + .iter() + .fold((String::new(), vec![]), |(mut s, mut h), span| { + s.push_str(span.content.as_ref()); + let mut styles = span + .styled_graphemes(span.style) + .map(|grapheme| grapheme.style) + .collect(); + h.append(&mut styles); + + let w = span.width() as u16; + alt_x = alt_x + w; + remaining_width = remaining_width.saturating_sub(w); + + (s, h) + }); + self.set_string_truncated(x, y, &text, width.into(), |idx| styles[idx], true, true); + (x, y) + } + pub fn set_spans(&mut self, x: u16, y: u16, spans: &Spans, width: u16) -> (u16, u16) { let mut remaining_width = width; let mut x = x; diff --git a/helix-tui/src/widgets/table.rs b/helix-tui/src/widgets/table.rs index 400f65e0a..97762167e 100644 --- a/helix-tui/src/widgets/table.rs +++ b/helix-tui/src/widgets/table.rs @@ -354,7 +354,13 @@ impl TableState { impl<'a> Table<'a> { // type State = TableState; - pub fn render_table(mut self, area: Rect, buf: &mut Buffer, state: &mut TableState) { + pub fn render_table( + mut self, + area: Rect, + buf: &mut Buffer, + state: &mut TableState, + truncate: bool, + ) { if area.area() == 0 { return; } @@ -401,6 +407,7 @@ impl<'a> Table<'a> { width: *width, height: max_header_height, }, + truncate, ); col += *width + self.column_spacing; } @@ -457,6 +464,7 @@ impl<'a> Table<'a> { width: *width, height: table_row.height, }, + truncate, ); col += *width + self.column_spacing; } @@ -464,20 +472,24 @@ impl<'a> Table<'a> { } } -fn render_cell(buf: &mut Buffer, cell: &Cell, area: Rect) { +fn render_cell(buf: &mut Buffer, cell: &Cell, area: Rect, truncate: bool) { buf.set_style(area, cell.style); for (i, spans) in cell.content.lines.iter().enumerate() { if i as u16 >= area.height { break; } - buf.set_spans(area.x, area.y + i as u16, spans, area.width); + if truncate { + buf.set_spans_truncated(area.x, area.y + i as u16, spans, area.width); + } else { + buf.set_spans(area.x, area.y + i as u16, spans, area.width); + } } } impl<'a> Widget for Table<'a> { fn render(self, area: Rect, buf: &mut Buffer) { let mut state = TableState::default(); - Table::render_table(self, area, buf, &mut state); + Table::render_table(self, area, buf, &mut state, false); } } From 67783ddfd4fc7f06bd6addaa6d65d49759934ace Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Thu, 30 Mar 2023 17:31:54 +0200 Subject: [PATCH 036/260] Performant and correct set_spans_truncated the previous implementation used set_string_truncated. This is not only awkward with this kind of "streaming" string (and therefore lead to an inefficient and incorrect initial implementation) but that function also truncates strings of width 1 when there is only a single char available. The implementation here is performant, correct and also handles the single width case correctly. --- helix-tui/src/buffer.rs | 60 ++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/helix-tui/src/buffer.rs b/helix-tui/src/buffer.rs index 2c212b125..8e0b0adf9 100644 --- a/helix-tui/src/buffer.rs +++ b/helix-tui/src/buffer.rs @@ -434,28 +434,44 @@ impl Buffer { } pub fn set_spans_truncated(&mut self, x: u16, y: u16, spans: &Spans, width: u16) -> (u16, u16) { - let mut remaining_width = width; - let mut alt_x = x; - let (text, styles) = - spans - .0 - .iter() - .fold((String::new(), vec![]), |(mut s, mut h), span| { - s.push_str(span.content.as_ref()); - let mut styles = span - .styled_graphemes(span.style) - .map(|grapheme| grapheme.style) - .collect(); - h.append(&mut styles); - - let w = span.width() as u16; - alt_x = alt_x + w; - remaining_width = remaining_width.saturating_sub(w); - - (s, h) - }); - self.set_string_truncated(x, y, &text, width.into(), |idx| styles[idx], true, true); - (x, y) + // prevent panic if out of range + if !self.in_bounds(x, y) || width == 0 { + return (x, y); + } + + let mut x_offset = x as usize; + let max_offset = min(self.area.right(), width.saturating_add(x)); + let mut start_index = self.index_of(x, y); + let mut index = self.index_of(max_offset as u16, y); + + let content_width = spans.width(); + let truncated = content_width > width as usize; + if truncated { + self.content[start_index].set_symbol("…"); + start_index += 1; + } else { + index -= width as usize - content_width; + } + for span in spans.0.iter().rev() { + for s in span.content.graphemes(true).rev() { + let width = s.width(); + if width == 0 { + continue; + } + let start = index - width; + if start < start_index { + break; + } + self.content[start].set_symbol(s); + self.content[start].set_style(span.style); + for i in start + 1..index { + self.content[i].reset(); + } + index -= width; + x_offset += width; + } + } + (x_offset as u16, y) } pub fn set_spans(&mut self, x: u16, y: u16, spans: &Spans, width: u16) -> (u16, u16) { From ab819d80f1391667f8ff6b149fa4fbe977f4607a Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Thu, 30 Mar 2023 17:56:10 +0200 Subject: [PATCH 037/260] Correctly reload theme on :config-reload The current implementation didn't reload the theme if no no theme was explicitly configured (so the default theme was used). This commit brings `refresh_theme` in line with the initialization code. --- helix-term/src/application.rs | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 4d903eec4..130a74af6 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -393,20 +393,23 @@ impl Application { /// Refresh theme after config change fn refresh_theme(&mut self, config: &Config) -> Result<(), Error> { - if let Some(theme) = config.theme.clone() { - let true_color = self.true_color(); - let theme = self - .theme_loader - .load(&theme) - .map_err(|err| anyhow::anyhow!("Failed to load theme `{}`: {}", theme, err))?; - - if true_color || theme.is_16_color() { - self.editor.set_theme(theme); - } else { - anyhow::bail!("theme requires truecolor support, which is not available") - } - } + let true_color = config.editor.true_color || crate::true_color(); + let theme = config + .theme + .as_ref() + .and_then(|theme| { + self.theme_loader + .load(theme) + .map_err(|e| { + log::warn!("failed to load theme `{}` - {}", theme, e); + e + }) + .ok() + .filter(|theme| (true_color || theme.is_16_color())) + }) + .unwrap_or_else(|| self.theme_loader.default_theme(true_color)); + self.editor.set_theme(theme); Ok(()) } @@ -431,10 +434,6 @@ impl Application { } } - fn true_color(&self) -> bool { - self.config.load().editor.true_color || crate::true_color() - } - #[cfg(windows)] // no signal handling available on windows pub async fn handle_signals(&mut self, _signal: ()) {} From 7a69c40524833f93c3df32ba457a1a658472bb4b Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Thu, 30 Mar 2023 18:22:51 +0200 Subject: [PATCH 038/260] Hide signature help if it overlays completion menu (#5523) --- helix-term/src/commands.rs | 15 ++++++++++++--- helix-term/src/commands/lsp.rs | 17 ++++++++++++++++- helix-term/src/ui/completion.rs | 6 +++++- helix-term/src/ui/editor.rs | 26 ++++++++++++++++++-------- helix-term/src/ui/popup.rs | 28 +++++++++++++++++----------- 5 files changed, 68 insertions(+), 24 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 0f53fdc94..b55f1ab72 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -54,8 +54,8 @@ use crate::{ job::Callback, keymap::ReverseKeymap, ui::{ - self, editor::InsertEvent, overlay::overlayed, FilePicker, Picker, Popup, Prompt, - PromptEvent, + self, editor::InsertEvent, lsp::SignatureHelp, overlay::overlayed, FilePicker, Picker, + Popup, Prompt, PromptEvent, }, }; @@ -4261,7 +4261,7 @@ pub fn completion(cx: &mut Context) { } let size = compositor.size(); let ui = compositor.find::().unwrap(); - ui.set_completion( + let completion_area = ui.set_completion( editor, savepoint, items, @@ -4270,6 +4270,15 @@ pub fn completion(cx: &mut Context) { trigger_offset, size, ); + let size = compositor.size(); + let signature_help_area = compositor + .find_id::>(SignatureHelp::ID) + .map(|signature_help| signature_help.area(size, editor)); + // Delete the signature help popup if they intersect. + if matches!((completion_area, signature_help_area),(Some(a), Some(b)) if a.intersects(b)) + { + compositor.remove(SignatureHelp::ID); + } }, ); } diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 0b0d1db4d..f8e83a46c 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -1221,10 +1221,25 @@ pub fn signature_help_impl(cx: &mut Context, invoked: SignatureHelpInvoked) { contents.set_active_param_range(active_param_range()); let old_popup = compositor.find_id::>(SignatureHelp::ID); - let popup = Popup::new(SignatureHelp::ID, contents) + let mut popup = Popup::new(SignatureHelp::ID, contents) .position(old_popup.and_then(|p| p.get_position())) .position_bias(Open::Above) .ignore_escape_key(true); + + // Don't create a popup if it intersects the auto-complete menu. + let size = compositor.size(); + if compositor + .find::() + .unwrap() + .completion + .as_mut() + .map(|completion| completion.area(size, editor)) + .filter(|area| area.intersects(popup.area(size, editor))) + .is_some() + { + return; + } + compositor.replace_or_push(SignatureHelp::ID, popup); }, ); diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index da6b5ddcb..e0b1419c5 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -414,6 +414,10 @@ impl Completion { true } + + pub fn area(&mut self, viewport: Rect, editor: &Editor) -> Rect { + self.popup.area(viewport, editor) + } } impl Component for Completion { @@ -481,7 +485,7 @@ impl Component for Completion { }; let popup_area = { - let (popup_x, popup_y) = self.popup.get_rel_position(area, cx); + let (popup_x, popup_y) = self.popup.get_rel_position(area, cx.editor); let (popup_width, popup_height) = self.popup.get_size(); Rect::new(popup_x, popup_y, popup_width, popup_height) }; diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index d4b141a04..fd8e8fb21 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -952,7 +952,7 @@ impl EditorView { start_offset: usize, trigger_offset: usize, size: Rect, - ) { + ) -> Option { let mut completion = Completion::new( editor, savepoint, @@ -964,15 +964,17 @@ impl EditorView { if completion.is_empty() { // skip if we got no completion results - return; + return None; } + let area = completion.area(size, editor); editor.last_completion = None; self.last_insert.1.push(InsertEvent::TriggerCompletion); // TODO : propagate required size on resize to completion too completion.required_size((size.width, size.height)); self.completion = Some(completion); + Some(area) } pub fn clear_completion(&mut self, editor: &mut Editor) { @@ -1256,13 +1258,15 @@ impl Component for EditorView { // let completion swallow the event if necessary let mut consumed = false; if let Some(completion) = &mut self.completion { - // use a fake context here - let mut cx = Context { - editor: cx.editor, - jobs: cx.jobs, - scroll: None, + let res = { + // use a fake context here + let mut cx = Context { + editor: cx.editor, + jobs: cx.jobs, + scroll: None, + }; + completion.handle_event(event, &mut cx) }; - let res = completion.handle_event(event, &mut cx); if let EventResult::Consumed(callback) = res { consumed = true; @@ -1270,6 +1274,12 @@ impl Component for EditorView { if callback.is_some() { // assume close_fn self.clear_completion(cx.editor); + + // In case the popup was deleted because of an intersection w/ the auto-complete menu. + commands::signature_help_impl( + &mut cx, + commands::SignatureHelpInvoked::Automatic, + ); } } } diff --git a/helix-term/src/ui/popup.rs b/helix-term/src/ui/popup.rs index 5a95c1bba..dff7b2319 100644 --- a/helix-term/src/ui/popup.rs +++ b/helix-term/src/ui/popup.rs @@ -6,7 +6,10 @@ use crate::{ use tui::buffer::Buffer as Surface; use helix_core::Position; -use helix_view::graphics::{Margin, Rect}; +use helix_view::{ + graphics::{Margin, Rect}, + Editor, +}; // TODO: share logic with Menu, it's essentially Popup(render_fn), but render fn needs to return // a width/height hint. maybe Popup(Box) @@ -88,10 +91,10 @@ impl Popup { /// Calculate the position where the popup should be rendered and return the coordinates of the /// top left corner. - pub fn get_rel_position(&mut self, viewport: Rect, cx: &Context) -> (u16, u16) { + pub fn get_rel_position(&mut self, viewport: Rect, editor: &Editor) -> (u16, u16) { let position = self .position - .get_or_insert_with(|| cx.editor.cursor().0.unwrap_or_default()); + .get_or_insert_with(|| editor.cursor().0.unwrap_or_default()); let (width, height) = self.size; @@ -155,6 +158,16 @@ impl Popup { pub fn contents_mut(&mut self) -> &mut T { &mut self.contents } + + pub fn area(&mut self, viewport: Rect, editor: &Editor) -> Rect { + // trigger required_size so we recalculate if the child changed + self.required_size((viewport.width, viewport.height)); + + let (rel_x, rel_y) = self.get_rel_position(viewport, editor); + + // clip to viewport + viewport.intersection(Rect::new(rel_x, rel_y, self.size.0, self.size.1)) + } } impl Component for Popup { @@ -232,16 +245,9 @@ impl Component for Popup { } fn render(&mut self, viewport: Rect, surface: &mut Surface, cx: &mut Context) { - // trigger required_size so we recalculate if the child changed - self.required_size((viewport.width, viewport.height)); - + let area = self.area(viewport, cx.editor); cx.scroll = Some(self.scroll); - let (rel_x, rel_y) = self.get_rel_position(viewport, cx); - - // clip to viewport - let area = viewport.intersection(Rect::new(rel_x, rel_y, self.size.0, self.size.1)); - // clear area let background = cx.editor.theme.get("ui.popup"); surface.clear_with(area, background); From a48d1a4abc0d23d6bc3cfda714d87b9fa4484da8 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Thu, 30 Mar 2023 18:27:00 +0200 Subject: [PATCH 039/260] Prefer utf-8 over utf-32 Utf-8 support has been around for a while as an unstable feature but utf-32 is fairly new. A bunch of LS (like rust-analyzer) added this in a pinch, but it's pretty broken right now. The performance overhead is not very large (still a lot better than utf-16). We can switch back once the ecosystem has matured. --- helix-lsp/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 3dab6bc55..f94963386 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -538,8 +538,8 @@ impl Client { }), general: Some(lsp::GeneralClientCapabilities { position_encodings: Some(vec![ - PositionEncodingKind::UTF32, PositionEncodingKind::UTF8, + PositionEncodingKind::UTF32, PositionEncodingKind::UTF16, ]), ..Default::default() From 9fe3adcff9866ef18953a067fbc0b84e7eb968b5 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Fri, 31 Mar 2023 04:26:20 +0200 Subject: [PATCH 040/260] add option to enable/disable lsp snippets --- book/src/configuration.md | 1 + helix-lsp/src/client.rs | 4 ++-- helix-lsp/src/lib.rs | 25 ++++++++++++++++++++----- helix-term/src/commands/typed.rs | 9 ++++++--- helix-view/src/editor.rs | 8 ++++++-- 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index 2af0e6326..4c8ff0647 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -127,6 +127,7 @@ The following statusline elements can be configured: | `auto-signature-help` | Enable automatic popup of signature help (parameter hints) | `true` | | `display-inlay-hints` | Display inlay hints[^2] | `false` | | `display-signature-help-docs` | Display docs under signature help popup | `true` | +| `snippets` | Enables snippet completions. Requires a server restart (`:lsp-restart`) to take effect after `:config-reload`/`:set`. | `true` | [^1]: By default, a progress spinner is shown in the statusline beside the file path. [^2]: You may also have to activate them in the LSP config for them to appear, not just in Helix. diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index f94963386..94e994899 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -411,7 +411,7 @@ impl Client { // General messages // ------------------------------------------------------------------------------------------- - pub(crate) async fn initialize(&self) -> Result { + pub(crate) async fn initialize(&self, enable_snippets: bool) -> Result { if let Some(config) = &self.config { log::info!("Using custom LSP config: {}", config); } @@ -459,7 +459,7 @@ impl Client { text_document: Some(lsp::TextDocumentClientCapabilities { completion: Some(lsp::CompletionClientCapabilities { completion_item: Some(lsp::CompletionItemCapability { - snippet_support: Some(true), + snippet_support: Some(enable_snippets), resolve_support: Some(lsp::CompletionItemCapabilityResolveSupport { properties: vec![ String::from("documentation"), diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index d56148a41..c3a5d816e 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -647,6 +647,7 @@ impl Registry { language_config: &LanguageConfiguration, doc_path: Option<&std::path::PathBuf>, root_dirs: &[PathBuf], + enable_snippets: bool, ) -> Result>> { let config = match &language_config.language_server { Some(config) => config, @@ -661,8 +662,14 @@ impl Registry { // initialize a new client let id = self.counter.fetch_add(1, Ordering::Relaxed); - let NewClientResult(client, incoming) = - start_client(id, language_config, config, doc_path, root_dirs)?; + let NewClientResult(client, incoming) = start_client( + id, + language_config, + config, + doc_path, + root_dirs, + enable_snippets, + )?; self.incoming.push(UnboundedReceiverStream::new(incoming)); let old_clients = entry.insert(vec![(id, client.clone())]); @@ -695,6 +702,7 @@ impl Registry { language_config: &LanguageConfiguration, doc_path: Option<&std::path::PathBuf>, root_dirs: &[PathBuf], + enable_snippets: bool, ) -> Result>> { let config = match &language_config.language_server { Some(config) => config, @@ -711,8 +719,14 @@ impl Registry { // initialize a new client let id = self.counter.fetch_add(1, Ordering::Relaxed); - let NewClientResult(client, incoming) = - start_client(id, language_config, config, doc_path, root_dirs)?; + let NewClientResult(client, incoming) = start_client( + id, + language_config, + config, + doc_path, + root_dirs, + enable_snippets, + )?; clients.push((id, client.clone())); self.incoming.push(UnboundedReceiverStream::new(incoming)); Ok(Some(client)) @@ -811,6 +825,7 @@ fn start_client( ls_config: &LanguageServerConfiguration, doc_path: Option<&std::path::PathBuf>, root_dirs: &[PathBuf], + enable_snippets: bool, ) -> Result { let (client, incoming, initialize_notify) = Client::start( &ls_config.command, @@ -834,7 +849,7 @@ fn start_client( .capabilities .get_or_try_init(|| { _client - .initialize() + .initialize(enable_snippets) .map_ok(|response| response.capabilities) }) .await; diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index ca55151ad..0255bbea4 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1378,9 +1378,12 @@ fn lsp_restart( .context("LSP not defined for the current document")?; let scope = config.scope.clone(); - cx.editor - .language_servers - .restart(config, doc.path(), &editor_config.workspace_lsp_roots)?; + cx.editor.language_servers.restart( + config, + doc.path(), + &editor_config.workspace_lsp_roots, + editor_config.lsp.snippets, + )?; // This collect is needed because refresh_language_server would need to re-borrow editor. let document_ids_to_refresh: Vec = cx diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 727e1261d..34c59b9b4 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -352,6 +352,8 @@ pub struct LspConfig { pub display_signature_help_docs: bool, /// Display inlay hints pub display_inlay_hints: bool, + /// Whether to enable snippet support + pub snippets: bool, } impl Default for LspConfig { @@ -362,6 +364,7 @@ impl Default for LspConfig { auto_signature_help: true, display_signature_help_docs: true, display_inlay_hints: false, + snippets: true, } } } @@ -1092,12 +1095,13 @@ impl Editor { // if doc doesn't have a URL it's a scratch buffer, ignore it let doc = self.document(doc_id)?; let (lang, path) = (doc.language.clone(), doc.path().cloned()); - let root_dirs = &doc.config.load().workspace_lsp_roots; + let config = doc.config.load(); + let root_dirs = &config.workspace_lsp_roots; // try to find a language server based on the language name let language_server = lang.as_ref().and_then(|language| { self.language_servers - .get(language, path.as_ref(), root_dirs) + .get(language, path.as_ref(), root_dirs, config.lsp.snippets) .map_err(|e| { log::error!( "Failed to initialize the LSP for `{}` {{ {} }}", From ec55b4d5afcfc827a933697baaf19f44984cc72b Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 31 Mar 2023 01:21:05 -0500 Subject: [PATCH 041/260] Add changelog notes for the 23.03 release (#6455) * changelog: Checkpoint 2023-01-10 commit: 927fa112ec049e5f40309ffdd57c314897e18bbc * changelog: Checkpoint 2023-02-05 commit: 9c98043c1cd6a8b92f35214007a90bb0f287beda * changelog: Checkpoint 2023-03-17 commit: bd473928ae049dfe956f8966bfde19859c148e81 * changelog: Checkpoint 2023-03-27 commit: 5323020c3f02b178f2b6807f13d89bf7f40d3cce * Set a tentative release date for 2023-03-31 * Update CHANGELOG.md * Mention virtual text PR in inlayed type hints feature links * Fix description for 5097 * Rebalance features, usability improvements and fixes * Reorganize some out-of-place changes to the proper sections * Eliminate the LSP configurations section This has a lot of overlap with the 'new languages' section with newly supported LSP configurations. Smaller changes to LSP configurations are not so common so I folded those into the 'updated languages and queries' section. --- CHANGELOG.md | 262 ++++++++++++++++++++++++++++++++++++++ VERSION | 2 +- contrib/Helix.appdata.xml | 3 + 3 files changed, 266 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc91c9ff3..0778fef1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,265 @@ +# 23.03 (2023-03-31) + +> Checkpoint: `5323020c3f02b178f2b6807f13d89bf7f40d3cce` + +For the full log, check out the [git log](https://github.com/helix-editor/helix/compare/22.12..23.03). + +Breaking changes: + +- Select diagnostic range in `goto_*_diag` commands (#4713, #5164, #6193) +- Remove jump behavior from `increment`/`decrement` (#4123, #5929) +- Select change range in `goto_*_change` commands (#5206) +- Split file modification indicator from filename statusline elements (#4731, #6036) +- Jump to symbol ranges in LSP goto commands (#5986) + +Features: + +- Dynamic workspace symbol picker (#5055) +- Soft-wrap (#5420, #5786, #5893, #6142, #6440) +- Initial support for LSP snippet completions (#5864, b1f7528, #6263, bbf4800, 90348b8, f87299f, #6371) +- Add a statusline element for showing the current version control HEAD (#5682) +- Display LSP type hints (#5420, #5934, #6312) +- Enable the Kitty keyboard protocol on terminals with support (#4939, #6170, #6194) +- Add a statusline element for the basename of the current file (#5318) +- Add substring matching syntax for the picker (#5658) +- Support LSP `textDocument/prepareRename` (#6103) +- Allow multiple runtime directories with priorities (#5411) +- Allow configuring whether to insert or replace completions (#5728) + +Commands: + +- `:pipe-to` which pipes selections into a shell command and ignores output (#4931) +- `merge_consecutive_selections` (`A-_`) combines all consecutive selections (#5047) +- `rotate_view_reverse` which focuses the previous view (#5356) +- `goto_declaration` (`gD`, requires LSP) which jumps to a symbol's declaration (#5646) +- `file_picker_in_current_buffer_directory` (#4666) +- `:character-info` which shows information about the character under the cursor (#4000) +- `:toggle-option` for toggling config options at runtime (#4085) +- `dap_restart` for restarting a debug session in DAP (#5651) +- `:lsp-stop` to stop the language server of the current buffer (#5964) +- `:reset-diff-change` for resetting a diff hunk to its original text (#4974) + +Usability improvements: + +- Remove empty detail section in completion menu when LSP doesn't send details (#4902) +- Pass client information on LSP initialization (#4904) +- Allow specifying environment variables for language servers in language config (#4004) +- Allow detached git worktrees to be recognized as root paths (#5097) +- Improve error message handling for theme loading failures (#5073) +- Print the names of binaries required for LSP/DAP in health-check (#5195) +- Improve sorting in the picker in cases of ties (#5169) +- Add theming for prompt suggestions (#5104) +- Open a file picker when using `:open` on directories (#2707, #5278) +- Reload language config with `:config-reload` (#5239, #5381, #5431) +- Improve indent queries for python when the tree is errored (#5332) +- Picker: Open files without closing the picker with `A-ret` (#4435) +- Allow theming cursors by primary/secondary and by mode (#5130) +- Allow configuration of the minimum width for the line-numbers gutter (#4724, #5696) +- Use filename completer for `:run-shell-command` command (#5729) +- Surround with line-endings with `ms` (#4571) +- Hide duplicate symlinks in file pickers (#5658) +- Tabulate buffer picker contents (#5777) +- Add an option to disable LSP (#4425) +- Short-circuit tree-sitter and word object motions (#5851) +- Add exit code to failed command message (#5898) +- Make `m` textobject look for pairs enclosing selections (#3344) +- Negotiate LSP position encoding (#5894) +- Display deprecated LSP completions with strikethrough (#5932) +- Add JSONRPC request ID to failed LSP/DAP request log messages (#6010, #6018) +- Ignore case when filtering LSP completions (#6008) +- Show current language when no arguments are passed to `:set-language` (#5895) +- Refactor and rewrite all book documentation (#5534) +- Separate diagnostic picker message and code (#6095) +- Add a config option to bypass undercurl detection (#6253) +- Only complete appropriate arguments for typed commands (#5966) +- Discard outdated LSP diagnostics (3c9d5d0) +- Discard outdated LSP workspace edits (b6a4927) +- Run shell commands asynchronously (#6373) +- Show diagnostic codes in LSP diagnostic messages (#6378) + +Fixes: + +- Fix behavior of `auto-completion` flag for completion-on-trigger (#5042) +- Reset editor mode when changing buffers (#5072) +- Respect scrolloff settings in mouse movements (#5255) +- Avoid trailing `s` when only one file is opened (#5189) +- Fix erroneous indent between closers of auto-pairs (#5330) +- Expand `~` when parsing file paths in `:open` (#5329) +- Fix theme inheritance for default themes (#5218) +- Fix `extend_line` with a count when the current line(s) are selected (#5288) +- Prompt: Fix autocompletion for paths containing periods (#5175) +- Skip serializing JSONRPC params if params is null (#5471) +- Fix interaction with the `xclip` clipboard provider (#5426) +- Fix undo/redo execution from the command palette (#5294) +- Fix highlighting of non-block cursors (#5575) +- Fix panic when nooping in `join_selections` and `join_selections_space` (#5423) +- Fix selecting a changed file in global search (#5639) +- Fix initial syntax highlight layer sort order (#5196) +- Fix UTF-8 length handling for shellwords (#5738) +- Remove C-j and C-k bindings from the completion menu (#5070) +- Always commit to history when pasting (#5790) +- Properly handle LSP position encoding (#5711) +- Fix infinite loop in `copy_selection_on_prev_line` (#5888) +- Fix completion popup positioning (#5842) +- Fix a panic when uncommenting a line with only a comment token (#5933) +- Fix panic in `goto_window_center` at EOF (#5987) +- Ignore invalid file URIs sent by a language server (#6000) +- Decode LSP URIs for the workspace diagnostics picker (#6016) +- Fix incorrect usages of `tab_width` with `indent_width` (#5918) +- DAP: Send Disconnect if the Terminated event is received (#5532) +- DAP: Validate key and index exist when requesting variables (#5628) +- Check LSP renaming support before prompting for rename text (#6257) +- Fix indent guide rendering (#6136) +- Fix division by zero panic (#6155) +- Fix lacking space panic (#6109) +- Send error replies for malformed and unhandled LSP requests (#6058) +- Fix table column calculations for dynamic pickers (#5920) +- Skip adding jumplist entries for `:` line number previews (#5751) +- Fix completion race conditions (#6173) +- Fix `shrink_selection` with multiple cursors (#6093) +- Fix indentation calculation for lines with mixed tabs/spaces (#6278) +- No-op `client/registerCapability` LSP requests (#6258) +- Send the STOP signal to all processes in the process group (#3546) +- Fix workspace edit client capabilities declaration (7bf168d) +- Fix highlighting in picker results with multiple columns (#6333) + +Themes: + +- Update `serika` (#5038, #6344) +- Update `flatwhite` (#5036, #6323) +- Update `autumn` (#5051, #5397, #6280, #6316) +- Update `acme` (#5019, #5486, #5488) +- Update `gruvbox` themes (#5066, #5333, #5540, #6285, #6295) +- Update `base16_transparent` (#5105) +- Update `dark_high_contrast` (#5105) +- Update `dracula` (#5236, #5627, #6414) +- Update `monokai_pro_spectrum` (#5250, #5602) +- Update `rose_pine` (#5267, #5489, #6384) +- Update `kanagawa` (#5273, #5571, #6085) +- Update `emacs` (#5334) +- Add `github` themes (#5353, efeec12) + - Dark themes: `github_dark`, `github_dark_colorblind`, `github_dark_dimmed`, `github_dark_high_contrast`, `github_dark_tritanopia` + - Light themes: `github_light`, `github_light_colorblind`, `github_light_dimmed`, `github_light_high_contrast`, `github_light_tritanopia` +- Update `solarized` variants (#5445, #6327) +- Update `catppuccin` variants (#5404, #6107, #6269) +- Use curly underlines in built-in themes (#5419) +- Update `zenburn` (#5573) +- Rewrite `snazzy` (#3971) +- Add `monokai_aqua` (#5578) +- Add `markup.strikethrough` to existing themes (#5619) +- Update `sonokai` (#5440) +- Update `onedark` (#5755) +- Add `ayu_evolve` (#5638, #6028, #6225) +- Add `jellybeans` (#5719) +- Update `fleet_dark` (#5605, #6266, #6324, #6375) +- Add `darcula-solid` (#5778) +- Remove text background from monokai themes (#6009) +- Update `pop_dark` (#5992, #6208, #6227, #6292) +- Add `everblush` (#6086) +- Add `adwaita-dark` (#6042, #6342) +- Update `papercolor` (#6162) +- Update `onelight` (#6192, #6276) +- Add `molokai` (#6260) +- Update `ayu` variants (#6329) +- Update `tokyonight` variants (#6349) +- Update `nord` variants (#6376) + +New languages: + +- BibTeX (#5064) +- Mermaid.js (#5147) +- Crystal (#4993, #5205) +- MATLAB/Octave (#5192) +- `tfvars` (uses HCL) (#5396) +- Ponylang (#5416) +- DHall (1f6809c) +- Sagemath (#5649) +- MSBuild (#5793) +- pem (#5797) +- passwd (#4959) +- hosts (#4950, #5914) +- uxntal (#6047) +- Yuck (#6064, #6242) +- GNU gettext PO (#5996) +- Sway (#6023) +- NASM (#6068) +- PRQL (#6126) +- reStructuredText (#6180) +- Smithy (#6370) +- VHDL (#5826) +- Rego (OpenPolicy Agent) (#6415) +- Nim (#6123) + +Updated languages and queries: + +- Use diff syntax for patch files (#5085) +- Add Haskell textobjects (#5061) +- Fix commonlisp configuration (#5091) +- Update Scheme (bae890d) +- Add indent queries for Bash (#5149) +- Recognize `c++` as a C++ extension (#5183) +- Enable HTTP server in `metals` (Scala) config (#5551) +- Change V-lang language server to `v ls` from `vls` (#5677) +- Inject comment grammar into Nix (#5208) +- Update Rust highlights (#5238, #5349) +- Fix HTML injection within Markdown (#5265) +- Fix comment token for godot (#5276) +- Expand injections for Vue (#5268) +- Add `.bash_aliases` as a Bash file-type (#5347) +- Fix comment token for sshclientconfig (#5351) +- Update Prisma (#5417) +- Update C++ (#5457) +- Add more file-types for Python (#5593) +- Update tree-sitter-scala (#5576) +- Add an injection regex for Lua (#5606) +- Add `build.gradle` to java roots configuration (#5641) +- Add Hub PR files to markdown file-types (#5634) +- Add an external formatter configuration for Cue (#5679) +- Add injections for builders and writers to Nix (#5629) +- Update tree-sitter-xml to fix whitespace parsing (#5685) +- Add `Justfile` to the make file-types configuration (#5687) +- Update tree-sitter-sql and highlight queries (#5683, #5772) +- Use the bash grammar and queries for env language (#5720) +- Add podspec files to ruby file-types (#5811) +- Recognize `.C` and `.H` file-types as C++ (#5808) +- Recognize plist and mobileconfig files as XML (#5863) +- Fix `select` indentation in Go (#5713) +- Check for external file modifications when writing (#5805) +- Recognize containerfiles as dockerfile syntax (#5873) +- Update godot grammar and queries (#5944, #6186) +- Improve DHall highlights (#5959) +- Recognize `.env.dist` and `source.env` as env language (#6003) +- Update tree-sitter-git-rebase (#6030, #6094) +- Improve SQL highlights (#6041) +- Improve markdown highlights and inject LaTeX (#6100) +- Add textobject queries for Elm (#6084) +- Recognize graphql schema file type (#6159) +- Improve highlighting in comments (#6143) +- Improve highlighting for JavaScript/TypeScript/ECMAScript languages (#6205) +- Improve PHP highlights (#6203, #6250, #6299) +- Improve Go highlights (#6204) +- Highlight unchecked sqlx functions as SQL in Rust (#6256) +- Improve Erlang highlights (cdd6c8d) +- Improve Nix highlights (fb4d703) +- Improve gdscript highlights (#6311) +- Improve Vlang highlights (#6279) +- Improve Makefile highlights (#6339) +- Remove auto-pair for `'` in OCaml (#6381) +- Fix indents in switch statements in ECMA languages (#6369) +- Recognize xlb and storyboard file-types as XML (#6407) +- Recognize cts and mts file-types as TypeScript (#6424) +- Recognize SVG file-type as XML (#6431) +- Add theme scopes for (un)checked list item markup scopes (#6434) +- Update git commit grammar and add the comment textobject (#6439) +- Recognize ARB file-type as JSON (#6452) + +Packaging: + +- Fix Nix flake devShell for darwin hosts (#5368) +- Add Appstream metadata file to `contrib/` (#5643) +- Increase the MSRV to 1.65 (#5570, #6185) +- Expose the Nix flake's `wrapper` (#5994) + # 22.12 (2022-12-06) This is a great big release filled with changes from a 99 contributors. A big _thank you_ to you all! diff --git a/VERSION b/VERSION index e70b3aebd..35371314c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -22.12 \ No newline at end of file +23.03 \ No newline at end of file diff --git a/contrib/Helix.appdata.xml b/contrib/Helix.appdata.xml index a24284975..b99738a18 100644 --- a/contrib/Helix.appdata.xml +++ b/contrib/Helix.appdata.xml @@ -36,6 +36,9 @@ + + https://helix-editor.com/news/release-23-03-highlights/ + https://helix-editor.com/news/release-22-12-highlights/ From e59cb19892c7b3987d9e27ae8505a5a42bc4e07d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Fri, 31 Mar 2023 17:13:51 +0900 Subject: [PATCH 042/260] Disable aarch64-macos build for now (build issues) --- .github/workflows/release.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9518a5373..bc1533593 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -85,12 +85,13 @@ jobs: rust: stable target: x86_64-pc-windows-msvc cross: false - - build: aarch64-macos - os: macos-latest - rust: stable - target: aarch64-apple-darwin - cross: false - skip_tests: true # x86_64 host can't run aarch64 code + # 23.03: build issues + # - build: aarch64-macos + # os: macos-latest + # rust: stable + # target: aarch64-apple-darwin + # cross: false + # skip_tests: true # x86_64 host can't run aarch64 code # - build: x86_64-win-gnu # os: windows-2019 # rust: stable-x86_64-gnu From 3cf037237f1d080fdcb7990250955701389ae072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Fri, 31 Mar 2023 17:14:01 +0900 Subject: [PATCH 043/260] Fix AppImage build problems --- .github/workflows/release.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bc1533593..2fa34e1f3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -156,6 +156,10 @@ jobs: shell: bash if: matrix.build == 'aarch64-linux' || matrix.build == 'x86_64-linux' run: | + # Required as of 22.x https://github.com/AppImage/AppImageKit/wiki/FUSE + sudo add-apt-repository universe + sudo apt install libfuse2 + mkdir dist name=dev From 406c5c38a1bb0475579c7d4cd1fd7a90f09d543c Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 31 Mar 2023 22:10:41 -0500 Subject: [PATCH 044/260] changelog: Add remaining notes for 23.03 (#6498) * changelog: Add remaining notes for 23.03 * changelog: Convert PR/commit names to links * Split out 5748 into multiple bullets --- CHANGELOG.md | 467 ++++++++++++++++++++++++++------------------------- 1 file changed, 239 insertions(+), 228 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0778fef1d..01184571e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,264 +1,275 @@ # 23.03 (2023-03-31) -> Checkpoint: `5323020c3f02b178f2b6807f13d89bf7f40d3cce` +23.03 brings some long-awaited and exciting features. Thank you to everyone involved! This release saw changes from 102 contributors. For the full log, check out the [git log](https://github.com/helix-editor/helix/compare/22.12..23.03). +Also check out the [release notes](https://helix-editor.com/news/release-23-03-highlights/) for more commentary on larger features. Breaking changes: -- Select diagnostic range in `goto_*_diag` commands (#4713, #5164, #6193) -- Remove jump behavior from `increment`/`decrement` (#4123, #5929) -- Select change range in `goto_*_change` commands (#5206) -- Split file modification indicator from filename statusline elements (#4731, #6036) -- Jump to symbol ranges in LSP goto commands (#5986) +- Select diagnostic range in `goto_*_diag` commands ([#4713](https://github.com/helix-editor/helix/pull/4713), [#5164](https://github.com/helix-editor/helix/pull/5164), [#6193](https://github.com/helix-editor/helix/pull/6193)) +- Remove jump behavior from `increment`/`decrement` ([#4123](https://github.com/helix-editor/helix/pull/4123), [#5929](https://github.com/helix-editor/helix/pull/5929)) +- Select change range in `goto_*_change` commands ([#5206](https://github.com/helix-editor/helix/pull/5206)) +- Split file modification indicator from filename statusline elements ([#4731](https://github.com/helix-editor/helix/pull/4731), [#6036](https://github.com/helix-editor/helix/pull/6036)) +- Jump to symbol ranges in LSP goto commands ([#5986](https://github.com/helix-editor/helix/pull/5986)) +- Workspace detection now stops at the first `.helix/` directory (merging multiple `.helix/languages.toml` configurations is no longer supported) ([#5748](https://github.com/helix-editor/helix/pull/5748)) Features: -- Dynamic workspace symbol picker (#5055) -- Soft-wrap (#5420, #5786, #5893, #6142, #6440) -- Initial support for LSP snippet completions (#5864, b1f7528, #6263, bbf4800, 90348b8, f87299f, #6371) -- Add a statusline element for showing the current version control HEAD (#5682) -- Display LSP type hints (#5420, #5934, #6312) -- Enable the Kitty keyboard protocol on terminals with support (#4939, #6170, #6194) -- Add a statusline element for the basename of the current file (#5318) -- Add substring matching syntax for the picker (#5658) -- Support LSP `textDocument/prepareRename` (#6103) -- Allow multiple runtime directories with priorities (#5411) -- Allow configuring whether to insert or replace completions (#5728) +- Dynamic workspace symbol picker ([#5055](https://github.com/helix-editor/helix/pull/5055)) +- Soft-wrap ([#5420](https://github.com/helix-editor/helix/pull/5420), [#5786](https://github.com/helix-editor/helix/pull/5786), [#5893](https://github.com/helix-editor/helix/pull/5893), [#6142](https://github.com/helix-editor/helix/pull/6142), [#6440](https://github.com/helix-editor/helix/pull/6440)) +- Initial support for LSP snippet completions ([#5864](https://github.com/helix-editor/helix/pull/5864), [b1f7528](https://github.com/helix-editor/helix/commit/b1f7528), [#6263](https://github.com/helix-editor/helix/pull/6263), [bbf4800](https://github.com/helix-editor/helix/commit/bbf4800), [90348b8](https://github.com/helix-editor/helix/commit/90348b8), [f87299f](https://github.com/helix-editor/helix/commit/f87299f), [#6371](https://github.com/helix-editor/helix/pull/6371), [9fe3adc](https://github.com/helix-editor/helix/commit/9fe3adc)) +- Add a statusline element for showing the current version control HEAD ([#5682](https://github.com/helix-editor/helix/pull/5682)) +- Display LSP type hints ([#5420](https://github.com/helix-editor/helix/pull/5420), [#5934](https://github.com/helix-editor/helix/pull/5934), [#6312](https://github.com/helix-editor/helix/pull/6312)) +- Enable the Kitty keyboard protocol on terminals with support ([#4939](https://github.com/helix-editor/helix/pull/4939), [#6170](https://github.com/helix-editor/helix/pull/6170), [#6194](https://github.com/helix-editor/helix/pull/6194), [#6438](https://github.com/helix-editor/helix/pull/6438)) +- Add a statusline element for the basename of the current file ([#5318](https://github.com/helix-editor/helix/pull/5318)) +- Add substring matching syntax for the picker ([#5658](https://github.com/helix-editor/helix/pull/5658)) +- Support LSP `textDocument/prepareRename` ([#6103](https://github.com/helix-editor/helix/pull/6103)) +- Allow multiple runtime directories with priorities ([#5411](https://github.com/helix-editor/helix/pull/5411)) +- Allow configuring whether to insert or replace completions ([#5728](https://github.com/helix-editor/helix/pull/5728)) +- Allow per-workspace config file `.helix/config.toml` ([#5748](https://github.com/helix-editor/helix/pull/5748)) +- Add `workspace-lsp-roots` config option to support multiple LSP roots for use with monorepos ([#5748](https://github.com/helix-editor/helix/pull/5748)) Commands: -- `:pipe-to` which pipes selections into a shell command and ignores output (#4931) -- `merge_consecutive_selections` (`A-_`) combines all consecutive selections (#5047) -- `rotate_view_reverse` which focuses the previous view (#5356) -- `goto_declaration` (`gD`, requires LSP) which jumps to a symbol's declaration (#5646) -- `file_picker_in_current_buffer_directory` (#4666) -- `:character-info` which shows information about the character under the cursor (#4000) -- `:toggle-option` for toggling config options at runtime (#4085) -- `dap_restart` for restarting a debug session in DAP (#5651) -- `:lsp-stop` to stop the language server of the current buffer (#5964) -- `:reset-diff-change` for resetting a diff hunk to its original text (#4974) +- `:pipe-to` which pipes selections into a shell command and ignores output ([#4931](https://github.com/helix-editor/helix/pull/4931)) +- `merge_consecutive_selections` (`A-_`) combines all consecutive selections ([#5047](https://github.com/helix-editor/helix/pull/5047)) +- `rotate_view_reverse` which focuses the previous view ([#5356](https://github.com/helix-editor/helix/pull/5356)) +- `goto_declaration` (`gD`, requires LSP) which jumps to a symbol's declaration ([#5646](https://github.com/helix-editor/helix/pull/5646)) +- `file_picker_in_current_buffer_directory` ([#4666](https://github.com/helix-editor/helix/pull/4666)) +- `:character-info` which shows information about the character under the cursor ([#4000](https://github.com/helix-editor/helix/pull/4000)) +- `:toggle-option` for toggling config options at runtime ([#4085](https://github.com/helix-editor/helix/pull/4085)) +- `dap_restart` for restarting a debug session in DAP ([#5651](https://github.com/helix-editor/helix/pull/5651)) +- `:lsp-stop` to stop the language server of the current buffer ([#5964](https://github.com/helix-editor/helix/pull/5964)) +- `:reset-diff-change` for resetting a diff hunk to its original text ([#4974](https://github.com/helix-editor/helix/pull/4974)) +- `:config-open-workspace` for opening the config file local to the current workspace ([#5748](https://github.com/helix-editor/helix/pull/5748)) Usability improvements: -- Remove empty detail section in completion menu when LSP doesn't send details (#4902) -- Pass client information on LSP initialization (#4904) -- Allow specifying environment variables for language servers in language config (#4004) -- Allow detached git worktrees to be recognized as root paths (#5097) -- Improve error message handling for theme loading failures (#5073) -- Print the names of binaries required for LSP/DAP in health-check (#5195) -- Improve sorting in the picker in cases of ties (#5169) -- Add theming for prompt suggestions (#5104) -- Open a file picker when using `:open` on directories (#2707, #5278) -- Reload language config with `:config-reload` (#5239, #5381, #5431) -- Improve indent queries for python when the tree is errored (#5332) -- Picker: Open files without closing the picker with `A-ret` (#4435) -- Allow theming cursors by primary/secondary and by mode (#5130) -- Allow configuration of the minimum width for the line-numbers gutter (#4724, #5696) -- Use filename completer for `:run-shell-command` command (#5729) -- Surround with line-endings with `ms` (#4571) -- Hide duplicate symlinks in file pickers (#5658) -- Tabulate buffer picker contents (#5777) -- Add an option to disable LSP (#4425) -- Short-circuit tree-sitter and word object motions (#5851) -- Add exit code to failed command message (#5898) -- Make `m` textobject look for pairs enclosing selections (#3344) -- Negotiate LSP position encoding (#5894) -- Display deprecated LSP completions with strikethrough (#5932) -- Add JSONRPC request ID to failed LSP/DAP request log messages (#6010, #6018) -- Ignore case when filtering LSP completions (#6008) -- Show current language when no arguments are passed to `:set-language` (#5895) -- Refactor and rewrite all book documentation (#5534) -- Separate diagnostic picker message and code (#6095) -- Add a config option to bypass undercurl detection (#6253) -- Only complete appropriate arguments for typed commands (#5966) -- Discard outdated LSP diagnostics (3c9d5d0) -- Discard outdated LSP workspace edits (b6a4927) -- Run shell commands asynchronously (#6373) -- Show diagnostic codes in LSP diagnostic messages (#6378) +- Remove empty detail section in completion menu when LSP doesn't send details ([#4902](https://github.com/helix-editor/helix/pull/4902)) +- Pass client information on LSP initialization ([#4904](https://github.com/helix-editor/helix/pull/4904)) +- Allow specifying environment variables for language servers in language config ([#4004](https://github.com/helix-editor/helix/pull/4004)) +- Allow detached git worktrees to be recognized as root paths ([#5097](https://github.com/helix-editor/helix/pull/5097)) +- Improve error message handling for theme loading failures ([#5073](https://github.com/helix-editor/helix/pull/5073)) +- Print the names of binaries required for LSP/DAP in health-check ([#5195](https://github.com/helix-editor/helix/pull/5195)) +- Improve sorting in the picker in cases of ties ([#5169](https://github.com/helix-editor/helix/pull/5169)) +- Add theming for prompt suggestions ([#5104](https://github.com/helix-editor/helix/pull/5104)) +- Open a file picker when using `:open` on directories ([#2707](https://github.com/helix-editor/helix/pull/2707), [#5278](https://github.com/helix-editor/helix/pull/5278)) +- Reload language config with `:config-reload` ([#5239](https://github.com/helix-editor/helix/pull/5239), [#5381](https://github.com/helix-editor/helix/pull/5381), [#5431](https://github.com/helix-editor/helix/pull/5431)) +- Improve indent queries for python when the tree is errored ([#5332](https://github.com/helix-editor/helix/pull/5332)) +- Picker: Open files without closing the picker with `A-ret` ([#4435](https://github.com/helix-editor/helix/pull/4435)) +- Allow theming cursors by primary/secondary and by mode ([#5130](https://github.com/helix-editor/helix/pull/5130)) +- Allow configuration of the minimum width for the line-numbers gutter ([#4724](https://github.com/helix-editor/helix/pull/4724), [#5696](https://github.com/helix-editor/helix/pull/5696)) +- Use filename completer for `:run-shell-command` command ([#5729](https://github.com/helix-editor/helix/pull/5729)) +- Surround with line-endings with `ms` ([#4571](https://github.com/helix-editor/helix/pull/4571)) +- Hide duplicate symlinks in file pickers ([#5658](https://github.com/helix-editor/helix/pull/5658)) +- Tabulate buffer picker contents ([#5777](https://github.com/helix-editor/helix/pull/5777)) +- Add an option to disable LSP ([#4425](https://github.com/helix-editor/helix/pull/4425)) +- Short-circuit tree-sitter and word object motions ([#5851](https://github.com/helix-editor/helix/pull/5851)) +- Add exit code to failed command message ([#5898](https://github.com/helix-editor/helix/pull/5898)) +- Make `m` textobject look for pairs enclosing selections ([#3344](https://github.com/helix-editor/helix/pull/3344)) +- Negotiate LSP position encoding ([#5894](https://github.com/helix-editor/helix/pull/5894), [a48d1a4](https://github.com/helix-editor/helix/commit/a48d1a4)) +- Display deprecated LSP completions with strikethrough ([#5932](https://github.com/helix-editor/helix/pull/5932)) +- Add JSONRPC request ID to failed LSP/DAP request log messages ([#6010](https://github.com/helix-editor/helix/pull/6010), [#6018](https://github.com/helix-editor/helix/pull/6018)) +- Ignore case when filtering LSP completions ([#6008](https://github.com/helix-editor/helix/pull/6008)) +- Show current language when no arguments are passed to `:set-language` ([#5895](https://github.com/helix-editor/helix/pull/5895)) +- Refactor and rewrite all book documentation ([#5534](https://github.com/helix-editor/helix/pull/5534)) +- Separate diagnostic picker message and code ([#6095](https://github.com/helix-editor/helix/pull/6095)) +- Add a config option to bypass undercurl detection ([#6253](https://github.com/helix-editor/helix/pull/6253)) +- Only complete appropriate arguments for typed commands ([#5966](https://github.com/helix-editor/helix/pull/5966)) +- Discard outdated LSP diagnostics ([3c9d5d0](https://github.com/helix-editor/helix/commit/3c9d5d0)) +- Discard outdated LSP workspace edits ([b6a4927](https://github.com/helix-editor/helix/commit/b6a4927)) +- Run shell commands asynchronously ([#6373](https://github.com/helix-editor/helix/pull/6373)) +- Show diagnostic codes in LSP diagnostic messages ([#6378](https://github.com/helix-editor/helix/pull/6378)) +- Highlight the current line in a DAP debug session ([#5957](https://github.com/helix-editor/helix/pull/5957)) +- Hide signature help if it overlaps with the completion menu ([#5523](https://github.com/helix-editor/helix/pull/5523), [7a69c40](https://github.com/helix-editor/helix/commit/7a69c40)) Fixes: -- Fix behavior of `auto-completion` flag for completion-on-trigger (#5042) -- Reset editor mode when changing buffers (#5072) -- Respect scrolloff settings in mouse movements (#5255) -- Avoid trailing `s` when only one file is opened (#5189) -- Fix erroneous indent between closers of auto-pairs (#5330) -- Expand `~` when parsing file paths in `:open` (#5329) -- Fix theme inheritance for default themes (#5218) -- Fix `extend_line` with a count when the current line(s) are selected (#5288) -- Prompt: Fix autocompletion for paths containing periods (#5175) -- Skip serializing JSONRPC params if params is null (#5471) -- Fix interaction with the `xclip` clipboard provider (#5426) -- Fix undo/redo execution from the command palette (#5294) -- Fix highlighting of non-block cursors (#5575) -- Fix panic when nooping in `join_selections` and `join_selections_space` (#5423) -- Fix selecting a changed file in global search (#5639) -- Fix initial syntax highlight layer sort order (#5196) -- Fix UTF-8 length handling for shellwords (#5738) -- Remove C-j and C-k bindings from the completion menu (#5070) -- Always commit to history when pasting (#5790) -- Properly handle LSP position encoding (#5711) -- Fix infinite loop in `copy_selection_on_prev_line` (#5888) -- Fix completion popup positioning (#5842) -- Fix a panic when uncommenting a line with only a comment token (#5933) -- Fix panic in `goto_window_center` at EOF (#5987) -- Ignore invalid file URIs sent by a language server (#6000) -- Decode LSP URIs for the workspace diagnostics picker (#6016) -- Fix incorrect usages of `tab_width` with `indent_width` (#5918) -- DAP: Send Disconnect if the Terminated event is received (#5532) -- DAP: Validate key and index exist when requesting variables (#5628) -- Check LSP renaming support before prompting for rename text (#6257) -- Fix indent guide rendering (#6136) -- Fix division by zero panic (#6155) -- Fix lacking space panic (#6109) -- Send error replies for malformed and unhandled LSP requests (#6058) -- Fix table column calculations for dynamic pickers (#5920) -- Skip adding jumplist entries for `:` line number previews (#5751) -- Fix completion race conditions (#6173) -- Fix `shrink_selection` with multiple cursors (#6093) -- Fix indentation calculation for lines with mixed tabs/spaces (#6278) -- No-op `client/registerCapability` LSP requests (#6258) -- Send the STOP signal to all processes in the process group (#3546) -- Fix workspace edit client capabilities declaration (7bf168d) -- Fix highlighting in picker results with multiple columns (#6333) +- Fix behavior of `auto-completion` flag for completion-on-trigger ([#5042](https://github.com/helix-editor/helix/pull/5042)) +- Reset editor mode when changing buffers ([#5072](https://github.com/helix-editor/helix/pull/5072)) +- Respect scrolloff settings in mouse movements ([#5255](https://github.com/helix-editor/helix/pull/5255)) +- Avoid trailing `s` when only one file is opened ([#5189](https://github.com/helix-editor/helix/pull/5189)) +- Fix erroneous indent between closers of auto-pairs ([#5330](https://github.com/helix-editor/helix/pull/5330)) +- Expand `~` when parsing file paths in `:open` ([#5329](https://github.com/helix-editor/helix/pull/5329)) +- Fix theme inheritance for default themes ([#5218](https://github.com/helix-editor/helix/pull/5218)) +- Fix `extend_line` with a count when the current line(s) are selected ([#5288](https://github.com/helix-editor/helix/pull/5288)) +- Prompt: Fix autocompletion for paths containing periods ([#5175](https://github.com/helix-editor/helix/pull/5175)) +- Skip serializing JSONRPC params if params is null ([#5471](https://github.com/helix-editor/helix/pull/5471)) +- Fix interaction with the `xclip` clipboard provider ([#5426](https://github.com/helix-editor/helix/pull/5426)) +- Fix undo/redo execution from the command palette ([#5294](https://github.com/helix-editor/helix/pull/5294)) +- Fix highlighting of non-block cursors ([#5575](https://github.com/helix-editor/helix/pull/5575)) +- Fix panic when nooping in `join_selections` and `join_selections_space` ([#5423](https://github.com/helix-editor/helix/pull/5423)) +- Fix selecting a changed file in global search ([#5639](https://github.com/helix-editor/helix/pull/5639)) +- Fix initial syntax highlight layer sort order ([#5196](https://github.com/helix-editor/helix/pull/5196)) +- Fix UTF-8 length handling for shellwords ([#5738](https://github.com/helix-editor/helix/pull/5738)) +- Remove C-j and C-k bindings from the completion menu ([#5070](https://github.com/helix-editor/helix/pull/5070)) +- Always commit to history when pasting ([#5790](https://github.com/helix-editor/helix/pull/5790)) +- Properly handle LSP position encoding ([#5711](https://github.com/helix-editor/helix/pull/5711)) +- Fix infinite loop in `copy_selection_on_prev_line` ([#5888](https://github.com/helix-editor/helix/pull/5888)) +- Fix completion popup positioning ([#5842](https://github.com/helix-editor/helix/pull/5842)) +- Fix a panic when uncommenting a line with only a comment token ([#5933](https://github.com/helix-editor/helix/pull/5933)) +- Fix panic in `goto_window_center` at EOF ([#5987](https://github.com/helix-editor/helix/pull/5987)) +- Ignore invalid file URIs sent by a language server ([#6000](https://github.com/helix-editor/helix/pull/6000)) +- Decode LSP URIs for the workspace diagnostics picker ([#6016](https://github.com/helix-editor/helix/pull/6016)) +- Fix incorrect usages of `tab_width` with `indent_width` ([#5918](https://github.com/helix-editor/helix/pull/5918)) +- DAP: Send Disconnect if the Terminated event is received ([#5532](https://github.com/helix-editor/helix/pull/5532)) +- DAP: Validate key and index exist when requesting variables ([#5628](https://github.com/helix-editor/helix/pull/5628)) +- Check LSP renaming support before prompting for rename text ([#6257](https://github.com/helix-editor/helix/pull/6257)) +- Fix indent guide rendering ([#6136](https://github.com/helix-editor/helix/pull/6136)) +- Fix division by zero panic ([#6155](https://github.com/helix-editor/helix/pull/6155)) +- Fix lacking space panic ([#6109](https://github.com/helix-editor/helix/pull/6109)) +- Send error replies for malformed and unhandled LSP requests ([#6058](https://github.com/helix-editor/helix/pull/6058)) +- Fix table column calculations for dynamic pickers ([#5920](https://github.com/helix-editor/helix/pull/5920)) +- Skip adding jumplist entries for `:` line number previews ([#5751](https://github.com/helix-editor/helix/pull/5751)) +- Fix completion race conditions ([#6173](https://github.com/helix-editor/helix/pull/6173)) +- Fix `shrink_selection` with multiple cursors ([#6093](https://github.com/helix-editor/helix/pull/6093)) +- Fix indentation calculation for lines with mixed tabs/spaces ([#6278](https://github.com/helix-editor/helix/pull/6278)) +- No-op `client/registerCapability` LSP requests ([#6258](https://github.com/helix-editor/helix/pull/6258)) +- Send the STOP signal to all processes in the process group ([#3546](https://github.com/helix-editor/helix/pull/3546)) +- Fix workspace edit client capabilities declaration ([7bf168d](https://github.com/helix-editor/helix/commit/7bf168d)) +- Fix highlighting in picker results with multiple columns ([#6333](https://github.com/helix-editor/helix/pull/6333)) +- Canonicalize paths before stripping the current dir as a prefix ([#6290](https://github.com/helix-editor/helix/pull/6290)) +- Fix truncation behavior for long path names in the file picker ([#6410](https://github.com/helix-editor/helix/pull/6410), [67783dd](https://github.com/helix-editor/helix/commit/67783dd)) +- Fix theme reloading behavior in `:config-reload` ([ab819d8](https://github.com/helix-editor/helix/commit/ab819d8)) Themes: -- Update `serika` (#5038, #6344) -- Update `flatwhite` (#5036, #6323) -- Update `autumn` (#5051, #5397, #6280, #6316) -- Update `acme` (#5019, #5486, #5488) -- Update `gruvbox` themes (#5066, #5333, #5540, #6285, #6295) -- Update `base16_transparent` (#5105) -- Update `dark_high_contrast` (#5105) -- Update `dracula` (#5236, #5627, #6414) -- Update `monokai_pro_spectrum` (#5250, #5602) -- Update `rose_pine` (#5267, #5489, #6384) -- Update `kanagawa` (#5273, #5571, #6085) -- Update `emacs` (#5334) -- Add `github` themes (#5353, efeec12) +- Update `serika` ([#5038](https://github.com/helix-editor/helix/pull/5038), [#6344](https://github.com/helix-editor/helix/pull/6344)) +- Update `flatwhite` ([#5036](https://github.com/helix-editor/helix/pull/5036), [#6323](https://github.com/helix-editor/helix/pull/6323)) +- Update `autumn` ([#5051](https://github.com/helix-editor/helix/pull/5051), [#5397](https://github.com/helix-editor/helix/pull/5397), [#6280](https://github.com/helix-editor/helix/pull/6280), [#6316](https://github.com/helix-editor/helix/pull/6316)) +- Update `acme` ([#5019](https://github.com/helix-editor/helix/pull/5019), [#5486](https://github.com/helix-editor/helix/pull/5486), [#5488](https://github.com/helix-editor/helix/pull/5488)) +- Update `gruvbox` themes ([#5066](https://github.com/helix-editor/helix/pull/5066), [#5333](https://github.com/helix-editor/helix/pull/5333), [#5540](https://github.com/helix-editor/helix/pull/5540), [#6285](https://github.com/helix-editor/helix/pull/6285), [#6295](https://github.com/helix-editor/helix/pull/6295)) +- Update `base16_transparent` ([#5105](https://github.com/helix-editor/helix/pull/5105)) +- Update `dark_high_contrast` ([#5105](https://github.com/helix-editor/helix/pull/5105)) +- Update `dracula` ([#5236](https://github.com/helix-editor/helix/pull/5236), [#5627](https://github.com/helix-editor/helix/pull/5627), [#6414](https://github.com/helix-editor/helix/pull/6414)) +- Update `monokai_pro_spectrum` ([#5250](https://github.com/helix-editor/helix/pull/5250), [#5602](https://github.com/helix-editor/helix/pull/5602)) +- Update `rose_pine` ([#5267](https://github.com/helix-editor/helix/pull/5267), [#5489](https://github.com/helix-editor/helix/pull/5489), [#6384](https://github.com/helix-editor/helix/pull/6384)) +- Update `kanagawa` ([#5273](https://github.com/helix-editor/helix/pull/5273), [#5571](https://github.com/helix-editor/helix/pull/5571), [#6085](https://github.com/helix-editor/helix/pull/6085)) +- Update `emacs` ([#5334](https://github.com/helix-editor/helix/pull/5334)) +- Add `github` themes ([#5353](https://github.com/helix-editor/helix/pull/5353), [efeec12](https://github.com/helix-editor/helix/commit/efeec12)) - Dark themes: `github_dark`, `github_dark_colorblind`, `github_dark_dimmed`, `github_dark_high_contrast`, `github_dark_tritanopia` - Light themes: `github_light`, `github_light_colorblind`, `github_light_dimmed`, `github_light_high_contrast`, `github_light_tritanopia` -- Update `solarized` variants (#5445, #6327) -- Update `catppuccin` variants (#5404, #6107, #6269) -- Use curly underlines in built-in themes (#5419) -- Update `zenburn` (#5573) -- Rewrite `snazzy` (#3971) -- Add `monokai_aqua` (#5578) -- Add `markup.strikethrough` to existing themes (#5619) -- Update `sonokai` (#5440) -- Update `onedark` (#5755) -- Add `ayu_evolve` (#5638, #6028, #6225) -- Add `jellybeans` (#5719) -- Update `fleet_dark` (#5605, #6266, #6324, #6375) -- Add `darcula-solid` (#5778) -- Remove text background from monokai themes (#6009) -- Update `pop_dark` (#5992, #6208, #6227, #6292) -- Add `everblush` (#6086) -- Add `adwaita-dark` (#6042, #6342) -- Update `papercolor` (#6162) -- Update `onelight` (#6192, #6276) -- Add `molokai` (#6260) -- Update `ayu` variants (#6329) -- Update `tokyonight` variants (#6349) -- Update `nord` variants (#6376) +- Update `solarized` variants ([#5445](https://github.com/helix-editor/helix/pull/5445), [#6327](https://github.com/helix-editor/helix/pull/6327)) +- Update `catppuccin` variants ([#5404](https://github.com/helix-editor/helix/pull/5404), [#6107](https://github.com/helix-editor/helix/pull/6107), [#6269](https://github.com/helix-editor/helix/pull/6269), [#6464](https://github.com/helix-editor/helix/pull/6464)) +- Use curly underlines in built-in themes ([#5419](https://github.com/helix-editor/helix/pull/5419)) +- Update `zenburn` ([#5573](https://github.com/helix-editor/helix/pull/5573)) +- Rewrite `snazzy` ([#3971](https://github.com/helix-editor/helix/pull/3971)) +- Add `monokai_aqua` ([#5578](https://github.com/helix-editor/helix/pull/5578)) +- Add `markup.strikethrough` to existing themes ([#5619](https://github.com/helix-editor/helix/pull/5619)) +- Update `sonokai` ([#5440](https://github.com/helix-editor/helix/pull/5440)) +- Update `onedark` ([#5755](https://github.com/helix-editor/helix/pull/5755)) +- Add `ayu_evolve` ([#5638](https://github.com/helix-editor/helix/pull/5638), [#6028](https://github.com/helix-editor/helix/pull/6028), [#6225](https://github.com/helix-editor/helix/pull/6225)) +- Add `jellybeans` ([#5719](https://github.com/helix-editor/helix/pull/5719)) +- Update `fleet_dark` ([#5605](https://github.com/helix-editor/helix/pull/5605), [#6266](https://github.com/helix-editor/helix/pull/6266), [#6324](https://github.com/helix-editor/helix/pull/6324), [#6375](https://github.com/helix-editor/helix/pull/6375)) +- Add `darcula-solid` ([#5778](https://github.com/helix-editor/helix/pull/5778)) +- Remove text background from monokai themes ([#6009](https://github.com/helix-editor/helix/pull/6009)) +- Update `pop_dark` ([#5992](https://github.com/helix-editor/helix/pull/5992), [#6208](https://github.com/helix-editor/helix/pull/6208), [#6227](https://github.com/helix-editor/helix/pull/6227), [#6292](https://github.com/helix-editor/helix/pull/6292)) +- Add `everblush` ([#6086](https://github.com/helix-editor/helix/pull/6086)) +- Add `adwaita-dark` ([#6042](https://github.com/helix-editor/helix/pull/6042), [#6342](https://github.com/helix-editor/helix/pull/6342)) +- Update `papercolor` ([#6162](https://github.com/helix-editor/helix/pull/6162)) +- Update `onelight` ([#6192](https://github.com/helix-editor/helix/pull/6192), [#6276](https://github.com/helix-editor/helix/pull/6276)) +- Add `molokai` ([#6260](https://github.com/helix-editor/helix/pull/6260)) +- Update `ayu` variants ([#6329](https://github.com/helix-editor/helix/pull/6329)) +- Update `tokyonight` variants ([#6349](https://github.com/helix-editor/helix/pull/6349)) +- Update `nord` variants ([#6376](https://github.com/helix-editor/helix/pull/6376)) New languages: -- BibTeX (#5064) -- Mermaid.js (#5147) -- Crystal (#4993, #5205) -- MATLAB/Octave (#5192) -- `tfvars` (uses HCL) (#5396) -- Ponylang (#5416) -- DHall (1f6809c) -- Sagemath (#5649) -- MSBuild (#5793) -- pem (#5797) -- passwd (#4959) -- hosts (#4950, #5914) -- uxntal (#6047) -- Yuck (#6064, #6242) -- GNU gettext PO (#5996) -- Sway (#6023) -- NASM (#6068) -- PRQL (#6126) -- reStructuredText (#6180) -- Smithy (#6370) -- VHDL (#5826) -- Rego (OpenPolicy Agent) (#6415) -- Nim (#6123) +- BibTeX ([#5064](https://github.com/helix-editor/helix/pull/5064)) +- Mermaid.js ([#5147](https://github.com/helix-editor/helix/pull/5147)) +- Crystal ([#4993](https://github.com/helix-editor/helix/pull/4993), [#5205](https://github.com/helix-editor/helix/pull/5205)) +- MATLAB/Octave ([#5192](https://github.com/helix-editor/helix/pull/5192)) +- `tfvars` (uses HCL) ([#5396](https://github.com/helix-editor/helix/pull/5396)) +- Ponylang ([#5416](https://github.com/helix-editor/helix/pull/5416)) +- DHall ([1f6809c](https://github.com/helix-editor/helix/commit/1f6809c)) +- Sagemath ([#5649](https://github.com/helix-editor/helix/pull/5649)) +- MSBuild ([#5793](https://github.com/helix-editor/helix/pull/5793)) +- pem ([#5797](https://github.com/helix-editor/helix/pull/5797)) +- passwd ([#4959](https://github.com/helix-editor/helix/pull/4959)) +- hosts ([#4950](https://github.com/helix-editor/helix/pull/4950), [#5914](https://github.com/helix-editor/helix/pull/5914)) +- uxntal ([#6047](https://github.com/helix-editor/helix/pull/6047)) +- Yuck ([#6064](https://github.com/helix-editor/helix/pull/6064), [#6242](https://github.com/helix-editor/helix/pull/6242)) +- GNU gettext PO ([#5996](https://github.com/helix-editor/helix/pull/5996)) +- Sway ([#6023](https://github.com/helix-editor/helix/pull/6023)) +- NASM ([#6068](https://github.com/helix-editor/helix/pull/6068)) +- PRQL ([#6126](https://github.com/helix-editor/helix/pull/6126)) +- reStructuredText ([#6180](https://github.com/helix-editor/helix/pull/6180)) +- Smithy ([#6370](https://github.com/helix-editor/helix/pull/6370)) +- VHDL ([#5826](https://github.com/helix-editor/helix/pull/5826)) +- Rego (OpenPolicy Agent) ([#6415](https://github.com/helix-editor/helix/pull/6415)) +- Nim ([#6123](https://github.com/helix-editor/helix/pull/6123)) Updated languages and queries: -- Use diff syntax for patch files (#5085) -- Add Haskell textobjects (#5061) -- Fix commonlisp configuration (#5091) -- Update Scheme (bae890d) -- Add indent queries for Bash (#5149) -- Recognize `c++` as a C++ extension (#5183) -- Enable HTTP server in `metals` (Scala) config (#5551) -- Change V-lang language server to `v ls` from `vls` (#5677) -- Inject comment grammar into Nix (#5208) -- Update Rust highlights (#5238, #5349) -- Fix HTML injection within Markdown (#5265) -- Fix comment token for godot (#5276) -- Expand injections for Vue (#5268) -- Add `.bash_aliases` as a Bash file-type (#5347) -- Fix comment token for sshclientconfig (#5351) -- Update Prisma (#5417) -- Update C++ (#5457) -- Add more file-types for Python (#5593) -- Update tree-sitter-scala (#5576) -- Add an injection regex for Lua (#5606) -- Add `build.gradle` to java roots configuration (#5641) -- Add Hub PR files to markdown file-types (#5634) -- Add an external formatter configuration for Cue (#5679) -- Add injections for builders and writers to Nix (#5629) -- Update tree-sitter-xml to fix whitespace parsing (#5685) -- Add `Justfile` to the make file-types configuration (#5687) -- Update tree-sitter-sql and highlight queries (#5683, #5772) -- Use the bash grammar and queries for env language (#5720) -- Add podspec files to ruby file-types (#5811) -- Recognize `.C` and `.H` file-types as C++ (#5808) -- Recognize plist and mobileconfig files as XML (#5863) -- Fix `select` indentation in Go (#5713) -- Check for external file modifications when writing (#5805) -- Recognize containerfiles as dockerfile syntax (#5873) -- Update godot grammar and queries (#5944, #6186) -- Improve DHall highlights (#5959) -- Recognize `.env.dist` and `source.env` as env language (#6003) -- Update tree-sitter-git-rebase (#6030, #6094) -- Improve SQL highlights (#6041) -- Improve markdown highlights and inject LaTeX (#6100) -- Add textobject queries for Elm (#6084) -- Recognize graphql schema file type (#6159) -- Improve highlighting in comments (#6143) -- Improve highlighting for JavaScript/TypeScript/ECMAScript languages (#6205) -- Improve PHP highlights (#6203, #6250, #6299) -- Improve Go highlights (#6204) -- Highlight unchecked sqlx functions as SQL in Rust (#6256) -- Improve Erlang highlights (cdd6c8d) -- Improve Nix highlights (fb4d703) -- Improve gdscript highlights (#6311) -- Improve Vlang highlights (#6279) -- Improve Makefile highlights (#6339) -- Remove auto-pair for `'` in OCaml (#6381) -- Fix indents in switch statements in ECMA languages (#6369) -- Recognize xlb and storyboard file-types as XML (#6407) -- Recognize cts and mts file-types as TypeScript (#6424) -- Recognize SVG file-type as XML (#6431) -- Add theme scopes for (un)checked list item markup scopes (#6434) -- Update git commit grammar and add the comment textobject (#6439) -- Recognize ARB file-type as JSON (#6452) +- Use diff syntax for patch files ([#5085](https://github.com/helix-editor/helix/pull/5085)) +- Add Haskell textobjects ([#5061](https://github.com/helix-editor/helix/pull/5061)) +- Fix commonlisp configuration ([#5091](https://github.com/helix-editor/helix/pull/5091)) +- Update Scheme ([bae890d](https://github.com/helix-editor/helix/commit/bae890d)) +- Add indent queries for Bash ([#5149](https://github.com/helix-editor/helix/pull/5149)) +- Recognize `c++` as a C++ extension ([#5183](https://github.com/helix-editor/helix/pull/5183)) +- Enable HTTP server in `metals` (Scala) config ([#5551](https://github.com/helix-editor/helix/pull/5551)) +- Change V-lang language server to `v ls` from `vls` ([#5677](https://github.com/helix-editor/helix/pull/5677)) +- Inject comment grammar into Nix ([#5208](https://github.com/helix-editor/helix/pull/5208)) +- Update Rust highlights ([#5238](https://github.com/helix-editor/helix/pull/5238), [#5349](https://github.com/helix-editor/helix/pull/5349)) +- Fix HTML injection within Markdown ([#5265](https://github.com/helix-editor/helix/pull/5265)) +- Fix comment token for godot ([#5276](https://github.com/helix-editor/helix/pull/5276)) +- Expand injections for Vue ([#5268](https://github.com/helix-editor/helix/pull/5268)) +- Add `.bash_aliases` as a Bash file-type ([#5347](https://github.com/helix-editor/helix/pull/5347)) +- Fix comment token for sshclientconfig ([#5351](https://github.com/helix-editor/helix/pull/5351)) +- Update Prisma ([#5417](https://github.com/helix-editor/helix/pull/5417)) +- Update C++ ([#5457](https://github.com/helix-editor/helix/pull/5457)) +- Add more file-types for Python ([#5593](https://github.com/helix-editor/helix/pull/5593)) +- Update tree-sitter-scala ([#5576](https://github.com/helix-editor/helix/pull/5576)) +- Add an injection regex for Lua ([#5606](https://github.com/helix-editor/helix/pull/5606)) +- Add `build.gradle` to java roots configuration ([#5641](https://github.com/helix-editor/helix/pull/5641)) +- Add Hub PR files to markdown file-types ([#5634](https://github.com/helix-editor/helix/pull/5634)) +- Add an external formatter configuration for Cue ([#5679](https://github.com/helix-editor/helix/pull/5679)) +- Add injections for builders and writers to Nix ([#5629](https://github.com/helix-editor/helix/pull/5629)) +- Update tree-sitter-xml to fix whitespace parsing ([#5685](https://github.com/helix-editor/helix/pull/5685)) +- Add `Justfile` to the make file-types configuration ([#5687](https://github.com/helix-editor/helix/pull/5687)) +- Update tree-sitter-sql and highlight queries ([#5683](https://github.com/helix-editor/helix/pull/5683), [#5772](https://github.com/helix-editor/helix/pull/5772)) +- Use the bash grammar and queries for env language ([#5720](https://github.com/helix-editor/helix/pull/5720)) +- Add podspec files to ruby file-types ([#5811](https://github.com/helix-editor/helix/pull/5811)) +- Recognize `.C` and `.H` file-types as C++ ([#5808](https://github.com/helix-editor/helix/pull/5808)) +- Recognize plist and mobileconfig files as XML ([#5863](https://github.com/helix-editor/helix/pull/5863)) +- Fix `select` indentation in Go ([#5713](https://github.com/helix-editor/helix/pull/5713)) +- Check for external file modifications when writing ([#5805](https://github.com/helix-editor/helix/pull/5805)) +- Recognize containerfiles as dockerfile syntax ([#5873](https://github.com/helix-editor/helix/pull/5873)) +- Update godot grammar and queries ([#5944](https://github.com/helix-editor/helix/pull/5944), [#6186](https://github.com/helix-editor/helix/pull/6186)) +- Improve DHall highlights ([#5959](https://github.com/helix-editor/helix/pull/5959)) +- Recognize `.env.dist` and `source.env` as env language ([#6003](https://github.com/helix-editor/helix/pull/6003)) +- Update tree-sitter-git-rebase ([#6030](https://github.com/helix-editor/helix/pull/6030), [#6094](https://github.com/helix-editor/helix/pull/6094)) +- Improve SQL highlights ([#6041](https://github.com/helix-editor/helix/pull/6041)) +- Improve markdown highlights and inject LaTeX ([#6100](https://github.com/helix-editor/helix/pull/6100)) +- Add textobject queries for Elm ([#6084](https://github.com/helix-editor/helix/pull/6084)) +- Recognize graphql schema file type ([#6159](https://github.com/helix-editor/helix/pull/6159)) +- Improve highlighting in comments ([#6143](https://github.com/helix-editor/helix/pull/6143)) +- Improve highlighting for JavaScript/TypeScript/ECMAScript languages ([#6205](https://github.com/helix-editor/helix/pull/6205)) +- Improve PHP highlights ([#6203](https://github.com/helix-editor/helix/pull/6203), [#6250](https://github.com/helix-editor/helix/pull/6250), [#6299](https://github.com/helix-editor/helix/pull/6299)) +- Improve Go highlights ([#6204](https://github.com/helix-editor/helix/pull/6204)) +- Highlight unchecked sqlx functions as SQL in Rust ([#6256](https://github.com/helix-editor/helix/pull/6256)) +- Improve Erlang highlights ([cdd6c8d](https://github.com/helix-editor/helix/commit/cdd6c8d)) +- Improve Nix highlights ([fb4d703](https://github.com/helix-editor/helix/commit/fb4d703)) +- Improve gdscript highlights ([#6311](https://github.com/helix-editor/helix/pull/6311)) +- Improve Vlang highlights ([#6279](https://github.com/helix-editor/helix/pull/6279)) +- Improve Makefile highlights ([#6339](https://github.com/helix-editor/helix/pull/6339)) +- Remove auto-pair for `'` in OCaml ([#6381](https://github.com/helix-editor/helix/pull/6381)) +- Fix indents in switch statements in ECMA languages ([#6369](https://github.com/helix-editor/helix/pull/6369)) +- Recognize xlb and storyboard file-types as XML ([#6407](https://github.com/helix-editor/helix/pull/6407)) +- Recognize cts and mts file-types as TypeScript ([#6424](https://github.com/helix-editor/helix/pull/6424)) +- Recognize SVG file-type as XML ([#6431](https://github.com/helix-editor/helix/pull/6431)) +- Add theme scopes for (un)checked list item markup scopes ([#6434](https://github.com/helix-editor/helix/pull/6434)) +- Update git commit grammar and add the comment textobject ([#6439](https://github.com/helix-editor/helix/pull/6439), [#6493](https://github.com/helix-editor/helix/pull/6493)) +- Recognize ARB file-type as JSON ([#6452](https://github.com/helix-editor/helix/pull/6452)) +- Inject markdown into markdown strings in Julia ([#6489](https://github.com/helix-editor/helix/pull/6489)) Packaging: -- Fix Nix flake devShell for darwin hosts (#5368) -- Add Appstream metadata file to `contrib/` (#5643) -- Increase the MSRV to 1.65 (#5570, #6185) -- Expose the Nix flake's `wrapper` (#5994) +- Fix Nix flake devShell for darwin hosts ([#5368](https://github.com/helix-editor/helix/pull/5368)) +- Add Appstream metadata file to `contrib/` ([#5643](https://github.com/helix-editor/helix/pull/5643)) +- Increase the MSRV to 1.65 ([#5570](https://github.com/helix-editor/helix/pull/5570), [#6185](https://github.com/helix-editor/helix/pull/6185)) +- Expose the Nix flake's `wrapper` ([#5994](https://github.com/helix-editor/helix/pull/5994)) # 22.12 (2022-12-06) From c3c87741d95c893980e70719dfb5f620bb6fde3e Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sun, 2 Apr 2023 01:58:10 +0300 Subject: [PATCH 045/260] build(nix): update flake dependencies, remove deprecated code from flake --- flake.lock | 111 +++++++++++++++++++++++++++++++++++++++++------------ flake.nix | 2 - 2 files changed, 87 insertions(+), 26 deletions(-) diff --git a/flake.lock b/flake.lock index fa292273a..d33c404ef 100644 --- a/flake.lock +++ b/flake.lock @@ -18,9 +18,6 @@ }, "dream2nix": { "inputs": { - "alejandra": [ - "nci" - ], "all-cabal-json": [ "nci" ], @@ -28,6 +25,8 @@ "devshell": [ "nci" ], + "drv-parts": "drv-parts", + "flake-compat": "flake-compat", "flake-parts": [ "nci", "parts" @@ -51,6 +50,7 @@ "nci", "nixpkgs" ], + "nixpkgsV1": "nixpkgsV1", "poetry2nix": [ "nci" ], @@ -62,11 +62,11 @@ ] }, "locked": { - "lastModified": 1677289985, - "narHash": "sha256-lUp06cTTlWubeBGMZqPl9jODM99LpWMcwxRiscFAUJg=", + "lastModified": 1680258209, + "narHash": "sha256-lEo50RXI/17/a9aCIun8Hz62ZJ5JM5RGeTgclIP+Lgc=", "owner": "nix-community", "repo": "dream2nix", - "rev": "28b973a8d4c30cc1cbb3377ea2023a76bc3fb889", + "rev": "6f512b5a220fdb26bd3c659f7b55e4f052ec8b35", "type": "github" }, "original": { @@ -75,6 +75,54 @@ "type": "github" } }, + "drv-parts": { + "inputs": { + "flake-compat": [ + "nci", + "dream2nix", + "flake-compat" + ], + "flake-parts": [ + "nci", + "dream2nix", + "flake-parts" + ], + "nixpkgs": [ + "nci", + "dream2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1680172861, + "narHash": "sha256-QMyI338xRxaHFDlCXdLCtgelGQX2PdlagZALky4ZXJ8=", + "owner": "davhau", + "repo": "drv-parts", + "rev": "ced8a52f62b0a94244713df2225c05c85b416110", + "type": "github" + }, + "original": { + "owner": "davhau", + "repo": "drv-parts", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "locked": { "lastModified": 1659877975, @@ -119,11 +167,11 @@ ] }, "locked": { - "lastModified": 1677297103, - "narHash": "sha256-ArlJIbp9NGV9yvhZdV0SOUFfRlI/kHeKoCk30NbSiLc=", + "lastModified": 1680329418, + "narHash": "sha256-+KN0eQLSZvL1J0kDO8/fxv0UCHTyZCADLmpIfeeiSGo=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "a79272a2cb0942392bb3a5bf9a3ec6bc568795b2", + "rev": "98c1d2ff5155f0fee5d290f6b982cb990839d540", "type": "github" }, "original": { @@ -134,11 +182,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1677063315, - "narHash": "sha256-qiB4ajTeAOVnVSAwCNEEkoybrAlA+cpeiBxLobHndE8=", + "lastModified": 1680213900, + "narHash": "sha256-cIDr5WZIj3EkKyCgj/6j3HBH4Jj1W296z7HTcWj1aMA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "988cc958c57ce4350ec248d2d53087777f9e1949", + "rev": "e3652e0735fbec227f342712f180f4f21f0594f2", "type": "github" }, "original": { @@ -151,11 +199,11 @@ "nixpkgs-lib": { "locked": { "dir": "lib", - "lastModified": 1675183161, - "narHash": "sha256-Zq8sNgAxDckpn7tJo7V1afRSk2eoVbu3OjI1QklGLNg=", + "lastModified": 1678375444, + "narHash": "sha256-XIgHfGvjFvZQ8hrkfocanCDxMefc/77rXeHvYdzBMc8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e1e1b192c1a5aab2960bf0a0bd53a2e8124fa18e", + "rev": "130fa0baaa2b93ec45523fdcde942f6844ee9f6e", "type": "github" }, "original": { @@ -166,6 +214,21 @@ "type": "github" } }, + "nixpkgsV1": { + "locked": { + "lastModified": 1678500271, + "narHash": "sha256-tRBLElf6f02HJGG0ZR7znMNFv/Uf7b2fFInpTHiHaSE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5eb98948b66de29f899c7fe27ae112a47964baf8", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-22.11", + "type": "indirect" + } + }, "parts": { "inputs": { "nixpkgs-lib": [ @@ -174,11 +237,11 @@ ] }, "locked": { - "lastModified": 1675933616, - "narHash": "sha256-/rczJkJHtx16IFxMmAWu5nNYcSXNg1YYXTHoGjLrLUA=", + "lastModified": 1679737941, + "narHash": "sha256-srSD9CwsVPnUMsIZ7Kt/UegkKUEBcTyU1Rev7mO45S0=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "47478a4a003e745402acf63be7f9a092d51b83d7", + "rev": "3502ee99d6dade045bdeaf7b0cd8ec703484c25c", "type": "github" }, "original": { @@ -192,11 +255,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1675933616, - "narHash": "sha256-/rczJkJHtx16IFxMmAWu5nNYcSXNg1YYXTHoGjLrLUA=", + "lastModified": 1679737941, + "narHash": "sha256-srSD9CwsVPnUMsIZ7Kt/UegkKUEBcTyU1Rev7mO45S0=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "47478a4a003e745402acf63be7f9a092d51b83d7", + "rev": "3502ee99d6dade045bdeaf7b0cd8ec703484c25c", "type": "github" }, "original": { @@ -221,11 +284,11 @@ ] }, "locked": { - "lastModified": 1677292251, - "narHash": "sha256-D+6q5Z2MQn3UFJtqsM5/AvVHi3NXKZTIMZt1JGq/spA=", + "lastModified": 1680315536, + "narHash": "sha256-0AsBuKssJMbcRcw4HJQwJsUHhZxR5+gaf6xPQayhR44=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "34cdbf6ad480ce13a6a526f57d8b9e609f3d65dc", + "rev": "5c8c151bdd639074a0051325c16df1a64ee23497", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 2ac764888..6dcaf6cc4 100644 --- a/flake.nix +++ b/flake.nix @@ -123,8 +123,6 @@ then ''$RUSTFLAGS -C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment'' else "$RUSTFLAGS"; in { - # by default NCI adds rust-analyzer component, but helix toolchain doesn't have rust-analyzer - nci.toolchains.shell.components = ["rust-src" "rustfmt" "clippy"]; nci.projects."helix-project".relPath = ""; nci.crates."helix-term" = { overrides = { From fc5e515b306ed71369b7cd0f5420afeaef23b7c5 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 31 Mar 2023 10:02:05 -0500 Subject: [PATCH 046/260] Enable aarch64-macos releases --- .github/workflows/release.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2fa34e1f3..74ab8be0f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -86,12 +86,12 @@ jobs: target: x86_64-pc-windows-msvc cross: false # 23.03: build issues - # - build: aarch64-macos - # os: macos-latest - # rust: stable - # target: aarch64-apple-darwin - # cross: false - # skip_tests: true # x86_64 host can't run aarch64 code + - build: aarch64-macos + os: macos-latest + rust: stable + target: aarch64-apple-darwin + cross: false + skip_tests: true # x86_64 host can't run aarch64 code # - build: x86_64-win-gnu # os: windows-2019 # rust: stable-x86_64-gnu From 6bfc3097412e54563f7bd6a6ff5fce5b4d9577e1 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 31 Mar 2023 10:05:52 -0500 Subject: [PATCH 047/260] Remove the rust-toolchain.toml file before building the release The 'dtolnay/rust-toolchain' action ignores the rust-toolchain.toml file, but the installed 'cargo' respects it. This can create a version mismatch if the MSRV is different from the stable rust version. Any additional targets installed by rustup like aarch64-darwin might not be installed for the correct version. To fix this, we remove the rust-toolchain.toml file before calling 'cargo'. --- .github/workflows/release.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 74ab8be0f..b26daca85 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -114,6 +114,12 @@ jobs: mkdir -p runtime/grammars/sources tar xJf grammars/grammars.tar.xz -C runtime/grammars/sources + # The rust-toolchain action ignores rust-toolchain.toml files. + # Removing this before building with cargo ensures that the rust-toolchain + # is considered the same between installation and usage. + - name: Remove the rust-toolchain.toml file + run: rm rust-toolchain.toml + - name: Install ${{ matrix.rust }} toolchain uses: dtolnay/rust-toolchain@master with: From 38b9bdf871d406df8e9a3f1ed8c34dae992c184e Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 31 Mar 2023 14:02:53 -0500 Subject: [PATCH 048/260] Recursive create the pkgname directory when creating a release tarball This step without the '-p' works fine for regular releases but it can fail if the CI is running when this file changes or on a branch matching 'patch/ci-release-*'. --- .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 b26daca85..b509ff9e0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -255,7 +255,7 @@ jobs: exe=".exe" fi pkgname=helix-$GITHUB_REF_NAME-$platform - mkdir $pkgname + mkdir -p $pkgname cp $source/LICENSE $source/README.md $pkgname mkdir $pkgname/contrib cp -r $source/contrib/completion $pkgname/contrib From bfe8d267fec4964c6981ae38d9e4f46cdebb61b7 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Mon, 3 Apr 2023 03:56:48 +0200 Subject: [PATCH 049/260] normalize LSP workspaces (#6517) --- helix-lsp/src/client.rs | 4 +++- helix-lsp/src/lib.rs | 10 +++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 94e994899..29a67988a 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -4,7 +4,7 @@ use crate::{ Call, Error, OffsetEncoding, Result, }; -use helix_core::{find_workspace, ChangeSet, Rope}; +use helix_core::{find_workspace, path, ChangeSet, Rope}; use helix_loader::{self, VERSION_AND_GIT_HASH}; use lsp::{ notification::DidChangeWorkspaceFolders, DidChangeWorkspaceFoldersParams, OneOf, @@ -66,6 +66,7 @@ impl Client { may_support_workspace: bool, ) -> bool { let (workspace, workspace_is_cwd) = find_workspace(); + let workspace = path::get_normalized_path(&workspace); let root = find_lsp_workspace( doc_path .and_then(|x| x.parent().and_then(|x| x.to_str())) @@ -201,6 +202,7 @@ impl Client { let (server_rx, server_tx, initialize_notify) = Transport::start(reader, writer, stderr, id); let (workspace, workspace_is_cwd) = find_workspace(); + let workspace = path::get_normalized_path(&workspace); let root = find_lsp_workspace( doc_path .and_then(|x| x.parent().and_then(|x| x.to_str())) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index c3a5d816e..c206ac1d6 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -10,7 +10,10 @@ pub use lsp::{Position, Url}; pub use lsp_types as lsp; use futures_util::stream::select_all::SelectAll; -use helix_core::syntax::{LanguageConfiguration, LanguageServerConfiguration}; +use helix_core::{ + path, + syntax::{LanguageConfiguration, LanguageServerConfiguration}, +}; use tokio::sync::mpsc::UnboundedReceiver; use std::{ @@ -888,12 +891,13 @@ pub fn find_lsp_workspace( workspace_is_cwd: bool, ) -> Option { let file = std::path::Path::new(file); - let file = if file.is_absolute() { + let mut file = if file.is_absolute() { file.to_path_buf() } else { let current_dir = std::env::current_dir().expect("unable to determine current directory"); current_dir.join(file) }; + file = path::get_normalized_path(&file); if !file.starts_with(workspace) { return None; @@ -910,7 +914,7 @@ pub fn find_lsp_workspace( if root_dirs .iter() - .any(|root_dir| root_dir == ancestor.strip_prefix(workspace).unwrap()) + .any(|root_dir| path::get_normalized_path(&workspace.join(root_dir)) == ancestor) { // if the worskapce is the cwd do not search any higher for workspaces // but specify From 1073dd632932d0c9131f6413a5ced69ee7096e60 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Mon, 3 Apr 2023 03:58:50 +0200 Subject: [PATCH 050/260] robustly handle invalid LSP ranges (#6512) --- helix-lsp/src/lib.rs | 25 ++++++++++++++++++++----- helix-term/src/ui/completion.rs | 16 ++++++---------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index c206ac1d6..a59fa31e4 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -132,7 +132,11 @@ pub mod util { ) -> Option { let pos_line = pos.line as usize; if pos_line > doc.len_lines() - 1 { - return None; + // If it extends past the end, truncate it to the end. This is because the + // way the LSP describes the range including the last newline is by + // specifying a line number after what we would call the last line. + log::warn!("LSP position {pos:?} out of range assuming EOF"); + return Some(doc.len_chars()); } // We need to be careful here to fully comply ith the LSP spec. @@ -242,9 +246,20 @@ pub mod util { pub fn lsp_range_to_range( doc: &Rope, - range: lsp::Range, + mut range: lsp::Range, offset_encoding: OffsetEncoding, ) -> Option { + // This is sort of an edgecase. It's not clear from the spec how to deal with + // ranges where end < start. They don't make much sense but vscode simply caps start to end + // and because it's not specified quite a few LS rely on this as a result (for example the TS server) + if range.start > range.end { + log::error!( + "Invalid LSP range start {:?} > end {:?}, using an empty range at the end instead", + range.start, + range.end + ); + range.start = range.end; + } let start = lsp_pos_to_pos(doc, range.start, offset_encoding)?; let end = lsp_pos_to_pos(doc, range.end, offset_encoding)?; @@ -951,16 +966,16 @@ mod tests { test_case!("", (0, 0) => Some(0)); test_case!("", (0, 1) => Some(0)); - test_case!("", (1, 0) => None); + test_case!("", (1, 0) => Some(0)); test_case!("\n\n", (0, 0) => Some(0)); test_case!("\n\n", (1, 0) => Some(1)); test_case!("\n\n", (1, 1) => Some(1)); test_case!("\n\n", (2, 0) => Some(2)); - test_case!("\n\n", (3, 0) => None); + test_case!("\n\n", (3, 0) => Some(2)); test_case!("test\n\n\n\ncase", (4, 3) => Some(11)); test_case!("test\n\n\n\ncase", (4, 4) => Some(12)); test_case!("test\n\n\n\ncase", (4, 5) => Some(12)); - test_case!("", (u32::MAX, u32::MAX) => None); + test_case!("", (u32::MAX, u32::MAX) => Some(0)); } #[test] diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index e0b1419c5..bc216509f 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -141,16 +141,12 @@ impl Completion { } }; - let start_offset = - match util::lsp_pos_to_pos(doc.text(), edit.range.start, offset_encoding) { - Some(start) => start as i128 - primary_cursor as i128, - None => return Transaction::new(doc.text()), - }; - let end_offset = - match util::lsp_pos_to_pos(doc.text(), edit.range.end, offset_encoding) { - Some(end) => end as i128 - primary_cursor as i128, - None => return Transaction::new(doc.text()), - }; + let Some(range) = util::lsp_range_to_range(doc.text(), edit.range, offset_encoding) else{ + return Transaction::new(doc.text()); + }; + + let start_offset = range.anchor as i128 - primary_cursor as i128; + let end_offset = range.head as i128 - primary_cursor as i128; (Some((start_offset, end_offset)), edit.new_text) } else { From 9420ba7484b14d10d24edf7236852cc18d985dfb Mon Sep 17 00:00:00 2001 From: Casper Rogild Storm Date: Mon, 3 Apr 2023 06:41:41 +0200 Subject: [PATCH 051/260] Let..else refactor (#6562) --- helix-term/src/commands/typed.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 0255bbea4..afc3d7069 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -2125,20 +2125,16 @@ fn reset_diff_change( let scrolloff = editor.config().scrolloff; let (view, doc) = current!(editor); - // TODO refactor to use let..else once MSRV is raised to 1.65 - let handle = match doc.diff_handle() { - Some(handle) => handle, - None => bail!("Diff is not available in the current buffer"), + let Some(handle) = doc.diff_handle() else { + bail!("Diff is not available in the current buffer") }; let diff = handle.load(); let doc_text = doc.text().slice(..); let line = doc.selection(view.id).primary().cursor_line(doc_text); - // TODO refactor to use let..else once MSRV is raised to 1.65 - let hunk_idx = match diff.hunk_at(line as u32, true) { - Some(hunk_idx) => hunk_idx, - None => bail!("There is no change at the cursor"), + let Some(hunk_idx) = diff.hunk_at(line as u32, true) else { + bail!("There is no change at the cursor") }; let hunk = diff.nth_hunk(hunk_idx); let diff_base = diff.diff_base(); From d63c717b82c690c6ecd3a9fae687b849eb533e91 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Mon, 3 Apr 2023 10:26:31 +0200 Subject: [PATCH 052/260] dracula theme: style inlay hints as comments (#6515) --- runtime/themes/dracula.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index b08357dbe..6935b487f 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -45,6 +45,9 @@ "ui.virtual.whitespace" = { fg = "subtle" } "ui.virtual.wrap" = { fg = "subtle" } "ui.virtual.ruler" = { bg = "background_dark"} +"ui.virtual.inlay-hint" = { fg = "comment" } +"ui.virtual.inlay-hint.parameter" = { fg = "comment", modifiers = ["italic"] } +"ui.virtual.inlay-hint.type" = { fg = "comment", modifiers = ["italic"] } "error" = { fg = "red" } "warning" = { fg = "cyan" } From 1fcfef12be3d9041092111523e6c9cb13d2f519c Mon Sep 17 00:00:00 2001 From: Jack Allison Date: Mon, 3 Apr 2023 04:34:19 -0400 Subject: [PATCH 053/260] Update OneDark theme to use light-gray for inlay hints. (#6503) Co-authored-by: Jack Allison --- runtime/themes/onedark.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/themes/onedark.toml b/runtime/themes/onedark.toml index 6df5f797b..21101ea75 100644 --- a/runtime/themes/onedark.toml +++ b/runtime/themes/onedark.toml @@ -54,6 +54,7 @@ "ui.virtual.indent-guide" = { fg = "faint-gray" } "ui.virtual.whitespace" = { fg = "light-gray" } "ui.virtual.ruler" = { bg = "gray" } +"ui.virtual.inlay-hint" = { fg = "light-gray" } "ui.cursor" = { fg = "white", modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "white", modifiers = ["reversed"] } From dd6e0cce3bcc6a4e57c5869f6a5ba36c101a17b3 Mon Sep 17 00:00:00 2001 From: Dmitry Ulyanov Date: Mon, 3 Apr 2023 17:22:43 +0300 Subject: [PATCH 054/260] Fix line number display for LSP goto pickers (#6559) Line numbers are 0-indexed in the LSP spec but 1-indexed for display and jumping purposes in Helix. --- helix-term/src/commands/lsp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index f8e83a46c..78dbc0be9 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -81,7 +81,7 @@ impl ui::menu::Item for lsp::Location { // Most commonly, this will not allocate, especially on Unix systems where the root prefix // is a simple `/` and not `C:\` (with whatever drive letter) - write!(&mut res, ":{}", self.range.start.line) + write!(&mut res, ":{}", self.range.start.line + 1) .expect("Will only failed if allocating fail"); res.into() } From d0c9f38b6836e6337a1a5c7c4c55c612b1e45e90 Mon Sep 17 00:00:00 2001 From: Bertrand Bousquet Date: Mon, 3 Apr 2023 15:56:21 +0000 Subject: [PATCH 055/260] Update Varua theme for soft wrap (#6568) --- runtime/themes/varua.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/themes/varua.toml b/runtime/themes/varua.toml index c1afaca0a..20ee235fc 100644 --- a/runtime/themes/varua.toml +++ b/runtime/themes/varua.toml @@ -65,6 +65,7 @@ "ui.virtual.whitespace" = "grey0" "ui.statusline.insert" = { bg = "green", fg = "bg2" } "ui.statusline.select" = { bg = "blue", fg = "bg2" } +"ui.virtual.wrap" = { fg = "grey0" } "hint" = "blue" "info" = "aqua" From 43072f78760777978da5c7a6426c66c20d7c4568 Mon Sep 17 00:00:00 2001 From: Yevgnen Date: Mon, 3 Apr 2023 23:57:38 +0800 Subject: [PATCH 056/260] Update colors for inlay hints for emacs theme (#6569) --- runtime/themes/emacs.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/themes/emacs.toml b/runtime/themes/emacs.toml index bb33e2d8b..513af60e1 100644 --- a/runtime/themes/emacs.toml +++ b/runtime/themes/emacs.toml @@ -70,6 +70,7 @@ "ui.selection.primary" = { bg = "lightgoldenrod2" } "ui.virtual.whitespace" = "highlight" "ui.virtual.ruler" = { bg = "gray95" } +"ui.virtual.inlay-hint" = { fg = "gray75" } "ui.cursorline.primary" = { bg = "darkseagreen2" } "ui.cursorline.secondary" = { bg = "darkseagreen2" } From 789833c9953f1639ff4c580de326d3bb7b9210f9 Mon Sep 17 00:00:00 2001 From: Rowan Shi <37481598+rowanxshi@users.noreply.github.com> Date: Mon, 3 Apr 2023 12:36:54 -0400 Subject: [PATCH 057/260] minor: R lang config update --slave to --no-echo (#6570) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index a8fdc4a83..38de820b3 100644 --- a/languages.toml +++ b/languages.toml @@ -1446,7 +1446,7 @@ shebangs = ["r", "R"] roots = [] comment-token = "#" indent = { tab-width = 2, unit = " " } -language-server = { command = "R", args = ["--slave", "-e", "languageserver::run()"] } +language-server = { command = "R", args = ["--no-echo", "-e", "languageserver::run()"] } [[grammar]] name = "r" From 9d883873054f9fd4f9289dd80f06d66898524fa6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 08:59:13 +0800 Subject: [PATCH 058/260] build(deps): bump futures-executor from 0.3.27 to 0.3.28 (#6576) Bumps [futures-executor](https://github.com/rust-lang/futures-rs) from 0.3.27 to 0.3.28. - [Release notes](https://github.com/rust-lang/futures-rs/releases) - [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.27...0.3.28) --- updated-dependencies: - dependency-name: futures-executor 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 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b7ed2c9c8..c3421fbbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -450,15 +450,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -467,15 +467,15 @@ dependencies = [ [[package]] name = "futures-task" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-core", "futures-task", From dbafe756fa592bd684d5024bd993927159527251 Mon Sep 17 00:00:00 2001 From: Slug <106496265+GreasySlug@users.noreply.github.com> Date: Tue, 4 Apr 2023 22:59:12 +0900 Subject: [PATCH 060/260] Update base16_transparent and dark_high_contrast themes (#6577) * Update inlay-hint and wrap for base16_transparent * Update inlay-hint and wrap for dark_high_contrast * Tune dark_high_contrast cursor match theming --- runtime/themes/base16_transparent.toml | 4 ++++ runtime/themes/dark_high_contrast.toml | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/runtime/themes/base16_transparent.toml b/runtime/themes/base16_transparent.toml index fd07cb281..8019c6fa9 100644 --- a/runtime/themes/base16_transparent.toml +++ b/runtime/themes/base16_transparent.toml @@ -25,6 +25,10 @@ "ui.virtual.ruler" = { bg = "gray" } "ui.virtual.whitespace" = "gray" "ui.virtual.indent-guide" = "gray" +"ui.virtual.inlay-hint" = { fg = "white", bg = "gray" } +"ui.virtual.inlay-hint.parameter" = { fg = "white", bg = "gray"} +"ui.virtual.inlay-hint.type" = { fg = "white", bg = "gray"} +"ui.virtual.wrap" = "gray" "variable" = "light-red" "constant.numeric" = "yellow" diff --git a/runtime/themes/dark_high_contrast.toml b/runtime/themes/dark_high_contrast.toml index 897c31e25..51701cfce 100644 --- a/runtime/themes/dark_high_contrast.toml +++ b/runtime/themes/dark_high_contrast.toml @@ -8,9 +8,14 @@ "ui.text" = "white" "ui.text.focus" = { modifiers = ["reversed"] } # file picker selected +"ui.virtual" = "gray" "ui.virtual.whitespace" = "gray" "ui.virtual.ruler" = { fg = "white", bg = "gray" } "ui.virtual.indent-guide" = "white" +"ui.virtual.inlay-hint" = { fg = "black", bg = "orange" } +"ui.virtual.inlay-hint.parameter" = { fg = "black", bg = "orange" } +"ui.virtual.inlay-hint.type" = { fg = "black", bg = "orange" } +"ui.virtual.wrap" = "gray" "ui.statusline" = { fg = "white", bg = "deep_blue" } "ui.statusline.inactive" = { fg = "gray", bg = "deep_blue" } @@ -22,7 +27,7 @@ "ui.cursor" = { fg = "black", bg = "white" } "ui.cursor.insert" = { fg = "black", bg = "white" } "ui.cursor.select" = { fg = "black", bg = "white" } -"ui.cursor.match" = { bg = "white", modifiers = ["dim"] } +"ui.cursor.match" = { modifiers = ["reversed"] } "ui.cursor.primary" = { fg = "black", bg = "white", modifiers = ["slow_blink"] } "ui.cursor.secondary" = "white" "ui.cursorline.primary" = { bg = "deep_blue", underline = { color = "orange", style = "double_line" } } From 480784d2cf56dbb86a194f42c6ae50a88f0f6ffb Mon Sep 17 00:00:00 2001 From: Rohit K Viswanath Date: Tue, 4 Apr 2023 19:35:13 +0530 Subject: [PATCH 061/260] Update inlay-hint color for mellow & rasmus themes (#6583) --- runtime/themes/mellow.toml | 1 + runtime/themes/rasmus.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/runtime/themes/mellow.toml b/runtime/themes/mellow.toml index 279fd5c2b..16d7b6086 100644 --- a/runtime/themes/mellow.toml +++ b/runtime/themes/mellow.toml @@ -80,6 +80,7 @@ "ui.virtual" = { fg = "gray02" } "ui.virtual.indent-guide" = { fg = "gray02" } +"ui.virtual.inlay-hint" = { fg = "gray04" } "ui.selection" = { bg = "gray03" } "ui.selection.primary" = { bg = "gray03" } diff --git a/runtime/themes/rasmus.toml b/runtime/themes/rasmus.toml index 3158a6a45..bcfb0c66c 100644 --- a/runtime/themes/rasmus.toml +++ b/runtime/themes/rasmus.toml @@ -85,6 +85,7 @@ "ui.virtual" = { fg = "gray03" } "ui.virtual.indent-guide" = { fg = "gray04" } +"ui.virtual.inlay-hint" = { fg = "gray05" } "ui.selection" = { bg = "gray03" } "ui.selection.primary" = { bg = "gray03" } From 2f4b9a47f36c04eae7c2a67445150337065aaeff Mon Sep 17 00:00:00 2001 From: Bertrand Bousquet Date: Tue, 4 Apr 2023 17:34:25 +0000 Subject: [PATCH 062/260] Update Varua theme for inlay hints (#6589) --- runtime/themes/varua.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/themes/varua.toml b/runtime/themes/varua.toml index 20ee235fc..b07ab08dc 100644 --- a/runtime/themes/varua.toml +++ b/runtime/themes/varua.toml @@ -66,6 +66,7 @@ "ui.statusline.insert" = { bg = "green", fg = "bg2" } "ui.statusline.select" = { bg = "blue", fg = "bg2" } "ui.virtual.wrap" = { fg = "grey0" } +"ui.virtual.inlay-hint" = { fg = "grey1" } "hint" = "blue" "info" = "aqua" From 577aded04a01801cbd61c7953a24b24d499a7e83 Mon Sep 17 00:00:00 2001 From: Jack Wolfard <31635014+JackWolfard@users.noreply.github.com> Date: Tue, 4 Apr 2023 12:25:06 -0700 Subject: [PATCH 063/260] Recognize CUDA files as C++ (#6521) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 38de820b3..0d5b32222 100644 --- a/languages.toml +++ b/languages.toml @@ -212,7 +212,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-c", rev = "7175a6dd name = "cpp" scope = "source.cpp" injection-regex = "cpp" -file-types = ["cc", "hh", "c++", "cpp", "hpp", "h", "ipp", "tpp", "cxx", "hxx", "ixx", "txx", "ino", "C", "H"] +file-types = ["cc", "hh", "c++", "cpp", "hpp", "h", "ipp", "tpp", "cxx", "hxx", "ixx", "txx", "ino", "C", "H", "cu", "cuh"] roots = [] comment-token = "//" language-server = { command = "clangd" } From 01b70762fda6a7cd004ed623844398d620c44eda Mon Sep 17 00:00:00 2001 From: Constantin Angheloiu Date: Tue, 4 Apr 2023 22:47:23 +0300 Subject: [PATCH 064/260] Dim pane divider color in base16_transparent theme (#6534) --- runtime/themes/base16_transparent.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/base16_transparent.toml b/runtime/themes/base16_transparent.toml index 8019c6fa9..63aa1f869 100644 --- a/runtime/themes/base16_transparent.toml +++ b/runtime/themes/base16_transparent.toml @@ -9,7 +9,7 @@ "ui.linenr" = { fg = "light-gray" } "ui.linenr.selected" = { fg = "white", modifiers = ["bold"] } "ui.popup" = { fg = "white" } -"ui.window" = { fg = "white" } +"ui.window" = { fg = "gray" } "ui.selection" = { bg = "gray" } "comment" = "light-gray" "ui.statusline" = { fg = "white" } From 531b745c54e5d316603601cc05ade50ab02066ab Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Tue, 4 Apr 2023 15:11:09 -0700 Subject: [PATCH 065/260] [theme][zenburn] set inlay hint to comment style (#6593) --- runtime/themes/zenburn.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runtime/themes/zenburn.toml b/runtime/themes/zenburn.toml index 4c019a2c5..8518e78f8 100644 --- a/runtime/themes/zenburn.toml +++ b/runtime/themes/zenburn.toml @@ -8,7 +8,8 @@ "ui.popup" = { bg = "uibg" } "ui.selection" = { bg = "#304a3d" } "ui.selection.primary" = { bg = "#2f2f2f" } -"comment" = { fg = "#7f9f7f" } +"comment" = { fg = "comment" } +"ui.virtual.inlay-hint" = { fg = "comment" } "comment.block.documentation" = { fg = "black", modifiers = ["bold"] } "ui.statusline" = { bg = "statusbg", fg = "#ccdc90" } "ui.statusline.inactive" = { fg = '#2e3330', bg = '#88b090' } @@ -50,6 +51,7 @@ "error" = "errorfg" [palette] +comment = "#7f9f7f" bg = "#3f3f3f" uibg = "#2c2e2e" constant = "#dca3a3" From b6909bc41ad998dac9a0a8198535ba0f21a32c22 Mon Sep 17 00:00:00 2001 From: Ivan Ermakov Date: Thu, 6 Apr 2023 10:28:08 +0700 Subject: [PATCH 066/260] Add gdformat support (#6614) --- languages.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/languages.toml b/languages.toml index 0d5b32222..48c1345c8 100644 --- a/languages.toml +++ b/languages.toml @@ -1545,6 +1545,7 @@ file-types = ["gd"] shebangs = [] roots = ["project.godot"] auto-format = true +formatter = { command = "gdformat", args = ["-"] } comment-token = "#" indent = { tab-width = 4, unit = "\t" } From fc4ca96c2986bc875f1fc6e2cb164dcaf4f4a09c Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 5 Apr 2023 22:29:17 -0500 Subject: [PATCH 067/260] Update tree-sitter to v0.20.10 (#6608) We used a git dependency to take advantage of the latest fixes in master but a new release is now available: https://crates.io/crates/tree-sitter/0.20.10 --- Cargo.lock | 5 +++-- Cargo.toml | 3 --- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3421fbbc..26448c425 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2192,8 +2192,9 @@ dependencies = [ [[package]] name = "tree-sitter" -version = "0.20.9" -source = "git+https://github.com/tree-sitter/tree-sitter?rev=c51896d32dcc11a38e41f36e3deb1a6a9c4f4b14#c51896d32dcc11a38e41f36e3deb1a6a9c4f4b14" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e747b1f9b7b931ed39a548c1fae149101497de3c1fc8d9e18c62c1a66c683d3d" dependencies = [ "cc", "regex", diff --git a/Cargo.toml b/Cargo.toml index aaa21659a..c63518897 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,3 @@ inherits = "test" package.helix-core.opt-level = 2 package.helix-tui.opt-level = 2 package.helix-term.opt-level = 2 - -[patch.crates-io] -tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "c51896d32dcc11a38e41f36e3deb1a6a9c4f4b14" } From 951e8686e8182ca9a914ea8ea864c7234349d391 Mon Sep 17 00:00:00 2001 From: Gyeongwan Koh Date: Fri, 7 Apr 2023 01:18:39 +0900 Subject: [PATCH 068/260] Colorize inlay hints in the boo_berry theme (#6625) --- runtime/themes/boo_berry.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/themes/boo_berry.toml b/runtime/themes/boo_berry.toml index 62e3b372c..d3a3e2232 100644 --- a/runtime/themes/boo_berry.toml +++ b/runtime/themes/boo_berry.toml @@ -52,6 +52,7 @@ "ui.virtual.whitespace" = { fg = "berry_desaturated" } "ui.virtual.ruler" = { bg = "berry_dim" } "ui.virtual.indent-guide" = { fg = "berry_fade" } +"ui.virtual.inlay-hint" = { fg = "berry_desaturated" } "diff.plus" = { fg = "mint" } "diff.delta" = { fg = "gold" } From c22ebfe62ed0404a0f7328e3a5100c971f864004 Mon Sep 17 00:00:00 2001 From: Erasin Wang Date: Fri, 7 Apr 2023 00:26:41 +0800 Subject: [PATCH 069/260] Add Hurl Support (#6450) * Add http Support It's like [vscode-restclient](https://github.com/Huachao/vscode-restclient) - https://github.com/erasin/tree-sitter-http/tree/main/tests * Add Hurl Support --- book/src/generated/lang-support.md | 1 + languages.toml | 14 +++ runtime/queries/hurl/highlights.scm | 127 ++++++++++++++++++++++++++++ runtime/queries/hurl/indents.scm | 11 +++ runtime/queries/hurl/injections.scm | 14 +++ 5 files changed, 167 insertions(+) create mode 100644 runtime/queries/hurl/highlights.scm create mode 100644 runtime/queries/hurl/indents.scm create mode 100644 runtime/queries/hurl/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 48667f2e5..d71acc566 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -59,6 +59,7 @@ | heex | ✓ | ✓ | | `elixir-ls` | | hosts | ✓ | | | | | html | ✓ | | | `vscode-html-language-server` | +| hurl | ✓ | | ✓ | | | idris | | | | `idris2-lsp` | | iex | ✓ | | | | | ini | ✓ | | | | diff --git a/languages.toml b/languages.toml index 48c1345c8..c5c69b9b6 100644 --- a/languages.toml +++ b/languages.toml @@ -2422,3 +2422,17 @@ language-server = { command = "nimlangserver" } [[grammar]] name = "nim" source = { git = "https://github.com/aMOPel/tree-sitter-nim", rev = "240239b232550e431d67de250d1b5856209e7f06" } + +[[language]] +name = "hurl" +scope = "source.hurl" +injection-regex = "hurl" +file-types = ["hurl"] +roots = [] +comment-token = "#" +indent = { tab-width = 2, unit = " " } + +[[grammar]] +name = "hurl" +source = { git = "https://github.com/pfeiferj/tree-sitter-hurl", rev = "264c42064b61ee21abe88d0061f29a0523352e22" } + diff --git a/runtime/queries/hurl/highlights.scm b/runtime/queries/hurl/highlights.scm new file mode 100644 index 000000000..c066b2844 --- /dev/null +++ b/runtime/queries/hurl/highlights.scm @@ -0,0 +1,127 @@ +[ + "[QueryStringParams]" + "[FormParams]" + "[MultipartFormData]" + "[Cookies]" + "[Captures]" + "[Asserts]" + "[Options]" + "[BasicAuth]" +] @attribute + +(comment) @comment + +[ + (key_string) + (json_key_string) +] @variable.other.member + +(value_string) @string +(quoted_string) @string +(json_string) @string +(file_value) @string.special.path +(regex) @string.regex + +[ + "\\" + (regex_escaped_char) + (quoted_string_escaped_char) + (key_string_escaped_char) + (value_string_escaped_char) + (oneline_string_escaped_char) + (multiline_string_escaped_char) + (filename_escaped_char) + (json_string_escaped_char) +] @constant.character.escape + +(method) @type.builtin +(multiline_string_type) @type + +[ + "status" + "url" + "header" + "cookie" + "body" + "xpath" + "jsonpath" + "regex" + "variable" + "duration" + "sha256" + "md5" + "bytes" +] @function.builtin + +(filter) @attribute + +(version) @string.special +[ + "null" + "cacert" + "location" + "insecure" + "max-redirs" + "retry" + "retry-interval" + "retry-max-count" + (variable_option "variable") + "verbose" + "very-verbose" +] @constant.builtin + +(boolean) @constant.builtin.boolean + +(variable_name) @variable + +[ + "not" + "equals" + "==" + "notEquals" + "!=" + "greaterThan" + ">" + "greaterThanOrEquals" + ">=" + "lessThan" + "<" + "lessThanOrEquals" + "<=" + "startsWith" + "endsWith" + "contains" + "matches" + "exists" + "includes" + "isInteger" + "isFloat" + "isBoolean" + "isString" + "isCollection" +] @keyword.operator + +(integer) @constant.numeric.integer +(float) @constant.numeric.float +(status) @constant.numeric +(json_number) @constant.numeric.float + +[ + ":" + "," +] @punctuation.delimiter + +[ + "[" + "]" + "{" + "}" + "{{" + "}}" +] @punctuation.special + +[ + "base64," + "file," + "hex," +] @string.special \ No newline at end of file diff --git a/runtime/queries/hurl/indents.scm b/runtime/queries/hurl/indents.scm new file mode 100644 index 000000000..d436f76fd --- /dev/null +++ b/runtime/queries/hurl/indents.scm @@ -0,0 +1,11 @@ +[ + (json_object) + (json_array) + (xml_tag) +] @indent + +[ + "}" + "]" + (xml_close_tag) +] @outdent diff --git a/runtime/queries/hurl/injections.scm b/runtime/queries/hurl/injections.scm new file mode 100644 index 000000000..a0d238173 --- /dev/null +++ b/runtime/queries/hurl/injections.scm @@ -0,0 +1,14 @@ +((comment) @injection.content + (#set! injection.language "comment")) + +((json_value) @injection.content + (#set! injection.language "json")) + +((xml) @injection.content + (#set! injection.language "xml")) + +((multiline_string + (multiline_string_type) @injection.language + (multiline_string_content) @injection.content) + (#set! injection.include-children) + (#set! injection.combined)) From 7ce52e5b2c5fb1d8c9c5c783ec2072b6b9f97663 Mon Sep 17 00:00:00 2001 From: Casper Rogild Storm Date: Thu, 6 Apr 2023 18:30:47 +0200 Subject: [PATCH 070/260] Added `ferra` theme (#6619) * Added ferra theme * Updated with author information * Conform to themelint --- runtime/themes/ferra.toml | 84 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 runtime/themes/ferra.toml diff --git a/runtime/themes/ferra.toml b/runtime/themes/ferra.toml new file mode 100644 index 000000000..da5339e2e --- /dev/null +++ b/runtime/themes/ferra.toml @@ -0,0 +1,84 @@ +# Author : Casper Rogild Storm + +"comment" = { fg = "ferra_bark", modifiers = ["italic"] } +"constant" = { fg = "ferra_sage" } +"function" = { fg = "ferra_coral" } +"function.macro" = { fg = "ferra_mist" } +"keyword" = { fg = "ferra_mist" } +"operator" = { fg = "ferra_mist" } +"punctuation" = { fg = "ferra_blush" } +"string" = { fg = "ferra_sage" } +"type" = { fg = "ferra_rose" } +"variable" = { fg = "ferra_blush" } +"variable.builtin" = { fg = "ferra_rose" } +"tag" = { fg = "ferra_sage" } +"label" = { fg = "ferra_sage" } +"attribute" = { fg = "ferra_blush" } +"namespace" = { fg = "ferra_blush" } +"module" = { fg = "ferra_blush" } + +"markup.heading" = { fg = "ferra_sage", modifiers = ["bold"] } +"markup.heading.marker" = { fg = "ferra_bark" } +"markup.list" = { fg = "ferra_mist" } +"markup.bold" = { modifiers = ["bold"] } +"markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } +"markup.link.url" = { fg = "ferra_rose", modifiers = ["underlined"] } +"markup.link.text" = { fg = "ferra_rose" } +"markup.quote" = { fg = "ferra_bark" } +"markup.raw" = { fg = "ferra_coral" } + +"ui.background" = { bg = "ferra_night" } +"ui.cursor" = { fg = "ferra_night", bg = "ferra_blush" } +"ui.cursor.match" = { fg = "ferra_night", bg = "ferra_bark" } +"ui.cursor.select" = { fg = "ferra_night", bg = "ferra_rose" } +"ui.cursor.insert" = { fg = "ferra_night", bg = "ferra_coral" } +"ui.linenr" = { fg = "ferra_bark" } +"ui.linenr.selected" = { fg = "ferra_blush" } +"ui.cursorline" = { fg = "ferra_blush", bg = "ferra_ash" } +"ui.statusline" = { fg = "ferra_blush", bg = "ferra_ash" } +"ui.statusline.inactive" = { fg = "ferra_bark", bg = "ferra_ash" } +"ui.statusline.normal" = { fg = "ferra_ash", bg = "ferra_blush" } +"ui.statusline.insert" = { fg = "ferra_ash", bg = "ferra_coral" } +"ui.statusline.select" = { fg = "ferra_ash", bg = "ferra_rose" } +"ui.popup" = { fg = "ferra_blush", bg = "ferra_ash" } +"ui.window" = { fg = "ferra_bark", bg = "ferra_night" } +"ui.help" = { fg = "ferra_blush", bg = "ferra_ash" } +"ui.text" = { fg = "ferra_blush" } +"ui.text.focus" = { fg = "ferra_coral" } +"ui.menu" = { fg = "ferra_blush", bg = "ferra_ash" } +"ui.menu.selected" = { fg = "ferra_coral", bg = "ferra_ash" } +"ui.selection" = { bg = "ferra_umber", fg = "ferra_night" } +"ui.selection.primary" = { bg = "ferra_night", fg = "ferra_umber" } +"ui.virtual" = { fg = "ferra_bark" } +"ui.virtual.whitespace" = { fg = "ferra_bark" } +"ui.virtual.ruler" = { fg = "ferra_night", bg = "ferra_ash" } +"ui.virtual.indent-guide" = { fg = "ferra_ash" } +"ui.virtual.inlay-hint" = { fg = "ferra_bark" } + +"diff.plus" = { fg = "ferra_sage" } +"diff.delta" = { fg = "ferra_blush" } +"diff.minus" = { fg = "ferra_ember" } + +"error" = { fg = "ferra_ember" } +"warning" = { fg = "ferra_honey" } +"info" = { fg = "ferra_blush" } +"hint" = { fg = "ferra_blush" } + +"diagnostic.warning" = { underline = { color = "ferra_honey", style = "curl" } } +"diagnostic.error" = { underline = { color = "ferra_ember", style = "curl" } } +"diagnostic.info" = { underline = { color = "ferra_blush", style = "curl" } } +"diagnostic.hint" = { underline = { color = "ferra_blush", style = "curl" } } + +[palette] +ferra_night = "#2b292d" +ferra_ash = "#383539" +ferra_umber = "#4d424b" +ferra_bark = "#6F5D63" +ferra_mist = "#D1D1E0" +ferra_sage = "#B1B695" +ferra_blush = "#fecdb2" +ferra_coral = "#ffa07a" +ferra_rose = "#F6B6C9" +ferra_ember = "#e06b75" +ferra_honey = "#F5D76E" From 4b32b544fc57c53e1406fa7705068f0222498019 Mon Sep 17 00:00:00 2001 From: Clara Hobbs Date: Thu, 6 Apr 2023 12:35:05 -0400 Subject: [PATCH 071/260] Add textobject queries for Julia (#6588) * Add textobjects queries for Julia * Update docs for Julia textobject queries --- book/src/generated/lang-support.md | 2 +- runtime/queries/julia/textobjects.scm | 46 +++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/julia/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index d71acc566..12cd2babf 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -69,7 +69,7 @@ | json | ✓ | | ✓ | `vscode-json-language-server` | | jsonnet | ✓ | | | `jsonnet-language-server` | | jsx | ✓ | ✓ | ✓ | `typescript-language-server` | -| julia | ✓ | | ✓ | `julia` | +| julia | ✓ | ✓ | ✓ | `julia` | | kdl | ✓ | | | | | kotlin | ✓ | | | `kotlin-language-server` | | latex | ✓ | ✓ | | `texlab` | diff --git a/runtime/queries/julia/textobjects.scm b/runtime/queries/julia/textobjects.scm new file mode 100644 index 000000000..1927c2b18 --- /dev/null +++ b/runtime/queries/julia/textobjects.scm @@ -0,0 +1,46 @@ +(function_definition (_)? @function.inside) @function.around + +(short_function_definition (_)? @function.inside) @function.around + +(macro_definition (_)? @function.inside) @function.around + +(struct_definition (_)? @class.inside) @class.around + +(abstract_definition (_)? @class.inside) @class.around + +(primitive_definition (_)? @class.inside) @class.around + +(parameter_list + ; Match all children of parameter_list *except* keyword_parameters + ([(identifier) + (slurp_parameter) + (optional_parameter) + (typed_parameter) + (tuple_expression) + (interpolation_expression) + (call_expression)] + @parameter.inside . ","? @parameter.around) @parameter.around) + +(keyword_parameters + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +(argument_list + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +(type_parameter_list + ((_) @parameter.inside . ","? @parameter.around) @parameter.around) + +(line_comment) @comment.inside + +(line_comment)+ @comment.around + +(block_comment) @comment.inside + +(block_comment)+ @comment.around + +(_expression (macro_identifier + (identifier) @_name + (#match? @_name "^(test|test_throws|test_logs|inferred|test_deprecated|test_warn|test_nowarn|test_broken|test_skip)$") + ) + . + (macro_argument_list) @test.inside) @test.around From 3dd715a115880831e3a0f75a3c00f0b6e1a8364f Mon Sep 17 00:00:00 2001 From: Danillo Melo Date: Thu, 6 Apr 2023 13:37:45 -0300 Subject: [PATCH 072/260] Update Ruby Highlights (#6587) * update ruby highlights * Updated SQL injection.scm * Move private, public, protected to builtin methods --- languages.toml | 2 +- runtime/queries/ruby/highlights.scm | 120 +++++++++++++++++++--------- runtime/queries/ruby/injections.scm | 6 ++ 3 files changed, 89 insertions(+), 39 deletions(-) diff --git a/languages.toml b/languages.toml index c5c69b9b6..a1a2f0a1d 100644 --- a/languages.toml +++ b/languages.toml @@ -606,7 +606,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "ruby" -source = { git = "https://github.com/tree-sitter/tree-sitter-ruby", rev = "4c600a463d97e36a0ca5ac57e11f3ac8c297a0fa" } +source = { git = "https://github.com/tree-sitter/tree-sitter-ruby", rev = "206c7077164372c596ffa8eaadb9435c28941364" } [[language]] name = "bash" diff --git a/runtime/queries/ruby/highlights.scm b/runtime/queries/ruby/highlights.scm index 898f8f794..7c69276ba 100644 --- a/runtime/queries/ruby/highlights.scm +++ b/runtime/queries/ruby/highlights.scm @@ -1,44 +1,67 @@ ; Keywords [ + "BEGIN" + "END" "alias" - "and" "begin" - "break" - "case" "class" - "def" "do" - "else" - "elsif" "end" - "ensure" - "for" - "if" - "in" "module" - "next" - "or" + "in" "rescue" - "retry" - "return" - "then" - "unless" - "until" + "ensure" +] @keyword + +[ + "if" + "else" + "elsif" "when" + "case" + "unless" + "then" +] @keyword.control.conditional + +[ + "for" "while" + "retry" + "until" + "redo" +] @keyword.control.repeat + +[ "yield" -] @keyword + "return" + "next" + "break" +] @keyword.control.return + +[ + "def" + "undef" +] @keyword.function + +((identifier) @keyword.control.import + (#match? @keyword.control.import "^(require|require_relative|load|autoload)$")) + +[ + "or" + "and" + "not" +] @keyword.operator -((identifier) @keyword - (#match? @keyword "^(private|protected|public)$")) +((identifier) @keyword.control.exception + (#match? @keyword.control.exception "^(raise|fail)$")) ; Function calls -((identifier) @function.method.builtin - (#eq? @function.method.builtin "require")) +((identifier) @function.builtin + (#match? @function.builtin "^(attr|attr_accessor|attr_reader|attr_writer|include|prepend|refine|private|protected|public)$")) -"defined?" @function.method.builtin +"defined?" @function.builtin (call method: [(identifier) (constant)] @function.method) @@ -58,7 +81,10 @@ ] @variable.other.member ((identifier) @constant.builtin - (#match? @constant.builtin "^__(FILE|LINE|ENCODING)__$")) + (#match? @constant.builtin "^(__FILE__|__LINE__|__ENCODING__)$")) + +((constant) @constant.builtin + (#match? @constant.builtin "^(ENV|ARGV|ARGF|RUBY_PLATFORM|RUBY_RELEASE_DATE|RUBY_VERSION|STDERR|STDIN|STDOUT|TOPLEVEL_BINDING)$")) ((constant) @constant (#match? @constant "^[A-Z\\d_]+$")) @@ -66,22 +92,23 @@ (constant) @constructor (self) @variable.builtin -(super) @variable.builtin +(super) @function.builtin +[(forward_parameter)(forward_argument)] @variable.parameter +(keyword_parameter name:((_)":" @variable.parameter) @variable.parameter) +(optional_parameter name:((_)"=" @operator) @variable.parameter) +(optional_parameter name: (identifier) @variable.parameter) +(splat_parameter name: (identifier) @variable.parameter) @variable.parameter +(hash_splat_parameter name: (identifier) @variable.parameter) @variable.parameter +(method_parameters (identifier) @variable.parameter) (block_parameter (identifier) @variable.parameter) (block_parameters (identifier) @variable.parameter) -(destructured_parameter (identifier) @variable.parameter) -(hash_splat_parameter (identifier) @variable.parameter) -(lambda_parameters (identifier) @variable.parameter) -(method_parameters (identifier) @variable.parameter) -(splat_parameter (identifier) @variable.parameter) - -(keyword_parameter name: (identifier) @variable.parameter) -(optional_parameter name: (identifier) @variable.parameter) ((identifier) @function.method (#is-not? local)) -(identifier) @variable +[ + (identifier) +] @variable ; Literals @@ -96,10 +123,11 @@ [ (simple_symbol) (delimited_symbol) - (hash_key_symbol) (bare_symbol) ] @string.special.symbol +(pair key: ((_)":" @string.special.symbol) @string.special.symbol) + (regex) @string.regexp (escape_sequence) @constant.character.escape @@ -112,7 +140,7 @@ (nil) (true) (false) -]@constant.builtin +] @constant.builtin (interpolation "#{" @punctuation.special @@ -121,20 +149,36 @@ (comment) @comment ; Operators - [ -"=" +":" +"?" +"~" "=>" "->" +"!" ] @operator +(assignment + "=" @operator) + +(operator_assignment + operator: ["+=" "-=" "*=" "**=" "/=" "||=" "|=" "&&=" "&=" "%=" ">>=" "<<=" "^="] @operator) + +(binary + operator: ["/" "|" "==" "===" "||" "&&" ">>" "<<" "<" ">" "<=" ">=" "&" "^" "!~" "=~" "<=>" "**" "*" "!=" "%" "-" "+"] @operator) + +(range + operator: [".." "..."] @operator) + [ "," ";" "." + "&." ] @punctuation.delimiter [ + "|" "(" ")" "[" diff --git a/runtime/queries/ruby/injections.scm b/runtime/queries/ruby/injections.scm index 321c90add..1a865df19 100644 --- a/runtime/queries/ruby/injections.scm +++ b/runtime/queries/ruby/injections.scm @@ -1,2 +1,8 @@ ((comment) @injection.content (#set! injection.language "comment")) + +((heredoc_body + (heredoc_content) @injection.content + (heredoc_end) @name + (#set! injection.language "sql")) + (#eq? @name "SQL")) From b663b89529b40d00d4db580901cccacdd35c63cf Mon Sep 17 00:00:00 2001 From: Michael <20937441+KMikeeU@users.noreply.github.com> Date: Thu, 6 Apr 2023 21:48:10 +0200 Subject: [PATCH 073/260] xml: highlight .xsd as XML files (#6631) xsd or "XML Schema Definition" files are in XML format and should therefore be highlighted as such --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index a1a2f0a1d..51ef3bcf8 100644 --- a/languages.toml +++ b/languages.toml @@ -2069,7 +2069,7 @@ source = { git = "https://github.com/Unoqwy/tree-sitter-kdl", rev = "e1cd292c6d1 name = "xml" scope = "source.xml" injection-regex = "xml" -file-types = ["xml", "mobileconfig", "plist", "xib", "storyboard", "svg"] +file-types = ["xml", "mobileconfig", "plist", "xib", "storyboard", "svg", "xsd"] indent = { tab-width = 2, unit = " " } roots = [] From 1148ce1fd9941e00bd416bce1f06a987d0e7b5f2 Mon Sep 17 00:00:00 2001 From: karei <31644842+kareigu@users.noreply.github.com> Date: Fri, 7 Apr 2023 03:19:48 +0300 Subject: [PATCH 074/260] Add support for Robot Framework files (#6611) * Add support for Robot Framework files * Run docgen --- book/src/generated/lang-support.md | 1 + languages.toml | 14 ++++++++++++++ runtime/queries/robot/highlights.scm | 21 +++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 runtime/queries/robot/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 12cd2babf..3f56dd606 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -117,6 +117,7 @@ | rego | ✓ | | | `regols` | | rescript | ✓ | ✓ | | `rescript-language-server` | | rmarkdown | ✓ | | ✓ | `R` | +| robot | ✓ | | | `robotframework_ls` | | ron | ✓ | | ✓ | | | rst | ✓ | | | | | ruby | ✓ | ✓ | ✓ | `solargraph` | diff --git a/languages.toml b/languages.toml index 51ef3bcf8..c643beab1 100644 --- a/languages.toml +++ b/languages.toml @@ -1437,6 +1437,20 @@ comment-token = "//" indent = { tab-width = 4, unit = " " } grammar = "rust" +[[language]] +name = "robot" +scope = "source.robot" +injection-regex = "robot" +file-types = ["robot", "resource"] +comment-token = "#" +roots = [] +indent = { tab-width = 4, unit = " " } +language-server = { command = "robotframework_ls" } + +[[grammar]] +name = "robot" +source = { git = "https://github.com/Hubro/tree-sitter-robot", rev = "f1142bfaa6acfce95e25d2c6d18d218f4f533927" } + [[language]] name = "r" scope = "source.r" diff --git a/runtime/queries/robot/highlights.scm b/runtime/queries/robot/highlights.scm new file mode 100644 index 000000000..60f416b7b --- /dev/null +++ b/runtime/queries/robot/highlights.scm @@ -0,0 +1,21 @@ +(comment) @comment +(ellipses) @punctuation.delimiter + +(section_header) @keyword +(extra_text) @comment + +(setting_statement) @keyword + +(variable_definition (variable_name) @variable) + +(keyword_definition (name) @function) +(keyword_definition (body (keyword_setting) @keyword)) + +(test_case_definition (name) @property) + +(keyword_invocation (keyword) @function) + +(argument (text_chunk) @string) +(argument (scalar_variable) @string.special) +(argument (list_variable) @string.special) +(argument (dictionary_variable) @string.special) From e856906f766aa6d58aba6f6bca9e2e1879b1629d Mon Sep 17 00:00:00 2001 From: Daniel Sedlak Date: Fri, 7 Apr 2023 17:10:38 +0200 Subject: [PATCH 075/260] Fix typos (#6643) --- helix-core/src/position.rs | 4 ++-- helix-core/src/selection.rs | 2 +- helix-core/src/shellwords.rs | 4 ++-- helix-core/src/text_annotations.rs | 4 ++-- helix-lsp/src/client.rs | 14 +++++++------- helix-lsp/src/lib.rs | 6 +++--- helix-lsp/src/snippet.rs | 12 ++++++------ helix-term/src/application.rs | 4 ++-- helix-term/src/commands.rs | 22 +++++++++++----------- helix-term/src/commands/dap.rs | 4 ++-- helix-term/src/commands/lsp.rs | 26 +++++++++++++------------- helix-term/src/commands/typed.rs | 4 ++-- helix-term/src/ui/document.rs | 8 ++++---- helix-term/src/ui/fuzzy_match.rs | 6 +++--- helix-term/src/ui/fuzzy_match/test.rs | 4 ++-- helix-term/src/ui/overlay.rs | 2 +- helix-term/src/ui/picker.rs | 2 +- helix-term/tests/test/movement.rs | 2 +- helix-tui/src/backend/crossterm.rs | 6 +++--- helix-view/src/editor.rs | 2 +- helix-view/src/theme.rs | 2 +- 21 files changed, 70 insertions(+), 70 deletions(-) diff --git a/helix-core/src/position.rs b/helix-core/src/position.rs index 04bf8c31f..ee764bc64 100644 --- a/helix-core/src/position.rs +++ b/helix-core/src/position.rs @@ -109,7 +109,7 @@ pub fn visual_coords_at_pos(text: RopeSlice, pos: usize, tab_width: usize) -> Po /// softwrapping positions are estimated with an O(1) algorithm /// to ensure consistent performance for large lines (currently unimplemented) /// -/// Usualy you want to use `visual_offset_from_anchor` instead but this function +/// Usually you want to use `visual_offset_from_anchor` instead but this function /// can be useful (and faster) if /// * You already know the visual position of the block /// * You only care about the horizontal offset (column) and not the vertical offset (row) @@ -291,7 +291,7 @@ pub fn pos_at_visual_coords(text: RopeSlice, coords: Position, tab_width: usize) /// /// If no (text) grapheme starts at exactly at the specified column the /// start of the grapheme to the left is returned. If there is no grapheme -/// to the left (for example if the line starts with virtual text) then the positiong +/// to the left (for example if the line starts with virtual text) then the positioning /// of the next grapheme to the right is returned. /// /// If the `line` coordinate is beyond the end of the file, the EOF diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index 8e93c633e..259b131a4 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -38,7 +38,7 @@ use std::borrow::Cow; /// Ranges are considered to be inclusive on the left and /// exclusive on the right, regardless of anchor-head ordering. /// This means, for example, that non-zero-width ranges that -/// are directly adjecent, sharing an edge, do not overlap. +/// are directly adjacent, sharing an edge, do not overlap. /// However, a zero-width range will overlap with the shared /// left-edge of another range. /// diff --git a/helix-core/src/shellwords.rs b/helix-core/src/shellwords.rs index 0883eb917..9d873c366 100644 --- a/helix-core/src/shellwords.rs +++ b/helix-core/src/shellwords.rs @@ -294,14 +294,14 @@ mod test { #[test] fn test_lists() { let input = - r#":set statusline.center ["file-type","file-encoding"] '["list", "in", "qoutes"]'"#; + r#":set statusline.center ["file-type","file-encoding"] '["list", "in", "quotes"]'"#; let shellwords = Shellwords::from(input); let result = shellwords.words().to_vec(); let expected = vec![ Cow::from(":set"), Cow::from("statusline.center"), Cow::from(r#"["file-type","file-encoding"]"#), - Cow::from(r#"["list", "in", "qoutes"]"#), + Cow::from(r#"["list", "in", "quotes"]"#), ]; assert_eq!(expected, result); } diff --git a/helix-core/src/text_annotations.rs b/helix-core/src/text_annotations.rs index e60931845..11d19d485 100644 --- a/helix-core/src/text_annotations.rs +++ b/helix-core/src/text_annotations.rs @@ -172,7 +172,7 @@ impl TextAnnotations { for char_idx in char_range { if let Some((_, Some(highlight))) = self.overlay_at(char_idx) { // we don't know the number of chars the original grapheme takes - // however it doesn't matter as highlight bounderies are automatically + // however it doesn't matter as highlight boundaries are automatically // aligned to grapheme boundaries in the rendering code highlights.push((highlight.0, char_idx..char_idx + 1)) } @@ -203,7 +203,7 @@ impl TextAnnotations { /// Add new grapheme overlays. /// - /// The overlayed grapheme will be rendered with `highlight` + /// The overlaid grapheme will be rendered with `highlight` /// patched on top of `ui.text`. /// /// The overlays **must be sorted** by their `char_idx`. diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 29a67988a..93e822c44 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -52,8 +52,8 @@ pub struct Client { root_path: std::path::PathBuf, root_uri: Option, workspace_folders: Mutex>, - initalize_notify: Arc, - /// workspace folders added while the server is still initalizing + initialize_notify: Arc, + /// workspace folders added while the server is still initializing req_timeout: u64, } @@ -92,14 +92,14 @@ impl Client { return true; } - // this server definitly doesn't support multiple workspace, no need to check capabilities + // this server definitely doesn't support multiple workspace, no need to check capabilities if !may_support_workspace { return false; } let Some(capabilities) = self.capabilities.get() else { let client = Arc::clone(self); - // initalization hasn't finished yet, deal with this new root later + // initialization hasn't finished yet, deal with this new root later // TODO: In the edgecase that a **new root** is added // for an LSP that **doesn't support workspace_folders** before initaliation is finished // the new roots are ignored. @@ -108,7 +108,7 @@ impl Client { // documents LSP client handle. It's doable but a pretty weird edgecase so let's // wait and see if anyone ever runs into it. tokio::spawn(async move { - client.initalize_notify.notified().await; + client.initialize_notify.notified().await; if let Some(workspace_folders_caps) = client .capabilities() .workspace @@ -234,7 +234,7 @@ impl Client { root_path, root_uri, workspace_folders: Mutex::new(workspace_folders), - initalize_notify: initialize_notify.clone(), + initialize_notify: initialize_notify.clone(), }; Ok((client, server_rx, initialize_notify)) @@ -279,7 +279,7 @@ impl Client { "utf-16" => Some(OffsetEncoding::Utf16), "utf-32" => Some(OffsetEncoding::Utf32), encoding => { - log::error!("Server provided invalid position encording {encoding}, defaulting to utf-16"); + log::error!("Server provided invalid position encoding {encoding}, defaulting to utf-16"); None }, }) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index a59fa31e4..31ee1d75c 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -152,10 +152,10 @@ pub mod util { // > ‘\n’, ‘\r\n’ and ‘\r’. Positions are line end character agnostic. // > So you can not specify a position that denotes \r|\n or \n| where | represents the character offset. // - // This means that while the line must be in bounds the `charater` + // This means that while the line must be in bounds the `character` // must be capped to the end of the line. // Note that the end of the line here is **before** the line terminator - // so we must use `line_end_char_index` istead of `doc.line_to_char(pos_line + 1)` + // so we must use `line_end_char_index` instead of `doc.line_to_char(pos_line + 1)` // // FIXME: Helix does not fully comply with the LSP spec for line terminators. // The LSP standard requires that line terminators are ['\n', '\r\n', '\r']. @@ -893,7 +893,7 @@ fn start_client( /// * if the file is outside `workspace` return `None` /// * start at `file` and search the file tree upward /// * stop the search at the first `root_dirs` entry that contains `file` -/// * if no `root_dirs` matchs `file` stop at workspace +/// * if no `root_dirs` matches `file` stop at workspace /// * Returns the top most directory that contains a `root_marker` /// * If no root marker and we stopped at a `root_dirs` entry, return the directory we stopped at /// * If we stopped at `workspace` instead and `workspace_is_cwd == false` return `None` diff --git a/helix-lsp/src/snippet.rs b/helix-lsp/src/snippet.rs index a4f049e83..ebf3da240 100644 --- a/helix-lsp/src/snippet.rs +++ b/helix-lsp/src/snippet.rs @@ -61,7 +61,7 @@ fn render_elements( offset: &mut usize, tabstops: &mut Vec<(usize, (usize, usize))>, newline_with_offset: &str, - include_placeholer: bool, + include_placeholder: bool, ) { use SnippetElement::*; @@ -89,7 +89,7 @@ fn render_elements( offset, tabstops, newline_with_offset, - include_placeholer, + include_placeholder, ); } &Tabstop { tabstop } => { @@ -100,14 +100,14 @@ fn render_elements( value: inner_snippet_elements, } => { let start_offset = *offset; - if include_placeholer { + if include_placeholder { render_elements( inner_snippet_elements, insert, offset, tabstops, newline_with_offset, - include_placeholer, + include_placeholder, ); } tabstops.push((*tabstop, (start_offset, *offset))); @@ -127,7 +127,7 @@ fn render_elements( pub fn render( snippet: &Snippet<'_>, newline_with_offset: &str, - include_placeholer: bool, + include_placeholder: bool, ) -> (Tendril, Vec>) { let mut insert = Tendril::new(); let mut tabstops = Vec::new(); @@ -139,7 +139,7 @@ pub fn render( &mut offset, &mut tabstops, newline_with_offset, - include_placeholer, + include_placeholder, ); // sort in ascending order (except for 0, which should always be the last one (per lsp doc)) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 130a74af6..f7d7fa636 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -25,7 +25,7 @@ use crate::{ config::Config, job::Jobs, keymap::Keymaps, - ui::{self, overlay::overlayed}, + ui::{self, overlay::overlaid}, }; use log::{debug, error, warn}; @@ -169,7 +169,7 @@ impl Application { 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))); + compositor.push(Box::new(overlaid(picker))); } else { let nr_of_files = args.files.len(); for (i, (file, pos)) in args.files.into_iter().enumerate() { diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index b55f1ab72..17669924c 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -54,7 +54,7 @@ use crate::{ job::Callback, keymap::ReverseKeymap, ui::{ - self, editor::InsertEvent, lsp::SignatureHelp, overlay::overlayed, FilePicker, Picker, + self, editor::InsertEvent, lsp::SignatureHelp, overlay::overlaid, FilePicker, Picker, Popup, Prompt, PromptEvent, }, }; @@ -1561,7 +1561,7 @@ fn half_page_down(cx: &mut Context) { } #[allow(deprecated)] -// currently uses the deprected `visual_coords_at_pos`/`pos_at_visual_coords` functions +// currently uses the deprecated `visual_coords_at_pos`/`pos_at_visual_coords` functions // as this function ignores softwrapping (and virtual text) and instead only cares // about "text visual position" // @@ -2147,7 +2147,7 @@ fn global_search(cx: &mut Context) { Some((path.clone().into(), Some((*line_num, *line_num)))) }, ); - compositor.push(Box::new(overlayed(picker))); + compositor.push(Box::new(overlaid(picker))); }, )); Ok(call) @@ -2421,7 +2421,7 @@ fn append_mode(cx: &mut Context) { fn file_picker(cx: &mut Context) { let root = find_workspace().0; let picker = ui::file_picker(root, &cx.editor.config()); - cx.push_layer(Box::new(overlayed(picker))); + cx.push_layer(Box::new(overlaid(picker))); } fn file_picker_in_current_buffer_directory(cx: &mut Context) { @@ -2438,12 +2438,12 @@ fn file_picker_in_current_buffer_directory(cx: &mut Context) { }; let picker = ui::file_picker(path, &cx.editor.config()); - cx.push_layer(Box::new(overlayed(picker))); + cx.push_layer(Box::new(overlaid(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(overlayed(picker))); + cx.push_layer(Box::new(overlaid(picker))); } fn buffer_picker(cx: &mut Context) { @@ -2508,7 +2508,7 @@ fn buffer_picker(cx: &mut Context) { Some((meta.id.into(), Some((line, line)))) }, ); - cx.push_layer(Box::new(overlayed(picker))); + cx.push_layer(Box::new(overlaid(picker))); } fn jumplist_picker(cx: &mut Context) { @@ -2590,7 +2590,7 @@ fn jumplist_picker(cx: &mut Context) { Some((meta.path.clone()?.into(), Some((line, line)))) }, ); - cx.push_layer(Box::new(overlayed(picker))); + cx.push_layer(Box::new(overlaid(picker))); } impl ui::menu::Item for MappableCommand { @@ -2664,7 +2664,7 @@ pub fn command_palette(cx: &mut Context) { } } }); - compositor.push(Box::new(overlayed(picker))); + compositor.push(Box::new(overlaid(picker))); }, )); } @@ -4185,7 +4185,7 @@ pub fn completion(cx: &mut Context) { None => return, }; - // setup a chanel that allows the request to be canceled + // setup a channel that allows the request to be canceled let (tx, rx) = oneshot::channel(); // set completion_request so that this request can be canceled // by setting completion_request, the old channel stored there is dropped @@ -4238,7 +4238,7 @@ pub fn completion(cx: &mut Context) { let (view, doc) = current_ref!(editor); // check if the completion request is stale. // - // Completions are completed asynchrounsly and therefore the user could + // Completions are completed asynchronously and therefore the user could //switch document/view or leave insert mode. In all of thoise cases the // completion should be discarded if editor.mode != Mode::Insert || view.id != trigger_view || doc.id() != trigger_doc { diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index dac1e9d52..8efdc9cfa 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -2,7 +2,7 @@ use super::{Context, Editor}; use crate::{ compositor::{self, Compositor}, job::{Callback, Jobs}, - ui::{self, overlay::overlayed, FilePicker, Picker, Popup, Prompt, PromptEvent, Text}, + ui::{self, overlay::overlaid, FilePicker, Picker, Popup, Prompt, PromptEvent, Text}, }; use dap::{StackFrame, Thread, ThreadStates}; use helix_core::syntax::{DebugArgumentValue, DebugConfigCompletion, DebugTemplate}; @@ -270,7 +270,7 @@ pub fn dap_launch(cx: &mut Context) { let templates = config.templates.clone(); - cx.push_layer(Box::new(overlayed(Picker::new( + cx.push_layer(Box::new(overlaid(Picker::new( templates, (), |cx, template, _action| { diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 78dbc0be9..7a26b3cf6 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -26,7 +26,7 @@ use helix_view::{ use crate::{ compositor::{self, Compositor}, ui::{ - self, lsp::SignatureHelp, overlay::overlayed, DynamicPicker, FileLocation, FilePicker, + self, lsp::SignatureHelp, overlay::overlaid, DynamicPicker, FileLocation, FilePicker, Popup, PromptEvent, }, }; @@ -372,7 +372,7 @@ pub fn symbol_picker(cx: &mut Context) { }; let picker = sym_picker(symbols, current_url, offset_encoding); - compositor.push(Box::new(overlayed(picker))) + compositor.push(Box::new(overlaid(picker))) } }, ) @@ -431,7 +431,7 @@ pub fn workspace_symbol_picker(cx: &mut Context) { future.boxed() }; let dyn_picker = DynamicPicker::new(picker, Box::new(get_symbols)); - compositor.push(Box::new(overlayed(dyn_picker))) + compositor.push(Box::new(overlaid(dyn_picker))) }, ) } @@ -454,7 +454,7 @@ pub fn diagnostics_picker(cx: &mut Context) { DiagnosticsFormat::HideSourcePath, offset_encoding, ); - cx.push_layer(Box::new(overlayed(picker))); + cx.push_layer(Box::new(overlaid(picker))); } } @@ -471,7 +471,7 @@ pub fn workspace_diagnostics_picker(cx: &mut Context) { DiagnosticsFormat::ShowSourcePath, offset_encoding, ); - cx.push_layer(Box::new(overlayed(picker))); + cx.push_layer(Box::new(overlaid(picker))); } impl ui::menu::Item for lsp::CodeActionOrCommand { @@ -491,7 +491,7 @@ impl ui::menu::Item for lsp::CodeActionOrCommand { /// /// While the `kind` field is defined as open ended in the LSP spec (any value may be used) /// in practice a closed set of common values (mostly suggested in the LSP spec) are used. -/// VSCode displays each of these categories seperatly (seperated by a heading in the codeactions picker) +/// VSCode displays each of these categories separately (separated by a heading in the codeactions picker) /// to make them easier to navigate. Helix does not display these headings to the user. /// However it does sort code actions by their categories to achieve the same order as the VScode picker, /// just without the headings. @@ -521,7 +521,7 @@ fn action_category(action: &CodeActionOrCommand) -> u32 { } } -fn action_prefered(action: &CodeActionOrCommand) -> bool { +fn action_preferred(action: &CodeActionOrCommand) -> bool { matches!( action, CodeActionOrCommand::CodeAction(CodeAction { @@ -600,12 +600,12 @@ pub fn code_action(cx: &mut Context) { } // Sort codeactions into a useful order. This behaviour is only partially described in the LSP spec. - // Many details are modeled after vscode because langauge servers are usually tested against it. + // Many details are modeled after vscode because language servers are usually tested against it. // VScode sorts the codeaction two times: // // First the codeactions that fix some diagnostics are moved to the front. // If both codeactions fix some diagnostics (or both fix none) the codeaction - // that is marked with `is_preffered` is shown first. The codeactions are then shown in seperate + // that is marked with `is_preferred` is shown first. The codeactions are then shown in separate // submenus that only contain a certain category (see `action_category`) of actions. // // Below this done in in a single sorting step @@ -627,10 +627,10 @@ pub fn code_action(cx: &mut Context) { return order; } - // if one of the codeactions is marked as prefered show it first + // if one of the codeactions is marked as preferred show it first // otherwise keep the original LSP sorting - action_prefered(action1) - .cmp(&action_prefered(action2)) + action_preferred(action1) + .cmp(&action_preferred(action2)) .reverse() }); @@ -955,7 +955,7 @@ fn goto_impl( }, move |_editor, location| Some(location_to_file_location(location)), ); - compositor.push(Box::new(overlayed(picker))); + compositor.push(Box::new(overlaid(picker))); } } } diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index afc3d7069..3c954d20f 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -116,7 +116,7 @@ fn open(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> let call: job::Callback = job::Callback::EditorCompositor(Box::new( move |editor: &mut Editor, compositor: &mut Compositor| { let picker = ui::file_picker(path, &editor.config()); - compositor.push(Box::new(overlayed(picker))); + compositor.push(Box::new(overlaid(picker))); }, )); Ok(call) @@ -1335,7 +1335,7 @@ fn lsp_workspace_command( let picker = ui::Picker::new(commands, (), |cx, command, _action| { execute_lsp_command(cx.editor, command.clone()); }); - compositor.push(Box::new(overlayed(picker))) + compositor.push(Box::new(overlaid(picker))) }, )); Ok(call) diff --git a/helix-term/src/ui/document.rs b/helix-term/src/ui/document.rs index 39c209505..80da1c542 100644 --- a/helix-term/src/ui/document.rs +++ b/helix-term/src/ui/document.rs @@ -118,7 +118,7 @@ pub fn render_document( fn translate_positions( char_pos: usize, - first_visisble_char_idx: usize, + first_visible_char_idx: usize, translated_positions: &mut [TranslatedPosition], text_fmt: &TextFormat, renderer: &mut TextRenderer, @@ -126,7 +126,7 @@ fn translate_positions( ) { // check if any positions translated on the fly (like cursor) has been reached for (char_idx, callback) in &mut *translated_positions { - if *char_idx < char_pos && *char_idx >= first_visisble_char_idx { + if *char_idx < char_pos && *char_idx >= first_visible_char_idx { // by replacing the char_index with usize::MAX large number we ensure // that the same position is only translated once // text will never reach usize::MAX as rust memory allocations are limited @@ -259,7 +259,7 @@ pub fn render_text<'t>( } } - // aquire the correct grapheme style + // acquire the correct grapheme style if char_pos >= style_span.1 { style_span = styles.next().unwrap_or((Style::default(), usize::MAX)); } @@ -404,7 +404,7 @@ impl<'a> TextRenderer<'a> { let cut_off_start = self.col_offset.saturating_sub(position.col); let is_whitespace = grapheme.is_whitespace(); - // TODO is it correct to apply the whitspace style to all unicode white spaces? + // TODO is it correct to apply the whitespace style to all unicode white spaces? if is_whitespace { style = style.patch(self.whitespace_style); } diff --git a/helix-term/src/ui/fuzzy_match.rs b/helix-term/src/ui/fuzzy_match.rs index b406702ff..22dc3a7fa 100644 --- a/helix-term/src/ui/fuzzy_match.rs +++ b/helix-term/src/ui/fuzzy_match.rs @@ -54,7 +54,7 @@ impl QueryAtom { } fn indices(&self, matcher: &Matcher, item: &str, indices: &mut Vec) -> bool { - // for inverse there are no indicies to return + // for inverse there are no indices to return // just return whether we matched if self.inverse { return self.matches(matcher, item); @@ -120,7 +120,7 @@ enum QueryAtomKind { /// /// Usage: `foo` Fuzzy, - /// Item contains query atom as a continous substring + /// Item contains query atom as a continuous substring /// /// Usage `'foo` Substring, @@ -213,7 +213,7 @@ impl FuzzyQuery { Some(score) } - pub fn fuzzy_indicies(&self, item: &str, matcher: &Matcher) -> Option<(i64, Vec)> { + pub fn fuzzy_indices(&self, item: &str, matcher: &Matcher) -> Option<(i64, Vec)> { let (score, mut indices) = self.first_fuzzy_atom.as_ref().map_or_else( || Some((0, Vec::new())), |atom| matcher.fuzzy_indices(item, atom), diff --git a/helix-term/src/ui/fuzzy_match/test.rs b/helix-term/src/ui/fuzzy_match/test.rs index 3f90ef681..5df79eeb1 100644 --- a/helix-term/src/ui/fuzzy_match/test.rs +++ b/helix-term/src/ui/fuzzy_match/test.rs @@ -7,8 +7,8 @@ fn run_test<'a>(query: &str, items: &'a [&'a str]) -> Vec { items .iter() .filter_map(|item| { - let (_, indicies) = query.fuzzy_indicies(item, &matcher)?; - let matched_string = indicies + let (_, indices) = query.fuzzy_indices(item, &matcher)?; + let matched_string = indices .iter() .map(|&pos| item.chars().nth(pos).unwrap()) .collect(); diff --git a/helix-term/src/ui/overlay.rs b/helix-term/src/ui/overlay.rs index 5b2bc8060..ff184d407 100644 --- a/helix-term/src/ui/overlay.rs +++ b/helix-term/src/ui/overlay.rs @@ -16,7 +16,7 @@ pub struct Overlay { } /// Surrounds the component with a margin of 5% on each side, and an additional 2 rows at the bottom -pub fn overlayed(content: T) -> Overlay { +pub fn overlaid(content: T) -> Overlay { Overlay { content, calc_child_size: Box::new(|rect: Rect| clip_rect_relative(rect.clip_bottom(2), 90, 90)), diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index e73088e52..e7a7de909 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -794,7 +794,7 @@ impl Component for Picker { // might be inconsistencies. This is the best we can do since only the // text in Row is displayed to the end user. let (_score, highlights) = FuzzyQuery::new(self.prompt.line()) - .fuzzy_indicies(&line, &self.matcher) + .fuzzy_indices(&line, &self.matcher) .unwrap_or_default(); let highlight_byte_ranges: Vec<_> = line diff --git a/helix-term/tests/test/movement.rs b/helix-term/tests/test/movement.rs index e10ec6f5d..9a48cdbcb 100644 --- a/helix-term/tests/test/movement.rs +++ b/helix-term/tests/test/movement.rs @@ -391,7 +391,7 @@ async fn cursor_position_newly_opened_file() -> anyhow::Result<()> { #[tokio::test(flavor = "multi_thread")] async fn cursor_position_append_eof() -> anyhow::Result<()> { - // Selection is fowards + // Selection is forwards test(( "#[foo|]#", "abar", diff --git a/helix-tui/src/backend/crossterm.rs b/helix-tui/src/backend/crossterm.rs index 4d44f187d..9d70a9fb0 100644 --- a/helix-tui/src/backend/crossterm.rs +++ b/helix-tui/src/backend/crossterm.rs @@ -344,9 +344,9 @@ impl ModifierDiff { } } -/// Crossterm uses semicolon as a seperator for colors -/// this is actually not spec compliant (altough commonly supported) -/// However the correct approach is to use colons as a seperator. +/// Crossterm uses semicolon as a separator for colors +/// this is actually not spec compliant (although commonly supported) +/// However the correct approach is to use colons as a separator. /// This usually doesn't make a difference for emulators that do support colored underlines. /// However terminals that do not support colored underlines will ignore underlines colors with colons /// while escape sequences with semicolons are always processed which leads to weird visual artifacts. diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 34c59b9b4..80c47ed08 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -851,7 +851,7 @@ pub struct Editor { pub config_events: (UnboundedSender, UnboundedReceiver), /// Allows asynchronous tasks to control the rendering /// The `Notify` allows asynchronous tasks to request the editor to perform a redraw - /// The `RwLock` blocks the editor from performing the render until an exclusive lock can be aquired + /// The `RwLock` blocks the editor from performing the render until an exclusive lock can be acquired pub redraw_handle: RedrawHandle, pub needs_redraw: bool, /// Cached position of the cursor calculated during rendering. diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 5d79ff26b..a8cc59260 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -128,7 +128,7 @@ impl Loader { let parent_palette = parent_theme_toml.get("palette"); let palette = theme_toml.get("palette"); - // handle the table seperately since it needs a `merge_depth` of 2 + // handle the table separately since it needs a `merge_depth` of 2 // this would conflict with the rest of the theme merge strategy let palette_values = match (parent_palette, palette) { (Some(parent_palette), Some(palette)) => { From af88a3c15cc4ddbb1e2f2ea6492868ffb8aba40b Mon Sep 17 00:00:00 2001 From: gibbz00 Date: Sat, 8 Apr 2023 14:18:11 +0200 Subject: [PATCH 076/260] Fix #6605: Remove soft-wrap.enable option wrapping. (#6656) Co-authored-by: gibbz00 --- helix-core/src/syntax.rs | 2 +- helix-view/src/document.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 408469675..0e6696db0 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -555,7 +555,7 @@ impl LanguageConfiguration { #[serde(default, rename_all = "kebab-case", deny_unknown_fields)] pub struct SoftWrap { /// Soft wrap lines that exceed viewport width. Default to off - pub enable: Option, + pub enable: bool, /// Maximum space left free at the end of the line. /// This space is used to wrap text at word boundaries. If that is not possible within this limit /// the word is simply split at the end of the line. diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index eca600265..65a5a6e22 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1444,9 +1444,8 @@ impl Document { .as_ref() .and_then(|config| config.soft_wrap.as_ref()); let enable_soft_wrap = language_soft_wrap - .and_then(|soft_wrap| soft_wrap.enable) - .or(editor_soft_wrap.enable) - .unwrap_or(false); + .map(|soft_wrap| soft_wrap.enable) + .unwrap_or_else(|| editor_soft_wrap.enable); let max_wrap = language_soft_wrap .and_then(|soft_wrap| soft_wrap.max_wrap) .or(config.soft_wrap.max_wrap) From 25858ec2e3265a2cfc562e39136beb76df77953b Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sat, 8 Apr 2023 14:18:33 +0200 Subject: [PATCH 077/260] themes: add inlay-hint to nightfox (#6655) --- runtime/themes/nightfox.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/themes/nightfox.toml b/runtime/themes/nightfox.toml index 8cddbbaef..fad56d189 100644 --- a/runtime/themes/nightfox.toml +++ b/runtime/themes/nightfox.toml @@ -33,6 +33,7 @@ "ui.virtual.ruler" = { bg = "bg3" } # Vertical rulers (colored columns in editing area). "ui.virtual.whitespace" = { fg = "bg3" } # Whitespace markers in editing area. "ui.virtual.indent-guide" = { fg = "black" } # Vertical indent width guides +"ui.virtual.inlay-hint" = { fg = "comment", bg = "bg2" } # Default style for inlay hints of all kinds "ui.statusline" = { fg = "fg2", bg = "bg0" } # Status line. "ui.statusline.inactive" = { fg = "fg3", bg = "bg0" } # Status line in unfocused windows. From 58e457a4e1037caf43c17dea93c5321c1ae74103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Sat, 8 Apr 2023 21:50:43 +0900 Subject: [PATCH 078/260] Revert "Fix #6605: Remove soft-wrap.enable option wrapping. (#6656)" This caused a bug that would ignore the global config. This reverts commit af88a3c15cc4ddbb1e2f2ea6492868ffb8aba40b. --- helix-core/src/syntax.rs | 4 +++- helix-view/src/document.rs | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 0e6696db0..c34ea81a3 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -555,7 +555,9 @@ impl LanguageConfiguration { #[serde(default, rename_all = "kebab-case", deny_unknown_fields)] pub struct SoftWrap { /// Soft wrap lines that exceed viewport width. Default to off - pub enable: bool, + // NOTE: Option on purpose because the struct is shared between language config and global config. + // By default the option is None so that the language config falls back to the global config unless explicitly set. + pub enable: Option, /// Maximum space left free at the end of the line. /// This space is used to wrap text at word boundaries. If that is not possible within this limit /// the word is simply split at the end of the line. diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 65a5a6e22..eca600265 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1444,8 +1444,9 @@ impl Document { .as_ref() .and_then(|config| config.soft_wrap.as_ref()); let enable_soft_wrap = language_soft_wrap - .map(|soft_wrap| soft_wrap.enable) - .unwrap_or_else(|| editor_soft_wrap.enable); + .and_then(|soft_wrap| soft_wrap.enable) + .or(editor_soft_wrap.enable) + .unwrap_or(false); let max_wrap = language_soft_wrap .and_then(|soft_wrap| soft_wrap.max_wrap) .or(config.soft_wrap.max_wrap) From 6dabd36491673db0110e8b78f9489fa9354708c6 Mon Sep 17 00:00:00 2001 From: Arnar Date: Sun, 9 Apr 2023 21:23:01 +0200 Subject: [PATCH 079/260] Update gleam grammar (#6641) --- languages.toml | 2 +- runtime/queries/gleam/highlights.scm | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index c643beab1..fa725aafa 100644 --- a/languages.toml +++ b/languages.toml @@ -1425,7 +1425,7 @@ language-server = { command = "gleam", args = ["lsp"] } [[grammar]] name = "gleam" -source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "d6cbdf3477fcdb0b4d811518a356f9b5cd1795ed" } +source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "ae79782c00656945db69641378e688cdb78d52c1" } [[language]] name = "ron" diff --git a/runtime/queries/gleam/highlights.scm b/runtime/queries/gleam/highlights.scm index 34b3ce65c..56222b8fd 100644 --- a/runtime/queries/gleam/highlights.scm +++ b/runtime/queries/gleam/highlights.scm @@ -77,6 +77,7 @@ "if" "import" "let" + "panic" "todo" "try" "type" From 78b516430adcfb68e5a0989c5af6b9a096175674 Mon Sep 17 00:00:00 2001 From: Alireza Alavi <63902085+alirezaalavi87@users.noreply.github.com> Date: Sun, 9 Apr 2023 22:53:57 +0330 Subject: [PATCH 080/260] Fix minor grammar issue in 'from-vim' docs (#6667) --- book/src/from-vim.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/book/src/from-vim.md b/book/src/from-vim.md index 6ace91027..ffd5addc6 100644 --- a/book/src/from-vim.md +++ b/book/src/from-vim.md @@ -2,9 +2,9 @@ Helix's editing model is strongly inspired from Vim and Kakoune, and a notable difference from Vim (and the most striking similarity to Kakoune) is that Helix -follows the `selection → action` model. This means that the whatever you are -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 +follows the `selection → action` model. This means that whatever you are +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) and Helix's [Migrating from Vim](https://github.com/helix-editor/helix/wiki/Migrating-from-Vim). From 76825c7b661f4526856627bf1e34f024088f3fda Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 10 Apr 2023 03:26:18 +0800 Subject: [PATCH 081/260] Fix ayu theme markup unreadable bg (#6538) * Fix ayu theme markup unreadable bg * Add modifiers for markup --- runtime/themes/ayu_dark.toml | 5 ++++- runtime/themes/ayu_light.toml | 7 +++++-- runtime/themes/ayu_mirage.toml | 5 ++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/runtime/themes/ayu_dark.toml b/runtime/themes/ayu_dark.toml index 211d423f4..1e1aab91e 100644 --- a/runtime/themes/ayu_dark.toml +++ b/runtime/themes/ayu_dark.toml @@ -22,7 +22,10 @@ "namespace" = "blue" "markup.heading" = "orange" "markup.list" = "yellow" -"markup.raw.block" = { bg = "gray", fg = "orange" } +"markup.bold" = { fg = "orange", modifiers = ["bold"] } +"markup.italic" = { fg = "orange", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } +"markup.raw.block" = "orange" "markup.link.url" = "blue" "markup.link.text" = "yellow" "markup.link.label" = "green" diff --git a/runtime/themes/ayu_light.toml b/runtime/themes/ayu_light.toml index 4b0ba1db7..d4cb56de8 100644 --- a/runtime/themes/ayu_light.toml +++ b/runtime/themes/ayu_light.toml @@ -22,8 +22,11 @@ "namespace" = "blue" "markup.heading" = "orange" "markup.list" = "yellow" -"markup.raw.block" = { bg = "gray", fg = "orange" } -"markup.link.url" = "blue" +"markup.bold" = { fg = "orange", modifiers = ["bold"] } +"markup.italic" = { fg = "orange", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } +"markup.raw.block" = "orange" +"markup.link.url" = { fg = "blue", modifiers = ["underlined"] } "markup.link.text" = "yellow" "markup.link.label" = "green" "markup.quote" = "yellow" diff --git a/runtime/themes/ayu_mirage.toml b/runtime/themes/ayu_mirage.toml index 5afe0acd9..b27efc1cc 100644 --- a/runtime/themes/ayu_mirage.toml +++ b/runtime/themes/ayu_mirage.toml @@ -22,7 +22,10 @@ "namespace" = "blue" "markup.heading" = "orange" "markup.list" = "yellow" -"markup.raw.block" = { bg = "gray", fg = "orange" } +"markup.bold" = { fg = "orange", modifiers = ["bold"] } +"markup.italic" = { fg = "orange", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } +"markup.raw.block" = "orange" "markup.link.url" = "blue" "markup.link.text" = "yellow" "markup.link.label" = "green" From 894c2b9edb112dd0a3f97c3955d5996929d2828c Mon Sep 17 00:00:00 2001 From: Nico Bos Date: Sun, 9 Apr 2023 21:57:41 +0200 Subject: [PATCH 082/260] Add Windows install instructions using Winget (#6602) --- book/src/install.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/book/src/install.md b/book/src/install.md index a0e24de72..5f1651ae9 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -12,6 +12,7 @@ - [macOS](#macos) - [Homebrew Core](#homebrew-core) - [Windows](#windows) + - [Winget](#winget) - [Scoop](#scoop) - [Chocolatey](#chocolatey) - [MSYS2](#msys2) @@ -109,9 +110,17 @@ brew install helix ## Windows -Install on Windows using [Scoop](https://scoop.sh/), [Chocolatey](https://chocolatey.org/) +Install on Windows using [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/), [Scoop](https://scoop.sh/), [Chocolatey](https://chocolatey.org/) or [MSYS2](https://msys2.org/). +### Winget +Windows Package Manager winget command-line tool is by default available on Windows 11 and modern versions of Windows 10 as a part of the App Installer. +You can get [App Installer from the Microsoft Store](https://www.microsoft.com/p/app-installer/9nblggh4nns1#activetab=pivot:overviewtab). If it's already installed, make sure it is updated with the latest version. + +```sh +winget install Helix.Helix +``` + ### Scoop ```sh From e72ad1e731877570c6f728e1490485e4b31524a5 Mon Sep 17 00:00:00 2001 From: not Date: Sun, 9 Apr 2023 20:14:48 -0500 Subject: [PATCH 083/260] theme(rose-pine): Improve whitespace and search matches colors (#6679) * feat: make whitespace characters more readable * feat: make search matches more discernable * fix: reduce importance of whitespace characters * feat: add background to ui.text.focus https://github.com/rose-pine/helix/pull/4 Co-authored-by: Iorvethe <58810330+Iorvethe@users.noreply.github.com> --- runtime/themes/rose_pine.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime/themes/rose_pine.toml b/runtime/themes/rose_pine.toml index ea17ac224..e1d968941 100644 --- a/runtime/themes/rose_pine.toml +++ b/runtime/themes/rose_pine.toml @@ -32,11 +32,11 @@ "ui.help" = { fg = "subtle", bg = "overlay" } "ui.text" = { fg = "text" } -# "ui.text.focus" = {} +"ui.text.focus" = { bg = "overlay" } "ui.text.info" = { fg = "subtle" } "ui.virtual.ruler" = { bg = "overlay" } -"ui.virtual.whitespace" = { fg = "highlight_low" } +"ui.virtual.whitespace" = { fg = "highlight_high" } "ui.virtual.indent-guide" = { fg = "muted" } "ui.virtual.inlay-hint" = { fg = "subtle" } @@ -61,6 +61,7 @@ "diagnostic.info" = { underline = { color = "foam", style = "curl" } } "diagnostic.warning" = { underline = { color = "gold", style = "curl" } } "diagnostic.error" = { underline = { color = "love", style = "curl" } } +"special" = "rose" "attribute" = "iris" From 5106a124edc738d5add32a7a862124b9b715e320 Mon Sep 17 00:00:00 2001 From: tippfehlr Date: Mon, 10 Apr 2023 17:09:45 +0200 Subject: [PATCH 084/260] Fix `file-picker.follow-symlinks` config option name in docs (#6685) --- 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 4c8ff0647..38f9f9eb2 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -161,7 +161,7 @@ All git related options are only enabled in a git repository. | Key | Description | Default | |--|--|---------| |`hidden` | Enables ignoring hidden files | true -|`follow-links` | Follow symlinks instead of ignoring them | true +|`follow-symlinks` | Follow symlinks instead of ignoring them | true |`deduplicate-links` | Ignore symlinks that point at files already shown in the picker | true |`parents` | Enables reading ignore files from parent directories | true |`ignore` | Enables reading `.ignore` files | true From 686a1e2f311932c2fcfeee6e8384ab8ce959d618 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 10 Apr 2023 10:52:03 -0500 Subject: [PATCH 085/260] Update tree-sitter-git-commit (#6692) Trailers are now supported, for example 'Co-authored-by' or 'Signed-off-by'. Commits are also now recognized in message bodies. --- languages.toml | 2 +- runtime/queries/git-commit/highlights.scm | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/languages.toml b/languages.toml index fa725aafa..479777f9e 100644 --- a/languages.toml +++ b/languages.toml @@ -1194,7 +1194,7 @@ text-width = 72 [[grammar]] name = "git-commit" -source = { git = "https://github.com/the-mikedavis/tree-sitter-git-commit", rev = "bd0ca5a6065f2cada3ac6a82a66db3ceff55fa6b" } +source = { git = "https://github.com/the-mikedavis/tree-sitter-git-commit", rev = "db88cffa3952dd2328b741af5d0fc69bdb76704f" } [[language]] name = "diff" diff --git a/runtime/queries/git-commit/highlights.scm b/runtime/queries/git-commit/highlights.scm index 20f58ee57..319d76569 100644 --- a/runtime/queries/git-commit/highlights.scm +++ b/runtime/queries/git-commit/highlights.scm @@ -10,5 +10,9 @@ (change kind: "modified" @diff.delta) (change kind: "renamed" @diff.delta.moved) -[":" "->" (scissors)] @punctuation.delimiter +(trailer + key: (trailer_key) @variable.other.member + value: (trailer_value) @string) + +[":" "=" "->" (scissors)] @punctuation.delimiter (comment) @comment From f8b7e95481fee5c9a7ee4def990985a068acbc3a Mon Sep 17 00:00:00 2001 From: Konstantin Keller <30801340+koskeller@users.noreply.github.com> Date: Tue, 11 Apr 2023 00:55:52 +0300 Subject: [PATCH 086/260] LSP: Gracefully handle 'workspace/configuration' from a stopped server (#6693) --- helix-term/src/application.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index f7d7fa636..4d28c8bed 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -1033,8 +1033,7 @@ impl Application { None => self .editor .language_servers - .get_by_id(server_id) - .unwrap() + .get_by_id(server_id)? .config()?, }; if let Some(section) = item.section.as_ref() { From ed67aa864d02b611d94da7f2eceaa6a04a3d5c37 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Apr 2023 09:55:34 +0900 Subject: [PATCH 087/260] build(deps): bump libc from 0.2.140 to 0.2.141 (#6700) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.140 to 0.2.141. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.140...0.2.141) --- updated-dependencies: - dependency-name: libc 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-term/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26448c425..195a2201b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1425,9 +1425,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "libloading" diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 5222ddaa1..b240f1d82 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -68,7 +68,7 @@ grep-searcher = "0.1.11" [target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100 signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } -libc = "0.2.140" +libc = "0.2.141" [build-dependencies] helix-loader = { version = "0.6", path = "../helix-loader" } From b9b4ed5c6c68e8c2c744e779b5c4d1c148a60f47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Apr 2023 09:55:55 +0900 Subject: [PATCH 088/260] build(deps): bump bitflags from 2.0.2 to 2.1.0 (#6699) Bumps [bitflags](https://github.com/bitflags/bitflags) from 2.0.2 to 2.1.0. - [Release notes](https://github.com/bitflags/bitflags/releases) - [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md) - [Commits](https://github.com/bitflags/bitflags/compare/2.0.2...2.1.0) --- updated-dependencies: - dependency-name: bitflags 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 | 10 +++++----- helix-core/Cargo.toml | 2 +- helix-tui/Cargo.toml | 2 +- helix-view/Cargo.toml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 195a2201b..472b3152a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,9 +75,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1" +checksum = "c70beb79cbb5ce9c4f8e20849978f34225931f665bb49efa6982875a4d5facb3" [[package]] name = "bstr" @@ -1081,7 +1081,7 @@ version = "0.6.0" dependencies = [ "ahash 0.8.3", "arc-swap", - "bitflags 2.0.2", + "bitflags 2.1.0", "chrono", "dunce", "encoding_rs", @@ -1207,7 +1207,7 @@ dependencies = [ name = "helix-tui" version = "0.6.0" dependencies = [ - "bitflags 2.0.2", + "bitflags 2.1.0", "cassowary", "crossterm", "helix-core", @@ -1240,7 +1240,7 @@ version = "0.6.0" dependencies = [ "anyhow", "arc-swap", - "bitflags 2.0.2", + "bitflags 2.1.0", "chardetng", "clipboard-win", "crossterm", diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index e5c5f8f1a..887a83cfc 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -29,7 +29,7 @@ tree-sitter = "0.20" once_cell = "1.17" arc-swap = "1" regex = "1" -bitflags = "2.0" +bitflags = "2.1" ahash = "0.8.3" hashbrown = { version = "0.13.2", features = ["raw"] } dunce = "1.0" diff --git a/helix-tui/Cargo.toml b/helix-tui/Cargo.toml index 5a250bdc1..3d8a20d13 100644 --- a/helix-tui/Cargo.toml +++ b/helix-tui/Cargo.toml @@ -16,7 +16,7 @@ include = ["src/**/*", "README.md"] default = ["crossterm"] [dependencies] -bitflags = "2.0" +bitflags = "2.1" cassowary = "0.3" unicode-segmentation = "1.10" crossterm = { version = "0.26", optional = true } diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index 4f7b08edd..f9d28795d 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -14,7 +14,7 @@ default = [] term = ["crossterm"] [dependencies] -bitflags = "2.0" +bitflags = "2.1" anyhow = "1" helix-core = { version = "0.6", path = "../helix-core" } helix-loader = { version = "0.6", path = "../helix-loader" } From 2f82bc13e87ded654f933d1751063da889bac7c7 Mon Sep 17 00:00:00 2001 From: EsfoNL <59415349+EsfoNL@users.noreply.github.com> Date: Wed, 12 Apr 2023 00:59:08 +0200 Subject: [PATCH 089/260] Fix crash on opening jumplist (#6672) Co-authored-by: Esra Fokker --- helix-term/src/commands.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 17669924c..95310c1fe 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2547,6 +2547,13 @@ fn jumplist_picker(cx: &mut Context) { } } + for (view, _) in cx.editor.tree.views_mut() { + for doc_id in view.jumps.iter().map(|e| e.0).collect::>().iter() { + let doc = doc_mut!(cx.editor, doc_id); + view.sync_changes(doc); + } + } + let new_meta = |view: &View, doc_id: DocumentId, selection: Selection| { let doc = &cx.editor.documents.get(&doc_id); let text = doc.map_or("".into(), |d| { From d5fec302c9fc6a6e334a0d518c6d10f7dbeb26a7 Mon Sep 17 00:00:00 2001 From: Constantin Angheloiu Date: Wed, 12 Apr 2023 04:02:14 +0300 Subject: [PATCH 090/260] base16_transparent: Highlight selected item state (#6716) Increase visibility of selected file in file picker https://asciinema.org/a/DBaZ5zjaYrKlXDSAVH8THVZg4 --- runtime/themes/base16_transparent.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/themes/base16_transparent.toml b/runtime/themes/base16_transparent.toml index 63aa1f869..c314ae8c5 100644 --- a/runtime/themes/base16_transparent.toml +++ b/runtime/themes/base16_transparent.toml @@ -3,6 +3,8 @@ "ui.background" = { fg = "white"} "ui.background.separator" = { fg = "gray" } +"ui.text" = { fg = "light-gray" } +"ui.text.focus" = { fg = "white" } "ui.menu" = { fg = "white" } "ui.menu.selected" = { modifiers = ["reversed"] } "ui.menu.scroll" = { fg = "light-gray" } From 92c5f5f18cfafa8e9f6cb6cf0f6b584977af8eb2 Mon Sep 17 00:00:00 2001 From: Ollie Charles Date: Wed, 12 Apr 2023 14:38:11 +0100 Subject: [PATCH 091/260] Initial Cabal language support (#6485) --- book/src/generated/lang-support.md | 1 + languages.toml | 13 ++++++++++++- runtime/queries/cabal/highlights.scm | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 runtime/queries/cabal/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 3f56dd606..28dfeb049 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -9,6 +9,7 @@ | bicep | ✓ | | | `bicep-langserver` | | c | ✓ | ✓ | ✓ | `clangd` | | c-sharp | ✓ | ✓ | | `OmniSharp` | +| cabal | ✓ | | | | | cairo | ✓ | | | | | capnp | ✓ | | ✓ | | | clojure | ✓ | | | `clojure-lsp` | diff --git a/languages.toml b/languages.toml index 479777f9e..e7c374992 100644 --- a/languages.toml +++ b/languages.toml @@ -2437,6 +2437,18 @@ language-server = { command = "nimlangserver" } name = "nim" source = { git = "https://github.com/aMOPel/tree-sitter-nim", rev = "240239b232550e431d67de250d1b5856209e7f06" } +[[language]] +name = "cabal" +scope = "source.cabal" +file-types = [ "cabal" ] +roots = ["cabal.project", "Setup.hs"] +indent = { tab-width = 2, unit = " " } +comment-token = "--" + +[[grammar]] +name = "cabal" +source = { git = "https://gitlab.com/magus/tree-sitter-cabal/", rev = "7d5fa6887ae05a0b06d046f1e754c197c8ad869b" } + [[language]] name = "hurl" scope = "source.hurl" @@ -2449,4 +2461,3 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "hurl" source = { git = "https://github.com/pfeiferj/tree-sitter-hurl", rev = "264c42064b61ee21abe88d0061f29a0523352e22" } - diff --git a/runtime/queries/cabal/highlights.scm b/runtime/queries/cabal/highlights.scm new file mode 100644 index 000000000..d6b9f4627 --- /dev/null +++ b/runtime/queries/cabal/highlights.scm @@ -0,0 +1,15 @@ +(comment) @comment + +[ + "cabal-version" + (field_name) +] @type + +(section_name) @type + +[ + (section_type) + "if" + "elseif" + "else" +] @keyword From 9248de87802131475eaf52acbc1e0c95e6a1097e Mon Sep 17 00:00:00 2001 From: basbebe Date: Tue, 7 Feb 2023 12:35:08 +0100 Subject: [PATCH 092/260] Adjust everforest to resemble original more closely Adjust palettes and assignments: Color palettes of upstream everforest where tweaked since creation of this port: - https://github.com/sainnhe/everforest/pull/108 - https://github.com/sainnhe/everforest/pull/109 These adjustments move the helix everforest theme closer to the dcocumented upstream vim theme --- runtime/themes/everforest_dark.toml | 121 +++++++++++++------------ runtime/themes/everforest_light.toml | 127 +++++++++++++++------------ 2 files changed, 140 insertions(+), 108 deletions(-) diff --git a/runtime/themes/everforest_dark.toml b/runtime/themes/everforest_dark.toml index 4947e4f3b..3dd9243f6 100644 --- a/runtime/themes/everforest_dark.toml +++ b/runtime/themes/everforest_dark.toml @@ -1,81 +1,93 @@ -# Everforest (Dark Hard) -# Author: CptPotato +# Everforest (Dark Medium) +# Authors: CptPotato, basbebe # Original Author: # URL: https://github.com/sainnhe/everforest -# Filename: autoload/everforest.vim +# Filename: colors/everforest.vim # Author: sainnhe # Email: sainnhe@gmail.com # License: MIT License -"type" = "yellow" -"constant" = "purple" +"type" = { fg = "yellow", modifiers = ["italic"] } +"constant" = "fg" +"constant.builtin" = { fg = "purple", modifiers = ["italic"] } +"constant.builtin.boolean" = "purple" "constant.numeric" = "purple" -"constant.character.escape" = "orange" -"string" = "green" -"string.regexp" = "blue" -"comment" = "grey0" +"constant.character.escape" = "green" +"string" = "aqua" +"string.regexp" = "green" +"string.special" = "yellow" +"comment" = { fg = "grey1", modifiers = ["italic"] } "variable" = "fg" -"variable.builtin" = "blue" +"variable.builtin" = { fg = "purple", modifiers = ["italic"] } "variable.parameter" = "fg" -"variable.other.member" = "fg" -"label" = "aqua" +"variable.other.member" = "blue" +"label" = "orange" "punctuation" = "grey2" -"punctuation.delimiter" = "grey2" +"punctuation.delimiter" = "grey1" "punctuation.bracket" = "fg" +"punctuation.special" = "blue" "keyword" = "red" -"keyword.directive" = "aqua" +"keyword.operator" = "orange" +"keyword.directive" = "purple" +"keyword.storage" = "orange" "operator" = "orange" "function" = "green" -"function.builtin" = "blue" -"function.macro" = "aqua" -"tag" = "yellow" -"namespace" = "aqua" -"attribute" = "aqua" -"constructor" = "yellow" -"module" = "blue" -"special" = "orange" +"function.macro" = "green" +"tag" = "orange" +"namespace" = { fg = "yellow", modifiers = ["italic"] } +"attribute" = { fg = "purple", modifiers = ["italic"] } +"constructor" = "green" +"module" = "yellow" +"special" = "blue" -"markup.heading.marker" = "grey2" +"markup.heading.marker" = "grey1" "markup.heading.1" = { fg = "red", modifiers = ["bold"] } "markup.heading.2" = { fg = "orange", 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 = "fg", modifiers = ["bold"] } +"markup.heading.6" = { fg = "purple", modifiers = ["bold"] } "markup.list" = "red" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } "markup.strikethrough" = { modifiers = ["crossed_out"] } -"markup.link.url" = { fg = "blue", modifiers = ["underlined"] } +"markup.link.url" = { fg = "blue", underline = { style = "line" } } +"markup.link.label" = "orange" "markup.link.text" = "purple" -"markup.quote" = "grey2" -"markup.raw" = "green" +"markup.quote" = "grey1" +"markup.raw.inline" = "green" +"markup.raw.block" = "aqua" "diff.plus" = "green" -"diff.delta" = "orange" +"diff.delta" = "blue" "diff.minus" = "red" "ui.background" = { bg = "bg0" } -"ui.background.separator" = "grey0" -"ui.cursor" = { fg = "bg0", bg = "fg" } -"ui.cursor.match" = { fg = "orange", bg = "bg_yellow" } +"ui.background.separator" = "bg_visual" +"ui.cursor" = { fg = "bg1", bg = "grey2" } "ui.cursor.insert" = { fg = "bg0", bg = "grey1" } "ui.cursor.select" = { fg = "bg0", bg = "blue" } +"ui.cursor.match" = { fg = "orange", bg = "bg_yellow" } +"ui.cursor.primary" = { fg = "bg0", bg = "fg" } "ui.cursorline.primary" = { bg = "bg1" } -"ui.cursorline.secondary" = { bg = "bg1" } +"ui.cursorline.secondary" = { bg = "bg2" } "ui.selection" = { bg = "bg3" } "ui.linenr" = "grey0" -"ui.linenr.selected" = "fg" +"ui.linenr.selected" = "grey2" "ui.statusline" = { fg = "grey2", bg = "bg3" } "ui.statusline.inactive" = { fg = "grey0", bg = "bg1" } -"ui.statusline.normal" = { fg = "bg0", bg = "grey2", modifiers = ["bold"] } -"ui.statusline.insert" = { fg = "bg0", bg = "yellow", modifiers = ["bold"] } +"ui.statusline.normal" = { fg = "bg0", bg = "statusline1", modifiers = [ + "bold", +] } +"ui.statusline.insert" = { fg = "bg0", bg = "statusline2", modifiers = [ + "bold", +] } "ui.statusline.select" = { fg = "bg0", bg = "blue", modifiers = ["bold"] } -"ui.bufferline" = { fg = "grey0", bg = "bg1" } -"ui.bufferline.active" = { fg = "fg", bg = "bg3", modifiers = ["bold"] } +"ui.bufferline" = { fg = "grey2", bg = "bg3" } +"ui.bufferline.active" = { fg = "bg0", bg = "statusline1", modifiers = ["bold"] } "ui.popup" = { fg = "grey2", bg = "bg2" } -"ui.window" = { fg = "grey0", bg = "bg0" } +"ui.window" = { fg = "bg4", bg = "bg_dim" } "ui.help" = { fg = "fg", bg = "bg2" } "ui.text" = "fg" "ui.text.focus" = "fg" @@ -85,30 +97,30 @@ "ui.virtual.indent-guide" = { fg = "bg4" } "ui.virtual.ruler" = { bg = "bg3" } -"hint" = "blue" -"info" = "aqua" +"hint" = "green" +"info" = "blue" "warning" = "yellow" "error" = "red" -"diagnostic.hint" = { underline = { color = "blue", style = "curl" } } -"diagnostic.info" = { underline = { color = "aqua", style = "curl" } } +"diagnostic.hint" = { underline = { color = "green", style = "curl" } } +"diagnostic.info" = { underline = { color = "blue", style = "curl" } } "diagnostic.warning" = { underline = { color = "yellow", style = "curl" } } "diagnostic.error" = { underline = { color = "red", style = "curl" } } - [palette] -bg0 = "#2b3339" -bg1 = "#323c41" -bg2 = "#3a454a" -bg3 = "#445055" -bg4 = "#4c555b" -bg5 = "#53605c" -bg_visual = "#503946" -bg_red = "#4e3e43" -bg_green = "#404d44" -bg_blue = "#394f5a" -bg_yellow = "#4a4940" +bg_dim = "#232a2e" +bg0 = "#2d353b" +bg1 = "#343f44" +bg2 = "#3d484d" +bg3 = "#475258" +bg4 = "#4f585e" +bg5 = "#56635f" +bg_visual = "#543a48" +bg_red = "#514045" +bg_green = "#425047" +bg_blue = "#3a515d" +bg_yellow = "#4d4c43" fg = "#d3c6aa" red = "#e67e80" @@ -118,6 +130,7 @@ green = "#a7c080" aqua = "#83c092" blue = "#7fbbb3" purple = "#d699b6" + grey0 = "#7a8478" grey1 = "#859289" grey2 = "#9da9a0" diff --git a/runtime/themes/everforest_light.toml b/runtime/themes/everforest_light.toml index f9a55b0a8..ef0544ac6 100644 --- a/runtime/themes/everforest_light.toml +++ b/runtime/themes/everforest_light.toml @@ -1,81 +1,95 @@ -# Everforest (Dark Hard) -# Author: CptPotato +# Everforest (Light Medium) +# Authors: CptPotato, WindSoilder, basbebe # Original Author: # URL: https://github.com/sainnhe/everforest -# Filename: autoload/everforest.vim +# Filename: colors/everforest.vim # Author: sainnhe # Email: sainnhe@gmail.com # License: MIT License -"type" = "yellow" -"constant" = "purple" +"type" = { fg = "yellow", modifiers = ["italic"] } +"constant" = "fg" +"constant.builtin" = { fg = "purple", modifiers = ["italic"] } +"constant.builtin.boolean" = "purple" "constant.numeric" = "purple" -"constant.character.escape" = "orange" -"string" = "green" -"string.regexp" = "blue" -"comment" = "grey0" +"constant.character.escape" = "green" +"string" = "aqua" +"string.regexp" = "green" +"string.special" = "yellow" +"comment" = { fg = "grey1", modifiers = ["italic"] } "variable" = "fg" -"variable.builtin" = "blue" +"variable.builtin" = { fg = "purple", modifiers = ["italic"] } "variable.parameter" = "fg" -"variable.other.member" = "fg" -"label" = "aqua" +"variable.other.member" = "blue" +"label" = "orange" "punctuation" = "grey2" -"punctuation.delimiter" = "grey2" +"punctuation.delimiter" = "grey1" "punctuation.bracket" = "fg" +"punctuation.special" = "blue" "keyword" = "red" -"keyword.directive" = "aqua" +"keyword.operator" = "orange" +"keyword.directive" = "purple" +"keyword.storage" = "orange" "operator" = "orange" "function" = "green" -"function.builtin" = "blue" -"function.macro" = "aqua" -"tag" = "yellow" -"namespace" = "aqua" -"attribute" = "aqua" -"constructor" = "yellow" -"module" = "blue" -"special" = "orange" +"function.macro" = "green" +"tag" = "orange" +"namespace" = { fg = "yellow", modifiers = ["italic"] } +"attribute" = { fg = "purple", modifiers = ["italic"] } +"constructor" = "green" +"module" = "yellow" +"special" = "blue" -"markup.heading.marker" = "grey2" +"markup.heading.marker" = "grey1" "markup.heading.1" = { fg = "red", modifiers = ["bold"] } "markup.heading.2" = { fg = "orange", 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 = "fg", modifiers = ["bold"] } +"markup.heading.6" = { fg = "purple", modifiers = ["bold"] } "markup.list" = "red" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } "markup.strikethrough" = { modifiers = ["crossed_out"] } -"markup.link.url" = { fg = "blue", modifiers = ["underlined"] } +"markup.link.url" = { fg = "blue", underline = { style = "line" } } +"markup.link.label" = "orange" "markup.link.text" = "purple" -"markup.quote" = "grey2" -"markup.raw" = "green" +"markup.quote" = "grey1" +"markup.raw.inline" = "green" +"markup.raw.block" = "aqua" "diff.plus" = "green" -"diff.delta" = "orange" +"diff.delta" = "blue" "diff.minus" = "red" "ui.background" = { bg = "bg0" } -"ui.background.separator" = "grey0" -"ui.cursor" = { fg = "bg0", bg = "fg" } -"ui.cursor.match" = { fg = "orange", bg = "bg_yellow" } +"ui.background.separator" = "bg_visual" +"ui.cursor" = { fg = "bg1", bg = "grey2" } "ui.cursor.insert" = { fg = "bg0", bg = "grey1" } "ui.cursor.select" = { fg = "bg0", bg = "blue" } +"ui.cursor.match" = { bg = "bg4", modifiers = ["bold"] } +"ui.cursor.primary" = { fg = "bg0", bg = "fg" } "ui.cursorline.primary" = { bg = "bg1" } -"ui.cursorline.secondary" = { bg = "bg1" } +"ui.cursorline.secondary" = { bg = "bg2" } "ui.selection" = { bg = "bg3" } "ui.linenr" = "grey0" -"ui.linenr.selected" = "fg" +"ui.linenr.selected" = "grey2" "ui.statusline" = { fg = "grey2", bg = "bg3" } "ui.statusline.inactive" = { fg = "grey0", bg = "bg1" } -"ui.statusline.normal" = { fg = "bg0", bg = "grey2", modifiers = ["bold"] } -"ui.statusline.insert" = { fg = "bg0", bg = "yellow", modifiers = ["bold"] } +"ui.statusline.normal" = { fg = "bg0", bg = "statusline1", modifiers = [ + "bold", +] } +"ui.statusline.insert" = { fg = "bg0", bg = "statusline2", modifiers = [ + "bold", +] } "ui.statusline.select" = { fg = "bg0", bg = "blue", modifiers = ["bold"] } -"ui.bufferline" = { fg = "grey0", bg = "bg1" } -"ui.bufferline.active" = { fg = "fg", bg = "bg3", modifiers = ["bold"] } +"ui.bufferline" = { fg = "grey2", bg = "bg3" } +"ui.bufferline.active" = { fg = "bg0", bg = "statusline1", modifiers = [ + "bold", +] } "ui.popup" = { fg = "grey2", bg = "bg2" } -"ui.window" = { fg = "grey0", bg = "bg0" } +"ui.window" = { fg = "bg4", bg = "bg_dim" } "ui.help" = { fg = "fg", bg = "bg2" } "ui.text" = "fg" "ui.text.focus" = "fg" @@ -85,38 +99,43 @@ "ui.virtual.indent-guide" = { fg = "bg4" } "ui.virtual.ruler" = { bg = "bg3" } -"hint" = "blue" -"info" = "aqua" +"hint" = "green" +"info" = "blue" "warning" = "yellow" "error" = "red" -"diagnostic.hint" = { underline = { color = "blue", style = "curl" } } -"diagnostic.info" = { underline = { color = "aqua", style = "curl" } } +"diagnostic.hint" = { underline = { color = "green", style = "curl" } } +"diagnostic.info" = { underline = { color = "blue", style = "curl" } } "diagnostic.warning" = { underline = { color = "yellow", style = "curl" } } "diagnostic.error" = { underline = { color = "red", style = "curl" } } [palette] -bg0 = "#fff9e8" -bg1 = "#f7f4e0" -bg2 = "#f0eed9" -bg3 = "#e9e8d2" -bg4 = "#e1ddcb" -bg5 = "#bec5b2" -bg_visual = "#edf0cd" -bg_red = "#fce5dc" -bg_green = "#f1f3d4" -bg_blue = "#eaf2eb" -bg_yellow = "#fbefd0" +bg_dim = "#efebd4" +bg0 = "#fdf6e3" +bg1 = "#f4f0d9" +bg2 = "#efebd4" +bg3 = "#e6e2cc" +bg4 = "#e0dcc7" +bg5 = "#bdc3af" +bg_red = "#fbe3da" +bg_visual = "#eaedc8" +bg_yellow = "#faedcd" +bg_green = "#f0f1d2" +bg_blue = "#e9f0e9" fg = "#5c6a72" red = "#f85552" orange = "#f57d26" yellow = "#dfa000" green = "#8da101" -aqua = "#35a77c" blue = "#3a94c5" +aqua = "#35a77c" purple = "#df69ba" + grey0 = "#a6b0a0" grey1 = "#939f91" grey2 = "#829181" +statusline1 = "#93b259" +statusline2 = "#708089" +statusline3 = "#e66868" From bfcc4c37955775bb9365223d630f0135ce673f51 Mon Sep 17 00:00:00 2001 From: basbebe Date: Wed, 8 Feb 2023 08:41:22 +0100 Subject: [PATCH 093/260] Everforest: Fix keywords and types --- runtime/themes/everforest_dark.toml | 8 +++++--- runtime/themes/everforest_light.toml | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/runtime/themes/everforest_dark.toml b/runtime/themes/everforest_dark.toml index 3dd9243f6..b1fa02ef3 100644 --- a/runtime/themes/everforest_dark.toml +++ b/runtime/themes/everforest_dark.toml @@ -8,7 +8,7 @@ # Email: sainnhe@gmail.com # License: MIT License -"type" = { fg = "yellow", modifiers = ["italic"] } +"type" = "yellow" "constant" = "fg" "constant.builtin" = { fg = "purple", modifiers = ["italic"] } "constant.builtin.boolean" = "purple" @@ -30,7 +30,7 @@ "keyword" = "red" "keyword.operator" = "orange" "keyword.directive" = "purple" -"keyword.storage" = "orange" +"keyword.storage" = "red" "operator" = "orange" "function" = "green" "function.macro" = "green" @@ -85,7 +85,9 @@ ] } "ui.statusline.select" = { fg = "bg0", bg = "blue", modifiers = ["bold"] } "ui.bufferline" = { fg = "grey2", bg = "bg3" } -"ui.bufferline.active" = { fg = "bg0", bg = "statusline1", modifiers = ["bold"] } +"ui.bufferline.active" = { fg = "bg0", bg = "statusline1", modifiers = [ + "bold", +] } "ui.popup" = { fg = "grey2", bg = "bg2" } "ui.window" = { fg = "bg4", bg = "bg_dim" } "ui.help" = { fg = "fg", bg = "bg2" } diff --git a/runtime/themes/everforest_light.toml b/runtime/themes/everforest_light.toml index ef0544ac6..54201ab0e 100644 --- a/runtime/themes/everforest_light.toml +++ b/runtime/themes/everforest_light.toml @@ -8,7 +8,7 @@ # Email: sainnhe@gmail.com # License: MIT License -"type" = { fg = "yellow", modifiers = ["italic"] } +"type" = "yellow" "constant" = "fg" "constant.builtin" = { fg = "purple", modifiers = ["italic"] } "constant.builtin.boolean" = "purple" @@ -30,7 +30,7 @@ "keyword" = "red" "keyword.operator" = "orange" "keyword.directive" = "purple" -"keyword.storage" = "orange" +"keyword.storage" = "red" "operator" = "orange" "function" = "green" "function.macro" = "green" From 1421b67a4c1c6c252479b7ea45c183fa6cd7078d Mon Sep 17 00:00:00 2001 From: basbebe Date: Thu, 6 Apr 2023 09:00:29 +0200 Subject: [PATCH 094/260] Everforest theme: Style inlay-hints and wrap indicator --- runtime/themes/everforest_dark.toml | 4 +++- runtime/themes/everforest_light.toml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime/themes/everforest_dark.toml b/runtime/themes/everforest_dark.toml index b1fa02ef3..6903d1e54 100644 --- a/runtime/themes/everforest_dark.toml +++ b/runtime/themes/everforest_dark.toml @@ -95,9 +95,11 @@ "ui.text.focus" = "fg" "ui.menu" = { fg = "fg", bg = "bg3" } "ui.menu.selected" = { fg = "bg0", bg = "green" } +"ui.virtual.ruler" = { bg = "bg3" } "ui.virtual.whitespace" = { fg = "bg4" } "ui.virtual.indent-guide" = { fg = "bg4" } -"ui.virtual.ruler" = { bg = "bg3" } +"ui.virtual.inlay-hint" = { fg = "grey0" } +"ui.virtual.wrap" = { fg = "grey0" } "hint" = "green" "info" = "blue" diff --git a/runtime/themes/everforest_light.toml b/runtime/themes/everforest_light.toml index 54201ab0e..cf39e23d6 100644 --- a/runtime/themes/everforest_light.toml +++ b/runtime/themes/everforest_light.toml @@ -95,9 +95,11 @@ "ui.text.focus" = "fg" "ui.menu" = { fg = "fg", bg = "bg3" } "ui.menu.selected" = { fg = "bg0", bg = "green" } +"ui.virtual.ruler" = { bg = "bg3" } "ui.virtual.whitespace" = { fg = "bg4" } "ui.virtual.indent-guide" = { fg = "bg4" } -"ui.virtual.ruler" = { bg = "bg3" } +"ui.virtual.inlay-hint" = { fg = "grey0" } +"ui.virtual.wrap" = { fg = "grey0" } "hint" = "green" "info" = "blue" From deab323c28dfcc12f94a2e0c96a2a0635a0b6748 Mon Sep 17 00:00:00 2001 From: Ollie Charles Date: Wed, 12 Apr 2023 15:35:01 +0100 Subject: [PATCH 095/260] Update tree-sitter-haskell (#6317) --- languages.toml | 2 +- runtime/queries/haskell/textobjects.scm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/languages.toml b/languages.toml index e7c374992..22c1842e9 100644 --- a/languages.toml +++ b/languages.toml @@ -882,7 +882,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "haskell" -source = { git = "https://github.com/tree-sitter/tree-sitter-haskell", rev = "b6ec26f181dd059eedd506fa5fbeae1b8e5556c8" } +source = { git = "https://github.com/tree-sitter/tree-sitter-haskell", rev = "98fc7f59049aeb713ab9b72a8ff25dcaaef81087" } [[language]] name = "purescript" diff --git a/runtime/queries/haskell/textobjects.scm b/runtime/queries/haskell/textobjects.scm index 9870dc4a4..457fba1a7 100644 --- a/runtime/queries/haskell/textobjects.scm +++ b/runtime/queries/haskell/textobjects.scm @@ -2,7 +2,7 @@ [ (adt) - (decl_type) + (type_alias) (newtype) ] @class.around From 3e2eca0db85361d355de276b98797a86f0335e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Delafargue?= Date: Wed, 12 Apr 2023 16:36:57 +0200 Subject: [PATCH 096/260] tree-sitter(haskell): use quasiquoters as an injection point (#6474) Similar to tagged templates in JS, quasiquoters allow to embed external languages in haskell, so it makes sense to treat them as an injection point. --- runtime/queries/haskell/injections.scm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runtime/queries/haskell/injections.scm b/runtime/queries/haskell/injections.scm index 321c90add..788b8b8c6 100644 --- a/runtime/queries/haskell/injections.scm +++ b/runtime/queries/haskell/injections.scm @@ -1,2 +1,6 @@ ((comment) @injection.content (#set! injection.language "comment")) + +(quasiquote + (quoter) @injection.language + (quasiquote_body) @injection.content) From f6d65cf089a0b845ef01b91d0424a9ffe1e9ea45 Mon Sep 17 00:00:00 2001 From: Chirikumbrah <78883260+Chirikumbrah@users.noreply.github.com> Date: Wed, 12 Apr 2023 17:38:15 +0300 Subject: [PATCH 097/260] Refactor dracula theme (#6552) --- runtime/themes/dracula.toml | 211 +++++++++++++++++++++++------------- 1 file changed, 135 insertions(+), 76 deletions(-) diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index 6935b487f..f1d895f9d 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -1,83 +1,142 @@ # Author : Sebastian Zivota -"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"] } +# Author : Chirikumbrah -"diff.plus" = { fg = "green" } -"diff.delta" = { fg = "orange" } -"diff.minus" = { fg = "red" } +"annotation" = { fg = "white" } +"attribute" = { fg = "cyan" } +"comment" = { fg = "comment" } +"constant" = { fg = "purple" } +"constant.numeric" = { fg = "orange" } +"constant.builtin" = { fg = "orange" } +"constant.character.escape" = { fg = "pink" } +"constant.macro" = { fg = "purple" } +"constructor" = { fg = "cyan" } +"conditional" = { fg = "pink" } +"character" = { fg = "purple" } +"definition".underline = { sp = "cyan" } +"field.key" = { fg = "purple" } +"field" = { fg = "purple" } +"function" = { fg = "green" } +"function.builtin" = { fg = "green" } +"function.method" = { fg = "green" } +"function.macro" = { fg = "purple" } +"function.call" = { fg = "green" } +"keyword" = { fg = "pink" } +"keyword.operator" = { fg = "pink" } +"keyword.function" = { fg = "pink" } +"keyword.return" = { fg = "pink" } +"keyword.control.import" = { fg = "green" } +"keyword.directive" = { fg = "green" } +"keyword.control.repeat" = { fg = "cyan" } +"keyword.control.exception" = { fg = "purple" } +"keyword.storage.type" = { fg = "cyan" } +"keyword.storage.modifier" = { fg = "cyan" } +"method.call" = { fg = "green" } +"reference" = { fg = "grey" } +"special" = { fg = "orange" } +"symbol" = { fg = "yellow" } +"tag.attribute" = { fg = "purple" } +"tag.delimiter" = { fg = "white" } +"operator" = { fg = "pink" } +"label" = { fg = "cyan" } +"punctuation" = { fg = "white" } +"punctuation.bracket" = { fg = "white" } +"punctuation.delimiter" = { fg = "white" } +"punctuation.special" = { fg = "purple" } +"string" = { fg = "yellow" } +"string.regexp" = { fg = "cyan" } +"string.escape" = { fg = "cyan" } +"string.special" = { fg = "cyan" } +"tag" = { fg = "pink" } +"text" = { fg = "grey" } +"text.strong" = { modifiers = "bold" } +"text.emphasis" = { fg = "orange" } +"text.strike" = { fg = "white" } +"text.literal" = { fg = "orange" } +"text.uri".underline = { fg = "orange" } +"type.builtin" = { fg = "cyan", modifiers = ["italic"] } +"type" = { fg = "cyan", modifiers = ["italic"] } +"type.enum.variant" = { fg = "white", modifiers = ["italic"] } +"property" = { fg = "purple" } +"structure" = { fg = "purple" } +"scope" = { modifiers = "bold" } +"variable" = { fg = "purple" } +"variable.builtin" = { fg = "orange", modifiers = ["italic"] } +"variable.parameter" = { fg = "purple", modifiers = ["italic"] } +"parameter" = { fg = "orange" } -"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", modifiers = ["dim"] } -"ui.cursorline.primary" = { bg = "background_dark" } -"ui.help" = { fg = "foreground", bg = "background_dark" } -"ui.debug" = { fg = "red" } -"ui.highlight.frameline" = { fg = "black", bg = "red" } -"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.statusline.normal" = { fg = "background_dark", bg = "cyan" } -"ui.statusline.insert" = { fg = "background_dark", bg = "green" } -"ui.statusline.select" = { fg = "background_dark", bg = "purple" } -"ui.text" = { fg = "foreground" } -"ui.text.focus" = { fg = "cyan" } -"ui.window" = { fg = "foreground" } -"ui.virtual.whitespace" = { fg = "subtle" } -"ui.virtual.wrap" = { fg = "subtle" } -"ui.virtual.ruler" = { bg = "background_dark"} -"ui.virtual.inlay-hint" = { fg = "comment" } -"ui.virtual.inlay-hint.parameter" = { fg = "comment", modifiers = ["italic"] } -"ui.virtual.inlay-hint.type" = { fg = "comment", modifiers = ["italic"] } -"error" = { fg = "red" } -"warning" = { fg = "cyan" } +"diff.plus" = { fg = "green" } +"diff.delta" = { fg = "orange" } +"diff.minus" = { fg = "red" } +"ui.background" = { fg = "white", bg = "background" } +"ui.cursor.match" = { fg = "white", bg = "grey" } +"ui.cursor" = { fg = "background", bg = "purple", modifiers = ["dim"] } +"ui.cursor.normal" = { fg = "background", bg = "purple", modifiers = ["dim"] } +"ui.cursor.insert" = { fg = "background", bg = "green", modifiers = ["dim"] } +"ui.cursor.select" = { fg = "background", bg = "cyan", modifiers = ["dim"] } +"ui.cursor.primary.normal" = { fg = "background", bg = "purple" } +"ui.cursor.primary.insert" = { fg = "background", bg = "green" } +"ui.cursor.primary.select" = { fg = "background", bg = "cyan" } +"ui.cursorline.primary" = { bg = "cursorline" } +"ui.help" = { fg = "white", bg = "black" } +"ui.debug" = { fg = "red" } +"ui.highlight.frameline" = { fg = "background", bg = "red" } +"ui.linenr" = { fg = "comment" } +"ui.linenr.selected" = { fg = "white" } +"ui.menu" = { fg = "white", bg = "black" } +"ui.menu.selected" = { fg = "cyan", bg = "black" } +"ui.popup" = { fg = "white", bg = "black" } +"ui.selection.primary" = { bg = "selection_primary" } +"ui.selection" = { bg = "selection" } +"ui.statusline" = { fg = "white", bg = "darker" } +"ui.statusline.inactive" = { fg = "comment", bg = "darker" } +"ui.statusline.normal" = { fg = "black", bg = "purple" } +"ui.statusline.insert" = { fg = "black", bg = "green" } +"ui.statusline.select" = { fg = "black", bg = "cyan" } +"ui.text" = { fg = "white" } +"ui.text.focus" = { fg = "cyan" } +"ui.window" = { fg = "white" } +"ui.virtual.whitespace" = { fg = "subtle" } +"ui.virtual.wrap" = { fg = "subtle" } +"ui.virtual.ruler" = { bg = "black" } +"ui.virtual.inlay-hint" = { fg = "cyan" } +"ui.virtual.inlay-hint.parameter" = { fg = "cyan", modifiers = ["italic", "dim"] } +"ui.virtual.inlay-hint.type" = { fg = "cyan", modifiers = ["italic", "dim"] } +"hint" = { fg = "purple" } +"error" = { fg = "red" } +"warning" = { fg = "yellow" } +"info" = { fg = "cyan" } +"markup.heading" = { fg = "purple", modifiers = ["bold"] } +"markup.list" = { fg = "cyan" } +"markup.bold" = { fg = "orange", modifiers = ["bold"] } +"markup.italic" = { fg = "yellow", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } +"markup.link.url" = { fg = "cyan" } +"markup.link.text" = { fg = "pink" } +"markup.quote" = { fg = "yellow", modifiers = ["italic"] } +"markup.raw" = { fg = "white" } +"diagnostic" = { underline = { color = "orange", style = "curl" } } +"diagnostic.hint" = { underline = { color = "purple", style = "curl" } } +"diagnostic.warning" = { underline = { color = "yellow", style = "curl" } } +"diagnostic.error" = { underline = { color = "red", style = "curl" } } +"diagnostic.info" = { underline = { color = "cyan", style = "curl" } } -"markup.heading" = { fg = "purple", modifiers = ["bold"] } -"markup.list" = "cyan" -"markup.bold" = { fg = "orange", modifiers = ["bold"] } -"markup.italic" = { fg = "yellow", modifiers = ["italic"] } -"markup.strikethrough" = { modifiers = ["crossed_out"] } -"markup.link.url" = "cyan" -"markup.link.text" = "pink" -"markup.quote" = { fg = "yellow", modifiers = ["italic"] } -"markup.raw" = { fg = "foreground" } - -"diagnostic".underline = { color = "orange", style = "curl" } -"diagnostic.error".underline = { color = "red", style = "curl" } [palette] -background = "#282a36" -background_dark = "#21222c" -primary_highlight = "#800049" -secondary_highlight = "#4d4f66" -subtle = "#424450" -foreground = "#f8f8f2" -comment = "#6272a4" -red = "#ff5555" -orange = "#ffb86c" -yellow = "#f1fa8c" -green = "#50fa7b" -purple = "#bd93f9" -cyan = "#8be9fd" -pink = "#ff79c6" - +background = "#282A36" +cursorline = "#2d303e" +darker = "#222430" +black = "#191A21" +grey = "#666771" +comment = "#6272A4" +selection_primary = "#44475a" +selection = "#363848" +subtle = "#424450" +white = "#f8f8f2" +red = "#ff5555" +orange = "#ffb86c" +yellow = "#f1fa8c" +green = "#50fa7b" +purple = "#BD93F9" +cyan = "#8be9fd" +pink = "#ff79c6" From fed5e6e646b157faa3fd2be494209e68e132a8c1 Mon Sep 17 00:00:00 2001 From: Farzin Date: Wed, 12 Apr 2023 18:25:22 +0330 Subject: [PATCH 098/260] Highlight C/C++ escape sequences (#6724) --- runtime/queries/c/highlights.scm | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/queries/c/highlights.scm b/runtime/queries/c/highlights.scm index 8122216d8..07915f4e3 100644 --- a/runtime/queries/c/highlights.scm +++ b/runtime/queries/c/highlights.scm @@ -107,6 +107,7 @@ (null) @constant (number_literal) @constant.numeric (char_literal) @constant.character +(escape_sequence) @constant.character.escape (call_expression function: (identifier) @function) From 70de5026b801fb1a0eb54acc2d3685291c8e14f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Dzivjak?= Date: Wed, 12 Apr 2023 17:28:03 +0200 Subject: [PATCH 099/260] feat(languages): Support markdoc (#6432) Add basic support for [markdoc](https://markdoc.dev/). For language server, see: https://github.com/markdoc-extra/markdoc-ls For tree sitter, see: https://github.com/markdoc-extra/tree-sitter-markdoc --- book/src/generated/lang-support.md | 1 + languages.toml | 11 +++++++++++ runtime/queries/markdoc/highlights.scm | 16 ++++++++++++++++ runtime/queries/markdoc/injections.scm | 2 ++ 4 files changed, 30 insertions(+) create mode 100644 runtime/queries/markdoc/highlights.scm create mode 100644 runtime/queries/markdoc/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 28dfeb049..07aabef82 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -81,6 +81,7 @@ | llvm-mir-yaml | ✓ | | ✓ | | | lua | ✓ | ✓ | ✓ | `lua-language-server` | | make | ✓ | | | | +| markdoc | ✓ | | | `markdoc-ls` | | markdown | ✓ | | | `marksman` | | markdown.inline | ✓ | | | | | matlab | ✓ | | | | diff --git a/languages.toml b/languages.toml index 22c1842e9..9e55dd4e0 100644 --- a/languages.toml +++ b/languages.toml @@ -2461,3 +2461,14 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "hurl" source = { git = "https://github.com/pfeiferj/tree-sitter-hurl", rev = "264c42064b61ee21abe88d0061f29a0523352e22" } + +[[language]] +name = "markdoc" +scope = "text.markdoc" +roots = [] +file-types = ["mdoc"] +language-server = { command = "markdoc-ls", args = ["--stdio"] } + +[[grammar]] +name = "markdoc" +source = { git = "https://github.com/markdoc-extra/tree-sitter-markdoc", rev = "5ffe71b29e8a3f94823913ea9cea51fcfa7e3bf8" } diff --git a/runtime/queries/markdoc/highlights.scm b/runtime/queries/markdoc/highlights.scm new file mode 100644 index 000000000..8251e9afe --- /dev/null +++ b/runtime/queries/markdoc/highlights.scm @@ -0,0 +1,16 @@ +tag_name: (identifier) @tag +(tag_self_closing "/" @tag) +(tag_close "/" @tag) +([(tag_start) (tag_end) "="] @tag) +(attribute [key : (identifier)] @attribute) +(attribute [shorthand : (identifier)] @attribute) +(variable [variable : (identifier) (variable_sigil)] @variable) +(variable_tail property : (identifier) @variable.other.member) +(function function_name : (identifier) @function) +(function_parameter_named parameter : (identifier) @variable.parameter) + +(hash_key key: (identifier) @variable.other.member) +(string) @string +(number) @constant.numeric +(boolean) @constant.builtin.boolean +(null) @constant.builtin diff --git a/runtime/queries/markdoc/injections.scm b/runtime/queries/markdoc/injections.scm new file mode 100644 index 000000000..1594546ba --- /dev/null +++ b/runtime/queries/markdoc/injections.scm @@ -0,0 +1,2 @@ +((markdown) @injection.content + (#set! injection.language "markdown")) From fff8543b5809766608be14ee1a45f8b86f5a3de2 Mon Sep 17 00:00:00 2001 From: lefp <70862148+lefp@users.noreply.github.com> Date: Wed, 12 Apr 2023 15:42:41 -0400 Subject: [PATCH 100/260] Add OpenCL tree-sitter and LSP config (#6473) --- book/src/generated/lang-support.md | 1 + languages.toml | 13 +++ runtime/queries/opencl/highlights.scm | 150 +++++++++++++++++++++++++ runtime/queries/opencl/indents.scm | 1 + runtime/queries/opencl/injections.scm | 1 + runtime/queries/opencl/textobjects.scm | 1 + 6 files changed, 167 insertions(+) create mode 100644 runtime/queries/opencl/highlights.scm create mode 100644 runtime/queries/opencl/indents.scm create mode 100644 runtime/queries/opencl/injections.scm create mode 100644 runtime/queries/opencl/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 07aabef82..b458bd6f1 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -97,6 +97,7 @@ | ocaml | ✓ | | ✓ | `ocamllsp` | | ocaml-interface | ✓ | | | `ocamllsp` | | odin | ✓ | | | `ols` | +| opencl | ✓ | ✓ | ✓ | `clangd` | | openscad | ✓ | | | `openscad-lsp` | | org | ✓ | | | | | pascal | ✓ | ✓ | | `pasls` | diff --git a/languages.toml b/languages.toml index 9e55dd4e0..866881370 100644 --- a/languages.toml +++ b/languages.toml @@ -2472,3 +2472,16 @@ language-server = { command = "markdoc-ls", args = ["--stdio"] } [[grammar]] name = "markdoc" source = { git = "https://github.com/markdoc-extra/tree-sitter-markdoc", rev = "5ffe71b29e8a3f94823913ea9cea51fcfa7e3bf8" } + +[[language]] +name = "opencl" +scope = "source.cl" +injection-regex = "(cl|opencl)" +file-types = ["cl"] +roots = [] +comment-token = "//" +language-server = { command = "clangd" } + +[[grammar]] +name = "opencl" +source = { git = "https://github.com/lefp/tree-sitter-opencl", rev = "8e1d24a57066b3cd1bb9685bbc1ca9de5c1b78fb" } diff --git a/runtime/queries/opencl/highlights.scm b/runtime/queries/opencl/highlights.scm new file mode 100644 index 000000000..9d76d6c66 --- /dev/null +++ b/runtime/queries/opencl/highlights.scm @@ -0,0 +1,150 @@ +[ + "sizeof" + ; @todo why does "uniform" break highlighting? + ; "uniform" ; OpenCL C 3.0.13 reserves this as a keyword, but doesn't seem to use it for anything + (function_qualifier) +] @keyword + +[ + "enum" + "struct" + "typedef" + "union" +] @keyword.storage.type + +[ + "extern" + "register" + (type_qualifier) + (access_qualifier) + (storage_class_specifier) + (address_space_qualifier) +] @keyword.storage.modifier + +[ + "goto" + "break" + "continue" +] @keyword.control + +[ + "do" + "for" + "while" +] @keyword.control.repeat + +[ + "if" + "else" + "switch" + "case" + "default" +] @keyword.control.conditional + +"return" @keyword.control.return + +[ + "defined" + "#define" + "#elif" + "#else" + "#endif" + "#if" + "#ifdef" + "#ifndef" + "#include" + (preproc_directive) +] @keyword.directive + +(pointer_declarator "*" @type.builtin) +(abstract_pointer_declarator "*" @type.builtin) + +[ + "+" + "-" + "*" + "/" + "++" + "--" + "%" + "==" + "!=" + ">" + "<" + ">=" + "<=" + "&&" + "||" + "!" + "&" + "|" + "^" + "~" + "<<" + ">>" + "=" + "+=" + "-=" + "*=" + "/=" + "%=" + "<<=" + ">>=" + "&=" + "^=" + "|=" + "?" +] @operator + +(conditional_expression ":" @operator) + +"..." @punctuation + +["," "." ":" ";" "->" "::"] @punctuation.delimiter + +["(" ")" "[" "]" "{" "}"] @punctuation.bracket + +[(true) (false)] @constant.builtin.boolean + +(enumerator name: (identifier) @type.enum.variant) + +(string_literal) @string +(system_lib_string) @string + +(null) @constant +(number_literal) @constant.numeric +(char_literal) @constant.character + +(call_expression + function: (identifier) @function) +(call_expression + function: (field_expression + field: (field_identifier) @function)) +(call_expression (argument_list (identifier) @variable)) +(function_declarator + declarator: [(identifier) (field_identifier)] @function) +(parameter_declaration + declarator: (identifier) @variable.parameter) +(parameter_declaration + (pointer_declarator + declarator: (identifier) @variable.parameter)) +(preproc_function_def + name: (identifier) @function.special) + +(attribute + name: (identifier) @attribute) + +(field_identifier) @variable.other.member +(statement_identifier) @label +(type_identifier) @type +(scalar_type) @type.builtin +(sized_type_specifier) @type.builtin +(vector_type) @type.builtin +(other_builtin_type) @type.builtin + +((identifier) @constant + (#match? @constant "^[A-Z][A-Z\\d_]*$")) + +(identifier) @variable + +(comment) @comment diff --git a/runtime/queries/opencl/indents.scm b/runtime/queries/opencl/indents.scm new file mode 100644 index 000000000..a5a5208ca --- /dev/null +++ b/runtime/queries/opencl/indents.scm @@ -0,0 +1 @@ +; inherits: c diff --git a/runtime/queries/opencl/injections.scm b/runtime/queries/opencl/injections.scm new file mode 100644 index 000000000..a5a5208ca --- /dev/null +++ b/runtime/queries/opencl/injections.scm @@ -0,0 +1 @@ +; inherits: c diff --git a/runtime/queries/opencl/textobjects.scm b/runtime/queries/opencl/textobjects.scm new file mode 100644 index 000000000..a5a5208ca --- /dev/null +++ b/runtime/queries/opencl/textobjects.scm @@ -0,0 +1 @@ +; inherits: c From 161fef2166e851071176e2fdaa9455efb5af0a6d Mon Sep 17 00:00:00 2001 From: Michael <20937441+KMikeeU@users.noreply.github.com> Date: Wed, 12 Apr 2023 22:28:51 +0200 Subject: [PATCH 101/260] Add DTD language support (#6644) - Added syntax highlighting for the DTD subset of the XML spec. - Included .dtd and .ent as common file extensions --- book/src/generated/lang-support.md | 1 + languages.toml | 20 +++++++++++++++ runtime/queries/dtd/highlights.scm | 39 ++++++++++++++++++++++++++++++ runtime/queries/dtd/injections.scm | 2 ++ 4 files changed, 62 insertions(+) create mode 100644 runtime/queries/dtd/highlights.scm create mode 100644 runtime/queries/dtd/injections.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index b458bd6f1..e434961bd 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -28,6 +28,7 @@ | diff | ✓ | | | | | dockerfile | ✓ | | | `docker-langserver` | | dot | ✓ | | | `dot-language-server` | +| dtd | ✓ | | | | | edoc | ✓ | | | | | eex | ✓ | | | | | ejs | ✓ | | | | diff --git a/languages.toml b/languages.toml index 866881370..c497e2964 100644 --- a/languages.toml +++ b/languages.toml @@ -2099,6 +2099,26 @@ roots = [] name = "xml" source = { git = "https://github.com/RenjiSann/tree-sitter-xml", rev = "48a7c2b6fb9d515577e115e6788937e837815651" } + +[[language]] +name = "dtd" +scope = "source.dtd" +injection-regex = "dtd" +file-types = ["dtd", "ent"] +indent = {tab-width = 2, unit = " "} +roots = [] + +[language.auto-pairs] +'(' = ')' +'[' = ']' +'"' = '"' +"'" = "'" +'<' = '>' + +[[grammar]] +name = "dtd" +source = { git = "https://github.com/KMikeeU/tree-sitter-dtd", rev = "6116becb02a6b8e9588ef73d300a9ba4622e156f"} + [[language]] name = "wit" scope = "source.wit" diff --git a/runtime/queries/dtd/highlights.scm b/runtime/queries/dtd/highlights.scm new file mode 100644 index 000000000..cb3d482b5 --- /dev/null +++ b/runtime/queries/dtd/highlights.scm @@ -0,0 +1,39 @@ +; highlights.scm + +(comment) @comment + +[ + "ELEMENT" + "ATTLIST" +] @keyword + +[ + "#REQUIRED" + "#IMPLIED" + "#FIXED" + "#PCDATA" +] @keyword.directive + +[ + "EMPTY" + "ANY" + "SYSTEM" + "PUBLIC" +] @constant + +(element_name) @module + + +(attribute_name) @attribute + +(system_literal) @string +(pubid_literal) @string +(attribute_value) @string + +[ + ">" + "" + " Date: Thu, 13 Apr 2023 01:43:34 +0200 Subject: [PATCH 102/260] Fix #6669: Theme preview doesn't return theme to normal (#6694) * Fix #6669: Theme preview doesn't return theme to normal when delete name with Alt-Backspace * Fix #6669: Return theme preview to normal theme for all remaining keybinds that change the promt text --- helix-term/src/ui/prompt.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 35ae8c2a8..a9ccfb737 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -511,11 +511,21 @@ impl Component for Prompt { ctrl!('e') | key!(End) => self.move_end(), ctrl!('a') | key!(Home) => self.move_start(), ctrl!('w') | alt!(Backspace) | ctrl!(Backspace) => { - self.delete_word_backwards(cx.editor) + self.delete_word_backwards(cx.editor); + (self.callback_fn)(cx, &self.line, PromptEvent::Update); + } + alt!('d') | alt!(Delete) | ctrl!(Delete) => { + self.delete_word_forwards(cx.editor); + (self.callback_fn)(cx, &self.line, PromptEvent::Update); + } + ctrl!('k') => { + self.kill_to_end_of_line(cx.editor); + (self.callback_fn)(cx, &self.line, PromptEvent::Update); + } + ctrl!('u') => { + self.kill_to_start_of_line(cx.editor); + (self.callback_fn)(cx, &self.line, PromptEvent::Update); } - alt!('d') | alt!(Delete) | ctrl!(Delete) => self.delete_word_forwards(cx.editor), - ctrl!('k') => self.kill_to_end_of_line(cx.editor), - ctrl!('u') => self.kill_to_start_of_line(cx.editor), ctrl!('h') | key!(Backspace) | shift!(Backspace) => { self.delete_char_backwards(cx.editor); (self.callback_fn)(cx, &self.line, PromptEvent::Update); From bff7fc8695f1d58b918f94dee7638f8a4a1e4b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Gonz=C3=A1lez?= Date: Wed, 12 Apr 2023 21:27:12 -0400 Subject: [PATCH 103/260] Add inlay hints styling to darcula theme (#6732) * Add inlay hints coloring for darcula theme * Add whitespace --------- Co-authored-by: Ivan Tham --- runtime/themes/darcula.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/themes/darcula.toml b/runtime/themes/darcula.toml index 2779a9440..53a271bd2 100644 --- a/runtime/themes/darcula.toml +++ b/runtime/themes/darcula.toml @@ -23,6 +23,7 @@ "ui.virtual.ruler" = { bg = "grey02" } "ui.virtual.indent-guide" = "grey02" "ui.virtual.whitespace" = "grey03" +"ui.virtual.inlay-hint" = { fg = "grey03", modifiers = ["italic"] } "ui.bufferline" = { fg = "grey04", bg = "grey00" } "ui.bufferline.active" = { fg = "grey07", bg = "grey02" } From 5ec41195a0dde08c559f9f1b95c0ff4054dfa2ba Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Thu, 13 Apr 2023 20:37:33 +0200 Subject: [PATCH 104/260] ensure :toggle soft-wrap.enable works by default (#6742) --- 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 80c47ed08..52f86f2da 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -749,7 +749,10 @@ impl Default for Config { bufferline: BufferLine::default(), indent_guides: IndentGuidesConfig::default(), color_modes: false, - soft_wrap: SoftWrap::default(), + soft_wrap: SoftWrap { + enable: Some(false), + ..SoftWrap::default() + }, text_width: 80, completion_replace: false, workspace_lsp_roots: Vec::new(), From bb275421997b9e2bd63b04227b7e345a193818d5 Mon Sep 17 00:00:00 2001 From: Farzin Date: Fri, 14 Apr 2023 04:04:40 +0330 Subject: [PATCH 105/260] Fix python highlights to support single character and alphanumeric constant identifier (#6751) --- runtime/queries/python/highlights.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/queries/python/highlights.scm b/runtime/queries/python/highlights.scm index 70b91efbe..0c6a83c54 100644 --- a/runtime/queries/python/highlights.scm +++ b/runtime/queries/python/highlights.scm @@ -94,7 +94,7 @@ ; Variables ((identifier) @constant - (#match? @constant "^[A-Z_]{2,}$")) + (#match? @constant "^_*[A-Z][A-Z\\d_]*$")) ((identifier) @type (#match? @type "^[A-Z]")) From cd7ef578187cdd56764e6a439aadfdefcd8f80b3 Mon Sep 17 00:00:00 2001 From: zetashift Date: Fri, 14 Apr 2023 16:08:11 +0200 Subject: [PATCH 106/260] Change smithy language server to the one from AWS (#6572) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index c497e2964..575ed82df 100644 --- a/languages.toml +++ b/languages.toml @@ -2399,7 +2399,7 @@ file-types = ["smithy"] roots = ["smithy-build.json"] comment-token = "//" indent = { tab-width = 4, unit = " " } -language-server = { command = "cs", args = ["launch", "com.disneystreaming.smithy:smithy-language-server:latest.release", "--", "0"] } +language-server = { command = "cs", args = ["launch", "--contrib", "smithy-language-server", "--", "0"] } [[grammar]] name = "smithy" From 78e8066c3e2e53711473ec5f11b0808ca7a94994 Mon Sep 17 00:00:00 2001 From: John Careaga Date: Fri, 14 Apr 2023 08:57:59 -0400 Subject: [PATCH 107/260] Replace 'Visual' (mode) with 'Select' in tutor --- runtime/tutor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tutor b/runtime/tutor index a6682ed92..df4d6d541 100644 --- a/runtime/tutor +++ b/runtime/tutor @@ -994,7 +994,7 @@ lines. * Type * to set the search register to the primary selection. - * Type n / N in Visual mode to add selections on each search + * Type n / N in Select mode to add selections on each search match. * Press Ctrl-s to save position to the jumplist. From 896404c7ead29c4c19564581ccb53b913440a583 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Fri, 14 Apr 2023 16:59:52 +0200 Subject: [PATCH 108/260] emit cargo metadata duiring build scripts to avoid outdated buildscript outputs (#6743) * rebuild on revision change * rerun grammar build if grammars change --- helix-loader/build.rs | 39 ++++++++++++++++++++++++++++++++++++- helix-loader/src/grammar.rs | 12 ++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/helix-loader/build.rs b/helix-loader/build.rs index c4b89e6b9..63548a0c8 100644 --- a/helix-loader/build.rs +++ b/helix-loader/build.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::path::Path; use std::process::Command; const VERSION: &str = include_str!("../VERSION"); @@ -11,7 +12,7 @@ fn main() { .filter(|output| output.status.success()) .and_then(|x| String::from_utf8(x.stdout).ok()); - let version: Cow<_> = match git_hash { + let version: Cow<_> = match &git_hash { Some(git_hash) => format!("{} ({})", VERSION, &git_hash[..8]).into(), None => VERSION.into(), }; @@ -23,4 +24,40 @@ fn main() { println!("cargo:rerun-if-changed=../VERSION"); println!("cargo:rustc-env=VERSION_AND_GIT_HASH={}", version); + + if git_hash.is_none() { + return; + } + + // we need to revparse because the git dir could be anywhere if you are + // using detached worktrees but there is no good way to obtain an OsString + // from command output so for now we can't accept non-utf8 paths here + // probably rare enouch where it doesn't matter tough we could use gitoxide + // here but that would be make it a hard dependency and slow compile times + let Some(git_dir): Option = Command::new("git") + .args(["rev-parse", "--git-dir"]) + .output() + .ok() + .filter(|output| output.status.success()) + .and_then(|x| String::from_utf8(x.stdout).ok()) + else{ return; }; + // If heads starts pointing at something else (different branch) + // we need to return + let head = Path::new(&git_dir).join("HEAD"); + if head.exists() { + println!("cargo:rerun-if-changed={}", head.display()); + } + // if the thing head points to (branch) itself changes + // we need to return + let Some(head_ref): Option = Command::new("git") + .args(["symbolic-ref", "HEAD"]) + .output() + .ok() + .filter(|output| output.status.success()) + .and_then(|x| String::from_utf8(x.stdout).ok()) + else{ return; }; + let head_ref = Path::new(&git_dir).join(head_ref); + if head_ref.exists() { + println!("cargo:rerun-if-changed={}", head_ref.display()); + } } diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index a85cb274c..2eb59a38e 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -413,6 +413,18 @@ fn build_tree_sitter_library( let mut library_path = parser_lib_path.join(&grammar.grammar_id); library_path.set_extension(DYLIB_EXTENSION); + // if we are running inside a buildscript emit cargo metadata + // to detect if we are running from a buildscript check some env variables + // that cargo only sets for build scripts + if std::env::var("OUT_DIR").is_ok() && std::env::var("CARGO").is_ok() { + if let Some(scanner_path) = scanner_path.as_ref().and_then(|path| path.to_str()) { + println!("cargo:rerun-if-changed={scanner_path}"); + } + if let Some(parser_path) = parser_path.to_str() { + println!("cargo:rerun-if-changed={parser_path}"); + } + } + let recompile = needs_recompile(&library_path, &parser_path, &scanner_path) .context("Failed to compare source and binary timestamps")?; From 4cdba7cccdd6a9fe5fbb3d15c9db3edc147b7a90 Mon Sep 17 00:00:00 2001 From: VuiMuich Date: Fri, 14 Apr 2023 17:03:21 +0200 Subject: [PATCH 109/260] Add standalone language support for `just` (#6453) Co-authored-by: Michael Davis --- book/src/generated/lang-support.md | 1 + languages.toml | 17 ++++++++-- runtime/queries/just/folds.scm | 4 +++ runtime/queries/just/highlights.scm | 33 +++++++++++++++++++ runtime/queries/just/indents.scm | 3 ++ runtime/queries/just/injections.scm | 16 ++++++++++ runtime/queries/just/locals.scm | 10 ++++++ runtime/queries/just/textobjects.scm | 48 ++++++++++++++++++++++++++++ 8 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 runtime/queries/just/folds.scm create mode 100644 runtime/queries/just/highlights.scm create mode 100644 runtime/queries/just/indents.scm create mode 100644 runtime/queries/just/injections.scm create mode 100644 runtime/queries/just/locals.scm create mode 100644 runtime/queries/just/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index e434961bd..331d212f5 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -72,6 +72,7 @@ | jsonnet | ✓ | | | `jsonnet-language-server` | | jsx | ✓ | ✓ | ✓ | `typescript-language-server` | | julia | ✓ | ✓ | ✓ | `julia` | +| just | ✓ | ✓ | ✓ | | | kdl | ✓ | | | | | kotlin | ✓ | | | `kotlin-language-server` | | latex | ✓ | ✓ | | `texlab` | diff --git a/languages.toml b/languages.toml index 575ed82df..8a0aa6612 100644 --- a/languages.toml +++ b/languages.toml @@ -978,8 +978,8 @@ source = { git = "https://github.com/uyha/tree-sitter-cmake", rev = "6e51463ef30 [[language]] name = "make" scope = "source.make" -file-types = ["Makefile", "makefile", "mk", "Justfile", "justfile", ".justfile"] -injection-regex = "(make|makefile|Makefile|mk|just)" +file-types = ["Makefile", "makefile", "mk"] +injection-regex = "(make|makefile|Makefile|mk)" roots = [] comment-token = "#" indent = { tab-width = 4, unit = "\t" } @@ -2505,3 +2505,16 @@ language-server = { command = "clangd" } [[grammar]] name = "opencl" source = { git = "https://github.com/lefp/tree-sitter-opencl", rev = "8e1d24a57066b3cd1bb9685bbc1ca9de5c1b78fb" } + +[[language]] +name = "just" +scope = "source.just" +file-types = ["justfile", "Justfile", "just"] +injection-regex = "just" +roots = [] +comment-token = "#" +indent = { tab-width = 4, unit = "\t" } + +[[grammar]] +name = "just" +source = { git = "https://github.com/IndianBoy42/tree-sitter-just", rev = "8af0aab79854aaf25b620a52c39485849922f766" } diff --git a/runtime/queries/just/folds.scm b/runtime/queries/just/folds.scm new file mode 100644 index 000000000..6fc68fbd4 --- /dev/null +++ b/runtime/queries/just/folds.scm @@ -0,0 +1,4 @@ +(body) @fold +(recipe) @fold +(interpolation) @fold +(item (_) @fold) diff --git a/runtime/queries/just/highlights.scm b/runtime/queries/just/highlights.scm new file mode 100644 index 000000000..1026f654f --- /dev/null +++ b/runtime/queries/just/highlights.scm @@ -0,0 +1,33 @@ +(assignment (NAME) @variable) +(alias (NAME) @variable) +(value (NAME) @variable) +(parameter (NAME) @variable) +(setting (NAME) @keyword) +(setting "shell" @keyword) + +(call (NAME) @function) +(dependency (NAME) @function) +(depcall (NAME) @function) +(recipeheader (NAME) @function) + +(depcall (expression) @variable.parameter) +(parameter) @variable.parameter +(variadic_parameters) @variable.parameter + +["if" "else"] @keyword.control.conditional + +(string) @string + +(boolean ["true" "false"]) @constant.builtin.boolean + +(comment) @comment + +; (interpolation) @string + +(shebang interpreter:(TEXT) @keyword ) @comment + +["export" "alias" "set"] @keyword + +["@" "==" "!=" "+" ":="] @operator + +[ "(" ")" "[" "]" "{{" "}}" "{" "}"] @punctuation.bracket diff --git a/runtime/queries/just/indents.scm b/runtime/queries/just/indents.scm new file mode 100644 index 000000000..3db597466 --- /dev/null +++ b/runtime/queries/just/indents.scm @@ -0,0 +1,3 @@ +[ + (recipe_body) +] @indent diff --git a/runtime/queries/just/injections.scm b/runtime/queries/just/injections.scm new file mode 100644 index 000000000..cae1035ae --- /dev/null +++ b/runtime/queries/just/injections.scm @@ -0,0 +1,16 @@ +((comment) @injection.content + (#set! injection.language "comment")) + +(shebang_recipe + (shebang + interpreter:(TEXT) @injection.language) + (shebang_body) @injection.content +) + +(source_file + (item (setting lang:(NAME) @injection.language)) + (item (recipe (body (recipe_body) @injection.content))) +) + +; ((interpolation (expression) @injection.content) +; (#set! injection.language "just")) diff --git a/runtime/queries/just/locals.scm b/runtime/queries/just/locals.scm new file mode 100644 index 000000000..18e162a97 --- /dev/null +++ b/runtime/queries/just/locals.scm @@ -0,0 +1,10 @@ +(assignment (NAME) @local.definition) +(alias left:(NAME) @local.definition) +(alias right:(NAME) @local.reference) +(value (NAME) @local.reference) +(parameter (NAME) @local.definition) + +(call (NAME) @local.reference) +(dependency (NAME) @local.reference) +(depcall (NAME) @local.reference) +(recipeheader (NAME) @local.definition) diff --git a/runtime/queries/just/textobjects.scm b/runtime/queries/just/textobjects.scm new file mode 100644 index 000000000..4be379587 --- /dev/null +++ b/runtime/queries/just/textobjects.scm @@ -0,0 +1,48 @@ +(body) @function.inside +(recipe) @function.around +(expression + if:(expression) @function.inside +) +(expression + else:(expression) @function.inside +) +(interpolation (expression) @function.inside) @function.around +(settinglist (stringlist) @function.inside) @function.around + +(call (NAME) @class.inside) @class.around +(dependency (NAME) @class.inside) @class.around +(depcall (NAME) @class.inside) + +(dependency) @parameter.around +(depcall) @parameter.inside +(depcall (expression) @parameter.inside) + +(stringlist + (string) @parameter.inside + . ","? @_end + ; Commented out since we don't support `#make-range!` at the moment + ; (#make-range! "parameter.around" @parameter.inside @_end) +) +(parameters + [(parameter) + (variadic_parameters)] @parameter.inside + . " "? @_end + ; Commented out since we don't support `#make-range!` at the moment + ; (#make-range! "parameter.around" @parameter.inside @_end) +) + +(expression + (condition) @function.inside +) @function.around +(expression + if:(expression) @function.inside +) +(expression + else:(expression) @function.inside +) + +(item [(alias) (assignment) (export) (setting)]) @class.around +(recipeheader) @class.around +(line) @class.around + +(comment) @comment.around From 99a8b6159cef76acb0bb0a9a872a36155e8cf6cd Mon Sep 17 00:00:00 2001 From: Matthew Toohey Date: Sat, 15 Apr 2023 00:53:04 -0400 Subject: [PATCH 110/260] Fix go locals query for var_spec identifiers --- runtime/queries/go/locals.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/queries/go/locals.scm b/runtime/queries/go/locals.scm index d240e2b78..aae562571 100644 --- a/runtime/queries/go/locals.scm +++ b/runtime/queries/go/locals.scm @@ -12,7 +12,7 @@ (identifier) @local.definition)) (var_spec - name: (identifier) @local.definition) + (identifier) @local.definition) (for_statement (range_clause From 523e9e457305d055cdbca1b21dab089002c93ffc Mon Sep 17 00:00:00 2001 From: dylrich Date: Sun, 16 Apr 2023 10:05:25 -0500 Subject: [PATCH 111/260] ferra: fix ruler overriding foreground style Ferra's current ruler styling overrides the foreground style, which is an odd look only for characters in the ruler column. This commit removes the foreground styling for the ruler rule. This is more in line with what other themes do for the ruler. --- runtime/themes/ferra.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/ferra.toml b/runtime/themes/ferra.toml index da5339e2e..360ad02f6 100644 --- a/runtime/themes/ferra.toml +++ b/runtime/themes/ferra.toml @@ -52,7 +52,7 @@ "ui.selection.primary" = { bg = "ferra_night", fg = "ferra_umber" } "ui.virtual" = { fg = "ferra_bark" } "ui.virtual.whitespace" = { fg = "ferra_bark" } -"ui.virtual.ruler" = { fg = "ferra_night", bg = "ferra_ash" } +"ui.virtual.ruler" = { bg = "ferra_ash" } "ui.virtual.indent-guide" = { fg = "ferra_ash" } "ui.virtual.inlay-hint" = { fg = "ferra_bark" } From 7607727483dbc6461749e3c2d9b9305431eb8fb2 Mon Sep 17 00:00:00 2001 From: karei Date: Sun, 16 Apr 2023 13:54:34 +0300 Subject: [PATCH 112/260] Add `inlay-hint` colours to Kanagawa Makes the LSP hints more legible against the background colour and more in line with the normal colours in the theme. --- runtime/themes/kanagawa.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/themes/kanagawa.toml b/runtime/themes/kanagawa.toml index a7d33f3ee..d0576a4e3 100644 --- a/runtime/themes/kanagawa.toml +++ b/runtime/themes/kanagawa.toml @@ -16,6 +16,9 @@ "ui.virtual" = "sumiInk4" "ui.virtual.ruler" = { bg = "sumiInk2" } +"ui.virtual.inlay-hint" = "fujiGray" +"ui.virtual.inlay-hint.parameter" = { fg = "carpYellow", modifiers = ["dim"] } +"ui.virtual.inlay-hint.type" = { fg = "waveAqua2", modifiers = ["dim"] } "ui.statusline" = { fg = "oldWhite", bg = "sumiInk0" } "ui.statusline.inactive" = { fg = "fujiGray", bg = "sumiInk0" } From 7706ff77eb8aea9471af822355cad337707b9fc5 Mon Sep 17 00:00:00 2001 From: Aleksey Kuznetsov Date: Sun, 16 Apr 2023 23:44:12 +0500 Subject: [PATCH 113/260] make :toggle-option print the new value (#6774) Co-authored-by: Michael Davis --- helix-term/src/commands/typed.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 3c954d20f..eb5c156fb 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1770,12 +1770,12 @@ fn toggle_option( let pointer = format!("/{}", key.replace('.', "/")); let value = config.pointer_mut(&pointer).ok_or_else(key_error)?; - if let Value::Bool(b) = *value { - *value = Value::Bool(!b); - } else { + let Value::Bool(old_value) = *value else { anyhow::bail!("Key `{}` is not toggle-able", key) - } + }; + let new_value = !old_value; + *value = Value::Bool(new_value); // This unwrap should never fail because we only replace one boolean value // with another, maintaining a valid json config let config = serde_json::from_value(config).unwrap(); @@ -1784,6 +1784,8 @@ fn toggle_option( .config_events .0 .send(ConfigEvent::Update(config))?; + cx.editor + .set_status(format!("Option `{}` is now set to `{}`", key, new_value)); Ok(()) } From 1b016a89d546fb84d3c737d7c4bacb9e26c8b893 Mon Sep 17 00:00:00 2001 From: shem Date: Sun, 16 Apr 2023 23:07:00 +0200 Subject: [PATCH 114/260] Fix crash on opening from suspend state (#6764) * Fix crash on opening from suspend state (#6725) * Fix code style * revert using of the imperative code style. Add panic if couldn't set terminal raw mode * remove redundant import of core::panic macros * small refactoring --- helix-term/src/application.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 4d28c8bed..cda498e2f 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -471,7 +471,17 @@ impl Application { } } signal::SIGCONT => { - self.claim_term().await.unwrap(); + // Copy/Paste from same issue from neovim: + // https://github.com/neovim/neovim/issues/12322 + // https://github.com/neovim/neovim/pull/13084 + for retries in 1..=10 { + match self.claim_term().await { + Ok(()) => break, + Err(err) if retries == 10 => panic!("Failed to claim terminal: {}", err), + Err(_) => continue, + } + } + // redraw the terminal let area = self.terminal.size().expect("couldn't get terminal size"); self.compositor.resize(area); From 8839eb0af47b99511956d81a6dbb32e948d2076c Mon Sep 17 00:00:00 2001 From: A-Walrus <58790821+A-Walrus@users.noreply.github.com> Date: Mon, 17 Apr 2023 23:36:04 +0300 Subject: [PATCH 115/260] Fix unwrap bug in DAP (#6786) --- helix-dap/src/client.rs | 10 +++----- helix-dap/src/transport.rs | 46 +++++++++++++++++++++------------- helix-view/src/handlers/dap.rs | 1 + 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs index 7efb72d80..acdfc5b7e 100644 --- a/helix-dap/src/client.rs +++ b/helix-dap/src/client.rs @@ -62,12 +62,10 @@ impl Client { if command.is_empty() { return Result::Err(Error::Other(anyhow!("Command not provided"))); } - if transport == "tcp" && port_arg.is_some() { - Self::tcp_process(command, args, port_arg.unwrap(), id).await - } else if transport == "stdio" { - Self::stdio(command, args, id) - } else { - Result::Err(Error::Other(anyhow!("Incorrect transport {}", transport))) + match (transport, port_arg) { + ("tcp", Some(port_arg)) => Self::tcp_process(command, args, port_arg, id).await, + ("stdio", _) => Self::stdio(command, args, id), + _ => Result::Err(Error::Other(anyhow!("Incorrect transport {}", transport))), } } diff --git a/helix-dap/src/transport.rs b/helix-dap/src/transport.rs index dd03e5685..0f646b6a4 100644 --- a/helix-dap/src/transport.rs +++ b/helix-dap/src/transport.rs @@ -230,38 +230,48 @@ impl Transport { } } - async fn recv( + async fn recv_inner( transport: Arc, mut server_stdout: Box, client_tx: UnboundedSender, - ) { + ) -> Result<()> { let mut recv_buffer = String::new(); loop { - match Self::recv_server_message(&mut server_stdout, &mut recv_buffer).await { - Ok(msg) => { - transport - .process_server_message(&client_tx, msg) - .await - .unwrap(); - } - Err(err) => { - error!("err: <- {:?}", err); - break; - } - } + let msg = Self::recv_server_message(&mut server_stdout, &mut recv_buffer).await?; + transport.process_server_message(&client_tx, msg).await?; } } - async fn send( + async fn recv( + transport: Arc, + server_stdout: Box, + client_tx: UnboundedSender, + ) { + if let Err(err) = Self::recv_inner(transport, server_stdout, client_tx).await { + error!("err: <- {:?}", err); + } + } + + async fn send_inner( transport: Arc, mut server_stdin: Box, mut client_rx: UnboundedReceiver, - ) { + ) -> Result<()> { while let Some(payload) = client_rx.recv().await { transport .send_payload_to_server(&mut server_stdin, payload) - .await - .unwrap() + .await?; + } + Ok(()) + } + + async fn send( + transport: Arc, + server_stdin: Box, + client_rx: UnboundedReceiver, + ) { + if let Err(err) = Self::send_inner(transport, server_stdin, client_rx).await { + error!("err: <- {:?}", err); } } diff --git a/helix-view/src/handlers/dap.rs b/helix-view/src/handlers/dap.rs index 107c29be5..3da01494d 100644 --- a/helix-view/src/handlers/dap.rs +++ b/helix-view/src/handlers/dap.rs @@ -321,6 +321,7 @@ impl Editor { } } None => { + self.debugger = None; self.set_status( "Terminated debugging session and disconnected debugger.", ); From a333f6fed7d11c03f9277ea4fdf58617b8818ebc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:04:48 +0900 Subject: [PATCH 116/260] build(deps): bump etcetera from 0.4.0 to 0.5.0 (#6798) Bumps [etcetera](https://github.com/lunacookies/etcetera) from 0.4.0 to 0.5.0. - [Release notes](https://github.com/lunacookies/etcetera/releases) - [Commits](https://github.com/lunacookies/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 | 6 +++--- helix-core/Cargo.toml | 2 +- helix-loader/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 472b3152a..3cf7b7e94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -384,12 +384,12 @@ dependencies = [ [[package]] name = "etcetera" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d017fce18e4e9bfa75e1db51f49f4487bd3f8a7df509b24a46474a956ee962fd" +checksum = "870a9fdff9c99141df9277dece5ec8021434eca50f05cbac41a5eb07c9659e7d" dependencies = [ "cfg-if", - "dirs-next", + "home", "thiserror", ] diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 887a83cfc..99776694e 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -45,7 +45,7 @@ encoding_rs = "0.8" chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] } -etcetera = "0.4" +etcetera = "0.5" textwrap = "0.16.0" [dev-dependencies] diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index 9225ad1a2..4cc3e1866 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -17,7 +17,7 @@ path = "src/main.rs" anyhow = "1" serde = { version = "1.0", features = ["derive"] } toml = "0.7" -etcetera = "0.4" +etcetera = "0.5" tree-sitter = "0.20" once_cell = "1.17" log = "0.4" From 3f72792033e6a49880595172a5235bb55ca6805f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:05:03 +0900 Subject: [PATCH 117/260] build(deps): bump serde_json from 1.0.95 to 1.0.96 (#6799) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.95 to 1.0.96. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.95...v1.0.96) --- 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 3cf7b7e94..e13524ba2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1822,9 +1822,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", From 6f972e5da2de1d532fbcd0c9e8b0a6378fbb9c15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:05:31 +0900 Subject: [PATCH 118/260] build(deps): bump serde from 1.0.159 to 1.0.160 (#6800) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.159 to 1.0.160. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.159...v1.0.160) --- 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 e13524ba2..2c9b92271 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1802,18 +1802,18 @@ checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "serde" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", From 2ccb5b75d0a310b90b5cc453915281560ba1f220 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:06:08 +0900 Subject: [PATCH 119/260] build(deps): bump libloading from 0.7.4 to 0.8.0 (#6801) Bumps [libloading](https://github.com/nagisa/rust_libloading) from 0.7.4 to 0.8.0. - [Release notes](https://github.com/nagisa/rust_libloading/releases) - [Commits](https://github.com/nagisa/rust_libloading/compare/0.7.4...0.8.0) --- updated-dependencies: - dependency-name: libloading 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 | 88 +++++++++++++++++++++++++++++++++++------ helix-loader/Cargo.toml | 2 +- 2 files changed, 78 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c9b92271..470f41b44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -359,7 +359,7 @@ checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" dependencies = [ "errno-dragonfly", "libc", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -420,7 +420,7 @@ dependencies = [ "cfg-if", "libc", "redox_syscall 0.2.16", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1399,7 +1399,7 @@ checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1431,12 +1431,12 @@ checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb" dependencies = [ "cfg-if", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -1525,7 +1525,7 @@ dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1614,7 +1614,7 @@ dependencies = [ "libc", "redox_syscall 0.2.16", "smallvec", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1770,7 +1770,7 @@ dependencies = [ "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -2000,7 +2000,7 @@ dependencies = [ "fastrand", "redox_syscall 0.3.5", "rustix", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -2131,7 +2131,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -2427,6 +2427,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -2457,6 +2466,21 @@ dependencies = [ "windows_x86_64_msvc 0.47.0", ] +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -2469,6 +2493,12 @@ version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "831d567d53d4f3cb1db332b68e6e2b6260228eb4d99a777d8b2e8ed794027c90" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -2481,6 +2511,12 @@ version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a42d54a417c60ce4f0e31661eed628f0fa5aca73448c093ec4d45fab4c51cdf" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -2493,6 +2529,12 @@ version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1925beafdbb22201a53a483db861a5644123157c1c3cee83323a2ed565d71e3" +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -2505,6 +2547,12 @@ version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a8ef8f2f1711b223947d9b69b596cf5a4e452c930fb58b6fc3fdae7d0ec6b31" +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -2517,6 +2565,12 @@ version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7acaa0c2cf0d2ef99b61c308a0c3dbae430a51b7345dedec470bd8f53f5a3642" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -2529,6 +2583,12 @@ version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5a0628f71be1d11e17ca4a0e9e15b3a5180f6fbf1c2d55e3ba3f850378052c1" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -2541,6 +2601,12 @@ version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d6e62c256dc6d40b8c8707df17df8d774e60e39db723675241e7c15e910bce7" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + [[package]] name = "winnow" version = "0.4.1" diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index 4cc3e1866..31cfbf62d 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -29,4 +29,4 @@ cc = { version = "1" } threadpool = { version = "1.0" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -libloading = "0.7" +libloading = "0.8" From ca65d312e715413cd5675cafd599d74534900d3f Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Tue, 18 Apr 2023 03:10:19 +0200 Subject: [PATCH 120/260] always build grammars with c++14 and c11 (#6792) --- Cargo.lock | 1 + helix-loader/Cargo.toml | 1 + helix-loader/src/grammar.rs | 48 +++++++++++++++++++++++++++++++------ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 470f41b44..38b10fce4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1134,6 +1134,7 @@ dependencies = [ "log", "once_cell", "serde", + "tempfile", "threadpool", "toml", "tree-sitter", diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index 31cfbf62d..60b1e911b 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -27,6 +27,7 @@ log = "0.4" # cloning/compiling tree-sitter grammars cc = { version = "1" } threadpool = { version = "1.0" } +tempfile = "3.5.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] libloading = "0.8" diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index 2eb59a38e..3697ec7e1 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -8,6 +8,7 @@ use std::{ process::Command, sync::mpsc::channel, }; +use tempfile::TempPath; use tree_sitter::Language; #[cfg(unix)] @@ -446,13 +447,17 @@ fn build_tree_sitter_library( command.env(key, value); } command.args(compiler.args()); + // used to delay dropping the temporary object file until after the compilation is complete + let _path_guard; if cfg!(all(windows, target_env = "msvc")) { command .args(["/nologo", "/LD", "/I"]) .arg(header_path) .arg("/Od") - .arg("/utf-8"); + .arg("/utf-8") + .arg("/std:c++14") + .arg("/std:c11"); if let Some(scanner_path) = scanner_path.as_ref() { command.arg(scanner_path); } @@ -466,20 +471,49 @@ fn build_tree_sitter_library( .arg("-shared") .arg("-fPIC") .arg("-fno-exceptions") - .arg("-g") .arg("-I") .arg(header_path) .arg("-o") - .arg(&library_path) - .arg("-O3"); + .arg(&library_path); + if let Some(scanner_path) = scanner_path.as_ref() { if scanner_path.extension() == Some("c".as_ref()) { - command.arg("-xc").arg("-std=c99").arg(scanner_path); + command.arg("-xc").arg("-std=c11").arg(scanner_path); } else { - command.arg(scanner_path); + let mut cpp_command = Command::new(compiler.path()); + cpp_command.current_dir(src_path); + for (key, value) in compiler.env() { + cpp_command.env(key, value); + } + cpp_command.args(compiler.args()); + let object_file = + library_path.with_file_name(format!("{}_scanner.o", &grammar.grammar_id)); + cpp_command + .arg("-fPIC") + .arg("-fno-exceptions") + .arg("-I") + .arg(header_path) + .arg("-o") + .arg(&object_file) + .arg("-std=c++14") + .arg("-c") + .arg(scanner_path); + let output = cpp_command + .output() + .context("Failed to execute C++ compiler")?; + if !output.status.success() { + return Err(anyhow!( + "Parser compilation failed.\nStdout: {}\nStderr: {}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + )); + } + + command.arg(&object_file); + _path_guard = TempPath::from_path(object_file); } } - command.arg("-xc").arg(parser_path); + command.arg("-xc").arg("-std=c11").arg(parser_path); if cfg!(all( unix, not(any(target_os = "macos", target_os = "illumos")) From 4f03c03556aacc43306152d43aa815b2527a630f Mon Sep 17 00:00:00 2001 From: Lakshya Singh Date: Wed, 19 Apr 2023 04:51:15 +0530 Subject: [PATCH 121/260] update tree-sitter-markdown (#6785) * chore: fix bump tree-sitter-markdown Signed-off-by: Lakshya Singh * chore: bump markdown_inline to latest rev Signed-off-by: Lakshya Singh --------- Signed-off-by: Lakshya Singh --- languages.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/languages.toml b/languages.toml index 8a0aa6612..dc4d10238 100644 --- a/languages.toml +++ b/languages.toml @@ -1126,7 +1126,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "markdown" -source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "7e7aa9a25ca9729db9fe22912f8f47bdb403a979", subpath = "tree-sitter-markdown" } +source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "fa6bfd51727e4bef99f7eec5f43947f73d64ea7d", subpath = "tree-sitter-markdown" } [[language]] name = "markdown.inline" @@ -1138,7 +1138,7 @@ grammar = "markdown_inline" [[grammar]] name = "markdown_inline" -source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "7e7aa9a25ca9729db9fe22912f8f47bdb403a979", subpath = "tree-sitter-markdown-inline" } +source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "fa6bfd51727e4bef99f7eec5f43947f73d64ea7d", subpath = "tree-sitter-markdown-inline" } [[language]] name = "dart" From 83c307a66a05644c95c3864b3a79293d92f0b176 Mon Sep 17 00:00:00 2001 From: David Else <12832280+David-Else@users.noreply.github.com> Date: Wed, 19 Apr 2023 22:56:18 +0000 Subject: [PATCH 122/260] Improve and update the installation documentation (#6809) --- book/src/install.md | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/book/src/install.md b/book/src/install.md index 5f1651ae9..169e6e0b6 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -41,8 +41,6 @@ line. ## Linux, macOS, Windows and OpenBSD packaging status -Helix is available for Linux, macOS and Windows via the official repositories listed below. - [![Packaging status](https://repology.org/badge/vertical-allrepos/helix.svg)](https://repology.org/project/helix/versions) ## Linux @@ -51,7 +49,7 @@ The following third party repositories are available: ### Ubuntu -Helix is available via [Maveonair's PPA](https://launchpad.net/~maveonair/+archive/ubuntu/helix-editor): +Add the `PPA` for Helix: ```sh sudo add-apt-repository ppa:maveonair/helix-editor @@ -61,7 +59,7 @@ sudo apt install helix ### Fedora/RHEL -Helix is available via `copr`: +Enable the `COPR` repository for Helix: ```sh sudo dnf copr enable varlad/helix @@ -92,8 +90,8 @@ If you are using a version of Nix without flakes enabled, ### AppImage -Install Helix using [AppImage](https://appimage.org/). -Download Helix AppImage from the [latest releases](https://github.com/helix-editor/helix/releases/latest) page. +Install Helix using the Linux [AppImage](https://appimage.org/) format. +Download the official Helix AppImage from the [latest releases](https://github.com/helix-editor/helix/releases/latest) page. ```sh chmod +x helix-*.AppImage # change permission for executable mode @@ -143,33 +141,37 @@ pacman -S mingw-w64-ucrt-x86_64-helix ## Building from source -Clone the repository: +Requirements: + +- The [Rust toolchain](https://www.rust-lang.org/tools/install) +- The [Git version control system](https://git-scm.com/) +- A c++14 compatible compiler to build the tree-sitter grammars, for example GCC or Clang + +If you are using the `musl-libc` standard library instead of `glibc` the following environment variable must be set during the build to ensure tree-sitter grammars can be loaded correctly: + +```sh +RUSTFLAGS="-C target-feature=-crt-static" +``` + +1. Clone the repository: ```sh git clone https://github.com/helix-editor/helix cd helix ``` -Compile from source: +2. Compile from source: ```sh cargo install --path helix-term --locked ``` This command will create the `hx` executable and construct the tree-sitter -grammars in the local `runtime` folder. To build the tree-sitter grammars requires -a c++ compiler to be installed, for example `gcc-c++`. - -> 💡 If you are using the musl-libc instead of glibc the following environment variable must be set during the build -> to ensure tree-sitter grammars can be loaded correctly: -> -> ```sh -> RUSTFLAGS="-C target-feature=-crt-static" -> ``` +grammars in the local `runtime` folder. > 💡 Tree-sitter grammars can 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). This will install them in +> grammars with `hx --grammar fetch` and compile them with +> `hx --grammar build`. This will install them in > the `runtime` directory within the user's helix config directory (more > [details below](#multiple-runtime-directories)). From f5d38cee17e78bf82eb2d0b3070aa9cd52c0a741 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Thu, 20 Apr 2023 07:53:16 +0200 Subject: [PATCH 123/260] produce error when grammar build fails (#6795) * produce error when grammar build fails * print which grammar build failed --- helix-loader/src/grammar.rs | 59 ++++++++++++++----------------------- 1 file changed, 22 insertions(+), 37 deletions(-) diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index 3697ec7e1..a5dcc4c8a 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use serde::{Deserialize, Serialize}; use std::fs; use std::time::SystemTime; @@ -98,15 +98,12 @@ pub fn fetch_grammars() -> Result<()> { let mut git_up_to_date = 0; let mut non_git = Vec::new(); - for res in results { + for (grammar_id, res) in results { match res { Ok(FetchStatus::GitUpToDate) => git_up_to_date += 1, - Ok(FetchStatus::GitUpdated { - grammar_id, - revision, - }) => git_updated.push((grammar_id, revision)), - Ok(FetchStatus::NonGit { grammar_id }) => non_git.push(grammar_id), - Err(e) => errors.push(e), + Ok(FetchStatus::GitUpdated { revision }) => git_updated.push((grammar_id, revision)), + Ok(FetchStatus::NonGit) => non_git.push(grammar_id), + Err(e) => errors.push((grammar_id, e)), } } @@ -138,10 +135,10 @@ pub fn fetch_grammars() -> Result<()> { if !errors.is_empty() { let len = errors.len(); - println!("{} grammars failed to fetch", len); - for (i, error) in errors.into_iter().enumerate() { - println!("\tFailure {}/{}: {}", i + 1, len, error); + for (i, (grammar, error)) in errors.into_iter().enumerate() { + println!("Failure {}/{len}: {grammar} {error}", i + 1); } + bail!("{len} grammars failed to fetch"); } Ok(()) @@ -158,11 +155,11 @@ pub fn build_grammars(target: Option) -> Result<()> { let mut already_built = 0; let mut built = Vec::new(); - for res in results { + for (grammar_id, res) in results { match res { Ok(BuildStatus::AlreadyBuilt) => already_built += 1, - Ok(BuildStatus::Built { grammar_id }) => built.push(grammar_id), - Err(e) => errors.push(e), + Ok(BuildStatus::Built) => built.push(grammar_id), + Err(e) => errors.push((grammar_id, e)), } } @@ -179,10 +176,10 @@ pub fn build_grammars(target: Option) -> Result<()> { if !errors.is_empty() { let len = errors.len(); - println!("{} grammars failed to build", len); - for (i, error) in errors.into_iter().enumerate() { - println!("\tFailure {}/{}: {}", i, len, error); + for (i, (grammar_id, error)) in errors.into_iter().enumerate() { + println!("Failure {}/{len}: {grammar_id} {error}", i + 1); } + bail!("{len} grammars failed to build"); } Ok(()) @@ -214,7 +211,7 @@ fn get_grammar_configs() -> Result> { Ok(grammars) } -fn run_parallel(grammars: Vec, job: F) -> Vec> +fn run_parallel(grammars: Vec, job: F) -> Vec<(String, Result)> where F: Fn(GrammarConfiguration) -> Result + Send + 'static + Clone, Res: Send + 'static, @@ -229,7 +226,7 @@ where pool.execute(move || { // 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)); + let _ = tx.send((grammar.grammar_id.clone(), job(grammar))); }); } @@ -240,13 +237,8 @@ where enum FetchStatus { GitUpToDate, - GitUpdated { - grammar_id: String, - revision: String, - }, - NonGit { - grammar_id: String, - }, + GitUpdated { revision: String }, + NonGit, } fn fetch_grammar(grammar: GrammarConfiguration) -> Result { @@ -287,17 +279,12 @@ fn fetch_grammar(grammar: GrammarConfiguration) -> Result { )?; git(&grammar_dir, ["checkout", &revision])?; - Ok(FetchStatus::GitUpdated { - grammar_id: grammar.grammar_id, - revision, - }) + Ok(FetchStatus::GitUpdated { revision }) } else { Ok(FetchStatus::GitUpToDate) } } else { - Ok(FetchStatus::NonGit { - grammar_id: grammar.grammar_id, - }) + Ok(FetchStatus::NonGit) } } @@ -347,7 +334,7 @@ where enum BuildStatus { AlreadyBuilt, - Built { grammar_id: String }, + Built, } fn build_grammar(grammar: GrammarConfiguration, target: Option<&str>) -> Result { @@ -533,9 +520,7 @@ fn build_tree_sitter_library( )); } - Ok(BuildStatus::Built { - grammar_id: grammar.grammar_id, - }) + Ok(BuildStatus::Built) } fn needs_recompile( From b336cd76a740eea6ea41baa1028233ccf6e12ee5 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Thu, 20 Apr 2023 07:53:38 +0200 Subject: [PATCH 124/260] update dependencies (#6808) --- Cargo.lock | 137 ++++++++++++++++------------------------------------- 1 file changed, 40 insertions(+), 97 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38b10fce4..f413bc41f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -197,9 +197,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "crc32fast" @@ -260,7 +260,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.11", + "syn 2.0.15", ] [[package]] @@ -277,7 +277,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.15", ] [[package]] @@ -353,13 +353,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -413,14 +413,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" +checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" dependencies = [ "cfg-if", "libc", "redox_syscall 0.2.16", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -495,9 +495,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if", "libc", @@ -721,9 +721,9 @@ dependencies = [ [[package]] name = "gix-hash" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0c5a9f4d621d4f4ea046bb331df5c746ca735b8cae5b234cc2be70ee4dbef0" +checksum = "2a258595457bc192d1f1c59d0d168a1e34e2be9b97a614e14995416185de41a7" dependencies = [ "hex", "thiserror", @@ -731,9 +731,9 @@ dependencies = [ [[package]] name = "gix-hashtable" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9609c1b8f36f12968e6a6098f7cdb52004f7d42d570f47a2d6d7c16612f19acb" +checksum = "e4e55e40dfd694884f0eb78796c5bddcf2f8b295dace47039099dd7e76534973" dependencies = [ "gix-hash", "hashbrown 0.13.2", @@ -912,9 +912,9 @@ dependencies = [ [[package]] name = "gix-revision" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b12fc4bbc3161a5b2d68079fce93432cef8771ff88ca017abb01187fddfc41a1" +checksum = "3c6f6ff53f888858afc24bf12628446a14279ceec148df6194481f306f553ad2" dependencies = [ "bstr", "gix-date", @@ -1298,16 +1298,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.55" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "716f12fbcfac6ffab0a5e9ec51d0a0ff70503742bb2dc7b99396394c9dc323f0" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows 0.47.0", + "windows 0.48.0", ] [[package]] @@ -1394,13 +1394,13 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1451,9 +1451,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd550e73688e6d578f0ac2119e32b797a327631a42f9433e59d02e139c8df60d" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" [[package]] name = "lock_api" @@ -1638,9 +1638,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.54" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -1762,16 +1762,16 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.5" +version = "0.37.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e78cc525325c06b4a7ff02db283472f3c042b7ff0c391f96c6d5ac6f4f91b75" +checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1818,7 +1818,7 @@ checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.15", ] [[package]] @@ -1840,7 +1840,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.15", ] [[package]] @@ -1982,9 +1982,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.11" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e3787bb71465627110e7d87ed4faaa36c1f61042ee67badb9e2ef173accc40" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ "proc-macro2", "quote", @@ -2050,7 +2050,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.15", ] [[package]] @@ -2143,7 +2143,7 @@ checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.15", ] [[package]] @@ -2412,11 +2412,11 @@ dependencies = [ [[package]] name = "windows" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2649ff315bee4c98757f15dac226efe3d81927adbb6e882084bb1ee3e0c330a7" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.47.0", + "windows-targets 0.48.0", ] [[package]] @@ -2452,21 +2452,6 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-targets" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f8996d3f43b4b2d44327cd71b7b0efd1284ab60e6e9d0e8b630e18555d87d3e" -dependencies = [ - "windows_aarch64_gnullvm 0.47.0", - "windows_aarch64_msvc 0.47.0", - "windows_i686_gnu 0.47.0", - "windows_i686_msvc 0.47.0", - "windows_x86_64_gnu 0.47.0", - "windows_x86_64_gnullvm 0.47.0", - "windows_x86_64_msvc 0.47.0", -] - [[package]] name = "windows-targets" version = "0.48.0" @@ -2488,12 +2473,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831d567d53d4f3cb1db332b68e6e2b6260228eb4d99a777d8b2e8ed794027c90" - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" @@ -2506,12 +2485,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" -[[package]] -name = "windows_aarch64_msvc" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a42d54a417c60ce4f0e31661eed628f0fa5aca73448c093ec4d45fab4c51cdf" - [[package]] name = "windows_aarch64_msvc" version = "0.48.0" @@ -2524,12 +2497,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" -[[package]] -name = "windows_i686_gnu" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1925beafdbb22201a53a483db861a5644123157c1c3cee83323a2ed565d71e3" - [[package]] name = "windows_i686_gnu" version = "0.48.0" @@ -2542,12 +2509,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" -[[package]] -name = "windows_i686_msvc" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8ef8f2f1711b223947d9b69b596cf5a4e452c930fb58b6fc3fdae7d0ec6b31" - [[package]] name = "windows_i686_msvc" version = "0.48.0" @@ -2560,12 +2521,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" -[[package]] -name = "windows_x86_64_gnu" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acaa0c2cf0d2ef99b61c308a0c3dbae430a51b7345dedec470bd8f53f5a3642" - [[package]] name = "windows_x86_64_gnu" version = "0.48.0" @@ -2578,12 +2533,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a0628f71be1d11e17ca4a0e9e15b3a5180f6fbf1c2d55e3ba3f850378052c1" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" @@ -2596,12 +2545,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" -[[package]] -name = "windows_x86_64_msvc" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6e62c256dc6d40b8c8707df17df8d774e60e39db723675241e7c15e910bce7" - [[package]] name = "windows_x86_64_msvc" version = "0.48.0" From 13cc44c65e5037141b52f4a1b5fc66d7db100d25 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Fri, 21 Apr 2023 05:49:27 +0200 Subject: [PATCH 125/260] fix windows build (#6834) --- helix-loader/src/grammar.rs | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index a5dcc4c8a..3dac237c8 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -443,10 +443,42 @@ fn build_tree_sitter_library( .arg(header_path) .arg("/Od") .arg("/utf-8") - .arg("/std:c++14") .arg("/std:c11"); if let Some(scanner_path) = scanner_path.as_ref() { - command.arg(scanner_path); + if scanner_path.extension() == Some("c".as_ref()) { + command.arg(scanner_path); + } else { + let mut cpp_command = Command::new(compiler.path()); + cpp_command.current_dir(src_path); + for (key, value) in compiler.env() { + cpp_command.env(key, value); + } + cpp_command.args(compiler.args()); + let object_file = + library_path.with_file_name(format!("{}_scanner.o", &grammar.grammar_id)); + cpp_command + .args(["/nologo", "/LD", "/I"]) + .arg(header_path) + .arg("/Od") + .arg("/utf-8") + .arg("/std:c++14") + .arg("/o") + .arg(&object_file) + .arg("/c") + .arg(scanner_path); + let output = cpp_command + .output() + .context("Failed to execute C++ compiler")?; + if !output.status.success() { + return Err(anyhow!( + "Parser compilation failed.\nStdout: {}\nStderr: {}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + )); + } + command.arg(&object_file); + _path_guard = TempPath::from_path(object_file); + } } command From c3e2db77f7d1d268856e0c3cba328e9fbd0cc71f Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Fri, 21 Apr 2023 05:50:37 +0200 Subject: [PATCH 126/260] flip symbol range in LSP goto commands (#6794) --- helix-term/src/commands/lsp.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 7a26b3cf6..be8ae02a6 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -205,7 +205,9 @@ fn jump_to_location( log::warn!("lsp position out of bounds - {:?}", location.range); return; }; - doc.set_selection(view.id, Selection::single(new_range.anchor, new_range.head)); + // 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(new_range.head, new_range.anchor)); align_view(doc, view, Align::Center); } From 5aedf11493d83c97cd2cad1d1ac0488b9d1f5f36 Mon Sep 17 00:00:00 2001 From: Ollie Charles Date: Fri, 21 Apr 2023 04:51:17 +0100 Subject: [PATCH 127/260] Replace `*.cabal` in Haskell `roots` with `cabal.project` (#6828) `roots` doesn't support wildcards. As such this root is dropped, and `cabal.project` is added, which is probably the best we can do for Cabal-based projects for now. --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index dc4d10238..953a23fcd 100644 --- a/languages.toml +++ b/languages.toml @@ -875,7 +875,7 @@ name = "haskell" scope = "source.haskell" injection-regex = "haskell" file-types = ["hs", "hs-boot"] -roots = ["Setup.hs", "stack.yaml", "*.cabal"] +roots = ["Setup.hs", "stack.yaml", "cabal.project"] comment-token = "--" language-server = { command = "haskell-language-server-wrapper", args = ["--lsp"] } indent = { tab-width = 2, unit = " " } From 234280736491747b54562e636565960b23092963 Mon Sep 17 00:00:00 2001 From: Chirikumbrah <78883260+Chirikumbrah@users.noreply.github.com> Date: Fri, 21 Apr 2023 06:51:47 +0300 Subject: [PATCH 128/260] another refactoring of dracula theme (#6767) --- runtime/themes/dracula.toml | 169 +++++++++++++++++------------------- 1 file changed, 80 insertions(+), 89 deletions(-) diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index f1d895f9d..bfdd620d0 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -1,75 +1,65 @@ # Author : Sebastian Zivota # Author : Chirikumbrah -"annotation" = { fg = "white" } -"attribute" = { fg = "cyan" } -"comment" = { fg = "comment" } -"constant" = { fg = "purple" } -"constant.numeric" = { fg = "orange" } -"constant.builtin" = { fg = "orange" } -"constant.character.escape" = { fg = "pink" } -"constant.macro" = { fg = "purple" } -"constructor" = { fg = "cyan" } -"conditional" = { fg = "pink" } -"character" = { fg = "purple" } -"definition".underline = { sp = "cyan" } -"field.key" = { fg = "purple" } -"field" = { fg = "purple" } -"function" = { fg = "green" } -"function.builtin" = { fg = "green" } -"function.method" = { fg = "green" } -"function.macro" = { fg = "purple" } -"function.call" = { fg = "green" } -"keyword" = { fg = "pink" } -"keyword.operator" = { fg = "pink" } -"keyword.function" = { fg = "pink" } -"keyword.return" = { fg = "pink" } -"keyword.control.import" = { fg = "green" } -"keyword.directive" = { fg = "green" } -"keyword.control.repeat" = { fg = "cyan" } -"keyword.control.exception" = { fg = "purple" } -"keyword.storage.type" = { fg = "cyan" } -"keyword.storage.modifier" = { fg = "cyan" } -"method.call" = { fg = "green" } -"reference" = { fg = "grey" } -"special" = { fg = "orange" } -"symbol" = { fg = "yellow" } -"tag.attribute" = { fg = "purple" } -"tag.delimiter" = { fg = "white" } -"operator" = { fg = "pink" } -"label" = { fg = "cyan" } -"punctuation" = { fg = "white" } -"punctuation.bracket" = { fg = "white" } -"punctuation.delimiter" = { fg = "white" } -"punctuation.special" = { fg = "purple" } -"string" = { fg = "yellow" } -"string.regexp" = { fg = "cyan" } -"string.escape" = { fg = "cyan" } -"string.special" = { fg = "cyan" } -"tag" = { fg = "pink" } -"text" = { fg = "grey" } -"text.strong" = { modifiers = "bold" } -"text.emphasis" = { fg = "orange" } -"text.strike" = { fg = "white" } -"text.literal" = { fg = "orange" } -"text.uri".underline = { fg = "orange" } -"type.builtin" = { fg = "cyan", modifiers = ["italic"] } -"type" = { fg = "cyan", modifiers = ["italic"] } -"type.enum.variant" = { fg = "white", modifiers = ["italic"] } -"property" = { fg = "purple" } -"structure" = { fg = "purple" } -"scope" = { modifiers = "bold" } -"variable" = { fg = "purple" } -"variable.builtin" = { fg = "orange", modifiers = ["italic"] } -"variable.parameter" = { fg = "purple", modifiers = ["italic"] } -"parameter" = { fg = "orange" } +"annotation" = { fg = "foreground" } +"attribute" = { fg = "green", modifiers = ["italic"] } +"comment" = { fg = "comment" } +"comment.block.documentation" = { fg = "comment" } +"comment.block" = { fg = "comment" } +"comment.line" = { fg = "comment" } +"constant" = { fg = "purple" } +"constant.numeric" = { fg = "purple" } +"constant.builtin" = { fg = "purple" } +"constant.builtin.boolean" = { fg = "purple" } +"constant.character" = { fg = "cyan" } +"constant.character.escape" = { fg = "pink" } +"constant.macro" = { fg = "purple" } +"constructor" = { fg = "purple" } +"function" = { fg = "green" } +"function.builtin" = { fg = "green" } +"function.method" = { fg = "green" } +"function.macro" = { fg = "purple" } +"function.call" = { fg = "green" } +"keyword" = { fg = "pink" } +"keyword.operator" = { fg = "pink" } +"keyword.function" = { fg = "pink" } +"keyword.return" = { fg = "pink" } +"keyword.control.import" = { fg = "pink" } +"keyword.directive" = { fg = "green" } +"keyword.control.repeat" = { fg = "pink" } +"keyword.control.conditional" = { fg = "pink" } +"keyword.control.exception" = { fg = "purple" } +"keyword.storage" = { fg = "pink" } +"keyword.storage.type" = { fg = "cyan", modifiers = ["italic"] } +"keyword.storage.modifier" = { fg = "pink" } +"tag" = { fg = "pink" } +"tag.attribute" = { fg = "purple" } +"tag.delimiter" = { fg = "foreground" } +"label" = { fg = "cyan" } +"punctuation" = { fg = "foreground" } +"punctuation.bracket" = { fg = "foreground" } +"punctuation.delimiter" = { fg = "foreground" } +"punctuation.special" = { fg = "pink" } +"special" = { fg = "pink" } +"string" = { fg = "yellow" } +"string.special" = { fg = "orange" } +"string.symbol" = { fg = "yellow" } +"string.regexp" = { fg = "red" } +"type.builtin" = { fg = "cyan" } +"type" = { fg = "cyan", modifiers = ["italic"] } +"type.enum.variant" = { fg = "foreground", modifiers = ["italic"] } +"variable" = { fg = "foreground" } +"variable.builtin" = { fg = "purple", modifiers = ["italic"] } +"variable.parameter" = { fg = "orange", modifiers = ["italic"] } +"variable.other" = { fg = "cyan" } +"variable.other.member" = { fg = "purple" } "diff.plus" = { fg = "green" } "diff.delta" = { fg = "orange" } "diff.minus" = { fg = "red" } -"ui.background" = { fg = "white", bg = "background" } -"ui.cursor.match" = { fg = "white", bg = "grey" } +"ui.background" = { fg = "foreground", bg = "background" } +"ui.cursor.match" = { fg = "foreground", bg = "grey" } "ui.cursor" = { fg = "background", bg = "purple", modifiers = ["dim"] } "ui.cursor.normal" = { fg = "background", bg = "purple", modifiers = ["dim"] } "ui.cursor.insert" = { fg = "background", bg = "green", modifiers = ["dim"] } @@ -78,24 +68,24 @@ "ui.cursor.primary.insert" = { fg = "background", bg = "green" } "ui.cursor.primary.select" = { fg = "background", bg = "cyan" } "ui.cursorline.primary" = { bg = "cursorline" } -"ui.help" = { fg = "white", bg = "black" } +"ui.help" = { fg = "foreground", bg = "black" } "ui.debug" = { fg = "red" } "ui.highlight.frameline" = { fg = "background", bg = "red" } "ui.linenr" = { fg = "comment" } -"ui.linenr.selected" = { fg = "white" } -"ui.menu" = { fg = "white", bg = "black" } +"ui.linenr.selected" = { fg = "foreground" } +"ui.menu" = { fg = "foreground", bg = "black" } "ui.menu.selected" = { fg = "cyan", bg = "black" } -"ui.popup" = { fg = "white", bg = "black" } +"ui.popup" = { fg = "foreground", bg = "black" } "ui.selection.primary" = { bg = "selection_primary" } "ui.selection" = { bg = "selection" } -"ui.statusline" = { fg = "white", bg = "darker" } +"ui.statusline" = { fg = "foreground", bg = "darker" } "ui.statusline.inactive" = { fg = "comment", bg = "darker" } "ui.statusline.normal" = { fg = "black", bg = "purple" } "ui.statusline.insert" = { fg = "black", bg = "green" } "ui.statusline.select" = { fg = "black", bg = "cyan" } -"ui.text" = { fg = "white" } +"ui.text" = { fg = "foreground" } "ui.text.focus" = { fg = "cyan" } -"ui.window" = { fg = "white" } +"ui.window" = { fg = "foreground" } "ui.virtual.whitespace" = { fg = "subtle" } "ui.virtual.wrap" = { fg = "subtle" } "ui.virtual.ruler" = { bg = "black" } @@ -114,29 +104,30 @@ "markup.link.url" = { fg = "cyan" } "markup.link.text" = { fg = "pink" } "markup.quote" = { fg = "yellow", modifiers = ["italic"] } -"markup.raw" = { fg = "white" } +"markup.raw" = { fg = "foreground" } "diagnostic" = { underline = { color = "orange", style = "curl" } } "diagnostic.hint" = { underline = { color = "purple", style = "curl" } } "diagnostic.warning" = { underline = { color = "yellow", style = "curl" } } "diagnostic.error" = { underline = { color = "red", style = "curl" } } "diagnostic.info" = { underline = { color = "cyan", style = "curl" } } +"definition" = { underline = { color = "cyan" } } [palette] -background = "#282A36" -cursorline = "#2d303e" -darker = "#222430" -black = "#191A21" -grey = "#666771" -comment = "#6272A4" -selection_primary = "#44475a" -selection = "#363848" -subtle = "#424450" -white = "#f8f8f2" -red = "#ff5555" -orange = "#ffb86c" -yellow = "#f1fa8c" -green = "#50fa7b" -purple = "#BD93F9" -cyan = "#8be9fd" -pink = "#ff79c6" +foreground = "#f8f8f2" +background = "#282A36" +cursorline = "#2d303e" +darker = "#222430" +black = "#191A21" +grey = "#666771" +comment = "#6272A4" +selection_primary = "#44475a" +selection = "#363848" +subtle = "#424450" +red = "#ff5555" +orange = "#ffb86c" +yellow = "#f1fa8c" +green = "#50fa7b" +purple = "#BD93F9" +cyan = "#8be9fd" +pink = "#ff79c6" From 78088ac18510754c9aac27c162e4d81890a11a82 Mon Sep 17 00:00:00 2001 From: Paul Lange Date: Fri, 21 Apr 2023 05:53:04 +0200 Subject: [PATCH 129/260] Ayu dark improvements (#6622) * theme(ayu_dark): Differentiate primary cursor * theme(ayu_dark): Color statusline mode field * theme(ayu): Adapt other ayu themes as well --- runtime/themes/ayu_dark.toml | 6 +++++- runtime/themes/ayu_light.toml | 6 +++++- runtime/themes/ayu_mirage.toml | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/runtime/themes/ayu_dark.toml b/runtime/themes/ayu_dark.toml index 1e1aab91e..0b011b0ea 100644 --- a/runtime/themes/ayu_dark.toml +++ b/runtime/themes/ayu_dark.toml @@ -36,11 +36,15 @@ # Interface "ui.background"= { bg = "background" } -"ui.cursor" = { fg = "dark_gray", bg = "orange" } +"ui.cursor" = { fg = "dark_gray", bg = "yellow" } +"ui.cursor.primary" = { fg = "dark_gray", bg = "orange" } "ui.cursor.match" = "orange" "ui.linenr" = "dark_gray" "ui.linenr.selected" = "gray" "ui.statusline" = { fg = "foreground", bg = "black" } +"ui.statusline.normal" = { fg = "black", bg = "blue" } +"ui.statusline.insert" = { fg = "black", bg = "orange" } +"ui.statusline.select" = { fg = "black", bg = "magenta" } "ui.cursorline" = { bg = "black" } "ui.popup" = { fg = "#7B91b3", bg = "black" } "ui.window" = "dark_gray" diff --git a/runtime/themes/ayu_light.toml b/runtime/themes/ayu_light.toml index d4cb56de8..6c405381d 100644 --- a/runtime/themes/ayu_light.toml +++ b/runtime/themes/ayu_light.toml @@ -36,11 +36,15 @@ # Interface "ui.background"= { bg = "background" } -"ui.cursor" = { fg = "dark_gray", bg = "orange" } +"ui.cursor" = { fg = "dark_gray", bg = "yellow" } +"ui.cursor.primary" = { fg = "dark_gray", bg = "orange" } "ui.cursor.match" = "orange" "ui.linenr" = "dark_gray" "ui.linenr.selected" = "gray" "ui.statusline" = { fg = "foreground", bg = "black" } +"ui.statusline.normal" = { fg = "black", bg = "blue" } +"ui.statusline.insert" = { fg = "black", bg = "orange" } +"ui.statusline.select" = { fg = "black", bg = "magenta" } "ui.cursorline" = { bg = "black" } "ui.popup" = { fg = "#7B91b3", bg = "black" } "ui.window" = "dark_gray" diff --git a/runtime/themes/ayu_mirage.toml b/runtime/themes/ayu_mirage.toml index b27efc1cc..a4b74fcfb 100644 --- a/runtime/themes/ayu_mirage.toml +++ b/runtime/themes/ayu_mirage.toml @@ -36,11 +36,15 @@ # Interface "ui.background"= { bg = "background" } -"ui.cursor" = { fg = "dark_gray", bg = "orange" } +"ui.cursor" = { fg = "dark_gray", bg = "yellow" } +"ui.cursor.primary" = { fg = "dark_gray", bg = "orange" } "ui.cursor.match" = "orange" "ui.linenr" = "dark_gray" "ui.linenr.selected" = "gray" "ui.statusline" = { fg = "foreground", bg = "black" } +"ui.statusline.normal" = { fg = "black", bg = "blue" } +"ui.statusline.insert" = { fg = "black", bg = "orange" } +"ui.statusline.select" = { fg = "black", bg = "magenta" } "ui.cursorline" = { bg = "black" } "ui.popup" = { fg = "#7B91b3", bg = "black" } "ui.window" = "dark_gray" From ee7413a3fd723015843e569924abbfbf32b56182 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Thu, 20 Apr 2023 22:53:27 -0500 Subject: [PATCH 130/260] tui: Allow toggling mouse capture at runtime (#6675) This picks up changes to the `editor.mouse` option at runtime - either through `:set-option` or `:config-reload`. When the value changes, we tell the terminal to enable or disable mouse capture sequences. --- helix-term/src/application.rs | 5 +++++ helix-tui/src/backend/crossterm.rs | 16 ++++++++++++++++ helix-tui/src/backend/mod.rs | 1 + helix-tui/src/backend/test.rs | 4 ++++ helix-tui/src/terminal.rs | 4 ++++ 5 files changed, 30 insertions(+) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index cda498e2f..b54d6835a 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -361,6 +361,9 @@ impl Application { ConfigEvent::Update(editor_config) => { let mut app_config = (*self.config.load().clone()).clone(); app_config.editor = *editor_config; + if let Err(err) = self.terminal.reconfigure(app_config.editor.clone().into()) { + self.editor.set_error(err.to_string()); + }; self.config.store(Arc::new(app_config)); } } @@ -419,6 +422,8 @@ impl Application { .map_err(|err| anyhow::anyhow!("Failed to load config: {}", err))?; self.refresh_language_config()?; self.refresh_theme(&default_config)?; + self.terminal + .reconfigure(default_config.editor.clone().into())?; // Store new config self.config.store(Arc::new(default_config)); Ok(()) diff --git a/helix-tui/src/backend/crossterm.rs b/helix-tui/src/backend/crossterm.rs index 9d70a9fb0..0c32028ec 100644 --- a/helix-tui/src/backend/crossterm.rs +++ b/helix-tui/src/backend/crossterm.rs @@ -63,6 +63,7 @@ pub struct CrosstermBackend { buffer: W, capabilities: Capabilities, supports_keyboard_enhancement_protocol: OnceCell, + mouse_capture_enabled: bool, } impl CrosstermBackend @@ -74,6 +75,7 @@ where buffer, capabilities: Capabilities::from_env_or_default(config), supports_keyboard_enhancement_protocol: OnceCell::new(), + mouse_capture_enabled: false, } } @@ -123,6 +125,7 @@ where execute!(self.buffer, terminal::Clear(terminal::ClearType::All))?; if config.enable_mouse_capture { execute!(self.buffer, EnableMouseCapture)?; + self.mouse_capture_enabled = true; } if self.supports_keyboard_enhancement_protocol() { execute!( @@ -136,6 +139,19 @@ where Ok(()) } + fn reconfigure(&mut self, config: Config) -> io::Result<()> { + if self.mouse_capture_enabled != config.enable_mouse_capture { + if config.enable_mouse_capture { + execute!(self.buffer, EnableMouseCapture)?; + } else { + execute!(self.buffer, DisableMouseCapture)?; + } + self.mouse_capture_enabled = config.enable_mouse_capture; + } + + Ok(()) + } + fn restore(&mut self, config: Config) -> io::Result<()> { // reset cursor shape write!(self.buffer, "\x1B[0 q")?; diff --git a/helix-tui/src/backend/mod.rs b/helix-tui/src/backend/mod.rs index 6d7c38942..6994bc6f5 100644 --- a/helix-tui/src/backend/mod.rs +++ b/helix-tui/src/backend/mod.rs @@ -14,6 +14,7 @@ pub use self::test::TestBackend; pub trait Backend { fn claim(&mut self, config: Config) -> Result<(), io::Error>; + fn reconfigure(&mut self, config: Config) -> Result<(), io::Error>; fn restore(&mut self, config: Config) -> Result<(), io::Error>; fn force_restore() -> Result<(), io::Error>; fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error> diff --git a/helix-tui/src/backend/test.rs b/helix-tui/src/backend/test.rs index ff133ff3e..771cc3094 100644 --- a/helix-tui/src/backend/test.rs +++ b/helix-tui/src/backend/test.rs @@ -111,6 +111,10 @@ impl Backend for TestBackend { Ok(()) } + fn reconfigure(&mut self, _config: Config) -> Result<(), io::Error> { + Ok(()) + } + fn restore(&mut self, _config: Config) -> Result<(), io::Error> { Ok(()) } diff --git a/helix-tui/src/terminal.rs b/helix-tui/src/terminal.rs index 802a8c1d9..8b7342751 100644 --- a/helix-tui/src/terminal.rs +++ b/helix-tui/src/terminal.rs @@ -116,6 +116,10 @@ where self.backend.claim(config) } + pub fn reconfigure(&mut self, config: Config) -> io::Result<()> { + self.backend.reconfigure(config) + } + pub fn restore(&mut self, config: Config) -> io::Result<()> { self.backend.restore(config) } From a1044a6c68bc822021da204f81e1d7c0ba13df31 Mon Sep 17 00:00:00 2001 From: "Michael T. Mordowanec" Date: Fri, 21 Apr 2023 23:45:50 +0200 Subject: [PATCH 131/260] Change soft-wrap.wrap_at_text_width to kebab case in documentation (#6842) Solves #6803. --- book/src/configuration.md | 2 +- book/src/languages.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index 38f9f9eb2..1fdbf0052 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -60,7 +60,7 @@ Its settings will be merged with the configuration directory `config.toml` and t | `rulers` | List of column positions at which to display the rulers. Can be overridden by language specific `rulers` in `languages.toml` file | `[]` | | `bufferline` | Renders a line at the top of the editor displaying open buffers. Can be `always`, `never` or `multiple` (only shown if more than one buffer is in use) | `never` | | `color-modes` | Whether to color the mode indicator with different colors depending on the mode itself | `false` | -| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap_at_text_width` is set | `80` | +| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap-at-text-width` is set | `80` | | `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml` | `[]` | ### `[editor.statusline]` Section diff --git a/book/src/languages.md b/book/src/languages.md index f44509fc8..fe4db1413 100644 --- a/book/src/languages.md +++ b/book/src/languages.md @@ -63,7 +63,7 @@ These configuration keys are available: | `config` | Language Server configuration | | `grammar` | The tree-sitter grammar to use (defaults to the value of `name`) | | `formatter` | The formatter for the language, it will take precedence over the lsp when defined. The formatter must be able to take the original file as input from stdin and write the formatted file to stdout | -| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap_at_text_width` is set, defaults to `editor.text-width` | +| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap-at-text-width` is set, defaults to `editor.text-width` | | `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml`. Overwrites the setting of the same name in `config.toml` if set. | ### File-type detection and the `file-types` key From b7c62e200e0fbe600855e6a2d492286349cae4ae Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Sat, 22 Apr 2023 12:38:25 +0200 Subject: [PATCH 132/260] fix windows builds (#6845) --- helix-loader/src/grammar.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs index 3dac237c8..16955187e 100644 --- a/helix-loader/src/grammar.rs +++ b/helix-loader/src/grammar.rs @@ -433,11 +433,12 @@ fn build_tree_sitter_library( for (key, value) in compiler.env() { command.env(key, value); } + command.args(compiler.args()); // used to delay dropping the temporary object file until after the compilation is complete let _path_guard; - if cfg!(all(windows, target_env = "msvc")) { + if compiler.is_like_msvc() { command .args(["/nologo", "/LD", "/I"]) .arg(header_path) @@ -455,20 +456,20 @@ fn build_tree_sitter_library( } cpp_command.args(compiler.args()); let object_file = - library_path.with_file_name(format!("{}_scanner.o", &grammar.grammar_id)); + library_path.with_file_name(format!("{}_scanner.obj", &grammar.grammar_id)); cpp_command .args(["/nologo", "/LD", "/I"]) .arg(header_path) .arg("/Od") .arg("/utf-8") .arg("/std:c++14") - .arg("/o") - .arg(&object_file) + .arg(format!("/Fo{}", object_file.display())) .arg("/c") .arg(scanner_path); let output = cpp_command .output() .context("Failed to execute C++ compiler")?; + if !output.status.success() { return Err(anyhow!( "Parser compilation failed.\nStdout: {}\nStderr: {}", From 228a4af35fec3be633c31ecbbdf0b6f7bb7a9fcd Mon Sep 17 00:00:00 2001 From: Atticus Sebastiani Date: Sat, 22 Apr 2023 21:07:34 -0500 Subject: [PATCH 133/260] make `:u` alias `:update` (#6835) * Gave the command update the alias u * Re added trailing newline * generated docs --- book/src/generated/typable-cmd.md | 2 +- helix-term/src/commands/typed.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 9d15b83c9..a9d68b75a 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -46,7 +46,7 @@ | `:character-info`, `:char` | Get info about the character under the primary cursor. | | `:reload` | Discard changes and reload from the source file. | | `:reload-all` | Discard changes and reload all documents from the source files. | -| `:update` | Write changes only if the file has been modified. | +| `:update`, `:u` | Write changes only if the file has been modified. | | `:lsp-workspace-command` | Open workspace command picker | | `:lsp-restart` | Restarts the Language Server that is in use by the current doc | | `:lsp-stop` | Stops the Language Server that is in use by the current doc | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index eb5c156fb..ea82dc366 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -2497,7 +2497,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ }, TypableCommand { name: "update", - aliases: &[], + aliases: &["u"], doc: "Write changes only if the file has been modified.", fun: update, signature: CommandSignature::none(), From 61ff2bc0941be0ca99f34d8ba013978356612caf Mon Sep 17 00:00:00 2001 From: ymgyt Date: Sun, 23 Apr 2023 22:24:17 +0900 Subject: [PATCH 134/260] return early if soft wrap is invalid (#6856) --- helix-core/src/movement.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-core/src/movement.rs b/helix-core/src/movement.rs index 60af47e5b..b44d149fb 100644 --- a/helix-core/src/movement.rs +++ b/helix-core/src/movement.rs @@ -62,7 +62,7 @@ pub fn move_vertically_visual( annotations: &mut TextAnnotations, ) -> Range { if !text_fmt.soft_wrap { - move_vertically(slice, range, dir, count, behaviour, text_fmt, annotations); + return move_vertically(slice, range, dir, count, behaviour, text_fmt, annotations); } annotations.clear_line_annotations(); let pos = range.cursor(slice); From fd1b3dc49973be4fcc402015798335f8f53c2733 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:51:12 +0900 Subject: [PATCH 135/260] build(deps): bump bitflags from 2.1.0 to 2.2.1 (#6869) Bumps [bitflags](https://github.com/bitflags/bitflags) from 2.1.0 to 2.2.1. - [Release notes](https://github.com/bitflags/bitflags/releases) - [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md) - [Commits](https://github.com/bitflags/bitflags/compare/2.1.0...2.2.1) --- updated-dependencies: - dependency-name: bitflags 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 | 10 +++++----- helix-core/Cargo.toml | 2 +- helix-tui/Cargo.toml | 2 +- helix-view/Cargo.toml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f413bc41f..a4767d4f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,9 +75,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c70beb79cbb5ce9c4f8e20849978f34225931f665bb49efa6982875a4d5facb3" +checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813" [[package]] name = "bstr" @@ -1081,7 +1081,7 @@ version = "0.6.0" dependencies = [ "ahash 0.8.3", "arc-swap", - "bitflags 2.1.0", + "bitflags 2.2.1", "chrono", "dunce", "encoding_rs", @@ -1208,7 +1208,7 @@ dependencies = [ name = "helix-tui" version = "0.6.0" dependencies = [ - "bitflags 2.1.0", + "bitflags 2.2.1", "cassowary", "crossterm", "helix-core", @@ -1241,7 +1241,7 @@ version = "0.6.0" dependencies = [ "anyhow", "arc-swap", - "bitflags 2.1.0", + "bitflags 2.2.1", "chardetng", "clipboard-win", "crossterm", diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 99776694e..6ebac5e62 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -29,7 +29,7 @@ tree-sitter = "0.20" once_cell = "1.17" arc-swap = "1" regex = "1" -bitflags = "2.1" +bitflags = "2.2" ahash = "0.8.3" hashbrown = { version = "0.13.2", features = ["raw"] } dunce = "1.0" diff --git a/helix-tui/Cargo.toml b/helix-tui/Cargo.toml index 3d8a20d13..735669298 100644 --- a/helix-tui/Cargo.toml +++ b/helix-tui/Cargo.toml @@ -16,7 +16,7 @@ include = ["src/**/*", "README.md"] default = ["crossterm"] [dependencies] -bitflags = "2.1" +bitflags = "2.2" cassowary = "0.3" unicode-segmentation = "1.10" crossterm = { version = "0.26", optional = true } diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index f9d28795d..049705956 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -14,7 +14,7 @@ default = [] term = ["crossterm"] [dependencies] -bitflags = "2.1" +bitflags = "2.2" anyhow = "1" helix-core = { version = "0.6", path = "../helix-core" } helix-loader = { version = "0.6", path = "../helix-loader" } From 11e3fdd153ef6b3c020a5e93173232c23df5b33c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:51:25 +0900 Subject: [PATCH 136/260] build(deps): bump dunce from 1.0.3 to 1.0.4 (#6870) Bumps [dunce](https://gitlab.com/kornelski/dunce) from 1.0.3 to 1.0.4. - [Release notes](https://gitlab.com/kornelski/dunce/tags) - [Commits](https://gitlab.com/kornelski/dunce/compare/v1.0.3...v1.0.4) --- updated-dependencies: - dependency-name: dunce 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 a4767d4f9..ddf7b96e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -323,9 +323,9 @@ dependencies = [ [[package]] name = "dunce" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "either" From f47f8d538da6b7788547884d2eb724d616067259 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:51:35 +0900 Subject: [PATCH 137/260] build(deps): bump regex from 1.7.3 to 1.8.1 (#6871) Bumps [regex](https://github.com/rust-lang/regex) from 1.7.3 to 1.8.1. - [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.7.3...1.8.1) --- 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 | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ddf7b96e8..add85e954 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,6 +40,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -1011,7 +1020,7 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.20", "bstr", "fnv", "log", @@ -1033,12 +1042,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "997598b41d53a37a2e3fc5300d5c11d825368c054420a9c65125b8fe1078463f" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.20", "bstr", "grep-matcher", "log", "regex", - "regex-syntax", + "regex-syntax 0.6.29", "thread_local", ] @@ -1729,13 +1738,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.3" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" dependencies = [ - "aho-corasick", + "aho-corasick 1.0.1", "memchr", - "regex-syntax", + "regex-syntax 0.7.1", ] [[package]] @@ -1750,6 +1759,12 @@ version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +[[package]] +name = "regex-syntax" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" + [[package]] name = "ropey" version = "1.6.0" From d45af96fc44e25f121b459f7fee2b3f0278d4444 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:51:43 +0900 Subject: [PATCH 138/260] build(deps): bump libc from 0.2.141 to 0.2.142 (#6872) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.141 to 0.2.142. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.141...0.2.142) --- updated-dependencies: - dependency-name: libc 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-term/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index add85e954..ba5d7d4cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1435,9 +1435,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.141" +version = "0.2.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" [[package]] name = "libloading" diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index b240f1d82..7fb6b890a 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -68,7 +68,7 @@ grep-searcher = "0.1.11" [target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100 signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } -libc = "0.2.141" +libc = "0.2.142" [build-dependencies] helix-loader = { version = "0.6", path = "../helix-loader" } From 0097e191bb9f9f144043c2afcf04bc8632021281 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:52:17 +0900 Subject: [PATCH 139/260] build(deps): bump etcetera from 0.5.0 to 0.7.1 (#6873) Bumps [etcetera](https://github.com/lunacookies/etcetera) from 0.5.0 to 0.7.1. - [Release notes](https://github.com/lunacookies/etcetera/releases) - [Commits](https://github.com/lunacookies/etcetera/compare/v0.5.0...v0.7.1) --- 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 | 5 ++--- helix-core/Cargo.toml | 2 +- helix-loader/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba5d7d4cf..840c664bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -393,13 +393,12 @@ dependencies = [ [[package]] name = "etcetera" -version = "0.5.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870a9fdff9c99141df9277dece5ec8021434eca50f05cbac41a5eb07c9659e7d" +checksum = "51822eedc6129d8c4d96cec86d56b785e983f943c9ce9fb892e0c2a99a7f47a0" dependencies = [ "cfg-if", "home", - "thiserror", ] [[package]] diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 6ebac5e62..c10ed735e 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -45,7 +45,7 @@ encoding_rs = "0.8" chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] } -etcetera = "0.5" +etcetera = "0.7" textwrap = "0.16.0" [dev-dependencies] diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index 60b1e911b..ff8ffb1c8 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -17,7 +17,7 @@ path = "src/main.rs" anyhow = "1" serde = { version = "1.0", features = ["derive"] } toml = "0.7" -etcetera = "0.5" +etcetera = "0.7" tree-sitter = "0.20" once_cell = "1.17" log = "0.4" From 096ed0ced449ff0355fed6220c762c4f7f28ec25 Mon Sep 17 00:00:00 2001 From: Dimitri Sabadie Date: Tue, 25 Apr 2023 13:14:06 -0400 Subject: [PATCH 140/260] Add extend_to_first_nonwhitespace (#6837) Closes #6836 --- helix-term/src/commands.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 95310c1fe..5a75553cd 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -347,6 +347,7 @@ impl MappableCommand { goto_first_nonwhitespace, "Goto first non-blank in line", trim_selections, "Trim whitespace from selections", extend_to_line_start, "Extend to line start", + extend_to_first_nonwhitespace, "Extend to first non-blank in line", extend_to_line_end, "Extend to line end", extend_to_line_end_newline, "Extend to line end", signature_help, "Show signature help", @@ -839,6 +840,24 @@ fn kill_to_line_end(cx: &mut Context) { fn goto_first_nonwhitespace(cx: &mut Context) { let (view, doc) = current!(cx.editor); + + goto_first_nonwhitespace_impl( + view, + doc, + if cx.editor.mode == Mode::Select { + Movement::Extend + } else { + Movement::Move + }, + ) +} + +fn extend_to_first_nonwhitespace(cx: &mut Context) { + let (view, doc) = current!(cx.editor); + goto_first_nonwhitespace_impl(view, doc, Movement::Extend) +} + +fn goto_first_nonwhitespace_impl(view: &mut View, doc: &mut Document, movement: Movement) { let text = doc.text().slice(..); let selection = doc.selection(view.id).clone().transform(|range| { @@ -846,7 +865,7 @@ fn goto_first_nonwhitespace(cx: &mut Context) { if let Some(pos) = find_first_non_whitespace_char(text.line(line)) { let pos = pos + text.line_to_char(line); - range.put_cursor(text, pos, cx.editor.mode == Mode::Select) + range.put_cursor(text, pos, movement == Movement::Extend) } else { range } From e7f25d88ca059ba006525bd7d476da9ada5341b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Wed, 26 Apr 2023 01:05:23 +0200 Subject: [PATCH 141/260] Avoid extra indentation on Go switches (#6817) Unlike other languages, in Go, switches themselves are not indented; it's just each case body which is indented by one level: switch foo { case "bar": baz() } As such, we shouldn't `@indent` for type_switch_statement nor expression_switch_statement, as otherwise inserted lines show up as: switch foo { // inserted with "o" case "bar": // inserted with "o" baz() } With the fix, the inserted lines are indented properly: switch foo { // inserted with "o" case "bar": // inserted with "o" baz() } I also verified that indentation on selects similarly works well. Thanks to Triton171 for helping with this fix. --- runtime/queries/go/indents.scm | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/runtime/queries/go/indents.scm b/runtime/queries/go/indents.scm index e439a9055..b2befab08 100644 --- a/runtime/queries/go/indents.scm +++ b/runtime/queries/go/indents.scm @@ -14,8 +14,6 @@ (argument_list) (field_declaration_list) (block) - (type_switch_statement) - (expression_switch_statement) (var_declaration) ] @indent @@ -24,5 +22,19 @@ ")" ] @outdent -((_ "}" @outdent) @outer (#not-kind-eq? @outer "select_statement")) -(communication_case) @extend +; Switches and selects aren't indented, only their case bodies are. +; Outdent all closing braces except those closing switches or selects. +( + (_ "}" @outdent) @outer + (#not-kind-eq? @outer "select_statement") + (#not-kind-eq? @outer "type_switch_statement") + (#not-kind-eq? @outer "expression_switch_statement") +) + +; Starting a line after a new case should indent. +[ + (communication_case) + (expression_case) + (default_case) + (type_case) +] @extend From 080f85c34f7bfc3de8b8441d51d434623a4a9f79 Mon Sep 17 00:00:00 2001 From: Timothy DeHerrera Date: Tue, 25 Apr 2023 19:15:16 -0600 Subject: [PATCH 142/260] fix(nix): fix superflous `/` that breaks the build (#6880) Resolves #1779 --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 953a23fcd..abf76d7c2 100644 --- a/languages.toml +++ b/languages.toml @@ -2467,7 +2467,7 @@ comment-token = "--" [[grammar]] name = "cabal" -source = { git = "https://gitlab.com/magus/tree-sitter-cabal/", rev = "7d5fa6887ae05a0b06d046f1e754c197c8ad869b" } +source = { git = "https://gitlab.com/magus/tree-sitter-cabal", rev = "7d5fa6887ae05a0b06d046f1e754c197c8ad869b" } [[language]] name = "hurl" From 488707c7c81159d4a1f9a2b7690eb01723fd4e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Wed, 26 Apr 2023 15:51:04 +0200 Subject: [PATCH 143/260] add go.work and remove Gopkg.toml as Go roots (#6884) Gopkg.toml was used by dep, Go's original dependency management tool. It was an experiment that culminated in official and built-in support for Go modules in mid 2018, and dep was deprecated and archived in mid 2020 per https://github.com/golang/go/issues/38158. Now, in 2023, Gopkg.toml files are incredibly rare in actively developed Go projects, as people use go.mod with Go modules instead. While here, also add go.work as a root file, since that is used by Go module workspaces, added in Go 1.18 in early 2022. gopls or commands like `go build` work inside either go.work or go.mod. These two root files are the same ones used by gopls integrations with other editors like vim or neovim. --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index abf76d7c2..dc8dac7dd 100644 --- a/languages.toml +++ b/languages.toml @@ -292,7 +292,7 @@ name = "go" scope = "source.go" injection-regex = "go" file-types = ["go"] -roots = ["Gopkg.toml", "go.mod"] +roots = ["go.work", "go.mod"] auto-format = true comment-token = "//" language-server = { command = "gopls" } From 903bdaae875fa45b6371ace14fc5267cf2e228cc Mon Sep 17 00:00:00 2001 From: Wesley <95096973+WesleySoftware@users.noreply.github.com> Date: Wed, 26 Apr 2023 19:28:54 -0400 Subject: [PATCH 144/260] Set PerlNavigator as the language server for Perl (#6860) --- 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 331d212f5..900664d22 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -105,7 +105,7 @@ | pascal | ✓ | ✓ | | `pasls` | | passwd | ✓ | | | | | pem | ✓ | | | | -| perl | ✓ | ✓ | ✓ | | +| perl | ✓ | ✓ | ✓ | `perlnavigator` | | php | ✓ | ✓ | ✓ | `intelephense` | | po | ✓ | ✓ | | | | ponylang | ✓ | ✓ | ✓ | | diff --git a/languages.toml b/languages.toml index dc8dac7dd..00df32394 100644 --- a/languages.toml +++ b/languages.toml @@ -1008,6 +1008,7 @@ file-types = ["pl", "pm", "t"] shebangs = ["perl"] roots = [] comment-token = "#" +language-server = { command = "perlnavigator", args= ["--stdio"] } indent = { tab-width = 2, unit = " " } [[grammar]] From 8f1671eaaa6c917c131567dec1dc7dce628e548b Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Thu, 27 Apr 2023 02:38:20 +0200 Subject: [PATCH 145/260] fix panic in inlay hint computation when view anchor is out of bounds (#6883) --- helix-term/src/commands/lsp.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index be8ae02a6..b5d1d337e 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -1513,7 +1513,8 @@ fn compute_inlay_hints_for_view( // than computing all the hints for the full file (which could be dozens of time // longer than the view is). let view_height = view.inner_height(); - let first_visible_line = doc_text.char_to_line(view.offset.anchor); + let first_visible_line = + doc_text.char_to_line(view.offset.anchor.min(doc_text.len_chars())); let first_line = first_visible_line.saturating_sub(view_height); let last_line = first_visible_line .saturating_add(view_height.saturating_mul(2)) From 6dd5054da46fd68993d386de75bfc65130dc2c3b Mon Sep 17 00:00:00 2001 From: Cole Helbling Date: Wed, 26 Apr 2023 22:37:17 -0700 Subject: [PATCH 146/260] Highlight sqlx's `query_scalar{,_unchecked}` macros as SQL (#6793) * Highlight sqlx's `query_scalar{,_unchecked}` macros as SQL * Update injections.scm * fixup copy-pasta --- runtime/queries/rust/injections.scm | 35 ++++------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/runtime/queries/rust/injections.scm b/runtime/queries/rust/injections.scm index d191a53ad..b29a5ad70 100644 --- a/runtime/queries/rust/injections.scm +++ b/runtime/queries/rust/injections.scm @@ -25,11 +25,11 @@ arguments: (arguments (raw_string_literal) @injection.content) (#set! injection.language "regex")) -; Highlight SQL in `sqlx::query!()` +; Highlight SQL in `sqlx::query!()`, `sqlx::query_scalar!()`, and `sqlx::query_scalar_unchecked!()` (macro_invocation macro: (scoped_identifier path: (identifier) @_sqlx (#eq? @_sqlx "sqlx") - name: (identifier) @_query (#eq? @_query "query")) + name: (identifier) @_query (#match? @_query "^query(_scalar|_scalar_unchecked)?$")) (token_tree ; Only the first argument is SQL . @@ -37,38 +37,11 @@ ) (#set! injection.language "sql")) -; Highlight SQL in `sqlx::query_as!()` +; Highlight SQL in `sqlx::query_as!()` and `sqlx::query_as_unchecked!()` (macro_invocation macro: (scoped_identifier path: (identifier) @_sqlx (#eq? @_sqlx "sqlx") - name: (identifier) @_query_as (#eq? @_query_as "query_as")) - (token_tree - ; Only the second argument is SQL - . - ; Allow anything as the first argument in case the user has lower case type - ; names for some reason - (_) - [(string_literal) (raw_string_literal)] @injection.content - ) - (#set! injection.language "sql")) - -; Highlight SQL in `sqlx::query_unchecked!()` -(macro_invocation - macro: (scoped_identifier - path: (identifier) @_sqlx (#eq? @_sqlx "sqlx") - name: (identifier) @_query_as (#eq? @_query_as "query_unchecked")) - (token_tree - ; Only the first argument is SQL - . - [(string_literal) (raw_string_literal)] @injection.content - ) - (#set! injection.language "sql")) - -; Highlight SQL in `sqlx::query_as_unchecked!()` -(macro_invocation - macro: (scoped_identifier - path: (identifier) @_sqlx (#eq? @_sqlx "sqlx") - name: (identifier) @_query_as (#eq? @_query_as "query_as_unchecked")) + name: (identifier) @_query_as (#match? @_query_as "^query_as(_unchecked)?$")) (token_tree ; Only the second argument is SQL . From 222be0f1e769177241eb2d8d8dfb0de42e450820 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 27 Apr 2023 07:38:07 +0200 Subject: [PATCH 147/260] upgrade gitoxide to v0.44 and change repository discovery to worktree-only (#6867) (#6890) --- Cargo.lock | 240 ++++++++++++++++++++++--------------------- helix-vcs/Cargo.toml | 2 +- helix-vcs/src/git.rs | 27 +++-- 3 files changed, 139 insertions(+), 130 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 840c664bf..d8a07f41b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -289,15 +289,6 @@ dependencies = [ "syn 2.0.15", ] -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] - [[package]] name = "dirs-next" version = "2.0.0" @@ -308,17 +299,6 @@ dependencies = [ "dirs-sys-next", ] -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -514,9 +494,9 @@ dependencies = [ [[package]] name = "gix" -version = "0.43.1" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c256ea71cc1967faaefdaad15f334146b7c806f12460dcafd3afed845c8c78dd" +checksum = "ef2353761ba46eabc95759eb1deed72c99cb31ad8930bc5d811c06e3f52b0feb" dependencies = [ "gix-actor", "gix-attributes", @@ -526,9 +506,11 @@ dependencies = [ "gix-diff", "gix-discover", "gix-features", + "gix-fs", "gix-glob", "gix-hash", "gix-hashtable", + "gix-ignore", "gix-index", "gix-lock", "gix-mailmap", @@ -544,6 +526,7 @@ dependencies = [ "gix-tempfile", "gix-traverse", "gix-url", + "gix-utils", "gix-validate", "gix-worktree", "log", @@ -556,9 +539,9 @@ dependencies = [ [[package]] name = "gix-actor" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc22b0cdc52237667c301dd7cdc6ead8f8f73c9f824e9942c8ebd6b764f6c0bf" +checksum = "848efa0f1210cea8638f95691c82a46f98a74b9e3524f01d4955ebc25a8f84f3" dependencies = [ "bstr", "btoi", @@ -570,24 +553,26 @@ dependencies = [ [[package]] name = "gix-attributes" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2231a25934a240d0a4b6f4478401c73ee81d8be52de0293eedbc172334abf3e1" +checksum = "371c78ac6b4ef130abedc0f09c8f4b43d846df62d2d1571ca4e8cc5479886760" dependencies = [ "bstr", - "gix-features", "gix-glob", "gix-path", "gix-quote", + "kstring", + "log", + "smallvec", "thiserror", "unicode-bom", ] [[package]] name = "gix-bitmap" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "024bca0c7187517bda5ea24ab148c9ca8208dd0c3e2bea88cdb2008f91791a6d" +checksum = "55a95f4942360766c3880bdb2b4b57f1ef73b190fc424755e7fdf480430af618" dependencies = [ "thiserror", ] @@ -612,9 +597,9 @@ dependencies = [ [[package]] name = "gix-config" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbad5ce54a8fc997acc50febd89ec80fa6e97cb7f8d0654cb229936407489d8" +checksum = "58e8188bb673aeef4bb21dc8650084668e83ed944c1c6fcf22050b5e4de0ebdd" dependencies = [ "bstr", "gix-config-value", @@ -634,11 +619,11 @@ dependencies = [ [[package]] name = "gix-config-value" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d09154c0c8677e4da0ec35e896f56ee3e338e741b9599fae06075edd83a4081c" +checksum = "1a77b6c3e51bd6d8974ab80c7e7943b3f12abb8fa809834002db9742da6b4ac4" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.2.1", "bstr", "gix-path", "libc", @@ -647,9 +632,9 @@ dependencies = [ [[package]] name = "gix-credentials" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "750b684197374518ea057e0a0594713e07683faa0a3f43c0f93d97f64130ad8d" +checksum = "4896885f74b84a7bdcd0a2e32d9cb0a5082b34c8489c8fe1bfa94f155206b4f1" dependencies = [ "bstr", "gix-command", @@ -663,9 +648,9 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.4.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96271912ce39822501616f177dea7218784e6c63be90d5f36322ff3a722aae2" +checksum = "99056f37270715f5c7584fd8b46899a2296af9cae92463bf58b8bd1f5a78e553" dependencies = [ "bstr", "itoa", @@ -675,9 +660,9 @@ dependencies = [ [[package]] name = "gix-diff" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "103a0fa79b0d438f5ecb662502f052e530ace4fe1fe8e1c83c0c6da76d728e67" +checksum = "644a0f2768bc42d7a69289ada80c9e15c589caefc6a315d2307202df83ed1186" dependencies = [ "gix-hash", "gix-object", @@ -687,9 +672,9 @@ dependencies = [ [[package]] name = "gix-discover" -version = "0.16.2" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eba8ba458cb8f4a6c33409b0fe650b1258655175a7ffd1d24fafd3ed31d880b" +checksum = "0305d45385faeac734f1bda1fa7bad55b7d51416a26f6fb53d17a78186da0bd9" dependencies = [ "bstr", "dunce", @@ -702,9 +687,9 @@ dependencies = [ [[package]] name = "gix-features" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b76f9a80f6dd7be66442ae86e1f534effad9546676a392acc95e269d0c21c22" +checksum = "cf69b0f5c701cc3ae22d3204b671907668f6437ca88862d355eaf9bc47a4f897" dependencies = [ "crc32fast", "flate2", @@ -717,21 +702,32 @@ dependencies = [ "walkdir", ] +[[package]] +name = "gix-fs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b37a1832f691fdc09910bd267f9a2e413737c1f9ec68c6e31f9e802616278a9" +dependencies = [ + "gix-features", +] + [[package]] name = "gix-glob" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e43efd776bc543f46f0fd0ca3d920c37af71a764a16f2aebd89765e9ff2993" +checksum = "035fd81df824cb4d987835120b6259d2bd39fbaf1e888cab9426dc687170191f" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.2.1", "bstr", + "gix-features", + "gix-path", ] [[package]] name = "gix-hash" -version = "0.10.4" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a258595457bc192d1f1c59d0d168a1e34e2be9b97a614e14995416185de41a7" +checksum = "078eec3ac2808cc03f0bddd2704cb661da5c5dc33b41a9d7947b141d499c7c42" dependencies = [ "hex", "thiserror", @@ -739,22 +735,34 @@ dependencies = [ [[package]] name = "gix-hashtable" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4e55e40dfd694884f0eb78796c5bddcf2f8b295dace47039099dd7e76534973" +checksum = "afebb85691c6a085b114e01a27f4a61364519298c5826cb87a45c304802299bc" dependencies = [ "gix-hash", "hashbrown 0.13.2", "parking_lot", ] +[[package]] +name = "gix-ignore" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f958d7fe0858fb52a7573e279201e09df990874e21d2ef3df4ac85653fb88442" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "unicode-bom", +] + [[package]] name = "gix-index" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "717ab601ece7921f59fe86849dbe27d44a46ebb883b5885732c4f30df4996177" +checksum = "fa282756760f79c401d4f4f42588fbb4aa27bbb4b0830f3b4d3480c21a4ac5a7" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.2.1", "bstr", "btoi", "filetime", @@ -783,9 +791,9 @@ dependencies = [ [[package]] name = "gix-mailmap" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b66aea5e52875cd4915f4957a6f4b75831a36981e2ec3f5fad9e370e444fe1a" +checksum = "e8856cec3bdc3610c06970d28b6cb20a0c6621621cf9a8ec48cbd23f2630f362" dependencies = [ "bstr", "gix-actor", @@ -794,9 +802,9 @@ dependencies = [ [[package]] name = "gix-object" -version = "0.28.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df068db9180ee935fbb70504848369e270bdcb576b05c0faa8b9fd3b86fc017" +checksum = "c9bb30ce0818d37096daa29efe361a4bc6dd0b51a5726598898be7e9a40a01e1" dependencies = [ "bstr", "btoi", @@ -813,9 +821,9 @@ dependencies = [ [[package]] name = "gix-odb" -version = "0.43.1" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83af2e3e36005bfe010927f0dff41fb5acc3e3d89c6f1174135b3a34086bda2" +checksum = "5cd87fd2a4884899954daa06371ecd55b40e2c4b708e94fe70d869864d1cd552" dependencies = [ "arc-swap", "gix-features", @@ -831,9 +839,9 @@ dependencies = [ [[package]] name = "gix-pack" -version = "0.33.2" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9401911c7fe032ad7b31c6a6b5be59cb283d1d6c999417a8215056efe6d635f3" +checksum = "e9914b411b8068322b877af7774fd0f283b25b141969cef2536ed09a2cf9fac1" dependencies = [ "clru", "gix-chunk", @@ -853,24 +861,26 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32370dce200bb951df013e03dff35b4233fc7a89458642b047629b91734a7e19" +checksum = "7f6581146846102b54702f1cadb98f79f00b996bc8470edc24645f460060d276" dependencies = [ "bstr", + "home", + "once_cell", "thiserror", ] [[package]] name = "gix-prompt" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3034d4d935aef2c7bf719aaa54b88c520e82413118d886ae880a31d5bdee57" +checksum = "78c5086dbabb66cb29d1dec4636cc0357e76fc95da682c149ec96dd97222697f" dependencies = [ "gix-command", "gix-config-value", - "nix", "parking_lot", + "rustix", "thiserror", ] @@ -887,12 +897,13 @@ dependencies = [ [[package]] name = "gix-ref" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4e909396ed3b176823991ccc391c276ae2a015e54edaafa3566d35123cfac9d" +checksum = "2bf64922331b0abd855e75ba3148b072ce2b99e31cd9d1998b87b341e9dbb67e" dependencies = [ "gix-actor", "gix-features", + "gix-fs", "gix-hash", "gix-lock", "gix-object", @@ -906,9 +917,9 @@ dependencies = [ [[package]] name = "gix-refspec" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aba332462bda2e8efeae4302b39a6ed01ad56ef772fd5b7ef197cf2798294d65" +checksum = "f520fd43ef706cafe14f4d5a196303c173da1b8cea92ab30fef7d38e866f6015" dependencies = [ "bstr", "gix-hash", @@ -920,9 +931,9 @@ dependencies = [ [[package]] name = "gix-revision" -version = "0.12.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6f6ff53f888858afc24bf12628446a14279ceec148df6194481f306f553ad2" +checksum = "810f35e9afeccca999d5d348b239f9c162353127d2e13ff3240e31b919e35476" dependencies = [ "bstr", "gix-date", @@ -934,15 +945,14 @@ dependencies = [ [[package]] name = "gix-sec" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ffa5bf0772f9b01de501c035b6b084cf9b8bb07dec41e3afc6a17336a65f47" +checksum = "d59c51b67330c78abc069a3aec920dcb301b858739ca8414ce74c8df2d33734e" dependencies = [ - "bitflags 1.3.2", - "dirs", + "bitflags 2.2.1", "gix-path", "libc", - "windows 0.43.0", + "windows", ] [[package]] @@ -961,9 +971,9 @@ dependencies = [ [[package]] name = "gix-traverse" -version = "0.24.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd9a4a07bb22168dc79c60e1a6a41919d198187ca83d8a5940ad8d7122a45df3" +checksum = "a5be1e807f288c33bb005075111886cceb43ed8a167b3182a0f62c186e2a0dd1" dependencies = [ "gix-hash", "gix-hashtable", @@ -973,9 +983,9 @@ dependencies = [ [[package]] name = "gix-url" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a22b4b32ad14d68f7b7fb6458fa58d44b01797d94c1b8f4db2d9c7b3c366b5" +checksum = "3b7e76c8259755bc0ef8f6be85943475a3f1ee26ae82bcc621eb0e704be63bd9" dependencies = [ "bstr", "gix-features", @@ -985,6 +995,15 @@ dependencies = [ "url", ] +[[package]] +name = "gix-utils" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c10b69beac219acb8df673187a1f07dde2d74092f974fb3f9eb385aeb667c909" +dependencies = [ + "fastrand", +] + [[package]] name = "gix-validate" version = "0.7.4" @@ -997,15 +1016,18 @@ dependencies = [ [[package]] name = "gix-worktree" -version = "0.15.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54ec9a000b4f24af706c3cc680c7cda235656cbe3216336522f5692773b8a301" +checksum = "4753efd398078a1d049a7ab581730491cb1bfc750e179a362be5bd35042f7b53" dependencies = [ "bstr", + "filetime", "gix-attributes", "gix-features", + "gix-fs", "gix-glob", "gix-hash", + "gix-ignore", "gix-index", "gix-object", "gix-path", @@ -1315,7 +1337,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows 0.48.0", + "windows", ] [[package]] @@ -1426,6 +1448,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kstring" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" +dependencies = [ + "static_assertions", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1459,9 +1490,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" +checksum = "36eb31c1778188ae1e64398743890d0877fef36d11521ac60406b42016e8c2cf" [[package]] name = "lock_api" @@ -1537,18 +1568,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "nix" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", - "static_assertions", -] - [[package]] name = "nom" version = "7.1.3" @@ -1776,9 +1795,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.11" +version = "0.37.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" +checksum = "a0661814f891c57c930a610266415528da53c4933e6dea5fb350cbfe048a9ece" dependencies = [ "bitflags 1.3.2", "errno", @@ -2232,9 +2251,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-bom" -version = "1.1.4" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63ec69f541d875b783ca40184d655f2927c95f0bffd486faa83cd3ac3529ec32" +checksum = "98e90c70c9f0d4d1ee6d0a7d04aa06cb9bbd53d8cfbdd62a0269a7c2eb640552" [[package]] name = "unicode-general-category" @@ -2409,21 +2428,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.43.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows" version = "0.48.0" diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml index 8a226a0bb..978af3982 100644 --- a/helix-vcs/Cargo.toml +++ b/helix-vcs/Cargo.toml @@ -17,7 +17,7 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p parking_lot = "0.12" arc-swap = { version = "1.6.0" } -gix = { version = "0.43.0", default-features = false , optional = true } +gix = { version = "0.44.0", default-features = false , optional = true } imara-diff = "0.1.5" anyhow = "1" diff --git a/helix-vcs/src/git.rs b/helix-vcs/src/git.rs index 00a2c596d..cd28d5e48 100644 --- a/helix-vcs/src/git.rs +++ b/helix-vcs/src/git.rs @@ -23,7 +23,7 @@ impl Git { // This path depends on the install location of git and therefore requires some overhead to lookup // This is basically only used on windows and has some overhead hence it's disabled on other platforms. // `gitoxide` doesn't use this as default - let config = gix::permissions::Config { + let config = gix::open::permissions::Config { system: true, git: true, user: true, @@ -32,19 +32,24 @@ impl Git { git_binary: cfg!(windows), }; // change options for config permissions without touching anything else - git_open_opts_map.reduced = git_open_opts_map.reduced.permissions(gix::Permissions { + git_open_opts_map.reduced = git_open_opts_map + .reduced + .permissions(gix::open::Permissions { + config, + ..gix::open::Permissions::default_for_level(gix::sec::Trust::Reduced) + }); + git_open_opts_map.full = git_open_opts_map.full.permissions(gix::open::Permissions { config, - ..gix::Permissions::default_for_level(gix::sec::Trust::Reduced) - }); - git_open_opts_map.full = git_open_opts_map.full.permissions(gix::Permissions { - config, - ..gix::Permissions::default_for_level(gix::sec::Trust::Full) + ..gix::open::Permissions::default_for_level(gix::sec::Trust::Full) }); - let mut open_options = gix::discover::upwards::Options::default(); - if let Some(ceiling_dir) = ceiling_dir { - open_options.ceiling_dirs = vec![ceiling_dir.to_owned()]; - } + let open_options = gix::discover::upwards::Options { + ceiling_dirs: ceiling_dir + .map(|dir| vec![dir.to_owned()]) + .unwrap_or_default(), + dot_git_only: true, + ..Default::default() + }; let res = ThreadSafeRepository::discover_with_environment_overrides_opts( path, From 2836ea2ac40bd54ec1b00ffcd5927cdb4b7724d3 Mon Sep 17 00:00:00 2001 From: Vitalii Solodilov Date: Thu, 27 Apr 2023 17:30:15 +0300 Subject: [PATCH 148/260] feat: add a config option to exclude declaration from LSP references (#6886) * feat: added the config option to exclude declaration from reference query Fixes: #5344 * fix: review * fix: review --- book/src/configuration.md | 1 + helix-lsp/src/client.rs | 3 ++- helix-term/src/commands/lsp.rs | 8 +++++++- helix-view/src/editor.rs | 3 +++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index 1fdbf0052..253a07269 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -128,6 +128,7 @@ The following statusline elements can be configured: | `display-inlay-hints` | Display inlay hints[^2] | `false` | | `display-signature-help-docs` | Display docs under signature help popup | `true` | | `snippets` | Enables snippet completions. Requires a server restart (`:lsp-restart`) to take effect after `:config-reload`/`:set`. | `true` | +| `goto-reference-include-declaration` | Include declaration in the goto references popup. | `true` | [^1]: By default, a progress spinner is shown in the statusline beside the file path. [^2]: You may also have to activate them in the LSP config for them to appear, not just in Helix. diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 93e822c44..89b714e21 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -1167,6 +1167,7 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + include_declaration: bool, work_done_token: Option, ) -> Option>> { let capabilities = self.capabilities.get().unwrap(); @@ -1183,7 +1184,7 @@ impl Client { position, }, context: lsp::ReferenceContext { - include_declaration: true, + include_declaration, }, work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token }, partial_result_params: lsp::PartialResultParams { diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index b5d1d337e..0ad6fb7eb 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -1078,13 +1078,19 @@ pub fn goto_implementation(cx: &mut Context) { } pub fn goto_reference(cx: &mut Context) { + let config = cx.editor.config(); 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 = match language_server.goto_reference(doc.identifier(), pos, None) { + let future = match language_server.goto_reference( + doc.identifier(), + pos, + config.lsp.goto_reference_include_declaration, + None, + ) { Some(future) => future, None => { cx.editor diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 52f86f2da..fd0abe91d 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -354,6 +354,8 @@ pub struct LspConfig { pub display_inlay_hints: bool, /// Whether to enable snippet support pub snippets: bool, + /// Whether to include declaration in the goto reference query + pub goto_reference_include_declaration: bool, } impl Default for LspConfig { @@ -365,6 +367,7 @@ impl Default for LspConfig { display_signature_help_docs: true, display_inlay_hints: false, snippets: true, + goto_reference_include_declaration: true, } } } From 9cdc6b2e8a0193881297e15641cd801384cd8865 Mon Sep 17 00:00:00 2001 From: ap29600 <66381278+ap29600@users.noreply.github.com> Date: Thu, 27 Apr 2023 16:32:21 +0200 Subject: [PATCH 149/260] Change Odin grammar to `ap29600/tree-sitter-odin` (#6766) * Change Odin grammar to `ap29600/tree-sitter-odin` The previously adopted grammar, `MineBill/tree-sitter-odin`, is unmaintained and mentions my repository as an alternative source. * update queries * docgen * fix queries * Update runtime/queries/odin/highlights.scm Co-authored-by: Michael Davis * remove `ERROR` query for `odin` * track the latest rev in `ap29600/tree-sitter-odin` * runtime/queries/odin/highlights.scm: update rune highlight class Co-authored-by: Michael Davis --------- Co-authored-by: Michael Davis --- book/src/generated/lang-support.md | 2 +- languages.toml | 2 +- runtime/queries/odin/highlights.scm | 151 ++++------------------------ runtime/queries/odin/indents.scm | 16 +++ 4 files changed, 36 insertions(+), 135 deletions(-) create mode 100644 runtime/queries/odin/indents.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 900664d22..b08bf1558 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -98,7 +98,7 @@ | nu | ✓ | | | | | ocaml | ✓ | | ✓ | `ocamllsp` | | ocaml-interface | ✓ | | | `ocamllsp` | -| odin | ✓ | | | `ols` | +| odin | ✓ | | ✓ | `ols` | | opencl | ✓ | ✓ | ✓ | `clangd` | | openscad | ✓ | | | `openscad-lsp` | | org | ✓ | | | | diff --git a/languages.toml b/languages.toml index 00df32394..14da46c15 100644 --- a/languages.toml +++ b/languages.toml @@ -1675,7 +1675,7 @@ indent = { tab-width = 4, unit = "\t" } [[grammar]] name = "odin" -source = { git = "https://github.com/MineBill/tree-sitter-odin", rev = "da885f4a387f169b9b69fe0968259ee257a8f69a" } +source = { git = "https://github.com/ap29600/tree-sitter-odin", rev = "b219207e49ffca2952529d33e94ed63b1b75c4f1" } [[language]] name = "meson" diff --git a/runtime/queries/odin/highlights.scm b/runtime/queries/odin/highlights.scm index 1d801ff1b..d474bf3a2 100644 --- a/runtime/queries/odin/highlights.scm +++ b/runtime/queries/odin/highlights.scm @@ -1,141 +1,26 @@ -; Function calls +(keyword) @keyword +(operator) @operator -(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 +(int_literal) @constant.numeric.integer +(float_literal) @constant.numeric.float +(rune_literal) @constant.character +(bool_literal) @constant.builtin.boolean +(nil) @constant.builtin -[ - (interpreted_string_literal) - (raw_string_literal) - (rune_literal) -] @string +(type_identifier) @type +(package_identifier) @namespace +(label_identifier) @label +(interpreted_string_literal) @string +(raw_string_literal) @string (escape_sequence) @constant.character.escape -(int_literal) @constant.numeric.integer -(float_literal) @constant.numeric.float -(imaginary_literal) @constant.numeric +(comment) @comment +(const_identifier) @constant -[ - (true) - (false) -] @constant.builtin.boolean -[ - (nil) - (undefined) -] @constant.builtin +(compiler_directive) @keyword.directive +(calling_convention) @string.special.symbol -(comment) @comment.line +(identifier) @variable +(pragma_identifier) @keyword.directive diff --git a/runtime/queries/odin/indents.scm b/runtime/queries/odin/indents.scm new file mode 100644 index 000000000..a3b90a38d --- /dev/null +++ b/runtime/queries/odin/indents.scm @@ -0,0 +1,16 @@ +[ + (foreign_block) + (block) + (compound_literal) + (proc_call) + (assignment_statement) + (const_declaration) + (var_declaration) + (switch_statement) +] @indent + +[ + ")" + "}" +] @outdent + From 204d1eba4b1bb09d2e861986d6b6e8b868d16afe Mon Sep 17 00:00:00 2001 From: jorge <20152130+chorcheus@users.noreply.github.com> Date: Thu, 27 Apr 2023 21:57:05 +0200 Subject: [PATCH 150/260] feat(commands): add clear-register typable command (#5695) Co-authored-by: Jorge --- book/src/generated/typable-cmd.md | 1 + helix-core/src/register.rs | 8 +++++++ helix-term/src/commands/typed.rs | 39 +++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index a9d68b75a..ae28a9ba0 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -78,3 +78,4 @@ | `:pipe-to` | Pipe each selection to the shell command, ignoring output. | | `:run-shell-command`, `:sh` | Run a shell command | | `:reset-diff-change`, `:diffget`, `:diffg` | Reset the diff change at the cursor position. | +| `:clear-register` | Clear given register. If no argument is provided, clear all registers. | diff --git a/helix-core/src/register.rs b/helix-core/src/register.rs index 52eb6e3e7..df68a7594 100644 --- a/helix-core/src/register.rs +++ b/helix-core/src/register.rs @@ -78,4 +78,12 @@ impl Registers { pub fn inner(&self) -> &HashMap { &self.inner } + + pub fn clear(&mut self) { + self.inner.clear(); + } + + pub fn remove(&mut self, name: char) -> Option { + self.inner.remove(&name) + } } diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index ea82dc366..fe92798ba 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -2167,6 +2167,38 @@ fn reset_diff_change( Ok(()) } +fn clear_register( + cx: &mut compositor::Context, + args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + + ensure!(args.len() <= 1, ":clear-register takes at most 1 argument"); + if args.is_empty() { + cx.editor.registers.clear(); + cx.editor.set_status("All registers cleared"); + return Ok(()); + } + + ensure!( + args[0].chars().count() == 1, + format!("Invalid register {}", args[0]) + ); + let register = args[0].chars().next().unwrap_or_default(); + match cx.editor.registers.remove(register) { + Some(_) => cx + .editor + .set_status(format!("Register {} cleared", register)), + None => cx + .editor + .set_error(format!("Register {} not found", register)), + } + Ok(()) +} + pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "quit", @@ -2720,6 +2752,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: reset_diff_change, signature: CommandSignature::none(), }, + TypableCommand { + name: "clear-register", + aliases: &[], + doc: "Clear given register. If no argument is provided, clear all registers.", + fun: clear_register, + signature: CommandSignature::none(), + }, ]; pub static TYPABLE_COMMAND_MAP: Lazy> = From 9c6c63a2be30252a6207f4aebb5e0f76f746b4c8 Mon Sep 17 00:00:00 2001 From: Timothy DeHerrera Date: Fri, 28 Apr 2023 03:21:34 -0600 Subject: [PATCH 151/260] inject language based on file extension & shebang (#3970) * inject language based on file extension Nodes can now be captured with "injection.filename". If this capture contains a valid file extension known to Helix, then the content will be highlighted as that language. * inject language by shebang Nodes can now be captured with "injection.shebang". If this capture contains a valid shebang line known to Helix, then the content will be highlighted as the language the shebang calls for. * add documentation for language injection * nix: fix highlights The `@` is now highlighted properly on either side of the function arg. Also, extending the phases with `buildPhase = prev.buildPhase + ''''` is now highlighted properly. Fix highlighting of `''$` style escapes (requires tree-sitter-nix bump) Fix `inherit` highlighting. * simplify injection_for_match Split out injection pair logic into its own method to make the overall flow easier to follow. Also transform the top-level function into a method on a HighlightConfiguration. * markdown: add shebang injection query --- book/src/SUMMARY.md | 1 + book/src/guides/injection.md | 57 +++++++ helix-core/src/syntax.rs | 207 +++++++++++++++--------- helix-term/src/ui/markdown.rs | 6 +- languages.toml | 2 +- runtime/queries/markdown/injections.scm | 4 + runtime/queries/nix/highlights.scm | 5 +- runtime/queries/nix/injections.scm | 18 ++- 8 files changed, 216 insertions(+), 84 deletions(-) create mode 100644 book/src/guides/injection.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 6e780b87f..ba330cf77 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -16,3 +16,4 @@ - [Adding languages](./guides/adding_languages.md) - [Adding textobject queries](./guides/textobject.md) - [Adding indent queries](./guides/indent.md) + - [Adding injection queries](./guides/injection.md) diff --git a/book/src/guides/injection.md b/book/src/guides/injection.md new file mode 100644 index 000000000..18c474cfe --- /dev/null +++ b/book/src/guides/injection.md @@ -0,0 +1,57 @@ +# Adding Injection Queries + +Writing language injection queries allows one to highlight a specific node as a different language. +In addition to the [standard](upstream-docs) language injection options used by tree-sitter, there +are a few Helix specific extensions that allow for more control. + +And example of a simple query that would highlight all strings as bash in Nix: +```scm +((string_expression (string_fragment) @injection.content) + (#set! injection.language "bash")) +``` + +## Capture Types + +- `@injection.language` (standard): +The captured node may contain the language name used to highlight the node captured by +`@injection.content`. + +- `@injection.content` (standard): +Marks the content to be highlighted as the language captured with `@injection.language` _et al_. + +- `@injection.filename` (extension): +The captured node may contain a filename with a file-extension known to Helix, +highlighting `@injection.content` as that language. This uses the language extensions defined in +both the default languages.toml distributed with Helix, as well as user defined languages. + +- `@injection.shebang` (extension): +The captured node may contain a shebang used to choose a language to highlight as. This also uses +the shebangs defined in the default and user `languages.toml`. + +## Settings + +- `injection.combined` (standard): +Indicates that all the matching nodes in the tree should have their content parsed as one +nested document. + +- `injection.language` (standard): +Forces the captured content to be highlighted as the given language + +- `injection.include-children` (standard): +Indicates that the content node’s entire text should be re-parsed, including the text of its child +nodes. By default, child nodes’ text will be excluded from the injected document. + +- `injection.include-unnamed-children` (extension): +Same as `injection.include-children` but only for unnamed child nodes. + +## Predicates + +- `#eq?` (standard): +The first argument (a capture) must be equal to the second argument +(a capture or a string). + +- `#match?` (standard): +The first argument (a capture) must match the regex given in the +second argument (a string). + +[upstream-docs]: http://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index c34ea81a3..6514b40f5 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -662,9 +662,8 @@ impl Loader { pub fn language_config_for_shebang(&self, source: &Rope) -> Option> { let line = Cow::from(source.line(0)); - static SHEBANG_REGEX: Lazy = Lazy::new(|| { - Regex::new(r"^#!\s*(?:\S*[/\\](?:env\s+(?:\-\S+\s+)*)?)?([^\s\.\d]+)").unwrap() - }); + static SHEBANG_REGEX: Lazy = + Lazy::new(|| Regex::new(&["^", SHEBANG].concat()).unwrap()); let configuration_id = SHEBANG_REGEX .captures(&line) .and_then(|cap| self.language_config_ids_by_shebang.get(&cap[1])); @@ -686,15 +685,14 @@ impl Loader { .cloned() } - pub fn language_configuration_for_injection_string( - &self, - string: &str, - ) -> Option> { + /// Unlike language_config_for_language_id, which only returns Some for an exact id, this + /// function will perform a regex match on the given string to find the closest language match. + pub fn language_config_for_name(&self, name: &str) -> Option> { let mut best_match_length = 0; let mut best_match_position = None; for (i, configuration) in self.language_configs.iter().enumerate() { if let Some(injection_regex) = &configuration.injection_regex { - if let Some(mat) = injection_regex.find(string) { + if let Some(mat) = injection_regex.find(name) { let length = mat.end() - mat.start(); if length > best_match_length { best_match_position = Some(i); @@ -704,11 +702,20 @@ impl Loader { } } - if let Some(i) = best_match_position { - let configuration = &self.language_configs[i]; - return Some(configuration.clone()); + best_match_position.map(|i| self.language_configs[i].clone()) + } + + pub fn language_configuration_for_injection_string( + &self, + capture: &InjectionLanguageMarker, + ) -> Option> { + match capture { + InjectionLanguageMarker::Name(string) => self.language_config_for_name(string), + InjectionLanguageMarker::Filename(file) => self.language_config_for_file_name(file), + InjectionLanguageMarker::Shebang(shebang) => { + self.language_config_for_language_id(shebang) + } } - None } pub fn language_configs(&self) -> impl Iterator> { @@ -800,7 +807,7 @@ impl Syntax { queue.push_back(self.root); let scopes = self.loader.scopes.load(); - let injection_callback = |language: &str| { + let injection_callback = |language: &InjectionLanguageMarker| { self.loader .language_configuration_for_injection_string(language) .and_then(|language_config| language_config.highlight_config(&scopes)) @@ -961,12 +968,9 @@ impl Syntax { ); let mut injections = Vec::new(); for mat in matches { - let (language_name, content_node, included_children) = injection_for_match( - &layer.config, - &layer.config.injections_query, - &mat, - source_slice, - ); + let (injection_capture, content_node, included_children) = layer + .config + .injection_for_match(&layer.config.injections_query, &mat, source_slice); // Explicitly remove this match so that none of its other captures will remain // in the stream of captures. @@ -974,9 +978,10 @@ impl Syntax { // If a language is found with the given name, then add a new language layer // to the highlighted document. - if let (Some(language_name), Some(content_node)) = (language_name, content_node) + if let (Some(injection_capture), Some(content_node)) = + (injection_capture, content_node) { - if let Some(config) = (injection_callback)(&language_name) { + if let Some(config) = (injection_callback)(&injection_capture) { let ranges = intersect_ranges(&layer.ranges, &[content_node], included_children); @@ -1001,14 +1006,11 @@ impl Syntax { ); for mat in matches { let entry = &mut injections_by_pattern_index[mat.pattern_index]; - let (language_name, content_node, included_children) = injection_for_match( - &layer.config, - combined_injections_query, - &mat, - source_slice, - ); - if language_name.is_some() { - entry.0 = language_name; + let (injection_capture, content_node, included_children) = layer + .config + .injection_for_match(combined_injections_query, &mat, source_slice); + if injection_capture.is_some() { + entry.0 = injection_capture; } if let Some(content_node) = content_node { entry.1.push(content_node); @@ -1395,6 +1397,8 @@ pub struct HighlightConfiguration { non_local_variable_patterns: Vec, injection_content_capture_index: Option, injection_language_capture_index: Option, + injection_filename_capture_index: Option, + injection_shebang_capture_index: Option, local_scope_capture_index: Option, local_def_capture_index: Option, local_def_value_capture_index: Option, @@ -1538,6 +1542,8 @@ impl HighlightConfiguration { // Store the numeric ids for all of the special captures. let mut injection_content_capture_index = None; let mut injection_language_capture_index = None; + let mut injection_filename_capture_index = None; + let mut injection_shebang_capture_index = None; let mut local_def_capture_index = None; let mut local_def_value_capture_index = None; let mut local_ref_capture_index = None; @@ -1558,6 +1564,8 @@ impl HighlightConfiguration { match name.as_str() { "injection.content" => injection_content_capture_index = i, "injection.language" => injection_language_capture_index = i, + "injection.filename" => injection_filename_capture_index = i, + "injection.shebang" => injection_shebang_capture_index = i, _ => {} } } @@ -1573,6 +1581,8 @@ impl HighlightConfiguration { non_local_variable_patterns, injection_content_capture_index, injection_language_capture_index, + injection_filename_capture_index, + injection_shebang_capture_index, local_scope_capture_index, local_def_capture_index, local_def_value_capture_index, @@ -1631,6 +1641,90 @@ impl HighlightConfiguration { self.highlight_indices.store(Arc::new(indices)); } + + fn injection_pair<'a>( + &self, + query_match: &QueryMatch<'a, 'a>, + source: RopeSlice<'a>, + ) -> (Option>, Option>) { + let mut injection_capture = None; + let mut content_node = None; + + for capture in query_match.captures { + let index = Some(capture.index); + if index == self.injection_language_capture_index { + let name = byte_range_to_str(capture.node.byte_range(), source); + injection_capture = Some(InjectionLanguageMarker::Name(name)); + } else if index == self.injection_filename_capture_index { + let name = byte_range_to_str(capture.node.byte_range(), source); + let path = Path::new(name.as_ref()).to_path_buf(); + injection_capture = Some(InjectionLanguageMarker::Filename(path.into())); + } else if index == self.injection_shebang_capture_index { + let node_slice = source.byte_slice(capture.node.byte_range()); + + // some languages allow space and newlines before the actual string content + // so a shebang could be on either the first or second line + let lines = if let Ok(end) = node_slice.try_line_to_byte(2) { + node_slice.byte_slice(..end) + } else { + node_slice + }; + + static SHEBANG_REGEX: Lazy = Lazy::new(|| Regex::new(SHEBANG).unwrap()); + + injection_capture = SHEBANG_REGEX + .captures(&Cow::from(lines)) + .map(|cap| InjectionLanguageMarker::Shebang(cap[1].to_owned())) + } else if index == self.injection_content_capture_index { + content_node = Some(capture.node); + } + } + (injection_capture, content_node) + } + + fn injection_for_match<'a>( + &self, + query: &'a Query, + query_match: &QueryMatch<'a, 'a>, + source: RopeSlice<'a>, + ) -> ( + Option>, + Option>, + IncludedChildren, + ) { + let (mut injection_capture, content_node) = self.injection_pair(query_match, source); + + let mut included_children = IncludedChildren::default(); + for prop in query.property_settings(query_match.pattern_index) { + match prop.key.as_ref() { + // In addition to specifying the language name via the text of a + // captured node, it can also be hard-coded via a `#set!` predicate + // that sets the injection.language key. + "injection.language" if injection_capture.is_none() => { + injection_capture = prop + .value + .as_ref() + .map(|s| InjectionLanguageMarker::Name(s.as_ref().into())); + } + + // By default, injections do not include the *children* of an + // `injection.content` node - only the ranges that belong to the + // node itself. This can be changed using a `#set!` predicate that + // sets the `injection.include-children` key. + "injection.include-children" => included_children = IncludedChildren::All, + + // Some queries might only exclude named children but include unnamed + // children in their `injection.content` node. This can be enabled using + // a `#set!` predicate that sets the `injection.include-unnamed-children` key. + "injection.include-unnamed-children" => { + included_children = IncludedChildren::Unnamed + } + _ => {} + } + } + + (injection_capture, content_node, included_children) + } } impl<'a> HighlightIterLayer<'a> { @@ -2042,56 +2136,15 @@ impl<'a> Iterator for HighlightIter<'a> { } } -fn injection_for_match<'a>( - config: &HighlightConfiguration, - query: &'a Query, - query_match: &QueryMatch<'a, 'a>, - source: RopeSlice<'a>, -) -> (Option>, Option>, IncludedChildren) { - let content_capture_index = config.injection_content_capture_index; - let language_capture_index = config.injection_language_capture_index; - - let mut language_name = None; - let mut content_node = None; - for capture in query_match.captures { - let index = Some(capture.index); - if index == language_capture_index { - let name = byte_range_to_str(capture.node.byte_range(), source); - language_name = Some(name); - } else if index == content_capture_index { - content_node = Some(capture.node); - } - } - - let mut included_children = IncludedChildren::default(); - for prop in query.property_settings(query_match.pattern_index) { - match prop.key.as_ref() { - // In addition to specifying the language name via the text of a - // captured node, it can also be hard-coded via a `#set!` predicate - // that sets the injection.language key. - "injection.language" => { - if language_name.is_none() { - language_name = prop.value.as_ref().map(|s| s.as_ref().into()) - } - } - - // By default, injections do not include the *children* of an - // `injection.content` node - only the ranges that belong to the - // node itself. This can be changed using a `#set!` predicate that - // sets the `injection.include-children` key. - "injection.include-children" => included_children = IncludedChildren::All, - - // Some queries might only exclude named children but include unnamed - // children in their `injection.content` node. This can be enabled using - // a `#set!` predicate that sets the `injection.include-unnamed-children` key. - "injection.include-unnamed-children" => included_children = IncludedChildren::Unnamed, - _ => {} - } - } - - (language_name, content_node, included_children) +#[derive(Debug, Clone)] +pub enum InjectionLanguageMarker<'a> { + Name(Cow<'a, str>), + Filename(Cow<'a, Path>), + Shebang(String), } +const SHEBANG: &str = r"#!\s*(?:\S*[/\\](?:env\s+(?:\-\S+\s+)*)?)?([^\s\.\d]+)"; + pub struct Merge { iter: I, spans: Box)>>, diff --git a/helix-term/src/ui/markdown.rs b/helix-term/src/ui/markdown.rs index 87136992c..fea3de78f 100644 --- a/helix-term/src/ui/markdown.rs +++ b/helix-term/src/ui/markdown.rs @@ -9,7 +9,7 @@ use std::sync::Arc; use pulldown_cmark::{CodeBlockKind, Event, HeadingLevel, Options, Parser, Tag}; use helix_core::{ - syntax::{self, HighlightEvent, Syntax}, + syntax::{self, HighlightEvent, InjectionLanguageMarker, Syntax}, Rope, }; use helix_view::{ @@ -47,7 +47,9 @@ pub fn highlighted_code_block<'a>( let rope = Rope::from(text.as_ref()); let syntax = config_loader - .language_configuration_for_injection_string(language) + .language_configuration_for_injection_string(&InjectionLanguageMarker::Name( + language.into(), + )) .and_then(|config| config.highlight_config(theme.scopes())) .map(|config| Syntax::new(&rope, config, Arc::clone(&config_loader))); diff --git a/languages.toml b/languages.toml index 14da46c15..9a0a538a0 100644 --- a/languages.toml +++ b/languages.toml @@ -591,7 +591,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "nix" -source = { git = "https://github.com/nix-community/tree-sitter-nix", rev = "6b71a810c0acd49b980c50fc79092561f7cee307" } +source = { git = "https://github.com/nix-community/tree-sitter-nix", rev = "1b69cf1fa92366eefbe6863c184e5d2ece5f187d" } [[language]] name = "ruby" diff --git a/runtime/queries/markdown/injections.scm b/runtime/queries/markdown/injections.scm index e88393512..80977459e 100644 --- a/runtime/queries/markdown/injections.scm +++ b/runtime/queries/markdown/injections.scm @@ -1,5 +1,9 @@ ; From nvim-treesitter/nvim-treesitter +(fenced_code_block + (code_fence_content) @injection.shebang @injection.content + (#set! injection.include-unnamed-children)) + (fenced_code_block (info_string (language) @injection.language) diff --git a/runtime/queries/nix/highlights.scm b/runtime/queries/nix/highlights.scm index a998aa644..4633e1786 100644 --- a/runtime/queries/nix/highlights.scm +++ b/runtime/queries/nix/highlights.scm @@ -47,8 +47,10 @@ (float_expression) @constant.numeric.float (escape_sequence) @constant.character.escape +(dollar_escape) @constant.character.escape (function_expression + "@"? @punctuation.delimiter universal: (identifier) @variable.parameter "@"? @punctuation.delimiter ) @@ -82,7 +84,8 @@ (binding attrpath: (attrpath attr: (identifier)) @variable.other.member) -(inherit_from attrs: (inherited_attrs attr: (identifier) @variable)) +(inherit_from attrs: (inherited_attrs attr: (identifier) @variable.other.member)) +(inherited_attrs attr: (identifier) @variable) (has_attr_expression expression: (_) diff --git a/runtime/queries/nix/injections.scm b/runtime/queries/nix/injections.scm index 62b48233a..1da63ce08 100644 --- a/runtime/queries/nix/injections.scm +++ b/runtime/queries/nix/injections.scm @@ -10,9 +10,11 @@ ; such as those of stdenv.mkDerivation. ((binding attrpath: (attrpath (identifier) @_path) - expression: (indented_string_expression - (string_fragment) @injection.content)) - (#match? @_path "(^\\w*Phase|(pre|post)\\w*|(.*\\.)?\\w*([sS]cript|[hH]ook)|(.*\\.)?startup)$") + expression: [ + (indented_string_expression (string_fragment) @injection.content) + (binary_expression (indented_string_expression (string_fragment) @injection.content)) + ]) + (#match? @_path "(^\\w*Phase|command|(pre|post)\\w*|(.*\\.)?\\w*([sS]cript|[hH]ook)|(.*\\.)?startup)$") (#set! injection.language "bash") (#set! injection.combined)) @@ -150,3 +152,13 @@ ; (#match? @_func "(^|\\.)writeFSharp(Bin)?$") ; (#set! injection.language "f-sharp") ; (#set! injection.combined)) + +((apply_expression + function: (apply_expression function: (_) @_func + argument: (string_expression (string_fragment) @injection.filename)) + argument: (indented_string_expression (string_fragment) @injection.content)) + (#match? @_func "(^|\\.)write(Text|Script(Bin)?)$") + (#set! injection.combined)) + +((indented_string_expression (string_fragment) @injection.shebang @injection.content) + (#set! injection.combined)) \ No newline at end of file From 6a1bb81f1022533c226395aaa41439ab1ea41dd4 Mon Sep 17 00:00:00 2001 From: Evgeniy Tatarkin Date: Fri, 28 Apr 2023 19:05:14 +0300 Subject: [PATCH 152/260] Sort the buffer picker by most recent access (#2980) --- helix-term/src/commands.rs | 18 +++++++++++++----- helix-view/src/document.rs | 9 +++++++++ helix-view/src/editor.rs | 8 ++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 5a75553cd..88393ff4c 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2473,6 +2473,7 @@ fn buffer_picker(cx: &mut Context) { path: Option, is_modified: bool, is_current: bool, + focused_at: std::time::Instant, } impl ui::menu::Item for BufferMeta { @@ -2505,14 +2506,21 @@ fn buffer_picker(cx: &mut Context) { path: doc.path().cloned(), is_modified: doc.is_modified(), is_current: doc.id() == current, + focused_at: doc.focused_at, }; + let mut items = cx + .editor + .documents + .values() + .map(|doc| new_meta(doc)) + .collect::>(); + + // mru + items.sort_unstable_by_key(|item| std::cmp::Reverse(item.focused_at)); + let picker = FilePicker::new( - cx.editor - .documents - .values() - .map(|doc| new_meta(doc)) - .collect(), + items, (), |cx, meta, action| { cx.editor.switch(meta.id, action); diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index eca600265..5ede5bc60 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -169,6 +169,9 @@ pub struct Document { diff_handle: Option, version_control_head: Option>>>, + + // when document was used for most-recent-used buffer picker + pub focused_at: std::time::Instant, } /// Inlay hints for a single `(Document, View)` combo. @@ -496,6 +499,7 @@ impl Document { diff_handle: None, config, version_control_head: None, + focused_at: std::time::Instant::now(), } } pub fn default(config: Arc>) -> Self { @@ -908,6 +912,11 @@ impl Document { } } + /// Mark document as recent used for MRU sorting + pub fn mark_as_focused(&mut self) { + self.focused_at = std::time::Instant::now(); + } + /// Remove a view's selection and inlay hints from this document. pub fn remove_view(&mut self, view_id: ViewId) { self.selections.remove(&view_id); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index fd0abe91d..005c66674 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1176,6 +1176,7 @@ impl Editor { let doc = doc_mut!(self, &doc_id); doc.ensure_view_init(view.id); view.sync_changes(doc); + doc.mark_as_focused(); align_view(doc, view, Align::Center); } @@ -1246,6 +1247,7 @@ impl Editor { let view_id = view!(self).id; let doc = doc_mut!(self, &id); doc.ensure_view_init(view_id); + doc.mark_as_focused(); return; } Action::HorizontalSplit | Action::VerticalSplit => { @@ -1267,6 +1269,7 @@ impl Editor { // initialize selection for view let doc = doc_mut!(self, &id); doc.ensure_view_init(view_id); + doc.mark_as_focused(); } } @@ -1417,6 +1420,7 @@ impl Editor { let view_id = self.tree.insert(view); let doc = doc_mut!(self, &doc_id); doc.ensure_view_init(view_id); + doc.mark_as_focused(); } self._refresh(); @@ -1471,6 +1475,10 @@ impl Editor { view.sync_changes(doc); } } + + let view = view!(self, view_id); + let doc = doc_mut!(self, &view.doc); + doc.mark_as_focused(); } pub fn focus_next(&mut self) { From 96720e7b841f602709c4e8f117555ed897affe53 Mon Sep 17 00:00:00 2001 From: 0rphee <0rph3e@proton.me> Date: Sat, 29 Apr 2023 14:21:15 -0600 Subject: [PATCH 153/260] [Theme - noctis] Refine multiple cursor highlighting Improve clarity when using multiple cursors --- runtime/themes/noctis.toml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/runtime/themes/noctis.toml b/runtime/themes/noctis.toml index 81733e637..3b996f6f3 100644 --- a/runtime/themes/noctis.toml +++ b/runtime/themes/noctis.toml @@ -5,6 +5,7 @@ ## GENERAL ============================== +'property' = { fg = "red" } # Regex group names. "warning" = { fg ="yellow", modifiers = ["bold"] } # Editor warnings. "error" = { bg = "mid-green", fg = "red", modifiers = ["bold"] } # Editor errors, like mis-typing a command. "info" = { fg = "mid-blue", bg = "mid-green" } # Code diagnostic info in gutter (LSP). @@ -29,11 +30,11 @@ '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.cursor' = { fg = "dark-green", bg = "white" } # Fallback cursor colour, non-primary cursors when there are multiple (shift-c). +'ui.cursor.primary' = { fg = "dark-green", bg = "light-blue" } # The primary cursor when there are multiple (shift-c). +'ui.cursor.insert' = { fg = "dark-green", bg = "light-blue" } # The cursor in insert mode (i). +'ui.cursor.select' = { fg = "dark-green", bg = "light-blue" } # The cursor in select mode (v). +'ui.cursor.match' = { fg = "dark-green", bg = "red", modifiers = ["bold"] } # The matching parentheses of that under the cursor. 'ui.selection' = { bg = "autocomp-green" } # All currently selected text. 'ui.selection.primary' = { bg = "autocomp-green" } # The primary selection when there are multiple. From f2ccc033321b528c4a8368de13d0cc42a95e5e6d Mon Sep 17 00:00:00 2001 From: 0rphee <0rph3e@proton.me> Date: Sat, 29 Apr 2023 14:29:04 -0600 Subject: [PATCH 154/260] [Theme - noctis] Change color for whitespace rendering and indent guides --- runtime/themes/noctis.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime/themes/noctis.toml b/runtime/themes/noctis.toml index 3b996f6f3..c7d33680e 100644 --- a/runtime/themes/noctis.toml +++ b/runtime/themes/noctis.toml @@ -45,8 +45,8 @@ '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.virtual.whitespace' = { fg = "light-gray"} # Whitespace markers in editing area. +'ui.virtual.indent-guide' = { fg = "light-gray" } # Indentation guides. 'ui.statusline' = { fg = "light-green", bg = "autocomp-green"} # Status line. 'ui.statusline.inactive' = { fg = "white", bg = "mid-green"} # Status line in unfocused windows. @@ -198,6 +198,7 @@ purple = "#918cff" white = "#b1cace" orange = "#ffa864" gray = "#5b858b" # mainly for comments/background text +light-gray = "#354e51" # used when whitespace rendering is enabled and for indent-guides red = "#e34e1b" dark-blue = "#19a2b7" From 77da0ae8cee941c9d4bcf6dc3dfaf0ff66846a9e Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Sun, 30 Apr 2023 16:20:13 +0200 Subject: [PATCH 155/260] downgrade gix log level to info (#6915) --- helix-vcs/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/helix-vcs/src/lib.rs b/helix-vcs/src/lib.rs index 4d3a3623b..63487fbcd 100644 --- a/helix-vcs/src/lib.rs +++ b/helix-vcs/src/lib.rs @@ -46,8 +46,8 @@ impl DiffProviderRegistry { .find_map(|provider| match provider.get_diff_base(file) { Ok(res) => Some(res), Err(err) => { - log::error!("{err:#?}"); - log::error!("failed to open diff base for {}", file.display()); + log::info!("{err:#?}"); + log::info!("failed to open diff base for {}", file.display()); None } }) @@ -59,8 +59,8 @@ impl DiffProviderRegistry { .find_map(|provider| match provider.get_current_head_name(file) { Ok(res) => Some(res), Err(err) => { - log::error!("{err:#?}"); - log::error!("failed to obtain current head name for {}", file.display()); + log::info!("{err:#?}"); + log::info!("failed to obtain current head name for {}", file.display()); None } }) From f52e81b1f340d13a7c7e80b8f8ad2ef30015d0ef Mon Sep 17 00:00:00 2001 From: sscheele Date: Sun, 30 Apr 2023 15:26:18 -0400 Subject: [PATCH 156/260] Update docs for `move_visual_line_*` (#6918) --- book/src/keymap.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index 173728f27..648dcfa96 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -32,8 +32,8 @@ | Key | Description | Command | | ----- | ----------- | ------- | | `h`, `Left` | Move left | `move_char_left` | -| `j`, `Down` | Move down | `move_line_down` | -| `k`, `Up` | Move up | `move_line_up` | +| `j`, `Down` | Move down | `move_visual_line_down` | +| `k`, `Up` | Move up | `move_visual_line_up` | | `l`, `Right` | Move right | `move_char_right` | | `w` | Move next word start | `move_next_word_start` | | `b` | Move previous word start | `move_prev_word_start` | @@ -218,6 +218,8 @@ Jumps to various locations. | `n` | Go to next buffer | `goto_next_buffer` | | `p` | Go to previous buffer | `goto_previous_buffer` | | `.` | Go to last modification in current file | `goto_last_modification` | +| `j` | Move down textual (instead of visual) line | `move_line_down` | +| `k` | Move up textual (instead of visual) line | `move_line_up` | #### Match mode From 5dcc891996b9191fd9ec30783cc0a35af21dec70 Mon Sep 17 00:00:00 2001 From: Rafael Madriz Date: Sun, 30 Apr 2023 16:26:38 -0300 Subject: [PATCH 157/260] tutor: Trim trailing white space (#6919) --- runtime/tutor | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/runtime/tutor b/runtime/tutor index df4d6d541..9bcb54a2d 100644 --- a/runtime/tutor +++ b/runtime/tutor @@ -23,7 +23,7 @@ ================================================================= = INTRODUCTION = ================================================================= - + Welcome to the Helix editor! Helix is different from editors you might be used to in that it is modal, meaning that it has different modes for editing text. The primary modes you will @@ -1146,13 +1146,13 @@ To uncomment the line, press Ctrl-c again. = 11.2 COMMENTING MULTIPLE LINES = ================================================================= -Using the selections and multi-cursor functionality, you can +Using the selections and multi-cursor functionality, you can comment multiple lines as long as it is under the selection or -cursors. +cursors. 1. Move your cursor to the line marked with '-->' below. -2. Now try to select or add more cursors the other lines marked - with '-->'. +2. Now try to select or add more cursors the other lines marked + with '-->'. 3. Comment those lines. --> How many are you going to comment? @@ -1170,7 +1170,7 @@ multiple cursors, they won't be uncommented but commented again. * Use Ctrl-c to comment a line under your cursor. Press Ctrl-c again to uncomment. - * To comment multiple lines, use the selections + * To comment multiple lines, use the selections and multi-cursors before typing Ctrl-c. * Commented lines cannot be uncommented but commented again. From efd09b6c7ccf8cdfde5856fd9db0d9b29ea5bd81 Mon Sep 17 00:00:00 2001 From: Rafael Madriz Date: Sun, 30 Apr 2023 18:35:34 -0300 Subject: [PATCH 158/260] tutor: Delete space between shorthand (#6920) --- runtime/tutor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tutor b/runtime/tutor index 9bcb54a2d..f0de5a2d5 100644 --- a/runtime/tutor +++ b/runtime/tutor @@ -941,7 +941,7 @@ lines. --> A horse is a horse, of course, of course, --> And no one can talk to a horse of course. - Note: * is like a shorthand for "/ y as all it really does is + Note: * is like a shorthand for "/y as all it really does is copy the selection into the / register. ================================================================= From b0b3f45b80931e73eadaf7e73f1981283b8e49fc Mon Sep 17 00:00:00 2001 From: Alexis-Lapierre <128792625+Alexis-Lapierre@users.noreply.github.com> Date: Mon, 1 May 2023 00:40:06 +0200 Subject: [PATCH 159/260] Conserve BOM and properly support UTF16 (#6497) --- helix-term/src/commands.rs | 3 +- helix-term/tests/test/commands/write.rs | 38 +++++ helix-view/src/document.rs | 178 +++++++++++++++++++----- helix-view/src/editor.rs | 4 +- 4 files changed, 186 insertions(+), 37 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 88393ff4c..882a8a1dc 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -5111,7 +5111,8 @@ async fn shell_impl_async( let output = if let Some(mut stdin) = process.stdin.take() { let input_task = tokio::spawn(async move { if let Some(input) = input { - helix_view::document::to_writer(&mut stdin, encoding::UTF_8, &input).await?; + helix_view::document::to_writer(&mut stdin, (encoding::UTF_8, false), &input) + .await?; } Ok::<_, anyhow::Error>(()) }); diff --git a/helix-term/tests/test/commands/write.rs b/helix-term/tests/test/commands/write.rs index 26515b7ae..f33c8aaf6 100644 --- a/helix-term/tests/test/commands/write.rs +++ b/helix-term/tests/test/commands/write.rs @@ -407,3 +407,41 @@ async fn test_write_fail_new_path() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test(flavor = "multi_thread")] +async fn test_write_utf_bom_file() -> anyhow::Result<()> { + // "ABC" with utf8 bom + const UTF8_FILE: [u8; 6] = [0xef, 0xbb, 0xbf, b'A', b'B', b'C']; + + // "ABC" in UTF16 with bom + const UTF16LE_FILE: [u8; 8] = [0xff, 0xfe, b'A', 0x00, b'B', 0x00, b'C', 0x00]; + const UTF16BE_FILE: [u8; 8] = [0xfe, 0xff, 0x00, b'A', 0x00, b'B', 0x00, b'C']; + + edit_file_with_content(&UTF8_FILE).await?; + edit_file_with_content(&UTF16LE_FILE).await?; + edit_file_with_content(&UTF16BE_FILE).await?; + + Ok(()) +} + +async fn edit_file_with_content(file_content: &[u8]) -> anyhow::Result<()> { + let mut file = tempfile::NamedTempFile::new()?; + + file.as_file_mut().write_all(&file_content)?; + + helpers::test_key_sequence( + &mut helpers::AppBuilder::new().build()?, + Some(&format!(":o {}:x", file.path().to_string_lossy())), + None, + true, + ) + .await?; + + file.rewind()?; + let mut new_file_content: Vec = Vec::new(); + file.read_to_end(&mut new_file_content)?; + + assert_eq!(file_content, new_file_content); + + Ok(()) +} diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 5ede5bc60..11b9ef0e6 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -5,6 +5,7 @@ use futures_util::future::BoxFuture; use futures_util::FutureExt; use helix_core::auto_pairs::AutoPairs; use helix_core::doc_formatter::TextFormat; +use helix_core::encoding::Encoding; use helix_core::syntax::Highlight; use helix_core::text_annotations::{InlineAnnotation, TextAnnotations}; use helix_core::Range; @@ -130,6 +131,7 @@ pub struct Document { path: Option, encoding: &'static encoding::Encoding, + has_bom: bool, pub restore_cursor: bool, @@ -277,16 +279,104 @@ impl fmt::Debug for DocumentInlayHintsId { } } +enum Encoder { + Utf16Be, + Utf16Le, + EncodingRs(encoding::Encoder), +} + +impl Encoder { + fn from_encoding(encoding: &'static encoding::Encoding) -> Self { + if encoding == encoding::UTF_16BE { + Self::Utf16Be + } else if encoding == encoding::UTF_16LE { + Self::Utf16Le + } else { + Self::EncodingRs(encoding.new_encoder()) + } + } + + fn encode_from_utf8( + &mut self, + src: &str, + dst: &mut [u8], + is_empty: bool, + ) -> (encoding::CoderResult, usize, usize) { + if src.is_empty() { + return (encoding::CoderResult::InputEmpty, 0, 0); + } + let mut write_to_buf = |convert: fn(u16) -> [u8; 2]| { + let to_write = src.char_indices().map(|(indice, char)| { + let mut encoded: [u16; 2] = [0, 0]; + ( + indice, + char.encode_utf16(&mut encoded) + .iter_mut() + .flat_map(|char| convert(*char)) + .collect::>(), + ) + }); + + let mut total_written = 0usize; + + for (indice, utf16_bytes) in to_write { + let character_size = utf16_bytes.len(); + + if dst.len() <= (total_written + character_size) { + return (encoding::CoderResult::OutputFull, indice, total_written); + } + + for character in utf16_bytes { + dst[total_written] = character; + total_written += 1; + } + } + + (encoding::CoderResult::InputEmpty, src.len(), total_written) + }; + + match self { + Self::Utf16Be => write_to_buf(u16::to_be_bytes), + Self::Utf16Le => write_to_buf(u16::to_le_bytes), + Self::EncodingRs(encoder) => { + let (code_result, read, written, ..) = encoder.encode_from_utf8(src, dst, is_empty); + + (code_result, read, written) + } + } + } +} + +// Apply BOM if encoding permit it, return the number of bytes written at the start of buf +fn apply_bom(encoding: &'static encoding::Encoding, buf: &mut [u8; BUF_SIZE]) -> usize { + if encoding == encoding::UTF_8 { + buf[0] = 0xef; + buf[1] = 0xbb; + buf[2] = 0xbf; + 3 + } else if encoding == encoding::UTF_16BE { + buf[0] = 0xfe; + buf[1] = 0xff; + 2 + } else if encoding == encoding::UTF_16LE { + buf[0] = 0xff; + buf[1] = 0xfe; + 2 + } else { + 0 + } +} + // The documentation and implementation of this function should be up-to-date with // its sibling function, `to_writer()`. // /// Decodes a stream of bytes into UTF-8, returning a `Rope` and the -/// encoding it was decoded as. The optional `encoding` parameter can -/// be used to override encoding auto-detection. +/// encoding it was decoded as with BOM information. The optional `encoding` +/// parameter can be used to override encoding auto-detection. pub fn from_reader( reader: &mut R, - encoding: Option<&'static encoding::Encoding>, -) -> Result<(Rope, &'static encoding::Encoding), Error> { + encoding: Option<&'static Encoding>, +) -> Result<(Rope, &'static Encoding, bool), Error> { // These two buffers are 8192 bytes in size each and are used as // intermediaries during the decoding process. Text read into `buf` // from `reader` is decoded into `buf_out` as UTF-8. Once either @@ -296,25 +386,32 @@ pub fn from_reader( let mut buf_out = [0u8; BUF_SIZE]; let mut builder = RopeBuilder::new(); - // By default, the encoding of the text is auto-detected via the - // `chardetng` crate which requires sample data from the reader. + // By default, the encoding of the text is auto-detected by + // `encoding_rs` for_bom, and if it fails, from `chardetng` + // crate which requires sample data from the reader. // As a manual override to this auto-detection is possible, the // same data is read into `buf` to ensure symmetry in the upcoming // loop. - let (encoding, mut decoder, mut slice, mut is_empty) = { + let (encoding, has_bom, mut decoder, mut slice, mut is_empty) = { let read = reader.read(&mut buf)?; let is_empty = read == 0; - let encoding = encoding.unwrap_or_else(|| { - let mut encoding_detector = chardetng::EncodingDetector::new(); - encoding_detector.feed(&buf, is_empty); - encoding_detector.guess(None, true) - }); + let (encoding, has_bom) = encoding + .map(|encoding| (encoding, false)) + .or_else(|| { + encoding::Encoding::for_bom(&buf).map(|(encoding, _bom_size)| (encoding, true)) + }) + .unwrap_or_else(|| { + let mut encoding_detector = chardetng::EncodingDetector::new(); + encoding_detector.feed(&buf, is_empty); + (encoding_detector.guess(None, true), false) + }); + let decoder = encoding.new_decoder(); // If the amount of bytes read from the reader is less than // `buf.len()`, it is undesirable to read the bytes afterwards. let slice = &buf[..read]; - (encoding, decoder, slice, is_empty) + (encoding, has_bom, decoder, slice, is_empty) }; // `RopeBuilder::append()` expects a `&str`, so this is the "real" @@ -382,7 +479,7 @@ pub fn from_reader( is_empty = read == 0; } let rope = builder.finish(); - Ok((rope, encoding)) + Ok((rope, encoding, has_bom)) } // The documentation and implementation of this function should be up-to-date with @@ -393,7 +490,7 @@ pub fn from_reader( /// replacement characters may appear in the encoded text. pub async fn to_writer<'a, W: tokio::io::AsyncWriteExt + Unpin + ?Sized>( writer: &'a mut W, - encoding: &'static encoding::Encoding, + encoding_with_bom_info: (&'static Encoding, bool), rope: &'a Rope, ) -> Result<(), Error> { // Text inside a `Rope` is stored as non-contiguous blocks of data called @@ -402,13 +499,22 @@ pub async fn to_writer<'a, W: tokio::io::AsyncWriteExt + Unpin + ?Sized>( // determined by filtering the iterator to remove all empty chunks and then // appending an empty chunk to it. This is valuable for detecting when all // chunks in the `Rope` have been iterated over in the subsequent loop. + let (encoding, has_bom) = encoding_with_bom_info; + let iter = rope .chunks() .filter(|c| !c.is_empty()) .chain(std::iter::once("")); let mut buf = [0u8; BUF_SIZE]; - let mut encoder = encoding.new_encoder(); - let mut total_written = 0usize; + + let mut total_written = if has_bom { + apply_bom(encoding, &mut buf) + } else { + 0 + }; + + let mut encoder = Encoder::from_encoding(encoding); + for chunk in iter { let is_empty = chunk.is_empty(); let mut total_read = 0usize; @@ -449,6 +555,7 @@ pub async fn to_writer<'a, W: tokio::io::AsyncWriteExt + Unpin + ?Sized>( break; } } + Ok(()) } @@ -466,10 +573,10 @@ use url::Url; impl Document { pub fn from( text: Rope, - encoding: Option<&'static encoding::Encoding>, + encoding_with_bom_info: Option<(&'static Encoding, bool)>, config: Arc>, ) -> Self { - let encoding = encoding.unwrap_or(encoding::UTF_8); + let (encoding, has_bom) = encoding_with_bom_info.unwrap_or((encoding::UTF_8, false)); let changes = ChangeSet::new(&text); let old_state = None; @@ -477,6 +584,7 @@ impl Document { id: DocumentId::default(), path: None, encoding, + has_bom, text, selections: HashMap::default(), inlay_hints: HashMap::default(), @@ -511,21 +619,21 @@ impl Document { /// overwritten with the `encoding` parameter. pub fn open( path: &Path, - encoding: Option<&'static encoding::Encoding>, + encoding: Option<&'static Encoding>, config_loader: Option>, config: Arc>, ) -> Result { // Open the file if it exists, otherwise assume it is a new file (and thus empty). - let (rope, encoding) = if path.exists() { + let (rope, encoding, has_bom) = if path.exists() { let mut file = std::fs::File::open(path).context(format!("unable to open {:?}", path))?; from_reader(&mut file, encoding)? } else { let encoding = encoding.unwrap_or(encoding::UTF_8); - (Rope::from(DEFAULT_LINE_ENDING.as_str()), encoding) + (Rope::from(DEFAULT_LINE_ENDING.as_str()), encoding, false) }; - let mut doc = Self::from(rope, Some(encoding), config); + let mut doc = Self::from(rope, Some((encoding, has_bom)), config); // set the path and try detecting the language doc.set_path(Some(path))?; @@ -576,7 +684,7 @@ impl Document { })?; { let mut stdin = process.stdin.take().ok_or(FormatterError::BrokenStdin)?; - to_writer(&mut stdin, encoding::UTF_8, &text) + to_writer(&mut stdin, (encoding::UTF_8, false), &text) .await .map_err(|_| FormatterError::BrokenStdin)?; } @@ -688,8 +796,7 @@ impl Document { let current_rev = self.get_current_revision(); let doc_id = self.id(); - let encoding = self.encoding; - + let encoding_with_bom_info = (self.encoding, self.has_bom); let last_saved_time = self.last_saved_time; // We encode the file according to the `Document`'s encoding. @@ -718,7 +825,7 @@ impl Document { } let mut file = File::create(&path).await?; - to_writer(&mut file, encoding, &text).await?; + to_writer(&mut file, encoding_with_bom_info, &text).await?; let event = DocumentSavedEvent { revision: current_rev, @@ -776,7 +883,7 @@ impl Document { provider_registry: &DiffProviderRegistry, redraw_handle: RedrawHandle, ) -> Result<(), Error> { - let encoding = &self.encoding; + let encoding = self.encoding; let path = self .path() .filter(|path| path.exists()) @@ -810,13 +917,16 @@ impl Document { /// Sets the [`Document`]'s encoding with the encoding correspondent to `label`. pub fn set_encoding(&mut self, label: &str) -> Result<(), Error> { - self.encoding = encoding::Encoding::for_label(label.as_bytes()) - .ok_or_else(|| anyhow!("unknown encoding"))?; + let encoding = + Encoding::for_label(label.as_bytes()).ok_or_else(|| anyhow!("unknown encoding"))?; + + self.encoding = encoding; + Ok(()) } /// Returns the [`Document`]'s current encoding. - pub fn encoding(&self) -> &'static encoding::Encoding { + pub fn encoding(&self) -> &'static Encoding { self.encoding } @@ -1280,7 +1390,7 @@ impl Document { /// Intialize/updates the differ for this document with a new base. pub fn set_diff_base(&mut self, diff_base: Vec, redraw_handle: RedrawHandle) { - if let Ok((diff_base, _)) = from_reader(&mut diff_base.as_slice(), Some(self.encoding)) { + if let Ok((diff_base, ..)) = from_reader(&mut diff_base.as_slice(), Some(self.encoding)) { if let Some(differ) = &self.diff_handle { differ.update_diff_base(diff_base); return; @@ -1724,7 +1834,7 @@ mod test { assert!(ref_path.exists()); let mut file = std::fs::File::open(path).unwrap(); - let text = from_reader(&mut file, Some(encoding)) + let text = from_reader(&mut file, Some(encoding.into())) .unwrap() .0 .to_string(); @@ -1750,7 +1860,7 @@ mod test { let text = Rope::from_str(&std::fs::read_to_string(path).unwrap()); let mut buf: Vec = Vec::new(); - helix_lsp::block_on(to_writer(&mut buf, encoding, &text)).unwrap(); + helix_lsp::block_on(to_writer(&mut buf, (encoding, false), &text)).unwrap(); let expectation = std::fs::read(ref_path).unwrap(); assert_eq!(buf, expectation); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 005c66674..8e4dab414 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1305,10 +1305,10 @@ impl Editor { } pub fn new_file_from_stdin(&mut self, action: Action) -> Result { - let (rope, encoding) = crate::document::from_reader(&mut stdin(), None)?; + let (rope, encoding, has_bom) = crate::document::from_reader(&mut stdin(), None)?; Ok(self.new_file_from_document( action, - Document::from(rope, Some(encoding), self.config.clone()), + Document::from(rope, Some((encoding, has_bom)), self.config.clone()), )) } From 75f62bc86f2ccf2f529d4faa45aed08adfefef78 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Sun, 30 Apr 2023 23:44:06 +0200 Subject: [PATCH 160/260] fix didChange notifaction offset encoding --- helix-lsp/src/client.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 89b714e21..840e73828 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -645,7 +645,11 @@ impl Client { // Calculation is therefore a bunch trickier. use helix_core::RopeSlice; - fn traverse(pos: lsp::Position, text: RopeSlice) -> lsp::Position { + fn traverse( + pos: lsp::Position, + text: RopeSlice, + offset_encoding: OffsetEncoding, + ) -> lsp::Position { let lsp::Position { mut line, mut character, @@ -662,7 +666,11 @@ impl Client { line += 1; character = 0; } else { - character += ch.len_utf16() as u32; + character += match offset_encoding { + OffsetEncoding::Utf8 => ch.len_utf8() as u32, + OffsetEncoding::Utf16 => ch.len_utf16() as u32, + OffsetEncoding::Utf32 => 1, + }; } } lsp::Position { line, character } @@ -683,7 +691,7 @@ impl Client { } Delete(_) => { let start = pos_to_lsp_pos(new_text, new_pos, offset_encoding); - let end = traverse(start, old_text.slice(old_pos..old_end)); + let end = traverse(start, old_text.slice(old_pos..old_end), offset_encoding); // deletion changes.push(lsp::TextDocumentContentChangeEvent { @@ -700,7 +708,8 @@ impl Client { // a subsequent delete means a replace, consume it let end = if let Some(Delete(len)) = iter.peek() { old_end = old_pos + len; - let end = traverse(start, old_text.slice(old_pos..old_end)); + let end = + traverse(start, old_text.slice(old_pos..old_end), offset_encoding); iter.next(); From d7878238c1a2994f7d467f4bead6660da3f5e8e4 Mon Sep 17 00:00:00 2001 From: Scott Stevenson Date: Mon, 1 May 2023 15:21:10 +0100 Subject: [PATCH 161/260] Recognise poetry.lock as TOML (#6928) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 9a0a538a0..e4855e90e 100644 --- a/languages.toml +++ b/languages.toml @@ -78,7 +78,7 @@ source = { git = "https://github.com/FuelLabs/tree-sitter-sway", rev = "e491a005 name = "toml" scope = "source.toml" injection-regex = "toml" -file-types = ["toml"] +file-types = ["toml", "poetry.lock"] roots = [] comment-token = "#" language-server = { command = "taplo", args = ["lsp", "stdio"] } From 015623720cfda031d04bb3628b4a0ad506b3bccf Mon Sep 17 00:00:00 2001 From: Scott Stevenson Date: Mon, 1 May 2023 15:21:30 +0100 Subject: [PATCH 162/260] Recognise Jupyter notebooks as JSON documents (#6927) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index e4855e90e..4e09d54f6 100644 --- a/languages.toml +++ b/languages.toml @@ -160,7 +160,7 @@ indent = { tab-width = 2, unit = " " } name = "json" scope = "source.json" injection-regex = "json" -file-types = ["json", "jsonc", "arb"] +file-types = ["json", "jsonc", "arb", "ipynb"] roots = [] language-server = { command = "vscode-json-language-server", args = ["--stdio"] } auto-format = true From 2701781db795cbdda739b5c1153b09429d7ae789 Mon Sep 17 00:00:00 2001 From: Chirikumbrah <78883260+Chirikumbrah@users.noreply.github.com> Date: Tue, 2 May 2023 00:51:35 +0300 Subject: [PATCH 163/260] Dracula theme: change variable and menu colors (#6855) --- runtime/themes/dracula.toml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index bfdd620d0..eb46d6d84 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -51,8 +51,8 @@ "variable" = { fg = "foreground" } "variable.builtin" = { fg = "purple", modifiers = ["italic"] } "variable.parameter" = { fg = "orange", modifiers = ["italic"] } -"variable.other" = { fg = "cyan" } -"variable.other.member" = { fg = "purple" } +"variable.other" = { fg = "foreground" } +"variable.other.member" = { fg = "foreground" } "diff.plus" = { fg = "green" } @@ -73,8 +73,9 @@ "ui.highlight.frameline" = { fg = "background", bg = "red" } "ui.linenr" = { fg = "comment" } "ui.linenr.selected" = { fg = "foreground" } -"ui.menu" = { fg = "foreground", bg = "black" } -"ui.menu.selected" = { fg = "cyan", bg = "black" } +"ui.menu" = { fg = "background", bg = "purple" } +"ui.menu.selected" = { fg = "background", bg = "green", modifiers = ["dim"] } +"ui.menu.scroll" = { fg = "background", bg = "purple" } "ui.popup" = { fg = "foreground", bg = "black" } "ui.selection.primary" = { bg = "selection_primary" } "ui.selection" = { bg = "selection" } From 1b3923374addd3423dfcb8221ceca174e3c0f2df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 09:57:45 +0900 Subject: [PATCH 164/260] build(deps): bump etcetera from 0.7.1 to 0.8.0 (#6931) Bumps [etcetera](https://github.com/lunacookies/etcetera) from 0.7.1 to 0.8.0. - [Release notes](https://github.com/lunacookies/etcetera/releases) - [Commits](https://github.com/lunacookies/etcetera/compare/v0.7.1...v0.8.0) --- 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 | 5 +++-- helix-core/Cargo.toml | 2 +- helix-loader/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d8a07f41b..c11ebf63a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -373,12 +373,13 @@ dependencies = [ [[package]] name = "etcetera" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51822eedc6129d8c4d96cec86d56b785e983f943c9ce9fb892e0c2a99a7f47a0" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" dependencies = [ "cfg-if", "home", + "windows-sys 0.48.0", ] [[package]] diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index c10ed735e..3f7d34db8 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -45,7 +45,7 @@ encoding_rs = "0.8" chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] } -etcetera = "0.7" +etcetera = "0.8" textwrap = "0.16.0" [dev-dependencies] diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index ff8ffb1c8..18216bcba 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -17,7 +17,7 @@ path = "src/main.rs" anyhow = "1" serde = { version = "1.0", features = ["derive"] } toml = "0.7" -etcetera = "0.7" +etcetera = "0.8" tree-sitter = "0.20" once_cell = "1.17" log = "0.4" From d9a7bd3bc1d11162811fa50187ca0937b2185f20 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 09:57:53 +0900 Subject: [PATCH 165/260] build(deps): bump anyhow from 1.0.70 to 1.0.71 (#6932) Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.70 to 1.0.71. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.70...1.0.71) --- 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 c11ebf63a..b57dc8df3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" [[package]] name = "arc-swap" From d3e535b697bf80fc7f9c13e12713c5b5e092211c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 09:58:06 +0900 Subject: [PATCH 166/260] build(deps): bump gix from 0.44.0 to 0.44.1 (#6933) Bumps [gix](https://github.com/Byron/gitoxide) from 0.44.0 to 0.44.1. - [Release notes](https://github.com/Byron/gitoxide/releases) - [Changelog](https://github.com/Byron/gitoxide/blob/main/CHANGELOG.md) - [Commits](https://github.com/Byron/gitoxide/compare/gix-v0.44.0...gix-v0.44.1) --- updated-dependencies: - dependency-name: gix 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 | 68 ++++++++++++++++++++++---------------------- helix-vcs/Cargo.toml | 2 +- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b57dc8df3..63de13315 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -495,9 +495,9 @@ dependencies = [ [[package]] name = "gix" -version = "0.44.0" +version = "0.44.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2353761ba46eabc95759eb1deed72c99cb31ad8930bc5d811c06e3f52b0feb" +checksum = "6bf41b61f7df395284f7a579c0fa1a7e012c5aede655174d4e91299ef1cac643" dependencies = [ "gix-actor", "gix-attributes", @@ -554,9 +554,9 @@ dependencies = [ [[package]] name = "gix-attributes" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "371c78ac6b4ef130abedc0f09c8f4b43d846df62d2d1571ca4e8cc5479886760" +checksum = "3015baa01ad2122fbcaab7863c857a603eb7b7ec12ac8141207c42c6439805e2" dependencies = [ "bstr", "gix-glob", @@ -598,9 +598,9 @@ dependencies = [ [[package]] name = "gix-config" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e8188bb673aeef4bb21dc8650084668e83ed944c1c6fcf22050b5e4de0ebdd" +checksum = "1d252a0eddb6df74600d3d8872dc9fe98835a7da43110411d705b682f49d4ac1" dependencies = [ "bstr", "gix-config-value", @@ -620,9 +620,9 @@ dependencies = [ [[package]] name = "gix-config-value" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a77b6c3e51bd6d8974ab80c7e7943b3f12abb8fa809834002db9742da6b4ac4" +checksum = "786861e84a5793ad5f863d846de5eb064cd23b87e61ad708c8c402608202e7be" dependencies = [ "bitflags 2.2.1", "bstr", @@ -633,9 +633,9 @@ dependencies = [ [[package]] name = "gix-credentials" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4896885f74b84a7bdcd0a2e32d9cb0a5082b34c8489c8fe1bfa94f155206b4f1" +checksum = "4874a4fc11ffa844a3c2b87a66957bda30a73b577ef1acf15ac34df5745de5ff" dependencies = [ "bstr", "gix-command", @@ -673,9 +673,9 @@ dependencies = [ [[package]] name = "gix-discover" -version = "0.17.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0305d45385faeac734f1bda1fa7bad55b7d51416a26f6fb53d17a78186da0bd9" +checksum = "1a6b61363e63e7cdaa3e6f96acb0257ebdb3d8883e21eba5930c99f07f0a5fc0" dependencies = [ "bstr", "dunce", @@ -714,9 +714,9 @@ dependencies = [ [[package]] name = "gix-glob" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "035fd81df824cb4d987835120b6259d2bd39fbaf1e888cab9426dc687170191f" +checksum = "c07c98204529ac3f24b34754540a852593d2a4c7349008df389240266627a72a" dependencies = [ "bitflags 2.2.1", "bstr", @@ -747,9 +747,9 @@ dependencies = [ [[package]] name = "gix-ignore" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f958d7fe0858fb52a7573e279201e09df990874e21d2ef3df4ac85653fb88442" +checksum = "ba205b6df563e2906768bb22834c82eb46c5fdfcd86ba2c347270bc8309a05b2" dependencies = [ "bstr", "gix-glob", @@ -822,9 +822,9 @@ dependencies = [ [[package]] name = "gix-odb" -version = "0.44.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cd87fd2a4884899954daa06371ecd55b40e2c4b708e94fe70d869864d1cd552" +checksum = "bca2f324aa67672b6d0f2c0fa93f96eb6a7029d260e4c1df5dce3c015f5e5add" dependencies = [ "arc-swap", "gix-features", @@ -840,9 +840,9 @@ dependencies = [ [[package]] name = "gix-pack" -version = "0.34.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9914b411b8068322b877af7774fd0f283b25b141969cef2536ed09a2cf9fac1" +checksum = "164a515900a83257ae4aa80e741655bee7a2e39113fb535d7a5ac623b445ff20" dependencies = [ "clru", "gix-chunk", @@ -862,9 +862,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6581146846102b54702f1cadb98f79f00b996bc8470edc24645f460060d276" +checksum = "4fc78f47095a0c15aea0e66103838f0748f4494bf7a9555dfe0f00425400396c" dependencies = [ "bstr", "home", @@ -874,9 +874,9 @@ dependencies = [ [[package]] name = "gix-prompt" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c5086dbabb66cb29d1dec4636cc0357e76fc95da682c149ec96dd97222697f" +checksum = "330d11fdf88fff3366c2491efde2f3e454958efe7d5ddf60272e8fb1d944bb01" dependencies = [ "gix-command", "gix-config-value", @@ -898,9 +898,9 @@ dependencies = [ [[package]] name = "gix-ref" -version = "0.28.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf64922331b0abd855e75ba3148b072ce2b99e31cd9d1998b87b341e9dbb67e" +checksum = "1e03989e9d49954368e1b526578230fc7189d1634acdfbe79e9ba1de717e15d5" dependencies = [ "gix-actor", "gix-features", @@ -918,9 +918,9 @@ dependencies = [ [[package]] name = "gix-refspec" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f520fd43ef706cafe14f4d5a196303c173da1b8cea92ab30fef7d38e866f6015" +checksum = "0a6ea733820df67e4cd7797deb12727905824d8f5b7c59d943c456d314475892" dependencies = [ "bstr", "gix-hash", @@ -946,9 +946,9 @@ dependencies = [ [[package]] name = "gix-sec" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59c51b67330c78abc069a3aec920dcb301b858739ca8414ce74c8df2d33734e" +checksum = "794520043d5a024dfeac335c6e520cb616f6963e30dab995892382e998c12897" dependencies = [ "bitflags 2.2.1", "gix-path", @@ -984,9 +984,9 @@ dependencies = [ [[package]] name = "gix-url" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7e76c8259755bc0ef8f6be85943475a3f1ee26ae82bcc621eb0e704be63bd9" +checksum = "dfc77f89054297cc81491e31f1bab4027e554b5ef742a44bd7035db9a0f78b76" dependencies = [ "bstr", "gix-features", @@ -1017,9 +1017,9 @@ dependencies = [ [[package]] name = "gix-worktree" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4753efd398078a1d049a7ab581730491cb1bfc750e179a362be5bd35042f7b53" +checksum = "10bf56a1f5037d84293ea6cece61d9f27c4866b1e13c1c95f37cf56b7da7af25" dependencies = [ "bstr", "filetime", diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml index 978af3982..f644add5b 100644 --- a/helix-vcs/Cargo.toml +++ b/helix-vcs/Cargo.toml @@ -17,7 +17,7 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p parking_lot = "0.12" arc-swap = { version = "1.6.0" } -gix = { version = "0.44.0", default-features = false , optional = true } +gix = { version = "0.44.1", default-features = false , optional = true } imara-diff = "0.1.5" anyhow = "1" From 7ea5965bd53f8805f93b1e66d9878ca9f8d269c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 09:59:05 +0900 Subject: [PATCH 167/260] build(deps): bump tokio-stream from 0.1.12 to 0.1.14 (#6934) Bumps [tokio-stream](https://github.com/tokio-rs/tokio) from 0.1.12 to 0.1.14. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Changelog](https://github.com/tokio-rs/tokio/blob/tokio-0.1.14/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-stream-0.1.12...tokio-0.1.14) --- 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 63de13315..4746b9e1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2182,9 +2182,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index f85265152..fccb8c273 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -25,6 +25,6 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" tokio = { version = "1.27", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } -tokio-stream = "0.1.12" +tokio-stream = "0.1.14" which = "4.4" parking_lot = "0.12.1" From d1a4bd876b3ae646693c0905d7f29b636e2e5033 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 10:17:59 +0900 Subject: [PATCH 168/260] build(deps): bump tokio from 1.27.0 to 1.28.0 (#6935) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.27.0 to 1.28.0. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.27.0...tokio-1.28.0) --- 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 | 10 +++++----- helix-lsp/Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4746b9e1a..369daed78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2152,9 +2152,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.27.0" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f" dependencies = [ "autocfg", "bytes", @@ -2166,14 +2166,14 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index fccb8c273..5143236de 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -24,7 +24,7 @@ lsp-types = { version = "0.94" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" -tokio = { version = "1.27", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } +tokio = { version = "1.28", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } tokio-stream = "0.1.14" which = "4.4" parking_lot = "0.12.1" From c49faf568105f69f2c2725c865e5ae17e3f25092 Mon Sep 17 00:00:00 2001 From: taupiqueur <93834534+taupiqueur@users.noreply.github.com> Date: Wed, 3 May 2023 02:43:37 +0200 Subject: [PATCH 169/260] Add language server command for Crystal (#6948) --- 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 b08bf1558..0dbbd69d2 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -18,7 +18,7 @@ | common-lisp | ✓ | | | `cl-lsp` | | cpon | ✓ | | ✓ | | | cpp | ✓ | ✓ | ✓ | `clangd` | -| crystal | ✓ | ✓ | | | +| crystal | ✓ | ✓ | | `crystalline` | | css | ✓ | | | `vscode-css-language-server` | | cue | ✓ | | | `cuelsp` | | d | ✓ | ✓ | ✓ | `serve-d` | diff --git a/languages.toml b/languages.toml index 4e09d54f6..81ba471e3 100644 --- a/languages.toml +++ b/languages.toml @@ -253,6 +253,7 @@ roots = ["shard.yml", "shard.lock"] comment-token = "#" indent = { tab-width = 2, unit = " " } grammar = "ruby" +language-server = { command = "crystalline", args = ["--stdio"] } [[language]] name = "c-sharp" From c6228825fdde327af45be122e136b0a2749658e5 Mon Sep 17 00:00:00 2001 From: Gagan Janjua Date: Wed, 3 May 2023 11:22:54 -0400 Subject: [PATCH 170/260] Add Amberwood theme (#6924) --- runtime/themes/amberwood.toml | 138 ++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 runtime/themes/amberwood.toml diff --git a/runtime/themes/amberwood.toml b/runtime/themes/amberwood.toml new file mode 100644 index 000000000..142ded369 --- /dev/null +++ b/runtime/themes/amberwood.toml @@ -0,0 +1,138 @@ + +"attribute" = { fg = "blue", modifiers = ["italic"] } +"ui.virtual.wrap"="softwrap" +"keyword" = "keyword" +"keyword.control.conditional" = { fg = "conditional", modifiers = ["italic"] } +"keyword.directive" = "magenta" # -- preprocessor comments (#if in C) + +"namespace" = { fg = "namespace", modifiers = ["italic"] } + +"punctuation" = "gray06" +"punctuation.delimiter" = "gray06" + +"operator" = "operator" +"special" = "yellow" + +"variable" = {fg="fg"} +"variable.builtin" = "bright_blue" +"variable.parameter" = {fg="white", modifiers=["italic"]} +"variable.other.member" = "white" + +"type" = "bright_blue" +"type.builtin" = "magenta" +"type.enum.variant" = "magenta" + +"constructor" = "yellow" + +"function" = {fg="function", modifiers=["italic"]} +"function.macro" = "bright_cyan" +"function.builtin" = "support_function" + +"tag" = "tag" +"comment" = { fg = "comment", modifiers = ["italic"] } + +"string" = "string" +"string.regexp" = "green" +"string.special" = "yellow" + +"constant" = "constant" +"constant.builtin" = "yellow" +"constant.numeric" = "numeric" +"constant.character.escape" = "cyan" + +# used for lifetimes +"label" = "yellow" + +"markup.heading.marker" = { fg = "gray06" } +"markup.heading" = { fg = "bright_blue", modifiers = ["bold"] } +"markup.list" = "gray06" +"markup.bold" = { modifiers = ["bold"] } +"markup.italic" = { modifiers = ["italic"] } +"markup.link.url" = { fg = "green", modifiers = ["underlined"] } +"markup.link.text" = { fg = "blue", modifiers = ["italic"] } +"markup.raw" = "yellow" + +"diff.plus" = "bright_green" +"diff.minus" = "red" +"diff.delta" = "bright_blue" + +"ui.background" = { bg = "bg" } +"ui.background.separator" = { fg = "fg" } + +"ui.linenr" = { fg = "gray04" } +"ui.linenr.selected" = { fg = "fg" } + +"ui.statusline" = { fg = "status_line_fg", bg = "gray01" } +"ui.statusline.inactive" = { fg = "fg", bg = "gray01", modifiers = ["dim"] } +"ui.statusline.normal" = { fg = "bg", bg = "cyan", modifiers = ["bold"] } +"ui.statusline.insert" = { fg = "bg", bg = "blue", modifiers = ["bold"] } +"ui.statusline.select" = { fg = "bg", bg = "magenta", modifiers = ["bold"] } + +"ui.popup" = { bg = "gray01" } +"ui.window" = { fg = "gray02" } +"ui.help" = { bg = "gray01", fg = "white" } + +"ui.text" = { fg = "fg" } +"ui.text.focus" = { fg = "fg" } + +"ui.virtual" = { fg = "gray02" } +"ui.virtual.ruler" = {bg="gray02"} +"ui.virtual.indent-guide" = { fg = "gray02" } +"ui.virtual.inlay-hint" = { fg = "gray03" } + + +"ui.selection" = { bg = "gray03" } +"ui.selection.primary" = { bg = "gray03" } + +"ui.cursor" = {fg="bg", bg = "cursor" } +"ui.cursor.match" = { fg = "yellow", modifiers = ["bold", "underlined"] } +"ui.cursorline.primary" = { bg = "gray01" } + +"ui.highlight" = { bg = "gray02" } + +"ui.menu" = { fg = "white", bg = "gray01" } +"ui.menu.selected" = { fg = "bright_white", bg = "gray03" } +"ui.menu.scroll" = { fg = "gray04", bg = "gray01" } + +diagnostic = { modifiers = ["underlined"] } + +warning = "yellow" +error = "error" +info = "bright_blue" +hint = "bright_cyan" + +[palette] +error="#fca5a5" +bg = "#0F1014" +fg = "#c9c7cd" +green = "#90b99f" +bright_green = "#9dc6ac" +yellow = "#e5c890" +blue = "#aca1cf" +bright_blue = "#b9aeda" +magenta = "#e29eca" +cyan = "#ea83a5" +bright_cyan = "#f591b2" +white = "#c1c0d4" +bright_white = "#cac9dd" +gray01 = "#1b1b1d" +gray02 = "#2a2a2d" +gray03 = "#3e3e43" +gray04 = "#57575f" +gray06 = "#9998a8" +gray07 = "#c1c0d4" +comment="#808080" +red="#e78284" +function="#e5c890" +support_function="#9898a6" +constant="#8eb6f5" +string="#9898a6" +tag="#9898a6" +keyword="#8eb6f5" +namespace= "#c58fff" +numeric= "#e9c46a" +status_line_fg = "#e5c890" +operator="#8eb6f5" +softwrap="#808080" +conditional="#a8a29e" +cursor="#e5c890" From fc1e9a6ff936f9ceb7bb85c810130f49b42300c9 Mon Sep 17 00:00:00 2001 From: Diego Pontoriero <74719+diegs@users.noreply.github.com> Date: Thu, 4 May 2023 18:02:19 -0700 Subject: [PATCH 171/260] languages: add build.gradle.kts to java and scala roots (#6970) Gradle scripts written in kotlin use a .kts extension: https://docs.gradle.org/current/userguide/kotlin_dsl.html#sec:scripts --- languages.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/languages.toml b/languages.toml index 81ba471e3..108e91a1c 100644 --- a/languages.toml +++ b/languages.toml @@ -731,7 +731,7 @@ name = "java" scope = "source.java" injection-regex = "java" file-types = ["java"] -roots = ["pom.xml", "build.gradle"] +roots = ["pom.xml", "build.gradle", "build.gradle.kts"] language-server = { command = "jdtls" } indent = { tab-width = 4, unit = " " } @@ -1159,7 +1159,7 @@ source = { git = "https://github.com/UserNobody14/tree-sitter-dart", rev = "2d7f [[language]] name = "scala" scope = "source.scala" -roots = ["build.sbt", "build.sc", "build.gradle", "pom.xml", ".scala-build"] +roots = ["build.sbt", "build.sc", "build.gradle", "build.gradle.kts", "pom.xml", ".scala-build"] file-types = ["scala", "sbt", "sc"] comment-token = "//" indent = { tab-width = 2, unit = " " } From 5ae30f1993180b2c043d13f83e16f8647f7ff129 Mon Sep 17 00:00:00 2001 From: Dave Powers Date: Fri, 5 May 2023 10:43:56 -0400 Subject: [PATCH 172/260] Fix keymap select / extend mode anchor link (#6974) --- 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 648dcfa96..f530bf6c5 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -15,7 +15,7 @@ - [Popup](#popup) - [Unimpaired](#unimpaired) - [Insert mode](#insert-mode) -- [Select / extend mode](#select-extend-mode) +- [Select / extend mode](#select--extend-mode) - [Picker](#picker) - [Prompt](#prompt) From 3a9e77934bfd1332b9f971b365883777e3f44b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrius=20Puk=C5=A1ta?= <54238857+yjhn@users.noreply.github.com> Date: Mon, 8 May 2023 17:11:23 +0000 Subject: [PATCH 173/260] Treat .sty and .cls files as latex (#6986) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 108e91a1c..ea992394b 100644 --- a/languages.toml +++ b/languages.toml @@ -654,7 +654,7 @@ source = { git = "https://github.com/gbprod/tree-sitter-twig", rev = "807b293fec name = "latex" scope = "source.tex" injection-regex = "tex" -file-types = ["tex"] +file-types = ["tex", "sty", "cls"] roots = [] comment-token = "%" language-server = { command = "texlab" } From 3fb0562e7b6eab72bba5b445703d392edd8eff3b Mon Sep 17 00:00:00 2001 From: Chirikumbrah <78883260+Chirikumbrah@users.noreply.github.com> Date: Mon, 8 May 2023 20:12:15 +0300 Subject: [PATCH 174/260] Update dracula menu colors (#6987) --- runtime/themes/dracula.toml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index eb46d6d84..1ec5b4fe2 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -73,11 +73,11 @@ "ui.highlight.frameline" = { fg = "background", bg = "red" } "ui.linenr" = { fg = "comment" } "ui.linenr.selected" = { fg = "foreground" } -"ui.menu" = { fg = "background", bg = "purple" } -"ui.menu.selected" = { fg = "background", bg = "green", modifiers = ["dim"] } -"ui.menu.scroll" = { fg = "background", bg = "purple" } +"ui.menu" = { fg = "foreground", bg = "current_line" } +"ui.menu.selected" = { fg = "current_line", bg = "purple", modifiers = ["dim"] } +"ui.menu.scroll" = { fg = "foreground", bg = "current_line" } "ui.popup" = { fg = "foreground", bg = "black" } -"ui.selection.primary" = { bg = "selection_primary" } +"ui.selection.primary" = { bg = "current_line" } "ui.selection" = { bg = "selection" } "ui.statusline" = { fg = "foreground", bg = "darker" } "ui.statusline.inactive" = { fg = "comment", bg = "darker" } @@ -87,8 +87,8 @@ "ui.text" = { fg = "foreground" } "ui.text.focus" = { fg = "cyan" } "ui.window" = { fg = "foreground" } -"ui.virtual.whitespace" = { fg = "subtle" } -"ui.virtual.wrap" = { fg = "subtle" } +"ui.virtual.whitespace" = { fg = "current_line" } +"ui.virtual.wrap" = { fg = "current_line" } "ui.virtual.ruler" = { bg = "black" } "ui.virtual.inlay-hint" = { fg = "cyan" } "ui.virtual.inlay-hint.parameter" = { fg = "cyan", modifiers = ["italic", "dim"] } @@ -122,13 +122,12 @@ darker = "#222430" black = "#191A21" grey = "#666771" comment = "#6272A4" -selection_primary = "#44475a" +current_line = "#44475a" selection = "#363848" -subtle = "#424450" red = "#ff5555" orange = "#ffb86c" yellow = "#f1fa8c" green = "#50fa7b" purple = "#BD93F9" cyan = "#8be9fd" -pink = "#ff79c6" +pink = "#ff79c6" From 301d45b34b181ecd4f2cb916b572f13665fcdf8a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 09:29:43 +0900 Subject: [PATCH 175/260] build(deps): bump termini from 0.1.4 to 1.0.0 (#7001) Bumps [termini](https://github.com/pascalkuthe/termini) from 0.1.4 to 1.0.0. - [Release notes](https://github.com/pascalkuthe/termini/releases) - [Commits](https://github.com/pascalkuthe/termini/compare/v0.1.4...v1.0.0) --- updated-dependencies: - dependency-name: termini dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 38 +++----------------------------------- helix-tui/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 369daed78..a074695fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -289,27 +289,6 @@ dependencies = [ "syn 2.0.15", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - [[package]] name = "dunce" version = "1.0.4" @@ -1744,17 +1723,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall 0.2.16", - "thiserror", -] - [[package]] name = "regex" version = "1.8.1" @@ -2049,11 +2017,11 @@ dependencies = [ [[package]] name = "termini" -version = "0.1.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c0f7ecb9c2a380d2686a747e4fc574043712326e8d39fbd220ab3bd29768a12" +checksum = "2ad441d87dd98bc5eeb31cf2fb7e4839968763006b478efb38668a3bf9da0d59" dependencies = [ - "dirs-next", + "home", ] [[package]] diff --git a/helix-tui/Cargo.toml b/helix-tui/Cargo.toml index 735669298..6cd031f89 100644 --- a/helix-tui/Cargo.toml +++ b/helix-tui/Cargo.toml @@ -20,7 +20,7 @@ bitflags = "2.2" cassowary = "0.3" unicode-segmentation = "1.10" crossterm = { version = "0.26", optional = true } -termini = "0.1" +termini = "1.0" serde = { version = "1", "optional" = true, features = ["derive"]} once_cell = "1.17" log = "~0.4" From 9cca80bd535976642f34c711895dd1d9ee94d8aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 09:30:11 +0900 Subject: [PATCH 176/260] build(deps): bump libc from 0.2.142 to 0.2.144 (#7000) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.142 to 0.2.144. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.142...0.2.144) --- updated-dependencies: - dependency-name: libc 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-term/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a074695fe..8cda8054f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1445,9 +1445,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.142" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "libloading" diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 7fb6b890a..f7496087a 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -68,7 +68,7 @@ grep-searcher = "0.1.11" [target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100 signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } -libc = "0.2.142" +libc = "0.2.144" [build-dependencies] helix-loader = { version = "0.6", path = "../helix-loader" } From 7089bc20f06ceb517bf8af59d7d4620390d903ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 09:30:35 +0900 Subject: [PATCH 177/260] build(deps): bump serde from 1.0.160 to 1.0.162 (#7002) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.160 to 1.0.162. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.160...1.0.162) --- 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 8cda8054f..fecc6124e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1805,18 +1805,18 @@ checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "serde" -version = "1.0.160" +version = "1.0.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6" dependencies = [ "proc-macro2", "quote", From 69332ae3b2fe712019d4caa181bec9946611d7a6 Mon Sep 17 00:00:00 2001 From: David Else <12832280+David-Else@users.noreply.github.com> Date: Tue, 9 May 2023 13:38:36 +0000 Subject: [PATCH 178/260] Add Flathub as third party repository (#6994) --- book/src/install.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/book/src/install.md b/book/src/install.md index 169e6e0b6..2f770b1d6 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -8,6 +8,7 @@ - [Fedora/RHEL](#fedorarhel) - [Arch Linux community](#arch-linux-community) - [NixOS](#nixos) + - [Flatpak](#flatpak) - [AppImage](#appimage) - [macOS](#macos) - [Homebrew Core](#homebrew-core) @@ -18,6 +19,9 @@ - [MSYS2](#msys2) - [Building from source](#building-from-source) - [Configuring Helix's runtime files](#configuring-helixs-runtime-files) + - [Linux and macOS](#linux-and-macos) + - [Windows](#windows) + - [Multiple runtime directories](#multiple-runtime-directories) - [Validating the installation](#validating-the-installation) - [Configure the desktop shortcut](#configure-the-desktop-shortcut) @@ -88,6 +92,15 @@ If you are using a version of Nix without flakes enabled, [install Cachix CLI](https://docs.cachix.org/installation) and use `cachix use helix` to configure Nix to use cached outputs when possible. +### Flatpak + +Helix is available on [Flathub](https://flathub.org/en-GB/apps/com.helix_editor.Helix): + +```sh +flatpak install flathub com.helix_editor.Helix +flatpak run com.helix_editor.Helix +``` + ### AppImage Install Helix using the Linux [AppImage](https://appimage.org/) format. From 8424f387b582ed793663f95ee570e709dff20dd6 Mon Sep 17 00:00:00 2001 From: Ollie Charles Date: Tue, 9 May 2023 20:31:22 +0100 Subject: [PATCH 179/260] Remove `tree-sitter-cabal` (#6996) --- book/src/generated/lang-support.md | 2 +- languages.toml | 4 ---- runtime/queries/cabal/highlights.scm | 15 --------------- 3 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 runtime/queries/cabal/highlights.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 0dbbd69d2..d5cf8f2db 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -9,7 +9,7 @@ | bicep | ✓ | | | `bicep-langserver` | | c | ✓ | ✓ | ✓ | `clangd` | | c-sharp | ✓ | ✓ | | `OmniSharp` | -| cabal | ✓ | | | | +| cabal | | | | | | cairo | ✓ | | | | | capnp | ✓ | | ✓ | | | clojure | ✓ | | | `clojure-lsp` | diff --git a/languages.toml b/languages.toml index ea992394b..175037be0 100644 --- a/languages.toml +++ b/languages.toml @@ -2467,10 +2467,6 @@ roots = ["cabal.project", "Setup.hs"] indent = { tab-width = 2, unit = " " } comment-token = "--" -[[grammar]] -name = "cabal" -source = { git = "https://gitlab.com/magus/tree-sitter-cabal", rev = "7d5fa6887ae05a0b06d046f1e754c197c8ad869b" } - [[language]] name = "hurl" scope = "source.hurl" diff --git a/runtime/queries/cabal/highlights.scm b/runtime/queries/cabal/highlights.scm deleted file mode 100644 index d6b9f4627..000000000 --- a/runtime/queries/cabal/highlights.scm +++ /dev/null @@ -1,15 +0,0 @@ -(comment) @comment - -[ - "cabal-version" - (field_name) -] @type - -(section_name) @type - -[ - (section_type) - "if" - "elseif" - "else" -] @keyword From 92c328c088ae818338237d7f11644ba079c54648 Mon Sep 17 00:00:00 2001 From: Kitsu Date: Tue, 9 May 2023 17:21:29 -0300 Subject: [PATCH 180/260] Add wbc and wbc! commands (#6947) --- book/src/generated/typable-cmd.md | 4 ++- helix-term/src/commands/typed.rs | 46 ++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index ae28a9ba0..a775c6555 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -12,7 +12,9 @@ | `:buffer-next`, `:bn`, `:bnext` | Goto next buffer. | | `:buffer-previous`, `:bp`, `:bprev` | Goto previous buffer. | | `:write`, `:w` | Write changes to disk. Accepts an optional path (:write some/path.txt) | -| `:write!`, `:w!` | Force write changes to disk creating necessary subdirectories. Accepts an optional path (:write some/path.txt) | +| `:write!`, `:w!` | Force write changes to disk creating necessary subdirectories. Accepts an optional path (:write! some/path.txt) | +| `:write-buffer-close`, `:wbc` | Write changes to disk and closes the buffer. Accepts an optional path (:write-buffer-close some/path.txt) | +| `:write-buffer-close!`, `:wbc!` | Force write changes to disk creating necessary subdirectories and closes the buffer. Accepts an optional path (:write-buffer-close! 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 fe92798ba..16ee83d76 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -382,6 +382,36 @@ fn force_write( write_impl(cx, args.first(), true) } +fn write_buffer_close( + cx: &mut compositor::Context, + args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + + write_impl(cx, args.first(), false)?; + + let document_ids = buffer_gather_paths_impl(cx.editor, args); + buffer_close_by_ids_impl(cx, &document_ids, false) +} + +fn force_write_buffer_close( + cx: &mut compositor::Context, + args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + + write_impl(cx, args.first(), true)?; + + let document_ids = buffer_gather_paths_impl(cx.editor, args); + buffer_close_by_ids_impl(cx, &document_ids, false) +} + fn new_file( cx: &mut compositor::Context, _args: &[Cow], @@ -2287,10 +2317,24 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "write!", aliases: &["w!"], - doc: "Force write changes to disk creating necessary subdirectories. Accepts an optional path (:write some/path.txt)", + doc: "Force write changes to disk creating necessary subdirectories. Accepts an optional path (:write! some/path.txt)", fun: force_write, signature: CommandSignature::positional(&[completers::filename]), }, + TypableCommand { + name: "write-buffer-close", + aliases: &["wbc"], + doc: "Write changes to disk and closes the buffer. Accepts an optional path (:write-buffer-close some/path.txt)", + fun: write_buffer_close, + signature: CommandSignature::positional(&[completers::filename]), + }, + TypableCommand { + name: "write-buffer-close!", + aliases: &["wbc!"], + doc: "Force write changes to disk creating necessary subdirectories and closes the buffer. Accepts an optional path (:write-buffer-close! some/path.txt)", + fun: force_write_buffer_close, + signature: CommandSignature::positional(&[completers::filename]), + }, TypableCommand { name: "new", aliases: &["n"], From 87da58578fdcacfe1d2de3d96bf47621c47c15c0 Mon Sep 17 00:00:00 2001 From: John Kelly Date: Wed, 10 May 2023 20:35:43 +0100 Subject: [PATCH 181/260] Add better error message for file save failure due to parent not existing (#7014) Fixes #5229 --- helix-view/src/document.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 11b9ef0e6..27f69d508 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -808,7 +808,7 @@ impl Document { if force { std::fs::DirBuilder::new().recursive(true).create(parent)?; } else { - bail!("can't save file, parent directory does not exist"); + bail!("can't save file, parent directory does not exist (use :w! to create it)"); } } } From 1e5997dc98ecd82b09ccee9fbe8d5350fd333fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Thu, 11 May 2023 11:30:46 +0900 Subject: [PATCH 182/260] nix: Update flake dependencies --- flake.lock | 85 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 33 deletions(-) diff --git a/flake.lock b/flake.lock index d33c404ef..8046f3590 100644 --- a/flake.lock +++ b/flake.lock @@ -3,15 +3,16 @@ "crane": { "flake": false, "locked": { - "lastModified": 1670900067, - "narHash": "sha256-VXVa+KBfukhmWizaiGiHRVX/fuk66P8dgSFfkVN4/MY=", + "lastModified": 1681175776, + "narHash": "sha256-7SsUy9114fryHAZ8p1L6G6YSu7jjz55FddEwa2U8XZc=", "owner": "ipetkov", "repo": "crane", - "rev": "59b31b41a589c0a65e4a1f86b0e5eac68081468b", + "rev": "445a3d222947632b5593112bb817850e8a9cf737", "type": "github" }, "original": { "owner": "ipetkov", + "ref": "v0.12.1", "repo": "crane", "type": "github" } @@ -62,11 +63,11 @@ ] }, "locked": { - "lastModified": 1680258209, - "narHash": "sha256-lEo50RXI/17/a9aCIun8Hz62ZJ5JM5RGeTgclIP+Lgc=", + "lastModified": 1683212002, + "narHash": "sha256-EObtqyQsv9v+inieRY5cvyCMCUI5zuU5qu+1axlJCPM=", "owner": "nix-community", "repo": "dream2nix", - "rev": "6f512b5a220fdb26bd3c659f7b55e4f052ec8b35", + "rev": "fbfb09d2ab5ff761d822dd40b4a1def81651d096", "type": "github" }, "original": { @@ -94,11 +95,11 @@ ] }, "locked": { - "lastModified": 1680172861, - "narHash": "sha256-QMyI338xRxaHFDlCXdLCtgelGQX2PdlagZALky4ZXJ8=", + "lastModified": 1680698112, + "narHash": "sha256-FgnobN/DvCjEsc0UAZEAdPLkL4IZi2ZMnu2K2bUaElc=", "owner": "davhau", "repo": "drv-parts", - "rev": "ced8a52f62b0a94244713df2225c05c85b416110", + "rev": "e8c2ec1157dc1edb002989669a0dbd935f430201", "type": "github" }, "original": { @@ -124,12 +125,15 @@ } }, "flake-utils": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1659877975, - "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "lastModified": 1681202837, + "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "owner": "numtide", "repo": "flake-utils", - "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "rev": "cfacdce06f30d2b68473a46042957675eebb3401", "type": "github" }, "original": { @@ -141,11 +145,11 @@ "mk-naked-shell": { "flake": false, "locked": { - "lastModified": 1676572903, - "narHash": "sha256-oQoDHHUTxNVSURfkFcYLuAK+btjs30T4rbEUtCUyKy8=", + "lastModified": 1681286841, + "narHash": "sha256-3XlJrwlR0nBiREnuogoa5i1b4+w/XPe0z8bbrJASw0g=", "owner": "yusdacra", "repo": "mk-naked-shell", - "rev": "aeca9f8aa592f5e8f71f407d081cb26fd30c5a57", + "rev": "7612f828dd6f22b7fb332cc69440e839d7ffe6bd", "type": "github" }, "original": { @@ -167,11 +171,11 @@ ] }, "locked": { - "lastModified": 1680329418, - "narHash": "sha256-+KN0eQLSZvL1J0kDO8/fxv0UCHTyZCADLmpIfeeiSGo=", + "lastModified": 1683699050, + "narHash": "sha256-UWKQpzVcSshB+sU2O8CCHjOSTQrNS7Kk9V3+UeBsJpg=", "owner": "yusdacra", "repo": "nix-cargo-integration", - "rev": "98c1d2ff5155f0fee5d290f6b982cb990839d540", + "rev": "ed27173cd1b223f598343ea3c15aacb1d140feac", "type": "github" }, "original": { @@ -182,11 +186,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1680213900, - "narHash": "sha256-cIDr5WZIj3EkKyCgj/6j3HBH4Jj1W296z7HTcWj1aMA=", + "lastModified": 1683408522, + "narHash": "sha256-9kcPh6Uxo17a3kK3XCHhcWiV1Yu1kYj22RHiymUhMkU=", "owner": "nixos", "repo": "nixpkgs", - "rev": "e3652e0735fbec227f342712f180f4f21f0594f2", + "rev": "897876e4c484f1e8f92009fd11b7d988a121a4e7", "type": "github" }, "original": { @@ -199,11 +203,11 @@ "nixpkgs-lib": { "locked": { "dir": "lib", - "lastModified": 1678375444, - "narHash": "sha256-XIgHfGvjFvZQ8hrkfocanCDxMefc/77rXeHvYdzBMc8=", + "lastModified": 1682879489, + "narHash": "sha256-sASwo8gBt7JDnOOstnps90K1wxmVfyhsTPPNTGBPjjg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "130fa0baaa2b93ec45523fdcde942f6844ee9f6e", + "rev": "da45bf6ec7bbcc5d1e14d3795c025199f28e0de0", "type": "github" }, "original": { @@ -237,11 +241,11 @@ ] }, "locked": { - "lastModified": 1679737941, - "narHash": "sha256-srSD9CwsVPnUMsIZ7Kt/UegkKUEBcTyU1Rev7mO45S0=", + "lastModified": 1683560683, + "narHash": "sha256-XAygPMN5Xnk/W2c1aW0jyEa6lfMDZWlQgiNtmHXytPc=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "3502ee99d6dade045bdeaf7b0cd8ec703484c25c", + "rev": "006c75898cf814ef9497252b022e91c946ba8e17", "type": "github" }, "original": { @@ -255,11 +259,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1679737941, - "narHash": "sha256-srSD9CwsVPnUMsIZ7Kt/UegkKUEBcTyU1Rev7mO45S0=", + "lastModified": 1683560683, + "narHash": "sha256-XAygPMN5Xnk/W2c1aW0jyEa6lfMDZWlQgiNtmHXytPc=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "3502ee99d6dade045bdeaf7b0cd8ec703484c25c", + "rev": "006c75898cf814ef9497252b022e91c946ba8e17", "type": "github" }, "original": { @@ -284,11 +288,11 @@ ] }, "locked": { - "lastModified": 1680315536, - "narHash": "sha256-0AsBuKssJMbcRcw4HJQwJsUHhZxR5+gaf6xPQayhR44=", + "lastModified": 1683771545, + "narHash": "sha256-we0GYcKTo2jRQGmUGrzQ9VH0OYAUsJMCsK8UkF+vZUA=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "5c8c151bdd639074a0051325c16df1a64ee23497", + "rev": "c57e210faf68e5d5386f18f1b17ad8365d25e4ed", "type": "github" }, "original": { @@ -296,6 +300,21 @@ "repo": "rust-overlay", "type": "github" } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", From 3b8c15618f51889ffd2f2f4be32f8404c1517956 Mon Sep 17 00:00:00 2001 From: ZJPzjp Date: Thu, 11 May 2023 13:44:52 +0800 Subject: [PATCH 183/260] Fix warnings from clippy (#7013) * Fix warnings from clippy * revert MAIN_SEPARATOR_STR --- helix-core/src/surround.rs | 7 +------ helix-core/src/syntax.rs | 9 ++++++--- helix-loader/src/lib.rs | 36 ++++++++++++++++++------------------ helix-term/src/ui/editor.rs | 2 +- helix-tui/src/buffer.rs | 2 +- helix-view/src/clipboard.rs | 2 +- helix-view/src/tree.rs | 3 +-- 7 files changed, 29 insertions(+), 32 deletions(-) diff --git a/helix-core/src/surround.rs b/helix-core/src/surround.rs index f430aee8a..b96cce5a0 100644 --- a/helix-core/src/surround.rs +++ b/helix-core/src/surround.rs @@ -397,15 +397,10 @@ mod test { let selections: SmallVec<[Range; 1]> = spec .match_indices('^') - .into_iter() .map(|(i, _)| Range::point(i)) .collect(); - let expectations: Vec = spec - .match_indices('_') - .into_iter() - .map(|(i, _)| i) - .collect(); + let expectations: Vec = spec.match_indices('_').map(|(i, _)| i).collect(); (rope, Selection::new(selections, 0), expectations) } diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 6514b40f5..005e985de 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -187,9 +187,12 @@ impl<'de> Deserialize<'de> for FileType { M: serde::de::MapAccess<'de>, { match map.next_entry::()? { - Some((key, suffix)) if key == "suffix" => Ok(FileType::Suffix( - suffix.replace('/', &std::path::MAIN_SEPARATOR.to_string()), - )), + Some((key, suffix)) if key == "suffix" => Ok(FileType::Suffix({ + // FIXME: use `suffix.replace('/', std::path::MAIN_SEPARATOR_STR)` + // if MSRV is updated to 1.68 + let mut seperator = [0; 1]; + suffix.replace('/', std::path::MAIN_SEPARATOR.encode_utf8(&mut seperator)) + })), Some((key, _value)) => Err(serde::de::Error::custom(format!( "unknown key in `file-types` list: {}", key diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index 6c7169758..ad4ad899d 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -209,6 +209,24 @@ pub fn merge_toml_values(left: toml::Value, right: toml::Value, merge_depth: usi } } +/// Finds the current workspace folder. +/// Used as a ceiling dir for LSP root resolution, the filepicker and potentially as a future filewatching root +/// +/// This function starts searching the FS upward from the CWD +/// and returns the first directory that contains either `.git` or `.helix`. +/// If no workspace was found returns (CWD, true). +/// Otherwise (workspace, false) is returned +pub fn find_workspace() -> (PathBuf, bool) { + let current_dir = std::env::current_dir().expect("unable to determine current directory"); + for ancestor in current_dir.ancestors() { + if ancestor.join(".git").exists() || ancestor.join(".helix").exists() { + return (ancestor.to_owned(), false); + } + } + + (current_dir, true) +} + #[cfg(test)] mod merge_toml_tests { use std::str; @@ -281,21 +299,3 @@ mod merge_toml_tests { ) } } - -/// Finds the current workspace folder. -/// Used as a ceiling dir for LSP root resolution, the filepicker and potentially as a future filewatching root -/// -/// This function starts searching the FS upward from the CWD -/// and returns the first directory that contains either `.git` or `.helix`. -/// If no workspace was found returns (CWD, true). -/// Otherwise (workspace, false) is returned -pub fn find_workspace() -> (PathBuf, bool) { - let current_dir = std::env::current_dir().expect("unable to determine current directory"); - for ancestor in current_dir.ancestors() { - if ancestor.join(".git").exists() || ancestor.join(".helix").exists() { - return (ancestor.to_owned(), false); - } - } - - (current_dir, true) -} diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index fd8e8fb21..1ecbc8cc1 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -103,7 +103,7 @@ impl EditorView { // Set DAP highlights, if needed. if let Some(frame) = editor.current_stack_frame() { - let dap_line = frame.line.saturating_sub(1) as usize; + let dap_line = frame.line.saturating_sub(1); let style = theme.get("ui.highlight.frameline"); let line_decoration = move |renderer: &mut TextRenderer, pos: LinePos| { if pos.doc_line != dap_line { diff --git a/helix-tui/src/buffer.rs b/helix-tui/src/buffer.rs index 8e0b0adf9..93e9fcf9b 100644 --- a/helix-tui/src/buffer.rs +++ b/helix-tui/src/buffer.rs @@ -442,7 +442,7 @@ impl Buffer { let mut x_offset = x as usize; let max_offset = min(self.area.right(), width.saturating_add(x)); let mut start_index = self.index_of(x, y); - let mut index = self.index_of(max_offset as u16, y); + let mut index = self.index_of(max_offset, y); let content_width = spans.width(); let truncated = content_width > width as usize; diff --git a/helix-view/src/clipboard.rs b/helix-view/src/clipboard.rs index d43d632a9..d639902f7 100644 --- a/helix-view/src/clipboard.rs +++ b/helix-view/src/clipboard.rs @@ -68,7 +68,7 @@ macro_rules! command_provider { #[cfg(windows)] pub fn get_clipboard_provider() -> Box { - Box::new(provider::WindowsProvider::default()) + Box::::default() } #[cfg(target_os = "macos")] diff --git a/helix-view/src/tree.rs b/helix-view/src/tree.rs index e8afd2045..4c9eba0fd 100644 --- a/helix-view/src/tree.rs +++ b/helix-view/src/tree.rs @@ -728,12 +728,11 @@ mod test { tree.focus = l0; let view = View::new(DocumentId::default(), GutterConfig::default()); tree.split(view, Layout::Vertical); - let l2 = tree.focus; // Tree in test // | L0 | L2 | | // | L1 | R0 | - tree.focus = l2; + let l2 = tree.focus; assert_eq!(Some(l0), tree.find_split_in_direction(l2, Direction::Left)); assert_eq!(Some(l1), tree.find_split_in_direction(l2, Direction::Down)); assert_eq!(Some(r0), tree.find_split_in_direction(l2, Direction::Right)); From 5938e2c0dc9465229758d1c2997a4857555d34cc Mon Sep 17 00:00:00 2001 From: Vitalii Solodilov Date: Fri, 12 May 2023 04:29:06 +0300 Subject: [PATCH 184/260] fix: update upstream tree-sitter-dockerfile (#6895) * fix: update upstream tree-sitter-dockerfile Fixes: #6797 * fix: review * fix: review --- languages.toml | 2 +- runtime/queries/dockerfile/highlights.scm | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/languages.toml b/languages.toml index 175037be0..8d86afe4e 100644 --- a/languages.toml +++ b/languages.toml @@ -1182,7 +1182,7 @@ language-server = { command = "docker-langserver", args = ["--stdio"] } [[grammar]] name = "dockerfile" -source = { git = "https://github.com/camdencheek/tree-sitter-dockerfile", rev = "7af32bc04a66ab196f5b9f92ac471f29372ae2ce" } +source = { git = "https://github.com/camdencheek/tree-sitter-dockerfile", rev = "8ee3a0f7587b2bd8c45c8cb7d28bd414604aec62" } [[language]] name = "git-commit" diff --git a/runtime/queries/dockerfile/highlights.scm b/runtime/queries/dockerfile/highlights.scm index 5a945fb9b..cdbf807c2 100644 --- a/runtime/queries/dockerfile/highlights.scm +++ b/runtime/queries/dockerfile/highlights.scm @@ -48,4 +48,7 @@ ((variable) @constant (#match? @constant "^[A-Z][A-Z_0-9]*$")) - +[ + (param) + (mount_param) +] @constant From 06d7f5d100fdcc99f4cdfda879898b2d488d8d7c Mon Sep 17 00:00:00 2001 From: lefp <70862148+lefp@users.noreply.github.com> Date: Fri, 12 May 2023 10:53:07 -0400 Subject: [PATCH 185/260] Add comment injections for Odin (#7027) --- runtime/queries/odin/injections.scm | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 runtime/queries/odin/injections.scm diff --git a/runtime/queries/odin/injections.scm b/runtime/queries/odin/injections.scm new file mode 100644 index 000000000..2f0e58eb6 --- /dev/null +++ b/runtime/queries/odin/injections.scm @@ -0,0 +1,2 @@ +((comment) @injection.content + (#set! injection.language "comment")) From d5fe08ddb8bf1408a1a92d39a63b51cd16d83255 Mon Sep 17 00:00:00 2001 From: A-Walrus <58790821+A-Walrus@users.noreply.github.com> Date: Sat, 13 May 2023 18:44:25 +0300 Subject: [PATCH 186/260] Replace DAP vars popup, instead of adding new (#7034) --- helix-term/src/commands.rs | 7 +++++++ helix-term/src/commands/dap.rs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 882a8a1dc..7d86bc0b3 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -97,6 +97,13 @@ impl<'a> Context<'a> { })); } + /// Call `replace_or_push` on the Compositor + pub fn replace_or_push_layer(&mut self, id: &'static str, component: T) { + self.callback = Some(Box::new(move |compositor: &mut Compositor, _| { + compositor.replace_or_push(id, component); + })); + } + #[inline] pub fn on_next_key( &mut self, diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index 8efdc9cfa..84794bedf 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -580,7 +580,7 @@ pub fn dap_variables(cx: &mut Context) { let contents = Text::from(tui::text::Text::from(variables)); let popup = Popup::new("dap-variables", contents); - cx.push_layer(Box::new(popup)); + cx.replace_or_push_layer("dap-variables", popup); } pub fn dap_terminate(cx: &mut Context) { From b50032ee8540ca68dfc96a71923a27145b305405 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 May 2023 10:26:05 +0900 Subject: [PATCH 187/260] build(deps): bump tokio from 1.28.0 to 1.28.1 (#7057) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.28.0 to 1.28.1. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.28.0...tokio-1.28.1) --- 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 fecc6124e..c86f4010b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2120,9 +2120,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.0" +version = "1.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f" +checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" dependencies = [ "autocfg", "bytes", From 4b9dba8217083f501bdbd2de1c5632e67145a78a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 May 2023 10:26:16 +0900 Subject: [PATCH 188/260] build(deps): bump serde from 1.0.162 to 1.0.163 (#7056) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.162 to 1.0.163. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.162...v1.0.163) --- 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 c86f4010b..e84dd6ba7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1805,18 +1805,18 @@ checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "serde" -version = "1.0.162" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.162" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", From e9efcebdb0437fde28aec95f2a790cc4cf73f0b4 Mon Sep 17 00:00:00 2001 From: gibbz00 Date: Tue, 16 May 2023 06:01:27 +0200 Subject: [PATCH 189/260] languages.toml: recognize `geojson` files. (#7054) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 8d86afe4e..019c9d668 100644 --- a/languages.toml +++ b/languages.toml @@ -160,7 +160,7 @@ indent = { tab-width = 2, unit = " " } name = "json" scope = "source.json" injection-regex = "json" -file-types = ["json", "jsonc", "arb", "ipynb"] +file-types = ["json", "jsonc", "arb", "ipynb", "geojson"] roots = [] language-server = { command = "vscode-json-language-server", args = ["--stdio"] } auto-format = true From 6f135e58a3e2897dc6566c26e3cea952f09380aa Mon Sep 17 00:00:00 2001 From: gibbz00 Date: Tue, 16 May 2023 06:02:22 +0200 Subject: [PATCH 190/260] languages.toml: recognize `gml` files. (#7055) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 019c9d668..6516cc37d 100644 --- a/languages.toml +++ b/languages.toml @@ -2085,7 +2085,7 @@ source = { git = "https://github.com/Unoqwy/tree-sitter-kdl", rev = "e1cd292c6d1 name = "xml" scope = "source.xml" injection-regex = "xml" -file-types = ["xml", "mobileconfig", "plist", "xib", "storyboard", "svg", "xsd"] +file-types = ["xml", "mobileconfig", "plist", "xib", "storyboard", "svg", "xsd", "gml"] indent = { tab-width = 2, unit = " " } roots = [] From 91da0dc172dde1a972be7708188a134db70562c3 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Thu, 18 May 2023 03:16:25 +0200 Subject: [PATCH 191/260] Update nightfox theme (#7061) * theme: nightfox - fix subselection highlighting This fixes an issue with subselect highlighting on the same line as reported here: https://github.com/helix-editor/helix/discussions/5158 * theme: nightfox - update bufferline colors This uses `ui.bufferline` to make it easier to distinguish between (in-)active tabs/buffers. --- runtime/themes/nightfox.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime/themes/nightfox.toml b/runtime/themes/nightfox.toml index fad56d189..069b32ab4 100644 --- a/runtime/themes/nightfox.toml +++ b/runtime/themes/nightfox.toml @@ -19,8 +19,8 @@ "ui.cursor.primary" = { bg = "fg1", fg = "bg1" } # The primary cursor when there are multiple (shift-c). "ui.cursor.match" = { fg = "yellow", modifiers = ["bold"] } # The matching parentheses of that under the cursor. -"ui.selection" = { bg = "bg3" } # All currently selected text. -"ui.selection.primary" = { bg = "bg4" } # The primary selection when there are multiple. +"ui.selection" = { bg = "bg4" } # All currently selected text. +"ui.selection.primary" = { bg = "sel1" } # The primary selection when there are multiple. "ui.cursorline.primary" = { bg = "bg3" } # The line of the primary cursor (if cursorline is enabled) # "ui.cursorline.secondary" = { } # The lines of any other cursors (if cursorline is enabled) # "ui.cursorcolumn.primary" = { } # The column of the primary cursor (if cursorcolumn is enabled) @@ -41,6 +41,10 @@ "ui.statusline.insert" = { bg = "green", fg = "bg0", modifiers = ["bold"] } # Statusline mode during insert mode (only if editor.color-modes is enabled) "ui.statusline.select" = { bg = "magenta", fg = "bg0", modifiers = ["bold"] } # Statusline mode during select mode (only if editor.color-modes is enabled) +"ui.bufferline" = { fg = "fg3", bg = "bg2", underline = { style = "line" } } +"ui.bufferline.active" = { fg = "fg2", bg = "bg4" } +"ui.bufferline.background" = { bg = "bg0" } + "ui.help" = { bg = "sel0", fg = "fg1" } # Description box for commands. "ui.menu" = { bg = "sel0", fg = "fg1" } # Code and command completion menus. From 5406e9f629313221c8ae97583393dfd6221d3dfc Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Tue, 4 Apr 2023 23:34:47 +0200 Subject: [PATCH 192/260] correctly handle completion rerequest --- helix-term/src/commands.rs | 9 +++-- helix-term/src/ui/completion.rs | 46 ++++++++++++++++---------- helix-term/src/ui/editor.rs | 57 +++++++++++++++++++++++--------- helix-view/src/document.rs | 58 +++++++++++++++++++++++---------- helix-view/src/editor.rs | 13 +++++--- 5 files changed, 127 insertions(+), 56 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 7d86bc0b3..8d70cd9e5 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -33,7 +33,7 @@ use helix_core::{ use helix_view::{ clipboard::ClipboardType, document::{FormatterError, Mode, SCRATCH_BUFFER_NAME}, - editor::{Action, Motion}, + editor::{Action, CompleteAction, Motion}, info::Info, input::KeyEvent, keyboard::KeyCode, @@ -4254,7 +4254,12 @@ pub fn completion(cx: &mut Context) { iter.reverse(); let offset = iter.take_while(|ch| chars::char_is_word(*ch)).count(); let start_offset = cursor.saturating_sub(offset); - let savepoint = doc.savepoint(view); + let savepoint = if let Some(CompleteAction::Selected { savepoint }) = &cx.editor.last_completion + { + savepoint.clone() + } else { + doc.savepoint(view) + }; let trigger_doc = doc.id(); let trigger_view = view.id; diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index bc216509f..dd21be03f 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -209,14 +209,27 @@ impl Completion { let (view, doc) = current!(editor); - // if more text was entered, remove it - doc.restore(view, &savepoint); - match event { - PromptEvent::Abort => { - editor.last_completion = None; - } + PromptEvent::Abort => {} PromptEvent::Update => { + // Update creates "ghost" transactiosn which are not send to the + // lsp server to avoid messing up rerequesting completions. Once a + // completion has been selected (with) tab it's always accepted whenever anything + // is typed. The only way to avoid that is to explicitly abort the completion + // with esc/c-c. This will remove the "ghost" transaction. + // + // The ghost transaction is modeled with a transaction that is not send to the LS. + // (apply_temporary) and a savepoint. It's extremly important this savepoint is restored + // (also without sending the transaction to the LS) *before any further transaction is applied*. + // Otherwise incremental sync breaks (since the state of the LS doesn't match the state the transaction + // is applied to). + if editor.last_completion.is_none() { + editor.last_completion = Some(CompleteAction::Selected { + savepoint: doc.savepoint(view), + }) + } + // if more text was entered, remove it + doc.restore(view, &savepoint, false); // always present here let item = item.unwrap(); @@ -229,19 +242,20 @@ impl Completion { true, replace_mode, ); - - // initialize a savepoint - doc.apply(&transaction, view.id); - - editor.last_completion = Some(CompleteAction { - trigger_offset, - changes: completion_changes(&transaction, trigger_offset), - }); + doc.apply_temporary(&transaction, view.id); } PromptEvent::Validate => { + if let Some(CompleteAction::Selected { savepoint }) = + editor.last_completion.take() + { + doc.restore(view, &savepoint, false); + } // always present here let item = item.unwrap(); + + // if more text was entered, remove it + doc.restore(view, &savepoint, true); let transaction = item_to_transaction( doc, view.id, @@ -251,10 +265,9 @@ impl Completion { false, replace_mode, ); - doc.apply(&transaction, view.id); - editor.last_completion = Some(CompleteAction { + editor.last_completion = Some(CompleteAction::Applied { trigger_offset, changes: completion_changes(&transaction, trigger_offset), }); @@ -270,7 +283,6 @@ impl Completion { } else { Self::resolve_completion_item(doc, item.clone()) }; - if let Some(additional_edits) = resolved_item .as_ref() .and_then(|item| item.additional_text_edits.as_ref()) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 1ecbc8cc1..f0989fa88 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -19,7 +19,7 @@ use helix_core::{ syntax::{self, HighlightEvent}, text_annotations::TextAnnotations, unicode::width::UnicodeWidthStr, - visual_offset_from_block, Position, Range, Selection, Transaction, + visual_offset_from_block, Change, Position, Range, Selection, Transaction, }; use helix_view::{ document::{Mode, SavePoint, SCRATCH_BUFFER_NAME}, @@ -48,7 +48,10 @@ pub struct EditorView { #[derive(Debug, Clone)] pub enum InsertEvent { Key(KeyEvent), - CompletionApply(CompleteAction), + CompletionApply { + trigger_offset: usize, + changes: Vec, + }, TriggerCompletion, RequestCompletion, } @@ -813,7 +816,7 @@ impl EditorView { } (Mode::Insert, Mode::Normal) => { // if exiting insert mode, remove completion - self.completion = None; + self.clear_completion(cxt.editor); cxt.editor.completion_request_handle = None; // TODO: Use an on_mode_change hook to remove signature help @@ -891,22 +894,25 @@ impl EditorView { for key in self.last_insert.1.clone() { match key { InsertEvent::Key(key) => self.insert_mode(cxt, key), - InsertEvent::CompletionApply(compl) => { + InsertEvent::CompletionApply { + trigger_offset, + changes, + } => { let (view, doc) = current!(cxt.editor); if let Some(last_savepoint) = last_savepoint.as_deref() { - doc.restore(view, last_savepoint); + doc.restore(view, last_savepoint, true); } let text = doc.text().slice(..); let cursor = doc.selection(view.id).primary().cursor(text); let shift_position = - |pos: usize| -> usize { pos + cursor - compl.trigger_offset }; + |pos: usize| -> usize { pos + cursor - trigger_offset }; let tx = Transaction::change( doc.text(), - compl.changes.iter().cloned().map(|(start, end, t)| { + changes.iter().cloned().map(|(start, end, t)| { (shift_position(start), shift_position(end), t) }), ); @@ -979,6 +985,21 @@ impl EditorView { pub fn clear_completion(&mut self, editor: &mut Editor) { self.completion = None; + if let Some(last_completion) = editor.last_completion.take() { + match last_completion { + CompleteAction::Applied { + trigger_offset, + changes, + } => self.last_insert.1.push(InsertEvent::CompletionApply { + trigger_offset, + changes, + }), + CompleteAction::Selected { savepoint } => { + let (view, doc) = current!(editor); + doc.restore(view, &savepoint, false); + } + } + } // Clear any savepoints editor.clear_idle_timer(); // don't retrigger @@ -1265,12 +1286,22 @@ impl Component for EditorView { jobs: cx.jobs, scroll: None, }; - completion.handle_event(event, &mut cx) - }; - if let EventResult::Consumed(callback) = res { - consumed = true; + if let EventResult::Consumed(callback) = + completion.handle_event(event, &mut cx) + { + consumed = true; + Some(callback) + } else if let EventResult::Consumed(callback) = + completion.handle_event(&Event::Key(key!(Enter)), &mut cx) + { + Some(callback) + } else { + None + } + }; + if let Some(callback) = res { if callback.is_some() { // assume close_fn self.clear_completion(cx.editor); @@ -1286,10 +1317,6 @@ impl Component for EditorView { // if completion didn't take the event, we pass it onto commands if !consumed { - if let Some(compl) = cx.editor.last_completion.take() { - self.last_insert.1.push(InsertEvent::CompletionApply(compl)); - } - self.insert_mode(&mut cx, key); // record last_insert key diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 27f69d508..4948befdd 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1034,7 +1034,12 @@ impl Document { } /// Apply a [`Transaction`] to the [`Document`] to change its text. - fn apply_impl(&mut self, transaction: &Transaction, view_id: ViewId) -> bool { + fn apply_impl( + &mut self, + transaction: &Transaction, + view_id: ViewId, + emit_lsp_notification: bool, + ) -> bool { use helix_core::Assoc; let old_doc = self.text().clone(); @@ -1130,25 +1135,31 @@ impl Document { apply_inlay_hint_changes(padding_after_inlay_hints); } - // emit lsp notification - if let Some(language_server) = self.language_server() { - let notify = language_server.text_document_did_change( - self.versioned_identifier(), - &old_doc, - self.text(), - changes, - ); + if emit_lsp_notification { + // emit lsp notification + if let Some(language_server) = self.language_server() { + let notify = language_server.text_document_did_change( + self.versioned_identifier(), + &old_doc, + self.text(), + changes, + ); - if let Some(notify) = notify { - tokio::spawn(notify); + if let Some(notify) = notify { + tokio::spawn(notify); + } } } } success } - /// Apply a [`Transaction`] to the [`Document`] to change its text. - pub fn apply(&mut self, transaction: &Transaction, view_id: ViewId) -> bool { + fn apply_inner( + &mut self, + transaction: &Transaction, + view_id: ViewId, + emit_lsp_notification: bool, + ) -> bool { // store the state just before any changes are made. This allows us to undo to the // state just before a transaction was applied. if self.changes.is_empty() && !transaction.changes().is_empty() { @@ -1158,7 +1169,7 @@ impl Document { }); } - let success = self.apply_impl(transaction, view_id); + let success = self.apply_impl(transaction, view_id, emit_lsp_notification); if !transaction.changes().is_empty() { // Compose this transaction with the previous one @@ -1168,12 +1179,23 @@ impl Document { } success } + /// Apply a [`Transaction`] to the [`Document`] to change its text. + pub fn apply(&mut self, transaction: &Transaction, view_id: ViewId) -> bool { + self.apply_inner(transaction, view_id, true) + } + + /// Apply a [`Transaction`] to the [`Document`] to change its text. + /// without notifying the language servers. This is useful for temporary transactions + /// that must not influence the server. + pub fn apply_temporary(&mut self, transaction: &Transaction, view_id: ViewId) -> bool { + self.apply_inner(transaction, view_id, false) + } fn undo_redo_impl(&mut self, view: &mut View, undo: bool) -> bool { let mut history = self.history.take(); let txn = if undo { history.undo() } else { history.redo() }; let success = if let Some(txn) = txn { - self.apply_impl(txn, view.id) + self.apply_impl(txn, view.id, true) } else { false }; @@ -1213,7 +1235,7 @@ impl Document { savepoint } - pub fn restore(&mut self, view: &mut View, savepoint: &SavePoint) { + pub fn restore(&mut self, view: &mut View, savepoint: &SavePoint, emit_lsp_notification: bool) { assert_eq!( savepoint.view, view.id, "Savepoint must not be used with a different view!" @@ -1228,7 +1250,7 @@ impl Document { let savepoint_ref = self.savepoints.remove(savepoint_idx); let mut revert = savepoint.revert.lock(); - self.apply(&revert, view.id); + self.apply_inner(&revert, view.id, emit_lsp_notification); *revert = Transaction::new(self.text()).with_selection(self.selection(view.id).clone()); self.savepoints.push(savepoint_ref) } @@ -1241,7 +1263,7 @@ impl Document { }; let mut success = false; for txn in txns { - if self.apply_impl(&txn, view.id) { + if self.apply_impl(&txn, view.id, true) { success = true; } } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 8e4dab414..43227c5f1 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1,7 +1,7 @@ use crate::{ align_view, clipboard::{get_clipboard_provider, ClipboardProvider}, - document::{DocumentSavedEventFuture, DocumentSavedEventResult, Mode}, + document::{DocumentSavedEventFuture, DocumentSavedEventResult, Mode, SavePoint}, graphics::{CursorKind, Rect}, info::Info, input::KeyEvent, @@ -906,9 +906,14 @@ enum ThemeAction { } #[derive(Debug, Clone)] -pub struct CompleteAction { - pub trigger_offset: usize, - pub changes: Vec, +pub enum CompleteAction { + Applied { + trigger_offset: usize, + changes: Vec, + }, + /// A savepoint of the currently active completion. The completion + /// MUST be restored before sending any event to the LSP + Selected { savepoint: Arc }, } #[derive(Debug, Copy, Clone)] From 30ff7f8db29d5fc84191268b94ec971e7ca5da5d Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Tue, 4 Apr 2023 23:35:31 +0200 Subject: [PATCH 193/260] resolve completions before applying transactions --- helix-term/src/ui/completion.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index dd21be03f..7ec4f5775 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -253,6 +253,17 @@ impl Completion { // always present here let item = item.unwrap(); + // apply additional edits, mostly used to auto import unqualified types + 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()) + }; // if more text was entered, remove it doc.restore(view, &savepoint, true); @@ -272,17 +283,6 @@ impl Completion { changes: completion_changes(&transaction, trigger_offset), }); - // apply additional edits, mostly used to auto import unqualified types - 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()) - }; if let Some(additional_edits) = resolved_item .as_ref() .and_then(|item| item.additional_text_edits.as_ref()) From 9c558fc4705934097b5f20b100462fc1fa4f50e1 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Wed, 5 Apr 2023 01:38:17 +0200 Subject: [PATCH 194/260] ensure correct trigger/start completion offset When re requesting a completion that already has a selected item we reuse that selections savepoint. However, the selection has likely changed since that savepoint which requires us to use the selection from that savepoint --- helix-term/src/commands.rs | 19 ++++++++++--------- helix-view/src/document.rs | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 8d70cd9e5..80774ceae 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4210,16 +4210,23 @@ pub fn completion(cx: &mut Context) { let (view, doc) = current!(cx.editor); + let savepoint = if let Some(CompleteAction::Selected { savepoint }) = &cx.editor.last_completion + { + savepoint.clone() + } else { + doc.savepoint(view) + }; + let language_server = match doc.language_server() { Some(language_server) => language_server, None => return, }; let offset_encoding = language_server.offset_encoding(); - let text = doc.text().slice(..); - let cursor = doc.selection(view.id).primary().cursor(text); + let text = savepoint.text.clone(); + let cursor = savepoint.cursor(); - let pos = pos_to_lsp_pos(doc.text(), cursor, offset_encoding); + let pos = pos_to_lsp_pos(&text, cursor, offset_encoding); let future = match language_server.completion(doc.identifier(), pos, None) { Some(future) => future, @@ -4254,12 +4261,6 @@ pub fn completion(cx: &mut Context) { iter.reverse(); let offset = iter.take_while(|ch| chars::char_is_word(*ch)).count(); let start_offset = cursor.saturating_sub(offset); - let savepoint = if let Some(CompleteAction::Selected { savepoint }) = &cx.editor.last_completion - { - savepoint.clone() - } else { - doc.savepoint(view) - }; let trigger_doc = doc.id(); let trigger_view = view.id; diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 4948befdd..e467efd39 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -114,6 +114,19 @@ pub struct SavePoint { /// The view this savepoint is associated with pub view: ViewId, revert: Mutex, + pub text: Rope, +} + +impl SavePoint { + pub fn cursor(&self) -> usize { + // we always create transactions with selections + self.revert + .lock() + .selection() + .unwrap() + .primary() + .cursor(self.text.slice(..)) + } } pub struct Document { @@ -1230,6 +1243,7 @@ impl Document { let savepoint = Arc::new(SavePoint { view: view.id, revert: Mutex::new(revert), + text: self.text.clone(), }); self.savepoints.push(Arc::downgrade(&savepoint)); savepoint From bcb8c3d34d87d97d01d37a2dda839197f2a375d8 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Wed, 5 Apr 2023 20:24:49 +0200 Subject: [PATCH 195/260] deduplicate savepoints --- helix-view/src/document.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index e467efd39..4d8e61e1d 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1240,6 +1240,22 @@ impl Document { /// the state it had when this function was called. pub fn savepoint(&mut self, view: &View) -> Arc { let revert = Transaction::new(self.text()).with_selection(self.selection(view.id).clone()); + // check if there is already an existing (identical) savepoint around + if let Some(savepoint) = self + .savepoints + .iter() + .rev() + .find_map(|savepoint| savepoint.upgrade()) + { + let transaction = savepoint.revert.lock(); + if savepoint.view == view.id + && transaction.changes().is_empty() + && transaction.selection() == revert.selection() + { + drop(transaction); + return savepoint; + } + } let savepoint = Arc::new(SavePoint { view: view.id, revert: Mutex::new(revert), From 28b730381cc93d06e5a090b8734505edbebb1af4 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Wed, 5 Apr 2023 20:25:28 +0200 Subject: [PATCH 196/260] only resolve completion items once --- helix-term/src/ui/completion.rs | 97 +++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index 7ec4f5775..c736f043f 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -16,7 +16,6 @@ use crate::commands; use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent}; use helix_lsp::{lsp, util}; -use lsp::CompletionItem; impl menu::Item for CompletionItem { type Data = (); @@ -26,28 +25,29 @@ impl menu::Item for CompletionItem { #[inline] fn filter_text(&self, _data: &Self::Data) -> Cow { - self.filter_text + self.item + .filter_text .as_ref() - .unwrap_or(&self.label) + .unwrap_or(&self.item.label) .as_str() .into() } fn format(&self, _data: &Self::Data) -> menu::Row { - let deprecated = self.deprecated.unwrap_or_default() - || self.tags.as_ref().map_or(false, |tags| { + let deprecated = self.item.deprecated.unwrap_or_default() + || self.item.tags.as_ref().map_or(false, |tags| { tags.contains(&lsp::CompletionItemTag::DEPRECATED) }); menu::Row::new(vec![ menu::Cell::from(Span::styled( - self.label.as_str(), + self.item.label.as_str(), if deprecated { Style::default().add_modifier(Modifier::CROSSED_OUT) } else { Style::default() }, )), - menu::Cell::from(match self.kind { + menu::Cell::from(match self.item.kind { Some(lsp::CompletionItemKind::TEXT) => "text", Some(lsp::CompletionItemKind::METHOD) => "method", Some(lsp::CompletionItemKind::FUNCTION) => "function", @@ -88,6 +88,12 @@ impl menu::Item for CompletionItem { } } +#[derive(Debug, PartialEq, Default, Clone)] +struct CompletionItem { + item: lsp::CompletionItem, + resolved: bool, +} + /// Wraps a Menu. pub struct Completion { popup: Popup>, @@ -103,7 +109,7 @@ impl Completion { pub fn new( editor: &Editor, savepoint: Arc, - mut items: Vec, + mut items: Vec, offset_encoding: helix_lsp::OffsetEncoding, start_offset: usize, trigger_offset: usize, @@ -111,6 +117,13 @@ impl Completion { let replace_mode = editor.config().completion_replace; // Sort completion items according to their preselect status (given by the LSP server) items.sort_by_key(|item| !item.preselect.unwrap_or(false)); + let items = items + .into_iter() + .map(|item| CompletionItem { + item, + resolved: false, + }) + .collect(); // Then create the menu let menu = Menu::new(items, (), move |editor: &mut Editor, item, event| { @@ -128,7 +141,7 @@ impl Completion { let text = doc.text().slice(..); let primary_cursor = selection.primary().cursor(text); - let (edit_offset, new_text) = if let Some(edit) = &item.text_edit { + let (edit_offset, new_text) = if let Some(edit) = &item.item.text_edit { let edit = match edit { lsp::CompletionTextEdit::Edit(edit) => edit.clone(), lsp::CompletionTextEdit::InsertAndReplace(item) => { @@ -151,9 +164,10 @@ impl Completion { (Some((start_offset, end_offset)), edit.new_text) } else { let new_text = item + .item .insert_text .clone() - .unwrap_or_else(|| item.label.clone()); + .unwrap_or_else(|| item.item.label.clone()); // check that we are still at the correct savepoint // we can still generate a transaction regardless but if the // document changed (and not just the selection) then we will @@ -162,9 +176,9 @@ impl Completion { (None, new_text) }; - if matches!(item.kind, Some(lsp::CompletionItemKind::SNIPPET)) + if matches!(item.item.kind, Some(lsp::CompletionItemKind::SNIPPET)) || matches!( - item.insert_text_format, + item.item.insert_text_format, Some(lsp::InsertTextFormat::SNIPPET) ) { @@ -251,26 +265,22 @@ impl Completion { doc.restore(view, &savepoint, false); } // always present here - let item = item.unwrap(); - - // apply additional edits, mostly used to auto import unqualified types - 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()) + let mut item = item.unwrap().clone(); + + // resolve item if not yet resolved + if !item.resolved { + if let Some(resolved) = + Self::resolve_completion_item(doc, item.item.clone()) + { + item.item = resolved; + } }; - // if more text was entered, remove it doc.restore(view, &savepoint, true); let transaction = item_to_transaction( doc, view.id, - item, + &item, offset_encoding, trigger_offset, false, @@ -283,15 +293,12 @@ impl Completion { changes: completion_changes(&transaction, trigger_offset), }); - if let Some(additional_edits) = resolved_item - .as_ref() - .and_then(|item| item.additional_text_edits.as_ref()) - .or(item.additional_text_edits.as_ref()) - { + // TOOD: add additional _edits to completion_changes? + if let Some(additional_edits) = item.item.additional_text_edits { if !additional_edits.is_empty() { let transaction = util::generate_transaction_from_edits( doc.text(), - additional_edits.clone(), + additional_edits, offset_encoding, // TODO: should probably transcode in Client ); doc.apply(&transaction, view.id); @@ -318,7 +325,7 @@ impl Completion { fn resolve_completion_item( doc: &Document, completion_item: lsp::CompletionItem, - ) -> Option { + ) -> Option { let language_server = doc.language_server()?; let future = language_server.resolve_completion_item(completion_item)?; @@ -371,7 +378,7 @@ impl Completion { self.popup.contents().is_empty() } - fn replace_item(&mut self, old_item: lsp::CompletionItem, new_item: lsp::CompletionItem) { + fn replace_item(&mut self, old_item: CompletionItem, new_item: CompletionItem) { self.popup.contents_mut().replace_option(old_item, new_item); } @@ -387,7 +394,7 @@ impl Completion { // > The returned completion item should have the documentation property filled in. // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion let current_item = match self.popup.contents().selection() { - Some(item) if item.documentation.is_none() => item.clone(), + Some(item) if !item.resolved => item.clone(), _ => return false, }; @@ -397,7 +404,7 @@ impl Completion { }; // This method should not block the compositor so we handle the response asynchronously. - let future = match language_server.resolve_completion_item(current_item.clone()) { + let future = match language_server.resolve_completion_item(current_item.item.clone()) { Some(future) => future, None => return false, }; @@ -415,7 +422,13 @@ impl Completion { .unwrap() .completion { - completion.replace_item(current_item, resolved_item); + completion.replace_item( + current_item, + CompletionItem { + item: resolved_item, + resolved: true, + }, + ); } }, ); @@ -469,25 +482,25 @@ impl Component for Completion { Markdown::new(md, cx.editor.syn_loader.clone()) }; - let mut markdown_doc = match &option.documentation { + let mut markdown_doc = match &option.item.documentation { Some(lsp::Documentation::String(contents)) | Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind: lsp::MarkupKind::PlainText, value: contents, })) => { // TODO: convert to wrapped text - markdowned(language, option.detail.as_deref(), Some(contents)) + markdowned(language, option.item.detail.as_deref(), Some(contents)) } Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind: lsp::MarkupKind::Markdown, value: contents, })) => { // TODO: set language based on doc scope - markdowned(language, option.detail.as_deref(), Some(contents)) + markdowned(language, option.item.detail.as_deref(), Some(contents)) } - None if option.detail.is_some() => { + None if option.item.detail.is_some() => { // TODO: set language based on doc scope - markdowned(language, option.detail.as_deref(), None) + markdowned(language, option.item.detail.as_deref(), None) } None => return, }; From 6842fd4c36c5855023b007a36b0b5c8bd965d8de Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Fri, 7 Apr 2023 14:50:47 +0200 Subject: [PATCH 197/260] clarify comments about completion savepoints Co-authored-by: Michael Davis --- helix-term/src/ui/completion.rs | 14 +++++++------- helix-view/src/document.rs | 2 +- helix-view/src/editor.rs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index c736f043f..c5c405801 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -226,14 +226,14 @@ impl Completion { match event { PromptEvent::Abort => {} PromptEvent::Update => { - // Update creates "ghost" transactiosn which are not send to the - // lsp server to avoid messing up rerequesting completions. Once a - // completion has been selected (with) tab it's always accepted whenever anything + // Update creates "ghost" transactions which are not sent to the + // lsp server to avoid messing up re-requesting completions. Once a + // completion has been selected (with tab, c-n or c-p) it's always accepted whenever anything // is typed. The only way to avoid that is to explicitly abort the completion - // with esc/c-c. This will remove the "ghost" transaction. + // with c-c. This will remove the "ghost" transaction. // - // The ghost transaction is modeled with a transaction that is not send to the LS. - // (apply_temporary) and a savepoint. It's extremly important this savepoint is restored + // The ghost transaction is modeled with a transaction that is not sent to the LS. + // (apply_temporary) and a savepoint. It's extremely important this savepoint is restored // (also without sending the transaction to the LS) *before any further transaction is applied*. // Otherwise incremental sync breaks (since the state of the LS doesn't match the state the transaction // is applied to). @@ -293,7 +293,7 @@ impl Completion { changes: completion_changes(&transaction, trigger_offset), }); - // TOOD: add additional _edits to completion_changes? + // TODO: add additional _edits to completion_changes? if let Some(additional_edits) = item.item.additional_text_edits { if !additional_edits.is_empty() { let transaction = util::generate_transaction_from_edits( diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 4d8e61e1d..e29e52cc5 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1197,7 +1197,7 @@ impl Document { self.apply_inner(transaction, view_id, true) } - /// Apply a [`Transaction`] to the [`Document`] to change its text. + /// Apply a [`Transaction`] to the [`Document`] to change its text /// without notifying the language servers. This is useful for temporary transactions /// that must not influence the server. pub fn apply_temporary(&mut self, transaction: &Transaction, view_id: ViewId) -> bool { diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 43227c5f1..9546d460b 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -911,7 +911,7 @@ pub enum CompleteAction { trigger_offset: usize, changes: Vec, }, - /// A savepoint of the currently active completion. The completion + /// A savepoint of the currently selected completion. The savepoint /// MUST be restored before sending any event to the LSP Selected { savepoint: Arc }, } From f8225ed9219f23cf04bd378ec43e1e1a1059a0ed Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Thu, 16 Feb 2023 22:15:06 +0100 Subject: [PATCH 198/260] fix panic when deleting overlapping ranges Some deletion operations (especially those that use indentation) can generate overlapping deletion ranges when using multiple cursors. To fix that problem a new `Transaction::delete` and `Transaction:delete_by_selection` function were added. These functions merge overlapping deletion ranges instead of generating an invalid transaction. This merging of changes is only possible for deletions and not for other changes and therefore require its own function. The function has been used in all commands that currently delete text by using `Transaction::change_by_selection`. --- helix-core/src/lib.rs | 2 +- helix-core/src/transaction.rs | 46 +++++++++++++++++++++++++++++++ helix-term/src/commands.rs | 37 ++++++++----------------- helix-term/tests/test/commands.rs | 44 +++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 27 deletions(-) diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index b67e2c8a3..14abf0162 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -67,4 +67,4 @@ pub use syntax::Syntax; pub use diagnostic::Diagnostic; pub use line_ending::{LineEnding, DEFAULT_LINE_ENDING}; -pub use transaction::{Assoc, Change, ChangeSet, Operation, Transaction}; +pub use transaction::{Assoc, Change, ChangeSet, Deletion, Operation, Transaction}; diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index d8e581aae..06efe259f 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -5,6 +5,7 @@ use std::borrow::Cow; /// (from, to, replacement) pub type Change = (usize, usize, Option); +pub type Deletion = (usize, usize); // TODO: pub(crate) #[derive(Debug, Clone, PartialEq, Eq)] @@ -534,6 +535,41 @@ impl Transaction { Self::from(changeset) } + /// Generate a transaction from a set of potentially overlapping deletions + /// by merging overlapping deletions together. + pub fn delete(doc: &Rope, deletions: I) -> Self + where + I: Iterator, + { + let len = doc.len_chars(); + + let (lower, upper) = deletions.size_hint(); + let size = upper.unwrap_or(lower); + let mut changeset = ChangeSet::with_capacity(2 * size + 1); // rough estimate + + let mut last = 0; + for (mut from, to) in deletions { + if last > to { + continue; + } + if last > from { + from = last + } + debug_assert!( + from <= to, + "Edit end must end before it starts (should {from} <= {to})" + ); + // Retain from last "to" to current "from" + changeset.retain(from - last); + changeset.delete(to - from); + last = to; + } + + changeset.retain(len - last); + + Self::from(changeset) + } + /// Generate a transaction with a change per selection range. pub fn change_by_selection(doc: &Rope, selection: &Selection, f: F) -> Self where @@ -580,6 +616,16 @@ impl Transaction { ) } + /// Generate a transaction with a deletion per selection range. + /// Compared to using `change_by_selection` directly these ranges may overlap. + /// In that case they are merged + pub fn delete_by_selection(doc: &Rope, selection: &Selection, f: F) -> Self + where + F: FnMut(&Range) -> Deletion, + { + Self::delete(doc, selection.iter().map(f)) + } + /// Insert text at each selection head. pub fn insert(doc: &Rope, selection: &Selection, text: Tendril) -> Self { Self::change_by_selection(doc, selection, |range| { diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 80774ceae..964d87ff9 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2315,9 +2315,8 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) { }; // then delete - let transaction = Transaction::change_by_selection(doc.text(), selection, |range| { - (range.from(), range.to(), None) - }); + let transaction = + Transaction::delete_by_selection(doc.text(), selection, |range| (range.from(), range.to())); doc.apply(&transaction, view.id); match op { @@ -2333,9 +2332,8 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) { #[inline] fn delete_selection_insert_mode(doc: &mut Document, view: &mut View, selection: &Selection) { - let transaction = Transaction::change_by_selection(doc.text(), selection, |range| { - (range.from(), range.to(), None) - }); + let transaction = + Transaction::delete_by_selection(doc.text(), selection, |range| (range.from(), range.to())); doc.apply(&transaction, view.id); } @@ -3422,10 +3420,10 @@ pub mod insert { let auto_pairs = doc.auto_pairs(cx.editor); let transaction = - Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| { + Transaction::delete_by_selection(doc.text(), doc.selection(view.id), |range| { let pos = range.cursor(text); if pos == 0 { - return (pos, pos, None); + return (pos, pos); } 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. @@ -3433,11 +3431,7 @@ pub mod insert { 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 - ( - graphemes::nth_prev_grapheme_boundary(text, pos, 1), - pos, - None, - ) + (graphemes::nth_prev_grapheme_boundary(text, pos, 1), pos) } else { let width: usize = fragment .chars() @@ -3464,7 +3458,7 @@ pub mod insert { _ => break, } } - (start, pos, None) // delete! + (start, pos) // delete! } } else { match ( @@ -3482,17 +3476,12 @@ pub mod insert { ( graphemes::nth_prev_grapheme_boundary(text, pos, count), graphemes::nth_next_grapheme_boundary(text, pos, count), - None, ) } _ => // delete 1 char { - ( - graphemes::nth_prev_grapheme_boundary(text, pos, count), - pos, - None, - ) + (graphemes::nth_prev_grapheme_boundary(text, pos, count), pos) } } } @@ -3508,13 +3497,9 @@ pub mod insert { let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); let transaction = - Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| { + Transaction::delete_by_selection(doc.text(), doc.selection(view.id), |range| { let pos = range.cursor(text); - ( - pos, - graphemes::nth_next_grapheme_boundary(text, pos, count), - None, - ) + (pos, graphemes::nth_next_grapheme_boundary(text, pos, count)) }); doc.apply(&transaction, view.id); diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index 342a849be..1efb204e6 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -385,3 +385,47 @@ async fn test_character_info() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test(flavor = "multi_thread")] +async fn test_delete_char_backward() -> anyhow::Result<()> { + // don't panic when deleting overlapping ranges + test(( + platform_line("#(x|)# #[x|]#").as_str(), + "c", + platform_line("#[\n|]#").as_str(), + )) + .await?; + test(( + platform_line("#( |)##( |)#a#( |)#axx#[x|]#a").as_str(), + "li", + platform_line("#(a|)##(|a)#xx#[|a]#").as_str(), + )) + .await?; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_delete_word_backward() -> anyhow::Result<()> { + // don't panic when deleting overlapping ranges + test(( + platform_line("fo#[o|]#ba#(r|)#").as_str(), + "a", + platform_line("#[\n|]#").as_str(), + )) + .await?; + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_delete_word_forward() -> anyhow::Result<()> { + // don't panic when deleting overlapping ranges + test(( + platform_line("fo#[o|]#b#(|ar)#").as_str(), + "i", + platform_line("fo#[\n|]#").as_str(), + )) + .await?; + Ok(()) +} + From 2c3ccc3e8b2487e9bcca271341aabc67811ebb46 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Thu, 16 Feb 2023 22:59:15 +0100 Subject: [PATCH 199/260] cleanup delete_by_selection_insert_mode function --- helix-term/src/commands.rs | 84 ++++++++++++++------------------------ 1 file changed, 31 insertions(+), 53 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 964d87ff9..05b5b9b69 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -27,8 +27,8 @@ use helix_core::{ textobject, tree_sitter::Node, unicode::width::UnicodeWidthChar, - visual_offset_from_block, LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, - Selection, SmallVec, Tendril, Transaction, + visual_offset_from_block, Deletion, LineEnding, Position, Range, Rope, RopeGraphemes, + RopeSlice, Selection, SmallVec, Tendril, Transaction, }; use helix_view::{ clipboard::ClipboardType, @@ -795,10 +795,7 @@ fn extend_to_line_start(cx: &mut Context) { } fn kill_to_line_start(cx: &mut Context) { - let (view, doc) = current!(cx.editor); - let text = doc.text().slice(..); - - let selection = doc.selection(view.id).clone().transform(|range| { + delete_by_selection_insert_mode(cx, move |text, range| { let line = range.cursor_line(text); let first_char = text.line_to_char(line); let anchor = range.cursor(text); @@ -817,32 +814,23 @@ fn kill_to_line_start(cx: &mut Context) { // select until start of line first_char }; - Range::new(head, anchor) + (head, anchor) }); - delete_selection_insert_mode(doc, view, &selection); - - lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } fn kill_to_line_end(cx: &mut Context) { - let (view, doc) = current!(cx.editor); - let text = doc.text().slice(..); - - let selection = doc.selection(view.id).clone().transform(|range| { + delete_by_selection_insert_mode(cx, |text, range| { let line = range.cursor_line(text); let line_end_pos = line_end_char_index(&text, line); let pos = range.cursor(text); - let mut new_range = range.put_cursor(text, line_end_pos, true); - // don't want to remove the line separator itself if the cursor doesn't reach the end of line. - if pos != line_end_pos { - new_range.head = line_end_pos; + // if the cursor is on the newline char delete that + if pos == line_end_pos { + (pos, text.line_to_char(line + 1)) + } else { + (pos, line_end_pos) } - new_range }); - delete_selection_insert_mode(doc, view, &selection); - - lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } fn goto_first_nonwhitespace(cx: &mut Context) { @@ -2331,10 +2319,18 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) { } #[inline] -fn delete_selection_insert_mode(doc: &mut Document, view: &mut View, selection: &Selection) { +fn delete_by_selection_insert_mode( + cx: &mut Context, + mut f: impl FnMut(RopeSlice, &Range) -> Deletion, +) { + let (view, doc) = current!(cx.editor); + let text = doc.text().slice(..); let transaction = - Transaction::delete_by_selection(doc.text(), selection, |range| (range.from(), range.to())); + Transaction::delete_by_selection(doc.text(), doc.selection(view.id), |range| { + f(text, range) + }); doc.apply(&transaction, view.id); + lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } fn delete_selection(cx: &mut Context) { @@ -3494,46 +3490,28 @@ pub mod insert { pub fn delete_char_forward(cx: &mut Context) { let count = cx.count(); - let (view, doc) = current!(cx.editor); - let text = doc.text().slice(..); - let transaction = - Transaction::delete_by_selection(doc.text(), doc.selection(view.id), |range| { - let pos = range.cursor(text); - (pos, graphemes::nth_next_grapheme_boundary(text, pos, count)) - }); - doc.apply(&transaction, view.id); - - lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); + delete_by_selection_insert_mode(cx, |text, range| { + let pos = range.cursor(text); + (pos, graphemes::nth_next_grapheme_boundary(text, pos, count)) + }) } pub fn delete_word_backward(cx: &mut Context) { let count = cx.count(); - let (view, doc) = current!(cx.editor); - let text = doc.text().slice(..); - - let selection = doc.selection(view.id).clone().transform(|range| { - let anchor = movement::move_prev_word_start(text, range, count).from(); + delete_by_selection_insert_mode(cx, |text, range| { + let anchor = movement::move_prev_word_start(text, *range, count).from(); let next = Range::new(anchor, range.cursor(text)); - exclude_cursor(text, next, range) + let range = exclude_cursor(text, next, *range); + (range.from(), range.to()) }); - delete_selection_insert_mode(doc, view, &selection); - - lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } pub fn delete_word_forward(cx: &mut Context) { let count = cx.count(); - let (view, doc) = current!(cx.editor); - let text = doc.text().slice(..); - - let selection = doc.selection(view.id).clone().transform(|range| { - let head = movement::move_next_word_end(text, range, count).to(); - Range::new(range.cursor(text), head) + delete_by_selection_insert_mode(cx, |text, range| { + let head = movement::move_next_word_end(text, *range, count).to(); + (range.cursor(text), head) }); - - delete_selection_insert_mode(doc, view, &selection); - - lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } } From 25d4ebe30d7920bc087f004075048f62f53726af Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Mon, 20 Feb 2023 16:31:26 +0100 Subject: [PATCH 200/260] don't move cursor while forward deleting in append mode Currently, when forward deleting (`delete_char_forward` bound to `del`, `delete_word_forward`, `kill_to_line_end`) the cursor is moved to the left in append mode (or generally when the cursor is at the end of the selection). For example in a document `|abc|def` (|indicates selection) if enter append mode the cursor is moved to `c` and the selection becomes: `|abcd|ef`. When deleting forward (`del`) `d` is deleted. The expectation would be that the selection doesn't shrink so that `del` again deletes `e` and then `f`. This would look as follows: `|abcd|ef` `|abce|f` `|abcf|` `|abc |` This is inline with how other editors like kakoune work. However, helix currently moves the selection backwards leading to the following behavior: `|abcd|ef` `|abc|ef` `|ab|ef` `ef` This means that `delete_char_forward` essentially acts like `delete_char_backward` after deleting the first character in append mode. To fix the problem the cursor must be moved to the right while deleting forward (first fix in this commit). Furthermore, when the EOF char is reached a newline char must be inserted (just like when entering appendmode) to prevent the cursor from moving to the right --- helix-core/src/transaction.rs | 5 ++ helix-term/src/commands.rs | 141 ++++++++++++++++++++---------- helix-term/tests/test/commands.rs | 23 +++++ 3 files changed, 124 insertions(+), 45 deletions(-) diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index 06efe259f..f4f94b540 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -570,6 +570,11 @@ impl Transaction { Self::from(changeset) } + pub fn insert_at_eof(mut self, text: Tendril) -> Transaction { + self.changes.insert(text); + self + } + /// Generate a transaction with a change per selection range. pub fn change_by_selection(doc: &Rope, selection: &Selection, f: F) -> Self where diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 05b5b9b69..5a844e351 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -795,42 +795,50 @@ fn extend_to_line_start(cx: &mut Context) { } fn kill_to_line_start(cx: &mut Context) { - delete_by_selection_insert_mode(cx, move |text, range| { - let line = range.cursor_line(text); - 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 + delete_by_selection_insert_mode( + cx, + move |text, range| { + let line = range.cursor_line(text); + 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 - } - } else { - // select until start of line - first_char - }; - (head, anchor) - }); + }; + (head, anchor) + }, + Direction::Backward, + ); } fn kill_to_line_end(cx: &mut Context) { - delete_by_selection_insert_mode(cx, |text, range| { - let line = range.cursor_line(text); - let line_end_pos = line_end_char_index(&text, line); - let pos = range.cursor(text); + delete_by_selection_insert_mode( + cx, + |text, range| { + let line = range.cursor_line(text); + let line_end_pos = line_end_char_index(&text, line); + let pos = range.cursor(text); - // if the cursor is on the newline char delete that - if pos == line_end_pos { - (pos, text.line_to_char(line + 1)) - } else { - (pos, line_end_pos) - } - }); + // if the cursor is on the newline char delete that + if pos == line_end_pos { + (pos, text.line_to_char(line + 1)) + } else { + (pos, line_end_pos) + } + }, + Direction::Forward, + ); } fn goto_first_nonwhitespace(cx: &mut Context) { @@ -2322,13 +2330,44 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) { fn delete_by_selection_insert_mode( cx: &mut Context, mut f: impl FnMut(RopeSlice, &Range) -> Deletion, + direction: Direction, ) { let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); - let transaction = + let mut selection = SmallVec::new(); + let mut insert_newline = false; + let text_len = text.len_chars(); + let mut transaction = Transaction::delete_by_selection(doc.text(), doc.selection(view.id), |range| { - f(text, range) + let (start, end) = f(text, range); + if direction == Direction::Forward { + let mut range = *range; + if range.head > range.anchor { + insert_newline |= end == text_len; + // move the cursor to the right so that the selection + // doesn't shrink when deleting forward (so the text appears to + // move to left) + // += 1 is enough here as the range is normalized to grapheme boundaries + // later anyway + range.head += 1; + } + selection.push(range); + } + (start, end) }); + + // in case we delete the last character and the cursor would be moved to the EOF char + // insert a newline, just like when entering append mode + if insert_newline { + transaction = transaction.insert_at_eof(doc.line_ending.as_str().into()); + } + + if direction == Direction::Forward { + doc.set_selection( + view.id, + Selection::new(selection, doc.selection(view.id).primary_index()), + ); + } doc.apply(&transaction, view.id); lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } @@ -3490,28 +3529,40 @@ pub mod insert { pub fn delete_char_forward(cx: &mut Context) { let count = cx.count(); - delete_by_selection_insert_mode(cx, |text, range| { - let pos = range.cursor(text); - (pos, graphemes::nth_next_grapheme_boundary(text, pos, count)) - }) + delete_by_selection_insert_mode( + cx, + |text, range| { + let pos = range.cursor(text); + (pos, graphemes::nth_next_grapheme_boundary(text, pos, count)) + }, + Direction::Forward, + ) } pub fn delete_word_backward(cx: &mut Context) { let count = cx.count(); - delete_by_selection_insert_mode(cx, |text, range| { - let anchor = movement::move_prev_word_start(text, *range, count).from(); - let next = Range::new(anchor, range.cursor(text)); - let range = exclude_cursor(text, next, *range); - (range.from(), range.to()) - }); + delete_by_selection_insert_mode( + cx, + |text, range| { + let anchor = movement::move_prev_word_start(text, *range, count).from(); + let next = Range::new(anchor, range.cursor(text)); + let range = exclude_cursor(text, next, *range); + (range.from(), range.to()) + }, + Direction::Backward, + ); } pub fn delete_word_forward(cx: &mut Context) { let count = cx.count(); - delete_by_selection_insert_mode(cx, |text, range| { - let head = movement::move_next_word_end(text, *range, count).to(); - (range.cursor(text), head) - }); + delete_by_selection_insert_mode( + cx, + |text, range| { + let head = movement::move_next_word_end(text, *range, count).to(); + (range.cursor(text), head) + }, + Direction::Forward, + ); } } diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index 1efb204e6..f91a6371f 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -429,3 +429,26 @@ async fn test_delete_word_forward() -> anyhow::Result<()> { Ok(()) } +#[tokio::test(flavor = "multi_thread")] +async fn test_delete_char_forward() -> anyhow::Result<()> { + test(( + platform_line(indoc! {"\ + #[abc|]#def + #(abc|)#ef + #(abc|)#f + #(abc|)# + "}) + .as_str(), + "a", + platform_line(indoc! {"\ + #[abc|]#ef + #(abc|)#f + #(abc|)# + #(abc|)# + "}) + .as_str(), + )) + .await?; + + Ok(()) +} From c6f169b1f87d01d72713e84bd331743e4da40f5f Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Wed, 3 May 2023 16:11:57 +0200 Subject: [PATCH 201/260] cleanup integration tests --- helix-term/tests/test/commands.rs | 94 +++++++++++-------------------- 1 file changed, 34 insertions(+), 60 deletions(-) diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index f91a6371f..52b123c7e 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -12,15 +12,13 @@ async fn test_selection_duplication() -> anyhow::Result<()> { #[lo|]#rem ipsum dolor - "}) - .as_str(), + "}), "CC", platform_line(indoc! {"\ #(lo|)#rem #(ip|)#sum #[do|]#lor - "}) - .as_str(), + "}), )) .await?; @@ -30,15 +28,13 @@ async fn test_selection_duplication() -> anyhow::Result<()> { #[|lo]#rem ipsum dolor - "}) - .as_str(), + "}), "CC", platform_line(indoc! {"\ #(|lo)#rem #(|ip)#sum #[|do]#lor - "}) - .as_str(), + "}), )) .await?; @@ -47,14 +43,12 @@ async fn test_selection_duplication() -> anyhow::Result<()> { platform_line(indoc! {"\ test #[testitem|]# - "}) - .as_str(), + "}), "", platform_line(indoc! {"\ test #[testitem|]# - "}) - .as_str(), + "}), )) .await?; @@ -63,14 +57,12 @@ async fn test_selection_duplication() -> anyhow::Result<()> { platform_line(indoc! {"\ test #[test|]# - "}) - .as_str(), + "}), "", platform_line(indoc! {"\ #[test|]# #(test|)# - "}) - .as_str(), + "}), )) .await?; @@ -79,14 +71,12 @@ async fn test_selection_duplication() -> anyhow::Result<()> { platform_line(indoc! {"\ #[testitem|]# test - "}) - .as_str(), + "}), "C", platform_line(indoc! {"\ #[testitem|]# test - "}) - .as_str(), + "}), )) .await?; @@ -95,14 +85,12 @@ async fn test_selection_duplication() -> anyhow::Result<()> { platform_line(indoc! {"\ #[test|]# test - "}) - .as_str(), + "}), "C", platform_line(indoc! {"\ #(test|)# #[test|]# - "}) - .as_str(), + "}), )) .await?; Ok(()) @@ -174,15 +162,13 @@ async fn test_multi_selection_paste() -> anyhow::Result<()> { #[|lorem]# #(|ipsum)# #(|dolor)# - "}) - .as_str(), + "}), "yp", platform_line(indoc! {"\ lorem#[|lorem]# ipsum#(|ipsum)# dolor#(|dolor)# - "}) - .as_str(), + "}), )) .await?; @@ -197,8 +183,7 @@ async fn test_multi_selection_shell_commands() -> anyhow::Result<()> { #[|lorem]# #(|ipsum)# #(|dolor)# - "}) - .as_str(), + "}), "|echo foo", platform_line(indoc! {"\ #[|foo\n]# @@ -207,8 +192,7 @@ async fn test_multi_selection_shell_commands() -> anyhow::Result<()> { #(|foo\n)# - "}) - .as_str(), + "}), )) .await?; @@ -218,8 +202,7 @@ async fn test_multi_selection_shell_commands() -> anyhow::Result<()> { #[|lorem]# #(|ipsum)# #(|dolor)# - "}) - .as_str(), + "}), "!echo foo", platform_line(indoc! {"\ #[|foo\n]# @@ -228,8 +211,7 @@ async fn test_multi_selection_shell_commands() -> anyhow::Result<()> { ipsum #(|foo\n)# dolor - "}) - .as_str(), + "}), )) .await?; @@ -239,8 +221,7 @@ async fn test_multi_selection_shell_commands() -> anyhow::Result<()> { #[|lorem]# #(|ipsum)# #(|dolor)# - "}) - .as_str(), + "}), "echo foo", platform_line(indoc! {"\ lorem#[|foo\n]# @@ -249,8 +230,7 @@ async fn test_multi_selection_shell_commands() -> anyhow::Result<()> { dolor#(|foo\n)# - "}) - .as_str(), + "}), )) .await?; @@ -294,16 +274,14 @@ async fn test_extend_line() -> anyhow::Result<()> { ipsum dolor - "}) - .as_str(), + "}), "x2x", platform_line(indoc! {"\ #[lorem ipsum dolor\n|]# - "}) - .as_str(), + "}), )) .await?; @@ -313,15 +291,13 @@ async fn test_extend_line() -> anyhow::Result<()> { #[l|]#orem ipsum - "}) - .as_str(), + "}), "2x", platform_line(indoc! {"\ #[lorem ipsum\n|]# - "}) - .as_str(), + "}), )) .await?; @@ -390,15 +366,15 @@ async fn test_character_info() -> anyhow::Result<()> { async fn test_delete_char_backward() -> anyhow::Result<()> { // don't panic when deleting overlapping ranges test(( - platform_line("#(x|)# #[x|]#").as_str(), + platform_line("#(x|)# #[x|]#"), "c", - platform_line("#[\n|]#").as_str(), + platform_line("#[\n|]#"), )) .await?; test(( - platform_line("#( |)##( |)#a#( |)#axx#[x|]#a").as_str(), + platform_line("#( |)##( |)#a#( |)#axx#[x|]#a"), "li", - platform_line("#(a|)##(|a)#xx#[|a]#").as_str(), + platform_line("#(a|)##(|a)#xx#[|a]#"), )) .await?; @@ -409,9 +385,9 @@ async fn test_delete_char_backward() -> anyhow::Result<()> { async fn test_delete_word_backward() -> anyhow::Result<()> { // don't panic when deleting overlapping ranges test(( - platform_line("fo#[o|]#ba#(r|)#").as_str(), + platform_line("fo#[o|]#ba#(r|)#"), "a", - platform_line("#[\n|]#").as_str(), + platform_line("#[\n|]#"), )) .await?; Ok(()) @@ -421,9 +397,9 @@ async fn test_delete_word_backward() -> anyhow::Result<()> { async fn test_delete_word_forward() -> anyhow::Result<()> { // don't panic when deleting overlapping ranges test(( - platform_line("fo#[o|]#b#(|ar)#").as_str(), + platform_line("fo#[o|]#b#(|ar)#"), "i", - platform_line("fo#[\n|]#").as_str(), + platform_line("fo#[\n|]#"), )) .await?; Ok(()) @@ -437,16 +413,14 @@ async fn test_delete_char_forward() -> anyhow::Result<()> { #(abc|)#ef #(abc|)#f #(abc|)# - "}) - .as_str(), + "}), "a", platform_line(indoc! {"\ #[abc|]#ef #(abc|)#f #(abc|)# #(abc|)# - "}) - .as_str(), + "}), )) .await?; From 2f2306475cac7ee9385b816424137421c13bf4c2 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Fri, 12 May 2023 16:42:00 +0200 Subject: [PATCH 202/260] async picker syntax highlighting --- helix-term/src/ui/picker.rs | 107 +++++++++++++++++++++++++----------- helix-view/src/document.rs | 24 +++++--- 2 files changed, 91 insertions(+), 40 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index e7a7de909..6120bfd1f 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -1,7 +1,9 @@ use crate::{ alt, - compositor::{Component, Compositor, Context, Event, EventResult}, - ctrl, key, shift, + compositor::{self, Component, Compositor, Context, Event, EventResult}, + ctrl, + job::Callback, + key, shift, ui::{ self, document::{render_document, LineDecoration, LinePos, TextRenderer}, @@ -9,7 +11,7 @@ use crate::{ EditorView, }, }; -use futures_util::future::BoxFuture; +use futures_util::{future::BoxFuture, FutureExt}; use tui::{ buffer::Buffer as Surface, layout::Constraint, @@ -26,7 +28,7 @@ use std::{collections::HashMap, io::Read, path::PathBuf}; use crate::ui::{Prompt, PromptEvent}; use helix_core::{ movement::Direction, text_annotations::TextAnnotations, - unicode::segmentation::UnicodeSegmentation, Position, + unicode::segmentation::UnicodeSegmentation, Position, Syntax, }; use helix_view::{ editor::Action, @@ -122,7 +124,7 @@ impl Preview<'_, '_> { } } -impl FilePicker { +impl FilePicker { pub fn new( options: Vec, editor_data: T::Data, @@ -208,29 +210,67 @@ impl FilePicker { } fn handle_idle_timeout(&mut self, cx: &mut Context) -> EventResult { + let Some((current_file, _)) = self.current_file(cx.editor) else { + return EventResult::Consumed(None) + }; + // Try to find a document in the cache - let doc = self - .current_file(cx.editor) - .and_then(|(path, _range)| match path { - PathOrId::Id(doc_id) => Some(doc_mut!(cx.editor, &doc_id)), - PathOrId::Path(path) => match self.preview_cache.get_mut(&path) { - Some(CachedPreview::Document(doc)) => Some(doc), - _ => None, - }, - }); + let doc = match ¤t_file { + PathOrId::Id(doc_id) => doc_mut!(cx.editor, doc_id), + PathOrId::Path(path) => match self.preview_cache.get_mut(path) { + Some(CachedPreview::Document(ref mut doc)) => doc, + _ => return EventResult::Consumed(None), + }, + }; + + let mut callback: Option = None; // Then attempt to highlight it if it has no language set - if let Some(doc) = doc { - if doc.language_config().is_none() { + if doc.language_config().is_none() { + if let Some(language_config) = doc.detect_language_config(&cx.editor.syn_loader) { + doc.language = Some(language_config.clone()); + let text = doc.text().clone(); let loader = cx.editor.syn_loader.clone(); - doc.detect_language(loader); + let job = tokio::task::spawn_blocking(move || { + let syntax = language_config + .highlight_config(&loader.scopes()) + .and_then(|highlight_config| Syntax::new(&text, highlight_config, loader)); + let callback = move |editor: &mut Editor, compositor: &mut Compositor| { + let Some(syntax) = syntax else { + log::info!("highlighting picker item failed"); + return + }; + log::info!("hmm1"); + let Some(Overlay { content: picker, .. }) = compositor.find::>() else { + log::info!("picker closed before syntax highlighting finished"); + return + }; + log::info!("hmm2"); + // Try to find a document in the cache + let doc = match current_file { + PathOrId::Id(doc_id) => doc_mut!(editor, &doc_id), + PathOrId::Path(path) => match picker.preview_cache.get_mut(&path) { + Some(CachedPreview::Document(ref mut doc)) => doc, + _ => return, + }, + }; + log::info!("yay"); + doc.syntax = Some(syntax); + }; + Callback::EditorCompositor(Box::new(callback)) + }); + let tmp: compositor::Callback = Box::new(move |_, ctx| { + ctx.jobs + .callback(job.map(|res| res.map_err(anyhow::Error::from))) + }); + callback = Some(Box::new(tmp)) } - - // QUESTION: do we want to compute inlay hints in pickers too ? Probably not for now - // but it could be interesting in the future } - EventResult::Consumed(None) + // QUESTION: do we want to compute inlay hints in pickers too ? Probably not for now + // but it could be interesting in the future + + EventResult::Consumed(callback) } } @@ -373,6 +413,10 @@ impl Component for FilePicker { self.picker.required_size((picker_width, height))?; Some((width, height)) } + + fn id(&self) -> Option<&'static str> { + Some("file-picker") + } } #[derive(PartialEq, Eq, Debug)] @@ -945,17 +989,16 @@ impl Component for DynamicPicker { cx.jobs.callback(async move { let new_options = new_options.await?; - let callback = - crate::job::Callback::EditorCompositor(Box::new(move |editor, compositor| { - // Wrapping of pickers in overlay is done outside the picker code, - // so this is fragile and will break if wrapped in some other widget. - let picker = match compositor.find_id::>>(Self::ID) { - Some(overlay) => &mut overlay.content.file_picker.picker, - None => return, - }; - picker.set_options(new_options); - editor.reset_idle_timer(); - })); + let callback = Callback::EditorCompositor(Box::new(move |editor, compositor| { + // Wrapping of pickers in overlay is done outside the picker code, + // so this is fragile and will break if wrapped in some other widget. + let picker = match compositor.find_id::>>(Self::ID) { + Some(overlay) => &mut overlay.content.file_picker.picker, + None => return, + }; + picker.set_options(new_options); + editor.reset_idle_timer(); + })); anyhow::Ok(callback) }); EventResult::Consumed(None) diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index e29e52cc5..770341dcd 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -154,9 +154,9 @@ pub struct Document { /// The document's default line ending. pub line_ending: LineEnding, - syntax: Option, + pub syntax: Option, /// Corresponding language scope name. Usually `source.`. - pub(crate) language: Option>, + pub language: Option>, /// Pending changes since last history commit. changes: ChangeSet, @@ -869,12 +869,20 @@ impl Document { /// Detect the programming language based on the file type. pub fn detect_language(&mut self, config_loader: Arc) { - if let Some(path) = &self.path { - let language_config = config_loader - .language_config_for_file_name(path) - .or_else(|| config_loader.language_config_for_shebang(self.text())); - self.set_language(language_config, Some(config_loader)); - } + self.set_language( + self.detect_language_config(&config_loader), + Some(config_loader), + ); + } + + /// Detect the programming language based on the file type. + pub fn detect_language_config( + &self, + config_loader: &syntax::Loader, + ) -> Option> { + config_loader + .language_config_for_file_name(self.path.as_ref()?) + .or_else(|| config_loader.language_config_for_shebang(self.text())) } /// Detect the indentation used in the file, or otherwise defaults to the language indentation From b0705337bec836604bdb97689d0a44940c6bddae Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Fri, 12 May 2023 16:49:39 +0200 Subject: [PATCH 203/260] automatically disable TS when parsing takes longer than 500ms --- helix-core/src/syntax.rs | 23 +++++++++++++++-------- helix-core/tests/indent.rs | 2 +- helix-term/src/ui/markdown.rs | 2 +- helix-term/src/ui/picker.rs | 3 --- helix-view/src/document.rs | 11 ++++++----- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 005e985de..f36c985e3 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -768,7 +768,11 @@ fn byte_range_to_str(range: std::ops::Range, source: RopeSlice) -> Cow, loader: Arc) -> Self { + pub fn new( + source: &Rope, + config: Arc, + loader: Arc, + ) -> Option { let root_layer = LanguageLayer { tree: None, config, @@ -793,11 +797,13 @@ impl Syntax { loader, }; - syntax - .update(source, source, &ChangeSet::new(source)) - .unwrap(); + let res = syntax.update(source, source, &ChangeSet::new(source)); - syntax + if res.is_err() { + log::error!("TS parser failed, disabeling TS for the current buffer: {res:?}"); + return None; + } + Some(syntax) } pub fn update( @@ -925,6 +931,7 @@ impl Syntax { PARSER.with(|ts_parser| { let ts_parser = &mut ts_parser.borrow_mut(); + ts_parser.parser.set_timeout_micros(1000 * 500); // half a second is pretty generours let mut cursor = ts_parser.cursors.pop().unwrap_or_else(QueryCursor::new); // TODO: might need to set cursor range cursor.set_byte_range(0..usize::MAX); @@ -2371,7 +2378,7 @@ mod test { let mut cursor = QueryCursor::new(); let config = HighlightConfiguration::new(language, "", "", "").unwrap(); - let syntax = Syntax::new(&source, Arc::new(config), Arc::new(loader)); + let syntax = Syntax::new(&source, Arc::new(config), Arc::new(loader)).unwrap(); let root = syntax.tree().root_node(); let mut test = |capture, range| { @@ -2442,7 +2449,7 @@ mod test { fn main() {} ", ); - let syntax = Syntax::new(&source, Arc::new(config), Arc::new(loader)); + let syntax = Syntax::new(&source, Arc::new(config), Arc::new(loader)).unwrap(); let tree = syntax.tree(); let root = tree.root_node(); assert_eq!(root.kind(), "source_file"); @@ -2529,7 +2536,7 @@ mod test { let language = get_language(language_name).unwrap(); let config = HighlightConfiguration::new(language, "", "", "").unwrap(); - let syntax = Syntax::new(&source, Arc::new(config), Arc::new(loader)); + let syntax = Syntax::new(&source, Arc::new(config), Arc::new(loader)).unwrap(); let root = syntax .tree() diff --git a/helix-core/tests/indent.rs b/helix-core/tests/indent.rs index f558f86f3..409706bb9 100644 --- a/helix-core/tests/indent.rs +++ b/helix-core/tests/indent.rs @@ -72,7 +72,7 @@ fn test_treesitter_indent(file_name: &str, lang_scope: &str) { let language_config = loader.language_config_for_scope(lang_scope).unwrap(); let highlight_config = language_config.highlight_config(&[]).unwrap(); - let syntax = Syntax::new(&doc, highlight_config, std::sync::Arc::new(loader)); + let syntax = Syntax::new(&doc, highlight_config, std::sync::Arc::new(loader)).unwrap(); let indent_query = language_config.indent_query().unwrap(); let text = doc.slice(..); diff --git a/helix-term/src/ui/markdown.rs b/helix-term/src/ui/markdown.rs index fea3de78f..def64434a 100644 --- a/helix-term/src/ui/markdown.rs +++ b/helix-term/src/ui/markdown.rs @@ -51,7 +51,7 @@ pub fn highlighted_code_block<'a>( language.into(), )) .and_then(|config| config.highlight_config(theme.scopes())) - .map(|config| Syntax::new(&rope, config, Arc::clone(&config_loader))); + .and_then(|config| Syntax::new(&rope, config, Arc::clone(&config_loader))); let syntax = match syntax { Some(s) => s, diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 6120bfd1f..d161f786c 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -240,12 +240,10 @@ impl FilePicker { log::info!("highlighting picker item failed"); return }; - log::info!("hmm1"); let Some(Overlay { content: picker, .. }) = compositor.find::>() else { log::info!("picker closed before syntax highlighting finished"); return }; - log::info!("hmm2"); // Try to find a document in the cache let doc = match current_file { PathOrId::Id(doc_id) => doc_mut!(editor, &doc_id), @@ -254,7 +252,6 @@ impl FilePicker { _ => return, }, }; - log::info!("yay"); doc.syntax = Some(syntax); }; Callback::EditorCompositor(Box::new(callback)) diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 770341dcd..eb3765679 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -972,8 +972,7 @@ impl Document { ) { if let (Some(language_config), Some(loader)) = (language_config, loader) { if let Some(highlight_config) = language_config.highlight_config(&loader.scopes()) { - let syntax = Syntax::new(&self.text, highlight_config, loader); - self.syntax = Some(syntax); + self.syntax = Syntax::new(&self.text, highlight_config, loader); } self.language = Some(language_config); @@ -1113,9 +1112,11 @@ impl Document { // update tree-sitter syntax tree if let Some(syntax) = &mut self.syntax { // TODO: no unwrap - syntax - .update(&old_doc, &self.text, transaction.changes()) - .unwrap(); + let res = syntax.update(&old_doc, &self.text, transaction.changes()); + if res.is_err() { + log::error!("TS parser failed, disabeling TS for the current buffer: {res:?}"); + self.syntax = None; + } } let changes = transaction.changes(); From 2cccb3f09c52824bf070e127c0b196ed8d8e7555 Mon Sep 17 00:00:00 2001 From: Ivan Gulakov <44394533+ogimgd@users.noreply.github.com> Date: Thu, 18 May 2023 08:27:29 +0200 Subject: [PATCH 204/260] Fix completion on paths containing spaces (#6779) There was an issue with autocompletion of a path with a space in it. Before: :o test\ dir -> -> test\ dirfile1 After: :o test\ dir -> -> test\ dir\file1 --- helix-term/src/commands/typed.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 16ee83d76..81a24059a 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -2847,13 +2847,10 @@ pub(super) fn command_mode(cx: &mut Context) { } else { // Otherwise, use the command's completer and the last shellword // as completion input. - let (part, part_len) = if words.len() == 1 || shellwords.ends_with_whitespace() { + let (word, word_len) = if words.len() == 1 || shellwords.ends_with_whitespace() { (&Cow::Borrowed(""), 0) } else { - ( - words.last().unwrap(), - shellwords.parts().last().unwrap().len(), - ) + (words.last().unwrap(), words.last().unwrap().len()) }; let argument_number = argument_number_of(&shellwords); @@ -2862,13 +2859,13 @@ pub(super) fn command_mode(cx: &mut Context) { .get(&words[0] as &str) .map(|tc| tc.completer_for_argument_number(argument_number)) { - completer(editor, part) + completer(editor, word) .into_iter() .map(|(range, file)| { let file = shellwords::escape(file); // offset ranges to input - let offset = input.len() - part_len; + let offset = input.len() - word_len; let range = (range.start + offset)..; (range, file) }) From 04fbf30488348e417e3922ef23973d4542923731 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 5 Apr 2023 15:37:20 -0500 Subject: [PATCH 205/260] Bump the version to 23.05 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 35371314c..527d78c51 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -23.03 \ No newline at end of file +23.05 \ No newline at end of file From 59f8f5e6d4c3eeabb24bee71740d48686d3257b6 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 5 Apr 2023 15:37:08 -0500 Subject: [PATCH 206/260] Add changelog notes for the 23.05 release --- CHANGELOG.md | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01184571e..8f2775b29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,120 @@ +# 23.05 (2023-05-18) + +23.05 is a smaller release focusing on fixes. There were 88 contributors in this release. Thank you all! + +Features: + +- Add a config option to exclude declaration from LSP references request ([#6886](https://github.com/helix-editor/helix/pull/6886)) +- Enable injecting languages based on their file extension and shebang ([#3970](https://github.com/helix-editor/helix/pull/3970)) +- Sort the buffer picker by most recent access ([#2980](https://github.com/helix-editor/helix/pull/2980)) +- Perform syntax highlighting in the picker asynchronously ([#7028](https://github.com/helix-editor/helix/pull/7028)) + +Commands: + +- `:update` is now aliased as `:u` ([#6835](https://github.com/helix-editor/helix/pull/6835)) +- Add `extend_to_first_nonwhitespace` which acts the same as `goto_first_nonwhitespace` but always extends ([#6837](https://github.com/helix-editor/helix/pull/6837)) +- Add `:clear-register` for clearing the given register or all registers ([#5695](https://github.com/helix-editor/helix/pull/5695)) +- Add `:write-buffer-close` and `:write-buffer-close!` ([#6947](https://github.com/helix-editor/helix/pull/6947)) + +Fixes: + +- Normalize LSP workspace paths ([#6517](https://github.com/helix-editor/helix/pull/6517)) +- Robustly handle invalid LSP ranges ([#6512](https://github.com/helix-editor/helix/pull/6512)) +- Fix line number display for LSP goto pickers ([#6559](https://github.com/helix-editor/helix/pull/6559)) +- Fix toggling of `soft-wrap.enable` option ([#6656](https://github.com/helix-editor/helix/pull/6656), [58e457a](https://github.com/helix-editor/helix/commit/58e457a), [#6742](https://github.com/helix-editor/helix/pull/6742)) +- Handle `workspace/configuration` requests from stopped language servers ([#6693](https://github.com/helix-editor/helix/pull/6693)) +- Fix possible crash from opening the jumplist picker ([#6672](https://github.com/helix-editor/helix/pull/6672)) +- Fix theme preview returning to current theme on line and word deletions ([#6694](https://github.com/helix-editor/helix/pull/6694)) +- Re-run crate build scripts on changes to revision and grammar repositories ([#6743](https://github.com/helix-editor/helix/pull/6743)) +- Fix crash on opening from suspended state ([#6764](https://github.com/helix-editor/helix/pull/6764)) +- Fix unwrap bug in DAP ([#6786](https://github.com/helix-editor/helix/pull/6786)) +- Always build tree-sitter parsers with C++14 and C11 ([#6792](https://github.com/helix-editor/helix/pull/6792), [#6834](https://github.com/helix-editor/helix/pull/6834), [#6845](https://github.com/helix-editor/helix/pull/6845)) +- Exit with a non-zero statuscode when tree-sitter parser builds fail ([#6795](https://github.com/helix-editor/helix/pull/6795)) +- Flip symbol range in LSP goto commands ([#6794](https://github.com/helix-editor/helix/pull/6794)) +- Fix runtime toggling of the `mouse` option ([#6675](https://github.com/helix-editor/helix/pull/6675)) +- Fix panic in inlay hint computation when view anchor is out of bounds ([#6883](https://github.com/helix-editor/helix/pull/6883)) +- Significantly improve performance of git discovery on slow file systems ([#6890](https://github.com/helix-editor/helix/pull/6890)) +- Downgrade gix log level to info ([#6915](https://github.com/helix-editor/helix/pull/6915)) +- Conserve BOM and properly support saving UTF16 files ([#6497](https://github.com/helix-editor/helix/pull/6497)) +- Correctly handle completion re-request ([#6594](https://github.com/helix-editor/helix/pull/6594)) +- Fix offset encoding in LSP `didChange` notifications ([#6921](https://github.com/helix-editor/helix/pull/6921)) +- Change `gix` logging level to info ([#6915](https://github.com/helix-editor/helix/pull/6915)) +- Improve error message when writes fail because parent directories do not exist ([#7014](https://github.com/helix-editor/helix/pull/7014)) +- Replace DAP variables popup instead of pushing more popups ([#7034](https://github.com/helix-editor/helix/pull/7034)) +- Disable tree-sitter for files after parsing for 500ms ([#7028](https://github.com/helix-editor/helix/pull/7028)) +- Fix crash when deleting with multiple cursors ([#6024](https://github.com/helix-editor/helix/pull/6024)) +- Fix selection sliding when deleting forwards in append mode ([#6024](https://github.com/helix-editor/helix/pull/6024)) +- Fix completion on paths containing spaces ([#6779](https://github.com/helix-editor/helix/pull/6779)) + +Themes: + +- Style inlay hints in `dracula` theme ([#6515](https://github.com/helix-editor/helix/pull/6515)) +- Style inlay hints in `onedark` theme ([#6503](https://github.com/helix-editor/helix/pull/6503)) +- Style inlay hints and the soft-wrap indicator in `varua` ([#6568](https://github.com/helix-editor/helix/pull/6568), [#6589](https://github.com/helix-editor/helix/pull/6589)) +- Style inlay hints in `emacs` theme ([#6569](https://github.com/helix-editor/helix/pull/6569)) +- Update `base16_transparent` and `dark_high_contrast` themes ([#6577](https://github.com/helix-editor/helix/pull/6577)) +- Style inlay hints for `mellow` and `rasmus` themes ([#6583](https://github.com/helix-editor/helix/pull/6583)) +- Dim pane divider for `base16_transparent` theme ([#6534](https://github.com/helix-editor/helix/pull/6534)) +- Style inlay hints in `zenburn` theme ([#6593](https://github.com/helix-editor/helix/pull/6593)) +- Style inlay hints in `boo_berry` theme ([#6625](https://github.com/helix-editor/helix/pull/6625)) +- Add `ferra` theme ([#6619](https://github.com/helix-editor/helix/pull/6619), [#6776](https://github.com/helix-editor/helix/pull/6776)) +- Style inlay hints in `nightfox` theme ([#6655](https://github.com/helix-editor/helix/pull/6655)) +- Fix `ayu` theme family markup code block background ([#6538](https://github.com/helix-editor/helix/pull/6538)) +- Improve whitespace and search match colors in `rose_pine` theme ([#6679](https://github.com/helix-editor/helix/pull/6679)) +- Highlight selected items in `base16_transparent` theme ([#6716](https://github.com/helix-editor/helix/pull/6716)) +- Adjust everforest to resemble original more closely ([#5866](https://github.com/helix-editor/helix/pull/5866)) +- Refactor `dracula` theme ([#6552](https://github.com/helix-editor/helix/pull/6552), [#6767](https://github.com/helix-editor/helix/pull/6767), [#6855](https://github.com/helix-editor/helix/pull/6855), [#6987](https://github.com/helix-editor/helix/pull/6987)) +- Style inlay hints in `darcula` theme ([#6732](https://github.com/helix-editor/helix/pull/6732)) +- Style inlay hints in `kanagawa` theme ([#6773](https://github.com/helix-editor/helix/pull/6773)) +- Improve `ayu_dark` theme ([#6622](https://github.com/helix-editor/helix/pull/6622)) +- Refactor `noctis` theme multiple cursor highlighting ([96720e7](https://github.com/helix-editor/helix/commit/96720e7)) +- Refactor `noctis` theme whitespace rendering and indent guides ([f2ccc03](https://github.com/helix-editor/helix/commit/f2ccc03)) +- Add `amberwood` theme ([#6924](https://github.com/helix-editor/helix/pull/6924)) +- Update `nightfox` theme ([#7061](https://github.com/helix-editor/helix/pull/7061)) + +Language support: + +- R language server: use the `--no-echo` flag to silence output ([#6570](https://github.com/helix-editor/helix/pull/6570)) +- Recognize CUDA files as C++ ([#6521](https://github.com/helix-editor/helix/pull/6521)) +- Add support for Hurl ([#6450](https://github.com/helix-editor/helix/pull/6450)) +- Add textobject queries for Julia ([#6588](https://github.com/helix-editor/helix/pull/6588)) +- Update Ruby highlight queries ([#6587](https://github.com/helix-editor/helix/pull/6587)) +- Add xsd to XML file-types ([#6631](https://github.com/helix-editor/helix/pull/6631)) +- Support Robot Framework ([#6611](https://github.com/helix-editor/helix/pull/6611)) +- Update Gleam tree-sitter parser ([#6641](https://github.com/helix-editor/helix/pull/6641)) +- Update git-commit tree-sitter parser ([#6692](https://github.com/helix-editor/helix/pull/6692)) +- Update Haskell tree-sitter parser ([#6317](https://github.com/helix-editor/helix/pull/6317)) +- Add injection queries for Haskell quasiquotes ([#6474](https://github.com/helix-editor/helix/pull/6474)) +- Highlight C/C++ escape sequences ([#6724](https://github.com/helix-editor/helix/pull/6724)) +- Support Markdoc ([#6432](https://github.com/helix-editor/helix/pull/6432)) +- Support OpenCL ([#6473](https://github.com/helix-editor/helix/pull/6473)) +- Support DTD ([#6644](https://github.com/helix-editor/helix/pull/6644)) +- Fix constant highlighting in Python queries ([#6751](https://github.com/helix-editor/helix/pull/6751)) +- Support Just ([#6453](https://github.com/helix-editor/helix/pull/6453)) +- Fix Go locals query for `var_spec` identifiers ([#6763](https://github.com/helix-editor/helix/pull/6763)) +- Update Markdown tree-sitter parser ([#6785](https://github.com/helix-editor/helix/pull/6785)) +- Fix Haskell workspace root for cabal projects ([#6828](https://github.com/helix-editor/helix/pull/6828)) +- Avoid extra indentation in Go switches ([#6817](https://github.com/helix-editor/helix/pull/6817)) +- Fix Go workspace roots ([#6884](https://github.com/helix-editor/helix/pull/6884)) +- Set PerlNavigator as the default Perl language server ([#6860](https://github.com/helix-editor/helix/pull/6860)) +- Highlight more sqlx macros in Rust ([#6793](https://github.com/helix-editor/helix/pull/6793)) +- Switch Odin tree-sitter grammar ([#6766](https://github.com/helix-editor/helix/pull/6766)) +- Recognize `poetry.lock` as TOML ([#6928](https://github.com/helix-editor/helix/pull/6928)) +- Recognize Jupyter notebooks as JSON ([#6927](https://github.com/helix-editor/helix/pull/6927)) +- Add language server configuration for Crystal ([#6948](https://github.com/helix-editor/helix/pull/6948)) +- Add `build.gradle.kts` to Java and Scala roots ([#6970](https://github.com/helix-editor/helix/pull/6970)) +- Recognize `sty` and `cls` files as latex ([#6986](https://github.com/helix-editor/helix/pull/6986)) +- Update Dockerfile tree-sitter grammar ([#6895](https://github.com/helix-editor/helix/pull/6895)) +- Add comment injections for Odin ([#7027](https://github.com/helix-editor/helix/pull/7027)) +- Recognize `gml` as XML ([#7055](https://github.com/helix-editor/helix/pull/7055)) +- Recognize `geojson` as JSON ([#7054](https://github.com/helix-editor/helix/pull/7054)) + +Packaging: + +- Update the Nix flake dependencies, remove a deprecated option ([#6546](https://github.com/helix-editor/helix/pull/6546)) +- Fix and re-enable aarch64-macos release binary builds ([#6504](https://github.com/helix-editor/helix/pull/6504)) +- The git dependency on `tree-sitter` has been replaced with a regular crates.io dependency ([#6608](https://github.com/helix-editor/helix/pull/6608)) + # 23.03 (2023-03-31) 23.03 brings some long-awaited and exciting features. Thank you to everyone involved! This release saw changes from 102 contributors. From 7f5940be80eaa3aec7903903072b7108f41dd97b Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Thu, 18 May 2023 15:56:49 +0900 Subject: [PATCH 207/260] Add 23.05 to the AppData --- contrib/Helix.appdata.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/Helix.appdata.xml b/contrib/Helix.appdata.xml index b99738a18..f1b310db4 100644 --- a/contrib/Helix.appdata.xml +++ b/contrib/Helix.appdata.xml @@ -36,6 +36,9 @@ + + https://github.com/helix-editor/helix/releases/tag/23.05 + https://helix-editor.com/news/release-23-03-highlights/ From 71551d395b4e47804df2d8ecea99e34dbbf16157 Mon Sep 17 00:00:00 2001 From: Philipp Mildenberger Date: Mon, 23 May 2022 18:10:48 +0200 Subject: [PATCH 208/260] Adds support for multiple language servers per language. Language Servers are now configured in a separate table in `languages.toml`: ```toml [langauge-server.mylang-lsp] command = "mylang-lsp" args = ["--stdio"] config = { provideFormatter = true } [language-server.efm-lsp-prettier] command = "efm-langserver" [language-server.efm-lsp-prettier.config] documentFormatting = true languages = { typescript = [ { formatCommand ="prettier --stdin-filepath ${INPUT}", formatStdin = true } ] } ``` The language server for a language is configured like this (`typescript-language-server` is configured by default): ```toml [[language]] name = "typescript" language-servers = [ { name = "efm-lsp-prettier", only-features = [ "format" ] }, "typescript-language-server" ] ``` or equivalent: ```toml [[language]] name = "typescript" language-servers = [ { name = "typescript-language-server", except-features = [ "format" ] }, "efm-lsp-prettier" ] ``` Each requested LSP feature is priorized in the order of the `language-servers` array. For example the first `goto-definition` supported language server (in this case `typescript-language-server`) will be taken for the relevant LSP request (command `goto_definition`). If no `except-features` or `only-features` is given all features for the language server are enabled, as long as the language server supports these. If it doesn't the next language server which supports the feature is tried. The list of supported features are: - `format` - `goto-definition` - `goto-declaration` - `goto-type-definition` - `goto-reference` - `goto-implementation` - `signature-help` - `hover` - `document-highlight` - `completion` - `code-action` - `workspace-command` - `document-symbols` - `workspace-symbols` - `diagnostics` - `rename-symbol` - `inlay-hints` Another side-effect/difference that comes with this PR, is that only one language server instance is started if different languages use the same language server. --- book/src/generated/typable-cmd.md | 2 +- book/src/guides/adding_languages.md | 1 + book/src/languages.md | 104 +++- helix-core/src/diagnostic.rs | 1 + helix-core/src/syntax.rs | 113 +++- helix-lsp/src/client.rs | 12 +- helix-lsp/src/lib.rs | 204 +++---- helix-lsp/src/transport.rs | 63 ++- helix-term/src/application.rs | 126 +++-- helix-term/src/commands.rs | 273 +++++----- helix-term/src/commands/lsp.rs | 799 +++++++++++++++------------- helix-term/src/commands/typed.rs | 106 ++-- helix-term/src/health.rs | 27 +- helix-term/src/ui/completion.rs | 85 ++- helix-term/src/ui/editor.rs | 17 +- helix-term/src/ui/mod.rs | 21 +- helix-term/src/ui/statusline.rs | 12 +- helix-view/src/document.rs | 145 +++-- helix-view/src/editor.rs | 64 ++- helix-view/src/gutter.rs | 2 +- languages.toml | 425 ++++++++------- xtask/src/docgen.rs | 11 +- 22 files changed, 1555 insertions(+), 1058 deletions(-) diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index a775c6555..0c377b3bb 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -50,7 +50,7 @@ | `:reload-all` | Discard changes and reload all documents from the source files. | | `:update`, `:u` | Write changes only if the file has been modified. | | `:lsp-workspace-command` | Open workspace command picker | -| `:lsp-restart` | Restarts the Language Server that is in use by the current doc | +| `:lsp-restart` | Restarts the language servers used by the currently opened file | | `:lsp-stop` | Stops the Language Server that is in use by the current doc | | `:tree-sitter-scopes` | Display tree sitter scopes, primarily for theming and development. | | `:debug-start`, `:dbg` | Start a debug session from a given template with given parameters. | diff --git a/book/src/guides/adding_languages.md b/book/src/guides/adding_languages.md index b92af4028..93ec013f5 100644 --- a/book/src/guides/adding_languages.md +++ b/book/src/guides/adding_languages.md @@ -9,6 +9,7 @@ below. necessary configuration for the new language. For more information on language configuration, refer to the [language configuration section](../languages.md) of the documentation. + A new language server can be added by extending the `[language-server]` table in the same file. 2. If you are adding a new language or updating an existing language server configuration, run the command `cargo xtask docgen` to update the [Language Support](../lang-support.md) documentation. diff --git a/book/src/languages.md b/book/src/languages.md index fe4db1413..3328c6103 100644 --- a/book/src/languages.md +++ b/book/src/languages.md @@ -18,6 +18,9 @@ There are three possible locations for a `languages.toml` file: ```toml # in /helix/languages.toml +[language-server.mylang-lsp] +command = "mylang-lsp" + [[language]] name = "rust" auto-format = false @@ -41,8 +44,8 @@ injection-regex = "mylang" file-types = ["mylang", "myl"] comment-token = "#" indent = { tab-width = 2, unit = " " } -language-server = { command = "mylang-lsp", args = ["--stdio"], environment = { "ENV1" = "value1", "ENV2" = "value2" } } formatter = { command = "mylang-formatter" , args = ["--stdin"] } +language-servers = [ "mylang-lsp" ] ``` These configuration keys are available: @@ -50,6 +53,7 @@ These configuration keys are available: | Key | Description | | ---- | ----------- | | `name` | The name of the language | +| `language-id` | The language-id for language servers, checkout the table at [TextDocumentItem](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentItem) for the right id | | `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"]`. See the file-type detection section below. | @@ -59,7 +63,7 @@ These configuration keys are available: | `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 `unit` (the text inserted into the document when indenting; usually set to N spaces or `"\t"` for tabs) and `tab-width` (the number of spaces rendered for a tab) | -| `language-server` | The Language Server to run. See the Language Server configuration section below. | +| `language-servers` | The Language Servers used for this language. See below for more information in the section [Configuring Language Servers for a language](#configuring-language-servers-for-a-language) | | `config` | Language Server configuration | | `grammar` | The tree-sitter grammar to use (defaults to the value of `name`) | | `formatter` | The formatter for the language, it will take precedence over the lsp when defined. The formatter must be able to take the original file as input from stdin and write the formatted file to stdout | @@ -92,31 +96,97 @@ with the following priorities: replaced at runtime with the appropriate path separator for the operating system, so this rule would match against `.git\config` files on Windows. -### Language Server configuration +## Language Server configuration + +Language servers are configured separately in the table `language-server` in the same file as the languages `languages.toml` + +For example: + +```toml +[language-server.mylang-lsp] +command = "mylang-lsp" +args = ["--stdio"] +config = { provideFormatter = true } +environment = { "ENV1" = "value1", "ENV2" = "value2" } + +[language-server.efm-lsp-prettier] +command = "efm-langserver" + +[language-server.efm-lsp-prettier.config] +documentFormatting = true +languages = { typescript = [ { formatCommand ="prettier --stdin-filepath ${INPUT}", formatStdin = true } ] } +``` -The `language-server` field takes the following keys: +These are the available options for a language server. -| 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 | -| `environment` | Any environment variables that will be used when starting the language server `{ "KEY1" = "Value1", "KEY2" = "Value2" }` | +| Key | Description | +| ---- | ----------- | +| `command` | The name or path of the language server binary to execute. Binaries must be in `$PATH` | +| `args` | A list of arguments to pass to the language server binary | +| `config` | LSP initialization options | +| `timeout` | The maximum time a request to the language server may take, in seconds. Defaults to `20` | +| `environment` | Any environment variables that will be used when starting the language server `{ "KEY1" = "Value1", "KEY2" = "Value2" }` | -The top-level `config` field is used to configure the LSP initialization options. A `format` -sub-table within `config` can be used to pass extra formatting options to -[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). +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-17.md#document-formatting-request--leftwards_arrow_with_hook). For example with typescript: ```toml -[[language]] -name = "typescript" -auto-format = true +[language-server.typescript-language-server] # 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 } } ``` +### Configuring Language Servers for a language + +The `language-servers` attribute in a language tells helix which language servers are used for this language. +They have to be defined in the `[language-server]` table as described in the previous section. +Different languages can use the same language server instance, e.g. `typescript-language-server` is used for javascript, jsx, tsx and typescript by default. +In case multiple language servers are specified in the `language-servers` attribute of a `language`, +it's often useful to only enable/disable certain language-server features for these language servers. +For example `efm-lsp-prettier` of the previous example is used only with a formatting command `prettier`, +so everything else should be handled by the `typescript-language-server` (which is configured by default) +The language configuration for typescript could look like this: + +```toml +[[language]] +name = "typescript" +language-servers = [ { name = "efm-lsp-prettier", only-features = [ "format" ] }, "typescript-language-server" ] +``` + +or equivalent: + +```toml +[[language]] +name = "typescript" +language-servers = [ { name = "typescript-language-server", except-features = [ "format" ] }, "efm-lsp-prettier" ] +``` + +Each requested LSP feature is priorized in the order of the `language-servers` array. +For example the first `goto-definition` supported language server (in this case `typescript-language-server`) will be taken for the relevant LSP request (command `goto_definition`). +If no `except-features` or `only-features` is given all features for the language server are enabled. +If a language server itself doesn't support a feature the next language server array entry will be tried (and so on). + +The list of supported features are: + +- `format` +- `goto-definition` +- `goto-declaration` +- `goto-type-definition` +- `goto-reference` +- `goto-implementation` +- `signature-help` +- `hover` +- `document-highlight` +- `completion` +- `code-action` +- `workspace-command` +- `document-symbols` +- `workspace-symbols` +- `diagnostics` +- `rename-symbol` +- `inlay-hints` + ## Tree-sitter grammar configuration The source for a language's tree-sitter grammar is specified in a `[[grammar]]` diff --git a/helix-core/src/diagnostic.rs b/helix-core/src/diagnostic.rs index 58ddb0383..0b75d2a58 100644 --- a/helix-core/src/diagnostic.rs +++ b/helix-core/src/diagnostic.rs @@ -43,6 +43,7 @@ pub struct Diagnostic { pub message: String, pub severity: Option, pub code: Option, + pub language_server_id: usize, pub tags: Vec, pub source: Option, pub data: Option, diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index f36c985e3..ff4bb6c27 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -17,7 +17,7 @@ use std::{ borrow::Cow, cell::RefCell, collections::{HashMap, VecDeque}, - fmt, + fmt::{self, Display}, hash::{Hash, Hasher}, mem::{replace, transmute}, path::{Path, PathBuf}, @@ -60,8 +60,11 @@ fn default_timeout() -> u64 { } #[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] pub struct Configuration { pub language: Vec, + #[serde(default)] + pub language_server: HashMap, } impl Default for Configuration { @@ -75,7 +78,10 @@ impl Default for Configuration { #[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct LanguageConfiguration { #[serde(rename = "name")] - pub language_id: String, // c-sharp, rust + pub language_id: String, // c-sharp, rust, tsx + #[serde(rename = "language-id")] + // see the table under https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentItem + pub language_server_language_id: Option, // csharp, rust, typescriptreact, for the language-server pub scope: String, // source.rust pub file_types: Vec, // filename extension or ends_with? #[serde(default)] @@ -85,9 +91,6 @@ pub struct LanguageConfiguration { pub text_width: Option, pub soft_wrap: Option, - #[serde(default, skip_serializing, deserialize_with = "deserialize_lsp_config")] - pub config: Option, - #[serde(default)] pub auto_format: bool, @@ -107,8 +110,8 @@ pub struct LanguageConfiguration { #[serde(skip)] pub(crate) highlight_config: OnceCell>>, // tags_config OnceCell<> https://github.com/tree-sitter/tree-sitter/pull/583 - #[serde(skip_serializing_if = "Option::is_none")] - pub language_server: Option, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub language_servers: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub indent: Option, @@ -208,6 +211,68 @@ impl<'de> Deserialize<'de> for FileType { } } +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "kebab-case")] +pub enum LanguageServerFeature { + Format, + GotoDeclaration, + GotoDefinition, + GotoTypeDefinition, + GotoReference, + GotoImplementation, + // Goto, use bitflags, combining previous Goto members? + SignatureHelp, + Hover, + DocumentHighlight, + Completion, + CodeAction, + WorkspaceCommand, + DocumentSymbols, + WorkspaceSymbols, + // Symbols, use bitflags, see above? + Diagnostics, + RenameSymbol, + InlayHints, +} + +impl Display for LanguageServerFeature { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + LanguageServerFeature::Format => write!(f, "format"), + LanguageServerFeature::GotoDeclaration => write!(f, "goto-declaration"), + LanguageServerFeature::GotoDefinition => write!(f, "goto-definition"), + LanguageServerFeature::GotoTypeDefinition => write!(f, "goto-type-definition"), + LanguageServerFeature::GotoReference => write!(f, "goto-type-definition"), + LanguageServerFeature::GotoImplementation => write!(f, "goto-implementation"), + LanguageServerFeature::SignatureHelp => write!(f, "signature-help"), + LanguageServerFeature::Hover => write!(f, "hover"), + LanguageServerFeature::DocumentHighlight => write!(f, "document-highlight"), + LanguageServerFeature::Completion => write!(f, "completion"), + LanguageServerFeature::CodeAction => write!(f, "code-action"), + LanguageServerFeature::WorkspaceCommand => write!(f, "workspace-command"), + LanguageServerFeature::DocumentSymbols => write!(f, "document-symbols"), + LanguageServerFeature::WorkspaceSymbols => write!(f, "workspace-symbols"), + LanguageServerFeature::Diagnostics => write!(f, "diagnostics"), + LanguageServerFeature::RenameSymbol => write!(f, "rename-symbol"), + LanguageServerFeature::InlayHints => write!(f, "inlay-hints"), + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged, rename_all = "kebab-case", deny_unknown_fields)] +pub enum LanguageServerFeatureConfiguration { + #[serde(rename_all = "kebab-case")] + Features { + #[serde(default, skip_serializing_if = "Vec::is_empty")] + only_features: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + except_features: Vec, + name: String, + }, + Simple(String), +} + #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub struct LanguageServerConfiguration { @@ -217,9 +282,10 @@ pub struct LanguageServerConfiguration { pub args: Vec, #[serde(default, skip_serializing_if = "HashMap::is_empty")] pub environment: HashMap, + #[serde(default, skip_serializing, deserialize_with = "deserialize_lsp_config")] + pub config: Option, #[serde(default = "default_timeout")] pub timeout: u64, - pub language_id: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -584,6 +650,15 @@ pub struct SoftWrap { pub wrap_at_text_width: Option, } +impl LanguageServerFeatureConfiguration { + pub fn name(&self) -> &String { + match self { + LanguageServerFeatureConfiguration::Simple(name) => name, + LanguageServerFeatureConfiguration::Features { name, .. } => name, + } + } +} + // Expose loader as Lazy<> global since it's always static? #[derive(Debug)] @@ -594,6 +669,8 @@ pub struct Loader { language_config_ids_by_suffix: HashMap, language_config_ids_by_shebang: HashMap, + language_server_configs: HashMap, + scopes: ArcSwap>, } @@ -601,6 +678,7 @@ impl Loader { pub fn new(config: Configuration) -> Self { let mut loader = Self { language_configs: Vec::new(), + language_server_configs: config.language_server, language_config_ids_by_extension: HashMap::new(), language_config_ids_by_suffix: HashMap::new(), language_config_ids_by_shebang: HashMap::new(), @@ -725,6 +803,10 @@ impl Loader { self.language_configs.iter() } + pub fn language_server_configs(&self) -> &HashMap { + &self.language_server_configs + } + pub fn set_scopes(&self, scopes: Vec) { self.scopes.store(Arc::new(scopes)); @@ -2370,7 +2452,10 @@ mod test { "#, ); - let loader = Loader::new(Configuration { language: vec![] }); + let loader = Loader::new(Configuration { + language: vec![], + language_server: HashMap::new(), + }); let language = get_language("rust").unwrap(); let query = Query::new(language, query_str).unwrap(); @@ -2429,7 +2514,10 @@ mod test { .map(String::from) .collect(); - let loader = Loader::new(Configuration { language: vec![] }); + let loader = Loader::new(Configuration { + language: vec![], + language_server: HashMap::new(), + }); let language = get_language("rust").unwrap(); let config = HighlightConfiguration::new( @@ -2532,7 +2620,10 @@ mod test { ) { let source = Rope::from_str(source); - let loader = Loader::new(Configuration { language: vec![] }); + let loader = Loader::new(Configuration { + language: vec![], + language_server: HashMap::new(), + }); let language = get_language(language_name).unwrap(); let config = HighlightConfiguration::new(language, "", "", "").unwrap(); diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 840e73828..c0f3adb82 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -44,6 +44,7 @@ fn workspace_for_uri(uri: lsp::Url) -> WorkspaceFolder { #[derive(Debug)] pub struct Client { id: usize, + name: String, _process: Child, server_tx: UnboundedSender, request_counter: AtomicU64, @@ -166,8 +167,7 @@ impl Client { tokio::spawn(self.did_change_workspace(vec![workspace_for_uri(root_uri)], Vec::new())); } - #[allow(clippy::type_complexity)] - #[allow(clippy::too_many_arguments)] + #[allow(clippy::type_complexity, clippy::too_many_arguments)] pub fn start( cmd: &str, args: &[String], @@ -176,6 +176,7 @@ impl Client { root_markers: &[String], manual_roots: &[PathBuf], id: usize, + name: String, req_timeout: u64, doc_path: Option<&std::path::PathBuf>, ) -> Result<(Self, UnboundedReceiver<(usize, Call)>, Arc)> { @@ -200,7 +201,7 @@ impl Client { let stderr = BufReader::new(process.stderr.take().expect("Failed to open stderr")); let (server_rx, server_tx, initialize_notify) = - Transport::start(reader, writer, stderr, id); + Transport::start(reader, writer, stderr, id, name.clone()); let (workspace, workspace_is_cwd) = find_workspace(); let workspace = path::get_normalized_path(&workspace); let root = find_lsp_workspace( @@ -225,6 +226,7 @@ impl Client { let client = Self { id, + name, _process: process, server_tx, request_counter: AtomicU64::new(0), @@ -240,6 +242,10 @@ impl Client { Ok((client, server_rx, initialize_notify)) } + pub fn name(&self) -> &String { + &self.name + } + pub fn id(&self) -> usize { self.id } diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 31ee1d75c..12e63255a 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -17,19 +17,16 @@ use helix_core::{ use tokio::sync::mpsc::UnboundedReceiver; use std::{ - collections::{hash_map::Entry, HashMap}, + collections::HashMap, path::{Path, PathBuf}, - sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, - }, + sync::Arc, }; use thiserror::Error; use tokio_stream::wrappers::UnboundedReceiverStream; pub type Result = core::result::Result; -type LanguageId = String; +type LanguageServerName = String; #[derive(Error, Debug)] pub enum Error { @@ -49,7 +46,7 @@ pub enum Error { Other(#[from] anyhow::Error), } -#[derive(Clone, Copy, Debug, Default)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub enum OffsetEncoding { /// UTF-8 code units aka bytes Utf8, @@ -624,23 +621,18 @@ impl Notification { #[derive(Debug)] pub struct Registry { - inner: HashMap)>>, - - counter: AtomicUsize, + inner: HashMap>>, + syn_loader: Arc, + counter: usize, pub incoming: SelectAll>, } -impl Default for Registry { - fn default() -> Self { - Self::new() - } -} - impl Registry { - pub fn new() -> Self { + pub fn new(syn_loader: Arc) -> Self { Self { inner: HashMap::new(), - counter: AtomicUsize::new(0), + syn_loader, + counter: 0, incoming: SelectAll::new(), } } @@ -649,15 +641,43 @@ impl Registry { self.inner .values() .flatten() - .find(|(client_id, _)| client_id == &id) - .map(|(_, client)| client.as_ref()) + .find(|client| client.id() == id) + .map(|client| &**client) } pub fn remove_by_id(&mut self, id: usize) { - self.inner.retain(|_, clients| { - clients.retain(|&(client_id, _)| client_id != id); - !clients.is_empty() - }) + self.inner.retain(|_, language_servers| { + language_servers.retain(|ls| id != ls.id()); + !language_servers.is_empty() + }); + } + + fn start_client( + &mut self, + name: String, + ls_config: &LanguageConfiguration, + doc_path: Option<&std::path::PathBuf>, + root_dirs: &[PathBuf], + enable_snippets: bool, + ) -> Result> { + let config = self + .syn_loader + .language_server_configs() + .get(&name) + .ok_or_else(|| anyhow::anyhow!("Language server '{name}' not defined"))?; + self.counter += 1; + let id = self.counter; + let NewClient(client, incoming) = start_client( + id, + name, + ls_config, + config, + doc_path, + root_dirs, + enable_snippets, + )?; + self.incoming.push(UnboundedReceiverStream::new(incoming)); + Ok(client) } pub fn restart( @@ -666,48 +686,46 @@ impl Registry { doc_path: Option<&std::path::PathBuf>, root_dirs: &[PathBuf], enable_snippets: bool, - ) -> Result>> { - let config = match &language_config.language_server { - Some(config) => config, - None => return Ok(None), - }; - - let scope = language_config.scope.clone(); - - match self.inner.entry(scope) { - Entry::Vacant(_) => Ok(None), - Entry::Occupied(mut entry) => { - // initialize a new client - let id = self.counter.fetch_add(1, Ordering::Relaxed); - - let NewClientResult(client, incoming) = start_client( - id, - language_config, - config, - doc_path, - root_dirs, - enable_snippets, - )?; - self.incoming.push(UnboundedReceiverStream::new(incoming)); + ) -> Result>> { + language_config + .language_servers + .iter() + .filter_map(|config| { + let name = config.name().clone(); + + #[allow(clippy::map_entry)] + if self.inner.contains_key(&name) { + let client = match self.start_client( + name.clone(), + language_config, + doc_path, + root_dirs, + enable_snippets, + ) { + Ok(client) => client, + error => return Some(error), + }; + let old_clients = self.inner.insert(name, vec![client.clone()]).unwrap(); - let old_clients = entry.insert(vec![(id, client.clone())]); + // TODO what if there are different language servers for different workspaces, + // I think the language servers will be stopped without being restarted, which is not intended + for old_client in old_clients { + tokio::spawn(async move { + let _ = old_client.force_shutdown().await; + }); + } - for (_, old_client) in old_clients { - tokio::spawn(async move { - let _ = old_client.force_shutdown().await; - }); + Some(Ok(client)) + } else { + None } - - Ok(Some(client)) - } - } + }) + .collect() } - pub fn stop(&mut self, language_config: &LanguageConfiguration) { - let scope = language_config.scope.clone(); - - if let Some(clients) = self.inner.remove(&scope) { - for (_, client) in clients { + pub fn stop(&mut self, name: &str) { + if let Some(clients) = self.inner.remove(name) { + for client in clients { tokio::spawn(async move { let _ = client.force_shutdown().await; }); @@ -721,37 +739,35 @@ impl Registry { doc_path: Option<&std::path::PathBuf>, root_dirs: &[PathBuf], enable_snippets: bool, - ) -> Result>> { - let config = match &language_config.language_server { - Some(config) => config, - None => return Ok(None), - }; - - let clients = self.inner.entry(language_config.scope.clone()).or_default(); - // check if we already have a client for this documents root that we can reuse - if let Some((_, client)) = clients.iter_mut().enumerate().find(|(i, (_, client))| { - client.try_add_doc(&language_config.roots, root_dirs, doc_path, *i == 0) - }) { - return Ok(Some(client.1.clone())); - } - // initialize a new client - let id = self.counter.fetch_add(1, Ordering::Relaxed); - - let NewClientResult(client, incoming) = start_client( - id, - language_config, - config, - doc_path, - root_dirs, - enable_snippets, - )?; - clients.push((id, client.clone())); - self.incoming.push(UnboundedReceiverStream::new(incoming)); - Ok(Some(client)) + ) -> Result>> { + language_config + .language_servers + .iter() + .map(|features| { + let name = features.name(); + if let Some(clients) = self.inner.get_mut(name) { + if let Some((_, client)) = clients.iter_mut().enumerate().find(|(i, client)| { + client.try_add_doc(&language_config.roots, root_dirs, doc_path, *i == 0) + }) { + return Ok(client.clone()); + } + } + let client = self.start_client( + name.clone(), + language_config, + doc_path, + root_dirs, + enable_snippets, + )?; + let clients = self.inner.entry(features.name().clone()).or_default(); + clients.push(client.clone()); + Ok(client) + }) + .collect() } pub fn iter_clients(&self) -> impl Iterator> { - self.inner.values().flatten().map(|(_, client)| client) + self.inner.values().flatten() } } @@ -833,26 +849,28 @@ impl LspProgressMap { } } -struct NewClientResult(Arc, UnboundedReceiver<(usize, Call)>); +struct NewClient(Arc, UnboundedReceiver<(usize, Call)>); /// start_client takes both a LanguageConfiguration and a LanguageServerConfiguration to ensure that /// it is only called when it makes sense. fn start_client( id: usize, + name: String, config: &LanguageConfiguration, ls_config: &LanguageServerConfiguration, doc_path: Option<&std::path::PathBuf>, root_dirs: &[PathBuf], enable_snippets: bool, -) -> Result { +) -> Result { let (client, incoming, initialize_notify) = Client::start( &ls_config.command, &ls_config.args, - config.config.clone(), + ls_config.config.clone(), ls_config.environment.clone(), &config.roots, config.workspace_lsp_roots.as_deref().unwrap_or(root_dirs), id, + name, ls_config.timeout, doc_path, )?; @@ -886,7 +904,7 @@ fn start_client( initialize_notify.notify_one(); }); - Ok(NewClientResult(client, incoming)) + Ok(NewClient(client, incoming)) } /// Find an LSP workspace of a file using the following mechanism: diff --git a/helix-lsp/src/transport.rs b/helix-lsp/src/transport.rs index 3e3e06eec..8c38c1773 100644 --- a/helix-lsp/src/transport.rs +++ b/helix-lsp/src/transport.rs @@ -38,6 +38,7 @@ enum ServerMessage { #[derive(Debug)] pub struct Transport { id: usize, + name: String, pending_requests: Mutex>>>, } @@ -47,6 +48,7 @@ impl Transport { server_stdin: BufWriter, server_stderr: BufReader, id: usize, + name: String, ) -> ( UnboundedReceiver<(usize, jsonrpc::Call)>, UnboundedSender, @@ -58,6 +60,7 @@ impl Transport { let transport = Self { id, + name, pending_requests: Mutex::new(HashMap::default()), }; @@ -83,6 +86,7 @@ impl Transport { async fn recv_server_message( reader: &mut (impl AsyncBufRead + Unpin + Send), buffer: &mut String, + language_server_name: &str, ) -> Result { let mut content_length = None; loop { @@ -124,7 +128,7 @@ impl Transport { reader.read_exact(&mut content).await?; let msg = std::str::from_utf8(&content).context("invalid utf8 from server")?; - info!("<- {}", msg); + info!("{language_server_name} <- {msg}"); // try parsing as output (server response) or call (server request) let output: serde_json::Result = serde_json::from_str(msg); @@ -135,12 +139,13 @@ impl Transport { async fn recv_server_error( err: &mut (impl AsyncBufRead + Unpin + Send), buffer: &mut String, + language_server_name: &str, ) -> Result<()> { buffer.truncate(0); if err.read_line(buffer).await? == 0 { return Err(Error::StreamClosed); }; - error!("err <- {:?}", buffer); + error!("{language_server_name} err <- {buffer:?}"); Ok(()) } @@ -162,15 +167,17 @@ impl Transport { Payload::Notification(value) => serde_json::to_string(&value)?, Payload::Response(error) => serde_json::to_string(&error)?, }; - self.send_string_to_server(server_stdin, json).await + self.send_string_to_server(server_stdin, json, &self.name) + .await } async fn send_string_to_server( &self, server_stdin: &mut BufWriter, request: String, + language_server_name: &str, ) -> Result<()> { - info!("-> {}", request); + info!("{language_server_name} -> {request}"); // send the headers server_stdin @@ -189,9 +196,13 @@ impl Transport { &self, client_tx: &UnboundedSender<(usize, jsonrpc::Call)>, msg: ServerMessage, + language_server_name: &str, ) -> Result<()> { match msg { - ServerMessage::Output(output) => self.process_request_response(output).await?, + ServerMessage::Output(output) => { + self.process_request_response(output, language_server_name) + .await? + } ServerMessage::Call(call) => { client_tx .send((self.id, call)) @@ -202,14 +213,18 @@ impl Transport { Ok(()) } - async fn process_request_response(&self, output: jsonrpc::Output) -> Result<()> { + async fn process_request_response( + &self, + output: jsonrpc::Output, + language_server_name: &str, + ) -> Result<()> { let (id, result) = match output { jsonrpc::Output::Success(jsonrpc::Success { id, result, .. }) => { - info!("<- {}", result); + info!("{language_server_name} <- {}", result); (id, Ok(result)) } jsonrpc::Output::Failure(jsonrpc::Failure { id, error, .. }) => { - error!("<- {}", error); + error!("{language_server_name} <- {error}"); (id, Err(error.into())) } }; @@ -240,12 +255,17 @@ impl Transport { ) { let mut recv_buffer = String::new(); loop { - match Self::recv_server_message(&mut server_stdout, &mut recv_buffer).await { + match Self::recv_server_message(&mut server_stdout, &mut recv_buffer, &transport.name) + .await + { Ok(msg) => { - match transport.process_server_message(&client_tx, msg).await { + match transport + .process_server_message(&client_tx, msg, &transport.name) + .await + { Ok(_) => {} Err(err) => { - error!("err: <- {:?}", err); + error!("{} err: <- {err:?}", transport.name); break; } }; @@ -270,7 +290,7 @@ impl Transport { params: jsonrpc::Params::None, })); match transport - .process_server_message(&client_tx, notification) + .process_server_message(&client_tx, notification, &transport.name) .await { Ok(_) => {} @@ -281,20 +301,22 @@ impl Transport { break; } Err(err) => { - error!("err: <- {:?}", err); + error!("{} err: <- {err:?}", transport.name); break; } } } } - async fn err(_transport: Arc, mut server_stderr: BufReader) { + async fn err(transport: Arc, mut server_stderr: BufReader) { let mut recv_buffer = String::new(); loop { - match Self::recv_server_error(&mut server_stderr, &mut recv_buffer).await { + match Self::recv_server_error(&mut server_stderr, &mut recv_buffer, &transport.name) + .await + { Ok(_) => {} Err(err) => { - error!("err: <- {:?}", err); + error!("{} err: <- {err:?}", transport.name); break; } } @@ -348,10 +370,11 @@ impl Transport { method: lsp_types::notification::Initialized::METHOD.to_string(), params: jsonrpc::Params::None, })); - match transport.process_server_message(&client_tx, notification).await { + let language_server_name = &transport.name; + match transport.process_server_message(&client_tx, notification, language_server_name).await { Ok(_) => {} Err(err) => { - error!("err: <- {:?}", err); + error!("{language_server_name} err: <- {err:?}"); } } @@ -361,7 +384,7 @@ impl Transport { match transport.send_payload_to_server(&mut server_stdin, msg).await { Ok(_) => {} Err(err) => { - error!("err: <- {:?}", err); + error!("{language_server_name} err: <- {err:?}"); } } } @@ -380,7 +403,7 @@ impl Transport { match transport.send_payload_to_server(&mut server_stdin, msg).await { Ok(_) => {} Err(err) => { - error!("err: <- {:?}", err); + error!("{} err: <- {err:?}", transport.name); } } } diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index b54d6835a..45f99e48d 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -30,6 +30,7 @@ use crate::{ use log::{debug, error, warn}; use std::{ + collections::btree_map::Entry, io::{stdin, stdout}, path::Path, sync::Arc, @@ -564,7 +565,7 @@ impl Application { let doc = doc_mut!(self.editor, &doc_save_event.doc_id); let id = doc.id(); doc.detect_language(loader); - let _ = self.editor.refresh_language_server(id); + self.editor.refresh_language_servers(id); } // TODO: fix being overwritten by lsp @@ -662,6 +663,18 @@ impl Application { ) { use helix_lsp::{Call, MethodCall, Notification}; + macro_rules! 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; + } + } + }; + } + match call { Call::Notification(helix_lsp::jsonrpc::Notification { method, params, .. }) => { let notification = match Notification::parse(&method, params) { @@ -677,14 +690,7 @@ impl Application { match notification { Notification::Initialized => { - 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 language_server = language_server!(); // Trigger a workspace/didChangeConfiguration notification after initialization. // This might not be required by the spec but Neovim does this as well, so it's @@ -694,7 +700,7 @@ impl Application { } let docs = self.editor.documents().filter(|doc| { - doc.language_server().map(|server| server.id()) == Some(server_id) + doc.language_servers().iter().any(|l| l.id() == server_id) }); // trigger textDocument/didOpen for docs that are already open @@ -723,6 +729,7 @@ impl Application { return; } }; + let offset_encoding = language_server!().offset_encoding(); let doc = self.editor.document_by_path_mut(&path).filter(|doc| { if let Some(version) = params.version { if version != doc.version() { @@ -745,18 +752,11 @@ impl Application { use helix_core::diagnostic::{Diagnostic, Range, Severity::*}; use lsp::DiagnosticSeverity; - let language_server = if let Some(language_server) = doc.language_server() { - language_server - } else { - log::warn!("Discarding diagnostic because language server is not initialized: {:?}", diagnostic); - return None; - }; - // TODO: convert inside server let start = if let Some(start) = lsp_pos_to_pos( text, diagnostic.range.start, - language_server.offset_encoding(), + offset_encoding, ) { start } else { @@ -764,11 +764,9 @@ impl Application { return None; }; - let end = if let Some(end) = lsp_pos_to_pos( - text, - diagnostic.range.end, - language_server.offset_encoding(), - ) { + let end = if let Some(end) = + lsp_pos_to_pos(text, diagnostic.range.end, offset_encoding) + { end } else { log::warn!("lsp position out of bounds - {:?}", diagnostic); @@ -807,14 +805,19 @@ impl Application { None => None, }; - let tags = if let Some(ref tags) = diagnostic.tags { - let new_tags = tags.iter().filter_map(|tag| { - match *tag { - lsp::DiagnosticTag::DEPRECATED => Some(DiagnosticTag::Deprecated), - lsp::DiagnosticTag::UNNECESSARY => Some(DiagnosticTag::Unnecessary), - _ => None - } - }).collect(); + let tags = if let Some(tags) = &diagnostic.tags { + let new_tags = tags + .iter() + .filter_map(|tag| match *tag { + lsp::DiagnosticTag::DEPRECATED => { + Some(DiagnosticTag::Deprecated) + } + lsp::DiagnosticTag::UNNECESSARY => { + Some(DiagnosticTag::Unnecessary) + } + _ => None, + }) + .collect(); new_tags } else { @@ -830,11 +833,12 @@ impl Application { tags, source: diagnostic.source.clone(), data: diagnostic.data.clone(), + language_server_id: server_id, }) }) .collect(); - doc.set_diagnostics(diagnostics); + doc.replace_diagnostics(diagnostics, server_id); } // Sort diagnostics first by severity and then by line numbers. @@ -842,13 +846,26 @@ impl Application { params .diagnostics .sort_unstable_by_key(|d| (d.severity, d.range.start)); + let diagnostics = params + .diagnostics + .into_iter() + .map(|d| (d, server_id, offset_encoding)) + .collect(); // 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); + match self.editor.diagnostics.entry(params.uri) { + Entry::Occupied(o) => { + let current_diagnostics = o.into_mut(); + // there may entries of other language servers, which is why we can't overwrite the whole entry + current_diagnostics.retain(|(_, lsp_id, _)| *lsp_id != server_id); + current_diagnostics.extend(diagnostics); + } + Entry::Vacant(v) => { + v.insert(diagnostics); + } + }; } Notification::ShowMessage(params) => { log::warn!("unhandled window/showMessage: {:?}", params); @@ -950,10 +967,12 @@ impl Application { .editor .documents_mut() .filter_map(|doc| { - if doc.language_server().map(|server| server.id()) - == Some(server_id) + if doc + .language_servers() + .iter() + .any(|server| server.id() == server_id) { - doc.set_diagnostics(Vec::new()); + doc.clear_diagnostics(server_id); doc.url() } else { None @@ -1029,28 +1048,15 @@ impl Application { })) } Ok(MethodCall::WorkspaceFolders) => { - let language_server = - self.editor.language_servers.get_by_id(server_id).unwrap(); - - Ok(json!(&*language_server.workspace_folders().await)) + Ok(json!(&*language_server!().workspace_folders().await)) } Ok(MethodCall::WorkspaceConfiguration(params)) => { + let language_server = language_server!(); let result: Vec<_> = params .items .iter() - .map(|item| { - let mut config = match &item.scope_uri { - Some(scope) => { - let path = scope.to_file_path().ok()?; - let doc = self.editor.document_by_path(path)?; - doc.language_config()?.config.as_ref()? - } - None => self - .editor - .language_servers - .get_by_id(server_id)? - .config()?, - }; + .filter_map(|item| { + let mut config = language_server.config()?; if let Some(section) = item.section.as_ref() { for part in section.split('.') { config = config.get(part)?; @@ -1074,15 +1080,7 @@ impl Application { } }; - 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)); + tokio::spawn(language_server!().reply(id, reply)); } Call::Invalid { id } => log::error!("LSP invalid method call id={:?}", id), } diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 5a844e351..c7d28e198 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -23,6 +23,7 @@ use helix_core::{ regex::{self, Regex, RegexBuilder}, search::{self, CharMatcher}, selection, shellwords, surround, + syntax::LanguageServerFeature, text_annotations::TextAnnotations, textobject, tree_sitter::Node, @@ -54,13 +55,13 @@ use crate::{ job::Callback, keymap::ReverseKeymap, ui::{ - self, editor::InsertEvent, lsp::SignatureHelp, overlay::overlaid, FilePicker, Picker, - Popup, Prompt, PromptEvent, + self, editor::InsertEvent, lsp::SignatureHelp, overlay::overlaid, CompletionItem, + FilePicker, Picker, Popup, Prompt, PromptEvent, }, }; use crate::job::{self, Jobs}; -use futures_util::StreamExt; +use futures_util::{stream::FuturesUnordered, StreamExt, TryStreamExt}; use std::{collections::HashMap, fmt, future::Future}; use std::{collections::HashSet, num::NonZeroUsize}; @@ -3029,7 +3030,7 @@ fn exit_select_mode(cx: &mut Context) { fn goto_first_diag(cx: &mut Context) { let (view, doc) = current!(cx.editor); - let selection = match doc.diagnostics().first() { + let selection = match doc.shown_diagnostics().next() { Some(diag) => Selection::single(diag.range.start, diag.range.end), None => return, }; @@ -3038,7 +3039,7 @@ fn goto_first_diag(cx: &mut Context) { fn goto_last_diag(cx: &mut Context) { let (view, doc) = current!(cx.editor); - let selection = match doc.diagnostics().last() { + let selection = match doc.shown_diagnostics().last() { Some(diag) => Selection::single(diag.range.start, diag.range.end), None => return, }; @@ -3054,10 +3055,9 @@ fn goto_next_diag(cx: &mut Context) { .cursor(doc.text().slice(..)); let diag = doc - .diagnostics() - .iter() + .shown_diagnostics() .find(|diag| diag.range.start > cursor_pos) - .or_else(|| doc.diagnostics().first()); + .or_else(|| doc.shown_diagnostics().next()); let selection = match diag { Some(diag) => Selection::single(diag.range.start, diag.range.end), @@ -3075,11 +3075,12 @@ fn goto_prev_diag(cx: &mut Context) { .cursor(doc.text().slice(..)); let diag = doc - .diagnostics() - .iter() + .shown_diagnostics() + .collect::>() + .into_iter() .rev() .find(|diag| diag.range.start < cursor_pos) - .or_else(|| doc.diagnostics().last()); + .or_else(|| doc.shown_diagnostics().last()); let selection = match diag { // NOTE: the selection is reversed because we're jumping to the @@ -3234,60 +3235,72 @@ pub mod insert { use helix_lsp::lsp; // if ch matches completion char, trigger completion let doc = doc_mut!(cx.editor); - let language_server = match doc.language_server() { - Some(language_server) => language_server, - None => return, - }; + let trigger_completion = doc + .language_servers_with_feature(LanguageServerFeature::Completion) + .iter() + .any(|ls| { + let capabilities = ls.capabilities(); - let capabilities = language_server.capabilities(); + // TODO: what if trigger is multiple chars long + matches!(&capabilities.completion_provider, Some(lsp::CompletionOptions { + trigger_characters: Some(triggers), + .. + }) if triggers.iter().any(|trigger| trigger.contains(ch))) + }); - if let Some(lsp::CompletionOptions { - trigger_characters: Some(triggers), - .. - }) = &capabilities.completion_provider - { - // TODO: what if trigger is multiple chars long - if triggers.iter().any(|trigger| trigger.contains(ch)) { - cx.editor.clear_idle_timer(); - super::completion(cx); - } + if trigger_completion { + cx.editor.clear_idle_timer(); + super::completion(cx); } } fn signature_help(cx: &mut Context, ch: char) { + use futures_util::FutureExt; use helix_lsp::lsp; // if ch matches signature_help char, trigger - let doc = doc_mut!(cx.editor); - // The language_server!() macro is not used here since it will - // print an "LSP not active for current buffer" message on - // every keypress. - let language_server = match doc.language_server() { - Some(language_server) => language_server, - None => return, - }; - - let capabilities = language_server.capabilities(); + let (view, doc) = current!(cx.editor); + // lsp doesn't tell us when to close the signature help, so we request + // the help information again after common close triggers which should + // return None, which in turn closes the popup. + let close_triggers = &[')', ';', '.']; + // TODO support multiple language servers (not just the first that is found) + let future = doc + .language_servers_with_feature(LanguageServerFeature::SignatureHelp) + .iter() + .find_map(|ls| { + let capabilities = ls.capabilities(); + + match capabilities { + lsp::ServerCapabilities { + signature_help_provider: + Some(lsp::SignatureHelpOptions { + trigger_characters: Some(triggers), + // TODO: retrigger_characters + .. + }), + .. + } if triggers.iter().any(|trigger| trigger.contains(ch)) + || close_triggers.contains(&ch) => + { + let pos = doc.position(view.id, ls.offset_encoding()); + ls.text_document_signature_help(doc.identifier(), pos, None) + } + _ if close_triggers.contains(&ch) => ls.text_document_signature_help( + doc.identifier(), + doc.position(view.id, ls.offset_encoding()), + None, + ), + // TODO: what if trigger is multiple chars long + _ => None, + } + }); - if let lsp::ServerCapabilities { - signature_help_provider: - Some(lsp::SignatureHelpOptions { - trigger_characters: Some(triggers), - // TODO: retrigger_characters - .. - }), - .. - } = capabilities - { - // TODO: what if trigger is multiple chars long - let is_trigger = triggers.iter().any(|trigger| trigger.contains(ch)); - // lsp doesn't tell us when to close the signature help, so we request - // the help information again after common close triggers which should - // return None, which in turn closes the popup. - let close_triggers = &[')', ';', '.']; - - if is_trigger || close_triggers.contains(&ch) { - super::signature_help_impl(cx, SignatureHelpInvoked::Automatic); - } + if let Some(future) = future { + super::signature_help_impl_with_future( + cx, + future.boxed(), + SignatureHelpInvoked::Automatic, + ) } } @@ -3301,7 +3314,7 @@ pub mod insert { Some(transaction) } - use helix_core::auto_pairs; + use helix_core::{auto_pairs, syntax::LanguageServerFeature}; pub fn insert_char(cx: &mut Context, c: char) { let (view, doc) = current_ref!(cx.editor); @@ -4046,55 +4059,55 @@ fn format_selections(cx: &mut Context) { use helix_lsp::{lsp, util::range_to_lsp_range}; let (view, doc) = current!(cx.editor); + let view_id = view.id; // via lsp if available // TODO: else via tree-sitter indentation calculations - let language_server = match doc.language_server() { - Some(language_server) => language_server, - None => return, - }; - - let ranges: Vec = doc - .selection(view.id) - .iter() - .map(|range| range_to_lsp_range(doc.text(), *range, language_server.offset_encoding())) - .collect(); - - if ranges.len() != 1 { + if doc.selection(view_id).len() != 1 { cx.editor .set_error("format_selections only supports a single selection for now"); return; } - // TODO: handle fails - // TODO: concurrent map over all ranges - - let range = ranges[0]; - - let request = match language_server.text_document_range_formatting( - doc.identifier(), - range, - lsp::FormattingOptions::default(), - None, - ) { - Some(future) => future, + let (future, offset_encoding) = match doc + .language_servers_with_feature(LanguageServerFeature::Format) + .iter() + .find_map(|language_server| { + let offset_encoding = language_server.offset_encoding(); + let ranges: Vec = doc + .selection(view_id) + .iter() + .map(|range| range_to_lsp_range(doc.text(), *range, offset_encoding)) + .collect(); + + // TODO: handle fails + // TODO: concurrent map over all ranges + + let range = ranges[0]; + + let future = language_server.text_document_range_formatting( + doc.identifier(), + range, + lsp::FormattingOptions::default(), + None, + )?; + Some((future, offset_encoding)) + }) { + Some(future_offset_encoding) => future_offset_encoding, None => { cx.editor - .set_error("Language server does not support range formatting"); + .set_error("No language server supports range formatting"); return; } }; - let edits = tokio::task::block_in_place(|| helix_lsp::block_on(request)).unwrap_or_default(); + let edits = tokio::task::block_in_place(|| helix_lsp::block_on(future)).unwrap_or_default(); - let transaction = helix_lsp::util::generate_transaction_from_edits( - doc.text(), - edits, - language_server.offset_encoding(), - ); + let transaction = + helix_lsp::util::generate_transaction_from_edits(doc.text(), edits, offset_encoding); - doc.apply(&transaction, view.id); + doc.apply(&transaction, view_id); } fn join_selections_impl(cx: &mut Context, select_space: bool) { @@ -4231,21 +4244,45 @@ pub fn completion(cx: &mut Context) { doc.savepoint(view) }; - let language_server = match doc.language_server() { - Some(language_server) => language_server, - None => return, - }; - - let offset_encoding = language_server.offset_encoding(); let text = savepoint.text.clone(); let cursor = savepoint.cursor(); - let pos = pos_to_lsp_pos(&text, cursor, offset_encoding); + let mut futures: FuturesUnordered<_> = doc + .language_servers_with_feature(LanguageServerFeature::Completion) + .iter() + // TODO this should probably already been filtered in something like "language_servers_with_feature" + .filter_map(|language_server| { + let language_server_id = language_server.id(); + let offset_encoding = language_server.offset_encoding(); + let pos = pos_to_lsp_pos(doc.text(), cursor, helix_lsp::OffsetEncoding::Utf8); + let completion_request = language_server.completion(doc.identifier(), pos, None)?; + + Some(async move { + let json = completion_request.await?; + let response: Option = serde_json::from_value(json)?; + + let items = match response { + Some(lsp::CompletionResponse::Array(items)) => items, + // TODO: do something with is_incomplete + Some(lsp::CompletionResponse::List(lsp::CompletionList { + is_incomplete: _is_incomplete, + items, + })) => items, + None => Vec::new(), + } + .into_iter() + .map(|item| CompletionItem { + item, + language_server_id, + offset_encoding, + resolved: false, + }) + .collect(); - let future = match language_server.completion(doc.identifier(), pos, None) { - Some(future) => future, - None => return, - }; + anyhow::Ok(items) + }) + }) + .collect(); // setup a channel that allows the request to be canceled let (tx, rx) = oneshot::channel(); @@ -4254,12 +4291,20 @@ pub fn completion(cx: &mut Context) { // and the associated request is automatically dropped cx.editor.completion_request_handle = Some(tx); let future = async move { + let items_future = async move { + let mut items = Vec::new(); + // TODO if one completion request errors, all other completion requests are discarded (even if they're valid) + while let Some(mut lsp_items) = futures.try_next().await? { + items.append(&mut lsp_items); + } + anyhow::Ok(items) + }; tokio::select! { biased; _ = rx => { - Ok(serde_json::Value::Null) + Ok(Vec::new()) } - res = future => { + res = items_future => { res } } @@ -4293,9 +4338,9 @@ pub fn completion(cx: &mut Context) { }, )); - cx.callback( - future, - move |editor, compositor, response: Option| { + cx.jobs.callback(async move { + let items = future.await?; + let call = move |editor: &mut Editor, compositor: &mut Compositor| { let (view, doc) = current_ref!(editor); // check if the completion request is stale. // @@ -4306,16 +4351,6 @@ pub fn completion(cx: &mut Context) { return; } - let items = match response { - Some(lsp::CompletionResponse::Array(items)) => items, - // TODO: do something with is_incomplete - Some(lsp::CompletionResponse::List(lsp::CompletionList { - is_incomplete: _is_incomplete, - items, - })) => items, - None => Vec::new(), - }; - if items.is_empty() { // editor.set_error("No completion available"); return; @@ -4326,7 +4361,6 @@ pub fn completion(cx: &mut Context) { editor, savepoint, items, - offset_encoding, start_offset, trigger_offset, size, @@ -4340,8 +4374,9 @@ pub fn completion(cx: &mut Context) { { compositor.remove(SignatureHelp::ID); } - }, - ); + }; + Ok(Callback::EditorCompositor(Box::new(call))) + }); } // comments @@ -5141,7 +5176,7 @@ async fn shell_impl_async( helix_view::document::to_writer(&mut stdin, (encoding::UTF_8, false), &input) .await?; } - Ok::<_, anyhow::Error>(()) + anyhow::Ok(()) }); let (output, _) = tokio::join! { process.wait_with_output(), diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 0ad6fb7eb..efef1211c 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -1,4 +1,4 @@ -use futures_util::FutureExt; +use futures_util::{future::BoxFuture, stream::FuturesUnordered, FutureExt}; use helix_lsp::{ block_on, lsp::{ @@ -8,6 +8,8 @@ use helix_lsp::{ util::{diagnostic_to_lsp_diagnostic, lsp_range_to_range, range_to_lsp_range}, OffsetEncoding, }; +use serde_json::Value; +use tokio_stream::StreamExt; use tui::{ text::{Span, Spans}, widgets::Row, @@ -15,7 +17,9 @@ use tui::{ use super::{align_view, push_jump, Align, Context, Editor, Open}; -use helix_core::{path, text_annotations::InlineAnnotation, Selection}; +use helix_core::{ + path, syntax::LanguageServerFeature, text_annotations::InlineAnnotation, Selection, +}; use helix_view::{ document::{DocumentInlayHints, DocumentInlayHintsId, Mode}, editor::Action, @@ -25,6 +29,7 @@ use helix_view::{ use crate::{ compositor::{self, Compositor}, + job::Callback, ui::{ self, lsp::SignatureHelp, overlay::overlaid, DynamicPicker, FileLocation, FilePicker, Popup, PromptEvent, @@ -35,24 +40,6 @@ use std::{ cmp::Ordering, collections::BTreeMap, fmt::Write, future::Future, path::PathBuf, sync::Arc, }; -/// 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) => { - match $doc.language_server() { - Some(language_server) => language_server, - None => { - $editor.set_status("Language server not active for current buffer"); - return; - } - } - }; -} - impl ui::menu::Item for lsp::Location { /// Current working directory. type Data = PathBuf; @@ -87,20 +74,30 @@ impl ui::menu::Item for lsp::Location { } } -impl ui::menu::Item for lsp::SymbolInformation { +struct SymbolInformationItem { + symbol: lsp::SymbolInformation, + offset_encoding: OffsetEncoding, +} + +impl ui::menu::Item for SymbolInformationItem { /// Path to currently focussed document type Data = Option; fn format(&self, current_doc_path: &Self::Data) -> Row { - if current_doc_path.as_ref() == Some(&self.location.uri) { - self.name.as_str().into() + if current_doc_path.as_ref() == Some(&self.symbol.location.uri) { + self.symbol.name.as_str().into() } else { - match self.location.uri.to_file_path() { + match self.symbol.location.uri.to_file_path() { Ok(path) => { let get_relative_path = path::get_relative_path(path.as_path()); - format!("{} ({})", &self.name, get_relative_path.to_string_lossy()).into() + format!( + "{} ({})", + &self.symbol.name, + get_relative_path.to_string_lossy() + ) + .into() } - Err(_) => format!("{} ({})", &self.name, &self.location.uri).into(), + Err(_) => format!("{} ({})", &self.symbol.name, &self.symbol.location.uri).into(), } } } @@ -116,6 +113,7 @@ struct DiagnosticStyles { struct PickerDiagnostic { url: lsp::Url, diag: lsp::Diagnostic, + offset_encoding: OffsetEncoding, } impl ui::menu::Item for PickerDiagnostic { @@ -211,21 +209,19 @@ fn jump_to_location( align_view(doc, view, Align::Center); } -fn sym_picker( - symbols: Vec, - current_path: Option, - offset_encoding: OffsetEncoding, -) -> FilePicker { +type SymbolPicker = FilePicker; + +fn sym_picker(symbols: Vec, current_path: Option) -> SymbolPicker { // TODO: drop current_path comparison and instead use workspace: bool flag? FilePicker::new( symbols, current_path.clone(), - move |cx, symbol, action| { + move |cx, item, action| { let (view, doc) = current!(cx.editor); push_jump(view, doc); - if current_path.as_ref() != Some(&symbol.location.uri) { - let uri = &symbol.location.uri; + if current_path.as_ref() != Some(&item.symbol.location.uri) { + let uri = &item.symbol.location.uri; let path = match uri.to_file_path() { Ok(path) => path, Err(_) => { @@ -245,7 +241,7 @@ fn sym_picker( let (view, doc) = current!(cx.editor); if let Some(range) = - lsp_range_to_range(doc.text(), symbol.location.range, offset_encoding) + lsp_range_to_range(doc.text(), item.symbol.location.range, item.offset_encoding) { // we flip the range so that the cursor sits on the start of the symbol // (for example start of the function). @@ -253,7 +249,7 @@ fn sym_picker( align_view(doc, view, Align::Center); } }, - move |_editor, symbol| Some(location_to_file_location(&symbol.location)), + move |_editor, item| Some(location_to_file_location(&item.symbol.location)), ) .truncate_start(false) } @@ -266,10 +262,9 @@ enum DiagnosticsFormat { fn diag_picker( cx: &Context, - diagnostics: BTreeMap>, + diagnostics: BTreeMap>, current_path: Option, format: DiagnosticsFormat, - offset_encoding: OffsetEncoding, ) -> FilePicker { // TODO: drop current_path comparison and instead use workspace: bool flag? @@ -277,10 +272,11 @@ fn diag_picker( let mut flat_diag = Vec::new(); for (url, diags) in diagnostics { flat_diag.reserve(diags.len()); - for diag in diags { + for (diag, _, offset_encoding) in diags { flat_diag.push(PickerDiagnostic { url: url.clone(), diag, + offset_encoding, }); } } @@ -295,7 +291,13 @@ fn diag_picker( FilePicker::new( flat_diag, (styles, format), - move |cx, PickerDiagnostic { url, diag }, action| { + move |cx, + PickerDiagnostic { + url, + diag, + offset_encoding, + }, + action| { if current_path.as_ref() == Some(url) { let (view, doc) = current!(cx.editor); push_jump(view, doc); @@ -306,14 +308,14 @@ fn diag_picker( let (view, doc) = current!(cx.editor); - if let Some(range) = lsp_range_to_range(doc.text(), diag.range, offset_encoding) { + 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, PickerDiagnostic { url, diag }| { + move |_editor, PickerDiagnostic { url, diag, .. }| { let location = lsp::Location::new(url.clone(), diag.range); Some(location_to_file_location(&location)) }, @@ -323,126 +325,149 @@ fn diag_picker( pub fn symbol_picker(cx: &mut Context) { fn nested_to_flat( - list: &mut Vec, + list: &mut Vec, file: &lsp::TextDocumentIdentifier, symbol: lsp::DocumentSymbol, + offset_encoding: OffsetEncoding, ) { #[allow(deprecated)] - list.push(lsp::SymbolInformation { - name: symbol.name, - kind: symbol.kind, - tags: symbol.tags, - deprecated: symbol.deprecated, - location: lsp::Location::new(file.uri.clone(), symbol.selection_range), - container_name: None, + list.push(SymbolInformationItem { + symbol: lsp::SymbolInformation { + name: symbol.name, + kind: symbol.kind, + tags: symbol.tags, + deprecated: symbol.deprecated, + location: lsp::Location::new(file.uri.clone(), symbol.selection_range), + container_name: None, + }, + offset_encoding, }); for child in symbol.children.into_iter().flatten() { - nested_to_flat(list, file, child); + nested_to_flat(list, file, child, offset_encoding); } } let doc = doc!(cx.editor); - let language_server = language_server!(cx.editor, doc); + let mut futures: FuturesUnordered<_> = doc + .language_servers_with_feature(LanguageServerFeature::DocumentSymbols) + .iter() + .filter_map(|ls| { + let request = ls.document_symbols(doc.identifier())?; + Some((request, ls.offset_encoding(), doc.identifier())) + }) + .map(|(request, offset_encoding, doc_id)| async move { + let json = request.await?; + let response: Option = serde_json::from_value(json)?; + let symbols = match response { + Some(symbols) => symbols, + None => return anyhow::Ok(vec![]), + }; + // lsp has two ways to represent symbols (flat/nested) + // convert the nested variant to flat, so that we have a homogeneous list + let symbols = match symbols { + lsp::DocumentSymbolResponse::Flat(symbols) => symbols + .into_iter() + .map(|symbol| SymbolInformationItem { + symbol, + offset_encoding, + }) + .collect(), + lsp::DocumentSymbolResponse::Nested(symbols) => { + let mut flat_symbols = Vec::new(); + for symbol in symbols { + nested_to_flat(&mut flat_symbols, &doc_id, symbol, offset_encoding) + } + flat_symbols + } + }; + Ok(symbols) + }) + .collect(); let current_url = doc.url(); - let offset_encoding = language_server.offset_encoding(); - let future = match language_server.document_symbols(doc.identifier()) { - Some(future) => future, - None => { - cx.editor - .set_error("Language server does not support document symbols"); - return; - } - }; - - cx.callback( - future, - move |editor, compositor, response: Option| { - if let Some(symbols) = response { - // lsp has two ways to represent symbols (flat/nested) - // convert the nested variant to flat, so that we have a homogeneous list - let symbols = match symbols { - lsp::DocumentSymbolResponse::Flat(symbols) => symbols, - lsp::DocumentSymbolResponse::Nested(symbols) => { - let doc = doc!(editor); - let mut flat_symbols = Vec::new(); - for symbol in symbols { - nested_to_flat(&mut flat_symbols, &doc.identifier(), symbol) - } - flat_symbols - } - }; + if futures.is_empty() { + cx.editor + .set_error("No Language server does support document symbols"); + return; + } - let picker = sym_picker(symbols, current_url, offset_encoding); - compositor.push(Box::new(overlaid(picker))) + cx.jobs.callback(async move { + let mut symbols = Vec::new(); + // TODO if one symbol request errors, all other requests are discarded (even if they're valid) + while let Some(mut lsp_items) = futures.try_next().await? { + symbols.append(&mut lsp_items); + } + let call = move |editor: &mut Editor, compositor: &mut Compositor| { + if symbols.is_empty() { + editor.set_error("No symbols available"); + return; } - }, - ) + let picker = sym_picker(symbols, current_url); + compositor.push(Box::new(overlaid(picker))) + }; + + Ok(Callback::EditorCompositor(Box::new(call))) + }); } pub fn workspace_symbol_picker(cx: &mut Context) { let doc = doc!(cx.editor); - let current_url = doc.url(); - let language_server = language_server!(cx.editor, doc); - let offset_encoding = language_server.offset_encoding(); - let future = match language_server.workspace_symbols("".to_string()) { - Some(future) => future, - None => { - cx.editor - .set_error("Language server does not support workspace symbols"); - return; + + let get_symbols = move |pattern: String, editor: &mut Editor| { + let doc = doc!(editor); + let mut futures: FuturesUnordered<_> = doc + .language_servers_with_feature(LanguageServerFeature::WorkspaceSymbols) + .iter() + .filter_map(|ls| Some((ls.workspace_symbols(pattern.clone())?, ls.offset_encoding()))) + .map(|(request, offset_encoding)| async move { + let json = request.await?; + + let response = serde_json::from_value::>>(json)? + .unwrap_or_default() + .into_iter() + .map(|symbol| SymbolInformationItem { + symbol, + offset_encoding, + }) + .collect(); + + anyhow::Ok(response) + }) + .collect(); + + if futures.is_empty() { + editor.set_error("No Language server does support workspace symbols"); } - }; - cx.callback( - future, - move |_editor, compositor, response: Option>| { - let symbols = response.unwrap_or_default(); - let picker = sym_picker(symbols, current_url, offset_encoding); - let get_symbols = |query: String, editor: &mut Editor| { - let doc = doc!(editor); - let language_server = match doc.language_server() { - Some(s) => s, - None => { - // This should not generally happen since the picker will not - // even open in the first place if there is no server. - return async move { Err(anyhow::anyhow!("LSP not active")) }.boxed(); - } - }; - let symbol_request = match language_server.workspace_symbols(query) { - Some(future) => future, - None => { - // This should also not happen since the language server must have - // supported workspace symbols before to reach this block. - return async move { - Err(anyhow::anyhow!( - "Language server does not support workspace symbols" - )) - } - .boxed(); - } - }; + async move { + let mut symbols = Vec::new(); + // TODO if one symbol request errors, all other requests are discarded (even if they're valid) + while let Some(mut lsp_items) = futures.try_next().await? { + symbols.append(&mut lsp_items); + } + anyhow::Ok(symbols) + } + .boxed() + }; - let future = async move { - let json = symbol_request.await?; - let response: Option> = - serde_json::from_value(json)?; + let current_url = doc.url(); + let initial_symbols = get_symbols("".to_owned(), cx.editor); - Ok(response.unwrap_or_default()) - }; - future.boxed() - }; + cx.jobs.callback(async move { + let symbols = initial_symbols.await?; + let call = move |_editor: &mut Editor, compositor: &mut Compositor| { + let picker = sym_picker(symbols, current_url); let dyn_picker = DynamicPicker::new(picker, Box::new(get_symbols)); compositor.push(Box::new(overlaid(dyn_picker))) - }, - ) + }; + + Ok(Callback::EditorCompositor(Box::new(call))) + }); } 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 @@ -454,7 +479,6 @@ pub fn diagnostics_picker(cx: &mut Context) { [(current_url.clone(), diagnostics)].into(), Some(current_url), DiagnosticsFormat::HideSourcePath, - offset_encoding, ); cx.push_layer(Box::new(overlaid(picker))); } @@ -462,24 +486,28 @@ pub fn diagnostics_picker(cx: &mut Context) { 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(); + // TODO not yet filtered by LanguageServerFeature, need to do something similar as Document::shown_diagnostics here for all open documents let diagnostics = cx.editor.diagnostics.clone(); let picker = diag_picker( cx, diagnostics, current_url, DiagnosticsFormat::ShowSourcePath, - offset_encoding, ); cx.push_layer(Box::new(overlaid(picker))); } -impl ui::menu::Item for lsp::CodeActionOrCommand { +struct CodeActionOrCommandItem { + lsp_item: lsp::CodeActionOrCommand, + offset_encoding: OffsetEncoding, + language_server_id: usize, +} + +impl ui::menu::Item for CodeActionOrCommandItem { type Data = (); fn format(&self, _data: &Self::Data) -> Row { - match self { + match &self.lsp_item { lsp::CodeActionOrCommand::CodeAction(action) => action.title.as_str().into(), lsp::CodeActionOrCommand::Command(command) => command.title.as_str().into(), } @@ -546,45 +574,40 @@ fn action_fixes_diagnostics(action: &CodeActionOrCommand) -> bool { pub fn code_action(cx: &mut Context) { let (view, doc) = current!(cx.editor); - let language_server = language_server!(cx.editor, doc); - 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 = match 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, - trigger_kind: Some(CodeActionTriggerKind::INVOKED), - }, - ) { - Some(future) => future, - None => { - cx.editor - .set_error("Language server does not support code actions"); - return; - } - }; - - cx.callback( - future, - move |editor, compositor, response: Option| { + let mut futures: FuturesUnordered<_> = doc + .language_servers_with_feature(LanguageServerFeature::CodeAction) + .iter() + // TODO this should probably already been filtered in something like "language_servers_with_feature" + .filter_map(|language_server| { + let offset_encoding = language_server.offset_encoding(); + let language_server_id = language_server.id(); + let range = range_to_lsp_range(doc.text(), selection_range, offset_encoding); + // Filter and convert overlapping diagnostics + let code_action_context = 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, + trigger_kind: Some(CodeActionTriggerKind::INVOKED), + }; + let code_action_request = + language_server.code_actions(doc.identifier(), range, code_action_context)?; + Some((code_action_request, offset_encoding, language_server_id)) + }) + .map(|(request, offset_encoding, ls_id)| async move { + let json = request.await?; + let response: Option = serde_json::from_value(json)?; let mut actions = match response { Some(a) => a, - None => return, + None => return anyhow::Ok(Vec::new()), }; // remove disabled code actions @@ -596,11 +619,6 @@ pub fn code_action(cx: &mut Context) { ) }); - if actions.is_empty() { - editor.set_status("No code actions available"); - return; - } - // Sort codeactions into a useful order. This behaviour is only partially described in the LSP spec. // Many details are modeled after vscode because language servers are usually tested against it. // VScode sorts the codeaction two times: @@ -636,18 +654,48 @@ pub fn code_action(cx: &mut Context) { .reverse() }); - let mut picker = ui::Menu::new(actions, (), move |editor, code_action, event| { + Ok(actions + .into_iter() + .map(|lsp_item| CodeActionOrCommandItem { + lsp_item, + offset_encoding, + language_server_id: ls_id, + }) + .collect()) + }) + .collect(); + + if futures.is_empty() { + cx.editor + .set_error("No Language server does support code actions"); + return; + } + + cx.jobs.callback(async move { + let mut actions = Vec::new(); + // TODO if one code action request errors, all other requests are ignored (even if they're valid) + while let Some(mut lsp_items) = futures.try_next().await? { + actions.append(&mut lsp_items); + } + + let call = move |editor: &mut Editor, compositor: &mut Compositor| { + if actions.is_empty() { + editor.set_error("No code actions available"); + return; + } + let mut picker = ui::Menu::new(actions, (), move |editor, action, event| { if event != PromptEvent::Validate { return; } // always present here - let code_action = code_action.unwrap(); + let action = action.unwrap(); + let offset_encoding = action.offset_encoding; - match code_action { + match &action.lsp_item { lsp::CodeActionOrCommand::Command(command) => { log::debug!("code action command: {:?}", command); - execute_lsp_command(editor, command.clone()); + execute_lsp_command(editor, action.language_server_id, command.clone()); } lsp::CodeActionOrCommand::CodeAction(code_action) => { log::debug!("code action: {:?}", code_action); @@ -659,7 +707,7 @@ pub fn code_action(cx: &mut Context) { // if code action provides both edit and command first the edit // should be applied and then the command if let Some(command) = &code_action.command { - execute_lsp_command(editor, command.clone()); + execute_lsp_command(editor, action.language_server_id, command.clone()); } } } @@ -668,8 +716,10 @@ pub fn code_action(cx: &mut Context) { let popup = Popup::new("code-action", picker).with_scrollbar(false); compositor.replace_or_push("code-action", popup); - }, - ) + }; + + Ok(Callback::EditorCompositor(Box::new(call))) + }); } impl ui::menu::Item for lsp::Command { @@ -679,13 +729,14 @@ impl ui::menu::Item for lsp::Command { } } -pub fn execute_lsp_command(editor: &mut Editor, cmd: lsp::Command) { - let doc = doc!(editor); - let language_server = language_server!(editor, doc); - +pub fn execute_lsp_command(editor: &mut Editor, language_server_id: usize, cmd: lsp::Command) { // the command is executed on the server and communicated back // to the client asynchronously using workspace edits - let future = match language_server.command(cmd) { + let future = match editor + .language_servers + .get_by_id(language_server_id) + .and_then(|language_server| language_server.command(cmd)) + { Some(future) => future, None => { editor.set_error("Language server does not support executing commands"); @@ -977,18 +1028,22 @@ fn to_locations(definitions: Option) -> Vec future, + let (future, offset_encoding) = match doc + .language_servers_with_feature(LanguageServerFeature::GotoDeclaration) + .iter() + .find_map(|language_server| { + let offset_encoding = language_server.offset_encoding(); + let pos = doc.position(view.id, offset_encoding); + let future = language_server.goto_declaration(doc.identifier(), pos, None)?; + Some((future, offset_encoding)) + }) { + Some(future_offset_encoding) => future_offset_encoding, None => { cx.editor - .set_error("Language server does not support goto-declaration"); + .set_error("No language server supports goto-declaration"); return; } }; @@ -1004,16 +1059,19 @@ pub fn goto_declaration(cx: &mut Context) { pub fn goto_definition(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 = match language_server.goto_definition(doc.identifier(), pos, None) { - Some(future) => future, + let (future, offset_encoding) = match doc + .language_servers_with_feature(LanguageServerFeature::GotoDefinition) + .iter() + .find_map(|language_server| { + let offset_encoding = language_server.offset_encoding(); + let pos = doc.position(view.id, offset_encoding); + let future = language_server.goto_definition(doc.identifier(), pos, None)?; + Some((future, offset_encoding)) + }) { + Some(future_offset_encoding) => future_offset_encoding, None => { cx.editor - .set_error("Language server does not support goto-definition"); + .set_error("No language server supports goto-definition"); return; } }; @@ -1029,16 +1087,19 @@ pub fn goto_definition(cx: &mut Context) { pub fn goto_type_definition(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 = match language_server.goto_type_definition(doc.identifier(), pos, None) { - Some(future) => future, + let (future, offset_encoding) = match doc + .language_servers_with_feature(LanguageServerFeature::GotoTypeDefinition) + .iter() + .find_map(|language_server| { + let offset_encoding = language_server.offset_encoding(); + let pos = doc.position(view.id, offset_encoding); + let future = language_server.goto_type_definition(doc.identifier(), pos, None)?; + Some((future, offset_encoding)) + }) { + Some(future_offset_encoding) => future_offset_encoding, None => { cx.editor - .set_error("Language server does not support goto-type-definition"); + .set_error("No language server supports goto-type-definition"); return; } }; @@ -1054,16 +1115,19 @@ pub fn goto_type_definition(cx: &mut Context) { pub fn goto_implementation(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 = match language_server.goto_implementation(doc.identifier(), pos, None) { - Some(future) => future, + let (future, offset_encoding) = match doc + .language_servers_with_feature(LanguageServerFeature::GotoImplementation) + .iter() + .find_map(|language_server| { + let offset_encoding = language_server.offset_encoding(); + let pos = doc.position(view.id, offset_encoding); + let future = language_server.goto_implementation(doc.identifier(), pos, None)?; + Some((future, offset_encoding)) + }) { + Some(future_offset_encoding) => future_offset_encoding, None => { cx.editor - .set_error("Language server does not support goto-implementation"); + .set_error("no language server supports goto-implementation"); return; } }; @@ -1080,21 +1144,24 @@ pub fn goto_implementation(cx: &mut Context) { pub fn goto_reference(cx: &mut Context) { let config = cx.editor.config(); 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 = match language_server.goto_reference( - doc.identifier(), - pos, - config.lsp.goto_reference_include_declaration, - None, - ) { - Some(future) => future, + let (future, offset_encoding) = match doc + .language_servers_with_feature(LanguageServerFeature::GotoReference) + .iter() + .find_map(|language_server| { + let offset_encoding = language_server.offset_encoding(); + let pos = doc.position(view.id, offset_encoding); + let future = language_server.goto_reference( + doc.identifier(), + pos, + config.lsp.goto_reference_include_declaration, + None, + )?; + Some((future, offset_encoding)) + }) { + Some(future_offset_encoding) => future_offset_encoding, None => { cx.editor - .set_error("Language server does not support goto-reference"); + .set_error("language server supports goto-reference"); return; } }; @@ -1108,7 +1175,7 @@ pub fn goto_reference(cx: &mut Context) { ); } -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Clone, Copy)] pub enum SignatureHelpInvoked { Manual, Automatic, @@ -1120,35 +1187,34 @@ pub fn signature_help(cx: &mut Context) { pub fn signature_help_impl(cx: &mut Context, invoked: SignatureHelpInvoked) { let (view, doc) = current!(cx.editor); - let was_manually_invoked = invoked == SignatureHelpInvoked::Manual; - let language_server = match doc.language_server() { - Some(language_server) => language_server, + // TODO merge multiple language server signature help into one instead of just taking the first language server that supports it + let future = match doc + .language_servers_with_feature(LanguageServerFeature::SignatureHelp) + .iter() + .find_map(|language_server| { + let pos = doc.position(view.id, language_server.offset_encoding()); + language_server.text_document_signature_help(doc.identifier(), pos, None) + }) { + Some(future) => future.boxed(), None => { // Do not show the message if signature help was invoked // automatically on backspace, trigger characters, etc. - if was_manually_invoked { + if invoked == SignatureHelpInvoked::Manual { cx.editor - .set_status("Language server not active for current buffer"); - } - return; - } - }; - let offset_encoding = language_server.offset_encoding(); - - let pos = doc.position(view.id, offset_encoding); - - let future = match language_server.text_document_signature_help(doc.identifier(), pos, None) { - Some(f) => f, - None => { - if was_manually_invoked { - cx.editor - .set_error("Language server does not support signature-help"); + .set_error("No language server supports signature-help"); } return; } }; + signature_help_impl_with_future(cx, future, invoked); +} +pub fn signature_help_impl_with_future( + cx: &mut Context, + future: BoxFuture<'static, helix_lsp::Result>, + invoked: SignatureHelpInvoked, +) { cx.callback( future, move |editor, compositor, response: Option| { @@ -1156,7 +1222,7 @@ pub fn signature_help_impl(cx: &mut Context, invoked: SignatureHelpInvoked) { if !(config.lsp.auto_signature_help || SignatureHelp::visible_popup(compositor).is_some() - || was_manually_invoked) + || invoked == SignatureHelpInvoked::Manual) { return; } @@ -1165,7 +1231,7 @@ pub fn signature_help_impl(cx: &mut Context, invoked: SignatureHelpInvoked) { // it very probably means the server was a little slow to respond and the user has // already moved on to something else, making a signature help popup will just be an // annoyance, see https://github.com/helix-editor/helix/issues/3112 - if !was_manually_invoked && editor.mode != Mode::Insert { + if invoked == SignatureHelpInvoked::Automatic && editor.mode != Mode::Insert { return; } @@ -1255,18 +1321,20 @@ pub fn signature_help_impl(cx: &mut Context, invoked: SignatureHelpInvoked) { pub fn hover(cx: &mut Context) { let (view, doc) = current!(cx.editor); - let language_server = language_server!(cx.editor, doc); - let offset_encoding = language_server.offset_encoding(); // TODO: factor out a doc.position_identifier() that returns lsp::TextDocumentPositionIdentifier + let request = doc + .language_servers_with_feature(LanguageServerFeature::Hover) + .iter() + .find_map(|language_server| { + let pos = doc.position(view.id, language_server.offset_encoding()); + language_server.text_document_hover(doc.identifier(), pos, None) + }); - let pos = doc.position(view.id, offset_encoding); - - let future = match language_server.text_document_hover(doc.identifier(), pos, None) { + let future = match request { Some(future) => future, None => { - cx.editor - .set_error("Language server does not support hover"); + cx.editor.set_error("No language server supports hover"); return; } }; @@ -1349,7 +1417,11 @@ pub fn rename_symbol(cx: &mut Context) { } } - fn create_rename_prompt(editor: &Editor, prefill: String) -> Box { + fn create_rename_prompt( + editor: &Editor, + prefill: String, + language_server_id: Option, + ) -> Box { let prompt = ui::Prompt::new( "rename-to:".into(), None, @@ -1358,27 +1430,36 @@ pub fn rename_symbol(cx: &mut Context) { if event != PromptEvent::Validate { return; } - 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 = - match language_server.rename_symbol(doc.identifier(), pos, input.to_string()) { - Some(future) => future, - None => { - cx.editor - .set_error("Language server does not support symbol renaming"); - return; + let request = doc + .language_servers_with_feature(LanguageServerFeature::RenameSymbol) + .iter() + .find_map(|language_server| { + if let Some(language_server_id) = language_server_id { + if language_server.id() != language_server_id { + return None; + } } - }; - match block_on(future) { - Ok(edits) => { - let _ = apply_workspace_edit(cx.editor, offset_encoding, &edits); + let offset_encoding = language_server.offset_encoding(); + let pos = doc.position(view.id, offset_encoding); + let future = language_server.rename_symbol( + doc.identifier(), + pos, + input.to_string(), + )?; + Some((future, offset_encoding)) + }); + + if let Some((future, offset_encoding)) = request { + match block_on(future) { + Ok(edits) => { + let _ = apply_workspace_edit(cx.editor, offset_encoding, &edits); + } + Err(err) => cx.editor.set_error(err.to_string()), } - Err(err) => cx.editor.set_error(err.to_string()), + } else { + cx.editor + .set_error("No language server supports symbol renaming"); } }, ) @@ -1388,20 +1469,20 @@ pub fn rename_symbol(cx: &mut Context) { } let (view, doc) = current!(cx.editor); - let language_server = language_server!(cx.editor, doc); - let offset_encoding = language_server.offset_encoding(); - - if !language_server.supports_rename() { - cx.editor - .set_error("Language server does not support symbol renaming"); - return; - } - let pos = doc.position(view.id, offset_encoding); + let prepare_rename_request = doc + .language_servers_with_feature(LanguageServerFeature::RenameSymbol) + .iter() + .find_map(|language_server| { + let offset_encoding = language_server.offset_encoding(); + let pos = doc.position(view.id, offset_encoding); + let future = language_server.prepare_rename(doc.identifier(), pos)?; + Some((future, offset_encoding, language_server.id())) + }); - match language_server.prepare_rename(doc.identifier(), pos) { + match prepare_rename_request { // Language server supports textDocument/prepareRename, use it. - Some(future) => cx.callback( + Some((future, offset_encoding, ls_id)) => cx.callback( future, move |editor, compositor, response: Option| { let prefill = match get_prefill_from_lsp_response(editor, offset_encoding, response) @@ -1413,7 +1494,7 @@ pub fn rename_symbol(cx: &mut Context) { } }; - let prompt = create_rename_prompt(editor, prefill); + let prompt = create_rename_prompt(editor, prefill, Some(ls_id)); compositor.push(prompt); }, @@ -1423,7 +1504,7 @@ pub fn rename_symbol(cx: &mut Context) { None => { let prefill = get_prefill_from_word_boundary(cx.editor); - let prompt = create_rename_prompt(cx.editor, prefill); + let prompt = create_rename_prompt(cx.editor, prefill, None); cx.push_layer(prompt); } @@ -1432,17 +1513,20 @@ 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 = match language_server.text_document_document_highlight(doc.identifier(), pos, None) - { + let (future, offset_encoding) = match doc + .language_servers_with_feature(LanguageServerFeature::DocumentHighlight) + .iter() + .find_map(|language_server| { + 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)?; + Some((future, offset_encoding)) + }) { Some(future) => future, None => { cx.editor - .set_error("Language server does not support document highlight"); + .set_error("No language server supports document-highlight"); return; } }; @@ -1455,8 +1539,6 @@ pub fn select_references_to_symbol_under_cursor(cx: &mut Context) { _ => 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; @@ -1502,63 +1584,58 @@ fn compute_inlay_hints_for_view( let view_id = view.id; let doc_id = view.doc; - let language_server = doc.language_server()?; - - let capabilities = language_server.capabilities(); - - let (future, new_doc_inlay_hints_id) = match capabilities.inlay_hint_provider { - Some( - lsp::OneOf::Left(true) - | lsp::OneOf::Right(lsp::InlayHintServerCapabilities::Options(_)), - ) => { - let doc_text = doc.text(); - let len_lines = doc_text.len_lines(); - - // Compute ~3 times the current view height of inlay hints, that way some scrolling - // will not show half the view with hints and half without while still being faster - // than computing all the hints for the full file (which could be dozens of time - // longer than the view is). - let view_height = view.inner_height(); - let first_visible_line = - doc_text.char_to_line(view.offset.anchor.min(doc_text.len_chars())); - let first_line = first_visible_line.saturating_sub(view_height); - let last_line = first_visible_line - .saturating_add(view_height.saturating_mul(2)) - .min(len_lines); - - let new_doc_inlay_hint_id = DocumentInlayHintsId { - first_line, - last_line, - }; - // Don't recompute the annotations in case nothing has changed about the view - if !doc.inlay_hints_oudated - && doc - .inlay_hints(view_id) - .map_or(false, |dih| dih.id == new_doc_inlay_hint_id) - { - return None; - } + let language_servers = doc.language_servers_with_feature(LanguageServerFeature::InlayHints); + let language_server = language_servers.iter().find(|language_server| { + matches!( + language_server.capabilities().inlay_hint_provider, + Some( + lsp::OneOf::Left(true) + | lsp::OneOf::Right(lsp::InlayHintServerCapabilities::Options(_)) + ) + ) + })?; + + let doc_text = doc.text(); + let len_lines = doc_text.len_lines(); + + // Compute ~3 times the current view height of inlay hints, that way some scrolling + // will not show half the view with hints and half without while still being faster + // than computing all the hints for the full file (which could be dozens of time + // longer than the view is). + let view_height = view.inner_height(); + let first_visible_line = doc_text.char_to_line(view.offset.anchor.min(doc_text.len_chars())); + let first_line = first_visible_line.saturating_sub(view_height); + let last_line = first_visible_line + .saturating_add(view_height.saturating_mul(2)) + .min(len_lines); + + let new_doc_inlay_hints_id = DocumentInlayHintsId { + first_line, + last_line, + }; + // Don't recompute the annotations in case nothing has changed about the view + if !doc.inlay_hints_oudated + && doc + .inlay_hints(view_id) + .map_or(false, |dih| dih.id == new_doc_inlay_hints_id) + { + return None; + } - let doc_slice = doc_text.slice(..); - let first_char_in_range = doc_slice.line_to_char(first_line); - let last_char_in_range = doc_slice.line_to_char(last_line); + let doc_slice = doc_text.slice(..); + let first_char_in_range = doc_slice.line_to_char(first_line); + let last_char_in_range = doc_slice.line_to_char(last_line); - let range = helix_lsp::util::range_to_lsp_range( - doc_text, - helix_core::Range::new(first_char_in_range, last_char_in_range), - language_server.offset_encoding(), - ); + let range = helix_lsp::util::range_to_lsp_range( + doc_text, + helix_core::Range::new(first_char_in_range, last_char_in_range), + language_server.offset_encoding(), + ); - ( - language_server.text_document_range_inlay_hints(doc.identifier(), range, None), - new_doc_inlay_hint_id, - ) - } - _ => return None, - }; + let offset_encoding = language_server.offset_encoding(); let callback = super::make_job_callback( - future?, + language_server.text_document_range_inlay_hints(doc.identifier(), range, None)?, move |editor, _compositor, response: Option>| { // The config was modified or the window was closed while the request was in flight if !editor.config().lsp.display_inlay_hints || editor.tree.try_get(view_id).is_none() { @@ -1572,8 +1649,8 @@ fn compute_inlay_hints_for_view( }; // If we have neither hints nor an LSP, empty the inlay hints since they're now oudated - let (mut hints, offset_encoding) = match (response, doc.language_server()) { - (Some(h), Some(ls)) if !h.is_empty() => (h, ls.offset_encoding()), + let mut hints = match response { + Some(hints) if !hints.is_empty() => hints, _ => { doc.set_inlay_hints( view_id, diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 81a24059a..b78de7729 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1329,23 +1329,20 @@ fn lsp_workspace_command( if event != PromptEvent::Validate { return Ok(()); } - - let (_, doc) = current!(cx.editor); - - let language_server = match doc.language_server() { - Some(language_server) => language_server, - None => { - cx.editor - .set_status("Language server not active for current buffer"); - return Ok(()); - } - }; - - let options = match &language_server.capabilities().execute_command_provider { - Some(options) => options, + let doc = doc!(cx.editor); + let language_servers = + doc.language_servers_with_feature(LanguageServerFeature::WorkspaceCommand); + let (language_server_id, options) = match language_servers.iter().find_map(|ls| { + ls.capabilities() + .execute_command_provider + .as_ref() + .map(|options| (ls.id(), options)) + }) { + Some(id_options) => id_options, None => { - cx.editor - .set_status("Workspace commands are not supported for this language server"); + cx.editor.set_status( + "No active language servers for this document support workspace commands", + ); return Ok(()); } }; @@ -1362,8 +1359,8 @@ fn lsp_workspace_command( let callback = async move { let call: job::Callback = Callback::EditorCompositor(Box::new( move |_editor: &mut Editor, compositor: &mut Compositor| { - let picker = ui::Picker::new(commands, (), |cx, command, _action| { - execute_lsp_command(cx.editor, command.clone()); + let picker = ui::Picker::new(commands, (), move |cx, command, _action| { + execute_lsp_command(cx.editor, language_server_id, command.clone()); }); compositor.push(Box::new(overlaid(picker))) }, @@ -1376,6 +1373,7 @@ fn lsp_workspace_command( if options.commands.iter().any(|c| c == &command) { execute_lsp_command( cx.editor, + language_server_id, helix_lsp::lsp::Command { title: command.clone(), arguments: None, @@ -1426,7 +1424,7 @@ fn lsp_restart( .collect(); for document_id in document_ids_to_refresh { - cx.editor.refresh_language_server(document_id); + cx.editor.refresh_language_servers(document_id); } Ok(()) @@ -1443,21 +1441,63 @@ fn lsp_stop( let doc = doc!(cx.editor); - let ls_id = doc - .language_server() - .map(|ls| ls.id()) - .context("LSP not running for the current document")?; + // TODO this stops language servers which may be used in another doc/language type that uses the same language servers + // I'm not sure if this is really what we want + let ls_shutdown_names = doc + .language_servers() + .iter() + .map(|ls| ls.name()) + .collect::>(); - let config = doc - .language_config() - .context("LSP not defined for the current document")?; - cx.editor.language_servers.stop(config); + for ls_name in &ls_shutdown_names { + cx.editor.language_servers.stop(ls_name); + } + + let doc_ids_active_clients: Vec<_> = cx + .editor + .documents() + .filter_map(|doc| { + let doc_active_ls_ids: Vec<_> = doc + .language_servers() + .iter() + .filter(|ls| !ls_shutdown_names.contains(&ls.name())) + .map(|ls| ls.id()) + .collect(); + + let active_clients: Vec<_> = cx + .editor + .language_servers + .iter_clients() + .filter(|client| doc_active_ls_ids.contains(&client.id())) + .map(Clone::clone) + .collect(); + + if active_clients.len() != doc.language_servers().len() { + Some((doc.id(), active_clients)) + } else { + None + } + }) + .collect(); + + for (doc_id, active_clients) in doc_ids_active_clients { + let doc = cx.editor.documents.get_mut(&doc_id).unwrap(); + + let stopped_clients: Vec<_> = doc + .language_servers() + .iter() + .filter(|ls| { + !active_clients + .iter() + .any(|active_ls| active_ls.id() == ls.id()) + }) + .map(|ls| ls.id()) + .collect(); // is necessary because of borrow-checking - for doc in cx.editor.documents_mut() { - if doc.language_server().map_or(false, |ls| ls.id() == ls_id) { - doc.set_language_server(None); - doc.set_diagnostics(Default::default()); + for client_id in stopped_clients { + doc.clear_diagnostics(client_id) } + doc.set_language_servers(active_clients); } Ok(()) @@ -1850,7 +1890,7 @@ fn language( doc.detect_indent_and_line_ending(); let id = doc.id(); - cx.editor.refresh_language_server(id); + cx.editor.refresh_language_servers(id); Ok(()) } @@ -2588,7 +2628,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "lsp-restart", aliases: &[], - doc: "Restarts the Language Server that is in use by the current doc", + doc: "Restarts the language servers used by the current doc", fun: lsp_restart, signature: CommandSignature::none(), }, diff --git a/helix-term/src/health.rs b/helix-term/src/health.rs index 480c2c675..031f982cc 100644 --- a/helix-term/src/health.rs +++ b/helix-term/src/health.rs @@ -2,7 +2,10 @@ use crossterm::{ style::{Color, Print, Stylize}, tty::IsTty, }; -use helix_core::config::{default_syntax_loader, user_syntax_loader}; +use helix_core::{ + config::{default_syntax_loader, user_syntax_loader}, + syntax::LanguageServerFeatureConfiguration, +}; use helix_loader::grammar::load_runtime_file; use helix_view::clipboard::get_clipboard_provider; use std::io::Write; @@ -192,10 +195,14 @@ pub fn languages_all() -> std::io::Result<()> { for lang in &syn_loader_conf.language { column(&lang.language_id, Color::Reset); - let lsp = lang - .language_server - .as_ref() - .map(|lsp| lsp.command.to_string()); + // TODO multiple language servers (check binary for each supported language server, not just the first) + + let lsp = lang.language_servers.first().and_then(|lsp| { + syn_loader_conf + .language_server + .get(lsp.name()) + .map(|config| config.command.clone()) + }); check_binary(lsp); let dap = lang.debugger.as_ref().map(|dap| dap.command.to_string()); @@ -264,11 +271,15 @@ pub fn language(lang_str: String) -> std::io::Result<()> { } }; + // TODO multiple language servers probe_protocol( "language server", - lang.language_server - .as_ref() - .map(|lsp| lsp.command.to_string()), + lang.language_servers.first().and_then(|lsp| { + syn_loader_conf + .language_server + .get(lsp.name()) + .map(|config| config.command.clone()) + }), )?; probe_protocol( diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index c5c405801..859403a7f 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -15,7 +15,7 @@ use helix_view::{graphics::Rect, Document, Editor}; use crate::commands; use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent}; -use helix_lsp::{lsp, util}; +use helix_lsp::{lsp, util, OffsetEncoding}; impl menu::Item for CompletionItem { type Data = (); @@ -38,6 +38,7 @@ impl menu::Item for CompletionItem { || self.item.tags.as_ref().map_or(false, |tags| { tags.contains(&lsp::CompletionItemTag::DEPRECATED) }); + menu::Row::new(vec![ menu::Cell::from(Span::styled( self.item.label.as_str(), @@ -79,19 +80,16 @@ impl menu::Item for CompletionItem { } None => "", }), - // self.detail.as_deref().unwrap_or("") - // self.label_details - // .as_ref() - // .or(self.detail()) - // .as_str(), ]) } } #[derive(Debug, PartialEq, Default, Clone)] -struct CompletionItem { - item: lsp::CompletionItem, - resolved: bool, +pub struct CompletionItem { + pub item: lsp::CompletionItem, + pub language_server_id: usize, + pub offset_encoding: OffsetEncoding, + pub resolved: bool, } /// Wraps a Menu. @@ -109,21 +107,13 @@ impl Completion { pub fn new( editor: &Editor, savepoint: Arc, - mut items: Vec, - offset_encoding: helix_lsp::OffsetEncoding, + mut items: Vec, start_offset: usize, trigger_offset: usize, ) -> Self { let replace_mode = editor.config().completion_replace; // Sort completion items according to their preselect status (given by the LSP server) - items.sort_by_key(|item| !item.preselect.unwrap_or(false)); - let items = items - .into_iter() - .map(|item| CompletionItem { - item, - resolved: false, - }) - .collect(); + items.sort_by_key(|item| !item.item.preselect.unwrap_or(false)); // Then create the menu let menu = Menu::new(items, (), move |editor: &mut Editor, item, event| { @@ -131,7 +121,6 @@ impl Completion { doc: &Document, view_id: ViewId, item: &CompletionItem, - offset_encoding: helix_lsp::OffsetEncoding, trigger_offset: usize, include_placeholder: bool, replace_mode: bool, @@ -154,6 +143,8 @@ impl Completion { } }; + let offset_encoding = item.offset_encoding; + let Some(range) = util::lsp_range_to_range(doc.text(), edit.range, offset_encoding) else{ return Transaction::new(doc.text()); }; @@ -247,15 +238,8 @@ impl Completion { // always present here let item = item.unwrap(); - let transaction = item_to_transaction( - doc, - view.id, - item, - offset_encoding, - trigger_offset, - true, - replace_mode, - ); + let transaction = + item_to_transaction(doc, view.id, item, trigger_offset, true, replace_mode); doc.apply_temporary(&transaction, view.id); } PromptEvent::Validate => { @@ -267,10 +251,15 @@ impl Completion { // always present here let mut item = item.unwrap().clone(); + let language_server = editor + .language_servers + .get_by_id(item.language_server_id) + .unwrap(); + // resolve item if not yet resolved if !item.resolved { if let Some(resolved) = - Self::resolve_completion_item(doc, item.item.clone()) + Self::resolve_completion_item(language_server, item.item.clone()) { item.item = resolved; } @@ -281,7 +270,6 @@ impl Completion { doc, view.id, &item, - offset_encoding, trigger_offset, false, replace_mode, @@ -299,7 +287,7 @@ impl Completion { let transaction = util::generate_transaction_from_edits( doc.text(), additional_edits, - offset_encoding, // TODO: should probably transcode in Client + item.offset_encoding, // TODO: should probably transcode in Client ); doc.apply(&transaction, view.id); } @@ -323,10 +311,17 @@ impl Completion { } fn resolve_completion_item( - doc: &Document, + language_server: &helix_lsp::Client, completion_item: lsp::CompletionItem, ) -> Option { - let language_server = doc.language_server()?; + let completion_resolve_provider = language_server + .capabilities() + .completion_provider + .as_ref()? + .resolve_provider; + if completion_resolve_provider != Some(true) { + return None; + } let future = language_server.resolve_completion_item(completion_item)?; let response = helix_lsp::block_on(future); @@ -397,8 +392,11 @@ impl Completion { Some(item) if !item.resolved => item.clone(), _ => return false, }; - - let language_server = match doc!(cx.editor).language_server() { + let language_server = match cx + .editor + .language_servers + .get_by_id(current_item.language_server_id) + { Some(language_server) => language_server, None => return false, }; @@ -422,13 +420,14 @@ impl Completion { .unwrap() .completion { - completion.replace_item( - current_item, - CompletionItem { - item: resolved_item, - resolved: true, - }, - ); + let resolved_item = CompletionItem { + item: resolved_item, + language_server_id: current_item.language_server_id, + offset_encoding: current_item.offset_encoding, + resolved: true, + }; + + completion.replace_item(current_item, resolved_item); } }, ); diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index f0989fa88..43b5d1af6 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -33,7 +33,7 @@ use std::{mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc, sync::Arc}; use tui::{buffer::Buffer as Surface, text::Span}; -use super::statusline; +use super::{completion::CompletionItem, statusline}; use super::{document::LineDecoration, lsp::SignatureHelp}; pub struct EditorView { @@ -650,7 +650,7 @@ impl EditorView { .primary() .cursor(doc.text().slice(..)); - let diagnostics = doc.diagnostics().iter().filter(|diagnostic| { + let diagnostics = doc.shown_diagnostics().filter(|diagnostic| { diagnostic.range.start <= cursor && diagnostic.range.end >= cursor }); @@ -953,20 +953,13 @@ impl EditorView { &mut self, editor: &mut Editor, savepoint: Arc, - items: Vec, - offset_encoding: helix_lsp::OffsetEncoding, + items: Vec, start_offset: usize, trigger_offset: usize, size: Rect, ) -> Option { - let mut completion = Completion::new( - editor, - savepoint, - items, - offset_encoding, - start_offset, - trigger_offset, - ); + let mut completion = + Completion::new(editor, savepoint, items, start_offset, trigger_offset); if completion.is_empty() { // skip if we got no completion results diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 3e9a14b06..118836c0f 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -17,7 +17,7 @@ mod text; use crate::compositor::{Component, Compositor}; use crate::filter_picker_entry; use crate::job::{self, Callback}; -pub use completion::Completion; +pub use completion::{Completion, CompletionItem}; pub use editor::EditorView; pub use markdown::Markdown; pub use menu::Menu; @@ -238,6 +238,7 @@ pub mod completers { use crate::ui::prompt::Completion; use fuzzy_matcher::skim::SkimMatcherV2 as Matcher; use fuzzy_matcher::FuzzyMatcher; + use helix_core::syntax::LanguageServerFeature; use helix_view::document::SCRATCH_BUFFER_NAME; use helix_view::theme; use helix_view::{editor::Config, Editor}; @@ -393,17 +394,13 @@ pub mod completers { pub fn lsp_workspace_command(editor: &Editor, input: &str) -> Vec { let matcher = Matcher::default(); - let (_, doc) = current_ref!(editor); - - let language_server = match doc.language_server() { - Some(language_server) => language_server, - None => { - return vec![]; - } - }; - - let options = match &language_server.capabilities().execute_command_provider { - Some(options) => options, + let language_servers = + doc!(editor).language_servers_with_feature(LanguageServerFeature::WorkspaceCommand); + let options = match language_servers + .into_iter() + .find_map(|ls| ls.capabilities().execute_command_provider.as_ref()) + { + Some(id_options) => id_options, None => { return vec![]; } diff --git a/helix-term/src/ui/statusline.rs b/helix-term/src/ui/statusline.rs index 887863519..b10e8076d 100644 --- a/helix-term/src/ui/statusline.rs +++ b/helix-term/src/ui/statusline.rs @@ -197,15 +197,16 @@ where ); } +// TODO think about handling multiple language servers fn render_lsp_spinner(context: &mut RenderContext, write: F) where F: Fn(&mut RenderContext, String, Option