mirror of https://github.com/helix-editor/helix
Merge branch 'master' into cursor-shape-new
commit
d4fb1d0633
@ -0,0 +1,2 @@
|
|||||||
|
[alias]
|
||||||
|
xtask = "run --package xtask --"
|
@ -0,0 +1,38 @@
|
|||||||
|
# Author: NNB <nnbnh@protonmail.com>
|
||||||
|
|
||||||
|
"ui.menu" = "black"
|
||||||
|
"ui.menu.selected" = { modifiers = ["reversed"] }
|
||||||
|
"ui.linenr" = { fg = "gray", bg = "black" }
|
||||||
|
"ui.popup" = { modifiers = ["reversed"] }
|
||||||
|
"ui.linenr.selected" = { fg = "white", bg = "black", modifiers = ["bold"] }
|
||||||
|
"ui.selection" = { fg = "black", bg = "blue" }
|
||||||
|
"ui.selection.primary" = { fg = "white", bg = "blue" }
|
||||||
|
"comment" = { fg = "gray" }
|
||||||
|
"ui.statusline" = { fg = "black", bg = "white" }
|
||||||
|
"ui.statusline.inactive" = { fg = "gray", bg = "white" }
|
||||||
|
"ui.help" = { modifiers = ["reversed"] }
|
||||||
|
"ui.cursor" = { modifiers = ["reversed"] }
|
||||||
|
"variable" = "red"
|
||||||
|
"constant.numeric" = "yellow"
|
||||||
|
"constant" = "yellow"
|
||||||
|
"attributes" = "yellow"
|
||||||
|
"type" = "yellow"
|
||||||
|
"ui.cursor.match" = { fg = "yellow", modifiers = ["underlined"] }
|
||||||
|
"string" = "green"
|
||||||
|
"variable.other.member" = "green"
|
||||||
|
"constant.character.escape" = "cyan"
|
||||||
|
"function" = "blue"
|
||||||
|
"constructor" = "blue"
|
||||||
|
"special" = "blue"
|
||||||
|
"keyword" = "magenta"
|
||||||
|
"label" = "magenta"
|
||||||
|
"namespace" = "magenta"
|
||||||
|
"ui.help" = { fg = "white", bg = "black" }
|
||||||
|
|
||||||
|
"diagnostic" = { modifiers = ["underlined"] }
|
||||||
|
"ui.gutter" = { bg = "black" }
|
||||||
|
"info" = "blue"
|
||||||
|
"hint" = "gray"
|
||||||
|
"debug" = "gray"
|
||||||
|
"warning" = "yellow"
|
||||||
|
"error" = "red"
|
@ -0,0 +1,5 @@
|
|||||||
|
# Commands
|
||||||
|
|
||||||
|
Command mode can be activated by pressing `:`, similar to vim. Built-in commands:
|
||||||
|
|
||||||
|
{{#include ./generated/typable-cmd.md}}
|
@ -0,0 +1,42 @@
|
|||||||
|
| Language | Syntax Highlighting | Treesitter Textobjects | Auto Indent | Default LSP |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| bash | ✓ | | | `bash-language-server` |
|
||||||
|
| c | ✓ | | | `clangd` |
|
||||||
|
| c-sharp | ✓ | | | |
|
||||||
|
| cmake | ✓ | | | `cmake-language-server` |
|
||||||
|
| cpp | ✓ | | | `clangd` |
|
||||||
|
| css | ✓ | | | |
|
||||||
|
| elixir | ✓ | | | `elixir-ls` |
|
||||||
|
| glsl | ✓ | | ✓ | |
|
||||||
|
| go | ✓ | ✓ | ✓ | `gopls` |
|
||||||
|
| html | ✓ | | | |
|
||||||
|
| java | ✓ | | | |
|
||||||
|
| javascript | ✓ | | ✓ | |
|
||||||
|
| json | ✓ | | ✓ | |
|
||||||
|
| julia | ✓ | | | `julia` |
|
||||||
|
| latex | ✓ | | | |
|
||||||
|
| ledger | ✓ | | | |
|
||||||
|
| llvm | ✓ | | | |
|
||||||
|
| lua | ✓ | | ✓ | |
|
||||||
|
| markdown | ✓ | | | |
|
||||||
|
| mint | | | | `mint` |
|
||||||
|
| nix | ✓ | | ✓ | `rnix-lsp` |
|
||||||
|
| ocaml | ✓ | | ✓ | |
|
||||||
|
| ocaml-interface | ✓ | | | |
|
||||||
|
| perl | ✓ | ✓ | ✓ | |
|
||||||
|
| php | ✓ | | ✓ | |
|
||||||
|
| prolog | | | | `swipl` |
|
||||||
|
| protobuf | ✓ | | ✓ | |
|
||||||
|
| python | ✓ | ✓ | ✓ | `pylsp` |
|
||||||
|
| racket | | | | `racket` |
|
||||||
|
| ruby | ✓ | | | `solargraph` |
|
||||||
|
| rust | ✓ | ✓ | ✓ | `rust-analyzer` |
|
||||||
|
| svelte | ✓ | | ✓ | `svelteserver` |
|
||||||
|
| toml | ✓ | | | |
|
||||||
|
| tsq | ✓ | | | |
|
||||||
|
| tsx | ✓ | | | `typescript-language-server` |
|
||||||
|
| typescript | ✓ | | ✓ | `typescript-language-server` |
|
||||||
|
| vue | ✓ | | | |
|
||||||
|
| wgsl | ✓ | | | |
|
||||||
|
| yaml | ✓ | | ✓ | |
|
||||||
|
| zig | ✓ | | ✓ | `zls` |
|
@ -0,0 +1,43 @@
|
|||||||
|
| Name | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `:quit`, `:q` | Close the current view. |
|
||||||
|
| `:quit!`, `:q!` | Close the current view forcefully (ignoring unsaved changes). |
|
||||||
|
| `:open`, `:o` | Open a file from disk into the current view. |
|
||||||
|
| `:buffer-close`, `:bc`, `:bclose` | Close the current buffer. |
|
||||||
|
| `:buffer-close!`, `:bc!`, `:bclose!` | Close the current buffer forcefully (ignoring unsaved changes). |
|
||||||
|
| `:write`, `:w` | Write changes to disk. Accepts an optional path (:write some/path.txt) |
|
||||||
|
| `:new`, `:n` | Create a new scratch buffer. |
|
||||||
|
| `:format`, `:fmt` | Format the file using the LSP formatter. |
|
||||||
|
| `:indent-style` | Set the indentation style for editing. ('t' for tabs or 1-8 for number of spaces.) |
|
||||||
|
| `:line-ending` | Set the document's default line ending. Options: crlf, lf, cr, ff, nel. |
|
||||||
|
| `:earlier`, `:ear` | Jump back to an earlier point in edit history. Accepts a number of steps or a time span. |
|
||||||
|
| `:later`, `:lat` | Jump to a later point in edit history. Accepts a number of steps or a time span. |
|
||||||
|
| `:write-quit`, `:wq`, `:x` | Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt) |
|
||||||
|
| `:write-quit!`, `:wq!`, `:x!` | Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt) |
|
||||||
|
| `:write-all`, `:wa` | Write changes from all views to disk. |
|
||||||
|
| `:write-quit-all`, `:wqa`, `:xa` | Write changes from all views to disk and close all views. |
|
||||||
|
| `:write-quit-all!`, `:wqa!`, `:xa!` | Write changes from all views to disk and close all views forcefully (ignoring unsaved changes). |
|
||||||
|
| `:quit-all`, `:qa` | Close all views. |
|
||||||
|
| `:quit-all!`, `:qa!` | Close all views forcefully (ignoring unsaved changes). |
|
||||||
|
| `:cquit`, `:cq` | Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2). |
|
||||||
|
| `:theme` | Change the editor theme. |
|
||||||
|
| `:clipboard-yank` | Yank main selection into system clipboard. |
|
||||||
|
| `:clipboard-yank-join` | Yank joined selections into system clipboard. A separator can be provided as first argument. Default value is newline. |
|
||||||
|
| `:primary-clipboard-yank` | Yank main selection into system primary clipboard. |
|
||||||
|
| `:primary-clipboard-yank-join` | Yank joined selections into system primary clipboard. A separator can be provided as first argument. Default value is newline. |
|
||||||
|
| `:clipboard-paste-after` | Paste system clipboard after selections. |
|
||||||
|
| `:clipboard-paste-before` | Paste system clipboard before selections. |
|
||||||
|
| `:clipboard-paste-replace` | Replace selections with content of system clipboard. |
|
||||||
|
| `:primary-clipboard-paste-after` | Paste primary clipboard after selections. |
|
||||||
|
| `:primary-clipboard-paste-before` | Paste primary clipboard before selections. |
|
||||||
|
| `:primary-clipboard-paste-replace` | Replace selections with content of system primary clipboard. |
|
||||||
|
| `:show-clipboard-provider` | Show clipboard provider name in status bar. |
|
||||||
|
| `:change-current-directory`, `:cd` | Change the current working directory. |
|
||||||
|
| `:show-directory`, `:pwd` | Show the current working directory. |
|
||||||
|
| `:encoding` | Set encoding based on `https://encoding.spec.whatwg.org` |
|
||||||
|
| `:reload` | Discard changes and reload from the source file. |
|
||||||
|
| `:tree-sitter-scopes` | Display tree sitter scopes, primarily for theming and development. |
|
||||||
|
| `:vsplit`, `:vs` | Open the file in a vertical split. |
|
||||||
|
| `:hsplit`, `:hs`, `:sp` | Open the file in a horizontal split. |
|
||||||
|
| `:tutor` | Open the tutorial. |
|
||||||
|
| `:goto`, `:g` | Go to line number. |
|
@ -0,0 +1,10 @@
|
|||||||
|
# Language Support
|
||||||
|
|
||||||
|
For more information like arguments passed to default LSP server,
|
||||||
|
extensions assosciated with a filetype, custom LSP settings, filetype
|
||||||
|
specific indent settings, etc see the default
|
||||||
|
[`languages.toml`][languages.toml] file.
|
||||||
|
|
||||||
|
{{#include ./generated/lang-support.md}}
|
||||||
|
|
||||||
|
[languages.toml]: https://github.com/helix-editor/helix/blob/master/languages.toml
|
@ -0,0 +1,37 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
Contributors are very welcome! **No contribution is too small and all contributions are valued.**
|
||||||
|
|
||||||
|
Some suggestions to get started:
|
||||||
|
|
||||||
|
- You can look at the [good first issue][good-first-issue] label on the issue tracker.
|
||||||
|
- Help with packaging on various distributions needed!
|
||||||
|
- To use print debugging to the [Helix log file][log-file], you must:
|
||||||
|
* Print using `log::info!`, `warn!`, or `error!`. (`log::info!("helix!")`)
|
||||||
|
* Pass the appropriate verbosity level option for the desired log level. (`hx -v <file>` for info, more `v`s for higher severity inclusive)
|
||||||
|
- If your preferred language is missing, integrating a tree-sitter grammar for
|
||||||
|
it and defining syntax highlight queries for it is straight forward and
|
||||||
|
doesn't require much knowledge of the internals.
|
||||||
|
|
||||||
|
We provide an [architecture.md][architecture.md] that should give you
|
||||||
|
a good overview of the internals.
|
||||||
|
|
||||||
|
# Auto generated documentation
|
||||||
|
|
||||||
|
Some parts of [the book][docs] are autogenerated from the code itself,
|
||||||
|
like the list of `:commands` and supported languages. To generate these
|
||||||
|
files, run
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cargo xtask docgen
|
||||||
|
```
|
||||||
|
|
||||||
|
inside the project. We use [xtask][xtask] as an ad-hoc task runner and
|
||||||
|
thus do not require any dependencies other than `cargo` (You don't have
|
||||||
|
to `cargo install` anything either).
|
||||||
|
|
||||||
|
[good-first-issue]: https://github.com/helix-editor/helix/labels/E-easy
|
||||||
|
[log-file]: https://github.com/helix-editor/helix/wiki/FAQ#access-the-log-file
|
||||||
|
[architecture.md]: ./architecture.md
|
||||||
|
[docs]: https://docs.helix-editor.com/
|
||||||
|
[xtask]: https://github.com/matklad/cargo-xtask
|
@ -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,164 @@
|
|||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
/// Get the vec of escaped / quoted / doublequoted filenames from the input str
|
||||||
|
pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
|
||||||
|
enum State {
|
||||||
|
Normal,
|
||||||
|
NormalEscaped,
|
||||||
|
Quoted,
|
||||||
|
QuoteEscaped,
|
||||||
|
Dquoted,
|
||||||
|
DquoteEscaped,
|
||||||
|
}
|
||||||
|
|
||||||
|
use State::*;
|
||||||
|
|
||||||
|
let mut state = Normal;
|
||||||
|
let mut args: Vec<Cow<str>> = Vec::new();
|
||||||
|
let mut escaped = String::with_capacity(input.len());
|
||||||
|
|
||||||
|
let mut start = 0;
|
||||||
|
let mut end = 0;
|
||||||
|
|
||||||
|
for (i, c) in input.char_indices() {
|
||||||
|
state = match state {
|
||||||
|
Normal => match c {
|
||||||
|
'\\' => {
|
||||||
|
escaped.push_str(&input[start..i]);
|
||||||
|
start = i + 1;
|
||||||
|
NormalEscaped
|
||||||
|
}
|
||||||
|
'"' => {
|
||||||
|
end = i;
|
||||||
|
Dquoted
|
||||||
|
}
|
||||||
|
'\'' => {
|
||||||
|
end = i;
|
||||||
|
Quoted
|
||||||
|
}
|
||||||
|
c if c.is_ascii_whitespace() => {
|
||||||
|
end = i;
|
||||||
|
Normal
|
||||||
|
}
|
||||||
|
_ => Normal,
|
||||||
|
},
|
||||||
|
NormalEscaped => Normal,
|
||||||
|
Quoted => match c {
|
||||||
|
'\\' => {
|
||||||
|
escaped.push_str(&input[start..i]);
|
||||||
|
start = i + 1;
|
||||||
|
QuoteEscaped
|
||||||
|
}
|
||||||
|
'\'' => {
|
||||||
|
end = i;
|
||||||
|
Normal
|
||||||
|
}
|
||||||
|
_ => Quoted,
|
||||||
|
},
|
||||||
|
QuoteEscaped => Quoted,
|
||||||
|
Dquoted => match c {
|
||||||
|
'\\' => {
|
||||||
|
escaped.push_str(&input[start..i]);
|
||||||
|
start = i + 1;
|
||||||
|
DquoteEscaped
|
||||||
|
}
|
||||||
|
'"' => {
|
||||||
|
end = i;
|
||||||
|
Normal
|
||||||
|
}
|
||||||
|
_ => Dquoted,
|
||||||
|
},
|
||||||
|
DquoteEscaped => Dquoted,
|
||||||
|
};
|
||||||
|
|
||||||
|
if i >= input.len() - 1 && end == 0 {
|
||||||
|
end = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if end > 0 {
|
||||||
|
let esc_trim = escaped.trim();
|
||||||
|
let inp = &input[start..end];
|
||||||
|
|
||||||
|
if !(esc_trim.is_empty() && inp.trim().is_empty()) {
|
||||||
|
if esc_trim.is_empty() {
|
||||||
|
args.push(inp.into());
|
||||||
|
} else {
|
||||||
|
args.push([escaped, inp.into()].concat().into());
|
||||||
|
escaped = "".to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start = i + 1;
|
||||||
|
end = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_normal() {
|
||||||
|
let input = r#":o single_word twó wörds \three\ \"with\ escaping\\"#;
|
||||||
|
let result = shellwords(input);
|
||||||
|
let expected = vec![
|
||||||
|
Cow::from(":o"),
|
||||||
|
Cow::from("single_word"),
|
||||||
|
Cow::from("twó"),
|
||||||
|
Cow::from("wörds"),
|
||||||
|
Cow::from(r#"three "with escaping\"#),
|
||||||
|
];
|
||||||
|
// TODO test is_owned and is_borrowed, once they get stabilized.
|
||||||
|
assert_eq!(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_quoted() {
|
||||||
|
let quoted =
|
||||||
|
r#":o 'single_word' 'twó wörds' '' ' ''\three\' \"with\ escaping\\' 'quote incomplete"#;
|
||||||
|
let result = shellwords(quoted);
|
||||||
|
let expected = vec![
|
||||||
|
Cow::from(":o"),
|
||||||
|
Cow::from("single_word"),
|
||||||
|
Cow::from("twó wörds"),
|
||||||
|
Cow::from(r#"three' "with escaping\"#),
|
||||||
|
Cow::from("quote incomplete"),
|
||||||
|
];
|
||||||
|
assert_eq!(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dquoted() {
|
||||||
|
let dquoted = r#":o "single_word" "twó wörds" "" " ""\three\' \"with\ escaping\\" "dquote incomplete"#;
|
||||||
|
let result = shellwords(dquoted);
|
||||||
|
let expected = vec![
|
||||||
|
Cow::from(":o"),
|
||||||
|
Cow::from("single_word"),
|
||||||
|
Cow::from("twó wörds"),
|
||||||
|
Cow::from(r#"three' "with escaping\"#),
|
||||||
|
Cow::from("dquote incomplete"),
|
||||||
|
];
|
||||||
|
assert_eq!(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mixed() {
|
||||||
|
let dquoted = r#":o single_word 'twó wörds' "\three\' \"with\ escaping\\""no space before"'and after' $#%^@ "%^&(%^" ')(*&^%''a\\\\\b' '"#;
|
||||||
|
let result = shellwords(dquoted);
|
||||||
|
let expected = vec![
|
||||||
|
Cow::from(":o"),
|
||||||
|
Cow::from("single_word"),
|
||||||
|
Cow::from("twó wörds"),
|
||||||
|
Cow::from("three' \"with escaping\\"),
|
||||||
|
Cow::from("no space before"),
|
||||||
|
Cow::from("and after"),
|
||||||
|
Cow::from("$#%^@"),
|
||||||
|
Cow::from("%^&(%^"),
|
||||||
|
Cow::from(")(*&^%"),
|
||||||
|
Cow::from(r#"a\\b"#),
|
||||||
|
//last ' just changes to quoted but since we dont have anything after it, it should be ignored
|
||||||
|
];
|
||||||
|
assert_eq!(expected, result);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
Subproject commit ad8c32917a16dfbb387d1da567bf0c3fb6fffde2
|
@ -0,0 +1 @@
|
|||||||
|
Subproject commit f00ff52251edbd58f4d39c9c3204383253032c11
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,96 @@
|
|||||||
|
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 Ok(index) = diagnostics.binary_search_by_key(&line, |d| d.line) {
|
||||||
|
let diagnostic = &diagnostics[index];
|
||||||
|
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,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,35 @@
|
|||||||
|
[
|
||||||
|
(atx_heading)
|
||||||
|
(setext_heading)
|
||||||
|
] @markup.heading
|
||||||
|
|
||||||
|
(code_fence_content) @none
|
||||||
|
|
||||||
|
[
|
||||||
|
(indented_code_block)
|
||||||
|
(fenced_code_block)
|
||||||
|
] @markup.raw.block
|
||||||
|
|
||||||
|
(code_span) @markup.raw.inline
|
||||||
|
|
||||||
|
(emphasis) @markup.italic
|
||||||
|
|
||||||
|
(strong_emphasis) @markup.bold
|
||||||
|
|
||||||
|
(link_destination) @markup.underline.link
|
||||||
|
|
||||||
|
; (link_label) @markup.label ; TODO: rename
|
||||||
|
|
||||||
|
[
|
||||||
|
(list_marker_plus)
|
||||||
|
(list_marker_minus)
|
||||||
|
(list_marker_star)
|
||||||
|
(list_marker_dot)
|
||||||
|
(list_marker_parenthesis)
|
||||||
|
] @punctuation.special
|
||||||
|
|
||||||
|
[
|
||||||
|
(backslash_escape)
|
||||||
|
(hard_line_break)
|
||||||
|
] @string.character.escape
|
||||||
|
|
@ -0,0 +1,8 @@
|
|||||||
|
(fenced_code_block
|
||||||
|
(info_string) @injection.language
|
||||||
|
(code_fence_content) @injection.content)
|
||||||
|
|
||||||
|
((html_block) @injection.content
|
||||||
|
(#set! injection.language "html"))
|
||||||
|
((html_tag) @injection.content
|
||||||
|
(#set! injection.language "html"))
|
@ -0,0 +1,17 @@
|
|||||||
|
indent = [
|
||||||
|
"function",
|
||||||
|
"identifier",
|
||||||
|
"method_invocation",
|
||||||
|
"if_statement",
|
||||||
|
"unless_statement",
|
||||||
|
"if_simple_statement",
|
||||||
|
"unless_simple_statement",
|
||||||
|
"variable_declaration",
|
||||||
|
"block",
|
||||||
|
"list_item",
|
||||||
|
"word_list_qw"
|
||||||
|
]
|
||||||
|
|
||||||
|
outdent = [
|
||||||
|
"}"
|
||||||
|
]
|
@ -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,60 @@
|
|||||||
|
# Author: NNB <nnbnh@protonmail.com>
|
||||||
|
|
||||||
|
"ui.background" = { bg = "base00" }
|
||||||
|
"ui.menu" = "base01"
|
||||||
|
"ui.menu.selected" = { fg = "base01", bg = "base04" }
|
||||||
|
"ui.linenr" = { fg = "base03", bg = "base01" }
|
||||||
|
"ui.popup" = { bg = "base01" }
|
||||||
|
"ui.window" = { bg = "base01" }
|
||||||
|
"ui.linenr.selected" = { fg = "base04", bg = "base01", modifiers = ["bold"] }
|
||||||
|
"ui.selection" = { bg = "base02" }
|
||||||
|
"comment" = { fg = "base03", modifiers = ["italic"] }
|
||||||
|
"ui.statusline" = { fg = "base04", bg = "base01" }
|
||||||
|
"ui.help" = { fg = "base04", bg = "base01" }
|
||||||
|
"ui.cursor" = { fg = "base04", modifiers = ["reversed"] }
|
||||||
|
"ui.cursor.primary" = { fg = "base05", modifiers = ["reversed"] }
|
||||||
|
"ui.text" = "base05"
|
||||||
|
"operator" = "base05"
|
||||||
|
"ui.text.focus" = "base05"
|
||||||
|
"variable" = "base08"
|
||||||
|
"constant.numeric" = "base09"
|
||||||
|
"constant" = "base09"
|
||||||
|
"attributes" = "base09"
|
||||||
|
"type" = "base0A"
|
||||||
|
"ui.cursor.match" = { fg = "base0A", modifiers = ["underlined"] }
|
||||||
|
"string" = "base0B"
|
||||||
|
"variable.other.member" = "base0B"
|
||||||
|
"constant.character.escape" = "base0C"
|
||||||
|
"function" = "base0D"
|
||||||
|
"constructor" = "base0D"
|
||||||
|
"special" = "base0D"
|
||||||
|
"keyword" = "base0E"
|
||||||
|
"label" = "base0E"
|
||||||
|
"namespace" = "base0E"
|
||||||
|
"ui.help" = { fg = "base06", bg = "base01" }
|
||||||
|
|
||||||
|
"diagnostic" = { modifiers = ["underlined"] }
|
||||||
|
"ui.gutter" = { bg = "base01" }
|
||||||
|
"info" = "base0D"
|
||||||
|
"hint" = "base03"
|
||||||
|
"debug" = "base03"
|
||||||
|
"warning" = "base09"
|
||||||
|
"error" = "base08"
|
||||||
|
|
||||||
|
[palette]
|
||||||
|
base00 = "#f8f8f8" # Default Background
|
||||||
|
base01 = "#e8e8e8" # Lighter Background (Used for status bars, line number and folding marks)
|
||||||
|
base02 = "#d8d8d8" # Selection Background
|
||||||
|
base03 = "#b8b8b8" # Comments, Invisibles, Line Highlighting
|
||||||
|
base04 = "#585858" # Dark Foreground (Used for status bars)
|
||||||
|
base05 = "#383838" # Default Foreground, Caret, Delimiters, Operators
|
||||||
|
base06 = "#282828" # Light Foreground (Not often used)
|
||||||
|
base07 = "#181818" # Light Background (Not often used)
|
||||||
|
base08 = "#ab4642" # Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
|
||||||
|
base09 = "#dc9656" # Integers, Boolean, Constants, XML Attributes, Markup Link Url
|
||||||
|
base0A = "#f7ca88" # Classes, Markup Bold, Search Text Background
|
||||||
|
base0B = "#a1b56c" # Strings, Inherited Class, Markup Code, Diff Inserted
|
||||||
|
base0C = "#86c1b9" # Support, Regular Expressions, Escape Characters, Markup Quotes
|
||||||
|
base0D = "#7cafc2" # Functions, Methods, Attribute IDs, Headings
|
||||||
|
base0E = "#ba8baf" # Keywords, Storage, Selector, Markup Italic, Diff Changed
|
||||||
|
base0F = "#a16946" # Deprecated, Opening/Closing Embedded Language Tags, e.g. <?php ?>
|
@ -0,0 +1,39 @@
|
|||||||
|
# Author: NNB <nnbnh@protonmail.com>
|
||||||
|
|
||||||
|
"ui.menu" = "black"
|
||||||
|
"ui.menu.selected" = { modifiers = ["reversed"] }
|
||||||
|
"ui.linenr" = { fg = "light-gray", bg = "black" }
|
||||||
|
"ui.popup" = { bg = "black" }
|
||||||
|
"ui.window" = { bg = "black" }
|
||||||
|
"ui.linenr.selected" = { fg = "white", bg = "black", modifiers = ["bold"] }
|
||||||
|
"ui.selection" = { fg = "gray", modifiers = ["reversed"] }
|
||||||
|
"comment" = { fg = "light-gray", modifiers = ["italic"] }
|
||||||
|
"ui.statusline" = { fg = "white", bg = "black" }
|
||||||
|
"ui.statusline.inactive" = { fg = "gray", bg = "black" }
|
||||||
|
"ui.help" = { fg = "white", bg = "black" }
|
||||||
|
"ui.cursor" = { fg = "light-gray", modifiers = ["reversed"] }
|
||||||
|
"ui.cursor.primary" = { modifiers = ["reversed"] }
|
||||||
|
"variable" = "light-red"
|
||||||
|
"constant.numeric" = "yellow"
|
||||||
|
"constant" = "yellow"
|
||||||
|
"attributes" = "yellow"
|
||||||
|
"type" = "light-yellow"
|
||||||
|
"ui.cursor.match" = { fg = "light-yellow", modifiers = ["underlined"] }
|
||||||
|
"string" = "light-green"
|
||||||
|
"variable.other.member" = "light-green"
|
||||||
|
"constant.character.escape" = "light-cyan"
|
||||||
|
"function" = "light-blue"
|
||||||
|
"constructor" = "light-blue"
|
||||||
|
"special" = "light-blue"
|
||||||
|
"keyword" = "light-magenta"
|
||||||
|
"label" = "light-magenta"
|
||||||
|
"namespace" = "light-magenta"
|
||||||
|
"ui.help" = { fg = "white", bg = "black" }
|
||||||
|
|
||||||
|
"diagnostic" = { modifiers = ["underlined"] }
|
||||||
|
"ui.gutter" = { bg = "black" }
|
||||||
|
"info" = "light-blue"
|
||||||
|
"hint" = "gray"
|
||||||
|
"debug" = "gray"
|
||||||
|
"warning" = "yellow"
|
||||||
|
"error" = "light-red"
|
@ -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,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "xtask"
|
||||||
|
version = "0.5.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
helix-term = { version = "0.5", path = "../helix-term" }
|
||||||
|
helix-core = { version = "0.5", path = "../helix-core" }
|
||||||
|
toml = "0.5"
|
@ -0,0 +1,277 @@
|
|||||||
|
use std::{env, error::Error};
|
||||||
|
|
||||||
|
type DynError = Box<dyn Error>;
|
||||||
|
|
||||||
|
pub mod helpers {
|
||||||
|
use std::{
|
||||||
|
fmt::Display,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::path;
|
||||||
|
use helix_core::syntax::Configuration as LangConfig;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum TsFeature {
|
||||||
|
Highlight,
|
||||||
|
TextObjects,
|
||||||
|
AutoIndent,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TsFeature {
|
||||||
|
pub fn all() -> &'static [Self] {
|
||||||
|
&[Self::Highlight, Self::TextObjects, Self::AutoIndent]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn runtime_filename(&self) -> &'static str {
|
||||||
|
match *self {
|
||||||
|
Self::Highlight => "highlights.scm",
|
||||||
|
Self::TextObjects => "textobjects.scm",
|
||||||
|
Self::AutoIndent => "indents.toml",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for TsFeature {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match *self {
|
||||||
|
Self::Highlight => "Syntax Highlighting",
|
||||||
|
Self::TextObjects => "Treesitter Textobjects",
|
||||||
|
Self::AutoIndent => "Auto Indent",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the list of languages that support a particular tree-sitter
|
||||||
|
/// based feature.
|
||||||
|
pub fn ts_lang_support(feat: TsFeature) -> Vec<String> {
|
||||||
|
let queries_dir = path::ts_queries();
|
||||||
|
|
||||||
|
find_files(&queries_dir, feat.runtime_filename())
|
||||||
|
.iter()
|
||||||
|
.map(|f| {
|
||||||
|
// .../helix/runtime/queries/python/highlights.scm
|
||||||
|
let tail = f.strip_prefix(&queries_dir).unwrap(); // python/highlights.scm
|
||||||
|
let lang = tail.components().next().unwrap(); // python
|
||||||
|
lang.as_os_str().to_string_lossy().to_string()
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the list of languages that have any form of tree-sitter
|
||||||
|
/// queries defined in the runtime directory.
|
||||||
|
pub fn langs_with_ts_queries() -> Vec<String> {
|
||||||
|
std::fs::read_dir(path::ts_queries())
|
||||||
|
.unwrap()
|
||||||
|
.filter_map(|entry| {
|
||||||
|
let entry = entry.ok()?;
|
||||||
|
entry
|
||||||
|
.file_type()
|
||||||
|
.ok()?
|
||||||
|
.is_dir()
|
||||||
|
.then(|| entry.file_name().to_string_lossy().to_string())
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// naive implementation, but suffices for our needs
|
||||||
|
pub fn find_files(dir: &Path, filename: &str) -> Vec<PathBuf> {
|
||||||
|
std::fs::read_dir(dir)
|
||||||
|
.unwrap()
|
||||||
|
.filter_map(|entry| {
|
||||||
|
let path = entry.ok()?.path();
|
||||||
|
if path.is_dir() {
|
||||||
|
Some(find_files(&path, filename))
|
||||||
|
} else {
|
||||||
|
(path.file_name()?.to_string_lossy() == filename).then(|| vec![path])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lang_config() -> LangConfig {
|
||||||
|
let bytes = std::fs::read(path::lang_config()).unwrap();
|
||||||
|
toml::from_slice(&bytes).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod md_gen {
|
||||||
|
use crate::DynError;
|
||||||
|
|
||||||
|
use crate::helpers;
|
||||||
|
use crate::path;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use helix_term::commands::cmd::TYPABLE_COMMAND_LIST;
|
||||||
|
|
||||||
|
pub const TYPABLE_COMMANDS_MD_OUTPUT: &str = "typable-cmd.md";
|
||||||
|
pub const LANG_SUPPORT_MD_OUTPUT: &str = "lang-support.md";
|
||||||
|
|
||||||
|
fn md_table_heading(cols: &[String]) -> String {
|
||||||
|
let mut header = String::new();
|
||||||
|
header += &md_table_row(cols);
|
||||||
|
header += &md_table_row(&vec!["---".to_string(); cols.len()]);
|
||||||
|
header
|
||||||
|
}
|
||||||
|
|
||||||
|
fn md_table_row(cols: &[String]) -> String {
|
||||||
|
"| ".to_owned() + &cols.join(" | ") + " |\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn md_mono(s: &str) -> String {
|
||||||
|
format!("`{}`", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn typable_commands() -> Result<String, DynError> {
|
||||||
|
let mut md = String::new();
|
||||||
|
md.push_str(&md_table_heading(&[
|
||||||
|
"Name".to_owned(),
|
||||||
|
"Description".to_owned(),
|
||||||
|
]));
|
||||||
|
|
||||||
|
let cmdify = |s: &str| format!("`:{}`", s);
|
||||||
|
|
||||||
|
for cmd in TYPABLE_COMMAND_LIST {
|
||||||
|
let names = std::iter::once(&cmd.name)
|
||||||
|
.chain(cmd.aliases.iter())
|
||||||
|
.map(|a| cmdify(a))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
|
|
||||||
|
md.push_str(&md_table_row(&[names.to_owned(), cmd.doc.to_owned()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(md)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lang_features() -> Result<String, DynError> {
|
||||||
|
let mut md = String::new();
|
||||||
|
let ts_features = helpers::TsFeature::all();
|
||||||
|
|
||||||
|
let mut cols = vec!["Language".to_owned()];
|
||||||
|
cols.append(
|
||||||
|
&mut ts_features
|
||||||
|
.iter()
|
||||||
|
.map(|t| t.to_string())
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
);
|
||||||
|
cols.push("Default LSP".to_owned());
|
||||||
|
|
||||||
|
md.push_str(&md_table_heading(&cols));
|
||||||
|
let config = helpers::lang_config();
|
||||||
|
|
||||||
|
let mut langs = config
|
||||||
|
.language
|
||||||
|
.iter()
|
||||||
|
.map(|l| l.language_id.clone())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
langs.sort_unstable();
|
||||||
|
|
||||||
|
let mut ts_features_to_langs = Vec::new();
|
||||||
|
for &feat in ts_features {
|
||||||
|
ts_features_to_langs.push((feat, helpers::ts_lang_support(feat)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut row = Vec::new();
|
||||||
|
for lang in langs {
|
||||||
|
let lc = config
|
||||||
|
.language
|
||||||
|
.iter()
|
||||||
|
.find(|l| l.language_id == lang)
|
||||||
|
.unwrap(); // lang comes from config
|
||||||
|
row.push(lc.language_id.clone());
|
||||||
|
|
||||||
|
for (_feat, support_list) in &ts_features_to_langs {
|
||||||
|
row.push(
|
||||||
|
if support_list.contains(&lang) {
|
||||||
|
"✓"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
.to_owned(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
row.push(
|
||||||
|
lc.language_server
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.command.clone())
|
||||||
|
.map(|c| md_mono(&c))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
md.push_str(&md_table_row(&row));
|
||||||
|
row.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(md)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(filename: &str, data: &str) {
|
||||||
|
let error = format!("Could not write to {}", filename);
|
||||||
|
let path = path::book_gen().join(filename);
|
||||||
|
fs::write(path, data).expect(&error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod path {
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub fn project_root() -> PathBuf {
|
||||||
|
Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||||
|
.parent()
|
||||||
|
.unwrap()
|
||||||
|
.to_path_buf()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn book_gen() -> PathBuf {
|
||||||
|
project_root().join("book/src/generated/")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ts_queries() -> PathBuf {
|
||||||
|
project_root().join("runtime/queries")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lang_config() -> PathBuf {
|
||||||
|
project_root().join("languages.toml")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod tasks {
|
||||||
|
use crate::md_gen;
|
||||||
|
use crate::DynError;
|
||||||
|
|
||||||
|
pub fn docgen() -> Result<(), DynError> {
|
||||||
|
use md_gen::*;
|
||||||
|
write(TYPABLE_COMMANDS_MD_OUTPUT, &typable_commands()?);
|
||||||
|
write(LANG_SUPPORT_MD_OUTPUT, &lang_features()?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_help() {
|
||||||
|
println!(
|
||||||
|
"
|
||||||
|
Usage: Run with `cargo xtask <task>`, eg. `cargo xtask docgen`.
|
||||||
|
|
||||||
|
Tasks:
|
||||||
|
docgen: Generate files to be included in the mdbook output.
|
||||||
|
"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), DynError> {
|
||||||
|
let task = env::args().nth(1);
|
||||||
|
match task {
|
||||||
|
None => tasks::print_help(),
|
||||||
|
Some(t) => match t.as_str() {
|
||||||
|
"docgen" => tasks::docgen()?,
|
||||||
|
invalid => return Err(format!("Invalid task name: {}", invalid).into()),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue