From cce19713fb970df1a96be7e76e3217e4e50efc42 Mon Sep 17 00:00:00 2001 From: gavynriebau Date: Mon, 16 Jan 2023 15:13:48 +0800 Subject: [PATCH 001/342] Fix for lost clipboard contents (#5424) (#5426) * Fix for lost clipboard contents (#5424) * PR feedback: Call "setsid" for all unix systems * PR Feedback: Only install libc for unix targets --- Cargo.lock | 1 + helix-view/Cargo.toml | 3 +++ helix-view/src/clipboard.rs | 21 ++++++++++++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 69ba8444..ede4ae0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1274,6 +1274,7 @@ dependencies = [ "helix-lsp", "helix-tui", "helix-vcs", + "libc", "log", "once_cell", "serde", diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index e7a20496..7d130317 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -48,5 +48,8 @@ which = "4.2" [target.'cfg(windows)'.dependencies] clipboard-win = { version = "4.5", features = ["std"] } +[target.'cfg(unix)'.dependencies] +libc = "0.2" + [dev-dependencies] helix-tui = { path = "../helix-tui" } diff --git a/helix-view/src/clipboard.rs b/helix-view/src/clipboard.rs index 4f83fb4d..3c620c14 100644 --- a/helix-view/src/clipboard.rs +++ b/helix-view/src/clipboard.rs @@ -276,12 +276,27 @@ pub mod provider { let stdin = input.map(|_| Stdio::piped()).unwrap_or_else(Stdio::null); let stdout = pipe_output.then(Stdio::piped).unwrap_or_else(Stdio::null); - let mut child = Command::new(self.prg) + let mut command: Command = Command::new(self.prg); + + let mut command_mut: &mut Command = command .args(self.args) .stdin(stdin) .stdout(stdout) - .stderr(Stdio::null()) - .spawn()?; + .stderr(Stdio::null()); + + // Fix for https://github.com/helix-editor/helix/issues/5424 + if cfg!(unix) { + use std::os::unix::process::CommandExt; + + unsafe { + command_mut = command_mut.pre_exec(|| match libc::setsid() { + -1 => Err(std::io::Error::last_os_error()), + _ => Ok(()), + }); + } + } + + let mut child = command_mut.spawn()?; if let Some(input) = input { let mut stdin = child.stdin.take().context("stdin is missing")?; From d3e0f18c89c94c887d50d2487a4ee76eb96dda2b Mon Sep 17 00:00:00 2001 From: Itay123 <40892795+Itay123TheKing@users.noreply.github.com> Date: Mon, 16 Jan 2023 09:18:13 +0200 Subject: [PATCH 002/342] Added opening files in the background with A-ret shortcut (#4435) --- helix-term/src/ui/picker.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index aad3f81c..eb935e56 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -1,4 +1,5 @@ use crate::{ + alt, compositor::{Component, Compositor, Context, Event, EventResult}, ctrl, key, shift, ui::{self, fuzzy_match::FuzzyQuery, EditorView}, @@ -619,6 +620,11 @@ impl Component for Picker { key!(Esc) | ctrl!('c') => { return close_fn; } + alt!(Enter) => { + if let Some(option) = self.selection() { + (self.callback_fn)(cx, option, Action::Load); + } + } key!(Enter) => { if let Some(option) = self.selection() { (self.callback_fn)(cx, option, Action::Replace); From 6f6334f3c65f66f72867e6500b3c4a76ed017dfe Mon Sep 17 00:00:00 2001 From: eugene yokota Date: Mon, 16 Jan 2023 10:48:17 -0500 Subject: [PATCH 003/342] highlight(scala): update the Scala highlight queries (#5546) There have been a lot of changes in tree-sitter/tree-sitter-scala, including partial support for Scala 3 syntax and breaking changes in some of the nodes. This bumps up the grammar to the latest, and adjusts the queries. Co-authored-by: Anton Sviridov Co-authored-by: Chris Kipp --- languages.toml | 2 +- runtime/queries/scala/highlights.scm | 129 ++++++++++++++++++++------- 2 files changed, 100 insertions(+), 31 deletions(-) diff --git a/languages.toml b/languages.toml index 51b4efb2..6d016902 100644 --- a/languages.toml +++ b/languages.toml @@ -1064,7 +1064,7 @@ language-server = { command = "metals" } [[grammar]] name = "scala" -source = { git = "https://github.com/tree-sitter/tree-sitter-scala", rev = "140c96cf398693189d4e50f76d19ddfcd8a018f8" } +source = { git = "https://github.com/tree-sitter/tree-sitter-scala", rev = "db1c8c23d7996476a791db85a0d292084c19c232" } [[language]] name = "dockerfile" diff --git a/runtime/queries/scala/highlights.scm b/runtime/queries/scala/highlights.scm index 50a6e18a..07307875 100644 --- a/runtime/queries/scala/highlights.scm +++ b/runtime/queries/scala/highlights.scm @@ -33,6 +33,26 @@ (type_definition name: (type_identifier) @type) +(full_enum_case + name: (identifier) @type) + +(simple_enum_case + name: (identifier) @type) + +;; val/var definitions/declarations + +(val_definition + pattern: (identifier) @variable) + +(var_definition + pattern: (identifier) @variable) + +(val_declaration + name: (identifier) @variable) + +(var_declaration + name: (identifier) @variable) + ; method definition (class_definition @@ -48,7 +68,7 @@ (function_definition name: (identifier) @function.method))) -; imports +; imports/exports (import_declaration path: (identifier) @namespace) @@ -58,7 +78,15 @@ path: (identifier) @type) (#match? @type "^[A-Z]")) ((stable_identifier (identifier) @type) (#match? @type "^[A-Z]")) -((import_selectors (identifier) @type) (#match? @type "^[A-Z]")) +(export_declaration + path: (identifier) @namespace) +((stable_identifier (identifier) @namespace)) + +((export_declaration + path: (identifier) @type) (#match? @type "^[A-Z]")) +((stable_identifier (identifier) @type) (#match? @type "^[A-Z]")) + +((namespace_selectors (identifier) @type) (#match? @type "^[A-Z]")) ; method invocation @@ -66,10 +94,17 @@ (call_expression function: (identifier) @function) +(call_expression + function: (operator_identifier) @function) + (call_expression function: (field_expression field: (identifier) @function.method)) +(call_expression + function: (field_expression + field: (operator_identifier) @function.method)) + ((call_expression function: (identifier) @variable.other.member) (#match? @variable.other.member "^[A-Z]")) @@ -87,9 +122,15 @@ (function_definition name: (identifier) @function) +(function_definition + name: (operator_identifier) @function) + (parameter name: (identifier) @variable.parameter) +(binding + name: (identifier) @variable.parameter) + ; expressions @@ -109,7 +150,7 @@ (symbol_literal) @string.special.symbol - + [ (string) (character_literal) @@ -118,29 +159,50 @@ (interpolation "$" @punctuation.special) +; annotations + +(annotation) @attribute + ;; keywords +;; storage in TextMate scope lingo means field or type [ + (opaque_modifier) + (infix_modifier) + (transparent_modifier) + (open_modifier) "abstract" - "case" - "class" - "extends" "final" - "finally" -;; `forSome` existential types not implemented yet "implicit" "lazy" -;; `macro` not implemented yet - "object" "override" - "package" "private" "protected" "sealed" +] @keyword.storage.modifier + +[ + "class" + "enum" + "extension" + "given" + "object" + "package" "trait" "type" "val" "var" +] @keyword.storage.type + +[ + "as" + "derives" + "end" + "extends" +;; `forSome` existential types not implemented yet +;; `macro` not implemented yet +;; `throws` + "using" "with" ] @keyword @@ -152,33 +214,36 @@ "new" @keyword.operator [ - "else" - "if" - "match" - "try" - "catch" - "throw" + "case" + "catch" + "else" + "finally" + "if" + "match" + "then" + "throw" + "try" ] @keyword.control.conditional [ - "(" - ")" - "[" - "]" - "{" - "}" + "(" + ")" + "[" + "]" + "{" + "}" ] @punctuation.bracket [ - "." - "," + "." + "," ] @punctuation.delimiter [ - "do" - "for" - "while" - "yield" + "do" + "for" + "while" + "yield" ] @keyword.control.repeat "def" @keyword.function @@ -191,6 +256,8 @@ "import" @keyword.control.import +"export" @keyword.control.import + "return" @keyword.control.return (comment) @comment @@ -200,4 +267,6 @@ (case_block (case_clause ("case") @keyword.control.conditional)) -(identifier) @variable \ No newline at end of file +(identifier) @variable + +(operator_identifier) @operator From 425d7e5f1b67d2c1748b4b30091d88d1446aecc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Delafargue?= Date: Mon, 16 Jan 2023 11:13:03 +0100 Subject: [PATCH 004/342] doc: add a note about nested bindings in key remapping It was not clear (to me) that minor modes were configurable in the keymap configuration. --- book/src/remapping.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/book/src/remapping.md b/book/src/remapping.md index e89c6611..2eac8846 100644 --- a/book/src/remapping.md +++ b/book/src/remapping.md @@ -25,6 +25,9 @@ j = { k = "normal_mode" } # Maps `jk` to exit insert mode ``` > NOTE: Typable commands can also be remapped, remember to keep the `:` prefix to indicate it's a typable command. +> NOTE: Bindings can be nested, to create (or edit) minor modes: `g = { a = "code_action"}` adds a new entry to +> the `goto` mode. + Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes `C-`, `S-` and `A-`. Special keys are encoded as follows: From 7bdba4a6bff99a89c0256889222f7bba5bfb1130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Delafargue?= Date: Mon, 16 Jan 2023 16:30:35 +0100 Subject: [PATCH 005/342] doc: add missing `whitespace.render` sub-key --- 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 a35482e6..f89ef5ae 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -216,7 +216,7 @@ Options for rendering whitespace with visible characters. Use `:set whitespace.r | Key | Description | Default | |-----|-------------|---------| -| `render` | Whether to render whitespace. May either be `"all"` or `"none"`, or a table with sub-keys `space`, `tab`, and `newline`. | `"none"` | +| `render` | Whether to render whitespace. May either be `"all"` or `"none"`, or a table with sub-keys `space`, `nbsp`, `tab`, and `newline`. | `"none"` | | `characters` | Literal characters to use when rendering whitespace. Sub-keys may be any of `tab`, `space`, `nbsp`, `newline` or `tabpad` | See example below | Example From 97083f88364e1455f42023dadadfb410fd476505 Mon Sep 17 00:00:00 2001 From: Ayoub Benali Date: Mon, 16 Jan 2023 17:03:03 +0100 Subject: [PATCH 006/342] Enable http server by default in Metals config (#5551) This is required to make commands like [doctor-run](https://scalameta.org/metals/docs/integrations/new-editor#run-doctor) work. It simply opens a browser to get general information about the build. Co-authored-by: Ayoub Benali --- languages.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 6d016902..a66605b2 100644 --- a/languages.toml +++ b/languages.toml @@ -1061,6 +1061,7 @@ file-types = ["scala", "sbt", "sc"] comment-token = "//" indent = { tab-width = 2, unit = " " } language-server = { command = "metals" } +config = { "isHttpEnabled" = true } [[grammar]] name = "scala" @@ -2106,4 +2107,4 @@ formatter = { command = "dhall" , args = ["format"] } [[grammar]] name = "dhall" -source = { git = "https://github.com/jbellerb/tree-sitter-dhall", rev = "affb6ee38d629c9296749767ab832d69bb0d9ea8" } \ No newline at end of file +source = { git = "https://github.com/jbellerb/tree-sitter-dhall", rev = "affb6ee38d629c9296749767ab832d69bb0d9ea8" } From 60f84be40c1c488dacf823f791ca33f43b5d28d8 Mon Sep 17 00:00:00 2001 From: greg-enbala <66078183+greg-enbala@users.noreply.github.com> Date: Mon, 16 Jan 2023 11:15:23 -0500 Subject: [PATCH 007/342] Separate jump behavior from increment/decrement (#4123) increment/decrement (C-a/C-x) had some buggy behavior where selections could be offset incorrectly or the editor could panic with some edits that changed the number of characters in a number or date. These stemmed from the automatic jumping behavior which attempted to find the next date or integer to increment. The jumping behavior also complicated the code quite a bit and made the behavior somewhat difficult to predict when using many cursors. This change removes the automatic jumping behavior and only increments or decrements when the full text in a range of a selection is a number or date. This simplifies the code and fixes the panics and buggy behaviors from changing the number of characters. --- helix-core/src/increment/date_time.rs | 321 ++++------------ helix-core/src/increment/integer.rs | 235 ++++++++++++ helix-core/src/increment/mod.rs | 12 +- helix-core/src/increment/number.rs | 507 -------------------------- helix-term/src/commands.rs | 113 ++---- 5 files changed, 349 insertions(+), 839 deletions(-) create mode 100644 helix-core/src/increment/integer.rs delete mode 100644 helix-core/src/increment/number.rs diff --git a/helix-core/src/increment/date_time.rs b/helix-core/src/increment/date_time.rs index 265242ce..2980bb58 100644 --- a/helix-core/src/increment/date_time.rs +++ b/helix-core/src/increment/date_time.rs @@ -1,114 +1,53 @@ -use chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; +use chrono::{Duration, NaiveDate, NaiveDateTime, NaiveTime}; use once_cell::sync::Lazy; use regex::Regex; -use ropey::RopeSlice; - -use std::borrow::Cow; -use std::cmp; use std::fmt::Write; -use super::Increment; -use crate::{Range, Tendril}; +/// Increment a Date or DateTime +/// +/// If just a Date is selected the day will be incremented. +/// If a DateTime is selected the second will be incremented. +pub fn increment(selected_text: &str, amount: i64) -> Option { + if selected_text.is_empty() { + return None; + } -#[derive(Debug, PartialEq, Eq)] -pub struct DateTimeIncrementor { - date_time: NaiveDateTime, - range: Range, - fmt: &'static str, - field: DateField, -} + FORMATS.iter().find_map(|format| { + let captures = format.regex.captures(selected_text)?; + if captures.len() - 1 != format.fields.len() { + return None; + } -impl DateTimeIncrementor { - pub fn from_range(text: RopeSlice, range: Range) -> Option { - let range = if range.is_empty() { - if range.anchor < text.len_chars() { - // Treat empty range as a cursor range. - range.put_cursor(text, range.anchor + 1, true) - } else { - // The range is empty and at the end of the text. - return None; + let date_time = captures.get(0)?; + let has_date = format.fields.iter().any(|f| f.unit.is_date()); + let has_time = format.fields.iter().any(|f| f.unit.is_time()); + let date_time = &selected_text[date_time.start()..date_time.end()]; + match (has_date, has_time) { + (true, true) => { + let date_time = NaiveDateTime::parse_from_str(date_time, format.fmt).ok()?; + Some( + date_time + .checked_add_signed(Duration::minutes(amount))? + .format(format.fmt) + .to_string(), + ) } - } else { - range - }; - - FORMATS.iter().find_map(|format| { - let from = range.from().saturating_sub(format.max_len); - let to = (range.from() + format.max_len).min(text.len_chars()); - - let (from_in_text, to_in_text) = (range.from() - from, range.to() - from); - let text: Cow = text.slice(from..to).into(); - - let captures = format.regex.captures(&text)?; - if captures.len() - 1 != format.fields.len() { - return None; + (true, false) => { + let date = NaiveDate::parse_from_str(date_time, format.fmt).ok()?; + Some( + date.checked_add_signed(Duration::days(amount))? + .format(format.fmt) + .to_string(), + ) } - - let date_time = captures.get(0)?; - let offset = range.from() - from_in_text; - let range = Range::new(date_time.start() + offset, date_time.end() + offset); - - let field = captures - .iter() - .skip(1) - .enumerate() - .find_map(|(i, capture)| { - let capture = capture?; - let capture_range = capture.range(); - - if capture_range.contains(&from_in_text) - && capture_range.contains(&(to_in_text - 1)) - { - Some(format.fields[i]) - } else { - None - } - })?; - - let has_date = format.fields.iter().any(|f| f.unit.is_date()); - let has_time = format.fields.iter().any(|f| f.unit.is_time()); - - let date_time = &text[date_time.start()..date_time.end()]; - let date_time = match (has_date, has_time) { - (true, true) => NaiveDateTime::parse_from_str(date_time, format.fmt).ok()?, - (true, false) => { - let date = NaiveDate::parse_from_str(date_time, format.fmt).ok()?; - - date.and_hms_opt(0, 0, 0).unwrap() - } - (false, true) => { - let time = NaiveTime::parse_from_str(date_time, format.fmt).ok()?; - - NaiveDate::from_ymd_opt(0, 1, 1).unwrap().and_time(time) - } - (false, false) => return None, - }; - - Some(DateTimeIncrementor { - date_time, - range, - fmt: format.fmt, - field, - }) - }) - } -} - -impl Increment for DateTimeIncrementor { - fn increment(&self, amount: i64) -> (Range, Tendril) { - let date_time = match self.field.unit { - DateUnit::Years => add_years(self.date_time, amount), - DateUnit::Months => add_months(self.date_time, amount), - DateUnit::Days => add_duration(self.date_time, Duration::days(amount)), - DateUnit::Hours => add_duration(self.date_time, Duration::hours(amount)), - DateUnit::Minutes => add_duration(self.date_time, Duration::minutes(amount)), - DateUnit::Seconds => add_duration(self.date_time, Duration::seconds(amount)), - DateUnit::AmPm => toggle_am_pm(self.date_time), + (false, true) => { + let time = NaiveTime::parse_from_str(date_time, format.fmt).ok()?; + let (adjusted_time, _) = time.overflowing_add_signed(Duration::minutes(amount)); + Some(adjusted_time.format(format.fmt).to_string()) + } + (false, false) => None, } - .unwrap_or(self.date_time); - - (self.range, date_time.format(self.fmt).to_string().into()) - } + }) } static FORMATS: Lazy> = Lazy::new(|| { @@ -144,7 +83,7 @@ impl Format { fn new(fmt: &'static str) -> Self { let mut remaining = fmt; let mut fields = Vec::new(); - let mut regex = String::new(); + let mut regex = "^".to_string(); let mut max_len = 0; while let Some(i) = remaining.find('%') { @@ -166,6 +105,7 @@ impl Format { write!(regex, "({})", field.regex).unwrap(); remaining = &after[spec_len..]; } + regex += "$"; let regex = Regex::new(®ex).unwrap(); @@ -305,155 +245,47 @@ impl DateUnit { } } -fn ndays_in_month(year: i32, month: u32) -> u32 { - // The first day of the next month... - let (y, m) = if month == 12 { - (year + 1, 1) - } else { - (year, month + 1) - }; - let d = NaiveDate::from_ymd_opt(y, m, 1).unwrap(); - - // ...is preceded by the last day of the original month. - d.pred_opt().unwrap().day() -} - -fn add_months(date_time: NaiveDateTime, amount: i64) -> Option { - let month = (date_time.month0() as i64).checked_add(amount)?; - let year = date_time.year() + i32::try_from(month / 12).ok()?; - let year = if month.is_negative() { year - 1 } else { year }; - - // Normalize month - let month = month % 12; - let month = if month.is_negative() { - month + 12 - } else { - month - } as u32 - + 1; - - let day = cmp::min(date_time.day(), ndays_in_month(year, month)); - - NaiveDate::from_ymd_opt(year, month, day).map(|date| date.and_time(date_time.time())) -} - -fn add_years(date_time: NaiveDateTime, amount: i64) -> Option { - let year = i32::try_from((date_time.year() as i64).checked_add(amount)?).ok()?; - let ndays = ndays_in_month(year, date_time.month()); - - if date_time.day() > ndays { - NaiveDate::from_ymd_opt(year, date_time.month(), ndays) - .and_then(|date| date.succ_opt().map(|date| date.and_time(date_time.time()))) - } else { - date_time.with_year(year) - } -} - -fn add_duration(date_time: NaiveDateTime, duration: Duration) -> Option { - date_time.checked_add_signed(duration) -} - -fn toggle_am_pm(date_time: NaiveDateTime) -> Option { - if date_time.hour() < 12 { - add_duration(date_time, Duration::hours(12)) - } else { - add_duration(date_time, Duration::hours(-12)) - } -} - #[cfg(test)] mod test { use super::*; - use crate::Rope; #[test] fn test_increment_date_times() { let tests = [ // (original, cursor, amount, expected) - ("2020-02-28", 0, 1, "2021-02-28"), - ("2020-02-29", 0, 1, "2021-03-01"), - ("2020-01-31", 5, 1, "2020-02-29"), - ("2020-01-20", 5, 1, "2020-02-20"), - ("2021-01-01", 5, -1, "2020-12-01"), - ("2021-01-31", 5, -2, "2020-11-30"), - ("2020-02-28", 8, 1, "2020-02-29"), - ("2021-02-28", 8, 1, "2021-03-01"), - ("2021-02-28", 0, -1, "2020-02-28"), - ("2021-03-01", 0, -1, "2020-03-01"), - ("2020-02-29", 5, -1, "2020-01-29"), - ("2020-02-20", 5, -1, "2020-01-20"), - ("2020-02-29", 8, -1, "2020-02-28"), - ("2021-03-01", 8, -1, "2021-02-28"), - ("1980/12/21", 8, 100, "1981/03/31"), - ("1980/12/21", 8, -100, "1980/09/12"), - ("1980/12/21", 8, 1000, "1983/09/17"), - ("1980/12/21", 8, -1000, "1978/03/27"), - ("2021-11-24 07:12:23", 0, 1, "2022-11-24 07:12:23"), - ("2021-11-24 07:12:23", 5, 1, "2021-12-24 07:12:23"), - ("2021-11-24 07:12:23", 8, 1, "2021-11-25 07:12:23"), - ("2021-11-24 07:12:23", 11, 1, "2021-11-24 08:12:23"), - ("2021-11-24 07:12:23", 14, 1, "2021-11-24 07:13:23"), - ("2021-11-24 07:12:23", 17, 1, "2021-11-24 07:12:24"), - ("2021/11/24 07:12:23", 0, 1, "2022/11/24 07:12:23"), - ("2021/11/24 07:12:23", 5, 1, "2021/12/24 07:12:23"), - ("2021/11/24 07:12:23", 8, 1, "2021/11/25 07:12:23"), - ("2021/11/24 07:12:23", 11, 1, "2021/11/24 08:12:23"), - ("2021/11/24 07:12:23", 14, 1, "2021/11/24 07:13:23"), - ("2021/11/24 07:12:23", 17, 1, "2021/11/24 07:12:24"), - ("2021-11-24 07:12", 0, 1, "2022-11-24 07:12"), - ("2021-11-24 07:12", 5, 1, "2021-12-24 07:12"), - ("2021-11-24 07:12", 8, 1, "2021-11-25 07:12"), - ("2021-11-24 07:12", 11, 1, "2021-11-24 08:12"), - ("2021-11-24 07:12", 14, 1, "2021-11-24 07:13"), - ("2021/11/24 07:12", 0, 1, "2022/11/24 07:12"), - ("2021/11/24 07:12", 5, 1, "2021/12/24 07:12"), - ("2021/11/24 07:12", 8, 1, "2021/11/25 07:12"), - ("2021/11/24 07:12", 11, 1, "2021/11/24 08:12"), - ("2021/11/24 07:12", 14, 1, "2021/11/24 07:13"), - ("Wed Nov 24 2021", 0, 1, "Thu Nov 25 2021"), - ("Wed Nov 24 2021", 4, 1, "Fri Dec 24 2021"), - ("Wed Nov 24 2021", 8, 1, "Thu Nov 25 2021"), - ("Wed Nov 24 2021", 11, 1, "Thu Nov 24 2022"), - ("24-Nov-2021", 0, 1, "25-Nov-2021"), - ("24-Nov-2021", 3, 1, "24-Dec-2021"), - ("24-Nov-2021", 7, 1, "24-Nov-2022"), - ("2021 Nov 24", 0, 1, "2022 Nov 24"), - ("2021 Nov 24", 5, 1, "2021 Dec 24"), - ("2021 Nov 24", 9, 1, "2021 Nov 25"), - ("Nov 24, 2021", 0, 1, "Dec 24, 2021"), - ("Nov 24, 2021", 4, 1, "Nov 25, 2021"), - ("Nov 24, 2021", 8, 1, "Nov 24, 2022"), - ("7:21:53 am", 0, 1, "8:21:53 am"), - ("7:21:53 am", 3, 1, "7:22:53 am"), - ("7:21:53 am", 5, 1, "7:21:54 am"), - ("7:21:53 am", 8, 1, "7:21:53 pm"), - ("7:21:53 AM", 0, 1, "8:21:53 AM"), - ("7:21:53 AM", 3, 1, "7:22:53 AM"), - ("7:21:53 AM", 5, 1, "7:21:54 AM"), - ("7:21:53 AM", 8, 1, "7:21:53 PM"), - ("7:21 am", 0, 1, "8:21 am"), - ("7:21 am", 3, 1, "7:22 am"), - ("7:21 am", 5, 1, "7:21 pm"), - ("7:21 AM", 0, 1, "8:21 AM"), - ("7:21 AM", 3, 1, "7:22 AM"), - ("7:21 AM", 5, 1, "7:21 PM"), - ("23:24:23", 1, 1, "00:24:23"), - ("23:24:23", 3, 1, "23:25:23"), - ("23:24:23", 6, 1, "23:24:24"), - ("23:24", 1, 1, "00:24"), - ("23:24", 3, 1, "23:25"), + ("2020-02-28", 1, "2020-02-29"), + ("2020-02-29", 1, "2020-03-01"), + ("2020-01-31", 1, "2020-02-01"), + ("2020-01-20", 1, "2020-01-21"), + ("2021-01-01", -1, "2020-12-31"), + ("2021-01-31", -2, "2021-01-29"), + ("2020-02-28", 1, "2020-02-29"), + ("2021-02-28", 1, "2021-03-01"), + ("2021-03-01", -1, "2021-02-28"), + ("2020-02-29", -1, "2020-02-28"), + ("2020-02-20", -1, "2020-02-19"), + ("2021-03-01", -1, "2021-02-28"), + ("1980/12/21", 100, "1981/03/31"), + ("1980/12/21", -100, "1980/09/12"), + ("1980/12/21", 1000, "1983/09/17"), + ("1980/12/21", -1000, "1978/03/27"), + ("2021-11-24 07:12:23", 1, "2021-11-24 07:13:23"), + ("2021-11-24 07:12", 1, "2021-11-24 07:13"), + ("Wed Nov 24 2021", 1, "Thu Nov 25 2021"), + ("24-Nov-2021", 1, "25-Nov-2021"), + ("2021 Nov 24", 1, "2021 Nov 25"), + ("Nov 24, 2021", 1, "Nov 25, 2021"), + ("7:21:53 am", 1, "7:22:53 am"), + ("7:21:53 AM", 1, "7:22:53 AM"), + ("7:21 am", 1, "7:22 am"), + ("23:24:23", 1, "23:25:23"), + ("23:24", 1, "23:25"), + ("23:59", 1, "00:00"), + ("23:59:59", 1, "00:00:59"), ]; - for (original, cursor, amount, expected) in tests { - let rope = Rope::from_str(original); - let range = Range::new(cursor, cursor + 1); - assert_eq!( - DateTimeIncrementor::from_range(rope.slice(..), range) - .unwrap() - .increment(amount) - .1, - Tendril::from(expected) - ); + for (original, amount, expected) in tests { + assert_eq!(increment(original, amount).unwrap(), expected); } } @@ -482,10 +314,7 @@ mod test { ]; for invalid in tests { - let rope = Rope::from_str(invalid); - let range = Range::new(0, 1); - - assert_eq!(DateTimeIncrementor::from_range(rope.slice(..), range), None) + assert_eq!(increment(invalid, 1), None) } } } diff --git a/helix-core/src/increment/integer.rs b/helix-core/src/increment/integer.rs new file mode 100644 index 00000000..30803e17 --- /dev/null +++ b/helix-core/src/increment/integer.rs @@ -0,0 +1,235 @@ +const SEPARATOR: char = '_'; + +/// Increment an integer. +/// +/// Supported bases: +/// 2 with prefix 0b +/// 8 with prefix 0o +/// 10 with no prefix +/// 16 with prefix 0x +/// +/// An integer can contain `_` as a separator but may not start or end with a separator. +/// Base 10 integers can go negative, but bases 2, 8, and 16 cannot. +/// All addition and subtraction is saturating. +pub fn increment(selected_text: &str, amount: i64) -> Option { + if selected_text.is_empty() + || selected_text.ends_with(SEPARATOR) + || selected_text.starts_with(SEPARATOR) + { + return None; + } + + let radix = if selected_text.starts_with("0x") { + 16 + } else if selected_text.starts_with("0o") { + 8 + } else if selected_text.starts_with("0b") { + 2 + } else { + 10 + }; + + // Get separator indexes from right to left. + let separator_rtl_indexes: Vec = selected_text + .chars() + .rev() + .enumerate() + .filter_map(|(i, c)| if c == SEPARATOR { Some(i) } else { None }) + .collect(); + + let word: String = selected_text.chars().filter(|&c| c != SEPARATOR).collect(); + + let mut new_text = if radix == 10 { + let number = &word; + let value = i128::from_str_radix(number, radix).ok()?; + let new_value = value.saturating_add(amount as i128); + + let format_length = match (value.is_negative(), new_value.is_negative()) { + (true, false) => number.len() - 1, + (false, true) => number.len() + 1, + _ => number.len(), + } - separator_rtl_indexes.len(); + + if number.starts_with('0') || number.starts_with("-0") { + format!("{:01$}", new_value, format_length) + } else { + format!("{}", new_value) + } + } else { + let number = &word[2..]; + let value = u128::from_str_radix(number, radix).ok()?; + let new_value = (value as i128).saturating_add(amount as i128); + let new_value = if new_value < 0 { 0 } else { new_value }; + let format_length = selected_text.len() - 2 - separator_rtl_indexes.len(); + + match radix { + 2 => format!("0b{:01$b}", new_value, format_length), + 8 => format!("0o{:01$o}", new_value, format_length), + 16 => { + let (lower_count, upper_count): (usize, usize) = + number.chars().fold((0, 0), |(lower, upper), c| { + ( + lower + c.is_ascii_lowercase().then(|| 1).unwrap_or(0), + upper + c.is_ascii_uppercase().then(|| 1).unwrap_or(0), + ) + }); + if upper_count > lower_count { + format!("0x{:01$X}", new_value, format_length) + } else { + format!("0x{:01$x}", new_value, format_length) + } + } + _ => unimplemented!("radix not supported: {}", radix), + } + }; + + // Add separators from original number. + for &rtl_index in &separator_rtl_indexes { + if rtl_index < new_text.len() { + let new_index = new_text.len().saturating_sub(rtl_index); + if new_index > 0 { + new_text.insert(new_index, SEPARATOR); + } + } + } + + // Add in additional separators if necessary. + if new_text.len() > selected_text.len() && !separator_rtl_indexes.is_empty() { + let spacing = match separator_rtl_indexes.as_slice() { + [.., b, a] => a - b - 1, + _ => separator_rtl_indexes[0], + }; + + let prefix_length = if radix == 10 { 0 } else { 2 }; + if let Some(mut index) = new_text.find(SEPARATOR) { + while index - prefix_length > spacing { + index -= spacing; + new_text.insert(index, SEPARATOR); + } + } + } + + Some(new_text) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_increment_basic_decimal_numbers() { + let tests = [ + ("100", 1, "101"), + ("100", -1, "99"), + ("99", 1, "100"), + ("100", 1000, "1100"), + ("100", -1000, "-900"), + ("-1", 1, "0"), + ("-1", 2, "1"), + ("1", -1, "0"), + ("1", -2, "-1"), + ]; + + for (original, amount, expected) in tests { + assert_eq!(increment(original, amount).unwrap(), expected); + } + } + + #[test] + fn test_increment_basic_hexadecimal_numbers() { + let tests = [ + ("0x0100", 1, "0x0101"), + ("0x0100", -1, "0x00ff"), + ("0x0001", -1, "0x0000"), + ("0x0000", -1, "0x0000"), + ("0xffffffffffffffff", 1, "0x10000000000000000"), + ("0xffffffffffffffff", 2, "0x10000000000000001"), + ("0xffffffffffffffff", -1, "0xfffffffffffffffe"), + ("0xABCDEF1234567890", 1, "0xABCDEF1234567891"), + ("0xabcdef1234567890", 1, "0xabcdef1234567891"), + ]; + + for (original, amount, expected) in tests { + assert_eq!(increment(original, amount).unwrap(), expected); + } + } + + #[test] + fn test_increment_basic_octal_numbers() { + let tests = [ + ("0o0107", 1, "0o0110"), + ("0o0110", -1, "0o0107"), + ("0o0001", -1, "0o0000"), + ("0o7777", 1, "0o10000"), + ("0o1000", -1, "0o0777"), + ("0o0107", 10, "0o0121"), + ("0o0000", -1, "0o0000"), + ("0o1777777777777777777777", 1, "0o2000000000000000000000"), + ("0o1777777777777777777777", 2, "0o2000000000000000000001"), + ("0o1777777777777777777777", -1, "0o1777777777777777777776"), + ]; + + for (original, amount, expected) in tests { + assert_eq!(increment(original, amount).unwrap(), expected); + } + } + + #[test] + fn test_increment_basic_binary_numbers() { + let tests = [ + ("0b00000100", 1, "0b00000101"), + ("0b00000100", -1, "0b00000011"), + ("0b00000100", 2, "0b00000110"), + ("0b00000100", -2, "0b00000010"), + ("0b00000001", -1, "0b00000000"), + ("0b00111111", 10, "0b01001001"), + ("0b11111111", 1, "0b100000000"), + ("0b10000000", -1, "0b01111111"), + ("0b0000", -1, "0b0000"), + ( + "0b1111111111111111111111111111111111111111111111111111111111111111", + 1, + "0b10000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0b1111111111111111111111111111111111111111111111111111111111111111", + 2, + "0b10000000000000000000000000000000000000000000000000000000000000001", + ), + ( + "0b1111111111111111111111111111111111111111111111111111111111111111", + -1, + "0b1111111111111111111111111111111111111111111111111111111111111110", + ), + ]; + + for (original, amount, expected) in tests { + assert_eq!(increment(original, amount).unwrap(), expected); + } + } + + #[test] + fn test_increment_with_separators() { + let tests = [ + ("999_999", 1, "1_000_000"), + ("1_000_000", -1, "999_999"), + ("-999_999", -1, "-1_000_000"), + ("0x0000_0000_0001", 0x1_ffff_0000, "0x0001_ffff_0001"), + ("0x0000_0000", -1, "0x0000_0000"), + ("0x0000_0000_0000", -1, "0x0000_0000_0000"), + ("0b01111111_11111111", 1, "0b10000000_00000000"), + ("0b11111111_11111111", 1, "0b1_00000000_00000000"), + ]; + + for (original, amount, expected) in tests { + assert_eq!(increment(original, amount).unwrap(), expected); + } + } + + #[test] + fn test_leading_and_trailing_separators_arent_a_match() { + assert_eq!(increment("9_", 1), None); + assert_eq!(increment("_9", 1), None); + assert_eq!(increment("_9_", 1), None); + } +} diff --git a/helix-core/src/increment/mod.rs b/helix-core/src/increment/mod.rs index f5945774..f1978bde 100644 --- a/helix-core/src/increment/mod.rs +++ b/helix-core/src/increment/mod.rs @@ -1,8 +1,10 @@ -pub mod date_time; -pub mod number; +mod date_time; +mod integer; -use crate::{Range, Tendril}; +pub fn integer(selected_text: &str, amount: i64) -> Option { + integer::increment(selected_text, amount) +} -pub trait Increment { - fn increment(&self, amount: i64) -> (Range, Tendril); +pub fn date_time(selected_text: &str, amount: i64) -> Option { + date_time::increment(selected_text, amount) } diff --git a/helix-core/src/increment/number.rs b/helix-core/src/increment/number.rs deleted file mode 100644 index 91268729..00000000 --- a/helix-core/src/increment/number.rs +++ /dev/null @@ -1,507 +0,0 @@ -use std::borrow::Cow; - -use ropey::RopeSlice; - -use super::Increment; - -use crate::{ - textobject::{textobject_word, TextObject}, - Range, Tendril, -}; - -#[derive(Debug, PartialEq, Eq)] -pub struct NumberIncrementor<'a> { - value: i64, - radix: u32, - range: Range, - - text: RopeSlice<'a>, -} - -impl<'a> NumberIncrementor<'a> { - /// Return information about number under rang if there is one. - pub fn from_range(text: RopeSlice, range: Range) -> Option { - // If the cursor is on the minus sign of a number we want to get the word textobject to the - // right of it. - let range = if range.to() < text.len_chars() - && range.to() - range.from() <= 1 - && text.char(range.from()) == '-' - { - Range::new(range.from() + 1, range.to() + 1) - } else { - range - }; - - let range = textobject_word(text, range, TextObject::Inside, 1, false); - - // If there is a minus sign to the left of the word object, we want to include it in the range. - let range = if range.from() > 0 && text.char(range.from() - 1) == '-' { - range.extend(range.from() - 1, range.from()) - } else { - range - }; - - let word: String = text - .slice(range.from()..range.to()) - .chars() - .filter(|&c| c != '_') - .collect(); - let (radix, prefixed) = if word.starts_with("0x") { - (16, true) - } else if word.starts_with("0o") { - (8, true) - } else if word.starts_with("0b") { - (2, true) - } else { - (10, false) - }; - - let number = if prefixed { &word[2..] } else { &word }; - - let value = i128::from_str_radix(number, radix).ok()?; - if (value.is_positive() && value.leading_zeros() < 64) - || (value.is_negative() && value.leading_ones() < 64) - { - return None; - } - - let value = value as i64; - Some(NumberIncrementor { - range, - value, - radix, - text, - }) - } -} - -impl<'a> Increment for NumberIncrementor<'a> { - fn increment(&self, amount: i64) -> (Range, Tendril) { - let old_text: Cow = self.text.slice(self.range.from()..self.range.to()).into(); - let old_length = old_text.len(); - let new_value = self.value.wrapping_add(amount); - - // Get separator indexes from right to left. - let separator_rtl_indexes: Vec = old_text - .chars() - .rev() - .enumerate() - .filter_map(|(i, c)| if c == '_' { Some(i) } else { None }) - .collect(); - - let format_length = if self.radix == 10 { - match (self.value.is_negative(), new_value.is_negative()) { - (true, false) => old_length - 1, - (false, true) => old_length + 1, - _ => old_text.len(), - } - } else { - old_text.len() - 2 - } - separator_rtl_indexes.len(); - - let mut new_text = match self.radix { - 2 => format!("0b{:01$b}", new_value, format_length), - 8 => format!("0o{:01$o}", new_value, format_length), - 10 if old_text.starts_with('0') || old_text.starts_with("-0") => { - format!("{:01$}", new_value, format_length) - } - 10 => format!("{}", new_value), - 16 => { - let (lower_count, upper_count): (usize, usize) = - old_text.chars().skip(2).fold((0, 0), |(lower, upper), c| { - ( - lower + usize::from(c.is_ascii_lowercase()), - upper + usize::from(c.is_ascii_uppercase()), - ) - }); - if upper_count > lower_count { - format!("0x{:01$X}", new_value, format_length) - } else { - format!("0x{:01$x}", new_value, format_length) - } - } - _ => unimplemented!("radix not supported: {}", self.radix), - }; - - // Add separators from original number. - for &rtl_index in &separator_rtl_indexes { - if rtl_index < new_text.len() { - let new_index = new_text.len() - rtl_index; - new_text.insert(new_index, '_'); - } - } - - // Add in additional separators if necessary. - if new_text.len() > old_length && !separator_rtl_indexes.is_empty() { - let spacing = match separator_rtl_indexes.as_slice() { - [.., b, a] => a - b - 1, - _ => separator_rtl_indexes[0], - }; - - let prefix_length = if self.radix == 10 { 0 } else { 2 }; - if let Some(mut index) = new_text.find('_') { - while index - prefix_length > spacing { - index -= spacing; - new_text.insert(index, '_'); - } - } - } - - (self.range, new_text.into()) - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::Rope; - - #[test] - fn test_decimal_at_point() { - let rope = Rope::from_str("Test text 12345 more text."); - let range = Range::point(12); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range), - Some(NumberIncrementor { - range: Range::new(10, 15), - value: 12345, - radix: 10, - text: rope.slice(..), - }) - ); - } - - #[test] - fn test_uppercase_hexadecimal_at_point() { - let rope = Rope::from_str("Test text 0x123ABCDEF more text."); - let range = Range::point(12); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range), - Some(NumberIncrementor { - range: Range::new(10, 21), - value: 0x123ABCDEF, - radix: 16, - text: rope.slice(..), - }) - ); - } - - #[test] - fn test_lowercase_hexadecimal_at_point() { - let rope = Rope::from_str("Test text 0xfa3b4e more text."); - let range = Range::point(12); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range), - Some(NumberIncrementor { - range: Range::new(10, 18), - value: 0xfa3b4e, - radix: 16, - text: rope.slice(..), - }) - ); - } - - #[test] - fn test_octal_at_point() { - let rope = Rope::from_str("Test text 0o1074312 more text."); - let range = Range::point(12); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range), - Some(NumberIncrementor { - range: Range::new(10, 19), - value: 0o1074312, - radix: 8, - text: rope.slice(..), - }) - ); - } - - #[test] - fn test_binary_at_point() { - let rope = Rope::from_str("Test text 0b10111010010101 more text."); - let range = Range::point(12); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range), - Some(NumberIncrementor { - range: Range::new(10, 26), - value: 0b10111010010101, - radix: 2, - text: rope.slice(..), - }) - ); - } - - #[test] - fn test_negative_decimal_at_point() { - let rope = Rope::from_str("Test text -54321 more text."); - let range = Range::point(12); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range), - Some(NumberIncrementor { - range: Range::new(10, 16), - value: -54321, - radix: 10, - text: rope.slice(..), - }) - ); - } - - #[test] - fn test_decimal_with_leading_zeroes_at_point() { - let rope = Rope::from_str("Test text 000045326 more text."); - let range = Range::point(12); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range), - Some(NumberIncrementor { - range: Range::new(10, 19), - value: 45326, - radix: 10, - text: rope.slice(..), - }) - ); - } - - #[test] - fn test_negative_decimal_cursor_on_minus_sign() { - let rope = Rope::from_str("Test text -54321 more text."); - let range = Range::point(10); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range), - Some(NumberIncrementor { - range: Range::new(10, 16), - value: -54321, - radix: 10, - text: rope.slice(..), - }) - ); - } - - #[test] - fn test_number_under_range_start_of_rope() { - let rope = Rope::from_str("100"); - let range = Range::point(0); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range), - Some(NumberIncrementor { - range: Range::new(0, 3), - value: 100, - radix: 10, - text: rope.slice(..), - }) - ); - } - - #[test] - fn test_number_under_range_end_of_rope() { - let rope = Rope::from_str("100"); - let range = Range::point(2); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range), - Some(NumberIncrementor { - range: Range::new(0, 3), - value: 100, - radix: 10, - text: rope.slice(..), - }) - ); - } - - #[test] - fn test_number_surrounded_by_punctuation() { - let rope = Rope::from_str(",100;"); - let range = Range::point(1); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range), - Some(NumberIncrementor { - range: Range::new(1, 4), - value: 100, - radix: 10, - text: rope.slice(..), - }) - ); - } - - #[test] - fn test_not_a_number_point() { - let rope = Rope::from_str("Test text 45326 more text."); - let range = Range::point(6); - assert_eq!(NumberIncrementor::from_range(rope.slice(..), range), None); - } - - #[test] - fn test_number_too_large_at_point() { - let rope = Rope::from_str("Test text 0xFFFFFFFFFFFFFFFFF more text."); - let range = Range::point(12); - assert_eq!(NumberIncrementor::from_range(rope.slice(..), range), None); - } - - #[test] - fn test_number_cursor_one_right_of_number() { - let rope = Rope::from_str("100 "); - let range = Range::point(3); - assert_eq!(NumberIncrementor::from_range(rope.slice(..), range), None); - } - - #[test] - fn test_number_cursor_one_left_of_number() { - let rope = Rope::from_str(" 100"); - let range = Range::point(0); - assert_eq!(NumberIncrementor::from_range(rope.slice(..), range), None); - } - - #[test] - fn test_increment_basic_decimal_numbers() { - let tests = [ - ("100", 1, "101"), - ("100", -1, "99"), - ("99", 1, "100"), - ("100", 1000, "1100"), - ("100", -1000, "-900"), - ("-1", 1, "0"), - ("-1", 2, "1"), - ("1", -1, "0"), - ("1", -2, "-1"), - ]; - - for (original, amount, expected) in tests { - let rope = Rope::from_str(original); - let range = Range::point(0); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range) - .unwrap() - .increment(amount) - .1, - Tendril::from(expected) - ); - } - } - - #[test] - fn test_increment_basic_hexadecimal_numbers() { - let tests = [ - ("0x0100", 1, "0x0101"), - ("0x0100", -1, "0x00ff"), - ("0x0001", -1, "0x0000"), - ("0x0000", -1, "0xffffffffffffffff"), - ("0xffffffffffffffff", 1, "0x0000000000000000"), - ("0xffffffffffffffff", 2, "0x0000000000000001"), - ("0xffffffffffffffff", -1, "0xfffffffffffffffe"), - ("0xABCDEF1234567890", 1, "0xABCDEF1234567891"), - ("0xabcdef1234567890", 1, "0xabcdef1234567891"), - ]; - - for (original, amount, expected) in tests { - let rope = Rope::from_str(original); - let range = Range::point(0); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range) - .unwrap() - .increment(amount) - .1, - Tendril::from(expected) - ); - } - } - - #[test] - fn test_increment_basic_octal_numbers() { - let tests = [ - ("0o0107", 1, "0o0110"), - ("0o0110", -1, "0o0107"), - ("0o0001", -1, "0o0000"), - ("0o7777", 1, "0o10000"), - ("0o1000", -1, "0o0777"), - ("0o0107", 10, "0o0121"), - ("0o0000", -1, "0o1777777777777777777777"), - ("0o1777777777777777777777", 1, "0o0000000000000000000000"), - ("0o1777777777777777777777", 2, "0o0000000000000000000001"), - ("0o1777777777777777777777", -1, "0o1777777777777777777776"), - ]; - - for (original, amount, expected) in tests { - let rope = Rope::from_str(original); - let range = Range::point(0); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range) - .unwrap() - .increment(amount) - .1, - Tendril::from(expected) - ); - } - } - - #[test] - fn test_increment_basic_binary_numbers() { - let tests = [ - ("0b00000100", 1, "0b00000101"), - ("0b00000100", -1, "0b00000011"), - ("0b00000100", 2, "0b00000110"), - ("0b00000100", -2, "0b00000010"), - ("0b00000001", -1, "0b00000000"), - ("0b00111111", 10, "0b01001001"), - ("0b11111111", 1, "0b100000000"), - ("0b10000000", -1, "0b01111111"), - ( - "0b0000", - -1, - "0b1111111111111111111111111111111111111111111111111111111111111111", - ), - ( - "0b1111111111111111111111111111111111111111111111111111111111111111", - 1, - "0b0000000000000000000000000000000000000000000000000000000000000000", - ), - ( - "0b1111111111111111111111111111111111111111111111111111111111111111", - 2, - "0b0000000000000000000000000000000000000000000000000000000000000001", - ), - ( - "0b1111111111111111111111111111111111111111111111111111111111111111", - -1, - "0b1111111111111111111111111111111111111111111111111111111111111110", - ), - ]; - - for (original, amount, expected) in tests { - let rope = Rope::from_str(original); - let range = Range::point(0); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range) - .unwrap() - .increment(amount) - .1, - Tendril::from(expected) - ); - } - } - - #[test] - fn test_increment_with_separators() { - let tests = [ - ("999_999", 1, "1_000_000"), - ("1_000_000", -1, "999_999"), - ("-999_999", -1, "-1_000_000"), - ("0x0000_0000_0001", 0x1_ffff_0000, "0x0001_ffff_0001"), - ("0x0000_0000_0001", 0x1_ffff_0000, "0x0001_ffff_0001"), - ("0x0000_0000_0001", 0x1_ffff_0000, "0x0001_ffff_0001"), - ("0x0000_0000", -1, "0xffff_ffff_ffff_ffff"), - ("0x0000_0000_0000", -1, "0xffff_ffff_ffff_ffff"), - ("0b01111111_11111111", 1, "0b10000000_00000000"), - ("0b11111111_11111111", 1, "0b1_00000000_00000000"), - ]; - - for (original, amount, expected) in tests { - let rope = Rope::from_str(original); - let range = Range::point(0); - assert_eq!( - NumberIncrementor::from_range(rope.slice(..), range) - .unwrap() - .increment(amount) - .1, - Tendril::from(expected) - ); - } - } -} diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 09c2e5df..e196e71e 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -11,9 +11,7 @@ pub use typed::*; use helix_core::{ comment, coords_at_pos, encoding, find_first_non_whitespace_char, find_root, graphemes, history::UndoKind, - increment::date_time::DateTimeIncrementor, - increment::{number::NumberIncrementor, Increment}, - indent, + increment, indent, indent::IndentStyle, line_ending::{get_line_ending_of_str, line_end_char_index, str_is_line_ending}, match_brackets, @@ -5028,57 +5026,25 @@ enum IncrementDirection { Increase, Decrease, } -/// Increment object under cursor by count. + +/// Increment objects within selections by count. fn increment(cx: &mut Context) { increment_impl(cx, IncrementDirection::Increase); } -/// Decrement object under cursor by count. +/// Decrement objects within selections by count. fn decrement(cx: &mut Context) { increment_impl(cx, IncrementDirection::Decrease); } -/// This function differs from find_next_char_impl in that it stops searching at the newline, but also -/// starts searching at the current character, instead of the next. -/// It does not want to start at the next character because this function is used for incrementing -/// number and we don't want to move forward if we're already on a digit. -fn find_next_char_until_newline( - text: RopeSlice, - char_matcher: M, - pos: usize, - _count: usize, - _inclusive: bool, -) -> Option { - // Since we send the current line to find_nth_next instead of the whole text, we need to adjust - // the position we send to this function so that it's relative to that line and its returned - // position since it's expected this function returns a global position. - let line_index = text.char_to_line(pos); - let pos_delta = text.line_to_char(line_index); - let pos = pos - pos_delta; - search::find_nth_next(text.line(line_index), char_matcher, pos, 1).map(|pos| pos + pos_delta) -} - -/// Decrement object under cursor by `amount`. +/// Increment objects within selections by `amount`. +/// A negative `amount` will decrement objects within selections. fn increment_impl(cx: &mut Context, increment_direction: IncrementDirection) { - // TODO: when incrementing or decrementing a number that gets a new digit or lose one, the - // selection is updated improperly. - find_char_impl( - cx.editor, - &find_next_char_until_newline, - true, - true, - char::is_ascii_digit, - 1, - ); - - // Increase by 1 if `IncrementDirection` is `Increase` - // Decrease by 1 if `IncrementDirection` is `Decrease` let sign = match increment_direction { IncrementDirection::Increase => 1, IncrementDirection::Decrease => -1, }; let mut amount = sign * cx.count() as i64; - // If the register is `#` then increase or decrease the `amount` by 1 per element let increase_by = if cx.register == Some('#') { sign } else { 0 }; @@ -5086,55 +5052,40 @@ fn increment_impl(cx: &mut Context, increment_direction: IncrementDirection) { let selection = doc.selection(view.id); let text = doc.text().slice(..); - let changes: Vec<_> = selection - .ranges() - .iter() - .filter_map(|range| { - let incrementor: Box = - if let Some(incrementor) = DateTimeIncrementor::from_range(text, *range) { - Box::new(incrementor) - } else if let Some(incrementor) = NumberIncrementor::from_range(text, *range) { - Box::new(incrementor) - } else { - return None; - }; + let mut new_selection_ranges = SmallVec::new(); + let mut cumulative_length_diff: i128 = 0; + let mut changes = vec![]; - let (range, new_text) = incrementor.increment(amount); + for range in selection { + let selected_text: Cow = range.fragment(text); + let new_from = ((range.from() as i128) + cumulative_length_diff) as usize; + let incremented = [increment::integer, increment::date_time] + .iter() + .find_map(|incrementor| incrementor(selected_text.as_ref(), amount)); - amount += increase_by; + amount += increase_by; - Some((range.from(), range.to(), Some(new_text))) - }) - .collect(); - - // Overlapping changes in a transaction will panic, so we need to find and remove them. - // For example, if there are cursors on each of the year, month, and day of `2021-11-29`, - // incrementing will give overlapping changes, with each change incrementing a different part of - // the date. Since these conflict with each other we remove these changes from the transaction - // so nothing happens. - let mut overlapping_indexes = HashSet::new(); - for (i, changes) in changes.windows(2).enumerate() { - if changes[0].1 > changes[1].0 { - overlapping_indexes.insert(i); - overlapping_indexes.insert(i + 1); + match incremented { + None => { + let new_range = Range::new( + new_from, + (range.to() as i128 + cumulative_length_diff) as usize, + ); + new_selection_ranges.push(new_range); + } + Some(new_text) => { + let new_range = Range::new(new_from, new_from + new_text.len()); + cumulative_length_diff += new_text.len() as i128 - selected_text.len() as i128; + new_selection_ranges.push(new_range); + changes.push((range.from(), range.to(), Some(new_text.into()))); + } } } - let changes: Vec<_> = changes - .into_iter() - .enumerate() - .filter_map(|(i, change)| { - if overlapping_indexes.contains(&i) { - None - } else { - Some(change) - } - }) - .collect(); if !changes.is_empty() { + let new_selection = Selection::new(new_selection_ranges, selection.primary_index()); let transaction = Transaction::change(doc.text(), changes.into_iter()); - let transaction = transaction.with_selection(selection.clone()); - + let transaction = transaction.with_selection(new_selection); apply_transaction(&transaction, doc, view); } } From 3cf5216dbd1b9c767e6a922f93f1a3b1a2955d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikodem=20Rabuli=C5=84ski?= Date: Mon, 16 Jan 2023 17:41:22 +0100 Subject: [PATCH 008/342] Commit to history after executing a command from the palette (#5294) --- helix-term/src/commands.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index e196e71e..7df53a48 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2504,7 +2504,22 @@ pub fn command_palette(cx: &mut Context) { on_next_key_callback: None, jobs: cx.jobs, }; + let focus = view!(ctx.editor).id; + command.execute(&mut ctx); + + if ctx.editor.tree.contains(focus) { + let config = ctx.editor.config(); + let mode = ctx.editor.mode(); + let view = view_mut!(ctx.editor, focus); + let doc = doc_mut!(ctx.editor, &view.doc); + + view.ensure_cursor_in_view(doc, config.scrolloff); + + if mode != Mode::Insert { + doc.append_changes_to_history(view); + } + } }); compositor.push(Box::new(overlayed(picker))); }, From 6d34faf4fb4b28365d3e2f93e032b4eea04912c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jan 2023 10:05:34 +0900 Subject: [PATCH 009/342] build(deps): bump libc from 0.2.137 to 0.2.139 (#5558) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.137 to 0.2.139. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.137...0.2.139) --- updated-dependencies: - dependency-name: libc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ede4ae0d..02c63d28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1427,9 +1427,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.137" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libloading" From 6317e0a7159bf124cb23e04b49dc29964cbe79a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jan 2023 10:07:09 +0900 Subject: [PATCH 010/342] build(deps): bump hashbrown from 0.13.1 to 0.13.2 (#5559) Bumps [hashbrown](https://github.com/rust-lang/hashbrown) from 0.13.1 to 0.13.2. - [Release notes](https://github.com/rust-lang/hashbrown/releases) - [Changelog](https://github.com/rust-lang/hashbrown/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/hashbrown/compare/v0.13.1...v0.13.2) --- updated-dependencies: - dependency-name: hashbrown dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- helix-core/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 02c63d28..665eb4b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -728,7 +728,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c52b625ad8cc360a0b7f426266f21fb07bd49b8f4ccf1b3ca7bc89424db1dec4" dependencies = [ "git-hash", - "hashbrown 0.13.1", + "hashbrown 0.13.2", ] [[package]] @@ -1104,9 +1104,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ "ahash 0.8.2", ] @@ -1121,7 +1121,7 @@ dependencies = [ "chrono", "encoding_rs", "etcetera", - "hashbrown 0.13.1", + "hashbrown 0.13.2", "helix-loader", "imara-diff", "log", diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index ca6cd51e..73e64cfd 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -31,7 +31,7 @@ arc-swap = "1" regex = "1" bitflags = "1.3" ahash = "0.8.2" -hashbrown = { version = "0.13.1", features = ["raw"] } +hashbrown = { version = "0.13.2", features = ["raw"] } log = "0.4" serde = { version = "1.0", features = ["derive"] } From a02dd17e8214125481a89f7aaa414f0c2285b3be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Delafargue?= Date: Tue, 17 Jan 2023 09:17:22 +0100 Subject: [PATCH 011/342] doc: make the order of unimpaired mappings consistent Most mappings are next `]` then previous `[`, except for a few ones. Fixes #5145 --- book/src/keymap.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index b38a1f44..92455911 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -305,10 +305,10 @@ Mappings in the style of [vim-unimpaired](https://github.com/tpope/vim-unimpaire | Key | Description | Command | | ----- | ----------- | ------- | -| `[d` | Go to previous diagnostic (**LSP**) | `goto_prev_diag` | | `]d` | Go to next diagnostic (**LSP**) | `goto_next_diag` | -| `[D` | Go to first diagnostic in document (**LSP**) | `goto_first_diag` | +| `[d` | Go to previous diagnostic (**LSP**) | `goto_prev_diag` | | `]D` | Go to last diagnostic in document (**LSP**) | `goto_last_diag` | +| `[D` | Go to first diagnostic in document (**LSP**) | `goto_first_diag` | | `]f` | Go to next function (**TS**) | `goto_next_function` | | `[f` | Go to previous function (**TS**) | `goto_prev_function` | | `]t` | Go to next type definition (**TS**) | `goto_next_class` | @@ -323,10 +323,10 @@ Mappings in the style of [vim-unimpaired](https://github.com/tpope/vim-unimpaire | `[p` | Go to previous paragraph | `goto_prev_paragraph` | | `]g` | Go to next change | `goto_next_change` | | `[g` | Go to previous change | `goto_prev_change` | -| `[G` | Go to first change | `goto_first_change` | | `]G` | Go to last change | `goto_last_change` | -| `[Space` | Add newline above | `add_newline_above` | +| `[G` | Go to first change | `goto_first_change` | | `]Space` | Add newline below | `add_newline_below` | +| `[Space` | Add newline above | `add_newline_above` | ## Insert mode From 9530fab4b6f320d212f966e46a0353931a010471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Delafargue?= Date: Tue, 17 Jan 2023 09:48:43 +0100 Subject: [PATCH 012/342] doc: expand documentation on configuring minor modes Fixes #3835, #4811 --- book/src/keymap.md | 3 +++ book/src/remapping.md | 27 +++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index 92455911..0550e57f 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -166,6 +166,9 @@ These sub-modes are accessible from normal mode and typically switch back to nor | `Ctrl-w` | Enter [window mode](#window-mode) | N/A | | `Space` | Enter [space mode](#space-mode) | N/A | +These modes (except command mode) can be configured by +[remapping keys](https://docs.helix-editor.com/remapping.html#minor-modes). + #### View mode Accessed by typing `z` in [normal mode](#normal-mode). diff --git a/book/src/remapping.md b/book/src/remapping.md index 2eac8846..8339e05f 100644 --- a/book/src/remapping.md +++ b/book/src/remapping.md @@ -25,8 +25,31 @@ j = { k = "normal_mode" } # Maps `jk` to exit insert mode ``` > NOTE: Typable commands can also be remapped, remember to keep the `:` prefix to indicate it's a typable command. -> NOTE: Bindings can be nested, to create (or edit) minor modes: `g = { a = "code_action"}` adds a new entry to -> the `goto` mode. +## Minor modes + +Minor modes are accessed by pressing a key (usually from normal mode), giving access to dedicated bindings. Bindings +can be modified or added by nesting definitions. + +```toml +[keys.insert.j] +k = "normal_mode" # Maps `jk` to exit insert mode + +[keys.normal.g] +a = "code_action" # Maps `ga` to show possible code actions + +# invert `j` and `k` in view mode +[keys.normal.z] +j = "scroll_up" +k = "scroll_down" + +# create a new minor mode bound to `+` +[keys.normal."+"] +m = ":run-shell-command make" +c = ":run-shell-command cargo build" +t = ":run-shell-command cargo test" +``` + +## Special keys and modifiers Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes `C-`, `S-` and `A-`. Special keys are encoded as follows: From e7e47fd54263fb46f2dbb6fe8954fa489d143752 Mon Sep 17 00:00:00 2001 From: mejo13 <36098293+mejo13@users.noreply.github.com> Date: Tue, 17 Jan 2023 23:15:21 +0100 Subject: [PATCH 013/342] Add command to rotate view backward (#5356) --- helix-term/src/commands.rs | 5 +++++ helix-view/src/editor.rs | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 7df53a48..15e4b47b 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -384,6 +384,7 @@ impl MappableCommand { swap_view_down, "Swap with split below", transpose_view, "Transpose splits", rotate_view, "Goto next window", + rotate_view_reverse, "Goto previous window", hsplit, "Horizontal bottom split", hsplit_new, "Horizontal bottom split scratch buffer", vsplit, "Vertical right split", @@ -4317,6 +4318,10 @@ fn rotate_view(cx: &mut Context) { cx.editor.focus_next() } +fn rotate_view_reverse(cx: &mut Context) { + cx.editor.focus_prev() +} + fn jump_view_right(cx: &mut Context) { cx.editor.focus_direction(tree::Direction::Right) } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 547a4ffb..4a44a00c 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1285,6 +1285,10 @@ impl Editor { self.focus(self.tree.next()); } + pub fn focus_prev(&mut self) { + self.focus(self.tree.prev()); + } + pub fn focus_direction(&mut self, direction: tree::Direction) { let current_view = self.tree.focus; if let Some(id) = self.tree.find_split_in_direction(current_view, direction) { From b65f104a3fe1d8bdd0dbf901f7c52576b2b5f1c0 Mon Sep 17 00:00:00 2001 From: Josh Bainbridge Date: Tue, 17 Jan 2023 22:16:05 +0000 Subject: [PATCH 014/342] Fix diagnostic indicator background for gruvbox themes (#5540) The diagnostic indicator background did not match the column or rows background colour as this was context specific, and the background for the indicator was being explicitly set. This commit removes the explicit value for the indicators background allowing it to adapt to the context. This is aligns it with other themes, and resolves the issue. --- runtime/themes/gruvbox.toml | 8 ++++---- runtime/themes/gruvbox_dark_hard.toml | 8 ++++---- runtime/themes/gruvbox_light.toml | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/runtime/themes/gruvbox.toml b/runtime/themes/gruvbox.toml index 5d897201..c293fc3e 100644 --- a/runtime/themes/gruvbox.toml +++ b/runtime/themes/gruvbox.toml @@ -33,10 +33,10 @@ "diff.delta" = "orange1" "diff.minus" = "red1" -"warning" = { fg = "orange1", bg = "bg1" } -"error" = { fg = "red1", bg = "bg1" } -"info" = { fg = "aqua1", bg = "bg1" } -"hint" = { fg = "blue1", bg = "bg1" } +"warning" = "orange1" +"error" = "red1" +"info" = "aqua1" +"hint" = "blue1" "ui.background" = { bg = "bg0" } "ui.linenr" = { fg = "bg4" } diff --git a/runtime/themes/gruvbox_dark_hard.toml b/runtime/themes/gruvbox_dark_hard.toml index a1a83e65..f39cd906 100644 --- a/runtime/themes/gruvbox_dark_hard.toml +++ b/runtime/themes/gruvbox_dark_hard.toml @@ -34,10 +34,10 @@ "diff.delta" = "orange1" "diff.minus" = "red1" -"warning" = { fg = "orange1", bg = "bg1" } -"error" = { fg = "red1", bg = "bg1" } -"info" = { fg = "aqua1", bg = "bg1" } -"hint" = { fg = "blue1", bg = "bg1" } +"warning" = "orange1" +"error" = "red1" +"info" = "aqua1" +"hint" = "blue1" "diagnostic.error" = { underline = { style = "curl", color = "red0" } } "diagnostic.warning" = { underline = { style = "curl", color = "orange1" } } diff --git a/runtime/themes/gruvbox_light.toml b/runtime/themes/gruvbox_light.toml index 7c1c765d..8ea9d625 100644 --- a/runtime/themes/gruvbox_light.toml +++ b/runtime/themes/gruvbox_light.toml @@ -34,10 +34,10 @@ "diff.delta" = "orange1" "diff.minus" = "red1" -"warning" = { fg = "orange1", bg = "bg1" } -"error" = { fg = "red1", bg = "bg1" } -"info" = { fg = "aqua1", bg = "bg1" } -"hint" = { fg = "blue1", bg = "bg1" } +"warning" = "orange1" +"error" = "red1" +"info" = "aqua1" +"hint" = "blue1" "ui.background" = { bg = "bg0" } "ui.linenr" = { fg = "bg4" } From deae13f404fadddf16f7c2005af8b383a1d8e362 Mon Sep 17 00:00:00 2001 From: gibbz00 Date: Wed, 18 Jan 2023 06:18:49 +0100 Subject: [PATCH 015/342] Primary cursor colors by mode (#5130) * (theme) feat: mode based primary cursor colors * docs/themes: mode based primary cursor colors --- book/src/themes.md | 4 ++++ helix-term/src/ui/editor.rs | 20 +++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/book/src/themes.md b/book/src/themes.md index 015ec59b..0d0827fd 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -252,10 +252,14 @@ These scopes are used for theming the editor interface. | `ui.background` | | | `ui.background.separator` | Picker separator below input line | | `ui.cursor` | | +| `ui.cursor.normal` | | | `ui.cursor.insert` | | | `ui.cursor.select` | | | `ui.cursor.match` | Matching bracket etc. | | `ui.cursor.primary` | Cursor with primary selection | +| `ui.cursor.primary.normal` | | +| `ui.cursor.primary.insert` | | +| `ui.cursor.primary.select` | | | `ui.gutter` | Gutter | | `ui.gutter.selected` | Gutter for the line the cursor is on | | `ui.linenr` | Line numbers | diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 35cf77ab..a19eb213 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -342,23 +342,29 @@ impl EditorView { let selection_scope = theme .find_scope_index("ui.selection") .expect("could not find `ui.selection` scope in the theme!"); + let primary_selection_scope = theme + .find_scope_index("ui.selection.primary") + .unwrap_or(selection_scope); let base_cursor_scope = theme .find_scope_index("ui.cursor") .unwrap_or(selection_scope); + let base_primary_cursor_scope = theme + .find_scope_index("ui.cursor.primary") + .unwrap_or(base_cursor_scope); let cursor_scope = match mode { Mode::Insert => theme.find_scope_index("ui.cursor.insert"), Mode::Select => theme.find_scope_index("ui.cursor.select"), - Mode::Normal => Some(base_cursor_scope), + Mode::Normal => theme.find_scope_index("ui.cursor.normal"), } .unwrap_or(base_cursor_scope); - let primary_cursor_scope = theme - .find_scope_index("ui.cursor.primary") - .unwrap_or(cursor_scope); - let primary_selection_scope = theme - .find_scope_index("ui.selection.primary") - .unwrap_or(selection_scope); + let primary_cursor_scope = match mode { + Mode::Insert => theme.find_scope_index("ui.cursor.primary.insert"), + Mode::Select => theme.find_scope_index("ui.cursor.primary.select"), + Mode::Normal => theme.find_scope_index("ui.cursor.primary.normal"), + } + .unwrap_or(base_primary_cursor_scope); let mut spans: Vec<(usize, std::ops::Range)> = Vec::new(); for (i, range) in selection.iter().enumerate() { From 9aafcb2b9a743f0f6afa722184e96b8a672064ea Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sat, 9 Jul 2022 00:16:09 +0530 Subject: [PATCH 016/342] Reuse table in picker --- helix-term/src/ui/picker.rs | 182 ++++++++++++++++++++++++--------- helix-tui/src/text.rs | 13 +++ helix-tui/src/widgets/table.rs | 14 ++- 3 files changed, 155 insertions(+), 54 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index eb935e56..e2e72b6e 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -7,7 +7,9 @@ use crate::{ use futures_util::future::BoxFuture; use tui::{ buffer::Buffer as Surface, - widgets::{Block, BorderType, Borders}, + layout::Constraint, + text::{Span, Spans}, + widgets::{Block, BorderType, Borders, Cell, Table}, }; use fuzzy_matcher::skim::SkimMatcherV2 as Matcher; @@ -20,10 +22,11 @@ use std::{ use std::{collections::HashMap, io::Read, path::PathBuf}; use crate::ui::{Prompt, PromptEvent}; -use helix_core::{movement::Direction, Position}; +use helix_core::{movement::Direction, unicode::segmentation::UnicodeSegmentation, Position}; use helix_view::{ editor::Action, graphics::{CursorKind, Margin, Modifier, Rect}, + theme::Style, Document, DocumentId, Editor, }; @@ -389,6 +392,8 @@ pub struct Picker { pub truncate_start: bool, /// Whether to show the preview panel (default true) show_preview: bool, + /// Constraints for tabular formatting + widths: Vec, callback_fn: Box, } @@ -406,6 +411,26 @@ impl Picker { |_editor: &mut Context, _pattern: &str, _event: PromptEvent| {}, ); + let n = options + .first() + .map(|option| option.row(&editor_data).cells.len()) + .unwrap_or_default(); + let max_lens = options.iter().fold(vec![0; n], |mut acc, option| { + let row = option.row(&editor_data); + // maintain max for each column + for (acc, cell) in acc.iter_mut().zip(row.cells.iter()) { + let width = cell.content.width(); + if width > *acc { + *acc = width; + } + } + acc + }); + let widths = max_lens + .into_iter() + .map(|len| Constraint::Length(len as u16)) + .collect(); + let mut picker = Self { options, editor_data, @@ -418,6 +443,7 @@ impl Picker { show_preview: true, callback_fn: Box::new(callback_fn), completion_height: 0, + widths, }; // scoring on empty input: @@ -437,8 +463,6 @@ impl Picker { } pub fn score(&mut self) { - let now = Instant::now(); - let pattern = self.prompt.line(); if pattern == &self.previous_pattern { @@ -480,8 +504,6 @@ impl Picker { self.force_score(); } - log::debug!("picker score {:?}", Instant::now().duration_since(now)); - // reset cursor position self.cursor = 0; let pattern = self.prompt.line(); @@ -657,7 +679,7 @@ impl Component for Picker { fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) { let text_style = cx.editor.theme.get("ui.text"); let selected = cx.editor.theme.get("ui.text.focus"); - let highlighted = cx.editor.theme.get("special").add_modifier(Modifier::BOLD); + let highlight_style = cx.editor.theme.get("special").add_modifier(Modifier::BOLD); // -- Render the frame: // clear area @@ -697,61 +719,119 @@ impl Component for Picker { } // -- Render the contents: - // subtract area of prompt from top and current item marker " > " from left - let inner = inner.clip_top(2).clip_left(3); + // subtract area of prompt from top + let inner = inner.clip_top(2); let rows = inner.height; let offset = self.cursor - (self.cursor % std::cmp::max(1, rows as usize)); + let cursor = self.cursor.saturating_sub(offset); - let files = self + let options = self .matches .iter() .skip(offset) - .map(|pmatch| (pmatch.index, self.options.get(pmatch.index).unwrap())); - - for (i, (_index, option)) in files.take(rows as usize).enumerate() { - let is_active = i == (self.cursor - offset); - if is_active { - surface.set_string( - inner.x.saturating_sub(3), - inner.y + i as u16, - " > ", - selected, - ); - surface.set_style( - Rect::new(inner.x, inner.y + i as u16, inner.width, 1), - selected, - ); - } + .take(rows as usize) + .map(|pmatch| &self.options[pmatch.index]) + .map(|option| option.row(&self.editor_data)) + .map(|mut row| { + const TEMP_CELL_SEP: &str = " "; + + let line = row.cell_text().join(TEMP_CELL_SEP); + + // Items are filtered by using the text returned by menu::Item::filter_text + // but we do highlighting here using the text in Row and therefore there + // 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) + .unwrap_or_default(); + + let highlight_byte_ranges: Vec<_> = line + .char_indices() + .enumerate() + .filter_map(|(char_idx, (byte_offset, ch))| { + highlights + .contains(&char_idx) + .then(|| byte_offset..byte_offset + ch.len_utf8()) + }) + .collect(); + + // The starting byte index of the current (iterating) cell + let mut cell_start_byte_offset = 0; + for cell in row.cells.iter_mut() { + let spans = match cell.content.lines.get(0) { + Some(s) => s, + None => continue, + }; + + let mut cell_len = 0; - let spans = option.label(&self.editor_data); - let (_score, highlights) = FuzzyQuery::new(self.prompt.line()) - .fuzzy_indicies(&String::from(&spans), &self.matcher) - .unwrap_or_default(); - - spans.0.into_iter().fold(inner, |pos, span| { - let new_x = surface - .set_string_truncated( - pos.x, - pos.y + i as u16, - &span.content, - pos.width as usize, - |idx| { - if highlights.contains(&idx) { - highlighted.patch(span.style) - } else if is_active { - selected.patch(span.style) + let graphemes_with_style: Vec<_> = spans + .0 + .iter() + .flat_map(|span| { + span.content + .grapheme_indices(true) + .zip(std::iter::repeat(span.style)) + }) + .map(|((grapheme_byte_offset, grapheme), style)| { + cell_len += grapheme.len(); + let start = cell_start_byte_offset; + + let grapheme_byte_range = + grapheme_byte_offset..grapheme_byte_offset + grapheme.len(); + + if highlight_byte_ranges.iter().any(|hl_rng| { + hl_rng.start >= start + grapheme_byte_range.start + && hl_rng.end <= start + grapheme_byte_range.end + }) { + (grapheme, style.patch(highlight_style)) } else { - text_style.patch(span.style) + (grapheme, style) } - }, - true, - self.truncate_start, - ) - .0; - pos.clip_left(new_x - pos.x) + }) + .collect(); + + let mut span_list: Vec<(String, Style)> = Vec::new(); + for (grapheme, style) in graphemes_with_style { + if span_list.last().map(|(_, sty)| sty) == Some(&style) { + let (string, _) = span_list.last_mut().unwrap(); + string.push_str(grapheme); + } else { + span_list.push((String::from(grapheme), style)) + } + } + + let spans: Vec = span_list + .into_iter() + .map(|(string, style)| Span::styled(string, style)) + .collect(); + let spans: Spans = spans.into(); + *cell = Cell::from(spans); + + cell_start_byte_offset += cell_len + TEMP_CELL_SEP.len(); + } + + row }); - } + + let table = Table::new(options) + .style(text_style) + .highlight_style(selected) + .highlight_symbol(" > ") + .column_spacing(1) + .widths(&self.widths); + + use tui::widgets::TableState; + + table.render_table( + inner, + surface, + &mut TableState { + offset: 0, + selected: Some(cursor), + }, + ); } fn cursor(&self, area: Rect, editor: &Editor) -> (Option, CursorKind) { diff --git a/helix-tui/src/text.rs b/helix-tui/src/text.rs index ccdafad5..6970634b 100644 --- a/helix-tui/src/text.rs +++ b/helix-tui/src/text.rs @@ -436,6 +436,19 @@ impl<'a> From>> for Text<'a> { } } +impl<'a> From> for String { + fn from(text: Text<'a>) -> String { + let lines: Vec = text.lines.iter().map(String::from).collect(); + lines.join("\n") + } +} + +impl<'a> From<&Text<'a>> for String { + fn from(text: &Text<'a>) -> String { + let lines: Vec = text.lines.iter().map(String::from).collect(); + lines.join("\n") + } +} impl<'a> IntoIterator for Text<'a> { type Item = Spans<'a>; type IntoIter = std::vec::IntoIter; diff --git a/helix-tui/src/widgets/table.rs b/helix-tui/src/widgets/table.rs index a8f428a7..26860e5c 100644 --- a/helix-tui/src/widgets/table.rs +++ b/helix-tui/src/widgets/table.rs @@ -126,6 +126,14 @@ impl<'a> Row<'a> { fn total_height(&self) -> u16 { self.height.saturating_add(self.bottom_margin) } + + /// Returns the contents of cells as plain text, without styles and colors. + pub fn cell_text(&self) -> Vec { + self.cells + .iter() + .map(|cell| String::from(&cell.content)) + .collect() + } } /// A widget to display data in formatted columns. @@ -477,6 +485,9 @@ impl<'a> Table<'a> { }; let mut col = table_row_start_col; for (width, cell) in columns_widths.iter().zip(table_row.cells.iter()) { + if is_selected { + buf.set_style(table_row_area, self.highlight_style); + } render_cell( buf, cell, @@ -489,9 +500,6 @@ impl<'a> Table<'a> { ); col += *width + self.column_spacing; } - if is_selected { - buf.set_style(table_row_area, self.highlight_style); - } } } } From 7a76c6cbbaf851d63cb4ca4be07c5d4c67afbbb2 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sun, 18 Dec 2022 18:12:25 +0530 Subject: [PATCH 017/342] Use upstream implementation of table column calculation Changed in https://github.com/fdehau/tui-rs/commit/a68e38e59e6735c0a99139303b1609669d2c38da. --- helix-term/src/ui/picker.rs | 5 +-- helix-tui/src/widgets/table.rs | 81 ++++++++-------------------------- 2 files changed, 20 insertions(+), 66 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index e2e72b6e..e00fe1f8 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -15,10 +15,7 @@ use tui::{ use fuzzy_matcher::skim::SkimMatcherV2 as Matcher; use tui::widgets::Widget; -use std::{ - cmp::{self, Ordering}, - time::Instant, -}; +use std::cmp::{self, Ordering}; use std::{collections::HashMap, io::Read, path::PathBuf}; use crate::ui::{Prompt, PromptEvent}; diff --git a/helix-tui/src/widgets/table.rs b/helix-tui/src/widgets/table.rs index 26860e5c..539f6a61 100644 --- a/helix-tui/src/widgets/table.rs +++ b/helix-tui/src/widgets/table.rs @@ -4,14 +4,8 @@ use crate::{ text::Text, widgets::{Block, Widget}, }; -use cassowary::{ - strength::{MEDIUM, REQUIRED, WEAK}, - WeightedRelation::*, - {Expression, Solver}, -}; use helix_core::unicode::width::UnicodeWidthStr; use helix_view::graphics::{Rect, Style}; -use std::collections::HashMap; /// A [`Cell`] contains the [`Text`] to be displayed in a [`Row`] of a [`Table`]. /// @@ -268,69 +262,32 @@ impl<'a> Table<'a> { } fn get_columns_widths(&self, max_width: u16, has_selection: bool) -> Vec { - let mut solver = Solver::new(); - let mut var_indices = HashMap::new(); - let mut ccs = Vec::new(); - let mut variables = Vec::new(); - for i in 0..self.widths.len() { - let var = cassowary::Variable::new(); - variables.push(var); - var_indices.insert(var, i); - } - let spacing_width = (variables.len() as u16).saturating_sub(1) * self.column_spacing; - let mut available_width = max_width.saturating_sub(spacing_width); + let mut constraints = Vec::with_capacity(self.widths.len() * 2 + 1); if has_selection { let highlight_symbol_width = self.highlight_symbol.map(|s| s.width() as u16).unwrap_or(0); - available_width = available_width.saturating_sub(highlight_symbol_width); + constraints.push(Constraint::Length(highlight_symbol_width)); } - for (i, constraint) in self.widths.iter().enumerate() { - ccs.push(variables[i] | GE(WEAK) | 0.); - ccs.push(match *constraint { - Constraint::Length(v) => variables[i] | EQ(MEDIUM) | f64::from(v), - Constraint::Percentage(v) => { - variables[i] | EQ(WEAK) | (f64::from(v * available_width) / 100.0) - } - Constraint::Ratio(n, d) => { - variables[i] - | EQ(WEAK) - | (f64::from(available_width) * f64::from(n) / f64::from(d)) - } - Constraint::Min(v) => variables[i] | GE(WEAK) | f64::from(v), - Constraint::Max(v) => variables[i] | LE(WEAK) | f64::from(v), - }) + for constraint in self.widths { + constraints.push(*constraint); + constraints.push(Constraint::Length(self.column_spacing)); } - solver - .add_constraint( - variables - .iter() - .fold(Expression::from_constant(0.), |acc, v| acc + *v) - | LE(REQUIRED) - | f64::from(available_width), - ) - .unwrap(); - solver.add_constraints(&ccs).unwrap(); - let mut widths = vec![0; variables.len()]; - for &(var, value) in solver.fetch_changes() { - let index = var_indices[&var]; - let value = if value.is_sign_negative() { - 0 - } else { - value.round() as u16 - }; - widths[index] = value; + if !self.widths.is_empty() { + constraints.pop(); } - // Cassowary could still return columns widths greater than the max width when there are - // fixed length constraints that cannot be satisfied. Therefore, we clamp the widths from - // left to right. - let mut available_width = max_width; - for w in &mut widths { - *w = available_width.min(*w); - available_width = available_width - .saturating_sub(*w) - .saturating_sub(self.column_spacing); + let mut chunks = crate::layout::Layout::default() + .direction(crate::layout::Direction::Horizontal) + .constraints(constraints) + .split(Rect { + x: 0, + y: 0, + width: max_width, + height: 1, + }); + if has_selection { + chunks.remove(0); } - widths + chunks.iter().step_by(2).map(|c| c.width).collect() } fn get_row_bounds( From b2837ff3bea286ce7ccfba9b6fbcd861977caf83 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sat, 24 Dec 2022 16:51:38 +0530 Subject: [PATCH 018/342] Minimize allocation when converting table rows to string --- helix-term/src/ui/picker.rs | 6 +++++- helix-tui/src/text.rs | 21 +++++++++++++++++---- helix-tui/src/widgets/table.rs | 7 ++----- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index e00fe1f8..05738ccf 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -733,7 +733,11 @@ impl Component for Picker { .map(|mut row| { const TEMP_CELL_SEP: &str = " "; - let line = row.cell_text().join(TEMP_CELL_SEP); + let line = row.cell_text().fold(String::new(), |mut s, frag| { + s.push_str(&frag); + s.push_str(TEMP_CELL_SEP); + s + }); // Items are filtered by using the text returned by menu::Item::filter_text // but we do highlighting here using the text in Row and therefore there diff --git a/helix-tui/src/text.rs b/helix-tui/src/text.rs index 6970634b..a3e242fe 100644 --- a/helix-tui/src/text.rs +++ b/helix-tui/src/text.rs @@ -438,17 +438,30 @@ impl<'a> From>> for Text<'a> { impl<'a> From> for String { fn from(text: Text<'a>) -> String { - let lines: Vec = text.lines.iter().map(String::from).collect(); - lines.join("\n") + String::from(&text) } } impl<'a> From<&Text<'a>> for String { fn from(text: &Text<'a>) -> String { - let lines: Vec = text.lines.iter().map(String::from).collect(); - lines.join("\n") + let size = text + .lines + .iter() + .flat_map(|spans| spans.0.iter().map(|span| span.content.len())) + .sum::() + + text.lines.len().saturating_sub(1); // for newline after each line + let mut output = String::with_capacity(size); + + for spans in &text.lines { + for span in &spans.0 { + output.push_str(&span.content); + } + output.push('\n'); + } + output } } + impl<'a> IntoIterator for Text<'a> { type Item = Spans<'a>; type IntoIter = std::vec::IntoIter; diff --git a/helix-tui/src/widgets/table.rs b/helix-tui/src/widgets/table.rs index 539f6a61..2983072d 100644 --- a/helix-tui/src/widgets/table.rs +++ b/helix-tui/src/widgets/table.rs @@ -122,11 +122,8 @@ impl<'a> Row<'a> { } /// Returns the contents of cells as plain text, without styles and colors. - pub fn cell_text(&self) -> Vec { - self.cells - .iter() - .map(|cell| String::from(&cell.content)) - .collect() + pub fn cell_text(&self) -> impl Iterator + '_ { + self.cells.iter().map(|cell| String::from(&cell.content)) } } From 5c7db7aed54f52b3af6102517f81c9d70bb6d1fb Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sun, 25 Dec 2022 11:24:09 +0530 Subject: [PATCH 019/342] Replace menu::Item::{row, label} with format() --- helix-term/src/commands.rs | 10 +++++----- helix-term/src/commands/dap.rs | 8 ++++---- helix-term/src/commands/lsp.rs | 16 ++++++++++------ helix-term/src/ui/completion.rs | 7 +------ helix-term/src/ui/menu.rs | 22 ++++++++++------------ helix-term/src/ui/picker.rs | 6 +++--- helix-tui/src/widgets/table.rs | 6 ++++++ 7 files changed, 39 insertions(+), 36 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 15e4b47b..5b3ce68e 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -5,7 +5,7 @@ pub(crate) mod typed; pub use dap::*; use helix_vcs::Hunk; pub use lsp::*; -use tui::text::Spans; +use tui::widgets::Row; pub use typed::*; use helix_core::{ @@ -1864,7 +1864,7 @@ fn global_search(cx: &mut Context) { impl ui::menu::Item for FileResult { type Data = Option; - fn label(&self, current_path: &Self::Data) -> Spans { + fn format(&self, current_path: &Self::Data) -> Row { let relative_path = helix_core::path::get_relative_path(&self.path) .to_string_lossy() .into_owned(); @@ -2312,7 +2312,7 @@ fn buffer_picker(cx: &mut Context) { impl ui::menu::Item for BufferMeta { type Data = (); - fn label(&self, _data: &Self::Data) -> Spans { + fn format(&self, _data: &Self::Data) -> Row { let path = self .path .as_deref() @@ -2381,7 +2381,7 @@ fn jumplist_picker(cx: &mut Context) { impl ui::menu::Item for JumpMeta { type Data = (); - fn label(&self, _data: &Self::Data) -> Spans { + fn format(&self, _data: &Self::Data) -> Row { let path = self .path .as_deref() @@ -2454,7 +2454,7 @@ fn jumplist_picker(cx: &mut Context) { impl ui::menu::Item for MappableCommand { type Data = ReverseKeymap; - fn label(&self, keymap: &Self::Data) -> Spans { + fn format(&self, keymap: &Self::Data) -> Row { let fmt_binding = |bindings: &Vec>| -> String { bindings.iter().fold(String::new(), |mut acc, bind| { if !acc.is_empty() { diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index b182f28c..b3166e39 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -12,7 +12,7 @@ use helix_view::editor::Breakpoint; use serde_json::{to_value, Value}; use tokio_stream::wrappers::UnboundedReceiverStream; -use tui::text::Spans; +use tui::{text::Spans, widgets::Row}; use std::collections::HashMap; use std::future::Future; @@ -25,7 +25,7 @@ use helix_view::handlers::dap::{breakpoints_changed, jump_to_stack_frame, select impl ui::menu::Item for StackFrame { type Data = (); - fn label(&self, _data: &Self::Data) -> Spans { + fn format(&self, _data: &Self::Data) -> Row { self.name.as_str().into() // TODO: include thread_states in the label } } @@ -33,7 +33,7 @@ impl ui::menu::Item for StackFrame { impl ui::menu::Item for DebugTemplate { type Data = (); - fn label(&self, _data: &Self::Data) -> Spans { + fn format(&self, _data: &Self::Data) -> Row { self.name.as_str().into() } } @@ -41,7 +41,7 @@ impl ui::menu::Item for DebugTemplate { impl ui::menu::Item for Thread { type Data = ThreadStates; - fn label(&self, thread_states: &Self::Data) -> Spans { + fn format(&self, thread_states: &Self::Data) -> Row { format!( "{} ({})", self.name, diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 86b0c5fa..90b6d76c 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -5,7 +5,10 @@ use helix_lsp::{ util::{diagnostic_to_lsp_diagnostic, lsp_pos_to_pos, lsp_range_to_range, range_to_lsp_range}, OffsetEncoding, }; -use tui::text::{Span, Spans}; +use tui::{ + text::{Span, Spans}, + widgets::Row, +}; use super::{align_view, push_jump, Align, Context, Editor, Open}; @@ -46,7 +49,7 @@ impl ui::menu::Item for lsp::Location { /// Current working directory. type Data = PathBuf; - fn label(&self, cwdir: &Self::Data) -> Spans { + fn format(&self, cwdir: &Self::Data) -> Row { // The preallocation here will overallocate a few characters since it will account for the // URL's scheme, which is not used most of the time since that scheme will be "file://". // Those extra chars will be used to avoid allocating when writing the line number (in the @@ -80,7 +83,7 @@ impl ui::menu::Item for lsp::SymbolInformation { /// Path to currently focussed document type Data = Option; - fn label(&self, current_doc_path: &Self::Data) -> Spans { + fn format(&self, current_doc_path: &Self::Data) -> Row { if current_doc_path.as_ref() == Some(&self.location.uri) { self.name.as_str().into() } else { @@ -110,7 +113,7 @@ struct PickerDiagnostic { impl ui::menu::Item for PickerDiagnostic { type Data = (DiagnosticStyles, DiagnosticsFormat); - fn label(&self, (styles, format): &Self::Data) -> Spans { + fn format(&self, (styles, format): &Self::Data) -> Row { let mut style = self .diag .severity @@ -149,6 +152,7 @@ impl ui::menu::Item for PickerDiagnostic { Span::styled(&self.diag.message, style), Span::styled(code, style), ]) + .into() } } @@ -467,7 +471,7 @@ pub fn workspace_diagnostics_picker(cx: &mut Context) { impl ui::menu::Item for lsp::CodeActionOrCommand { type Data = (); - fn label(&self, _data: &Self::Data) -> Spans { + fn format(&self, _data: &Self::Data) -> Row { match self { lsp::CodeActionOrCommand::CodeAction(action) => action.title.as_str().into(), lsp::CodeActionOrCommand::Command(command) => command.title.as_str().into(), @@ -662,7 +666,7 @@ pub fn code_action(cx: &mut Context) { impl ui::menu::Item for lsp::Command { type Data = (); - fn label(&self, _data: &Self::Data) -> Spans { + fn format(&self, _data: &Self::Data) -> Row { self.title.as_str().into() } } diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index 11d7886a..824bafd8 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -1,7 +1,6 @@ use crate::compositor::{Component, Context, Event, EventResult}; use helix_view::{apply_transaction, editor::CompleteAction, ViewId}; use tui::buffer::Buffer as Surface; -use tui::text::Spans; use std::borrow::Cow; @@ -33,11 +32,7 @@ impl menu::Item for CompletionItem { .into() } - fn label(&self, _data: &Self::Data) -> Spans { - self.label.as_str().into() - } - - fn row(&self, _data: &Self::Data) -> menu::Row { + fn format(&self, _data: &Self::Data) -> menu::Row { menu::Row::new(vec![ menu::Cell::from(self.label.as_str()), menu::Cell::from(match self.kind { diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index b9c1f9de..e92578c5 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -4,7 +4,7 @@ use crate::{ compositor::{Callback, Component, Compositor, Context, Event, EventResult}, ctrl, key, shift, }; -use tui::{buffer::Buffer as Surface, text::Spans, widgets::Table}; +use tui::{buffer::Buffer as Surface, widgets::Table}; pub use tui::widgets::{Cell, Row}; @@ -18,28 +18,24 @@ pub trait Item { /// Additional editor state that is used for label calculation. type Data; - fn label(&self, data: &Self::Data) -> Spans; + fn format(&self, data: &Self::Data) -> Row; fn sort_text(&self, data: &Self::Data) -> Cow { - let label: String = self.label(data).into(); + let label: String = self.format(data).cell_text().collect(); label.into() } fn filter_text(&self, data: &Self::Data) -> Cow { - let label: String = self.label(data).into(); + let label: String = self.format(data).cell_text().collect(); label.into() } - - fn row(&self, data: &Self::Data) -> Row { - Row::new(vec![Cell::from(self.label(data))]) - } } impl Item for PathBuf { /// Root prefix to strip. type Data = PathBuf; - fn label(&self, root_path: &Self::Data) -> Spans { + fn format(&self, root_path: &Self::Data) -> Row { self.strip_prefix(root_path) .unwrap_or(self) .to_string_lossy() @@ -144,10 +140,10 @@ impl Menu { let n = self .options .first() - .map(|option| option.row(&self.editor_data).cells.len()) + .map(|option| option.format(&self.editor_data).cells.len()) .unwrap_or_default(); let max_lens = self.options.iter().fold(vec![0; n], |mut acc, option| { - let row = option.row(&self.editor_data); + let row = option.format(&self.editor_data); // maintain max for each column for (acc, cell) in acc.iter_mut().zip(row.cells.iter()) { let width = cell.content.width(); @@ -331,7 +327,9 @@ impl Component for Menu { (a + b - 1) / b } - let rows = options.iter().map(|option| option.row(&self.editor_data)); + let rows = options + .iter() + .map(|option| option.format(&self.editor_data)); let table = Table::new(rows) .style(style) .highlight_style(selected) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 05738ccf..ccf37eb2 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -410,10 +410,10 @@ impl Picker { let n = options .first() - .map(|option| option.row(&editor_data).cells.len()) + .map(|option| option.format(&editor_data).cells.len()) .unwrap_or_default(); let max_lens = options.iter().fold(vec![0; n], |mut acc, option| { - let row = option.row(&editor_data); + let row = option.format(&editor_data); // maintain max for each column for (acc, cell) in acc.iter_mut().zip(row.cells.iter()) { let width = cell.content.width(); @@ -729,7 +729,7 @@ impl Component for Picker { .skip(offset) .take(rows as usize) .map(|pmatch| &self.options[pmatch.index]) - .map(|option| option.row(&self.editor_data)) + .map(|option| option.format(&self.editor_data)) .map(|mut row| { const TEMP_CELL_SEP: &str = " "; diff --git a/helix-tui/src/widgets/table.rs b/helix-tui/src/widgets/table.rs index 2983072d..400f65e0 100644 --- a/helix-tui/src/widgets/table.rs +++ b/helix-tui/src/widgets/table.rs @@ -127,6 +127,12 @@ impl<'a> Row<'a> { } } +impl<'a, T: Into>> From for Row<'a> { + fn from(cell: T) -> Self { + Row::new(vec![cell.into()]) + } +} + /// A widget to display data in formatted columns. /// /// It is a collection of [`Row`]s, themselves composed of [`Cell`]s: From 1b69c7b4af8867f46365f6e04ab2ba29676c312c Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Wed, 18 Jan 2023 17:01:17 +0100 Subject: [PATCH 020/342] doc: add build instructions for musl-libc (#5572) --- book/src/install.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/book/src/install.md b/book/src/install.md index bf0ff079..e2e546c7 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -99,6 +99,14 @@ cargo install --path helix-term --locked This will install the `hx` binary to `$HOME/.cargo/bin` and build tree-sitter grammars in `./runtime/grammars`. +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: + +``` +RUSTFLAGS="-C target-feature=-crt-static" +``` + + Helix also needs its runtime files so make sure to copy/symlink the `runtime/` directory into the config directory (for example `~/.config/helix/runtime` on Linux/macOS). This location can be overridden via the `HELIX_RUNTIME` environment variable. From 7868e5f2d8ab193431e45b8bb3cd048e766328c4 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Wed, 18 Jan 2023 17:28:45 +0100 Subject: [PATCH 021/342] highlight non-bar cursors (#5575) --- helix-term/src/ui/editor.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index a19eb213..f8244600 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -392,7 +392,14 @@ impl EditorView { if range.head > range.anchor { // Standard case. let cursor_start = prev_grapheme_boundary(text, range.head); - spans.push((selection_scope, range.anchor..cursor_start)); + // non block cursors look like they exclude the cursor + let selection_end = + if selection_is_primary && !cursor_is_block && mode != Mode::Insert { + range.head + } else { + cursor_start + }; + spans.push((selection_scope, range.anchor..selection_end)); if !selection_is_primary || cursor_is_block { spans.push((cursor_scope, cursor_start..range.head)); } @@ -402,7 +409,16 @@ impl EditorView { if !selection_is_primary || cursor_is_block { spans.push((cursor_scope, range.head..cursor_end)); } - spans.push((selection_scope, cursor_end..range.anchor)); + // non block cursors look like they exclude the cursor + let selection_start = if selection_is_primary + && !cursor_is_block + && !(mode == Mode::Insert && cursor_end == range.anchor) + { + range.head + } else { + cursor_end + }; + spans.push((selection_scope, selection_start..range.anchor)); } } From 4d7082eb5c432e3cf0ff0fed565e8b1438d09ad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Delafargue?= Date: Wed, 18 Jan 2023 22:15:22 +0100 Subject: [PATCH 022/342] theme(zenburn): separate theme for selection.ui.primary (#5573) --- runtime/themes/zenburn.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/themes/zenburn.toml b/runtime/themes/zenburn.toml index 63f4ac72..4c019a2c 100644 --- a/runtime/themes/zenburn.toml +++ b/runtime/themes/zenburn.toml @@ -6,7 +6,8 @@ "ui.linenr" = { fg = "#9fafaf", bg = "#262626"} "ui.linenr.selected" = { modifiers = ["bold"]} "ui.popup" = { bg = "uibg" } -"ui.selection" = { bg = "#2f2f2f" } +"ui.selection" = { bg = "#304a3d" } +"ui.selection.primary" = { bg = "#2f2f2f" } "comment" = { fg = "#7f9f7f" } "comment.block.documentation" = { fg = "black", modifiers = ["bold"] } "ui.statusline" = { bg = "statusbg", fg = "#ccdc90" } From 0e5159ceca6be34977349156a32cc1a3ec53ab6e Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Wed, 18 Jan 2023 22:28:47 +0100 Subject: [PATCH 023/342] Fix panic for noop selecting join (#5579) --- helix-term/src/commands.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 5b3ce68e..8b742d00 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3939,6 +3939,11 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) { } } + // nothing to do, bail out early to avoid crashes later + if changes.is_empty() { + return; + } + changes.sort_unstable_by_key(|(from, _to, _text)| *from); changes.dedup(); From efeec1282cd82e255f54b10e94c51f51294598eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Thu, 19 Jan 2023 15:23:08 +0900 Subject: [PATCH 024/342] theme: Make github match github.com more closely This is a slight divergence from the VSCode theme, but it's more accurate. https://github.com/primer/github-vscode-theme/issues/111 https://github.com/primer/github-vscode-theme/issues/88 --- runtime/themes/github_dark.toml | 4 ++-- runtime/themes/github_light.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime/themes/github_dark.toml b/runtime/themes/github_dark.toml index cdb97aa3..2b6dbfde 100644 --- a/runtime/themes/github_dark.toml +++ b/runtime/themes/github_dark.toml @@ -9,9 +9,9 @@ keyword = "scale.red.3" namespace = "scale.orange.2" punctuation = "fg.default" "punctuation.delimiter" = "fg.default" -operator = "scale.red.3" +operator = "scale.blue.1" special = "scale.blue.1" -"variable.other.member" = "fg.default" +"variable.other.member" = "scale.blue.1" variable = "fg.default" "variable.parameter" = "scale.orange.2" "variable.builtin" = "scale.red.3" diff --git a/runtime/themes/github_light.toml b/runtime/themes/github_light.toml index d9969729..3492460e 100644 --- a/runtime/themes/github_light.toml +++ b/runtime/themes/github_light.toml @@ -9,9 +9,9 @@ keyword = "scale.red.5" namespace = "scale.orange.6" punctuation = "fg.default" "punctuation.delimiter" = "fg.default" -operator = "scale.red.5" +operator = "scale.blue.8" special = "scale.blue.8" -"variable.other.member" = "fg.default" +"variable.other.member" = "scale.blue.8" variable = "fg.default" "variable.parameter" = "scale.orange.6" "variable.builtin" = "scale.red.5" From 670c6b0d40a6d7bb0c4710cf7a17324a6f0ec479 Mon Sep 17 00:00:00 2001 From: luetage Date: Thu, 19 Jan 2023 17:05:18 +0100 Subject: [PATCH 025/342] Kanagawa: theme rulers and some miscellaneous fixes (#5571) * discern between rulers and whitespace, add sumiInk2 * darker background for menu and help, bold selection * bold modifier for insert and select * dark color for window separator * bring ruler, whitespace, indent-guide together --- runtime/themes/kanagawa.toml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/runtime/themes/kanagawa.toml b/runtime/themes/kanagawa.toml index f3811111..a12a0912 100644 --- a/runtime/themes/kanagawa.toml +++ b/runtime/themes/kanagawa.toml @@ -14,30 +14,31 @@ "ui.linenr" = { fg = "sumiInk4" } "ui.linenr.selected" = { fg = "roninYellow" } +"ui.virtual.ruler" = { bg = "sumiInk2" } +"ui.virtual.whitespace" = "waveBlue1" "ui.virtual.indent-guide" = "sumiInk4" "ui.statusline" = { fg = "oldWhite", bg = "sumiInk0" } "ui.statusline.inactive" = { fg = "fujiGray", bg = "sumiInk0" } "ui.statusline.normal" = { fg = "sumiInk0", bg = "crystalBlue", modifiers = ["bold"] } -"ui.statusline.insert" = { fg = "sumiInk0", bg = "autumnGreen" } -"ui.statusline.select" = { fg = "sumiInk0", bg = "oniViolet" } +"ui.statusline.insert" = { fg = "sumiInk0", bg = "autumnGreen", modifiers = ["bold"] } +"ui.statusline.select" = { fg = "sumiInk0", bg = "oniViolet", modifiers = ["bold"] } "ui.bufferline" = { fg = "oldWhite", bg = "sumiInk0" } "ui.bufferline.inactive" = { fg = "fujiGray", bg = "sumiInk0" } "ui.popup" = { fg = "fujiWhite", bg = "sumiInk0" } -"ui.window" = { fg = "fujiWhite" } -"ui.help" = { fg = "fujiWhite", bg = "sumiInk1" } +"ui.window" = { fg = "sumiInk0" } +"ui.help" = { fg = "fujiWhite", bg = "sumiInk0" } "ui.text" = "fujiWhite" "ui.text.focus" = { fg = "fujiWhite", bg = "waveBlue1", modifiers = ["bold"] } -"ui.virtual" = "waveBlue1" "ui.cursor" = { fg = "waveBlue1", bg = "fujiWhite"} "ui.cursor.primary" = { fg = "waveBlue1", bg = "seaFoam" } "ui.cursor.match" = { fg = "seaFoam", modifiers = ["bold"] } "ui.highlight" = { fg = "fujiWhite", bg = "waveBlue2" } -"ui.menu" = { fg = "fujiWhite", bg = "sumiInk1" } -"ui.menu.selected" = { fg = "fujiWhite", bg = "waveBlue1" } +"ui.menu" = { fg = "fujiWhite", bg = "sumiInk0" } +"ui.menu.selected" = { fg = "fujiWhite", bg = "waveBlue1", modifiers = ["bold"] } "ui.cursorline.primary" = { bg = "sumiInk3"} @@ -107,7 +108,8 @@ fujiWhite = "#DCD7BA" # default foreground oldWhite = "#C8C093" # dark foreground, e.g. statuslines sumiInk0 = "#16161D" # dark background, e.g. statuslines, floating windows sumiInk1 = "#1F1F28" # default background -sumiInk3 = "#363646" # lighter background, e.g. colorcolumns and folds +sumiInk2 = "#2A2A37" # lighter background, e.g. colorcolumns, folds +sumiInk3 = "#363646" # lighter background, e.g. cursorline sumiInk4 = "#54546D" # darker foreground, e.g. linenumbers, fold column waveBlue1 = "#223249" # popup background, visual selection background waveBlue2 = "#2D4F67" # popup selection background, search background From 94ef6fb69b837229c1e7e84967a79fc53259b00b Mon Sep 17 00:00:00 2001 From: Nachum Barcohen <38861757+nabaco@users.noreply.github.com> Date: Thu, 19 Jan 2023 18:08:56 +0200 Subject: [PATCH 026/342] Add more file-types for python (#5593) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index a66605b2..c37860d3 100644 --- a/languages.toml +++ b/languages.toml @@ -473,7 +473,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-html", rev = "29f53 name = "python" scope = "source.python" injection-regex = "python" -file-types = ["py"] +file-types = ["py","pyi","py3","pyw","ptl",".pythonstartup",".pythonrc","SConstruct"] shebangs = ["python"] roots = [] comment-token = "#" From 4535d0fa74afc5bdd84ca698480249d20fbd8b61 Mon Sep 17 00:00:00 2001 From: eugene yokota Date: Thu, 19 Jan 2023 12:26:12 -0500 Subject: [PATCH 027/342] highlight(scala): update to fix potential crash (#5576) * highlight(scala): update to fix crash tree-sitter-scala has recently add a fix to workaround segv crashes in other editors. Not sure if it happens to Helix as well, but it's probably a good idea to use the latest. * highlight(scala): String interpolator support This captures String interpolator as `function` Co-authored-by: Chris Kipp --- languages.toml | 2 +- runtime/queries/scala/highlights.scm | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index c37860d3..b6f939aa 100644 --- a/languages.toml +++ b/languages.toml @@ -1065,7 +1065,7 @@ config = { "isHttpEnabled" = true } [[grammar]] name = "scala" -source = { git = "https://github.com/tree-sitter/tree-sitter-scala", rev = "db1c8c23d7996476a791db85a0d292084c19c232" } +source = { git = "https://github.com/tree-sitter/tree-sitter-scala", rev = "f6bbf35de41653b409ca9a3537a154f2b095ef64" } [[language]] name = "dockerfile" diff --git a/runtime/queries/scala/highlights.scm b/runtime/queries/scala/highlights.scm index 07307875..67603fdd 100644 --- a/runtime/queries/scala/highlights.scm +++ b/runtime/queries/scala/highlights.scm @@ -112,6 +112,9 @@ (generic_function function: (identifier) @function) +(interpolated_string_expression + interpolator: (identifier) @function) + ( (identifier) @function.builtin (#match? @function.builtin "^super$") From 8e10c592b90383a90b7e4a9335d323f8fab99ab5 Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 20 Jan 2023 00:20:40 -0600 Subject: [PATCH 028/342] add lua injection regex (#5606) --- languages.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/languages.toml b/languages.toml index b6f939aa..32383513 100644 --- a/languages.toml +++ b/languages.toml @@ -717,6 +717,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-ocaml", rev = "23d4 [[language]] name = "lua" +injection-regex = "lua" scope = "source.lua" file-types = ["lua"] shebangs = ["lua"] From 338f207d4bb4b25dfcf746a9f207dfac9a5025bd Mon Sep 17 00:00:00 2001 From: LeoniePhiline <22329650+LeoniePhiline@users.noreply.github.com> Date: Thu, 19 Jan 2023 23:12:37 +0100 Subject: [PATCH 029/342] fix(theme): Replace non-palette color "magenta" with palette color "red" in monokai_pro_spectrum --- runtime/themes/monokai_pro_spectrum.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/themes/monokai_pro_spectrum.toml b/runtime/themes/monokai_pro_spectrum.toml index 451f7986..1dc6de46 100644 --- a/runtime/themes/monokai_pro_spectrum.toml +++ b/runtime/themes/monokai_pro_spectrum.toml @@ -65,7 +65,7 @@ "variable.parameter" = "#f59762" # error -"error" = { bg = "magenta", fg = "yellow" } +"error" = { bg = "red", fg = "yellow" } # annotations, decorators "special" = "#f59762" @@ -88,7 +88,7 @@ # make diagnostic underlined, to distinguish with selection text. "diagnostic.warning" = { underline = { color = "orange", style = "curl" } } -"diagnostic.error" = { underline = { color = "magenta", style = "curl" } } # maybe should be red? +"diagnostic.error" = { underline = { color = "red", style = "curl" } } "diagnostic.info" = { underline = { color = "base8", style = "curl" } } "diagnostic.hint" = { underline = { color = "base8", style = "curl" } } From 248a9f3635ac7ea396c2b1b16a57637e7f23766d Mon Sep 17 00:00:00 2001 From: LeoniePhiline <22329650+LeoniePhiline@users.noreply.github.com> Date: Thu, 19 Jan 2023 23:20:50 +0100 Subject: [PATCH 030/342] fix(theme): Fix error background-foreground-contrast in monokai_pro_spectrum --- runtime/themes/monokai_pro_spectrum.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/themes/monokai_pro_spectrum.toml b/runtime/themes/monokai_pro_spectrum.toml index 1dc6de46..76123fcf 100644 --- a/runtime/themes/monokai_pro_spectrum.toml +++ b/runtime/themes/monokai_pro_spectrum.toml @@ -65,7 +65,7 @@ "variable.parameter" = "#f59762" # error -"error" = { bg = "red", fg = "yellow" } +"error" = { fg = "red", modifiers = ["bold"] } # annotations, decorators "special" = "#f59762" From edd0ba7f19c662555128c4b112faed0120d91197 Mon Sep 17 00:00:00 2001 From: yashpalgoyal1304 Date: Fri, 20 Jan 2023 21:35:34 +0530 Subject: [PATCH 031/342] book: Link MSYS2 proper command page (#5601) --- book/src/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/install.md b/book/src/install.md index e2e546c7..792799d7 100644 --- a/book/src/install.md +++ b/book/src/install.md @@ -69,7 +69,7 @@ choco install helix **MSYS2:** -Choose the proper command for your system from below: +Choose the [proper command](https://www.msys2.org/docs/package-naming/) for your system from below: - For 32 bit Windows 7 or above: From 68fc10903aad7b5dbb5b8be4ee17343e1a1b8f6c Mon Sep 17 00:00:00 2001 From: Timothy DeHerrera Date: Fri, 20 Jan 2023 12:35:52 -0700 Subject: [PATCH 032/342] themes: Extend snazzy (#3971) --- runtime/themes/snazzy.toml | 83 +++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 19 deletions(-) diff --git a/runtime/themes/snazzy.toml b/runtime/themes/snazzy.toml index b36d1243..110e2093 100644 --- a/runtime/themes/snazzy.toml +++ b/runtime/themes/snazzy.toml @@ -1,25 +1,55 @@ -# Author : Sebastian Zivota # Author : Timothy DeHerrera -"comment" = { fg = "comment" } -"constant" = { fg = "purple" } -"constant.character.escape" = { fg = "magenta" } -"function" = { fg = "green" } -"keyword" = { fg = "magenta" } -"operator" = { fg = "magenta" } -"punctuation" = { fg = "foreground" } -"string" = { fg = "yellow" } -"string.special.path" = { fg = "blue" } -"string.regexp" = { fg = "red" } -"tag" = { fg = "magenta" } -"type" = { fg = "cyan", modifiers = ["italic"] } -"type.enum.variant" = { fg = "foreground", modifiers = ["italic"] } -"variable" = { fg = "foreground" } -"variable.builtin" = { fg = "cyan", modifiers = ["italic"] } +"comment".fg = "comment" + +"constant".fg = "purple" +"constant.builtin".fg = "olive" +"constant.character".fg = "carnation" +"constant.character.escape".fg = "magenta" +"constant.numeric".fg = "cyan" +"constant.numeric.float".fg = "red" + +"function".fg = "green" +"function.builtin".fg = "sand" +"function.macro".fg = "blue" +"function.method".fg = "opal" + +"keyword" = { fg = "magenta", modifiers = ["bold"] } +"keyword.operator" = { fg = "coral", modifiers = ["bold"] } +"keyword.function" = { fg = "lilac", modifiers = ["bold"] } +"keyword.control" = { fg = "carnation", modifiers = ["bold"]} +"keyword.control.exception" = { fg = "red", modifiers = ["bold"] } +"keyword.storage" = { fg = "coral", modifiers = ["bold"] } + +"operator".fg = "coral" + +"punctuation".fg = "magenta" +"punctuation.delimiter".fg = "coral" +"punctuation.bracket".fg = "foreground" + +"string".fg = "yellow" +"string.special".fg = "blue" +"string.regexp".fg = "red" +"tag".fg = "carnation" +"attribute".fg = "opal" + +"type".fg = "opal" +"type.variant".fg = "sand" +"type.builtin".fg = "yellow" +"type.enum.variant".fg = "sand" + +"variable".fg = "cyan" +"variable.builtin".fg = "olive" +"variable.other.member".fg = "lilac" "variable.parameter" = { fg ="blue", modifiers = ["italic"] } -"diff.plus" = { fg = "green" } -"diff.delta" = { fg = "blue" } -"diff.minus" = { fg = "red" } +"namespace".fg = "olive" +"constructor".fg = "sand" +"special".fg = "magenta" +"label".fg = "magenta" + +"diff.plus".fg = "green" +"diff.delta".fg = "blue" +"diff.minus".fg = "red" "ui.background" = { fg = "foreground", bg = "background" } "ui.cursor" = { fg = "background", bg = "blue", modifiers = ["dim"] } @@ -36,16 +66,21 @@ "ui.cursorline" = { bg = "background_dark" } "ui.statusline" = { fg = "foreground", bg = "background_dark" } "ui.statusline.inactive" = { fg = "comment", bg = "background_dark" } +"ui.statusline.insert" = { fg = "olive", bg = "background_dark" } +"ui.statusline.normal" = { fg = "opal", bg = "background_dark" } +"ui.statusline.select" = { fg = "carnation", bg = "background_dark" } "ui.text" = { fg = "foreground" } "ui.text.focus" = { fg = "cyan" } "ui.window" = { fg = "foreground" } "ui.virtual.whitespace" = { fg = "comment" } +"ui.virtual.indent-guide" = { fg = "opal" } "ui.virtual.ruler" = { bg = "background_dark" } "error" = { fg = "red" } "warning" = { fg = "cyan" } "markup.heading" = { fg = "purple", modifiers = ["bold"] } +"markup.link.label" = { fg = "blue", modifiers = ["italic"] } "markup.list" = "cyan" "markup.bold" = { fg = "blue", modifiers = ["bold"] } "markup.italic" = { fg = "yellow", modifiers = ["italic"] } @@ -61,6 +96,8 @@ primary_highlight = "#800049" secondary_highlight = "#4d4f66" foreground = "#eff0eb" comment = "#a39e9b" + +# main colors red = "#ff5c57" blue = "#57c7ff" yellow = "#f3f99d" @@ -68,3 +105,11 @@ green = "#5af78e" purple = "#bd93f9" cyan = "#9aedfe" magenta = "#ff6ac1" + +# aux colors +lilac = "#c9c5fb" +coral = "#f97c7c" +sand = "#ffab6f" +carnation = "#f99fc6" +olive = "#b6d37c" +opal = "#b1d7c7" From a20a96abdcfbea3b3eb890bfc266850938434a90 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 22 Jan 2023 02:13:43 +0800 Subject: [PATCH 033/342] Remove apply_transaction helper (#5598) --- helix-term/src/commands.rs | 57 ++++++++++++++++---------------- helix-term/src/commands/lsp.rs | 4 +-- helix-term/src/commands/typed.rs | 13 +++----- helix-term/src/ui/completion.rs | 8 ++--- helix-term/src/ui/editor.rs | 3 +- helix-term/tests/test/helpers.rs | 4 +-- helix-view/src/document.rs | 9 ++--- helix-view/src/editor.rs | 2 +- helix-view/src/lib.rs | 11 ------ helix-view/src/view.rs | 2 -- 10 files changed, 46 insertions(+), 67 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 8b742d00..e773a2c7 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -26,7 +26,6 @@ use helix_core::{ SmallVec, Tendril, Transaction, }; use helix_view::{ - apply_transaction, clipboard::ClipboardType, document::{FormatterError, Mode, SCRATCH_BUFFER_NAME}, editor::{Action, Motion}, @@ -864,7 +863,7 @@ fn align_selections(cx: &mut Context) { changes.sort_unstable_by_key(|(from, _, _)| *from); let transaction = Transaction::change(doc.text(), changes.into_iter()); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } fn goto_window(cx: &mut Context, align: Align) { @@ -1316,7 +1315,7 @@ fn replace(cx: &mut Context) { } }); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); exit_select_mode(cx); } }) @@ -1334,7 +1333,7 @@ where (range.from(), range.to(), Some(text)) }); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } fn switch_case(cx: &mut Context) { @@ -2159,7 +2158,7 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) { let transaction = Transaction::change_by_selection(doc.text(), selection, |range| { (range.from(), range.to(), None) }); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); match op { Operation::Delete => { @@ -2177,7 +2176,7 @@ fn delete_selection_insert_mode(doc: &mut Document, view: &mut View, selection: let transaction = Transaction::change_by_selection(doc.text(), selection, |range| { (range.from(), range.to(), None) }); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } fn delete_selection(cx: &mut Context) { @@ -2273,7 +2272,7 @@ fn append_mode(cx: &mut Context) { doc.text(), [(end, end, Some(doc.line_ending.as_str().into()))].into_iter(), ); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } let selection = doc.selection(view.id).clone().transform(|range| { @@ -2583,7 +2582,7 @@ async fn make_format_callback( if let Ok(format) = format { if doc.version() == doc_version { - apply_transaction(&format, doc, view); + doc.apply(&format, view.id); doc.append_changes_to_history(view); doc.detect_indent_and_line_ending(); view.ensure_cursor_in_view(doc, scrolloff); @@ -2676,7 +2675,7 @@ fn open(cx: &mut Context, open: Open) { transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } // o inserts a new line after each line with a selection @@ -3104,7 +3103,7 @@ pub mod insert { let (view, doc) = current!(cx.editor); if let Some(t) = transaction { - apply_transaction(&t, doc, view); + doc.apply(&t, view.id); } // TODO: need a post insert hook too for certain triggers (autocomplete, signature help, etc) @@ -3126,7 +3125,7 @@ pub mod insert { &doc.selection(view.id).clone().cursors(doc.text().slice(..)), indent, ); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } pub fn insert_newline(cx: &mut Context) { @@ -3231,7 +3230,7 @@ pub mod insert { transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); let (view, doc) = current!(cx.editor); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } pub fn delete_char_backward(cx: &mut Context) { @@ -3326,7 +3325,7 @@ pub mod insert { } }); let (view, doc) = current!(cx.editor); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } @@ -3344,7 +3343,7 @@ pub mod insert { None, ) }); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } @@ -3625,7 +3624,7 @@ fn paste_impl( transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); } - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } pub(crate) fn paste_bracketed_value(cx: &mut Context, contents: String) { @@ -3717,7 +3716,7 @@ fn replace_with_yanked(cx: &mut Context) { } }); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); exit_select_mode(cx); } } @@ -3741,7 +3740,7 @@ fn replace_selections_with_clipboard_impl( ) }); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); doc.append_changes_to_history(view); } Err(e) => return Err(e.context("Couldn't get system clipboard contents")), @@ -3813,7 +3812,7 @@ fn indent(cx: &mut Context) { Some((pos, pos, Some(indent.clone()))) }), ); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } fn unindent(cx: &mut Context) { @@ -3852,7 +3851,7 @@ fn unindent(cx: &mut Context) { let transaction = Transaction::change(doc.text(), changes.into_iter()); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } fn format_selections(cx: &mut Context) { @@ -3907,7 +3906,7 @@ fn format_selections(cx: &mut Context) { language_server.offset_encoding(), ); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } fn join_selections_impl(cx: &mut Context, select_space: bool) { @@ -3966,7 +3965,7 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) { Transaction::change(doc.text(), changes.into_iter()) }; - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } fn keep_or_remove_selections_impl(cx: &mut Context, remove: bool) { @@ -4109,7 +4108,7 @@ fn toggle_comments(cx: &mut Context) { .map(|tc| tc.as_ref()); let transaction = comment::toggle_line_comments(doc.text(), doc.selection(view.id), token); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); exit_select_mode(cx); } @@ -4165,7 +4164,7 @@ fn rotate_selection_contents(cx: &mut Context, direction: Direction) { .map(|(range, fragment)| (range.from(), range.to(), Some(fragment))), ); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } fn rotate_selection_contents_forward(cx: &mut Context) { @@ -4698,7 +4697,7 @@ fn surround_add(cx: &mut Context) { let transaction = Transaction::change(doc.text(), changes.into_iter()) .with_selection(Selection::new(ranges, selection.primary_index())); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); exit_select_mode(cx); }) } @@ -4738,7 +4737,7 @@ fn surround_replace(cx: &mut Context) { (pos, pos + 1, Some(t)) }), ); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); exit_select_mode(cx); }); }) @@ -4766,7 +4765,7 @@ fn surround_delete(cx: &mut Context) { let transaction = Transaction::change(doc.text(), change_pos.into_iter().map(|p| (p, p + 1, None))); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); exit_select_mode(cx); }) } @@ -4981,7 +4980,7 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) { if behavior != &ShellBehavior::Ignore { let transaction = Transaction::change(doc.text(), changes.into_iter()) .with_selection(Selection::new(ranges, selection.primary_index())); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); doc.append_changes_to_history(view); } @@ -5044,7 +5043,7 @@ fn add_newline_impl(cx: &mut Context, open: Open) { }); let transaction = Transaction::change(text, changes); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } enum IncrementDirection { @@ -5111,7 +5110,7 @@ fn increment_impl(cx: &mut Context, increment_direction: IncrementDirection) { let new_selection = Selection::new(new_selection_ranges, selection.primary_index()); let transaction = Transaction::change(doc.text(), changes.into_iter()); let transaction = transaction.with_selection(new_selection); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } } diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 90b6d76c..578eb608 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -13,7 +13,7 @@ use tui::{ use super::{align_view, push_jump, Align, Context, Editor, Open}; use helix_core::{path, Selection}; -use helix_view::{apply_transaction, document::Mode, editor::Action, theme::Style}; +use helix_view::{document::Mode, editor::Action, theme::Style}; use crate::{ compositor::{self, Compositor}, @@ -800,7 +800,7 @@ pub fn apply_workspace_edit( offset_encoding, ); let view = view_mut!(editor, view_id); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); doc.append_changes_to_history(view); }; diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index de24c4fb..bd91df5a 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -4,10 +4,7 @@ use crate::job::Job; use super::*; -use helix_view::{ - apply_transaction, - editor::{Action, CloseError, ConfigEvent}, -}; +use helix_view::editor::{Action, CloseError, ConfigEvent}; use ui::completers::{self, Completer}; #[derive(Clone)] @@ -480,7 +477,7 @@ fn set_line_ending( } }), ); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); doc.append_changes_to_history(view); Ok(()) @@ -925,7 +922,7 @@ fn replace_selections_with_clipboard_impl( (range.from(), range.to(), Some(contents.as_str().into())) }); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); doc.append_changes_to_history(view); Ok(()) } @@ -1596,7 +1593,7 @@ fn sort_impl( .map(|(s, fragment)| (s.from(), s.to(), Some(fragment))), ); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); doc.append_changes_to_history(view); Ok(()) @@ -1640,7 +1637,7 @@ fn reflow( (range.from(), range.to(), Some(reflowed_text)) }); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); doc.append_changes_to_history(view); view.ensure_cursor_in_view(doc, scrolloff); diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index 824bafd8..2eca709d 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -1,5 +1,5 @@ use crate::compositor::{Component, Context, Event, EventResult}; -use helix_view::{apply_transaction, editor::CompleteAction, ViewId}; +use helix_view::{editor::CompleteAction, ViewId}; use tui::buffer::Buffer as Surface; use std::borrow::Cow; @@ -183,7 +183,7 @@ impl Completion { // initialize a savepoint doc.savepoint(); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); editor.last_completion = Some(CompleteAction { trigger_offset, @@ -203,7 +203,7 @@ impl Completion { trigger_offset, ); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); editor.last_completion = Some(CompleteAction { trigger_offset, @@ -233,7 +233,7 @@ impl Completion { additional_edits.clone(), offset_encoding, // TODO: should probably transcode in Client ); - apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } } } diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index f8244600..a0518964 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -17,7 +17,6 @@ use helix_core::{ visual_coords_at_pos, LineEnding, Position, Range, Selection, Transaction, }; use helix_view::{ - apply_transaction, document::{Mode, SCRATCH_BUFFER_NAME}, editor::{CompleteAction, CursorShapeConfig}, graphics::{Color, CursorKind, Modifier, Rect, Style}, @@ -1048,7 +1047,7 @@ impl EditorView { (shift_position(start), shift_position(end), t) }), ); - apply_transaction(&tx, doc, view); + doc.apply(&tx, view.id); } InsertEvent::TriggerCompletion => { let (_, doc) = current!(cxt.editor); diff --git a/helix-term/tests/test/helpers.rs b/helix-term/tests/test/helpers.rs index 2c5043d6..a0f3a32e 100644 --- a/helix-term/tests/test/helpers.rs +++ b/helix-term/tests/test/helpers.rs @@ -130,7 +130,7 @@ pub async fn test_key_sequence_with_input_text>( }) .with_selection(test_case.in_selection.clone()); - helix_view::apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); test_key_sequence( &mut app, @@ -315,7 +315,7 @@ impl AppBuilder { .with_selection(selection); // replace the initial text with the input text - helix_view::apply_transaction(&trans, doc, view); + doc.apply(&trans, view.id); } Ok(app) diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 856e5628..6b33ea6a 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -27,7 +27,7 @@ use helix_core::{ }; use crate::editor::RedrawHandle; -use crate::{apply_transaction, DocumentId, Editor, View, ViewId}; +use crate::{DocumentId, Editor, View, ViewId}; /// 8kB of buffer space for encoding and decoding `Rope`s. const BUF_SIZE: usize = 8192; @@ -650,7 +650,7 @@ impl Document { // This is not considered a modification of the contents of the file regardless // of the encoding. let transaction = helix_core::diff::compare_ropes(self.text(), &rope); - apply_transaction(&transaction, self, view); + self.apply(&transaction, view.id); self.append_changes_to_history(view); self.reset_modified(); @@ -852,9 +852,6 @@ impl Document { } /// Apply a [`Transaction`] to the [`Document`] to change its text. - /// Instead of calling this function directly, use [crate::apply_transaction] - /// to ensure that the transaction is applied to the appropriate [`View`] as - /// well. pub fn apply(&mut self, transaction: &Transaction, view_id: ViewId) -> bool { // store the state just before any changes are made. This allows us to undo to the // state just before a transaction was applied. @@ -911,7 +908,7 @@ impl Document { pub fn restore(&mut self, view: &mut View) { if let Some(revert) = self.savepoint.take() { - apply_transaction(&revert, self, view); + self.apply(&revert, view.id); } } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 4a44a00c..3ee0325d 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1502,6 +1502,6 @@ fn try_restore_indent(doc: &mut Document, view: &mut View) { let line_start_pos = text.line_to_char(range.cursor_line(text)); (line_start_pos, pos, None) }); - crate::apply_transaction(&transaction, doc, view); + doc.apply(&transaction, view.id); } } diff --git a/helix-view/src/lib.rs b/helix-view/src/lib.rs index 9cf36ae0..9a980446 100644 --- a/helix-view/src/lib.rs +++ b/helix-view/src/lib.rs @@ -66,17 +66,6 @@ pub fn align_view(doc: &Document, view: &mut View, align: Align) { view.offset.row = line.saturating_sub(relative); } -/// Applies a [`helix_core::Transaction`] to the given [`Document`] -/// and [`View`]. -pub fn apply_transaction( - transaction: &helix_core::Transaction, - doc: &mut Document, - view: &View, -) -> bool { - // TODO remove this helper function. Just call Document::apply everywhere directly. - doc.apply(transaction, view.id) -} - pub use document::Document; pub use editor::Editor; pub use theme::Theme; diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index c09d502d..23fb85c9 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -380,8 +380,6 @@ impl View { // } /// Applies a [`Transaction`] to the view. - /// Instead of calling this function directly, use [crate::apply_transaction] - /// which applies a transaction to the [`Document`] and view together. pub fn apply(&mut self, transaction: &Transaction, doc: &mut Document) { self.jumps.apply(transaction, doc); self.doc_revisions From 99fcb108609a90c922921d139291b7f99d5cb06a Mon Sep 17 00:00:00 2001 From: eugene yokota Date: Sat, 21 Jan 2023 14:18:16 -0500 Subject: [PATCH 034/342] theme: monkai_aqua variant (#5578) Current monokai (pro or otherwise) seems too red and green, missingthe bright aqua / cyan color found in Sublime's Monokai. This adds a variant of monokai, which I named monokai_aqua. --- runtime/themes/monokai_aqua.toml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 runtime/themes/monokai_aqua.toml diff --git a/runtime/themes/monokai_aqua.toml b/runtime/themes/monokai_aqua.toml new file mode 100644 index 00000000..0fe48254 --- /dev/null +++ b/runtime/themes/monokai_aqua.toml @@ -0,0 +1,17 @@ +inherits = "monokai" + +"keyword.control.import" = { fg = "cyan", modifiers = ["italic"] } +"keyword.function" = { fg = "cyan", modifiers = ["italic"] } +"keyword.storage.type" = { fg = "cyan", modifiers = ["italic"] } + +"namespace" = { fg = "text" } + +"type" = { fg = "type", modifiers = ["bold"] } + +"ui.statusline.normal" = { fg = "light-black", bg = "cyan" } +"ui.statusline.insert" = { fg = "light-black", bg = "green" } +"ui.statusline.select" = { fg = "light-black", bg = "purple" } + +[palette] +cyan = "#66D9EF" +type = "#66D9EF" From 42b040141632e332c837765f2eb1538ec9c53a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADtor=20Galv=C3=A3o?= Date: Sat, 21 Jan 2023 19:19:24 +0000 Subject: [PATCH 035/342] tutor: Change "Type" to "Press" for specials keys and modifiers (#5609) --- runtime/tutor | 74 +++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/runtime/tutor b/runtime/tutor index 0e693dc0..d51c57c2 100644 --- a/runtime/tutor +++ b/runtime/tutor @@ -48,13 +48,13 @@ _________________________________________________________________ 1. Type : to enter Command mode. Your cursor will move to the bottom of the screen. - 2. Type q or quit and type Enter to exit Helix. + 2. Type q or quit and press Enter to exit Helix. Note: The quit command will fail if there are unsaved changes. To force quit and DISCARD these changes, type q! or quit!. You will learn how to save files later. - To exit Command mode without entering a command, type Escape. + To exit Command mode without entering a command, press Escape. Now, move on to the next lesson. @@ -96,7 +96,7 @@ _________________________________________________________________ 2. Move to a place in the line which is missing text and type i to enter Insert mode. Keys you type will now type text. 3. Enter the missing text. - 4. Type Escape to exit Insert mode and return to Normal mode. + 4. Press Escape to exit Insert mode and return to Normal mode. 5. Repeat until the line matches the line below it. --> Th stce misg so. @@ -119,7 +119,7 @@ _________________________________________________________________ 2. Open a file in Helix by running: hx FILENAME 3. Make some edits to the file. 4. Type : to enter Command mode. - 5. Type w or write, and type Enter to save the file. + 5. Type w or write, and press Enter to save the file. You can also type wq or write-quit to save and exit. @@ -145,7 +145,7 @@ _________________________________________________________________ * Type d to delete the character at the cursor. - * Type i to enter Insert mode and type text. Type Escape to + * Type i to enter Insert mode and type text. Press Escape to return to Normal mode. @@ -469,7 +469,7 @@ _________________________________________________________________ Type N to go to the previous search match. 1. Type / and type in a common word, like 'banana'. - 2. Type Enter to confirm the search. + 2. Press Enter to confirm the search. 3. Use n and N to cycle through the matches. Searching uses regular expressions, allowing you to target more @@ -524,7 +524,7 @@ _________________________________________________________________ --> Fix th two nes at same ime. Fix these two lines at the same time. - Note: Type Alt-C to do the same above the cursor. + Note: Press Alt-C to do the same above the cursor. ================================================================= = 5.2 THE SELECT COMMAND = @@ -535,11 +535,11 @@ _________________________________________________________________ 1. Move the cursor to the line marked '-->' below. 2. Type x to select the line. 3. Type s. A prompt will appear. - 4. Type 'apples' and type Enter. Both occurrences of + 4. Type 'apples' and press Enter. Both occurrences of 'apples' in the line will be selected. 5. You can now type c and change 'apples' to something else, like 'oranges'. - 6. Type Escape to exit Insert mode. + 6. Press Escape to exit Insert mode. 7. Type , to remove the second cursor. --> I like to eat apples since my favorite fruit is apples. @@ -558,7 +558,7 @@ _________________________________________________________________ 1. Move the cursor to the line marked '-->' below. 2. Select the line with x and then type s. 3. Type ' +' to select any amount of consecutive spaces >1, - then type Enter. + then press Enter. 4. Type c and change the matches to single spaces. --> This sentence has some extra spaces. @@ -596,11 +596,11 @@ _________________________________________________________________ = 5.5 SPLIT SELECTION INTO LINES = ================================================================= - Type Alt-s to split the selection(s) on newlines. + Press Alt-s to split the selection(s) on newlines. 1. Move the cursor to the first row of the table below. 2. Select the entire table with 6x. - 3. Type Alt-s to split into selections at each line. + 3. Press Alt-s to split into selections at each line. 4. Align the table with &. | FRUIT | AMOUNT | @@ -626,7 +626,7 @@ _________________________________________________________________ * Type & to align selections. - * Type Alt-s to split the selection into lines. + * Press Alt-s to split the selection into lines. @@ -685,7 +685,7 @@ _________________________________________________________________ ================================================================= Type . to repeat the last insert command. - Type Alt-. to repeat the last f / t selection. + Press Alt-. to repeat the last f / t selection. 1. Move the cursor to the line marked '-->' below. 2. Make a change, insertion or appendage and repeat it with . . @@ -712,7 +712,7 @@ _________________________________________________________________ * Type r to replace selected characters. * Type . to repeat the last insertion. - * Type Alt-. to repeat the last f / t selection. + * Press Alt-. to repeat the last f / t selection. @@ -794,13 +794,13 @@ lines. = 7.4 INCREMENTING AND DECREMENTING = ================================================================= - Type Ctrl-a to increment the number under selection. - Type Ctrl-x to decrement the number under selection. + Press Ctrl-a to increment the number under selection. + Press Ctrl-x to decrement the number under selection. 1. Move the cursor to the third line marked '-->' below. - 2. Type Ctrl-a to increment the second point marked 2. + 2. Press Ctrl-a to increment the second point marked 2. 3. Repeat for the point marked 3. - 4. Move to the last point and type Ctrl-x to decrement the 6. + 4. Move to the last point and press Ctrl-x to decrement the 6. --> 1) First point. --> 2) Added point. @@ -822,8 +822,8 @@ lines. * Type < and > to indent / outdent lines. - * Type Ctrl-a to increment the selected number. - * Type Ctrl-x to decrement the selected number. + * Press Ctrl-a to increment the selected number. + * Press Ctrl-x to decrement the selected number. @@ -952,15 +952,15 @@ lines. searching or jumping to the definition of a function in code. It stores these in what's called the jumplist. - Type Ctrl-s to manually save your current position to + Press Ctrl-s to manually save your current position to the jumplist. - Type Ctrl-i ("in") and Ctrl-o ("out") to move forward and + Press Ctrl-i ("in") and Ctrl-o ("out") to move forward and backwards in the jumplist respectively. - 1. Type Ctrl-s somewhere. + 1. Press Ctrl-s somewhere. 2. Move far away in the file. - 3. Type Ctrl-o (just once!) to come back to where you saved. + 3. Press Ctrl-o (just once!) to come back to where you saved. @@ -975,8 +975,8 @@ lines. * Type n / N in Visual mode to add selections on each search match. - * Type Ctrl-s to save position to the jumplist. - * Type Ctrl-i and Ctrl-o to go forward and backward in the + * Press Ctrl-s to save position to the jumplist. + * Press Ctrl-i and Ctrl-o to go forward and backward in the jumplist. @@ -995,7 +995,7 @@ lines. Type ) and ( to cycle the primary selection forward and backward through selections respectively. - Type Alt-, to remove the primary selection. + Press Alt-, to remove the primary selection. 1. Move the cursor to the line marked '-->' below. 2. Select both lines with xx or 2x. @@ -1014,7 +1014,7 @@ lines. = 10.2 CYCLING THE CONTENT OF SELECTIONS = ================================================================= - Type Alt-) and Alt-( to cycle the content of the selections + Press Alt-) and Alt-( to cycle the content of the selections forward and backward respectively. 1. Move the cursor to the line marked '-->' below. @@ -1038,7 +1038,7 @@ lines. Type ~ to switch the case of all selected letters. Type ` to set all selected letters to lowercase. - Type Alt-` to set all selected letters to uppercase. + Press Alt-` to set all selected letters to uppercase. 1. Move the cursor to the first line marked '-->' below. 2. Select each wrongly capitalised or lowercase letter @@ -1048,7 +1048,7 @@ lines. 5. Type ` to change the line to lowercase. 6. Move to the third line marked '-->'. 7. Type x to select the line. - 8. Type Alt-` to change the line to uppercase. + 8. Press Alt-` to change the line to uppercase. --> thIs sENtencE hAs MIS-cApitalIsed leTTerS. --> this SENTENCE SHOULD all be in LOWERCASE. @@ -1065,10 +1065,10 @@ lines. 3. Type S then \. |! Enter (note the spaces after . and !). This effectively splits the selection into sentences at each dot or exclamation mark. - 4. Type Alt-; to reverse the selections. + 4. Press Alt-; to reverse the selections. 5. Type ; to reduce selections to a single character - the first letter of each sentence. - 6. Type Alt-` to convert all selected letters to uppercase. + 6. Press Alt-` to convert all selected letters to uppercase. --- these are sentences. some sentences don't start with uppercase @@ -1082,8 +1082,8 @@ letters! that is not good grammar. you can fix this. * Use ) and ( to cycle the primary selection back and forward through selections respectively. - * Type Alt-, to remove the primary selection. - * Type Alt-) and Alt-( to cycle the content of the selections. + * Press Alt-, to remove the primary selection. + * Press Alt-) and Alt-( to cycle the content of the selections. * Type ~ to alternate case of selected letters. * Use ` and Alt-` to set the case of selected letters to @@ -1102,7 +1102,7 @@ letters! that is not good grammar. you can fix this. = 11.1 COMMENTING A LINE = ================================================================= -Type Ctrl-c to comment the line under your cursor. +Press Ctrl-c to comment the line under your cursor. To uncomment the line, press Ctrl-c again. 1. Move your cursor to the line marked '-->' below. @@ -1146,7 +1146,7 @@ multiple cursors, they won't be uncommented but commented again. = CHAPTER 11 RECAP = ================================================================= - * Use Ctrl-c to comment a line under your cursor. Type Ctrl-c + * Use Ctrl-c to comment a line under your cursor. Press Ctrl-c again to uncomment. * To comment multiple lines, use the selections and multi-cursors before typing Ctrl-c. From 8347139ff582341246975f047f04b4848f6e5af9 Mon Sep 17 00:00:00 2001 From: Soso <51865119+sgued@users.noreply.github.com> Date: Sat, 21 Jan 2023 20:24:40 +0100 Subject: [PATCH 036/342] book: Use per-theme syntax-highlighting CSS variables (#5406) Until this patch, all themes used the Colibri values for syntax highlighting. This made the documentation very hard to read in some light themes. --- book/theme/css/variables.css | 71 +++++++++++++++++++++++++++++++++++- book/theme/highlight.css | 16 ++++---- 2 files changed, 78 insertions(+), 9 deletions(-) diff --git a/book/theme/css/variables.css b/book/theme/css/variables.css index 1bf91b19..5d0978cc 100644 --- a/book/theme/css/variables.css +++ b/book/theme/css/variables.css @@ -48,6 +48,18 @@ --searchresults-border-color: #888; --searchresults-li-bg: #252932; --search-mark-bg: #e3b171; + --hljs-background: #191f26; + --hljs-color: #e6e1cf; + --hljs-quote: #5c6773; + --hljs-variable: #ff7733; + --hljs-type: #ffee99; + --hljs-title: #b8cc52; + --hljs-symbol: #ffb454; + --hljs-selector-tag: #ff7733; + --hljs-selector-tag: #36a3d9; + --hljs-selector-tag: #00568d; + --hljs-selector-tag: #91b362; + --hljs-selector-tag: #d96c75; } .coal { @@ -88,6 +100,18 @@ --searchresults-border-color: #98a3ad; --searchresults-li-bg: #2b2b2f; --search-mark-bg: #355c7d; + --hljs-background: #969896; + --hljs-color: #cc6666; + --hljs-quote: #de935f; + --hljs-variable: #f0c674; + --hljs-type: #b5bd68; + --hljs-title: #8abeb7; + --hljs-symbol: #81a2be; + --hljs-selector-tag: #b294bb; + --hljs-selector-tag: #1d1f21; + --hljs-selector-tag: #c5c8c6; + --hljs-selector-tag: #718c00; + --hljs-selector-tag: #c82829; } .light { @@ -128,6 +152,14 @@ --searchresults-border-color: #888; --searchresults-li-bg: #e4f2fe; --search-mark-bg: #a2cff5; + --hljs-background: #f6f7f6; + --hljs-color: #000; + --hljs-quote: #575757; + --hljs-variable: #d70025; + --hljs-type: #b21e00; + --hljs-title: #0030f2; + --hljs-symbol: #008200; + --hljs-selector-tag: #9d00ec; } .navy { @@ -168,6 +200,19 @@ --searchresults-border-color: #5c5c68; --searchresults-li-bg: #242430; --search-mark-bg: #a2cff5; + + --hljs-background: #969896; + --hljs-color: #cc6666; + --hljs-quote: #de935f; + --hljs-variable: #f0c674; + --hljs-type: #b5bd68; + --hljs-title: #8abeb7; + --hljs-symbol: #81a2be; + --hljs-selector-tag: #b294bb; + --hljs-selector-tag: #1d1f21; + --hljs-selector-tag: #c5c8c6; + --hljs-selector-tag: #718c00; + --hljs-selector-tag: #c82829; } .rust { @@ -208,6 +253,14 @@ --searchresults-border-color: #888; --searchresults-li-bg: #dec2a2; --search-mark-bg: #e69f67; + --hljs-background: #f6f7f6; + --hljs-color: #000; + --hljs-quote: #575757; + --hljs-variable: #d70025; + --hljs-type: #b21e00; + --hljs-title: #0030f2; + --hljs-symbol: #008200; + --hljs-selector-tag: #9d00ec; } @media (prefers-color-scheme: dark) { @@ -292,7 +345,15 @@ --searchresults-header-fg: #5f5f71; --searchresults-border-color: #5c5c68; --searchresults-li-bg: #242430; - --search-mark-bg: #a2cff5; + --search-mark-bg: #acff5; + --hljs-background: #2f1e2e; + --hljs-color: #a39e9b; + --hljs-quote: #8d8687; + --hljs-variable: #ef6155; + --hljs-type: #f99b15; + --hljs-title: #fec418; + --hljs-symbol: #48b685; + --hljs-selector-tag: #815ba4; } .colibri { @@ -338,5 +399,13 @@ --searchresults-border-color: #5c5c68; --searchresults-li-bg: #242430; --search-mark-bg: #a2cff5; + --hljs-background: #TODO; + --hljs-color: #TODO; + --hljs-quote: #TODO; + --hljs-variable: #TODO; + --hljs-type: #TODO; + --hljs-title: #TODO; + --hljs-symbol: #TODO; + --hljs-selector-tag: #TODO; */ } diff --git a/book/theme/highlight.css b/book/theme/highlight.css index 8dce7d65..a2db0500 100644 --- a/book/theme/highlight.css +++ b/book/theme/highlight.css @@ -7,12 +7,12 @@ code.hljs { padding:3px 5px } .hljs { - background:#2f1e2e; - color:#a39e9b + background: var(--hljs-background); + color: var(--hljs-color); } .hljs-comment, .hljs-quote { - color:#8d8687 + color: var(--hljs-quote) } .hljs-link, .hljs-meta, @@ -23,7 +23,7 @@ code.hljs { .hljs-tag, .hljs-template-variable, .hljs-variable { - color:#ef6155 + color: var(--hljs-variable) } .hljs-built_in, .hljs-deletion, @@ -31,22 +31,22 @@ code.hljs { .hljs-number, .hljs-params, .hljs-type { - color:#f99b15 + color: var(--hljs-type) } .hljs-attribute, .hljs-section, .hljs-title { - color:#fec418 + color: var(--hljs-title) } .hljs-addition, .hljs-bullet, .hljs-string, .hljs-symbol { - color:#48b685 + color: var(--hljs-symbol) } .hljs-keyword, .hljs-selector-tag { - color:#815ba4 + color: var(--hljs-selector-tag) } .hljs-emphasis { font-style:italic From 2b58ff4d7cc09bc48bcdd79096110eeb578b509f Mon Sep 17 00:00:00 2001 From: Doug Kelkhoff <18220321+dgkf@users.noreply.github.com> Date: Sat, 21 Jan 2023 15:20:59 -0500 Subject: [PATCH 037/342] Add configuration for min width of line-numbers gutter (#4724) --- book/src/configuration.md | 52 +++++++++++++++++++ helix-view/src/editor.rs | 104 +++++++++++++++++++++++++++++++++---- helix-view/src/gutter.rs | 105 ++++++++++++++++++++++++++++++++++---- helix-view/src/tree.rs | 42 ++++----------- helix-view/src/view.rs | 99 ++++++++++++++++++++--------------- 5 files changed, 310 insertions(+), 92 deletions(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index f89ef5ae..ab229f77 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -256,3 +256,55 @@ render = true character = "╎" # Some characters that work well: "▏", "┆", "┊", "⸽" skip-levels = 1 ``` + +### `[editor.gutters]` Section + +For simplicity, `editor.gutters` accepts an array of gutter types, which will +use default settings for all gutter components. + +```toml +[editor] +gutters = ["diff", "diagnostics", "line-numbers", "spacer"] +``` + +To customize the behavior of gutters, the `[editor.gutters]` section must +be used. This section contains top level settings, as well as settings for +specific gutter components as sub-sections. + +| Key | Description | Default | +| --- | --- | --- | +| `layout` | A vector of gutters to display | `["diagnostics", "spacer", "line-numbers", "spacer", "diff"]` | + +Example: + +```toml +[editor.gutters] +layout = ["diff", "diagnostics", "line-numbers", "spacer"] +``` + +#### `[editor.gutters.line-numbers]` Section + +Options for the line number gutter + +| Key | Description | Default | +| --- | --- | --- | +| `min-width` | The minimum number of characters to use | `3` | + +Example: + +```toml +[editor.gutters.line-numbers] +min-width = 1 +``` + +#### `[editor.gutters.diagnotics]` Section + +Currently unused + +#### `[editor.gutters.diff]` Section + +Currently unused + +#### `[editor.gutters.spacer]` Section + +Currently unused \ No newline at end of file diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 3ee0325d..9af8e4c3 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -71,6 +71,96 @@ where ) } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case", default, deny_unknown_fields)] +pub struct GutterConfig { + /// Gutter Layout + pub layout: Vec, + /// Options specific to the "line-numbers" gutter + pub line_numbers: GutterLineNumbersConfig, +} + +impl Default for GutterConfig { + fn default() -> Self { + Self { + layout: vec![ + GutterType::Diagnostics, + GutterType::Spacer, + GutterType::LineNumbers, + GutterType::Spacer, + GutterType::Diff, + ], + line_numbers: GutterLineNumbersConfig::default(), + } + } +} + +impl From> for GutterConfig { + fn from(x: Vec) -> Self { + GutterConfig { + layout: x, + ..Default::default() + } + } +} + +fn deserialize_gutter_seq_or_struct<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + struct GutterVisitor; + + impl<'de> serde::de::Visitor<'de> for GutterVisitor { + type Value = GutterConfig; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + formatter, + "an array of gutter names or a detailed gutter configuration" + ) + } + + fn visit_seq(self, mut seq: S) -> Result + where + S: serde::de::SeqAccess<'de>, + { + let mut gutters = Vec::new(); + while let Some(gutter) = seq.next_element::<&str>()? { + gutters.push( + gutter + .parse::() + .map_err(serde::de::Error::custom)?, + ) + } + + Ok(gutters.into()) + } + + fn visit_map(self, map: M) -> Result + where + M: serde::de::MapAccess<'de>, + { + let deserializer = serde::de::value::MapAccessDeserializer::new(map); + Deserialize::deserialize(deserializer) + } + } + + deserializer.deserialize_any(GutterVisitor) +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case", default, deny_unknown_fields)] +pub struct GutterLineNumbersConfig { + /// Minimum number of characters to use for line number gutter. Defaults to 3. + pub min_width: usize, +} + +impl Default for GutterLineNumbersConfig { + fn default() -> Self { + Self { min_width: 3 } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case", default, deny_unknown_fields)] pub struct FilePickerConfig { @@ -132,8 +222,8 @@ pub struct Config { pub cursorline: bool, /// Highlight the columns cursors are currently on. Defaults to false. pub cursorcolumn: bool, - /// Gutters. Default ["diagnostics", "line-numbers"] - pub gutters: Vec, + #[serde(deserialize_with = "deserialize_gutter_seq_or_struct")] + pub gutters: GutterConfig, /// Middle click paste support. Defaults to true. pub middle_click_paste: bool, /// Automatic insertion of pairs to parentheses, brackets, @@ -606,13 +696,7 @@ impl Default for Config { line_number: LineNumber::Absolute, cursorline: false, cursorcolumn: false, - gutters: vec![ - GutterType::Diagnostics, - GutterType::Spacer, - GutterType::LineNumbers, - GutterType::Spacer, - GutterType::Diff, - ], + gutters: GutterConfig::default(), middle_click_paste: true, auto_pairs: AutoPairConfig::default(), auto_completion: true, @@ -844,6 +928,7 @@ impl Editor { let config = self.config(); self.auto_pairs = (&config.auto_pairs).into(); self.reset_idle_timer(); + self._refresh(); } pub fn clear_idle_timer(&mut self) { @@ -984,6 +1069,7 @@ impl Editor { for (view, _) in self.tree.views_mut() { let doc = doc_mut!(self, &view.doc); view.sync_changes(doc); + view.gutters = config.gutters.clone(); view.ensure_cursor_in_view(doc, config.scrolloff) } } diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 377518fb..c1b5e2b1 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -35,10 +35,10 @@ impl GutterType { } } - pub fn width(self, _view: &View, doc: &Document) -> usize { + pub fn width(self, view: &View, doc: &Document) -> usize { match self { GutterType::Diagnostics => 1, - GutterType::LineNumbers => line_numbers_width(_view, doc), + GutterType::LineNumbers => line_numbers_width(view, doc), GutterType::Spacer => 1, GutterType::Diff => 1, } @@ -140,12 +140,13 @@ pub fn line_numbers<'doc>( is_focused: bool, ) -> GutterFn<'doc> { let text = doc.text().slice(..); - let last_line = view.last_line(doc); - let width = GutterType::LineNumbers.width(view, doc); + let width = line_numbers_width(view, doc); + + let last_line_in_view = view.last_line(doc); // Whether to draw the line number for the last line of the // document or not. We only draw it if it's not an empty line. - let draw_last = text.line_to_byte(last_line) < text.len_bytes(); + let draw_last = text.line_to_byte(last_line_in_view) < text.len_bytes(); let linenr = theme.get("ui.linenr"); let linenr_select = theme.get("ui.linenr.selected"); @@ -158,7 +159,7 @@ pub fn line_numbers<'doc>( let mode = editor.mode; Box::new(move |line: usize, selected: bool, out: &mut String| { - if line == last_line && !draw_last { + if line == last_line_in_view && !draw_last { write!(out, "{:>1$}", '~', width).unwrap(); Some(linenr) } else { @@ -187,14 +188,19 @@ pub fn line_numbers<'doc>( }) } -pub fn line_numbers_width(_view: &View, doc: &Document) -> usize { +/// The width of a "line-numbers" gutter +/// +/// The width of the gutter depends on the number of lines in the document, +/// whether there is content on the last line (the `~` line), and the +/// `editor.gutters.line-numbers.min-width` settings. +fn line_numbers_width(view: &View, doc: &Document) -> usize { let text = doc.text(); let last_line = text.len_lines().saturating_sub(1); let draw_last = text.line_to_byte(last_line) < text.len_bytes(); let last_drawn = if draw_last { last_line + 1 } else { last_line }; - - // set a lower bound to 2-chars to minimize ambiguous relative line numbers - std::cmp::max(count_digits(last_drawn), 2) + let digits = count_digits(last_drawn); + let n_min = view.gutters.line_numbers.min_width; + digits.max(n_min) } pub fn padding<'doc>( @@ -282,3 +288,82 @@ pub fn diagnostics_or_breakpoints<'doc>( breakpoints(line, selected, out).or_else(|| diagnostics(line, selected, out)) }) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::document::Document; + use crate::editor::{GutterConfig, GutterLineNumbersConfig}; + use crate::graphics::Rect; + use crate::DocumentId; + use helix_core::Rope; + + #[test] + fn test_default_gutter_widths() { + let mut view = View::new(DocumentId::default(), GutterConfig::default()); + view.area = Rect::new(40, 40, 40, 40); + + let rope = Rope::from_str("abc\n\tdef"); + let doc = Document::from(rope, None); + + assert_eq!(view.gutters.layout.len(), 5); + assert_eq!(view.gutters.layout[0].width(&view, &doc), 1); + assert_eq!(view.gutters.layout[1].width(&view, &doc), 1); + assert_eq!(view.gutters.layout[2].width(&view, &doc), 3); + assert_eq!(view.gutters.layout[3].width(&view, &doc), 1); + assert_eq!(view.gutters.layout[4].width(&view, &doc), 1); + } + + #[test] + fn test_configured_gutter_widths() { + let gutters = GutterConfig { + layout: vec![GutterType::Diagnostics], + ..Default::default() + }; + + let mut view = View::new(DocumentId::default(), gutters); + view.area = Rect::new(40, 40, 40, 40); + + let rope = Rope::from_str("abc\n\tdef"); + let doc = Document::from(rope, None); + + assert_eq!(view.gutters.layout.len(), 1); + assert_eq!(view.gutters.layout[0].width(&view, &doc), 1); + + let gutters = GutterConfig { + layout: vec![GutterType::Diagnostics, GutterType::LineNumbers], + line_numbers: GutterLineNumbersConfig { min_width: 10 }, + }; + + let mut view = View::new(DocumentId::default(), gutters); + view.area = Rect::new(40, 40, 40, 40); + + let rope = Rope::from_str("abc\n\tdef"); + let doc = Document::from(rope, None); + + assert_eq!(view.gutters.layout.len(), 2); + assert_eq!(view.gutters.layout[0].width(&view, &doc), 1); + assert_eq!(view.gutters.layout[1].width(&view, &doc), 10); + } + + #[test] + fn test_line_numbers_gutter_width_resizes() { + let gutters = GutterConfig { + layout: vec![GutterType::Diagnostics, GutterType::LineNumbers], + line_numbers: GutterLineNumbersConfig { min_width: 1 }, + }; + + let mut view = View::new(DocumentId::default(), gutters); + view.area = Rect::new(40, 40, 40, 40); + + let rope = Rope::from_str("a\nb"); + let doc_short = Document::from(rope, None); + + let rope = Rope::from_str("a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np"); + let doc_long = Document::from(rope, None); + + assert_eq!(view.gutters.layout.len(), 2); + assert_eq!(view.gutters.layout[1].width(&view, &doc_short), 1); + assert_eq!(view.gutters.layout[1].width(&view, &doc_long), 2); + } +} diff --git a/helix-view/src/tree.rs b/helix-view/src/tree.rs index 469e913d..5ec2773d 100644 --- a/helix-view/src/tree.rs +++ b/helix-view/src/tree.rs @@ -701,7 +701,7 @@ impl<'a> DoubleEndedIterator for Traverse<'a> { #[cfg(test)] mod test { use super::*; - use crate::editor::GutterType; + use crate::editor::GutterConfig; use crate::DocumentId; #[test] @@ -712,34 +712,22 @@ mod test { width: 180, height: 80, }); - let mut view = View::new( - DocumentId::default(), - vec![GutterType::Diagnostics, GutterType::LineNumbers], - ); + let mut view = View::new(DocumentId::default(), GutterConfig::default()); view.area = Rect::new(0, 0, 180, 80); tree.insert(view); let l0 = tree.focus; - let view = View::new( - DocumentId::default(), - vec![GutterType::Diagnostics, GutterType::LineNumbers], - ); + let view = View::new(DocumentId::default(), GutterConfig::default()); tree.split(view, Layout::Vertical); let r0 = tree.focus; tree.focus = l0; - let view = View::new( - DocumentId::default(), - vec![GutterType::Diagnostics, GutterType::LineNumbers], - ); + let view = View::new(DocumentId::default(), GutterConfig::default()); tree.split(view, Layout::Horizontal); let l1 = tree.focus; tree.focus = l0; - let view = View::new( - DocumentId::default(), - vec![GutterType::Diagnostics, GutterType::LineNumbers], - ); + let view = View::new(DocumentId::default(), GutterConfig::default()); tree.split(view, Layout::Vertical); let l2 = tree.focus; @@ -781,40 +769,28 @@ mod test { }); let doc_l0 = DocumentId::default(); - let mut view = View::new( - doc_l0, - vec![GutterType::Diagnostics, GutterType::LineNumbers], - ); + let mut view = View::new(doc_l0, GutterConfig::default()); view.area = Rect::new(0, 0, 180, 80); tree.insert(view); let l0 = tree.focus; let doc_r0 = DocumentId::default(); - let view = View::new( - doc_r0, - vec![GutterType::Diagnostics, GutterType::LineNumbers], - ); + let view = View::new(doc_r0, GutterConfig::default()); tree.split(view, Layout::Vertical); let r0 = tree.focus; tree.focus = l0; let doc_l1 = DocumentId::default(); - let view = View::new( - doc_l1, - vec![GutterType::Diagnostics, GutterType::LineNumbers], - ); + let view = View::new(doc_l1, GutterConfig::default()); tree.split(view, Layout::Horizontal); let l1 = tree.focus; tree.focus = l0; let doc_l2 = DocumentId::default(); - let view = View::new( - doc_l2, - vec![GutterType::Diagnostics, GutterType::LineNumbers], - ); + let view = View::new(doc_l2, GutterConfig::default()); tree.split(view, Layout::Vertical); let l2 = tree.focus; diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 23fb85c9..abcf9a16 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -1,4 +1,10 @@ -use crate::{align_view, editor::GutterType, graphics::Rect, Align, Document, DocumentId, ViewId}; +use crate::{ + align_view, + editor::{GutterConfig, GutterType}, + graphics::Rect, + Align, Document, DocumentId, ViewId, +}; + use helix_core::{ pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection, Transaction, }; @@ -103,8 +109,8 @@ pub struct View { pub last_modified_docs: [Option; 2], /// used to store previous selections of tree-sitter objects pub object_selections: Vec, - /// GutterTypes used to fetch Gutter (constructor) and width for rendering - gutters: Vec, + /// all gutter-related configuration settings, used primarily for gutter rendering + pub gutters: GutterConfig, /// A mapping between documents and the last history revision the view was updated at. /// Changes between documents and views are synced lazily when switching windows. This /// mapping keeps track of the last applied history revision so that only new changes @@ -123,7 +129,7 @@ impl fmt::Debug for View { } impl View { - pub fn new(doc: DocumentId, gutter_types: Vec) -> Self { + pub fn new(doc: DocumentId, gutters: GutterConfig) -> Self { Self { id: ViewId::default(), doc, @@ -133,7 +139,7 @@ impl View { docs_access_history: Vec::new(), last_modified_docs: [None, None], object_selections: Vec::new(), - gutters: gutter_types, + gutters, doc_revisions: HashMap::new(), } } @@ -154,11 +160,12 @@ impl View { } pub fn gutters(&self) -> &[GutterType] { - &self.gutters + &self.gutters.layout } pub fn gutter_offset(&self, doc: &Document) -> u16 { self.gutters + .layout .iter() .map(|gutter| gutter.width(self, doc) as u16) .sum() @@ -414,18 +421,19 @@ impl View { mod tests { use super::*; use helix_core::Rope; - const OFFSET: u16 = 3; // 1 diagnostic + 2 linenr (< 100 lines) - const OFFSET_WITHOUT_LINE_NUMBERS: u16 = 1; // 1 diagnostic - // const OFFSET: u16 = GUTTERS.iter().map(|(_, width)| *width as u16).sum(); + + // 1 diagnostic + 1 spacer + 3 linenr (< 1000 lines) + 1 spacer + 1 diff + const DEFAULT_GUTTER_OFFSET: u16 = 7; + + // 1 diagnostics + 1 spacer + 1 gutter + const DEFAULT_GUTTER_OFFSET_ONLY_DIAGNOSTICS: u16 = 3; + use crate::document::Document; - use crate::editor::GutterType; + use crate::editor::{GutterConfig, GutterLineNumbersConfig, GutterType}; #[test] fn test_text_pos_at_screen_coords() { - let mut view = View::new( - DocumentId::default(), - vec![GutterType::Diagnostics, GutterType::LineNumbers], - ); + let mut view = View::new(DocumentId::default(), GutterConfig::default()); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("abc\n\tdef"); let doc = Document::from(rope, None); @@ -445,24 +453,24 @@ mod tests { assert_eq!(view.text_pos_at_screen_coords(&doc, 78, 41, 4), None); assert_eq!( - view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 3, 4), + view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 3, 4), Some(3) ); assert_eq!(view.text_pos_at_screen_coords(&doc, 40, 80, 4), Some(3)); assert_eq!( - view.text_pos_at_screen_coords(&doc, 41, 40 + OFFSET + 1, 4), + view.text_pos_at_screen_coords(&doc, 41, 40 + DEFAULT_GUTTER_OFFSET + 1, 4), Some(4) ); assert_eq!( - view.text_pos_at_screen_coords(&doc, 41, 40 + OFFSET + 4, 4), + view.text_pos_at_screen_coords(&doc, 41, 40 + DEFAULT_GUTTER_OFFSET + 4, 4), Some(5) ); assert_eq!( - view.text_pos_at_screen_coords(&doc, 41, 40 + OFFSET + 7, 4), + view.text_pos_at_screen_coords(&doc, 41, 40 + DEFAULT_GUTTER_OFFSET + 7, 4), Some(8) ); @@ -471,19 +479,36 @@ mod tests { #[test] fn test_text_pos_at_screen_coords_without_line_numbers_gutter() { - let mut view = View::new(DocumentId::default(), vec![GutterType::Diagnostics]); + let mut view = View::new( + DocumentId::default(), + GutterConfig { + layout: vec![GutterType::Diagnostics], + line_numbers: GutterLineNumbersConfig::default(), + }, + ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("abc\n\tdef"); let doc = Document::from(rope, None); assert_eq!( - view.text_pos_at_screen_coords(&doc, 41, 40 + OFFSET_WITHOUT_LINE_NUMBERS + 1, 4), + view.text_pos_at_screen_coords( + &doc, + 41, + 40 + DEFAULT_GUTTER_OFFSET_ONLY_DIAGNOSTICS + 1, + 4 + ), Some(4) ); } #[test] fn test_text_pos_at_screen_coords_without_any_gutters() { - let mut view = View::new(DocumentId::default(), vec![]); + let mut view = View::new( + DocumentId::default(), + GutterConfig { + layout: vec![], + line_numbers: GutterLineNumbersConfig::default(), + }, + ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("abc\n\tdef"); let doc = Document::from(rope, None); @@ -492,76 +517,70 @@ mod tests { #[test] fn test_text_pos_at_screen_coords_cjk() { - let mut view = View::new( - DocumentId::default(), - vec![GutterType::Diagnostics, GutterType::LineNumbers], - ); + let mut view = View::new(DocumentId::default(), GutterConfig::default()); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("Hi! こんにちは皆さん"); let doc = Document::from(rope, None); assert_eq!( - view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET, 4), + view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET, 4), Some(0) ); assert_eq!( - view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 4, 4), + view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 4, 4), Some(4) ); assert_eq!( - view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 5, 4), + view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 5, 4), Some(4) ); assert_eq!( - view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 6, 4), + view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 6, 4), Some(5) ); assert_eq!( - view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 7, 4), + view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 7, 4), Some(5) ); assert_eq!( - view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 8, 4), + view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 8, 4), Some(6) ); } #[test] fn test_text_pos_at_screen_coords_graphemes() { - let mut view = View::new( - DocumentId::default(), - vec![GutterType::Diagnostics, GutterType::LineNumbers], - ); + let mut view = View::new(DocumentId::default(), GutterConfig::default()); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("Hèl̀l̀ò world!"); let doc = Document::from(rope, None); assert_eq!( - view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET, 4), + view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET, 4), Some(0) ); assert_eq!( - view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 1, 4), + view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 1, 4), Some(1) ); assert_eq!( - view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 2, 4), + view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 2, 4), Some(3) ); assert_eq!( - view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 3, 4), + view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 3, 4), Some(5) ); assert_eq!( - view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 4, 4), + view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 4, 4), Some(7) ); } From f103d2273baef3f0e71b896419fda4538b6c6cde Mon Sep 17 00:00:00 2001 From: Alex <3957610+CptPotato@users.noreply.github.com> Date: Sat, 21 Jan 2023 23:21:26 +0100 Subject: [PATCH 038/342] Add `markup.strikethrough` theme keys (#5619) --- runtime/themes/autumn.toml | 3 ++- runtime/themes/base16_default_dark.toml | 1 + runtime/themes/base16_default_light.toml | 1 + runtime/themes/base16_terminal.toml | 1 + runtime/themes/base16_transparent.toml | 1 + runtime/themes/bogster.toml | 1 + runtime/themes/bogster_light.toml | 1 + runtime/themes/boo_berry.toml | 1 + runtime/themes/catppuccin_mocha.toml | 1 + runtime/themes/darcula.toml | 1 + runtime/themes/dark_high_contrast.toml | 1 + runtime/themes/dark_plus.toml | 1 + runtime/themes/doom_acario_dark.toml | 1 + runtime/themes/dracula.toml | 1 + runtime/themes/dracula_at_night.toml | 1 + runtime/themes/emacs.toml | 1 + runtime/themes/everforest_dark.toml | 1 + runtime/themes/everforest_light.toml | 1 + runtime/themes/flatwhite.toml | 3 ++- runtime/themes/fleet_dark.toml | 1 + runtime/themes/github_dark.toml | 1 + runtime/themes/github_light.toml | 1 + runtime/themes/gruvbox.toml | 1 + runtime/themes/gruvbox_dark_hard.toml | 1 + runtime/themes/gruvbox_light.toml | 1 + runtime/themes/hex_steel.toml | 1 + runtime/themes/ingrid.toml | 1 + runtime/themes/kanagawa.toml | 1 + runtime/themes/meliora.toml | 5 +++-- runtime/themes/mellow.toml | 1 + runtime/themes/monokai.toml | 1 + runtime/themes/monokai_pro.toml | 1 + runtime/themes/monokai_pro_machine.toml | 1 + runtime/themes/monokai_pro_octagon.toml | 1 + runtime/themes/monokai_pro_ristretto.toml | 1 + runtime/themes/monokai_pro_spectrum.toml | 1 + runtime/themes/night_owl.toml | 1 + runtime/themes/nightfox.toml | 1 + runtime/themes/noctis.toml | 1 + runtime/themes/noctis_bordo.toml | 1 + runtime/themes/nord.toml | 1 + runtime/themes/onedark.toml | 1 + runtime/themes/onedarker.toml | 1 + runtime/themes/onelight.toml | 1 + runtime/themes/papercolor-dark.toml | 1 + runtime/themes/papercolor-light.toml | 1 + runtime/themes/penumbra+.toml | 1 + runtime/themes/pop-dark.toml | 1 + runtime/themes/rasmus.toml | 1 + runtime/themes/rose_pine.toml | 1 + runtime/themes/serika-dark.toml | 1 + runtime/themes/serika-light.toml | 1 + runtime/themes/snazzy.toml | 1 + runtime/themes/solarized_dark.toml | 1 + runtime/themes/solarized_light.toml | 1 + runtime/themes/sonokai.toml | 1 + runtime/themes/spacebones_light.toml | 1 + runtime/themes/tokyonight.toml | 1 + theme.toml | 1 + 59 files changed, 63 insertions(+), 4 deletions(-) diff --git a/runtime/themes/autumn.toml b/runtime/themes/autumn.toml index 935c72e5..51860312 100644 --- a/runtime/themes/autumn.toml +++ b/runtime/themes/autumn.toml @@ -51,7 +51,8 @@ "markup.heading" = "my_yellow1" "markup.list" = "my_white2" "markup.bold" = { modifiers = ["bold"] } -"markup.italic" = { modifiers = ["italic"] } +"markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = "my_turquoise2" "markup.link.text" = "my_white2" "markup.quote" = "my_brown" diff --git a/runtime/themes/base16_default_dark.toml b/runtime/themes/base16_default_dark.toml index 74bbcd2e..1a38a6ae 100644 --- a/runtime/themes/base16_default_dark.toml +++ b/runtime/themes/base16_default_dark.toml @@ -37,6 +37,7 @@ "markup.list" = "base08" "markup.bold" = { fg = "base0A", modifiers = ["bold"] } "markup.italic" = { fg = "base0E", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "base09", modifiers = ["underlined"] } "markup.link.text" = "base08" "markup.quote" = "base0C" diff --git a/runtime/themes/base16_default_light.toml b/runtime/themes/base16_default_light.toml index 3784670f..84dab530 100644 --- a/runtime/themes/base16_default_light.toml +++ b/runtime/themes/base16_default_light.toml @@ -37,6 +37,7 @@ "markup.list" = "base08" "markup.bold" = { fg = "base0A", modifiers = ["bold"] } "markup.italic" = { fg = "base0E", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "base09", modifiers = ["underlined"] } "markup.link.text" = "base08" "markup.quote" = "base0C" diff --git a/runtime/themes/base16_terminal.toml b/runtime/themes/base16_terminal.toml index 1f5328dc..f3975861 100644 --- a/runtime/themes/base16_terminal.toml +++ b/runtime/themes/base16_terminal.toml @@ -34,6 +34,7 @@ "markup.list" = "light-red" "markup.bold" = { fg = "light-yellow", modifiers = ["bold"] } "markup.italic" = { fg = "light-magenta", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "yellow", modifiers = ["underlined"] } "markup.link.text" = "light-red" "markup.quote" = "light-cyan" diff --git a/runtime/themes/base16_transparent.toml b/runtime/themes/base16_transparent.toml index f8ee0890..fd07cb28 100644 --- a/runtime/themes/base16_transparent.toml +++ b/runtime/themes/base16_transparent.toml @@ -45,6 +45,7 @@ "markup.list" = "light-red" "markup.bold" = { fg = "light-yellow", modifiers = ["bold"] } "markup.italic" = { fg = "light-magenta", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "yellow", underline = { color = "yellow", style = "line"} } "markup.link.text" = "light-red" "markup.quote" = "light-cyan" diff --git a/runtime/themes/bogster.toml b/runtime/themes/bogster.toml index f6d9fdbf..1ea13f1f 100644 --- a/runtime/themes/bogster.toml +++ b/runtime/themes/bogster.toml @@ -31,6 +31,7 @@ "markup.list" = "bogster-red" "markup.bold" = { fg = "bogster-yellow", modifiers = ["bold"] } "markup.italic" = { fg = "bogster-purp", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "bogster-yellow", modifiers = ["underlined"] } "markup.link.text" = "bogster-red" "markup.quote" = "bogster-teal" diff --git a/runtime/themes/bogster_light.toml b/runtime/themes/bogster_light.toml index 2270f6ee..e528d89d 100644 --- a/runtime/themes/bogster_light.toml +++ b/runtime/themes/bogster_light.toml @@ -31,6 +31,7 @@ "markup.list" = "bogster-red" "markup.bold" = { fg = "bogster-yellow", modifiers = ["bold"] } "markup.italic" = { fg = "magenta", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "bogster-yellow", modifiers = ["underlined"] } "markup.link.text" = "bogster-red" "markup.quote" = "bogster-lblue" diff --git a/runtime/themes/boo_berry.toml b/runtime/themes/boo_berry.toml index 33d7627d..62e3b372 100644 --- a/runtime/themes/boo_berry.toml +++ b/runtime/themes/boo_berry.toml @@ -22,6 +22,7 @@ "markup.list" = { fg = "bubblegum" } "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "violet", modifiers = ["underlined"] } "markup.link.text" = { fg = "violet" } "markup.quote" = { fg = "berry_desaturated" } diff --git a/runtime/themes/catppuccin_mocha.toml b/runtime/themes/catppuccin_mocha.toml index 575ef303..2504fec8 100644 --- a/runtime/themes/catppuccin_mocha.toml +++ b/runtime/themes/catppuccin_mocha.toml @@ -50,6 +50,7 @@ "markup.list" = "mauve" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "rosewater", modifiers = ["italic", "underlined"] } "markup.link.text" = "blue" "markup.raw" = "flamingo" diff --git a/runtime/themes/darcula.toml b/runtime/themes/darcula.toml index ed2b081a..2779a944 100644 --- a/runtime/themes/darcula.toml +++ b/runtime/themes/darcula.toml @@ -56,6 +56,7 @@ "markup.list" = "white" "markup.bold" = { fg = "white", modifiers = ["bold"] } "markup.italic" = { fg = "white", modifiers = ["italic"] } +"markup.strikethrough" = { fg = "white", modifiers = ["crossed_out"] } "markup.link.url" = { fg = "lightblue", modifiers = ["underlined"] } "markup.link.text" = "white" "markup.quote" = "darkgreen" diff --git a/runtime/themes/dark_high_contrast.toml b/runtime/themes/dark_high_contrast.toml index 1c911eb5..897c31e2 100644 --- a/runtime/themes/dark_high_contrast.toml +++ b/runtime/themes/dark_high_contrast.toml @@ -84,6 +84,7 @@ "markup.list" = "pink" "markup.bold" = { fg = "emerald_green", modifiers = ["bold"] } "markup.italic" = { fg = "blue", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "blue", underline = { color = "blue", style = "line" } } "markup.link.text" = "pink" "markup.quote" = "yellow" diff --git a/runtime/themes/dark_plus.toml b/runtime/themes/dark_plus.toml index b4e30798..be8245c4 100644 --- a/runtime/themes/dark_plus.toml +++ b/runtime/themes/dark_plus.toml @@ -44,6 +44,7 @@ "markup.list" = "blue3" "markup.bold" = { fg = "blue2", modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { modifiers = ["underlined"] } "markup.link.text" = "orange" "markup.quote" = "dark_green" diff --git a/runtime/themes/doom_acario_dark.toml b/runtime/themes/doom_acario_dark.toml index c103dbfb..47f1dfca 100644 --- a/runtime/themes/doom_acario_dark.toml +++ b/runtime/themes/doom_acario_dark.toml @@ -29,6 +29,7 @@ 'markup.bold' = { fg = 'orange', modifiers = ['bold'] } 'markup.italic' = { fg = 'magenta', modifiers = ['italic'] } +'markup.strikethrough' = { modifiers = ['crossed_out'] } 'markup.heading' = { fg = 'red' } 'markup.link' = { fg = 'orange' } 'markup.link.url' = { fg = 'magenta' } diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index 0f459311..109a1bb3 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -50,6 +50,7 @@ "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"] } diff --git a/runtime/themes/dracula_at_night.toml b/runtime/themes/dracula_at_night.toml index 4a32f930..9f10ec90 100644 --- a/runtime/themes/dracula_at_night.toml +++ b/runtime/themes/dracula_at_night.toml @@ -50,6 +50,7 @@ "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"] } diff --git a/runtime/themes/emacs.toml b/runtime/themes/emacs.toml index ea8e711c..bb33e2d8 100644 --- a/runtime/themes/emacs.toml +++ b/runtime/themes/emacs.toml @@ -37,6 +37,7 @@ "markup.list" = { fg = "black" } "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "royalblue3", modifiers = ["underlined"] } "markup.link.text" = { fg = "royalblue3" } "markup.quote" = { fg = "gray60" } diff --git a/runtime/themes/everforest_dark.toml b/runtime/themes/everforest_dark.toml index 67aafbf2..4947e4f3 100644 --- a/runtime/themes/everforest_dark.toml +++ b/runtime/themes/everforest_dark.toml @@ -46,6 +46,7 @@ "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.text" = "purple" "markup.quote" = "grey2" diff --git a/runtime/themes/everforest_light.toml b/runtime/themes/everforest_light.toml index 6daf7963..f9a55b0a 100644 --- a/runtime/themes/everforest_light.toml +++ b/runtime/themes/everforest_light.toml @@ -46,6 +46,7 @@ "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.text" = "purple" "markup.quote" = "grey2" diff --git a/runtime/themes/flatwhite.toml b/runtime/themes/flatwhite.toml index 1743012b..5818b56b 100644 --- a/runtime/themes/flatwhite.toml +++ b/runtime/themes/flatwhite.toml @@ -37,14 +37,15 @@ "markup.raw" = { fg = "orange_text", bg = "orange_bg" } "markup.raw.inline" = { fg = "orange_text", bg = "orange_bg" } "markup.raw.block" = { fg = "orange_text", bg = "orange_bg" } +"markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "blue_text", bg = "blue_bg", modifiers = [ "underlined", ] } "markup.link.label" = { fg = "blue_text", bg = "blue_bg" } "markup.link.text" = { fg = "blue_text", bg = "blue_bg" } "markup.quote" = { fg = "teal_text", bg = "teal_bg" } -"markup.bold" = { modifiers = ["bold"] } "markup.list" = { fg = "purple_text", bg = "purple_bg" } "ui.background" = { fg = "base1", bg = "base7" } diff --git a/runtime/themes/fleet_dark.toml b/runtime/themes/fleet_dark.toml index f3285a76..0fc9e812 100644 --- a/runtime/themes/fleet_dark.toml +++ b/runtime/themes/fleet_dark.toml @@ -46,6 +46,7 @@ # "markup.normal" = {} # .completion / .hover "markup.bold" = { fg = "lightest", modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.heading" = { fg = "cyan", modifiers = ["bold"] } # .marker / .1 / .2 / .3 / .4 / .5 / .6 "markup.list" = "pink" # .unnumbered / .numbered "markup.list.numbered" = "cyan" diff --git a/runtime/themes/github_dark.toml b/runtime/themes/github_dark.toml index 2b6dbfde..4f9aa562 100644 --- a/runtime/themes/github_dark.toml +++ b/runtime/themes/github_dark.toml @@ -33,6 +33,7 @@ label = "scale.red.3" "markup.heading" = "scale.blue.2" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { modifiers = ["underlined"] } "markup.link.text" = { fg = "scale.blue.1", modifiers = ["underlined"] } "markup.raw" = "scale.blue.2" diff --git a/runtime/themes/github_light.toml b/runtime/themes/github_light.toml index 3492460e..3e226969 100644 --- a/runtime/themes/github_light.toml +++ b/runtime/themes/github_light.toml @@ -33,6 +33,7 @@ label = "scale.red.5" "markup.heading" = "scale.blue.6" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { modifiers = ["underlined"] } "markup.link.text" = { fg = "scale.blue.8", modifiers = ["underlined"] } "markup.raw" = "scale.blue.6" diff --git a/runtime/themes/gruvbox.toml b/runtime/themes/gruvbox.toml index c293fc3e..b88becd1 100644 --- a/runtime/themes/gruvbox.toml +++ b/runtime/themes/gruvbox.toml @@ -69,6 +69,7 @@ "markup.heading" = "aqua1" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "green1", modifiers = ["underlined"] } "markup.link.text" = "red1" "markup.raw" = "red1" diff --git a/runtime/themes/gruvbox_dark_hard.toml b/runtime/themes/gruvbox_dark_hard.toml index f39cd906..7fe45e8c 100644 --- a/runtime/themes/gruvbox_dark_hard.toml +++ b/runtime/themes/gruvbox_dark_hard.toml @@ -70,6 +70,7 @@ "markup.heading" = "aqua1" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "green1", modifiers = ["underlined"] } "markup.link.text" = "red1" "markup.raw" = "red1" diff --git a/runtime/themes/gruvbox_light.toml b/runtime/themes/gruvbox_light.toml index 8ea9d625..bd1a5ef2 100644 --- a/runtime/themes/gruvbox_light.toml +++ b/runtime/themes/gruvbox_light.toml @@ -70,6 +70,7 @@ "markup.heading" = "aqua1" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "green1", modifiers = ["underlined"] } "markup.link.text" = "red1" "markup.raw" = "red1" diff --git a/runtime/themes/hex_steel.toml b/runtime/themes/hex_steel.toml index c9b62559..c81df409 100644 --- a/runtime/themes/hex_steel.toml +++ b/runtime/themes/hex_steel.toml @@ -75,6 +75,7 @@ "markup.list" = { fg = "t4" } "markup.bold" = { fg = "t4" } "markup.italic" = { fg = "t4" } +"markup.strikethrough" = { fg = "t4", modifiers = ["crossed_out"] } "markup.link.url" = { fg = "t4", modifiers = ["underlined"] } "markup.link.text" = { fg = "t4" } "markup.quote" = { fg = "t4" } diff --git a/runtime/themes/ingrid.toml b/runtime/themes/ingrid.toml index fa1a4fdb..8942c3ca 100644 --- a/runtime/themes/ingrid.toml +++ b/runtime/themes/ingrid.toml @@ -33,6 +33,7 @@ "markup.list" = "red" "markup.bold" = { fg = "yellow", modifiers = ["bold"] } "markup.italic" = { fg = "magenta", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "yellow", modifiers = ["underlined"] } "markup.link.text" = "red" "markup.quote" = "cyan" diff --git a/runtime/themes/kanagawa.toml b/runtime/themes/kanagawa.toml index a12a0912..16e27362 100644 --- a/runtime/themes/kanagawa.toml +++ b/runtime/themes/kanagawa.toml @@ -97,6 +97,7 @@ hint = "dragonBlue" "markup.list" = "oniViolet" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "springBlue", modifiers = ["underlined"] } "markup.link.text" = "crystalBlue" "markup.quote" = "seaFoam" diff --git a/runtime/themes/meliora.toml b/runtime/themes/meliora.toml index d4cb9883..e7037e18 100644 --- a/runtime/themes/meliora.toml +++ b/runtime/themes/meliora.toml @@ -67,8 +67,9 @@ "markup.heading" = { fg = "orange" } "markup.list" = { fg = "blue" } -"markup.bold" = { fg = "magenta" } -"markup.italic" = { fg = "blue" } +"markup.bold" = { fg = "magenta", modifiers = ["bold"] } +"markup.italic" = { fg = "blue", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "comment" , modifiers = ["underlined"] } "markup.link.text" = { fg = "comment" } "markup.quote" = { fg = "yellow" } diff --git a/runtime/themes/mellow.toml b/runtime/themes/mellow.toml index a878df8a..279fd5c2 100644 --- a/runtime/themes/mellow.toml +++ b/runtime/themes/mellow.toml @@ -50,6 +50,7 @@ "markup.list" = "gray06" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "green", modifiers = ["underlined"] } "markup.link.text" = { fg = "blue", modifiers = ["italic"] } "markup.raw" = "yellow" diff --git a/runtime/themes/monokai.toml b/runtime/themes/monokai.toml index 92b81a8e..b75912f7 100644 --- a/runtime/themes/monokai.toml +++ b/runtime/themes/monokai.toml @@ -46,6 +46,7 @@ "markup.list" = "red" "markup.bold" = { fg = "yellow", modifiers = ["bold"] } "markup.italic" = { fg = "magenta", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "yellow", modifiers = ["underlined"] } "markup.link.text" = "red" "markup.quote" = "cyan" diff --git a/runtime/themes/monokai_pro.toml b/runtime/themes/monokai_pro.toml index 276f1f94..57bede94 100644 --- a/runtime/themes/monokai_pro.toml +++ b/runtime/themes/monokai_pro.toml @@ -99,6 +99,7 @@ "markup.heading" = "green" "markup.bold" = { fg = "orange", modifiers = ["bold"] } "markup.italic" = { fg = "orange", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "orange", modifiers = ["underlined"] } "markup.link.text" = "yellow" "markup.quote" = "green" diff --git a/runtime/themes/monokai_pro_machine.toml b/runtime/themes/monokai_pro_machine.toml index ae391f3d..b292e6b0 100644 --- a/runtime/themes/monokai_pro_machine.toml +++ b/runtime/themes/monokai_pro_machine.toml @@ -96,6 +96,7 @@ "markup.heading" = "green" "markup.bold" = { fg = "orange", modifiers = ["bold"] } "markup.italic" = { fg = "orange", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "orange", modifiers = ["underlined"] } "markup.link.text" = "yellow" "markup.quote" = "green" diff --git a/runtime/themes/monokai_pro_octagon.toml b/runtime/themes/monokai_pro_octagon.toml index 70e8f05b..3236fc16 100644 --- a/runtime/themes/monokai_pro_octagon.toml +++ b/runtime/themes/monokai_pro_octagon.toml @@ -99,6 +99,7 @@ "markup.heading" = "green" "markup.bold" = { fg = "orange", modifiers = ["bold"] } "markup.italic" = { fg = "orange", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "orange", modifiers = ["underlined"] } "markup.link.text" = "yellow" "markup.quote" = "green" diff --git a/runtime/themes/monokai_pro_ristretto.toml b/runtime/themes/monokai_pro_ristretto.toml index ab740446..f897bddb 100644 --- a/runtime/themes/monokai_pro_ristretto.toml +++ b/runtime/themes/monokai_pro_ristretto.toml @@ -96,6 +96,7 @@ "markup.heading" = "green" "markup.bold" = { fg = "orange", modifiers = ["bold"] } "markup.italic" = { fg = "orange", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "orange", modifiers = ["underlined"] } "markup.link.text" = "yellow" "markup.quote" = "green" diff --git a/runtime/themes/monokai_pro_spectrum.toml b/runtime/themes/monokai_pro_spectrum.toml index 76123fcf..74533404 100644 --- a/runtime/themes/monokai_pro_spectrum.toml +++ b/runtime/themes/monokai_pro_spectrum.toml @@ -96,6 +96,7 @@ "markup.heading" = "green" "markup.bold" = { fg = "orange", modifiers = ["bold"] } "markup.italic" = { fg = "orange", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "orange", modifiers = ["underlined"] } "markup.link.text" = "yellow" "markup.quote" = "green" diff --git a/runtime/themes/night_owl.toml b/runtime/themes/night_owl.toml index 7ef6e214..fc27dc7c 100644 --- a/runtime/themes/night_owl.toml +++ b/runtime/themes/night_owl.toml @@ -80,6 +80,7 @@ 'markup.list' = { fg = 'pink' } 'markup.bold' = { fg = 'foreground', modifiers = ['bold'] } 'markup.italic' = { fg = 'foreground', modifiers = ['italic'] } +'markup.strikethrough' = { fg = 'foreground', modifiers = ['crossed_out'] } 'markup.link' = { fg = 'pink', modifiers = ['underlined'] } 'markup.link.url' = { fg = 'slate', modifiers = ['underlined'] } 'markup.quote' = { fg = 'green', modifiers = ['italic'] } diff --git a/runtime/themes/nightfox.toml b/runtime/themes/nightfox.toml index 1f248d5c..8cddbbae 100644 --- a/runtime/themes/nightfox.toml +++ b/runtime/themes/nightfox.toml @@ -55,6 +55,7 @@ "markup.list" = { fg = "magenta", modifiers = ["bold"] } "markup.bold" = { fg = "orange", modifiers = ["bold"] } "markup.italic" = { fg = "pink" } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link" = { fg = "yellow-bright", modifiers = ["bold"] } "markup.quote" = { fg = "blue" } diff --git a/runtime/themes/noctis.toml b/runtime/themes/noctis.toml index e5abbec0..81733e63 100644 --- a/runtime/themes/noctis.toml +++ b/runtime/themes/noctis.toml @@ -150,6 +150,7 @@ 'markup.bold' = { modifiers = ["bold"] } # Bold text. 'markup.italic' = { modifiers = ["italic"] } # Italicised text. +"markup.strikethrough" = { modifiers = ["crossed_out"] } # Crossed out text. 'markup.link' = { fg = "light-blue", modifiers = ["underlined"] } 'markup.link.url' = { } # Urls pointed to by links. diff --git a/runtime/themes/noctis_bordo.toml b/runtime/themes/noctis_bordo.toml index d446543d..c3bbe79c 100644 --- a/runtime/themes/noctis_bordo.toml +++ b/runtime/themes/noctis_bordo.toml @@ -49,6 +49,7 @@ "markup.list" = "base08" "markup.quote" = "base0C" "markup.raw" = "base0B" +"markup.strikethrough" = { modifiers = ["crossed_out"] } "diff.delta" = "base09" "diff.plus" = "base0B" diff --git a/runtime/themes/nord.toml b/runtime/themes/nord.toml index 7eba10ac..c653f539 100644 --- a/runtime/themes/nord.toml +++ b/runtime/themes/nord.toml @@ -95,6 +95,7 @@ "markup.list" = "nord9" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.text" = "nord8" "markup.raw" = "nord7" diff --git a/runtime/themes/onedark.toml b/runtime/themes/onedark.toml index c4a56b90..9cab0901 100644 --- a/runtime/themes/onedark.toml +++ b/runtime/themes/onedark.toml @@ -30,6 +30,7 @@ "markup.raw.inline" = { fg = "green" } "markup.bold" = { fg = "gold", modifiers = ["bold"] } "markup.italic" = { fg = "purple", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.list" = { fg = "red" } "markup.quote" = { fg = "yellow" } "markup.link.url" = { fg = "cyan", modifiers = ["underlined"]} diff --git a/runtime/themes/onedarker.toml b/runtime/themes/onedarker.toml index 7a6e4a62..33f900cc 100644 --- a/runtime/themes/onedarker.toml +++ b/runtime/themes/onedarker.toml @@ -31,6 +31,7 @@ "markup.raw.block" = { fg = "white" } "markup.bold" = { fg = "gold", modifiers = ["bold"] } "markup.italic" = { fg = "purple", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.list" = { fg = "red" } "markup.quote" = { fg = "yellow" } "markup.link.url" = { fg = "blue", modifiers = ["underlined"]} diff --git a/runtime/themes/onelight.toml b/runtime/themes/onelight.toml index ad900a78..7c266979 100644 --- a/runtime/themes/onelight.toml +++ b/runtime/themes/onelight.toml @@ -48,6 +48,7 @@ "markup.raw.inline" = { fg = "green", bg = "grey-200" } "markup.bold" = { fg = "yellow", modifiers = ["bold"] } "markup.italic" = { fg = "purple", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.list" = { fg = "light-blue" } "markup.quote" = { fg = "gray" } "markup.link.url" = { fg = "cyan", modifiers = ["underlined"] } diff --git a/runtime/themes/papercolor-dark.toml b/runtime/themes/papercolor-dark.toml index d4b62660..088658e9 100644 --- a/runtime/themes/papercolor-dark.toml +++ b/runtime/themes/papercolor-dark.toml @@ -31,6 +31,7 @@ "markup.list" = "bright3" "markup.bold" = { fg = "foreground", modifiers = ["bold"] } "markup.italic" = { fg = "bright0", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "bright6", modifiers = ["underlined"] } "markup.link.text" = "bright2" "markup.link.label" = { fg = "regular2", modifiers = ["bold"] } diff --git a/runtime/themes/papercolor-light.toml b/runtime/themes/papercolor-light.toml index 0d3fc77c..c44c6709 100644 --- a/runtime/themes/papercolor-light.toml +++ b/runtime/themes/papercolor-light.toml @@ -32,6 +32,7 @@ "markup.list" = "regular4" "markup.bold" = { fg = "foreground", modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "regular4", modifiers = ["underlined"] } "markup.link.text" = "bright2" "markup.link.label" = { fg = "regular7", modifiers = ["bold"] } diff --git a/runtime/themes/penumbra+.toml b/runtime/themes/penumbra+.toml index 62db2f8a..bc53e82e 100644 --- a/runtime/themes/penumbra+.toml +++ b/runtime/themes/penumbra+.toml @@ -95,6 +95,7 @@ error = "red" "markup.list" = "sky" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { modifiers = ["underlined"] } "markup.link.text" = "magenta" "markup.quote" = "green" diff --git a/runtime/themes/pop-dark.toml b/runtime/themes/pop-dark.toml index bd16f34b..2ee55903 100644 --- a/runtime/themes/pop-dark.toml +++ b/runtime/themes/pop-dark.toml @@ -103,6 +103,7 @@ namespace = { fg = 'orangeL' } 'markup.list.unnumbered' = { fg = 'greenN' } 'markup.bold' = { modifiers = ['bold'] } 'markup.italic' = { modifiers = ['italic'] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } 'markup.link' = { fg = 'blueD' } 'markup.link.url' = { fg = 'blueL' } 'markup.link.label' = { fg = 'blueH' } diff --git a/runtime/themes/rasmus.toml b/runtime/themes/rasmus.toml index 996271d3..3158a6a4 100644 --- a/runtime/themes/rasmus.toml +++ b/runtime/themes/rasmus.toml @@ -55,6 +55,7 @@ "markup.list" = "gray07" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "cyan", modifiers = ["underlined"] } "markup.link.text" = "blue" "markup.raw" = "yellow" diff --git a/runtime/themes/rose_pine.toml b/runtime/themes/rose_pine.toml index 3386fffb..06e89306 100644 --- a/runtime/themes/rose_pine.toml +++ b/runtime/themes/rose_pine.toml @@ -143,6 +143,7 @@ # "markup.list.numbered" = "" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link" = "iris" "markup.link.url" = { fg = "iris", underline = { color = "iris", style = "line" } } "markup.link.label" = "subtle" diff --git a/runtime/themes/serika-dark.toml b/runtime/themes/serika-dark.toml index 480dc2cc..ba9bd3b3 100644 --- a/runtime/themes/serika-dark.toml +++ b/runtime/themes/serika-dark.toml @@ -71,6 +71,7 @@ "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"] } diff --git a/runtime/themes/serika-light.toml b/runtime/themes/serika-light.toml index 8a62e23d..bac8b240 100644 --- a/runtime/themes/serika-light.toml +++ b/runtime/themes/serika-light.toml @@ -71,6 +71,7 @@ "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"] } diff --git a/runtime/themes/snazzy.toml b/runtime/themes/snazzy.toml index 110e2093..eb88c5eb 100644 --- a/runtime/themes/snazzy.toml +++ b/runtime/themes/snazzy.toml @@ -84,6 +84,7 @@ "markup.list" = "cyan" "markup.bold" = { fg = "blue", modifiers = ["bold"] } "markup.italic" = { fg = "yellow", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = "cyan" "markup.link.text" = "magenta" "markup.quote" = { fg = "yellow", modifiers = ["italic"] } diff --git a/runtime/themes/solarized_dark.toml b/runtime/themes/solarized_dark.toml index a81c9299..6e5b790b 100644 --- a/runtime/themes/solarized_dark.toml +++ b/runtime/themes/solarized_dark.toml @@ -27,6 +27,7 @@ "markup.list" = "red" "markup.bold" = { fg = "yellow", modifiers = ["bold"] } "markup.italic" = { fg = "magenta", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "yellow", modifiers = ["underlined"] } "markup.link.text" = "red" "markup.quote" = "cyan" diff --git a/runtime/themes/solarized_light.toml b/runtime/themes/solarized_light.toml index 849751e8..ba21b90e 100644 --- a/runtime/themes/solarized_light.toml +++ b/runtime/themes/solarized_light.toml @@ -27,6 +27,7 @@ "markup.list" = "red" "markup.bold" = { fg = "yellow", modifiers = ["bold"] } "markup.italic" = { fg = "magenta", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "yellow", modifiers = ["underlined"] } "markup.link.text" = "red" "markup.quote" = "cyan" diff --git a/runtime/themes/sonokai.toml b/runtime/themes/sonokai.toml index 19f187d5..06aff50b 100644 --- a/runtime/themes/sonokai.toml +++ b/runtime/themes/sonokai.toml @@ -41,6 +41,7 @@ "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.text" = "purple" "markup.quote" = "grey" diff --git a/runtime/themes/spacebones_light.toml b/runtime/themes/spacebones_light.toml index f01b19dc..a62c7c82 100644 --- a/runtime/themes/spacebones_light.toml +++ b/runtime/themes/spacebones_light.toml @@ -34,6 +34,7 @@ "markup.list" = "theme_red" "markup.bold" = { fg = "theme_yellow", modifiers = ["bold"] } "markup.italic" = { fg = "theme_magenta", modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "theme_yellow", modifiers = ["underlined"] } "markup.link.text" = "theme_red" "markup.quote" = "theme_cyan" diff --git a/runtime/themes/tokyonight.toml b/runtime/themes/tokyonight.toml index 35ceaeba..4b082dc7 100644 --- a/runtime/themes/tokyonight.toml +++ b/runtime/themes/tokyonight.toml @@ -64,6 +64,7 @@ "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 = "green" } "markup.link.text" = { fg = "light-gray" } "markup.quote" = { fg = "yellow", modifiers = ["italic"] } diff --git a/theme.toml b/theme.toml index c7b5dc84..b67eaecc 100644 --- a/theme.toml +++ b/theme.toml @@ -31,6 +31,7 @@ label = "honey" "markup.heading" = "lilac" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.strikethrough" = { modifiers = ["crossed_out"] } "markup.link.url" = { fg = "silver", modifiers = ["underlined"] } "markup.link.text" = "almond" "markup.raw" = "almond" From d99a72053676658759ef6ae7531f432daabb025a Mon Sep 17 00:00:00 2001 From: Luca Saccarola <96259932+saccarosium@users.noreply.github.com> Date: Sat, 21 Jan 2023 23:52:56 +0100 Subject: [PATCH 039/342] theme: make dracula ui.virtual.whitespace less intrusive (#5627) --- runtime/themes/dracula.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runtime/themes/dracula.toml b/runtime/themes/dracula.toml index 109a1bb3..51464824 100644 --- a/runtime/themes/dracula.toml +++ b/runtime/themes/dracula.toml @@ -40,7 +40,7 @@ "ui.text" = { fg = "foreground" } "ui.text.focus" = { fg = "cyan" } "ui.window" = { fg = "foreground" } -"ui.virtual.whitespace" = { fg = "comment" } +"ui.virtual.whitespace" = { fg = "subtle" } "ui.virtual.ruler" = { bg = "background_dark"} "error" = { fg = "red" } @@ -64,6 +64,7 @@ background = "#282a36" background_dark = "#21222c" primary_highlight = "#800049" secondary_highlight = "#4d4f66" +subtle = "#424450" foreground = "#f8f8f2" comment = "#6272a4" red = "#ff5555" @@ -73,3 +74,4 @@ green = "#50fa7b" purple = "#bd93f9" cyan = "#8be9fd" pink = "#ff79c6" + From c8d77cfdb5f3f6ad04e9ffc5de8de33a0594447a Mon Sep 17 00:00:00 2001 From: Yuta Yamaguchi Date: Mon, 23 Jan 2023 03:04:14 +0900 Subject: [PATCH 040/342] refactor(helix-view): remove cfg_attr references a nonexistent feature (#5630) Fixes https://github.com/helix-editor/helix/issues/5615 --- helix-view/src/graphics.rs | 3 --- helix-view/src/keyboard.rs | 1 - 2 files changed, 4 deletions(-) diff --git a/helix-view/src/graphics.rs b/helix-view/src/graphics.rs index 9264c50f..a0b645fa 100644 --- a/helix-view/src/graphics.rs +++ b/helix-view/src/graphics.rs @@ -251,7 +251,6 @@ impl Rect { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Color { Reset, Black, @@ -353,7 +352,6 @@ bitflags! { /// /// let m = Modifier::BOLD | Modifier::ITALIC; /// ``` - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Modifier: u16 { const BOLD = 0b0000_0000_0001; const DIM = 0b0000_0000_0010; @@ -450,7 +448,6 @@ impl FromStr for Modifier { /// ); /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Style { pub fg: Option, pub bg: Option, diff --git a/helix-view/src/keyboard.rs b/helix-view/src/keyboard.rs index cf673e11..04a9922a 100644 --- a/helix-view/src/keyboard.rs +++ b/helix-view/src/keyboard.rs @@ -2,7 +2,6 @@ use bitflags::bitflags; bitflags! { /// Represents key modifiers (shift, control, alt). - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct KeyModifiers: u8 { const SHIFT = 0b0000_0001; const CONTROL = 0b0000_0010; From 5c6b7127f88ef7508cefec74e2dc6479e1cfa609 Mon Sep 17 00:00:00 2001 From: Jared Moulton Date: Mon, 23 Jan 2023 00:49:54 -0700 Subject: [PATCH 041/342] Add build.gradle to list of java roots (#5641) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index 32383513..cdfd3a2d 100644 --- a/languages.toml +++ b/languages.toml @@ -652,7 +652,7 @@ name = "java" scope = "source.java" injection-regex = "java" file-types = ["java"] -roots = ["pom.xml"] +roots = ["pom.xml", "build.gradle"] language-server = { command = "jdtls" } indent = { tab-width = 4, unit = " " } From 769fb5fe97ac321ba030ac8fbf7e3793700f282c Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 23 Jan 2023 21:51:34 +0800 Subject: [PATCH 042/342] Make clippy happy on Windows (#5644) --- helix-view/src/editor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 9af8e4c3..eef4a3f9 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -296,10 +296,10 @@ pub fn get_terminal_provider() -> Option { }); } - return Some(TerminalConfig { + Some(TerminalConfig { command: "conhost".to_string(), args: vec!["cmd".to_string(), "/C".to_string()], - }); + }) } #[cfg(not(any(windows, target_os = "wasm32")))] From 17acadb305bebfef094e4fcc9ba1e6fda6159c3b Mon Sep 17 00:00:00 2001 From: Eric Crosson Date: Mon, 23 Jan 2023 08:51:42 -0600 Subject: [PATCH 043/342] Use markdown language for hub pull-request files (#5634) The hub[^1] command-line tool uses a file called `PULLREQ_EDITMSG`[^2]. This file is used to edit the text from of each commit being submitted in a pull request, and the final content is rendered as markdown by GitHub. This commit adds `PULLREQ_EDITMSG` to the list of markdown file-types. [^1]: https://github.com/github/hub [^2]: https://github.com/github/hub/blob/c8e68d548a39ec0fab6f674a669c21b54d4eec61/commands/pull_request.go#L225 --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index cdfd3a2d..d1ab92b6 100644 --- a/languages.toml +++ b/languages.toml @@ -1019,7 +1019,7 @@ source = { git = "https://github.com/Flakebi/tree-sitter-tablegen", rev = "568dd name = "markdown" scope = "source.md" injection-regex = "md|markdown" -file-types = ["md", "markdown"] +file-types = ["md", "markdown", "PULLREQ_EDITMSG"] roots = [".marksman.toml"] language-server = { command = "marksman", args=["server"] } indent = { tab-width = 2, unit = " " } From 361a8344866841799199e362285b119960151eff Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Mon, 23 Jan 2023 18:18:44 +0100 Subject: [PATCH 044/342] Fix selecting a changed file in global search (#5639) --- helix-term/src/commands.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index e773a2c7..e7091401 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2003,6 +2003,10 @@ fn global_search(cx: &mut Context) { let line_num = *line_num; let (view, doc) = current!(cx.editor); let text = doc.text(); + if line_num >= text.len_lines() { + cx.editor.set_error("The line you jumped to does not exist anymore because the file has changed."); + return; + } let start = text.line_to_char(line_num); let end = text.line_to_char((line_num + 1).min(text.len_lines())); From 7e191f59157d024e8b8aaabc62f292183d39f6f9 Mon Sep 17 00:00:00 2001 From: Eloi Torrents Date: Mon, 23 Jan 2023 19:10:27 +0100 Subject: [PATCH 045/342] Support sagemath language (#5649) --- book/src/generated/lang-support.md | 1 + languages.toml | 10 ++++++++++ runtime/queries/sage/highlights.scm | 1 + runtime/queries/sage/injections.scm | 2 ++ runtime/queries/sage/textobjects.scm | 1 + 5 files changed, 15 insertions(+) create mode 100644 runtime/queries/sage/highlights.scm create mode 100644 runtime/queries/sage/injections.scm create mode 100644 runtime/queries/sage/textobjects.scm diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 00e6a91e..c0b5b558 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -109,6 +109,7 @@ | ron | ✓ | | ✓ | | | ruby | ✓ | ✓ | ✓ | `solargraph` | | rust | ✓ | ✓ | ✓ | `rust-analyzer` | +| sage | ✓ | ✓ | | | | scala | ✓ | | ✓ | `metals` | | scheme | ✓ | | | | | scss | ✓ | | | `vscode-css-language-server` | diff --git a/languages.toml b/languages.toml index d1ab92b6..1685c2a3 100644 --- a/languages.toml +++ b/languages.toml @@ -2109,3 +2109,13 @@ formatter = { command = "dhall" , args = ["format"] } [[grammar]] name = "dhall" source = { git = "https://github.com/jbellerb/tree-sitter-dhall", rev = "affb6ee38d629c9296749767ab832d69bb0d9ea8" } + +[[language]] +name = "sage" +scope = "source.sage" +file-types = ["sage"] +injection-regex = "sage" +roots = [] +comment-token = "#" +indent = { tab-width = 4, unit = " " } +grammar = "python" diff --git a/runtime/queries/sage/highlights.scm b/runtime/queries/sage/highlights.scm new file mode 100644 index 00000000..0b920cbf --- /dev/null +++ b/runtime/queries/sage/highlights.scm @@ -0,0 +1 @@ +; inherits: python diff --git a/runtime/queries/sage/injections.scm b/runtime/queries/sage/injections.scm new file mode 100644 index 00000000..321c90ad --- /dev/null +++ b/runtime/queries/sage/injections.scm @@ -0,0 +1,2 @@ +((comment) @injection.content + (#set! injection.language "comment")) diff --git a/runtime/queries/sage/textobjects.scm b/runtime/queries/sage/textobjects.scm new file mode 100644 index 00000000..0b920cbf --- /dev/null +++ b/runtime/queries/sage/textobjects.scm @@ -0,0 +1 @@ +; inherits: python From 639f22559e0b9354b02305a21c2423784d9f630e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Jan 2023 17:24:42 -0600 Subject: [PATCH 046/342] build(deps): bump tokio from 1.24.1 to 1.24.2 (#5657) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.24.1 to 1.24.2. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/commits) --- updated-dependencies: - dependency-name: tokio dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 665eb4b9..84eaf7e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2122,9 +2122,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.24.1" +version = "1.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9f76183f91ecfb55e1d7d5602bd1d979e38a3a522fe900241cf195624d67ae" +checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb" dependencies = [ "autocfg", "bytes", From 64ec0256d3e41d6b6e5a24f749489880a147ab8a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Jan 2023 17:25:49 -0600 Subject: [PATCH 047/342] build(deps): bump which from 4.3.0 to 4.4.0 (#5655) Bumps [which](https://github.com/harryfei/which-rs) from 4.3.0 to 4.4.0. - [Release notes](https://github.com/harryfei/which-rs/releases) - [Commits](https://github.com/harryfei/which-rs/compare/4.3.0...4.4.0) --- updated-dependencies: - dependency-name: which dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- helix-dap/Cargo.toml | 2 +- helix-lsp/Cargo.toml | 2 +- helix-term/Cargo.toml | 2 +- helix-view/Cargo.toml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84eaf7e6..96d75697 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2336,9 +2336,9 @@ checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "which" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", "libc", diff --git a/helix-dap/Cargo.toml b/helix-dap/Cargo.toml index 95a05905..d42ce23f 100644 --- a/helix-dap/Cargo.toml +++ b/helix-dap/Cargo.toml @@ -19,7 +19,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "net", "sync"] } -which = "4.2" +which = "4.4" [dev-dependencies] fern = "0.6" diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index d31731d2..0db61ad4 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -25,4 +25,4 @@ serde_json = "1.0" thiserror = "1.0" tokio = { version = "1.24", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } tokio-stream = "0.1.11" -which = "4.2" +which = "4.4" diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 895a0882..d4eebefb 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -37,7 +37,7 @@ helix-loader = { version = "0.6", path = "../helix-loader" } anyhow = "1" once_cell = "1.17" -which = "4.2" +which = "4.4" tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] } tui = { path = "../helix-tui", package = "helix-tui", default-features = false, features = ["crossterm"] } diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index 7d130317..c75291cc 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -42,7 +42,7 @@ serde_json = "1.0" toml = "0.5" log = "~0.4" -which = "4.2" +which = "4.4" [target.'cfg(windows)'.dependencies] From e9dc9f493554bd54ea3710e66a2fb0fd2e70b462 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Tue, 24 Jan 2023 17:07:01 +0100 Subject: [PATCH 048/342] Switch from toml::from_slice to toml::from_str (#5659) --- helix-loader/src/config.rs | 9 ++++++--- helix-loader/src/lib.rs | 12 ++++++++---- helix-view/src/theme.rs | 12 +++++++----- xtask/src/helpers.rs | 4 ++-- xtask/src/themelint.rs | 4 ++-- 5 files changed, 25 insertions(+), 16 deletions(-) diff --git a/helix-loader/src/config.rs b/helix-loader/src/config.rs index 259b1318..a4c6dcbd 100644 --- a/helix-loader/src/config.rs +++ b/helix-loader/src/config.rs @@ -1,6 +1,9 @@ +use std::str::from_utf8; + /// Default built-in languages.toml. pub fn default_lang_config() -> toml::Value { - toml::from_slice(include_bytes!("../../languages.toml")) + let default_config = include_bytes!("../../languages.toml"); + toml::from_str(from_utf8(default_config).unwrap()) .expect("Could not parse built-in languages.toml to valid toml") } @@ -11,8 +14,8 @@ pub fn user_lang_config() -> Result { .chain([crate::config_dir()].into_iter()) .map(|path| path.join("languages.toml")) .filter_map(|file| { - std::fs::read(&file) - .map(|config| toml::from_slice(&config)) + std::fs::read_to_string(&file) + .map(|config| toml::from_str(&config)) .ok() }) .collect::, _>>()? diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index 80d44a82..8dc2928a 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -179,6 +179,8 @@ pub fn merge_toml_values(left: toml::Value, right: toml::Value, merge_depth: usi #[cfg(test)] mod merge_toml_tests { + use std::str; + use super::merge_toml_values; use toml::Value; @@ -191,8 +193,9 @@ mod merge_toml_tests { indent = { tab-width = 4, unit = " ", test = "aaa" } "#; - let base: Value = toml::from_slice(include_bytes!("../../languages.toml")) - .expect("Couldn't parse built-in languages config"); + let base = include_bytes!("../../languages.toml"); + let base = str::from_utf8(base).expect("Couldn't parse built-in languages config"); + let base: Value = toml::from_str(base).expect("Couldn't parse built-in languages config"); let user: Value = toml::from_str(USER).unwrap(); let merged = merge_toml_values(base, user, 3); @@ -224,8 +227,9 @@ mod merge_toml_tests { language-server = { command = "deno", args = ["lsp"] } "#; - let base: Value = toml::from_slice(include_bytes!("../../languages.toml")) - .expect("Couldn't parse built-in languages config"); + let base = include_bytes!("../../languages.toml"); + let base = str::from_utf8(base).expect("Couldn't parse built-in languages config"); + let base: Value = toml::from_str(base).expect("Couldn't parse built-in languages config"); let user: Value = toml::from_str(USER).unwrap(); let merged = merge_toml_values(base, user, 3); diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index cb0d3ac4..9eae88a8 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -1,6 +1,7 @@ use std::{ collections::HashMap, path::{Path, PathBuf}, + str, }; use anyhow::{anyhow, Context, Result}; @@ -15,12 +16,13 @@ use crate::graphics::UnderlineStyle; pub use crate::graphics::{Color, Modifier, Style}; pub static DEFAULT_THEME_DATA: Lazy = Lazy::new(|| { - toml::from_slice(include_bytes!("../../theme.toml")).expect("Failed to parse default theme") + let bytes = include_bytes!("../../theme.toml"); + toml::from_str(str::from_utf8(bytes).unwrap()).expect("Failed to parse base default theme") }); pub static BASE16_DEFAULT_THEME_DATA: Lazy = Lazy::new(|| { - toml::from_slice(include_bytes!("../../base16_theme.toml")) - .expect("Failed to parse base 16 default theme") + let bytes = include_bytes!("../../base16_theme.toml"); + toml::from_str(str::from_utf8(bytes).unwrap()).expect("Failed to parse base 16 default theme") }); pub static DEFAULT_THEME: Lazy = Lazy::new(|| Theme { @@ -148,8 +150,8 @@ impl Loader { // Loads the theme data as `toml::Value` first from the user_dir then in default_dir fn load_toml(&self, path: PathBuf) -> Result { - let data = std::fs::read(&path)?; - let value = toml::from_slice(data.as_slice())?; + let data = std::fs::read_to_string(&path)?; + let value = toml::from_str(&data)?; Ok(value) } diff --git a/xtask/src/helpers.rs b/xtask/src/helpers.rs index 4f759e74..f96cdfb3 100644 --- a/xtask/src/helpers.rs +++ b/xtask/src/helpers.rs @@ -39,6 +39,6 @@ pub fn find_files(dir: &Path, filename: &str) -> Vec { } pub fn lang_config() -> LangConfig { - let bytes = std::fs::read(path::lang_config()).unwrap(); - toml::from_slice(&bytes).unwrap() + let text = std::fs::read_to_string(path::lang_config()).unwrap(); + toml::from_str(&text).unwrap() } diff --git a/xtask/src/themelint.rs b/xtask/src/themelint.rs index 06dfae40..e9980574 100644 --- a/xtask/src/themelint.rs +++ b/xtask/src/themelint.rs @@ -156,8 +156,8 @@ pub fn lint(file: String) -> Result<(), DynError> { return Ok(()); } let path = path::themes().join(file.clone() + ".toml"); - let theme = std::fs::read(&path).unwrap(); - let theme: Theme = toml::from_slice(&theme).expect("Failed to parse theme"); + let theme = std::fs::read_to_string(&path).unwrap(); + let theme: Theme = toml::from_str(&theme).expect("Failed to parse theme"); let mut messages: Vec = vec![]; get_rules().iter().for_each(|lint| match lint { From 52d854fa62e58909d5abb803bdf225b2a5069a4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jan 2023 11:10:35 -0600 Subject: [PATCH 049/342] build(deps): bump toml from 0.5.10 to 0.6.0 Bumps [toml](https://github.com/toml-rs/toml) from 0.5.10 to 0.6.0. - [Release notes](https://github.com/toml-rs/toml/releases) - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.5.10...toml-v0.6.0) --- updated-dependencies: - dependency-name: toml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 57 +++++++++++++++++++++++++++++++++++++++-- helix-core/Cargo.toml | 2 +- helix-loader/Cargo.toml | 2 +- helix-term/Cargo.toml | 2 +- helix-view/Cargo.toml | 2 +- xtask/Cargo.toml | 2 +- 6 files changed, 60 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96d75697..f7812f4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1379,6 +1379,16 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indoc" version = "1.0.8" @@ -1546,6 +1556,15 @@ 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" @@ -1867,6 +1886,15 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_spanned" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c68e921cef53841b8925c2abadd27c9b891d9613bdc43d6b823062866df38e8" +dependencies = [ + "serde", +] + [[package]] name = "sha1_smol" version = "1.0.0" @@ -2164,11 +2192,36 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.10" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb9d890e4dc9298b70f740f615f2e05b9db37dce531f6b24fb77ac993f9f217" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +checksum = "729bfd096e40da9c001f778f5cdecbd2957929a24e10e5883d9392220a751581" dependencies = [ + "indexmap", + "nom8", "serde", + "serde_spanned", + "toml_datetime", ] [[package]] diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 73e64cfd..bfe1106d 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -36,7 +36,7 @@ hashbrown = { version = "0.13.2", features = ["raw"] } log = "0.4" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -toml = "0.5" +toml = "0.6" imara-diff = "0.1.0" diff --git a/helix-loader/Cargo.toml b/helix-loader/Cargo.toml index a3d14584..5d0f0013 100644 --- a/helix-loader/Cargo.toml +++ b/helix-loader/Cargo.toml @@ -16,7 +16,7 @@ path = "src/main.rs" [dependencies] anyhow = "1" serde = { version = "1.0", features = ["derive"] } -toml = "0.5" +toml = "0.6" etcetera = "0.4" tree-sitter = "0.20" once_cell = "1.17" diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index d4eebefb..5736ecde 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -61,7 +61,7 @@ pulldown-cmark = { version = "0.9", default-features = false } content_inspector = "0.2.4" # config -toml = "0.5" +toml = "0.6" serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index c75291cc..a4b97f86 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -39,7 +39,7 @@ chardetng = "0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -toml = "0.5" +toml = "0.6" log = "~0.4" which = "4.4" diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 127b931c..2811ed05 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -10,4 +10,4 @@ helix-term = { version = "0.6", path = "../helix-term" } helix-core = { version = "0.6", path = "../helix-core" } helix-view = { version = "0.6", path = "../helix-view" } helix-loader = { version = "0.6", path = "../helix-loader" } -toml = "0.5" +toml = "0.6" From b3e9f6233a64bb08dcb87788d5ca54dd25f13a27 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 24 Jan 2023 11:11:07 -0600 Subject: [PATCH 050/342] Fix compatibility with toml 0.6.0 `toml::from_slice` has been removed. The CHANGELOG recommends using `toml::from_str` instead and doing the byte-to-str conversion yourself. The `toml::toml!` macro has also changed to return the type of the value declared within the macro body. In the change in `helix-view/src/theme.rs` this is a `toml::map::Map` (it was a `toml::Value` previously) allowing us to skip the match and use the map directly. Co-authored-by: Pascal Kuthe --- helix-core/tests/indent.rs | 4 ++-- helix-view/src/theme.rs | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/helix-core/tests/indent.rs b/helix-core/tests/indent.rs index e1114f4a..f74b576a 100644 --- a/helix-core/tests/indent.rs +++ b/helix-core/tests/indent.rs @@ -28,8 +28,8 @@ fn test_treesitter_indent(file_name: &str, lang_scope: &str) { let mut config_file = test_dir; config_file.push("languages.toml"); - let config = std::fs::read(config_file).unwrap(); - let config = toml::from_slice(&config).unwrap(); + let config = std::fs::read_to_string(config_file).unwrap(); + let config = toml::from_str(&config).unwrap(); let loader = Loader::new(config); // set runtime path so we can find the queries diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 9eae88a8..ead0b9fb 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -517,10 +517,8 @@ mod tests { let mut style = Style::default(); let palette = ThemePalette::default(); - if let Value::Table(entries) = table { - for (_name, value) in entries { - palette.parse_style(&mut style, value).unwrap(); - } + for (_name, value) in table { + palette.parse_style(&mut style, value).unwrap(); } assert_eq!( From 70887b7378d642226ad5102fbe601fecb225225c Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 24 Jan 2023 11:07:46 -0600 Subject: [PATCH 051/342] Refactor toml::Value->Theme conversion The `From` implementation for `Theme` converted the Value to a string and re-parsed the string to convert it to `HashMap` which feels a bit wasteful. This change uses the underlying `toml::map::Map` directly when the value is a table and warns about the unexpected `Value` shape otherwise. This is necessary because toml 0.6.0 changes the Display implementation for Value::Table so that the `to_string` no longer encodes the value as a Document, just a Value. So the parse of the Value fails to be decoded as a HashMap. The behavior for returning `Default::default` matches the previous code's behavior except that it did not warn when the input Value was failed to parse. --- helix-view/src/theme.rs | 78 ++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index ead0b9fb..43d4a7a7 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -4,7 +4,7 @@ use std::{ str, }; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Result}; use helix_core::hashmap; use helix_loader::merge_toml_values; use log::warn; @@ -209,16 +209,18 @@ pub struct Theme { impl From for Theme { fn from(value: Value) -> Self { - let values: Result> = - toml::from_str(&value.to_string()).context("Failed to load theme"); - - let (styles, scopes, highlights) = build_theme_values(values); - - Self { - styles, - scopes, - highlights, - ..Default::default() + if let Value::Table(table) = value { + let (styles, scopes, highlights) = build_theme_values(table); + + Self { + styles, + scopes, + highlights, + ..Default::default() + } + } else { + warn!("Expected theme TOML value to be a table, found {:?}", value); + Default::default() } } } @@ -228,9 +230,9 @@ impl<'de> Deserialize<'de> for Theme { where D: Deserializer<'de>, { - let values = HashMap::::deserialize(deserializer)?; + let values = Map::::deserialize(deserializer)?; - let (styles, scopes, highlights) = build_theme_values(Ok(values)); + let (styles, scopes, highlights) = build_theme_values(values); Ok(Self { styles, @@ -242,39 +244,37 @@ impl<'de> Deserialize<'de> for Theme { } fn build_theme_values( - values: Result>, + mut values: Map, ) -> (HashMap, Vec, Vec