Merge branch 'colored-indent-guides'

pull/6/head
trivernis 2 years ago
commit d18a064fad
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -232,10 +232,11 @@ Sets explorer side width and style.
Options for rendering vertical indent guides.
| Key | Description | Default |
| --- | --- | --- |
| `render` | Whether to render indent guides. | `false` |
| `character` | Literal character to use for rendering the indent guide | `│` |
| Key | Description | Default |
| --- | --- | --- |
| `render` | Whether to render indent guides. | `false` |
| `character` | Literal character to use for rendering the indent guide | `│` |
| `rainbow` | Whether or not the indent guides shall have changing colors. | `false` |
Example:
@ -243,6 +244,7 @@ Example:
[editor.indent-guides]
render = true
character = "╎"
rainbow = true
```
### `[editor.explorer]` Section

@ -89,6 +89,17 @@ Less common modifiers might not be supported by your terminal emulator.
| `hidden` |
| `crossed_out` |
### Rainbow
The `rainbow` key is used for rainbow highlight for matching brackets.
The key is a list of styles.
```toml
rainbow = ["#ff0000", "#ffa500", "#fff000", { fg = "#00ff00", modifiers = ["bold"] }]
```
Colors from the palette and modifiers may be used.
### Scopes
The following is a list of scopes available to use for styling.

@ -443,11 +443,18 @@ impl EditorView {
// extra loops if the code is deeply nested.
for i in starting_indent..(indent_level / tab_width as u16) {
let style = if config.indent_guides.rainbow {
let color_index = i as usize % theme.rainbow_length();
indent_guide_style.patch(theme.get(&format!("rainbow.{}", color_index)))
} else {
indent_guide_style
};
surface.set_string(
viewport.x + (i * tab_width as u16) - offset.col as u16,
viewport.y + line,
&indent_guide_char,
indent_guide_style,
style,
);
}
};

@ -595,6 +595,7 @@ impl Default for WhitespaceCharacters {
pub struct IndentGuidesConfig {
pub render: bool,
pub character: char,
pub rainbow: bool,
}
impl Default for IndentGuidesConfig {
@ -602,6 +603,7 @@ impl Default for IndentGuidesConfig {
Self {
render: true,
character: '',
rainbow: false,
}
}
}

@ -103,6 +103,7 @@ pub struct Theme {
// tree-sitter highlight styles are stored in a Vec to optimize lookups
scopes: Vec<String>,
highlights: Vec<Style>,
rainbow_length: usize,
}
impl<'de> Deserialize<'de> for Theme {
@ -113,6 +114,7 @@ impl<'de> Deserialize<'de> for Theme {
let mut styles = HashMap::new();
let mut scopes = Vec::new();
let mut highlights = Vec::new();
let mut rainbow_length = 0;
if let Ok(mut colors) = HashMap::<String, Value>::deserialize(deserializer) {
// TODO: alert user of parsing failures in editor
@ -130,6 +132,26 @@ impl<'de> Deserialize<'de> for Theme {
scopes.reserve(colors.len());
highlights.reserve(colors.len());
for (i, style) in colors
.remove("rainbow")
.and_then(|value| match palette.parse_style_array(value) {
Ok(styles) => Some(styles),
Err(err) => {
warn!("{}", err);
None
}
})
.unwrap_or_else(Self::default_rainbow)
.iter()
.enumerate()
{
let name = format!("rainbow.{}", i);
styles.insert(name.clone(), *style);
scopes.push(name);
highlights.push(*style);
rainbow_length += 1;
}
for (name, style_value) in colors {
let mut style = Style::default();
if let Err(err) = palette.parse_style(&mut style, style_value) {
@ -147,6 +169,7 @@ impl<'de> Deserialize<'de> for Theme {
scopes,
styles,
highlights,
rainbow_length,
})
}
}
@ -185,6 +208,21 @@ impl Theme {
.all(|color| !matches!(color, Some(Color::Rgb(..))))
})
}
pub fn rainbow_length(&self) -> usize {
self.rainbow_length
}
pub fn default_rainbow() -> Vec<Style> {
vec![
Style::default().fg(Color::Red),
Style::default().fg(Color::Yellow),
Style::default().fg(Color::Green),
Style::default().fg(Color::Blue),
Style::default().fg(Color::Cyan),
Style::default().fg(Color::Magenta),
]
}
}
struct ThemePalette {
@ -286,6 +324,24 @@ impl ThemePalette {
}
Ok(())
}
/// Parses a TOML array into a [`Vec`] of [`Style`]. If the value cannot be
/// parsed as an array or if any style in the array cannot be parsed then an
/// error is returned.
pub fn parse_style_array(&self, value: Value) -> Result<Vec<Style>, String> {
let mut styles = Vec::new();
for v in value
.as_array()
.ok_or_else(|| format!("Theme: could not parse value as an array: '{}'", value))?
{
let mut style = Style::default();
self.parse_style(&mut style, v.clone())?;
styles.push(style);
}
Ok(styles)
}
}
impl TryFrom<Value> for ThemePalette {
@ -362,4 +418,51 @@ mod tests {
.add_modifier(Modifier::BOLD)
);
}
#[test]
fn test_parse_valid_style_array() {
let theme = toml::toml! {
rainbow = ["#ff0000", "#ffa500", "#fff000", { fg = "#00ff00", modifiers = ["bold"] }]
};
let palette = ThemePalette::default();
let rainbow = theme.as_table().unwrap().get("rainbow").unwrap();
let parse_result = palette.parse_style_array(rainbow.clone());
assert_eq!(
Ok(vec![
Style::default().fg(Color::Rgb(255, 0, 0)),
Style::default().fg(Color::Rgb(255, 165, 0)),
Style::default().fg(Color::Rgb(255, 240, 0)),
Style::default()
.fg(Color::Rgb(0, 255, 0))
.add_modifier(Modifier::BOLD),
]),
parse_result
)
}
#[test]
fn test_parse_invalid_style_array() {
let palette = ThemePalette::default();
let theme = toml::toml! { invalid_hex_code = ["#f00"] };
let invalid_hex_code = theme.as_table().unwrap().get("invalid_hex_code").unwrap();
let parse_result = palette.parse_style_array(invalid_hex_code.clone());
assert_eq!(
Err("Theme: malformed hexcode: #f00".to_string()),
parse_result
);
let theme = toml::toml! { not_an_array = { red = "#ff0000" } };
let not_an_array = theme.as_table().unwrap().get("not_an_array").unwrap();
let parse_result = palette.parse_style_array(not_an_array.clone());
assert_eq!(
Err("Theme: could not parse value as an array: 'red = \"#ff0000\"\n'".to_string()),
parse_result
)
}
}

@ -848,7 +848,7 @@ indent = { tab-width = 4, unit = " " }
[[grammar]]
name = "wgsl"
source = { git = "https://github.com/szebniok/tree-sitter-wgsl", rev = "f00ff52251edbd58f4d39c9c3204383253032c11" }
source = { git = "https://github.com/szebniok/tree-sitter-wgsl", rev = "272e89ef2aeac74178edb9db4a83c1ffef80a463" }
[[language]]
name = "llvm"

@ -1,23 +1,41 @@
(const_literal) @constant.numeric
(int_literal) @constant.numeric.integer
(float_literal) @constant.numeric.float
(bool_literal) @constant.builtin.boolean
(type_declaration) @type
(global_constant_declaration) @variable
(global_variable_declaration) @variable
(compound_statement) @variable
(const_expression) @function
(variable_identifier_declaration
(identifier) @variable
(type_declaration) @type)
(function_declaration
(identifier) @function)
(identifier) @function
(function_return_type_declaration
(type_declaration) @type))
(parameter
(variable_identifier_declaration
(identifier) @variable.parameter
(type_declaration) @type))
(struct_declaration
(identifier) @type)
(struct_declaration
(struct_member
(variable_identifier_declaration
(identifier) @variable.other.member
(type_declaration) @type)))
(type_constructor_or_function_call_expression
(type_declaration) @function)
(parameter
(variable_identifier_declaration (identifier) @variable.parameter))
[
"struct"
"bitcast"
; "block"
"discard"
"enable"
"fallthrough"
@ -26,36 +44,28 @@
"private"
"read"
"read_write"
"return"
"storage"
"type"
"uniform"
"var"
"workgroup"
"write"
"override"
(texel_format)
] @keyword ; TODO reserved keywords
] @keyword
[
(true)
(false)
] @constant.builtin.boolean
"fn" @keyword.function
[ "," "." ":" ";" ] @punctuation.delimiter
"return" @keyword.control.return
;; brackets
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
["," "." ":" ";"] @punctuation.delimiter
["(" ")" "[" "]" "{" "}"] @punctuation.bracket
[
"loop"
"for"
"while"
"break"
"continue"
"continuing"
@ -64,7 +74,6 @@
[
"if"
"else"
"elseif"
"switch"
"case"
"default"
@ -92,10 +101,13 @@
"*"
"~"
"^"
"@"
"++"
"--"
] @operator
(attribute
(identifier) @variable.other.member)
(identifier) @attribute)
(comment) @comment

Loading…
Cancel
Save