Added Todo syntax highlighter
This commit is contained in:
Generated
+510
-492
File diff suppressed because it is too large
Load Diff
+4
-1
@@ -7,7 +7,8 @@ description = "A COSMIC todo.txt application"
|
|||||||
repository = "https://github.com/professorwaltwood/planit.git"
|
repository = "https://github.com/professorwaltwood/planit.git"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cosmic-files = { git = "https://github.com/pop-os/cosmic-files.git", version = "1.0.8" }
|
cosmic-files = { git = "https://github.com/pop-os/cosmic-files", version = "1.0.8" }
|
||||||
|
# cosmic-files = { git = "https://github.com/pop-os/cosmic-files.git", version = "1.0.8" }
|
||||||
futures-util = "0.3.31"
|
futures-util = "0.3.31"
|
||||||
i18n-embed = { version = "0.16", features = [
|
i18n-embed = { version = "0.16", features = [
|
||||||
"fluent-system",
|
"fluent-system",
|
||||||
@@ -17,6 +18,7 @@ i18n-embed-fl = "0.10"
|
|||||||
log = "0.4.29"
|
log = "0.4.29"
|
||||||
open = "5.3.2"
|
open = "5.3.2"
|
||||||
rust-embed = "8.8.0"
|
rust-embed = "8.8.0"
|
||||||
|
syntect = "5.3.0"
|
||||||
time = { version = "0.3.47", features = ["macros", "parsing"] }
|
time = { version = "0.3.47", features = ["macros", "parsing"] }
|
||||||
tokio = { version = "1.48.0", features = ["full"] }
|
tokio = { version = "1.48.0", features = ["full"] }
|
||||||
|
|
||||||
@@ -26,6 +28,7 @@ git = "https://github.com/pop-os/libcosmic.git"
|
|||||||
features = [
|
features = [
|
||||||
# Accessibility support
|
# Accessibility support
|
||||||
#"a11y",
|
#"a11y",
|
||||||
|
"debug",
|
||||||
# About widget for the app
|
# About widget for the app
|
||||||
"about",
|
"about",
|
||||||
# Uses cosmic-settings-daemon to watch for config file changes
|
# Uses cosmic-settings-daemon to watch for config file changes
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
name: todo.txt
|
||||||
|
scope: text.todo
|
||||||
|
variables:
|
||||||
|
date: '(\d{4}-\d{2}-\d{2}(?:\s+|$))'
|
||||||
|
prio: '(\([A-Z]\)(?:\s+|$))'
|
||||||
|
contexts:
|
||||||
|
main:
|
||||||
|
- match: '^\s*x\s'
|
||||||
|
push: done
|
||||||
|
|
||||||
|
- match: ""
|
||||||
|
push: todo
|
||||||
|
|
||||||
|
done:
|
||||||
|
- meta_scope: comment.line
|
||||||
|
- include: check_prio
|
||||||
|
|
||||||
|
todo:
|
||||||
|
- meta_scope: text.todo
|
||||||
|
- include: check_prio
|
||||||
|
|
||||||
|
desc_fallback:
|
||||||
|
- match: '\s'
|
||||||
|
- match: ""
|
||||||
|
push: desc_start
|
||||||
|
|
||||||
|
check_prio:
|
||||||
|
- match: "{{date}}"
|
||||||
|
scope: constant.numeric
|
||||||
|
push: check_date2
|
||||||
|
|
||||||
|
- match: "{{prio}}"
|
||||||
|
scope: keyword
|
||||||
|
push: check_date
|
||||||
|
|
||||||
|
- include: desc_fallback
|
||||||
|
|
||||||
|
check_date:
|
||||||
|
- match: "{{date}}"
|
||||||
|
scope: constant.numeric
|
||||||
|
set: check_date2
|
||||||
|
- include: desc_fallback
|
||||||
|
|
||||||
|
check_date2:
|
||||||
|
- match: "{{date}}"
|
||||||
|
scope: constant.numeric
|
||||||
|
set: desc_start
|
||||||
|
- include: desc_fallback
|
||||||
|
|
||||||
|
# Any preceeding whitespace has been read
|
||||||
|
# safe to assume start of match is succeeds whitespace
|
||||||
|
desc_start:
|
||||||
|
- match: '@\S+'
|
||||||
|
scope: string
|
||||||
|
push: desc
|
||||||
|
- match: '\+\S+'
|
||||||
|
scope: variable.function
|
||||||
|
push: desc
|
||||||
|
- match: '\b([^\s:]+):([^\s:]+)\b'
|
||||||
|
captures:
|
||||||
|
1: entity.name
|
||||||
|
2: entity.name.tag
|
||||||
|
push: desc
|
||||||
|
- match: ""
|
||||||
|
set: desc
|
||||||
|
|
||||||
|
desc:
|
||||||
|
- match: '(?:\s|^)@\S+'
|
||||||
|
scope: string
|
||||||
|
- match: '(?:\s|^)\+\S+'
|
||||||
|
scope: variable.function
|
||||||
|
- match: '\b([^\s:]+):([^\s:]+)\b'
|
||||||
|
captures:
|
||||||
|
1: entity.name
|
||||||
|
2: entity.name.tag
|
||||||
@@ -18,3 +18,5 @@ test having lots of items +planit @tests
|
|||||||
test having lots of items +planit @tests
|
test having lots of items +planit @tests
|
||||||
test having lots of items +planit @tests
|
test having lots of items +planit @tests
|
||||||
test having lots of items +planit @tests
|
test having lots of items +planit @tests
|
||||||
|
+sda sda sda@ asd @Sasd @dsa a@adsa
|
||||||
|
2020-01-01 @asda +asd
|
||||||
+50
-18
@@ -2,13 +2,16 @@
|
|||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::fl;
|
use crate::fl;
|
||||||
|
use crate::todo_editor::TodoHighlighter;
|
||||||
use cosmic::app::context_drawer;
|
use cosmic::app::context_drawer;
|
||||||
use cosmic::cosmic_config::{self, CosmicConfigEntry};
|
use cosmic::cosmic_config::{self, ConfigSet, CosmicConfigEntry};
|
||||||
use cosmic::iced::alignment::{Horizontal, Vertical};
|
use cosmic::iced::alignment::{Horizontal, Vertical};
|
||||||
use cosmic::iced::futures::channel::mpsc::Sender;
|
use cosmic::iced::futures::channel::mpsc::Sender;
|
||||||
use cosmic::iced::{Alignment, Length, Subscription};
|
use cosmic::iced::{Alignment, Length, Subscription, stream};
|
||||||
|
use cosmic::prelude::*;
|
||||||
|
use cosmic::widget::text_editor::{self, Content};
|
||||||
use cosmic::widget::{self, about::About, menu};
|
use cosmic::widget::{self, about::About, menu};
|
||||||
use cosmic::{Theme, iced_futures, prelude::*};
|
|
||||||
use futures_util::SinkExt;
|
use futures_util::SinkExt;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path;
|
use std::path;
|
||||||
@@ -33,6 +36,7 @@ pub struct AppModel {
|
|||||||
/// Key bindings for the application's menu bar.
|
/// Key bindings for the application's menu bar.
|
||||||
key_binds: HashMap<menu::KeyBind, MenuAction>,
|
key_binds: HashMap<menu::KeyBind, MenuAction>,
|
||||||
/// Configuration data that persists between application runs.
|
/// Configuration data that persists between application runs.
|
||||||
|
config_handler: Option<cosmic_config::Config>,
|
||||||
config: Config,
|
config: Config,
|
||||||
/// Time active
|
/// Time active
|
||||||
time: u32,
|
time: u32,
|
||||||
@@ -41,6 +45,7 @@ pub struct AppModel {
|
|||||||
/// Current Todo data
|
/// Current Todo data
|
||||||
todo: Option<Todo>,
|
todo: Option<Todo>,
|
||||||
dialog_opt: Option<Dialog<Message>>,
|
dialog_opt: Option<Dialog<Message>>,
|
||||||
|
content: Content,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Messages emitted by the application and its widgets.
|
/// Messages emitted by the application and its widgets.
|
||||||
@@ -53,6 +58,7 @@ pub enum Message {
|
|||||||
OpenFileDialog,
|
OpenFileDialog,
|
||||||
DialogMessage(DialogMessage),
|
DialogMessage(DialogMessage),
|
||||||
OpenFileResult(DialogResult),
|
OpenFileResult(DialogResult),
|
||||||
|
Edit(text_editor::Action),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a COSMIC application from the app model
|
/// Create a COSMIC application from the app model
|
||||||
@@ -90,6 +96,26 @@ impl cosmic::Application for AppModel {
|
|||||||
.links([(fl!("repository"), REPOSITORY)])
|
.links([(fl!("repository"), REPOSITORY)])
|
||||||
.license(env!("CARGO_PKG_LICENSE"));
|
.license(env!("CARGO_PKG_LICENSE"));
|
||||||
|
|
||||||
|
let (config_handler, config) =
|
||||||
|
match cosmic_config::Config::new(Self::APP_ID, Config::VERSION) {
|
||||||
|
Ok(config_handler) => {
|
||||||
|
let config = match Config::get_entry(&config_handler) {
|
||||||
|
Ok(ok) => ok,
|
||||||
|
Err((errs, config)) => {
|
||||||
|
log::info!("errors loading config: {errs:?}");
|
||||||
|
config
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(Some(config_handler), config)
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("failed to create config handler: {err}");
|
||||||
|
(None, Config::default())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let todo = config.current_file.clone().map(|path| Todo::new(path));
|
||||||
|
|
||||||
// Construct the app model with the runtime's core.
|
// Construct the app model with the runtime's core.
|
||||||
let mut app = AppModel {
|
let mut app = AppModel {
|
||||||
core,
|
core,
|
||||||
@@ -97,22 +123,13 @@ impl cosmic::Application for AppModel {
|
|||||||
about,
|
about,
|
||||||
key_binds: HashMap::new(),
|
key_binds: HashMap::new(),
|
||||||
// Optional configuration file for an application.
|
// Optional configuration file for an application.
|
||||||
config: cosmic_config::Config::new(Self::APP_ID, Config::VERSION)
|
config_handler: config_handler,
|
||||||
.map(|context| match Config::get_entry(&context) {
|
config: config,
|
||||||
Ok(config) => config,
|
|
||||||
Err((_errors, config)) => {
|
|
||||||
// for why in errors {
|
|
||||||
// tracing::error!(%why, "error loading app config");
|
|
||||||
// }
|
|
||||||
|
|
||||||
config
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or_default(),
|
|
||||||
time: 0,
|
time: 0,
|
||||||
watch_is_active: false,
|
watch_is_active: false,
|
||||||
todo: None,
|
todo: todo,
|
||||||
dialog_opt: None,
|
dialog_opt: None,
|
||||||
|
content: Content::with_text("test"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a startup command that sets the window title.
|
// Create a startup command that sets the window title.
|
||||||
@@ -167,6 +184,11 @@ impl cosmic::Application for AppModel {
|
|||||||
|
|
||||||
let header = widget::row::with_capacity(2)
|
let header = widget::row::with_capacity(2)
|
||||||
.push(widget::text::title1(fl!("welcome")))
|
.push(widget::text::title1(fl!("welcome")))
|
||||||
|
.push(
|
||||||
|
widget::TextEditor::new(&self.content)
|
||||||
|
.on_action(Message::Edit)
|
||||||
|
.highlight_with::<TodoHighlighter>((), |hl, _t| hl.to_format()),
|
||||||
|
)
|
||||||
.align_y(Alignment::End)
|
.align_y(Alignment::End)
|
||||||
.spacing(space_s);
|
.spacing(space_s);
|
||||||
|
|
||||||
@@ -222,7 +244,7 @@ impl cosmic::Application for AppModel {
|
|||||||
// Conditionally enables a timer that emits a message every second.
|
// Conditionally enables a timer that emits a message every second.
|
||||||
if self.watch_is_active {
|
if self.watch_is_active {
|
||||||
subscriptions.push(Subscription::run(|| {
|
subscriptions.push(Subscription::run(|| {
|
||||||
iced_futures::stream::channel(1, |mut emitter: Sender<Message>| async move {
|
stream::channel(1, |mut emitter: Sender<Message>| async move {
|
||||||
let mut time = 1;
|
let mut time = 1;
|
||||||
let mut interval = tokio::time::interval(Duration::from_secs(1));
|
let mut interval = tokio::time::interval(Duration::from_secs(1));
|
||||||
|
|
||||||
@@ -295,7 +317,14 @@ impl cosmic::Application for AppModel {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let mut todo = Todo::new(cpath);
|
let mut todo = Todo::new(cpath.clone());
|
||||||
|
|
||||||
|
if let Some(cfg) = &self.config_handler {
|
||||||
|
if let Err(err) = cfg.set("current_file", Some(cpath)) {
|
||||||
|
log::error!("failed to save config {:?}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// self.config.current_file = Some(cpath);
|
||||||
// Todo: this might need to be more async
|
// Todo: this might need to be more async
|
||||||
if let Err(err) = todo.load() {
|
if let Err(err) = todo.load() {
|
||||||
log::error!("failed to load file {:?} {:?}", path, err);
|
log::error!("failed to load file {:?} {:?}", path, err);
|
||||||
@@ -306,6 +335,9 @@ impl cosmic::Application for AppModel {
|
|||||||
}
|
}
|
||||||
DialogResult::Cancel => todo!(),
|
DialogResult::Cancel => todo!(),
|
||||||
},
|
},
|
||||||
|
Message::Edit(action) => {
|
||||||
|
self.content.perform(action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -1,9 +1,11 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use cosmic::cosmic_config::{self, CosmicConfigEntry, cosmic_config_derive::CosmicConfigEntry};
|
use cosmic::cosmic_config::{self, CosmicConfigEntry, cosmic_config_derive::CosmicConfigEntry};
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, CosmicConfigEntry, Eq, PartialEq)]
|
#[derive(Debug, Default, Clone, CosmicConfigEntry, Eq, PartialEq)]
|
||||||
#[version = 1]
|
#[version = 1]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
demo: String,
|
pub current_file: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ mod app;
|
|||||||
mod config;
|
mod config;
|
||||||
mod i18n;
|
mod i18n;
|
||||||
mod todo;
|
mod todo;
|
||||||
|
mod todo_editor;
|
||||||
|
|
||||||
fn main() -> cosmic::iced::Result {
|
fn main() -> cosmic::iced::Result {
|
||||||
// Get the system's preferred languages.
|
// Get the system's preferred languages.
|
||||||
|
|||||||
@@ -0,0 +1,244 @@
|
|||||||
|
use cosmic::{
|
||||||
|
iced::core::text::highlighter::{Format, Highlighter},
|
||||||
|
iced::{Color, Font},
|
||||||
|
theme::CosmicColor,
|
||||||
|
};
|
||||||
|
use std::{str::FromStr, sync::LazyLock};
|
||||||
|
use syntect::{highlighting, parsing};
|
||||||
|
|
||||||
|
static TODOSYNTAX: LazyLock<parsing::SyntaxSet> = LazyLock::new(|| {
|
||||||
|
let mut builder = parsing::SyntaxSetBuilder::new();
|
||||||
|
builder.add(
|
||||||
|
parsing::SyntaxDefinition::load_from_str(
|
||||||
|
std::include_str!("../resources/todo.sublime-syntax"),
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.expect("Failed to load todo syntax"),
|
||||||
|
);
|
||||||
|
builder.build()
|
||||||
|
});
|
||||||
|
|
||||||
|
static TODOTHEME: LazyLock<highlighting::Theme> = LazyLock::new(|| get_current_theme());
|
||||||
|
|
||||||
|
pub struct TodoHighlighter {
|
||||||
|
syntax: &'static parsing::SyntaxReference,
|
||||||
|
highlighter: highlighting::Highlighter<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Highlighter for TodoHighlighter {
|
||||||
|
type Settings = ();
|
||||||
|
|
||||||
|
type Highlight = TodoHighlight;
|
||||||
|
|
||||||
|
type Iterator<'a> = Box<dyn Iterator<Item = (std::ops::Range<usize>, Self::Highlight)> + 'a>;
|
||||||
|
|
||||||
|
fn new(_settings: &Self::Settings) -> Self {
|
||||||
|
let syntax = TODOSYNTAX.syntaxes().get(0).expect("Todo Syntax Reference");
|
||||||
|
let highlighter = highlighting::Highlighter::new(&*TODOTHEME);
|
||||||
|
Self {
|
||||||
|
syntax,
|
||||||
|
highlighter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, _s: &Self::Settings) {
|
||||||
|
// Re-highlight (only one line for planit)
|
||||||
|
self.change_line(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_line(&mut self, line: usize) {
|
||||||
|
// planit only edits one todo at a time
|
||||||
|
assert_eq!(line, 0);
|
||||||
|
|
||||||
|
// Nothing to do as no point in caching one line
|
||||||
|
}
|
||||||
|
|
||||||
|
fn highlight_line(&mut self, line: &str) -> Self::Iterator<'_> {
|
||||||
|
let mut parser = parsing::ParseState::new(self.syntax);
|
||||||
|
|
||||||
|
let ops = parser.parse_line(line, &*TODOSYNTAX).unwrap_or_default();
|
||||||
|
|
||||||
|
Box::new(scope_iterator(ops, line, &self.highlighter))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_line(&self) -> usize {
|
||||||
|
0 // only one line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TodoHighlight(highlighting::StyleModifier);
|
||||||
|
|
||||||
|
impl TodoHighlight {
|
||||||
|
pub fn color(&self) -> Option<Color> {
|
||||||
|
self.0.foreground.map(|color| Color {
|
||||||
|
r: color.r as f32 / 255.,
|
||||||
|
g: color.g as f32 / 255.,
|
||||||
|
b: color.b as f32 / 255.,
|
||||||
|
a: color.a as f32 / 255.,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn font(&self) -> Option<Font> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_format(&self) -> Format<Font> {
|
||||||
|
Format {
|
||||||
|
color: self.color(),
|
||||||
|
font: self.font(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scope_iterator<'a>(
|
||||||
|
ops: Vec<(usize, parsing::ScopeStackOp)>,
|
||||||
|
line: &str,
|
||||||
|
highlighter: &'a highlighting::Highlighter<'static>,
|
||||||
|
) -> impl Iterator<Item = (std::ops::Range<usize>, TodoHighlight)> + 'a {
|
||||||
|
let mut stack = parsing::ScopeStack::new();
|
||||||
|
ScopeRangeIterator {
|
||||||
|
ops,
|
||||||
|
line_length: line.len(),
|
||||||
|
index: 0,
|
||||||
|
last_str_index: 0,
|
||||||
|
}
|
||||||
|
.filter_map(move |(range, scope)| {
|
||||||
|
let _ = stack.apply(&scope);
|
||||||
|
|
||||||
|
if range.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((
|
||||||
|
range,
|
||||||
|
TodoHighlight(highlighter.style_mod_for_stack(&stack.scopes)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ScopeRangeIterator {
|
||||||
|
ops: Vec<(usize, parsing::ScopeStackOp)>,
|
||||||
|
line_length: usize,
|
||||||
|
index: usize,
|
||||||
|
last_str_index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for ScopeRangeIterator {
|
||||||
|
type Item = (std::ops::Range<usize>, parsing::ScopeStackOp);
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.index > self.ops.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let next_str_i = if self.index == self.ops.len() {
|
||||||
|
self.line_length
|
||||||
|
} else {
|
||||||
|
self.ops[self.index].0
|
||||||
|
};
|
||||||
|
|
||||||
|
let range = self.last_str_index..next_str_i;
|
||||||
|
self.last_str_index = next_str_i;
|
||||||
|
|
||||||
|
let op = if self.index == 0 {
|
||||||
|
parsing::ScopeStackOp::Noop
|
||||||
|
} else {
|
||||||
|
self.ops[self.index - 1].1.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.index += 1;
|
||||||
|
Some((range, op))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_current_theme() -> highlighting::Theme {
|
||||||
|
let theme = cosmic::theme::active();
|
||||||
|
let cosmic = theme.cosmic();
|
||||||
|
|
||||||
|
highlighting::Theme {
|
||||||
|
name: None,
|
||||||
|
author: None,
|
||||||
|
settings: highlighting::ThemeSettings::default(),
|
||||||
|
scopes: vec![
|
||||||
|
highlighting::ThemeItem {
|
||||||
|
scope: highlighting::ScopeSelectors::from_str("constant.numeric")
|
||||||
|
.expect("static scope selector"),
|
||||||
|
style: highlighting::StyleModifier {
|
||||||
|
foreground: Some(colour_map(cosmic.palette.accent_purple)),
|
||||||
|
background: None,
|
||||||
|
font_style: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
highlighting::ThemeItem {
|
||||||
|
scope: highlighting::ScopeSelectors::from_str("comment.line")
|
||||||
|
.expect("static scope selector"),
|
||||||
|
style: highlighting::StyleModifier {
|
||||||
|
foreground: Some(colour_map(cosmic.palette.ext_warm_grey)),
|
||||||
|
background: None,
|
||||||
|
font_style: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
highlighting::ThemeItem {
|
||||||
|
scope: highlighting::ScopeSelectors::from_str("text.todo string - comment.line")
|
||||||
|
.expect("static scope selector"),
|
||||||
|
style: highlighting::StyleModifier {
|
||||||
|
foreground: Some(colour_map(cosmic.palette.accent_green)),
|
||||||
|
background: None,
|
||||||
|
font_style: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
highlighting::ThemeItem {
|
||||||
|
scope: highlighting::ScopeSelectors::from_str(
|
||||||
|
"text.todo variable.function - comment.line",
|
||||||
|
)
|
||||||
|
.expect("static scope selector"),
|
||||||
|
style: highlighting::StyleModifier {
|
||||||
|
foreground: Some(colour_map(cosmic.palette.accent_blue)),
|
||||||
|
background: None,
|
||||||
|
font_style: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
highlighting::ThemeItem {
|
||||||
|
scope: highlighting::ScopeSelectors::from_str(
|
||||||
|
"text.todo entity.name - comment.line",
|
||||||
|
)
|
||||||
|
.expect("static scope selector"),
|
||||||
|
style: highlighting::StyleModifier {
|
||||||
|
foreground: Some(colour_map(cosmic.palette.accent_orange)),
|
||||||
|
background: None,
|
||||||
|
font_style: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
highlighting::ThemeItem {
|
||||||
|
scope: highlighting::ScopeSelectors::from_str(
|
||||||
|
"text.todo entity.name.tag - comment.line",
|
||||||
|
)
|
||||||
|
.expect("static scope selector"),
|
||||||
|
style: highlighting::StyleModifier {
|
||||||
|
foreground: Some(colour_map(cosmic.palette.accent_orange)),
|
||||||
|
background: None,
|
||||||
|
font_style: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
highlighting::ThemeItem {
|
||||||
|
scope: highlighting::ScopeSelectors::from_str("text.todo keyword - comment.line")
|
||||||
|
.expect("static scope selector"),
|
||||||
|
style: highlighting::StyleModifier {
|
||||||
|
foreground: Some(colour_map(cosmic.palette.accent_pink)),
|
||||||
|
background: None,
|
||||||
|
font_style: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn colour_map(colour: CosmicColor) -> highlighting::Color {
|
||||||
|
highlighting::Color {
|
||||||
|
r: (colour.red * 255.) as u8,
|
||||||
|
g: (colour.green * 255.) as u8,
|
||||||
|
b: (colour.blue * 255.) as u8,
|
||||||
|
a: (colour.alpha * 255.) as u8,
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user