mirror of https://github.com/helix-editor/helix
Merge branch 'master' into help-command
commit
063edb12ea
@ -0,0 +1,60 @@
|
|||||||
|
# Adding languages
|
||||||
|
|
||||||
|
## Submodules
|
||||||
|
|
||||||
|
To add a new language, you should first add a tree-sitter submodule. To do this,
|
||||||
|
you can run the command
|
||||||
|
```sh
|
||||||
|
git submodule add -f <repository> helix-syntax/languages/tree-sitter-<name>
|
||||||
|
```
|
||||||
|
For example, to add tree-sitter-ocaml you would run
|
||||||
|
```sh
|
||||||
|
git submodule add -f https://github.com/tree-sitter/tree-sitter-ocaml helix-syntax/languages/tree-sitter-ocaml
|
||||||
|
```
|
||||||
|
Make sure the submodule is shallow by doing
|
||||||
|
```sh
|
||||||
|
git config -f .gitmodules submodule.helix-syntax/languages/tree-sitter-<name>.shallow true
|
||||||
|
```
|
||||||
|
|
||||||
|
or you can manually add `shallow = true` to `.gitmodules`.
|
||||||
|
|
||||||
|
## languages.toml
|
||||||
|
|
||||||
|
Next, you need to add the language to the [`languages.toml`][languages.toml] found in the root of
|
||||||
|
the repository; this `languages.toml` file is included at compilation time, and
|
||||||
|
is distinct from the `language.toml` file in the user's [configuration
|
||||||
|
directory](../configuration.md).
|
||||||
|
|
||||||
|
These are the available keys and descriptions for the file.
|
||||||
|
|
||||||
|
| Key | Description |
|
||||||
|
| ---- | ----------- |
|
||||||
|
| name | The name of the language |
|
||||||
|
| scope | A string like `source.js` that identifies the language. Currently, we strive to match the scope names used by popular TextMate grammars and by the Linguist library. Usually `source.<name>` or `text.<name>` in case of markup languages |
|
||||||
|
| injection-regex | regex pattern that will be tested against a language name in order to determine whether this language should be used for a potential [language injection][treesitter-language-injection] site. |
|
||||||
|
| file-types | The filetypes of the language, for example `["yml", "yaml"]` |
|
||||||
|
| shebangs | The interpreters from the shebang line, for example `["sh", "bash"]` |
|
||||||
|
| roots | A set of marker files to look for when trying to find the workspace root. For example `Cargo.lock`, `yarn.lock` |
|
||||||
|
| auto-format | Whether to autoformat this language when saving |
|
||||||
|
| comment-token | The token to use as a comment-token |
|
||||||
|
| indent | The indent to use. Has sub keys `tab-width` and `unit` |
|
||||||
|
| config | Language server configuration |
|
||||||
|
|
||||||
|
## Queries
|
||||||
|
|
||||||
|
For a language to have syntax-highlighting and indentation among other things, you have to add queries. Add a directory for your language with the path `runtime/queries/<name>/`. The tree-sitter [website](https://tree-sitter.github.io/tree-sitter/syntax-highlighting#queries) gives more info on how to write queries.
|
||||||
|
|
||||||
|
## Common Issues
|
||||||
|
|
||||||
|
- If you get errors when building after switching branches, you may have to remove or update tree-sitter submodules. You can update submodules by running
|
||||||
|
```sh
|
||||||
|
git submodule sync; git submodule update --init
|
||||||
|
```
|
||||||
|
- Make sure to not use the `--remote` flag. To remove submodules look inside the `.gitmodules` and remove directories that are not present inside of it.
|
||||||
|
|
||||||
|
- If a parser is segfaulting or you want to remove the parser, make sure to remove the submodule *and* the compiled parser in `runtime/grammar/<name>.so`
|
||||||
|
|
||||||
|
- The indents query is `indents.toml`, *not* `indents.scm`. See [this](https://github.com/helix-editor/helix/issues/114) issue for more information.
|
||||||
|
|
||||||
|
[treesitter-language-injection]: https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection
|
||||||
|
[languages.toml]: https://github.com/helix-editor/helix/blob/master/languages.toml
|
@ -0,0 +1,14 @@
|
|||||||
|
# Languages
|
||||||
|
|
||||||
|
Language-specific settings and settings for particular language servers can be configured in a `languages.toml` file placed in your [configuration directory](./configuration.md). Helix actually uses two `languages.toml` files, the [first one](https://github.com/helix-editor/helix/blob/master/languages.toml) is in the main helix repository; it contains the default settings for each language and is included in the helix binary at compile time. Users who want to see the available settings and options can either reference the helix repo's `languages.toml` file, or consult the table in the [adding languages](./guides/adding_languages.md) section.
|
||||||
|
|
||||||
|
Changes made to the `languages.toml` file in a user's [configuration directory](./configuration.md) are merged with helix's defaults on start-up, such that a user's settings will take precedence over defaults in the event of a collision. For example, the default `languages.toml` sets rust's `auto-format` to `true`. If a user wants to disable auto-format, they can change the `languages.toml` in their [configuration directory](./configuration.md) to make the rust entry read like the example below; the new key/value pair `auto-format = false` will override the default when the two sets of settings are merged on start-up:
|
||||||
|
|
||||||
|
```
|
||||||
|
# in <config_dir>/helix/languages.toml
|
||||||
|
|
||||||
|
[[language]]
|
||||||
|
name = "rust"
|
||||||
|
auto-format = false
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,490 @@
|
|||||||
|
use chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use regex::Regex;
|
||||||
|
use ropey::RopeSlice;
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::cmp;
|
||||||
|
|
||||||
|
use super::Increment;
|
||||||
|
use crate::{Range, Tendril};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct DateTimeIncrementor {
|
||||||
|
date_time: NaiveDateTime,
|
||||||
|
range: Range,
|
||||||
|
fmt: &'static str,
|
||||||
|
field: DateField,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DateTimeIncrementor {
|
||||||
|
pub fn from_range(text: RopeSlice, range: Range) -> Option<DateTimeIncrementor> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} 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<str> = text.slice(from..to).into();
|
||||||
|
|
||||||
|
let captures = format.regex.captures(&text)?;
|
||||||
|
if captures.len() - 1 != format.fields.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(0, 0, 0)
|
||||||
|
}
|
||||||
|
(false, true) => {
|
||||||
|
let time = NaiveTime::parse_from_str(date_time, format.fmt).ok()?;
|
||||||
|
|
||||||
|
NaiveDate::from_ymd(0, 1, 1).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),
|
||||||
|
}
|
||||||
|
.unwrap_or(self.date_time);
|
||||||
|
|
||||||
|
(self.range, date_time.format(self.fmt).to_string().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORMATS: Lazy<Vec<Format>> = Lazy::new(|| {
|
||||||
|
vec![
|
||||||
|
Format::new("%Y-%m-%d %H:%M:%S"), // 2021-11-24 07:12:23
|
||||||
|
Format::new("%Y/%m/%d %H:%M:%S"), // 2021/11/24 07:12:23
|
||||||
|
Format::new("%Y-%m-%d %H:%M"), // 2021-11-24 07:12
|
||||||
|
Format::new("%Y/%m/%d %H:%M"), // 2021/11/24 07:12
|
||||||
|
Format::new("%Y-%m-%d"), // 2021-11-24
|
||||||
|
Format::new("%Y/%m/%d"), // 2021/11/24
|
||||||
|
Format::new("%a %b %d %Y"), // Wed Nov 24 2021
|
||||||
|
Format::new("%d-%b-%Y"), // 24-Nov-2021
|
||||||
|
Format::new("%Y %b %d"), // 2021 Nov 24
|
||||||
|
Format::new("%b %d, %Y"), // Nov 24, 2021
|
||||||
|
Format::new("%-I:%M:%S %P"), // 7:21:53 am
|
||||||
|
Format::new("%-I:%M %P"), // 7:21 am
|
||||||
|
Format::new("%-I:%M:%S %p"), // 7:21:53 AM
|
||||||
|
Format::new("%-I:%M %p"), // 7:21 AM
|
||||||
|
Format::new("%H:%M:%S"), // 23:24:23
|
||||||
|
Format::new("%H:%M"), // 23:24
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Format {
|
||||||
|
fmt: &'static str,
|
||||||
|
fields: Vec<DateField>,
|
||||||
|
regex: Regex,
|
||||||
|
max_len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Format {
|
||||||
|
fn new(fmt: &'static str) -> Self {
|
||||||
|
let mut remaining = fmt;
|
||||||
|
let mut fields = Vec::new();
|
||||||
|
let mut regex = String::new();
|
||||||
|
let mut max_len = 0;
|
||||||
|
|
||||||
|
while let Some(i) = remaining.find('%') {
|
||||||
|
let after = &remaining[i + 1..];
|
||||||
|
let mut chars = after.chars();
|
||||||
|
let c = chars.next().unwrap();
|
||||||
|
|
||||||
|
let spec_len = if c == '-' {
|
||||||
|
1 + chars.next().unwrap().len_utf8()
|
||||||
|
} else {
|
||||||
|
c.len_utf8()
|
||||||
|
};
|
||||||
|
|
||||||
|
let specifier = &after[..spec_len];
|
||||||
|
let field = DateField::from_specifier(specifier).unwrap();
|
||||||
|
fields.push(field);
|
||||||
|
max_len += field.max_len + remaining[..i].len();
|
||||||
|
regex += &remaining[..i];
|
||||||
|
regex += &format!("({})", field.regex);
|
||||||
|
remaining = &after[spec_len..];
|
||||||
|
}
|
||||||
|
|
||||||
|
let regex = Regex::new(®ex).unwrap();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
fmt,
|
||||||
|
fields,
|
||||||
|
regex,
|
||||||
|
max_len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Format {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.fmt == other.fmt && self.fields == other.fields && self.max_len == other.max_len
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Format {}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
struct DateField {
|
||||||
|
regex: &'static str,
|
||||||
|
unit: DateUnit,
|
||||||
|
max_len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DateField {
|
||||||
|
fn from_specifier(specifier: &str) -> Option<Self> {
|
||||||
|
match specifier {
|
||||||
|
"Y" => Some(DateField {
|
||||||
|
regex: r"\d{4}",
|
||||||
|
unit: DateUnit::Years,
|
||||||
|
max_len: 5,
|
||||||
|
}),
|
||||||
|
"y" => Some(DateField {
|
||||||
|
regex: r"\d\d",
|
||||||
|
unit: DateUnit::Years,
|
||||||
|
max_len: 2,
|
||||||
|
}),
|
||||||
|
"m" => Some(DateField {
|
||||||
|
regex: r"[0-1]\d",
|
||||||
|
unit: DateUnit::Months,
|
||||||
|
max_len: 2,
|
||||||
|
}),
|
||||||
|
"d" => Some(DateField {
|
||||||
|
regex: r"[0-3]\d",
|
||||||
|
unit: DateUnit::Days,
|
||||||
|
max_len: 2,
|
||||||
|
}),
|
||||||
|
"-d" => Some(DateField {
|
||||||
|
regex: r"[1-3]?\d",
|
||||||
|
unit: DateUnit::Days,
|
||||||
|
max_len: 2,
|
||||||
|
}),
|
||||||
|
"a" => Some(DateField {
|
||||||
|
regex: r"Sun|Mon|Tue|Wed|Thu|Fri|Sat",
|
||||||
|
unit: DateUnit::Days,
|
||||||
|
max_len: 3,
|
||||||
|
}),
|
||||||
|
"A" => Some(DateField {
|
||||||
|
regex: r"Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday",
|
||||||
|
unit: DateUnit::Days,
|
||||||
|
max_len: 9,
|
||||||
|
}),
|
||||||
|
"b" | "h" => Some(DateField {
|
||||||
|
regex: r"Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec",
|
||||||
|
unit: DateUnit::Months,
|
||||||
|
max_len: 3,
|
||||||
|
}),
|
||||||
|
"B" => Some(DateField {
|
||||||
|
regex: r"January|February|March|April|May|June|July|August|September|October|November|December",
|
||||||
|
unit: DateUnit::Months,
|
||||||
|
max_len: 9,
|
||||||
|
}),
|
||||||
|
"H" => Some(DateField {
|
||||||
|
regex: r"[0-2]\d",
|
||||||
|
unit: DateUnit::Hours,
|
||||||
|
max_len: 2,
|
||||||
|
}),
|
||||||
|
"M" => Some(DateField {
|
||||||
|
regex: r"[0-5]\d",
|
||||||
|
unit: DateUnit::Minutes,
|
||||||
|
max_len: 2,
|
||||||
|
}),
|
||||||
|
"S" => Some(DateField {
|
||||||
|
regex: r"[0-5]\d",
|
||||||
|
unit: DateUnit::Seconds,
|
||||||
|
max_len: 2,
|
||||||
|
}),
|
||||||
|
"I" => Some(DateField {
|
||||||
|
regex: r"[0-1]\d",
|
||||||
|
unit: DateUnit::Hours,
|
||||||
|
max_len: 2,
|
||||||
|
}),
|
||||||
|
"-I" => Some(DateField {
|
||||||
|
regex: r"1?\d",
|
||||||
|
unit: DateUnit::Hours,
|
||||||
|
max_len: 2,
|
||||||
|
}),
|
||||||
|
"P" => Some(DateField {
|
||||||
|
regex: r"am|pm",
|
||||||
|
unit: DateUnit::AmPm,
|
||||||
|
max_len: 2,
|
||||||
|
}),
|
||||||
|
"p" => Some(DateField {
|
||||||
|
regex: r"AM|PM",
|
||||||
|
unit: DateUnit::AmPm,
|
||||||
|
max_len: 2,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
enum DateUnit {
|
||||||
|
Years,
|
||||||
|
Months,
|
||||||
|
Days,
|
||||||
|
Hours,
|
||||||
|
Minutes,
|
||||||
|
Seconds,
|
||||||
|
AmPm,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DateUnit {
|
||||||
|
fn is_date(self) -> bool {
|
||||||
|
matches!(self, DateUnit::Years | DateUnit::Months | DateUnit::Days)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_time(self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
DateUnit::Hours | DateUnit::Minutes | DateUnit::Seconds
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(y, m, 1);
|
||||||
|
|
||||||
|
// ...is preceded by the last day of the original month.
|
||||||
|
d.pred().day()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_months(date_time: NaiveDateTime, amount: i64) -> Option<NaiveDateTime> {
|
||||||
|
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));
|
||||||
|
|
||||||
|
Some(NaiveDate::from_ymd(year, month, day).and_time(date_time.time()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_years(date_time: NaiveDateTime, amount: i64) -> Option<NaiveDateTime> {
|
||||||
|
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 {
|
||||||
|
let d = NaiveDate::from_ymd(year, date_time.month(), ndays);
|
||||||
|
Some(d.succ().and_time(date_time.time()))
|
||||||
|
} else {
|
||||||
|
date_time.with_year(year)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_duration(date_time: NaiveDateTime, duration: Duration) -> Option<NaiveDateTime> {
|
||||||
|
date_time.checked_add_signed(duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle_am_pm(date_time: NaiveDateTime) -> Option<NaiveDateTime> {
|
||||||
|
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"),
|
||||||
|
];
|
||||||
|
|
||||||
|
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,
|
||||||
|
expected.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_invalid_date_times() {
|
||||||
|
let tests = [
|
||||||
|
"0000-00-00",
|
||||||
|
"1980-2-21",
|
||||||
|
"1980-12-1",
|
||||||
|
"12345",
|
||||||
|
"2020-02-30",
|
||||||
|
"1999-12-32",
|
||||||
|
"19-12-32",
|
||||||
|
"1-2-3",
|
||||||
|
"0000/00/00",
|
||||||
|
"1980/2/21",
|
||||||
|
"1980/12/1",
|
||||||
|
"12345",
|
||||||
|
"2020/02/30",
|
||||||
|
"1999/12/32",
|
||||||
|
"19/12/32",
|
||||||
|
"1/2/3",
|
||||||
|
"123:456:789",
|
||||||
|
"11:61",
|
||||||
|
"2021-55-12 08:12:54",
|
||||||
|
];
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
pub mod date_time;
|
||||||
|
pub mod number;
|
||||||
|
|
||||||
|
use crate::{Range, Tendril};
|
||||||
|
|
||||||
|
pub trait Increment {
|
||||||
|
fn increment(&self, amount: i64) -> (Range, Tendril);
|
||||||
|
}
|
@ -0,0 +1,507 @@
|
|||||||
|
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<NumberIncrementor> {
|
||||||
|
// 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<str> = 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<usize> = 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 + 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: {}", 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,
|
||||||
|
expected.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_increment_basic_hexadedimal_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,
|
||||||
|
expected.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
expected.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
expected.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
expected.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,48 +1,92 @@
|
|||||||
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{Rope, Syntax};
|
use crate::{Rope, Syntax};
|
||||||
|
|
||||||
const PAIRS: &[(char, char)] = &[('(', ')'), ('{', '}'), ('[', ']'), ('<', '>')];
|
const PAIRS: &[(char, char)] = &[
|
||||||
|
('(', ')'),
|
||||||
|
('{', '}'),
|
||||||
|
('[', ']'),
|
||||||
|
('<', '>'),
|
||||||
|
('\'', '\''),
|
||||||
|
('\"', '\"'),
|
||||||
|
];
|
||||||
|
|
||||||
// limit matching pairs to only ( ) { } [ ] < >
|
// limit matching pairs to only ( ) { } [ ] < >
|
||||||
|
|
||||||
|
// Returns the position of the matching bracket under cursor.
|
||||||
|
//
|
||||||
|
// If the cursor is one the opening bracket, the position of
|
||||||
|
// the closing bracket is returned. If the cursor in the closing
|
||||||
|
// bracket, the position of the opening bracket is returned.
|
||||||
|
//
|
||||||
|
// If the cursor is not on a bracket, `None` is returned.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn find(syntax: &Syntax, doc: &Rope, pos: usize) -> Option<usize> {
|
pub fn find_matching_bracket(syntax: &Syntax, doc: &Rope, pos: usize) -> Option<usize> {
|
||||||
let tree = syntax.tree();
|
if pos >= doc.len_chars() || !is_valid_bracket(doc.char(pos)) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
find_pair(syntax, doc, pos, false)
|
||||||
|
}
|
||||||
|
|
||||||
let byte_pos = doc.char_to_byte(pos);
|
// Returns the position of the bracket that is closing the current scope.
|
||||||
|
//
|
||||||
|
// If the cursor is on an opening or closing bracket, the function
|
||||||
|
// behaves equivalent to [`find_matching_bracket`].
|
||||||
|
//
|
||||||
|
// If the cursor position is within a scope, the function searches
|
||||||
|
// for the surrounding scope that is surrounded by brackets and
|
||||||
|
// returns the position of the closing bracket for that scope.
|
||||||
|
//
|
||||||
|
// If no surrounding scope is found, the function returns `None`.
|
||||||
|
#[must_use]
|
||||||
|
pub fn find_matching_bracket_fuzzy(syntax: &Syntax, doc: &Rope, pos: usize) -> Option<usize> {
|
||||||
|
find_pair(syntax, doc, pos, true)
|
||||||
|
}
|
||||||
|
|
||||||
// most naive implementation: find the innermost syntax node, if we're at the edge of a node,
|
fn find_pair(syntax: &Syntax, doc: &Rope, pos: usize, traverse_parents: bool) -> Option<usize> {
|
||||||
// return the other edge.
|
let tree = syntax.tree();
|
||||||
|
let pos = doc.char_to_byte(pos);
|
||||||
|
|
||||||
let node = match tree
|
let mut node = tree.root_node().named_descendant_for_byte_range(pos, pos)?;
|
||||||
.root_node()
|
|
||||||
.named_descendant_for_byte_range(byte_pos, byte_pos)
|
|
||||||
{
|
|
||||||
Some(node) => node,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
if node.is_error() {
|
loop {
|
||||||
return None;
|
let (start_byte, end_byte) = surrounding_bytes(doc, &node)?;
|
||||||
|
let (start_char, end_char) = (doc.byte_to_char(start_byte), doc.byte_to_char(end_byte));
|
||||||
|
|
||||||
|
if is_valid_pair(doc, start_char, end_char) {
|
||||||
|
if end_byte == pos {
|
||||||
|
return Some(start_char);
|
||||||
|
}
|
||||||
|
// We return the end char if the cursor is either on the start char
|
||||||
|
// or at some arbitrary position between start and end char.
|
||||||
|
return Some(end_char);
|
||||||
}
|
}
|
||||||
|
|
||||||
let len = doc.len_bytes();
|
if traverse_parents {
|
||||||
let start_byte = node.start_byte();
|
node = node.parent()?;
|
||||||
let end_byte = node.end_byte().saturating_sub(1); // it's end exclusive
|
} else {
|
||||||
if start_byte >= len || end_byte >= len {
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let start_char = doc.byte_to_char(start_byte);
|
fn is_valid_bracket(c: char) -> bool {
|
||||||
let end_char = doc.byte_to_char(end_byte);
|
PAIRS.iter().any(|(l, r)| *l == c || *r == c)
|
||||||
|
|
||||||
if PAIRS.contains(&(doc.char(start_char), doc.char(end_char))) {
|
|
||||||
if start_byte == byte_pos {
|
|
||||||
return Some(end_char);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if end_byte == byte_pos {
|
fn is_valid_pair(doc: &Rope, start_char: usize, end_char: usize) -> bool {
|
||||||
return Some(start_char);
|
PAIRS.contains(&(doc.char(start_char), doc.char(end_char)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn surrounding_bytes(doc: &Rope, node: &Node) -> Option<(usize, usize)> {
|
||||||
|
let len = doc.len_bytes();
|
||||||
|
|
||||||
|
let start_byte = node.start_byte();
|
||||||
|
let end_byte = node.end_byte().saturating_sub(1);
|
||||||
|
|
||||||
|
if start_byte >= len || end_byte >= len {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
Some((start_byte, end_byte))
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 88408ffc5e27abcffced7010fc77396ae3636d7e
|
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 0ac2c6da562c7a2c26ed7e8691d4a590f7e8b90a
|
@ -0,0 +1 @@
|
|||||||
|
Subproject commit f00ff52251edbd58f4d39c9c3204383253032c11
|
@ -0,0 +1,12 @@
|
|||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let git_hash = Command::new("git")
|
||||||
|
.args(&["describe", "--dirty"])
|
||||||
|
.output()
|
||||||
|
.map(|x| String::from_utf8(x.stdout).ok())
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
.unwrap_or_else(|| String::from(env!("CARGO_PKG_VERSION")));
|
||||||
|
println!("cargo:rustc-env=VERSION_AND_GIT_HASH={}", git_hash);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,95 @@
|
|||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
use crate::{editor::Config, graphics::Style, Document, Theme, View};
|
||||||
|
|
||||||
|
pub type GutterFn<'doc> = Box<dyn Fn(usize, bool, &mut String) -> Option<Style> + 'doc>;
|
||||||
|
pub type Gutter =
|
||||||
|
for<'doc> fn(&'doc Document, &View, &Theme, &Config, bool, usize) -> GutterFn<'doc>;
|
||||||
|
|
||||||
|
pub fn diagnostic<'doc>(
|
||||||
|
doc: &'doc Document,
|
||||||
|
_view: &View,
|
||||||
|
theme: &Theme,
|
||||||
|
_config: &Config,
|
||||||
|
_is_focused: bool,
|
||||||
|
_width: usize,
|
||||||
|
) -> GutterFn<'doc> {
|
||||||
|
let warning = theme.get("warning");
|
||||||
|
let error = theme.get("error");
|
||||||
|
let info = theme.get("info");
|
||||||
|
let hint = theme.get("hint");
|
||||||
|
let diagnostics = doc.diagnostics();
|
||||||
|
|
||||||
|
Box::new(move |line: usize, _selected: bool, out: &mut String| {
|
||||||
|
use helix_core::diagnostic::Severity;
|
||||||
|
if let Some(diagnostic) = diagnostics.iter().find(|d| d.line == line) {
|
||||||
|
write!(out, "●").unwrap();
|
||||||
|
return Some(match diagnostic.severity {
|
||||||
|
Some(Severity::Error) => error,
|
||||||
|
Some(Severity::Warning) | None => warning,
|
||||||
|
Some(Severity::Info) => info,
|
||||||
|
Some(Severity::Hint) => hint,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn line_number<'doc>(
|
||||||
|
doc: &'doc Document,
|
||||||
|
view: &View,
|
||||||
|
theme: &Theme,
|
||||||
|
config: &Config,
|
||||||
|
is_focused: bool,
|
||||||
|
width: usize,
|
||||||
|
) -> GutterFn<'doc> {
|
||||||
|
let text = doc.text().slice(..);
|
||||||
|
let last_line = 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 linenr = theme.get("ui.linenr");
|
||||||
|
let linenr_select: Style = theme.try_get("ui.linenr.selected").unwrap_or(linenr);
|
||||||
|
|
||||||
|
let current_line = doc
|
||||||
|
.text()
|
||||||
|
.char_to_line(doc.selection(view.id).primary().cursor(text));
|
||||||
|
|
||||||
|
let config = config.line_number;
|
||||||
|
|
||||||
|
Box::new(move |line: usize, selected: bool, out: &mut String| {
|
||||||
|
if line == last_line && !draw_last {
|
||||||
|
write!(out, "{:>1$}", '~', width).unwrap();
|
||||||
|
Some(linenr)
|
||||||
|
} else {
|
||||||
|
use crate::editor::LineNumber;
|
||||||
|
let line = match config {
|
||||||
|
LineNumber::Absolute => line + 1,
|
||||||
|
LineNumber::Relative => {
|
||||||
|
if current_line == line {
|
||||||
|
line + 1
|
||||||
|
} else {
|
||||||
|
abs_diff(current_line, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let style = if selected && is_focused {
|
||||||
|
linenr_select
|
||||||
|
} else {
|
||||||
|
linenr
|
||||||
|
};
|
||||||
|
write!(out, "{:>1$}", line, width).unwrap();
|
||||||
|
Some(style)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
const fn abs_diff(a: usize, b: usize) -> usize {
|
||||||
|
if a > b {
|
||||||
|
a - b
|
||||||
|
} else {
|
||||||
|
b - a
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
; inherits: c
|
@ -0,0 +1,37 @@
|
|||||||
|
; inherits: c
|
||||||
|
|
||||||
|
[
|
||||||
|
"in"
|
||||||
|
"out"
|
||||||
|
"inout"
|
||||||
|
"uniform"
|
||||||
|
"shared"
|
||||||
|
"layout"
|
||||||
|
"attribute"
|
||||||
|
"varying"
|
||||||
|
"buffer"
|
||||||
|
"coherent"
|
||||||
|
"readonly"
|
||||||
|
"writeonly"
|
||||||
|
"precision"
|
||||||
|
"highp"
|
||||||
|
"mediump"
|
||||||
|
"lowp"
|
||||||
|
"centroid"
|
||||||
|
"sample"
|
||||||
|
"patch"
|
||||||
|
"smooth"
|
||||||
|
"flat"
|
||||||
|
"noperspective"
|
||||||
|
"invariant"
|
||||||
|
"precise"
|
||||||
|
] @keyword
|
||||||
|
|
||||||
|
"subroutine" @keyword.function
|
||||||
|
|
||||||
|
(extension_storage_class) @attribute
|
||||||
|
|
||||||
|
(
|
||||||
|
(identifier) @variable.builtin
|
||||||
|
(#match? @variable.builtin "^gl_")
|
||||||
|
)
|
@ -0,0 +1,19 @@
|
|||||||
|
indent = [
|
||||||
|
"init_declarator",
|
||||||
|
"compound_statement",
|
||||||
|
"preproc_arg",
|
||||||
|
"field_declaration_list",
|
||||||
|
"case_statement",
|
||||||
|
"conditional_expression",
|
||||||
|
"enumerator_list",
|
||||||
|
"struct_specifier",
|
||||||
|
"compound_literal_expression"
|
||||||
|
]
|
||||||
|
|
||||||
|
outdent = [
|
||||||
|
"#define",
|
||||||
|
"#ifdef",
|
||||||
|
"#endif",
|
||||||
|
"{",
|
||||||
|
"}"
|
||||||
|
]
|
@ -0,0 +1,3 @@
|
|||||||
|
(preproc_arg) @glsl
|
||||||
|
|
||||||
|
(comment) @comment
|
@ -0,0 +1 @@
|
|||||||
|
; inherits: c
|
@ -0,0 +1,9 @@
|
|||||||
|
indent = [
|
||||||
|
"object",
|
||||||
|
"array"
|
||||||
|
]
|
||||||
|
|
||||||
|
outdent = [
|
||||||
|
"]",
|
||||||
|
"}"
|
||||||
|
]
|
@ -0,0 +1,14 @@
|
|||||||
|
(type) @type
|
||||||
|
(statement) @keyword.operator
|
||||||
|
(number) @constant.numeric.integer
|
||||||
|
(comment) @comment
|
||||||
|
(string) @string
|
||||||
|
(label) @label
|
||||||
|
(keyword) @keyword
|
||||||
|
"ret" @keyword.control.return
|
||||||
|
(boolean) @constant.builtin.boolean
|
||||||
|
(float) @constant.numeric.float
|
||||||
|
(constant) @constant
|
||||||
|
(identifier) @variable
|
||||||
|
(symbol) @punctuation.delimiter
|
||||||
|
(bracket) @punctuation.bracket
|
@ -0,0 +1,181 @@
|
|||||||
|
; Variables
|
||||||
|
(variable_declaration
|
||||||
|
.
|
||||||
|
(scope) @keyword)
|
||||||
|
[
|
||||||
|
(single_var_declaration)
|
||||||
|
(scalar_variable)
|
||||||
|
(array_variable)
|
||||||
|
(hash_variable)
|
||||||
|
(hash_variable)
|
||||||
|
] @variable
|
||||||
|
|
||||||
|
|
||||||
|
[
|
||||||
|
(package_name)
|
||||||
|
(special_scalar_variable)
|
||||||
|
(special_array_variable)
|
||||||
|
(special_hash_variable)
|
||||||
|
(special_literal)
|
||||||
|
(super)
|
||||||
|
] @constant
|
||||||
|
|
||||||
|
(
|
||||||
|
[
|
||||||
|
(package_name)
|
||||||
|
(super)
|
||||||
|
]
|
||||||
|
.
|
||||||
|
("::" @operator)
|
||||||
|
)
|
||||||
|
|
||||||
|
(comments) @comment
|
||||||
|
(pod_statement) @comment.block.documentation
|
||||||
|
|
||||||
|
[
|
||||||
|
(use_no_statement)
|
||||||
|
(use_no_feature_statement)
|
||||||
|
(use_no_if_statement)
|
||||||
|
(use_no_version)
|
||||||
|
(use_constant_statement)
|
||||||
|
(use_parent_statement)
|
||||||
|
] @keyword
|
||||||
|
|
||||||
|
(use_constant_statement
|
||||||
|
constant: (identifier) @constant)
|
||||||
|
|
||||||
|
[
|
||||||
|
"require"
|
||||||
|
] @keyword
|
||||||
|
|
||||||
|
(method_invocation
|
||||||
|
.
|
||||||
|
(identifier) @variable)
|
||||||
|
|
||||||
|
(method_invocation
|
||||||
|
(arrow_operator)
|
||||||
|
.
|
||||||
|
(identifier) @function)
|
||||||
|
(method_invocation
|
||||||
|
function_name: (identifier) @function)
|
||||||
|
(named_block_statement
|
||||||
|
function_name: (identifier) @function)
|
||||||
|
|
||||||
|
(call_expression
|
||||||
|
function_name: (identifier) @function)
|
||||||
|
(function_definition
|
||||||
|
name: (identifier) @function)
|
||||||
|
[
|
||||||
|
(function)
|
||||||
|
(map)
|
||||||
|
(grep)
|
||||||
|
(bless)
|
||||||
|
] @function
|
||||||
|
|
||||||
|
[
|
||||||
|
"return"
|
||||||
|
"sub"
|
||||||
|
"package"
|
||||||
|
"BEGIN"
|
||||||
|
"END"
|
||||||
|
] @keyword.function
|
||||||
|
|
||||||
|
[
|
||||||
|
"("
|
||||||
|
")"
|
||||||
|
"["
|
||||||
|
"]"
|
||||||
|
"{"
|
||||||
|
"}"
|
||||||
|
] @punctuation.bracket
|
||||||
|
(standard_input_to_variable) @punctuation.bracket
|
||||||
|
|
||||||
|
[
|
||||||
|
"=~"
|
||||||
|
"or"
|
||||||
|
"="
|
||||||
|
"=="
|
||||||
|
"+"
|
||||||
|
"-"
|
||||||
|
"."
|
||||||
|
"//"
|
||||||
|
"||"
|
||||||
|
(arrow_operator)
|
||||||
|
(hash_arrow_operator)
|
||||||
|
(array_dereference)
|
||||||
|
(hash_dereference)
|
||||||
|
(to_reference)
|
||||||
|
(type_glob)
|
||||||
|
(hash_access_variable)
|
||||||
|
(ternary_expression)
|
||||||
|
(ternary_expression_in_hash)
|
||||||
|
] @operator
|
||||||
|
|
||||||
|
[
|
||||||
|
(regex_option)
|
||||||
|
(regex_option_for_substitution)
|
||||||
|
(regex_option_for_transliteration)
|
||||||
|
] @variable.parameter
|
||||||
|
|
||||||
|
(type_glob
|
||||||
|
(identifier) @variable)
|
||||||
|
(
|
||||||
|
(scalar_variable)
|
||||||
|
.
|
||||||
|
("->" @operator))
|
||||||
|
|
||||||
|
[
|
||||||
|
(word_list_qw)
|
||||||
|
(command_qx_quoted)
|
||||||
|
(string_single_quoted)
|
||||||
|
(string_double_quoted)
|
||||||
|
(string_qq_quoted)
|
||||||
|
(bareword)
|
||||||
|
(transliteration_tr_or_y)
|
||||||
|
] @string
|
||||||
|
|
||||||
|
[
|
||||||
|
(regex_pattern_qr)
|
||||||
|
(patter_matcher_m)
|
||||||
|
(substitution_pattern_s)
|
||||||
|
] @string.regexp
|
||||||
|
|
||||||
|
(escape_sequence) @string.special
|
||||||
|
|
||||||
|
[
|
||||||
|
","
|
||||||
|
(semi_colon)
|
||||||
|
(start_delimiter)
|
||||||
|
(end_delimiter)
|
||||||
|
(ellipsis_statement)
|
||||||
|
] @punctuation.delimiter
|
||||||
|
|
||||||
|
[
|
||||||
|
(integer)
|
||||||
|
(floating_point)
|
||||||
|
(scientific_notation)
|
||||||
|
(hexadecimal)
|
||||||
|
] @constant.numeric
|
||||||
|
|
||||||
|
[
|
||||||
|
; (if_statement)
|
||||||
|
(unless_statement)
|
||||||
|
(if_simple_statement)
|
||||||
|
(unless_simple_statement)
|
||||||
|
] @keyword.control.conditional
|
||||||
|
|
||||||
|
[
|
||||||
|
"if"
|
||||||
|
"elsif"
|
||||||
|
"else"
|
||||||
|
] @keyword.control.conditional
|
||||||
|
|
||||||
|
(foreach_statement) @keyword.control.repeat
|
||||||
|
(foreach_statement
|
||||||
|
.
|
||||||
|
(scope) @keyword)
|
||||||
|
|
||||||
|
(function_attribute) @label
|
||||||
|
|
||||||
|
(function_signature) @type
|
||||||
|
|
@ -0,0 +1,8 @@
|
|||||||
|
(function_definition
|
||||||
|
(identifier) (_) @function.inside) @function.around
|
||||||
|
|
||||||
|
(anonymous_function
|
||||||
|
(_) @function.inside) @function.around
|
||||||
|
|
||||||
|
(argument
|
||||||
|
(_) @parameter.inside)
|
@ -0,0 +1,102 @@
|
|||||||
|
(const_literal) @constant.numeric
|
||||||
|
|
||||||
|
(type_declaration) @type
|
||||||
|
|
||||||
|
(function_declaration
|
||||||
|
(identifier) @function)
|
||||||
|
|
||||||
|
(struct_declaration
|
||||||
|
(identifier) @type)
|
||||||
|
|
||||||
|
(type_constructor_or_function_call_expression
|
||||||
|
(type_declaration) @function)
|
||||||
|
|
||||||
|
(parameter
|
||||||
|
(variable_identifier_declaration (identifier) @variable.parameter))
|
||||||
|
|
||||||
|
[
|
||||||
|
"struct"
|
||||||
|
"bitcast"
|
||||||
|
; "block"
|
||||||
|
"discard"
|
||||||
|
"enable"
|
||||||
|
"fallthrough"
|
||||||
|
"fn"
|
||||||
|
"let"
|
||||||
|
"private"
|
||||||
|
"read"
|
||||||
|
"read_write"
|
||||||
|
"return"
|
||||||
|
"storage"
|
||||||
|
"type"
|
||||||
|
"uniform"
|
||||||
|
"var"
|
||||||
|
"workgroup"
|
||||||
|
"write"
|
||||||
|
(texel_format)
|
||||||
|
] @keyword ; TODO reserved keywords
|
||||||
|
|
||||||
|
[
|
||||||
|
(true)
|
||||||
|
(false)
|
||||||
|
] @constant.builtin.boolean
|
||||||
|
|
||||||
|
[ "," "." ":" ";" ] @punctuation.delimiter
|
||||||
|
|
||||||
|
;; brackets
|
||||||
|
[
|
||||||
|
"("
|
||||||
|
")"
|
||||||
|
"["
|
||||||
|
"]"
|
||||||
|
"{"
|
||||||
|
"}"
|
||||||
|
] @punctuation.bracket
|
||||||
|
|
||||||
|
[
|
||||||
|
"loop"
|
||||||
|
"for"
|
||||||
|
"break"
|
||||||
|
"continue"
|
||||||
|
"continuing"
|
||||||
|
] @keyword.control.repeat
|
||||||
|
|
||||||
|
[
|
||||||
|
"if"
|
||||||
|
"else"
|
||||||
|
"elseif"
|
||||||
|
"switch"
|
||||||
|
"case"
|
||||||
|
"default"
|
||||||
|
] @keyword.control.conditional
|
||||||
|
|
||||||
|
[
|
||||||
|
"&"
|
||||||
|
"&&"
|
||||||
|
"/"
|
||||||
|
"!"
|
||||||
|
"="
|
||||||
|
"=="
|
||||||
|
"!="
|
||||||
|
">"
|
||||||
|
">="
|
||||||
|
">>"
|
||||||
|
"<"
|
||||||
|
"<="
|
||||||
|
"<<"
|
||||||
|
"%"
|
||||||
|
"-"
|
||||||
|
"+"
|
||||||
|
"|"
|
||||||
|
"||"
|
||||||
|
"*"
|
||||||
|
"~"
|
||||||
|
"^"
|
||||||
|
] @operator
|
||||||
|
|
||||||
|
(attribute
|
||||||
|
(identifier) @variable.other.member)
|
||||||
|
|
||||||
|
(comment) @comment
|
||||||
|
|
||||||
|
(ERROR) @error
|
@ -0,0 +1,102 @@
|
|||||||
|
# Author : WindSoilder<WindSoilder@outlook.com>
|
||||||
|
# The unofficial Monokai Pro theme, simply migrate from jetbrains monokai pro theme: https://github.com/subtheme-dev/monokai-pro
|
||||||
|
# Credit goes to the original creator: https://monokai.pro
|
||||||
|
|
||||||
|
"ui.linenr.selected" = { bg = "base3" }
|
||||||
|
"ui.text.focus" = { fg = "yellow", modifiers= ["bold"] }
|
||||||
|
"ui.menu.selected" = { fg = "base2", bg = "yellow" }
|
||||||
|
|
||||||
|
"info" = "base8"
|
||||||
|
"hint" = "base8"
|
||||||
|
|
||||||
|
# background color
|
||||||
|
"ui.background" = { bg = "base2" }
|
||||||
|
"ui.statusline.inactive" = { fg = "base8", bg = "base8x0c" }
|
||||||
|
|
||||||
|
# status bars, panels, modals, autocompletion
|
||||||
|
"ui.statusline" = { bg = "base4" }
|
||||||
|
"ui.popup" = { bg = "base3" }
|
||||||
|
"ui.window" = { bg = "base3" }
|
||||||
|
"ui.help" = { bg = "base3" }
|
||||||
|
|
||||||
|
# active line, highlighting
|
||||||
|
"ui.selection" = { bg = "base4" }
|
||||||
|
"ui.cursor.match" = { bg = "base4" }
|
||||||
|
|
||||||
|
# comments, nord3 based lighter color
|
||||||
|
"comment" = { fg = "base5", modifiers = ["italic"] }
|
||||||
|
"ui.linenr" = { fg = "base5" }
|
||||||
|
|
||||||
|
# cursor, variables, constants, attributes, fields
|
||||||
|
"ui.cursor.primary" = { fg = "base7", modifiers = ["reversed"] }
|
||||||
|
"attribute" = "blue"
|
||||||
|
"variable" = "base8"
|
||||||
|
"constant" = "orange"
|
||||||
|
"variable.builtin" = "red"
|
||||||
|
"constant.builtin" = "red"
|
||||||
|
"namespace" = "base8"
|
||||||
|
|
||||||
|
# base text, punctuation
|
||||||
|
"ui.text" = { fg = "base8" }
|
||||||
|
"punctuation" = "base6"
|
||||||
|
|
||||||
|
# classes, types, primiatives
|
||||||
|
"type" = "green"
|
||||||
|
"type.builtin" = { fg = "red"}
|
||||||
|
"label" = "base8"
|
||||||
|
|
||||||
|
# declaration, methods, routines
|
||||||
|
"constructor" = "blue"
|
||||||
|
"function" = "green"
|
||||||
|
"function.macro" = { fg = "blue" }
|
||||||
|
"function.builtin" = { fg = "cyan" }
|
||||||
|
|
||||||
|
# operator, tags, units, punctuations
|
||||||
|
"operator" = "red"
|
||||||
|
"variable.other.member" = "base8"
|
||||||
|
|
||||||
|
# keywords, special
|
||||||
|
"keyword" = { fg = "red" }
|
||||||
|
"keyword.directive" = "blue"
|
||||||
|
"variable.parameter" = "#f59762"
|
||||||
|
|
||||||
|
# error
|
||||||
|
"error" = "red"
|
||||||
|
|
||||||
|
# annotations, decorators
|
||||||
|
"special" = "#f59762"
|
||||||
|
"module" = "#f59762"
|
||||||
|
|
||||||
|
# warnings, escape characters, regex
|
||||||
|
"warning" = "orange"
|
||||||
|
"constant.character.escape" = { fg = "base8" }
|
||||||
|
|
||||||
|
# strings
|
||||||
|
"string" = "yellow"
|
||||||
|
|
||||||
|
# integer, floating point
|
||||||
|
"constant.numeric" = "purple"
|
||||||
|
|
||||||
|
# make diagnostic underlined, to distinguish with selection text.
|
||||||
|
diagnostic = { modifiers = ["underlined"] }
|
||||||
|
|
||||||
|
[palette]
|
||||||
|
# primary colors
|
||||||
|
"red" = "#ff6188"
|
||||||
|
"orange" = "#fc9867"
|
||||||
|
"yellow" = "#ffd866"
|
||||||
|
"green" = "#a9dc76"
|
||||||
|
"blue" = "#78dce8"
|
||||||
|
"purple" = "#ab9df2"
|
||||||
|
# base colors, sorted from darkest to lightest
|
||||||
|
"base0" = "#19181a"
|
||||||
|
"base1" = "#221f22"
|
||||||
|
"base2" = "#2d2a2e"
|
||||||
|
"base3" = "#403e41"
|
||||||
|
"base4" = "#5b595c"
|
||||||
|
"base5" = "#727072"
|
||||||
|
"base6" = "#939293"
|
||||||
|
"base7" = "#c1c0c0"
|
||||||
|
"base8" = "#fcfcfa"
|
||||||
|
# variants (for when transparency isn't supported)
|
||||||
|
"base8x0c" = "#363337" # using base2 as bg
|
@ -0,0 +1,102 @@
|
|||||||
|
# Author : WindSoilder<WindSoilder@outlook.com>
|
||||||
|
# The unofficial Monokai Pro theme, simply migrate from jetbrains monokai pro theme: https://github.com/subtheme-dev/monokai-pro
|
||||||
|
# Credit goes to the original creator: https://monokai.pro
|
||||||
|
|
||||||
|
"ui.linenr.selected" = { bg = "base3" }
|
||||||
|
"ui.text.focus" = { fg = "yellow", modifiers= ["bold"] }
|
||||||
|
"ui.menu.selected" = { fg = "base2", bg = "yellow" }
|
||||||
|
|
||||||
|
"info" = "base8"
|
||||||
|
"hint" = "base8"
|
||||||
|
|
||||||
|
# background color
|
||||||
|
"ui.background" = { bg = "base2" }
|
||||||
|
"ui.statusline.inactive" = { fg = "base8", bg = "base8x0c" }
|
||||||
|
|
||||||
|
# status bars, panels, modals, autocompletion
|
||||||
|
"ui.statusline" = { bg = "base4" }
|
||||||
|
"ui.popup" = { bg = "base3" }
|
||||||
|
"ui.window" = { bg = "base3" }
|
||||||
|
"ui.help" = { bg = "base3" }
|
||||||
|
|
||||||
|
# active line, highlighting
|
||||||
|
"ui.selection" = { bg = "base4" }
|
||||||
|
"ui.cursor.match" = { bg = "base4" }
|
||||||
|
|
||||||
|
# comments, nord3 based lighter color
|
||||||
|
"comment" = { fg = "base5", modifiers = ["italic"] }
|
||||||
|
"ui.linenr" = { fg = "base5" }
|
||||||
|
|
||||||
|
# cursor, variables, constants, attributes, fields
|
||||||
|
"ui.cursor.primary" = { fg = "base7", modifiers = ["reversed"] }
|
||||||
|
"attribute" = "blue"
|
||||||
|
"variable" = "base8"
|
||||||
|
"constant" = "orange"
|
||||||
|
"variable.builtin" = "red"
|
||||||
|
"constant.builtin" = "red"
|
||||||
|
"namespace" = "base8"
|
||||||
|
|
||||||
|
# base text, punctuation
|
||||||
|
"ui.text" = { fg = "base8" }
|
||||||
|
"punctuation" = "base6"
|
||||||
|
|
||||||
|
# classes, types, primiatives
|
||||||
|
"type" = "green"
|
||||||
|
"type.builtin" = { fg = "red"}
|
||||||
|
"label" = "base8"
|
||||||
|
|
||||||
|
# declaration, methods, routines
|
||||||
|
"constructor" = "blue"
|
||||||
|
"function" = "green"
|
||||||
|
"function.macro" = { fg = "blue" }
|
||||||
|
"function.builtin" = { fg = "cyan" }
|
||||||
|
|
||||||
|
# operator, tags, units, punctuations
|
||||||
|
"operator" = "red"
|
||||||
|
"variable.other.member" = "base8"
|
||||||
|
|
||||||
|
# keywords, special
|
||||||
|
"keyword" = { fg = "red" }
|
||||||
|
"keyword.directive" = "blue"
|
||||||
|
"variable.parameter" = "#f59762"
|
||||||
|
|
||||||
|
# error
|
||||||
|
"error" = "red"
|
||||||
|
|
||||||
|
# annotations, decorators
|
||||||
|
"special" = "#f59762"
|
||||||
|
"module" = "#f59762"
|
||||||
|
|
||||||
|
# warnings, escape characters, regex
|
||||||
|
"warning" = "orange"
|
||||||
|
"constant.character.escape" = { fg = "base8" }
|
||||||
|
|
||||||
|
# strings
|
||||||
|
"string" = "yellow"
|
||||||
|
|
||||||
|
# integer, floating point
|
||||||
|
"constant.numeric" = "purple"
|
||||||
|
|
||||||
|
# make diagnostic underlined, to distinguish with selection text.
|
||||||
|
diagnostic = { modifiers = ["underlined"] }
|
||||||
|
|
||||||
|
[palette]
|
||||||
|
# primary colors
|
||||||
|
"red" = "#ff6d7e"
|
||||||
|
"orange" = "#ffb270"
|
||||||
|
"yellow" = "#ffed72"
|
||||||
|
"green" = "#a2e57b"
|
||||||
|
"blue" = "#7cd5f1"
|
||||||
|
"purple" = "#baa0f8"
|
||||||
|
# base colors
|
||||||
|
"base0" = "#161b1e"
|
||||||
|
"base1" = "#1d2528"
|
||||||
|
"base2" = "#273136"
|
||||||
|
"base3" = "#3a4449"
|
||||||
|
"base4" = "#545f62"
|
||||||
|
"base5" = "#6b7678"
|
||||||
|
"base6" = "#798384"
|
||||||
|
"base7" = "#b8c4c3"
|
||||||
|
"base8" = "#f2fffc"
|
||||||
|
# variants
|
||||||
|
"base8x0c" = "#303a3e"
|
@ -0,0 +1,102 @@
|
|||||||
|
# Author : WindSoilder<WindSoilder@outlook.com>
|
||||||
|
# The unofficial Monokai Pro theme, simply migrate from jetbrains monokai pro theme: https://github.com/subtheme-dev/monokai-pro
|
||||||
|
# Credit goes to the original creator: https://monokai.pro
|
||||||
|
|
||||||
|
"ui.linenr.selected" = { bg = "base3" }
|
||||||
|
"ui.text.focus" = { fg = "yellow", modifiers= ["bold"] }
|
||||||
|
"ui.menu.selected" = { fg = "base2", bg = "yellow" }
|
||||||
|
|
||||||
|
"info" = "base8"
|
||||||
|
"hint" = "base8"
|
||||||
|
|
||||||
|
# background color
|
||||||
|
"ui.background" = { bg = "base2" }
|
||||||
|
"ui.statusline.inactive" = { fg = "base8", bg = "base8x0c" }
|
||||||
|
|
||||||
|
# status bars, panels, modals, autocompletion
|
||||||
|
"ui.statusline" = { bg = "base4" }
|
||||||
|
"ui.popup" = { bg = "base3" }
|
||||||
|
"ui.window" = { bg = "base3" }
|
||||||
|
"ui.help" = { bg = "base3" }
|
||||||
|
|
||||||
|
# active line, highlighting
|
||||||
|
"ui.selection" = { bg = "base4" }
|
||||||
|
"ui.cursor.match" = { bg = "base4" }
|
||||||
|
|
||||||
|
# comments, nord3 based lighter color
|
||||||
|
"comment" = { fg = "base5", modifiers = ["italic"] }
|
||||||
|
"ui.linenr" = { fg = "base5" }
|
||||||
|
|
||||||
|
# cursor, variables, constants, attributes, fields
|
||||||
|
"ui.cursor.primary" = { fg = "base7", modifiers = ["reversed"] }
|
||||||
|
"attribute" = "blue"
|
||||||
|
"variable" = "base8"
|
||||||
|
"constant" = "orange"
|
||||||
|
"variable.builtin" = "red"
|
||||||
|
"constant.builtin" = "red"
|
||||||
|
"namespace" = "base8"
|
||||||
|
|
||||||
|
# base text, punctuation
|
||||||
|
"ui.text" = { fg = "base8" }
|
||||||
|
"punctuation" = "base6"
|
||||||
|
|
||||||
|
# classes, types, primiatives
|
||||||
|
"type" = "green"
|
||||||
|
"type.builtin" = { fg = "red"}
|
||||||
|
"label" = "base8"
|
||||||
|
|
||||||
|
# declaration, methods, routines
|
||||||
|
"constructor" = "blue"
|
||||||
|
"function" = "green"
|
||||||
|
"function.macro" = { fg = "blue" }
|
||||||
|
"function.builtin" = { fg = "cyan" }
|
||||||
|
|
||||||
|
# operator, tags, units, punctuations
|
||||||
|
"operator" = "red"
|
||||||
|
"variable.other.member" = "base8"
|
||||||
|
|
||||||
|
# keywords, special
|
||||||
|
"keyword" = { fg = "red" }
|
||||||
|
"keyword.directive" = "blue"
|
||||||
|
"variable.parameter" = "#f59762"
|
||||||
|
|
||||||
|
# error
|
||||||
|
"error" = "red"
|
||||||
|
|
||||||
|
# annotations, decorators
|
||||||
|
"special" = "#f59762"
|
||||||
|
"module" = "#f59762"
|
||||||
|
|
||||||
|
# warnings, escape characters, regex
|
||||||
|
"warning" = "orange"
|
||||||
|
"constant.character.escape" = { fg = "base8" }
|
||||||
|
|
||||||
|
# strings
|
||||||
|
"string" = "yellow"
|
||||||
|
|
||||||
|
# integer, floating point
|
||||||
|
"constant.numeric" = "purple"
|
||||||
|
|
||||||
|
# make diagnostic underlined, to distinguish with selection text.
|
||||||
|
diagnostic = { modifiers = ["underlined"] }
|
||||||
|
|
||||||
|
[palette]
|
||||||
|
# primary colors
|
||||||
|
"red" = "#ff657a"
|
||||||
|
"orange" = "#ff9b5e"
|
||||||
|
"yellow" = "#ffd76d"
|
||||||
|
"green" = "#bad761"
|
||||||
|
"blue" = "#9cd1bb"
|
||||||
|
"purple" = "#c39ac9"
|
||||||
|
# base colors
|
||||||
|
"base0" = "#161821"
|
||||||
|
"base1" = "#1e1f2b"
|
||||||
|
"base2" = "#282a3a"
|
||||||
|
"base3" = "#3a3d4b"
|
||||||
|
"base4" = "#535763"
|
||||||
|
"base5" = "#696d77"
|
||||||
|
"base6" = "#767b81"
|
||||||
|
"base7" = "#b2b9bd"
|
||||||
|
"base8" = "#eaf2f1"
|
||||||
|
# variants
|
||||||
|
"base8x0c" = "#303342"
|
@ -0,0 +1,102 @@
|
|||||||
|
# Author : WindSoilder<WindSoilder@outlook.com>
|
||||||
|
# The unofficial Monokai Pro theme, simply migrate from jetbrains monokai pro theme: https://github.com/subtheme-dev/monokai-pro
|
||||||
|
# Credit goes to the original creator: https://monokai.pro
|
||||||
|
|
||||||
|
"ui.linenr.selected" = { bg = "base3" }
|
||||||
|
"ui.text.focus" = { fg = "yellow", modifiers= ["bold"] }
|
||||||
|
"ui.menu.selected" = { fg = "base2", bg = "yellow" }
|
||||||
|
|
||||||
|
"info" = "base8"
|
||||||
|
"hint" = "base8"
|
||||||
|
|
||||||
|
# background color
|
||||||
|
"ui.background" = { bg = "base2" }
|
||||||
|
"ui.statusline.inactive" = { fg = "base8", bg = "base8x0c" }
|
||||||
|
|
||||||
|
# status bars, panels, modals, autocompletion
|
||||||
|
"ui.statusline" = { bg = "base4" }
|
||||||
|
"ui.popup" = { bg = "base3" }
|
||||||
|
"ui.window" = { bg = "base3" }
|
||||||
|
"ui.help" = { bg = "base3" }
|
||||||
|
|
||||||
|
# active line, highlighting
|
||||||
|
"ui.selection" = { bg = "base4" }
|
||||||
|
"ui.cursor.match" = { bg = "base4" }
|
||||||
|
|
||||||
|
# comments, nord3 based lighter color
|
||||||
|
"comment" = { fg = "base5", modifiers = ["italic"] }
|
||||||
|
"ui.linenr" = { fg = "base5" }
|
||||||
|
|
||||||
|
# cursor, variables, constants, attributes, fields
|
||||||
|
"ui.cursor.primary" = { fg = "base7", modifiers = ["reversed"] }
|
||||||
|
"attribute" = "blue"
|
||||||
|
"variable" = "base8"
|
||||||
|
"constant" = "orange"
|
||||||
|
"variable.builtin" = "red"
|
||||||
|
"constant.builtin" = "red"
|
||||||
|
"namespace" = "base8"
|
||||||
|
|
||||||
|
# base text, punctuation
|
||||||
|
"ui.text" = { fg = "base8" }
|
||||||
|
"punctuation" = "base6"
|
||||||
|
|
||||||
|
# classes, types, primiatives
|
||||||
|
"type" = "green"
|
||||||
|
"type.builtin" = { fg = "red"}
|
||||||
|
"label" = "base8"
|
||||||
|
|
||||||
|
# declaration, methods, routines
|
||||||
|
"constructor" = "blue"
|
||||||
|
"function" = "green"
|
||||||
|
"function.macro" = { fg = "blue" }
|
||||||
|
"function.builtin" = { fg = "cyan" }
|
||||||
|
|
||||||
|
# operator, tags, units, punctuations
|
||||||
|
"operator" = "red"
|
||||||
|
"variable.other.member" = "base8"
|
||||||
|
|
||||||
|
# keywords, special
|
||||||
|
"keyword" = { fg = "red" }
|
||||||
|
"keyword.directive" = "blue"
|
||||||
|
"variable.parameter" = "#f59762"
|
||||||
|
|
||||||
|
# error
|
||||||
|
"error" = "red"
|
||||||
|
|
||||||
|
# annotations, decorators
|
||||||
|
"special" = "#f59762"
|
||||||
|
"module" = "#f59762"
|
||||||
|
|
||||||
|
# warnings, escape characters, regex
|
||||||
|
"warning" = "orange"
|
||||||
|
"constant.character.escape" = { fg = "base8" }
|
||||||
|
|
||||||
|
# strings
|
||||||
|
"string" = "yellow"
|
||||||
|
|
||||||
|
# integer, floating point
|
||||||
|
"constant.numeric" = "purple"
|
||||||
|
|
||||||
|
# make diagnostic underlined, to distinguish with selection text.
|
||||||
|
diagnostic = { modifiers = ["underlined"] }
|
||||||
|
|
||||||
|
[palette]
|
||||||
|
# primary colors
|
||||||
|
"red" = "#fd6883"
|
||||||
|
"orange" = "#f38d70"
|
||||||
|
"yellow" = "#f9cc6c"
|
||||||
|
"green" = "#adda78"
|
||||||
|
"blue" = "#85dacc"
|
||||||
|
"purple" = "#a8a9eb"
|
||||||
|
# base colors
|
||||||
|
"base0" = "#191515"
|
||||||
|
"base1" = "#211c1c"
|
||||||
|
"base2" = "#2c2525"
|
||||||
|
"base3" = "#403838"
|
||||||
|
"base4" = "#5b5353"
|
||||||
|
"base5" = "#72696a"
|
||||||
|
"base6" = "#8c8384"
|
||||||
|
"base7" = "#c3b7b8"
|
||||||
|
"base8" = "#fff1f3"
|
||||||
|
# variants
|
||||||
|
"base8x0c" = "#352e2e"
|
@ -0,0 +1,102 @@
|
|||||||
|
# Author : WindSoilder<WindSoilder@outlook.com>
|
||||||
|
# The unofficial Monokai Pro theme, simply migrate from jetbrains monokai pro theme: https://github.com/subtheme-dev/monokai-pro
|
||||||
|
# Credit goes to the original creator: https://monokai.pro
|
||||||
|
|
||||||
|
"ui.linenr.selected" = { bg = "base3" }
|
||||||
|
"ui.text.focus" = { fg = "yellow", modifiers= ["bold"] }
|
||||||
|
"ui.menu.selected" = { fg = "base2", bg = "yellow" }
|
||||||
|
|
||||||
|
"info" = "base8"
|
||||||
|
"hint" = "base8"
|
||||||
|
|
||||||
|
# background color
|
||||||
|
"ui.background" = { bg = "base2" }
|
||||||
|
"ui.statusline.inactive" = { fg = "base8", bg = "base8x0c" }
|
||||||
|
|
||||||
|
# status bars, panels, modals, autocompletion
|
||||||
|
"ui.statusline" = { bg = "base4" }
|
||||||
|
"ui.popup" = { bg = "base3" }
|
||||||
|
"ui.window" = { bg = "base3" }
|
||||||
|
"ui.help" = { bg = "base3" }
|
||||||
|
|
||||||
|
# active line, highlighting
|
||||||
|
"ui.selection" = { bg = "base4" }
|
||||||
|
"ui.cursor.match" = { bg = "base4" }
|
||||||
|
|
||||||
|
# comments, nord3 based lighter color
|
||||||
|
"comment" = { fg = "base5", modifiers = ["italic"] }
|
||||||
|
"ui.linenr" = { fg = "base5" }
|
||||||
|
|
||||||
|
# cursor, variables, constants, attributes, fields
|
||||||
|
"ui.cursor.primary" = { fg = "base7", modifiers = ["reversed"] }
|
||||||
|
"attribute" = "blue"
|
||||||
|
"variable" = "base8"
|
||||||
|
"constant" = "orange"
|
||||||
|
"variable.builtin" = "red"
|
||||||
|
"constant.builtin" = "red"
|
||||||
|
"namespace" = "base8"
|
||||||
|
|
||||||
|
# base text, punctuation
|
||||||
|
"ui.text" = { fg = "base8" }
|
||||||
|
"punctuation" = "base6"
|
||||||
|
|
||||||
|
# classes, types, primiatives
|
||||||
|
"type" = "green"
|
||||||
|
"type.builtin" = { fg = "red"}
|
||||||
|
"label" = "base8"
|
||||||
|
|
||||||
|
# declaration, methods, routines
|
||||||
|
"constructor" = "blue"
|
||||||
|
"function" = "green"
|
||||||
|
"function.macro" = { fg = "blue" }
|
||||||
|
"function.builtin" = { fg = "cyan" }
|
||||||
|
|
||||||
|
# operator, tags, units, punctuations
|
||||||
|
"operator" = "red"
|
||||||
|
"variable.other.member" = "base8"
|
||||||
|
|
||||||
|
# keywords, special
|
||||||
|
"keyword" = { fg = "red" }
|
||||||
|
"keyword.directive" = "blue"
|
||||||
|
"variable.parameter" = "#f59762"
|
||||||
|
|
||||||
|
# error
|
||||||
|
"error" = "red"
|
||||||
|
|
||||||
|
# annotations, decorators
|
||||||
|
"special" = "#f59762"
|
||||||
|
"module" = "#f59762"
|
||||||
|
|
||||||
|
# warnings, escape characters, regex
|
||||||
|
"warning" = "orange"
|
||||||
|
"constant.character.escape" = { fg = "base8" }
|
||||||
|
|
||||||
|
# strings
|
||||||
|
"string" = "yellow"
|
||||||
|
|
||||||
|
# integer, floating point
|
||||||
|
"constant.numeric" = "purple"
|
||||||
|
|
||||||
|
# make diagnostic underlined, to distinguish with selection text.
|
||||||
|
diagnostic = { modifiers = ["underlined"] }
|
||||||
|
|
||||||
|
[palette]
|
||||||
|
# primary colors
|
||||||
|
"red" = "#fc618d"
|
||||||
|
"orange" = "#fd9353"
|
||||||
|
"yellow" = "#fce566"
|
||||||
|
"green" = "#7bd88f"
|
||||||
|
"blue" = "#5ad4e6"
|
||||||
|
"purple" = "#948ae3"
|
||||||
|
# base colors
|
||||||
|
"base0" = "#131313"
|
||||||
|
"base1" = "#191919"
|
||||||
|
"base2" = "#222222"
|
||||||
|
"base3" = "#363537"
|
||||||
|
"base4" = "#525053"
|
||||||
|
"base5" = "#69676c"
|
||||||
|
"base6" = "#8b888f"
|
||||||
|
"base7" = "#bab6c0"
|
||||||
|
"base8" = "#f7f1ff"
|
||||||
|
# variants
|
||||||
|
"base8x0c" = "#2b2b2b"
|
@ -0,0 +1,63 @@
|
|||||||
|
# Author: ChrisHa<chunghha@users.noreply.github.com>
|
||||||
|
# Author: RayGervais<raygervais@hotmail.ca>
|
||||||
|
|
||||||
|
"ui.background" = { bg = "base" }
|
||||||
|
"ui.menu" = "surface"
|
||||||
|
"ui.menu.selected" = { fg = "iris", bg = "surface" }
|
||||||
|
"ui.linenr" = {fg = "subtle" }
|
||||||
|
"ui.popup" = { bg = "overlay" }
|
||||||
|
"ui.window" = { bg = "overlay" }
|
||||||
|
"ui.liner.selected" = "highlightOverlay"
|
||||||
|
"ui.selection" = "highlight"
|
||||||
|
"comment" = "subtle"
|
||||||
|
"ui.statusline" = {fg = "foam", bg = "surface" }
|
||||||
|
"ui.statusline.inactive" = { fg = "iris", bg = "surface" }
|
||||||
|
"ui.help" = { fg = "foam", bg = "surface" }
|
||||||
|
"ui.cursor" = { fg = "rose", modifiers = ["reversed"] }
|
||||||
|
"ui.text" = { fg = "text" }
|
||||||
|
"operator" = "rose"
|
||||||
|
"ui.text.focus" = { fg = "base05" }
|
||||||
|
"variable" = "text"
|
||||||
|
"number" = "iris"
|
||||||
|
"constant" = "gold"
|
||||||
|
"attributes" = "gold"
|
||||||
|
"type" = "foam"
|
||||||
|
"ui.cursor.match" = { fg = "gold", modifiers = ["underlined"] }
|
||||||
|
"string" = "gold"
|
||||||
|
"property" = "foam"
|
||||||
|
"escape" = "subtle"
|
||||||
|
"function" = "rose"
|
||||||
|
"function.builtin" = "rose"
|
||||||
|
"function.method" = "foam"
|
||||||
|
"constructor" = "gold"
|
||||||
|
"special" = "gold"
|
||||||
|
"keyword" = "pine"
|
||||||
|
"label" = "iris"
|
||||||
|
"namespace" = "pine"
|
||||||
|
"ui.popup" = { bg = "overlay" }
|
||||||
|
"ui.window" = { bg = "base" }
|
||||||
|
"ui.help" = { bg = "overlay", fg = "foam" }
|
||||||
|
"text" = "text"
|
||||||
|
|
||||||
|
"info" = "gold"
|
||||||
|
"hint" = "gold"
|
||||||
|
"debug" = "rose"
|
||||||
|
"diagnostic" = "rose"
|
||||||
|
"error" = "love"
|
||||||
|
|
||||||
|
[palette]
|
||||||
|
base = "#faf4ed"
|
||||||
|
surface = "#fffaf3"
|
||||||
|
overlay = "#f2e9de"
|
||||||
|
inactive = "#9893a5"
|
||||||
|
subtle = "#6e6a86"
|
||||||
|
text = "#575279"
|
||||||
|
love = "#b4637a"
|
||||||
|
gold = "#ea9d34"
|
||||||
|
rose = "#d7827e"
|
||||||
|
pine = "#286983"
|
||||||
|
foam = "#56949f"
|
||||||
|
iris = "#907aa9"
|
||||||
|
highlight = "#eee9e6"
|
||||||
|
highlightInactive = "#f2ede9"
|
||||||
|
highlightOverlay = "#e4dfde"
|
@ -0,0 +1,65 @@
|
|||||||
|
# Author : Koen Van der Auwera <atog@hey.com>
|
||||||
|
# Based on SpaceBones Light https://github.com/chipotle/spacebones
|
||||||
|
# https://github.com/chipotle/spacebones/blob/main/SpaceBones%20Light.bbColorScheme
|
||||||
|
|
||||||
|
"attribute" = "#b1951d"
|
||||||
|
"keyword" = { fg = "#3a81c3" }
|
||||||
|
"keyword.directive" = "#3a81c3"
|
||||||
|
"namespace" = "#b1951d"
|
||||||
|
"punctuation" = "#6c3163"
|
||||||
|
"punctuation.delimiter" = "#6c3163"
|
||||||
|
"operator" = "#ba2f59"
|
||||||
|
"special" = "#ba2f59"
|
||||||
|
"property" = "#7590db"
|
||||||
|
"variable.property" = "#7590db"
|
||||||
|
"variable" = "#715ab1"
|
||||||
|
"variable.builtin" = "#715ab1"
|
||||||
|
"variable.parameter" = "#7590db"
|
||||||
|
"type" = "#6c3163"
|
||||||
|
"type.builtin" = "#6c3163"
|
||||||
|
"constructor" = { fg = "#4e3163", modifiers = ["bold"] }
|
||||||
|
"function" = { fg = "#715ab1", modifiers = ["bold"] }
|
||||||
|
"function.macro" = "#b1951d"
|
||||||
|
"function.builtin" = "#b1951d"
|
||||||
|
"comment" = { fg = "#a49da5", modifiers = ["italic"] }
|
||||||
|
"constant" = { fg = "#6c3163" }
|
||||||
|
"constant.builtin" = { fg = "#6c3163", modifiers = ["bold"] }
|
||||||
|
"string" = "#2d9574"
|
||||||
|
"number" = "#6c3163"
|
||||||
|
"escape" = { fg = "fg2", modifiers = ["bold"] }
|
||||||
|
"label" = "#b1951d"
|
||||||
|
"module" = "#b1951d"
|
||||||
|
|
||||||
|
"warning" = { fg = "#da8b55" }
|
||||||
|
"error" = { fg = "#e0211d" }
|
||||||
|
"info" = { fg = "#b1951d" }
|
||||||
|
"hint" = { fg = "#d1dcdf" }
|
||||||
|
|
||||||
|
"ui.background" = { bg = "bg0" }
|
||||||
|
"ui.linenr" = { fg = "bg3" }
|
||||||
|
"ui.linenr.selected" = { fg = "#b1951d" }
|
||||||
|
"ui.statusline" = { fg = "fg1", bg = "bg2" }
|
||||||
|
"ui.statusline.inactive" = { fg = "fg4", bg = "bg1" }
|
||||||
|
"ui.popup" = { bg = "bg1" }
|
||||||
|
"ui.window" = { bg = "bg1" }
|
||||||
|
"ui.help" = { bg = "bg1", fg = "fg1" }
|
||||||
|
"ui.text" = { fg = "fg1" }
|
||||||
|
"ui.text.focus" = { fg = "fg1" }
|
||||||
|
"ui.selection" = { bg = "bg3", modifiers = ["reversed"] }
|
||||||
|
"ui.cursor.primary" = { modifiers = ["reversed"] }
|
||||||
|
"ui.cursor.match" = { modifiers = ["reversed"] }
|
||||||
|
"ui.menu" = { fg = "fg1", bg = "bg2" }
|
||||||
|
"ui.menu.selected" = { fg = "#655370", bg = "#d1dcdf", modifiers = ["bold"] }
|
||||||
|
|
||||||
|
"diagnostic" = { modifiers = ["underlined"] }
|
||||||
|
|
||||||
|
[palette]
|
||||||
|
bg0 = "#fbf8ef"
|
||||||
|
bg1 = "#efeae9"
|
||||||
|
bg2 = "#d1dcdf"
|
||||||
|
bg3 = "#b4c6cb"
|
||||||
|
|
||||||
|
fg1 = "#655370"
|
||||||
|
fg2 = "#5f3bc4"
|
||||||
|
fg3 = "#bdae93"
|
||||||
|
fg4 = "#a89984"
|
Loading…
Reference in New Issue