Support loading custom syntax themes from a file (#2565)

This commit is contained in:
Lena 2025-03-19 23:31:09 +00:00 committed by GitHub
parent 92ef9f6fde
commit ad32993721
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 50 additions and 11 deletions

View file

@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
### Added
* support loading custom syntax highlighting themes from a file [[@acuteenvy](https://github.com/acuteenvy)] ([#2565](https://github.com/gitui-org/gitui/pull/2565))
* Select syntax highlighting theme out of the defaults from syntect [[@vasilismanol](https://github.com/vasilismanol)] ([#1931](https://github.com/extrawurst/gitui/issues/1931))
* new command-line option to override the default log file path (`--logfile`) [[@acuteenvy](https://github.com/acuteenvy)] ([#2539](https://github.com/gitui-org/gitui/pull/2539))

23
Cargo.lock generated
View file

@ -2657,6 +2657,19 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "plist"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
dependencies = [
"base64",
"indexmap",
"quick-xml",
"serde",
"time",
]
[[package]]
name = "poly1305"
version = "0.8.0"
@ -2748,6 +2761,15 @@ dependencies = [
"parking_lot",
]
[[package]]
name = "quick-xml"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2"
dependencies = [
"memchr",
]
[[package]]
name = "quote"
version = "1.0.38"
@ -3379,6 +3401,7 @@ dependencies = [
"fnv",
"once_cell",
"onig",
"plist",
"regex-syntax",
"serde",
"serde_derive",

View file

@ -56,6 +56,7 @@ syntect = { version = "5.2", default-features = false, features = [
"parsing",
"default-syntaxes",
"default-themes",
"plist-load",
"html",
] }
tui-textarea = "0.7"

View file

@ -49,7 +49,9 @@ pub fn process_cmdline() -> Result<CliArgs> {
.get_one::<String>("theme")
.map_or_else(|| PathBuf::from("theme.ron"), PathBuf::from);
let theme = get_app_config_path()?.join(arg_theme);
let confpath = get_app_config_path()?;
fs::create_dir_all(&confpath)?;
let theme = confpath.join(arg_theme);
let notify_watcher: bool =
*arg_matches.get_one("watcher").unwrap_or(&false);
@ -166,7 +168,6 @@ pub fn get_app_config_path() -> Result<PathBuf> {
.ok_or_else(|| anyhow!("failed to find os config dir."))?;
path.push("gitui");
fs::create_dir_all(&path)?;
Ok(path)
}

View file

@ -136,6 +136,7 @@ mod tests {
#[test]
fn test_symbolic_links() {
let app_home = get_app_config_path().unwrap();
fs::create_dir_all(&app_home).unwrap();
// save current config
let original_key_list_path = app_home.join(KEY_LIST_FILENAME);
let renamed_key_list = if original_key_list_path.exists() {

View file

@ -2,7 +2,7 @@ use asyncgit::{
asyncjob::{AsyncJob, RunParams},
ProgressPercent,
};
use once_cell::sync::Lazy;
use once_cell::sync::{Lazy, OnceCell};
use ratatui::text::{Line, Span};
use scopetime::scope_time;
use std::{
@ -14,7 +14,7 @@ use std::{
use syntect::{
highlighting::{
FontStyle, HighlightState, Highlighter,
RangedHighlightIterator, Style, ThemeSet,
RangedHighlightIterator, Style, Theme, ThemeSet,
},
parsing::{ParseState, ScopeStack, SyntaxSet},
};
@ -35,7 +35,7 @@ pub struct SyntaxText {
static SYNTAX_SET: Lazy<SyntaxSet> =
Lazy::new(two_face::syntax::extra_no_newlines);
static THEME_SET: Lazy<ThemeSet> = Lazy::new(ThemeSet::load_defaults);
static THEME: OnceCell<Theme> = OnceCell::new();
pub struct AsyncProgressBuffer {
current: usize,
@ -89,13 +89,25 @@ impl SyntaxText {
ParseState::new(syntax)
};
let theme =
THEME_SET.themes.get(syntax).unwrap_or_else(|| {
log::error!("The syntax theme:\"{}\" cannot be found. Using default theme:\"{}\" instead.", syntax, DEFAULT_SYNTAX_THEME);
&THEME_SET.themes[DEFAULT_SYNTAX_THEME]
});
let highlighter = Highlighter::new(theme);
let theme = THEME.get_or_try_init(|| -> Result<Theme, asyncgit::Error> {
let theme_path = crate::args::get_app_config_path()
.map_err(|e| asyncgit::Error::Generic(e.to_string()))?.join(format!("{syntax}.tmTheme"));
match ThemeSet::get_theme(&theme_path) {
Ok(t) => return Ok(t),
Err(e) => log::info!("could not load '{}': {e}, trying from the set of default themes", theme_path.display()),
}
let mut theme_set = ThemeSet::load_defaults();
if let Some(t) = theme_set.themes.remove(syntax) {
return Ok(t);
}
log::error!("the syntax theme '{syntax}' cannot be found. Using default theme ('{DEFAULT_SYNTAX_THEME}') instead");
Ok(theme_set.themes.remove(DEFAULT_SYNTAX_THEME).expect("the default theme should be there"))
})?;
let highlighter = Highlighter::new(theme);
let mut syntax_lines: Vec<SyntaxLine> = Vec::new();
let mut highlight_state =