diff --git a/.config/config.toml b/.config/config.toml index 8111267..b38bba4 100644 --- a/.config/config.toml +++ b/.config/config.toml @@ -9,6 +9,12 @@ use_nerd_font_icons = false # How much space to allocate for the UI (in percentage of the screen) ui_scale = 80 +# Previewers settings +# ---------------------------------------------------------------------------- +[previewers.file] +# The theme to use for syntax highlighting +theme = "Catppuccin Mocha" + # Keybindings # ---------------------------------------------------------------------------- # diff --git a/Cargo.lock b/Cargo.lock index a2e31f7..776d9c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,6 +50,15 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "ansi_colours" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14eec43e0298190790f41679fe69ef7a829d2a2ddd78c8c00339e84710e435fe" +dependencies = [ + "rgb", +] + [[package]] name = "anstream" version = "0.6.18" @@ -161,6 +170,43 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bat" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcc9e5637c2330d8eb7b920f2aa5d9e184446c258466f825ea1412c7614cc86" +dependencies = [ + "ansi_colours", + "bincode", + "bugreport", + "bytesize", + "clap", + "clircle", + "console", + "content_inspector", + "encoding_rs", + "etcetera", + "flate2", + "git2", + "globset", + "grep-cli", + "home", + "nu-ansi-term 0.49.0", + "once_cell", + "path_abs", + "plist", + "regex", + "semver", + "serde", + "serde_yaml", + "shell-words", + "syntect", + "thiserror", + "unicode-width 0.1.14", + "walkdir", + "wild", +] + [[package]] name = "better-panic" version = "0.3.0" @@ -221,6 +267,23 @@ dependencies = [ "serde", ] +[[package]] +name = "bugreport" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535120b8182547808081a66f1f77a64533c780b23da26763e0ee34dfb94f98c9" +dependencies = [ + "git-version", + "shell-escape", + "sys-info", +] + +[[package]] +name = "bytemuck" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" + [[package]] name = "byteorder" version = "1.5.0" @@ -233,6 +296,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +[[package]] +name = "bytesize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" + [[package]] name = "calloop" version = "0.13.0" @@ -312,6 +381,8 @@ version = "1.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baee610e9452a8f6f0a1b6194ec09ff9e2d85dea54432acdae41aa0761c95d70" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -385,6 +456,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "clircle" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e87cbed5354f17bd8ca8821a097fb62599787fe8f611743fad7ee156a0a600" +dependencies = [ + "cfg-if", + "libc", + "serde", + "winapi", +] + [[package]] name = "clru" version = "0.6.2" @@ -476,6 +559,7 @@ dependencies = [ "encode_unicode", "lazy_static", "libc", + "unicode-width 0.1.14", "windows-sys 0.52.0", ] @@ -499,6 +583,15 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "content_inspector" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" +dependencies = [ + "memchr", +] + [[package]] name = "convert_case" version = "0.6.0" @@ -824,6 +917,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + [[package]] name = "eyre" version = "0.6.12" @@ -1026,6 +1130,39 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "git-version" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad568aa3db0fcbc81f2f116137f263d7304f512a1209b35b85150d3ef88ad19" +dependencies = [ + "git-version-macro", +] + +[[package]] +name = "git-version-macro" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "git2" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70" +dependencies = [ + "bitflags 2.6.0", + "libc", + "libgit2-sys", + "log", + "url", +] + [[package]] name = "gix" version = "0.66.0" @@ -1520,6 +1657,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "globset" version = "0.4.15" @@ -1533,6 +1676,20 @@ dependencies = [ "regex-syntax 0.8.5", ] +[[package]] +name = "grep-cli" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47f1288f0e06f279f84926fa4c17e3fcd2a22b357927a82f2777f7be26e4cec0" +dependencies = [ + "bstr", + "globset", + "libc", + "log", + "termcolor", + "winapi-util", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -1854,6 +2011,15 @@ dependencies = [ "jiff-tzdb", ] +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + [[package]] name = "json5" version = "0.4.1" @@ -1883,6 +2049,18 @@ version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" +[[package]] +name = "libgit2-sys" +version = "0.16.2+1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + [[package]] name = "libloading" version = "0.8.5" @@ -1904,6 +2082,18 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "libz-sys" +version = "1.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -2037,6 +2227,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "nu-ansi-term" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "nucleo" version = "0.5.0" @@ -2207,6 +2406,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "path_abs" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ef02f6342ac01d8a93b65f96db53fe68a92a15f41144f97fb00a9e669633c3" +dependencies = [ + "std_prelude", +] + [[package]] name = "pathdiff" version = "0.2.2" @@ -2474,6 +2682,15 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rgb" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +dependencies = [ + "bytemuck", +] + [[package]] name = "ron" version = "0.8.1" @@ -2607,6 +2824,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha1_smol" version = "1.0.1" @@ -2633,6 +2863,18 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shell-escape" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + [[package]] name = "shlex" version = "1.3.0" @@ -2742,6 +2984,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "std_prelude" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8207e78455ffdf55661170876f88daf85356e4edd54e0a3dbc79586ca1e50cbe" + [[package]] name = "strip-ansi-escapes" version = "0.2.0" @@ -2834,11 +3082,22 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "sys-info" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b3a0d0aba8bf96a0e1ddfdc352fc53b3df7f39318c71854910c3c4b024ae52c" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "television" version = "0.1.13" dependencies = [ "anyhow", + "bat", "better-panic", "clap", "color-eyre", @@ -2900,6 +3159,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "terminal_size" version = "0.4.0" @@ -3136,7 +3404,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", - "nu-ansi-term", + "nu-ansi-term 0.46.0", "once_cell", "regex", "serde", @@ -3216,6 +3484,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "url" version = "2.5.3" @@ -3260,6 +3534,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "vergen" version = "9.0.1" @@ -3440,6 +3720,15 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "wild" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3131afc8c575281e1e80f36ed6a092aa502c08b18ed7524e86fbbb12bb410e1" +dependencies = [ + "glob", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 85ad24e..fdc7f02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ human-panic = "2.0.2" pretty_assertions = "1.4.1" termtree = "0.5.1" copypasta = "0.10.1" +bat = "0.24.0" [build-dependencies] diff --git a/crates/television/config.rs b/crates/television/config.rs index ae0a2be..1338088 100644 --- a/crates/television/config.rs +++ b/crates/television/config.rs @@ -12,6 +12,7 @@ use tracing::{info, warn}; use crate::{ action::Action, event::{convert_raw_event_to_key, Key}, + previewers::{self, PreviewerConfig}, television::Mode, }; @@ -43,6 +44,40 @@ impl Default for UiConfig { } } +#[derive(Clone, Debug, Deserialize, Default)] +pub struct PreviewersConfig { + #[serde(default)] + pub basic: BasicPreviewerConfig, + #[serde(default)] + pub directory: DirectoryPreviewerConfig, + pub file: FilePreviewerConfig, + #[serde(default)] + pub env_var: EnvVarPreviewerConfig, +} + +impl Into for PreviewersConfig { + fn into(self) -> PreviewerConfig { + PreviewerConfig::default().file(previewers::FilePreviewerConfig::new( + self.file.theme.clone(), + )) + } +} + +#[derive(Clone, Debug, Deserialize, Default)] +pub struct BasicPreviewerConfig {} + +#[derive(Clone, Debug, Deserialize, Default)] +pub struct DirectoryPreviewerConfig {} + +#[derive(Clone, Debug, Deserialize, Default)] +pub struct FilePreviewerConfig { + //pub max_file_size: u64, + pub theme: String, +} + +#[derive(Clone, Debug, Deserialize, Default)] +pub struct EnvVarPreviewerConfig {} + #[allow(dead_code)] #[derive(Clone, Debug, Default, Deserialize)] pub struct Config { @@ -54,19 +89,25 @@ pub struct Config { #[serde(default)] pub styles: Styles, pub ui: UiConfig, + #[serde(default)] + pub previewers: PreviewersConfig, } lazy_static! { pub static ref PROJECT_NAME: String = env!("CARGO_CRATE_NAME").to_uppercase().to_string(); pub static ref DATA_FOLDER: Option = - env::var(format!("{}_DATA", PROJECT_NAME.clone())) - .ok() - .map(PathBuf::from); + // if `TELEVISION_DATA` is set, use that as the data directory + env::var_os(format!("{}_DATA", PROJECT_NAME.clone())).or_else(|| { + // otherwise, use the XDG data directory + env::var_os("XDG_DATA_HOME") + }).map(PathBuf::from).filter(|p| p.is_absolute()); pub static ref CONFIG_FOLDER: Option = - env::var(format!("{}_CONFIG", PROJECT_NAME.clone())) - .ok() - .map(PathBuf::from); + // if `TELEVISION_CONFIG` is set, use that as the config directory + env::var_os(format!("{}_CONFIG", PROJECT_NAME.clone())).or_else(|| { + // otherwise, use the XDG config directory + env::var_os("XDG_CONFIG_HOME") + }).map(PathBuf::from).filter(|p| p.is_absolute()); } const CONFIG_FILE_NAME: &str = "config.toml"; diff --git a/crates/television/previewers.rs b/crates/television/previewers.rs index de1a7dd..81acaca 100644 --- a/crates/television/previewers.rs +++ b/crates/television/previewers.rs @@ -11,9 +11,13 @@ mod meta; // previewer types pub use basic::BasicPreviewer; +pub use basic::BasicPreviewerConfig; pub use directory::DirectoryPreviewer; +pub use directory::DirectoryPreviewerConfig; pub use env::EnvVarPreviewer; +pub use env::EnvVarPreviewerConfig; pub use files::FilePreviewer; +pub use files::FilePreviewerConfig; //use ratatui_image::protocol::StatefulProtocol; use syntect::highlighting::Style; @@ -26,7 +30,7 @@ pub enum PreviewType { Files, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum PreviewContent { Empty, FileTooLarge, @@ -47,7 +51,7 @@ pub const FILE_TOO_LARGE_MSG: &str = "File too large"; /// # Fields /// - `title`: The title of the preview. /// - `content`: The content of the preview. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Preview { pub title: String, pub content: PreviewContent, @@ -80,6 +84,7 @@ impl Preview { } } +#[derive(Debug, Default)] pub struct Previewer { basic: BasicPreviewer, directory: DirectoryPreviewer, @@ -87,19 +92,44 @@ pub struct Previewer { env_var: EnvVarPreviewer, } -impl Default for Previewer { - fn default() -> Self { - Previewer::new() +#[derive(Debug, Default)] +pub struct PreviewerConfig { + basic: BasicPreviewerConfig, + directory: DirectoryPreviewerConfig, + file: FilePreviewerConfig, + env_var: EnvVarPreviewerConfig, +} + +impl PreviewerConfig { + pub fn basic(mut self, config: BasicPreviewerConfig) -> Self { + self.basic = config; + self + } + + pub fn directory(mut self, config: DirectoryPreviewerConfig) -> Self { + self.directory = config; + self + } + + pub fn file(mut self, config: FilePreviewerConfig) -> Self { + self.file = config; + self + } + + pub fn env_var(mut self, config: EnvVarPreviewerConfig) -> Self { + self.env_var = config; + self } } impl Previewer { - pub fn new() -> Self { + pub fn new(config: Option) -> Self { + let config = config.unwrap_or_default(); Previewer { - basic: BasicPreviewer::new(), - directory: DirectoryPreviewer::new(), - file: FilePreviewer::new(), - env_var: EnvVarPreviewer::new(), + basic: BasicPreviewer::new(Some(config.basic)), + directory: DirectoryPreviewer::new(Some(config.directory)), + file: FilePreviewer::new(Some(config.file)), + env_var: EnvVarPreviewer::new(Some(config.env_var)), } } @@ -111,4 +141,11 @@ impl Previewer { PreviewType::Files => self.file.preview(entry).await, } } + + pub fn set_config(&mut self, config: PreviewerConfig) { + self.basic = BasicPreviewer::new(Some(config.basic)); + self.directory = DirectoryPreviewer::new(Some(config.directory)); + self.file = FilePreviewer::new(Some(config.file)); + self.env_var = EnvVarPreviewer::new(Some(config.env_var)); + } } diff --git a/crates/television/previewers/basic.rs b/crates/television/previewers/basic.rs index 3709eeb..dcbe377 100644 --- a/crates/television/previewers/basic.rs +++ b/crates/television/previewers/basic.rs @@ -3,17 +3,19 @@ use std::sync::Arc; use crate::entry::Entry; use crate::previewers::{Preview, PreviewContent}; -pub struct BasicPreviewer {} - -impl Default for BasicPreviewer { - fn default() -> Self { - BasicPreviewer::new() - } +#[derive(Debug, Default)] +pub struct BasicPreviewer { + config: BasicPreviewerConfig, } +#[derive(Debug, Default)] +pub struct BasicPreviewerConfig {} + impl BasicPreviewer { - pub fn new() -> Self { - BasicPreviewer {} + pub fn new(config: Option) -> Self { + BasicPreviewer { + config: config.unwrap_or_default(), + } } pub fn preview(&self, entry: &Entry) -> Arc { diff --git a/crates/television/previewers/cache.rs b/crates/television/previewers/cache.rs index 286ec3f..5da16e8 100644 --- a/crates/television/previewers/cache.rs +++ b/crates/television/previewers/cache.rs @@ -44,6 +44,7 @@ use crate::previewers::Preview; /// assert!(ring_set.contains(&3)); /// assert!(ring_set.contains(&4)); /// ``` +#[derive(Debug)] struct RingSet { ring_buffer: VecDeque, known_keys: HashSet, @@ -107,6 +108,7 @@ const DEFAULT_PREVIEW_CACHE_SIZE: usize = 100; /// A cache for previews. /// The cache is implemented as an LRU cache with a fixed size. +#[derive(Debug)] pub struct PreviewCache { entries: HashMap>, ring_set: RingSet, diff --git a/crates/television/previewers/directory.rs b/crates/television/previewers/directory.rs index 15d7a1c..c2a2d1f 100644 --- a/crates/television/previewers/directory.rs +++ b/crates/television/previewers/directory.rs @@ -11,20 +11,20 @@ use crate::previewers::cache::PreviewCache; use crate::previewers::{meta, Preview, PreviewContent}; use crate::utils::files::walk_builder; +#[derive(Debug, Default)] pub struct DirectoryPreviewer { cache: Arc>, + config: DirectoryPreviewerConfig, } -impl Default for DirectoryPreviewer { - fn default() -> Self { - DirectoryPreviewer::new() - } -} +#[derive(Debug, Default)] +pub struct DirectoryPreviewerConfig {} impl DirectoryPreviewer { - pub fn new() -> Self { + pub fn new(config: Option) -> Self { DirectoryPreviewer { cache: Arc::new(Mutex::new(PreviewCache::default())), + config: config.unwrap_or_default(), } } diff --git a/crates/television/previewers/env.rs b/crates/television/previewers/env.rs index daf17fb..190c668 100644 --- a/crates/television/previewers/env.rs +++ b/crates/television/previewers/env.rs @@ -4,20 +4,20 @@ use std::sync::Arc; use crate::entry; use crate::previewers::{Preview, PreviewContent}; +#[derive(Debug, Default)] pub struct EnvVarPreviewer { cache: HashMap>, + config: EnvVarPreviewerConfig, } -impl Default for EnvVarPreviewer { - fn default() -> Self { - EnvVarPreviewer::new() - } -} +#[derive(Debug, Default)] +pub struct EnvVarPreviewerConfig {} impl EnvVarPreviewer { - pub fn new() -> Self { + pub fn new(config: Option) -> Self { EnvVarPreviewer { cache: HashMap::new(), + config: config.unwrap_or_default(), } } diff --git a/crates/television/previewers/files.rs b/crates/television/previewers/files.rs index d59c29f..971ec86 100644 --- a/crates/television/previewers/files.rs +++ b/crates/television/previewers/files.rs @@ -22,8 +22,9 @@ use crate::utils::strings::{ preprocess_line, proportion_of_printable_ascii_characters, PRINTABLE_ASCII_THRESHOLD, }; -use crate::utils::syntax; +use crate::utils::syntax::{self, load_highlighting_assets}; +#[derive(Debug, Default)] pub struct FilePreviewer { cache: Arc>, pub syntax_set: Arc, @@ -31,16 +32,29 @@ pub struct FilePreviewer { //image_picker: Arc>, } -impl Default for FilePreviewer { - fn default() -> Self { - FilePreviewer::new() +#[derive(Debug, Clone, Default)] +pub struct FilePreviewerConfig { + pub theme: String, +} + +impl FilePreviewerConfig { + pub fn new(theme: String) -> Self { + FilePreviewerConfig { theme } } } impl FilePreviewer { - pub fn new() -> Self { - let syntax_set = SyntaxSet::load_defaults_nonewlines(); - let theme_set = ThemeSet::load_defaults(); + pub fn new(config: Option) -> Self { + let hl_assets = load_highlighting_assets(); + let syntax_set = hl_assets.get_syntax_set().unwrap().clone(); + + let theme = config.map_or_else( + || { + let theme_set = ThemeSet::load_defaults(); + theme_set.themes["base16-ocean.dark"].clone() + }, + |c| hl_assets.get_theme(&c.theme).clone(), + ); //info!("getting image picker"); //let image_picker = get_image_picker(); //info!("got image picker"); @@ -48,9 +62,7 @@ impl FilePreviewer { FilePreviewer { cache: Arc::new(Mutex::new(PreviewCache::default())), syntax_set: Arc::new(syntax_set), - syntax_theme: Arc::new( - theme_set.themes["base16-ocean.dark"].clone(), - ), + syntax_theme: Arc::new(theme), //image_picker: Arc::new(Mutex::new(image_picker)), } } @@ -173,7 +185,9 @@ impl FilePreviewer { let lines: Vec = reader .lines() .map_while(Result::ok) - .map(|line| preprocess_line(&line)) + // we need to add a newline here because sublime syntaxes expect one + // to be present at the end of each line + .map(|line| preprocess_line(&line) + "\n") .collect(); match syntax::compute_highlights_for_path( diff --git a/crates/television/television.rs b/crates/television/television.rs index 10eb814..60837ea 100644 --- a/crates/television/television.rs +++ b/crates/television/television.rs @@ -1,6 +1,7 @@ use crate::channels::remote_control::RemoteControl; use crate::channels::{OnAir, UnitChannel}; use crate::picker::Picker; +use crate::previewers; use crate::ui::layout::{Dimensions, Layout}; use crate::utils::strings::EMPTY_STRING; use crate::{action::Action, config::Config}; @@ -72,7 +73,7 @@ impl Television { results_picker: Picker::default(), rc_picker: Picker::default().inverted(), results_area_height: 0, - previewer: Previewer::new(), + previewer: Previewer::default(), preview_scroll: None, preview_pane_height: 0, current_preview_total_lines: 0, @@ -229,6 +230,11 @@ impl Television { /// * `Result<()>` - An Ok result or an error. pub fn register_config_handler(&mut self, config: Config) -> Result<()> { self.config = config; + let previewer_config = + std::convert::Into::::into( + self.config.previewers.clone(), + ); + self.previewer.set_config(previewer_config); Ok(()) } diff --git a/crates/television/utils/syntax.rs b/crates/television/utils/syntax.rs index 5b207ed..e703b00 100644 --- a/crates/television/utils/syntax.rs +++ b/crates/television/utils/syntax.rs @@ -1,4 +1,5 @@ -use std::path::Path; +use bat::assets::HighlightingAssets; +use std::path::{Path, PathBuf}; use syntect::easy::HighlightLines; use syntect::highlighting::{Style, Theme}; use syntect::parsing::SyntaxSet; @@ -56,3 +57,49 @@ pub fn compute_highlights_for_line<'a>( } } } + +// Based on code from https://github.com/sharkdp/bat e981e974076a926a38f124b7d8746de2ca5f0a28 + +use directories::BaseDirs; +use lazy_static::lazy_static; + +#[cfg(target_os = "macos")] +use std::env; + +/// Wrapper for 'dirs' that treats MacOS more like Linux, by following the XDG specification. +/// This means that the `XDG_CACHE_HOME` and `XDG_CONFIG_HOME` environment variables are +/// checked first. The fallback directories are `~/.cache/bat` and `~/.config/bat`, respectively. +pub struct BatProjectDirs { + cache_dir: PathBuf, +} + +impl BatProjectDirs { + fn new() -> Option { + #[cfg(target_os = "macos")] + let cache_dir_op = env::var_os("XDG_CACHE_HOME") + .map(PathBuf::from) + .filter(|p| p.is_absolute()) + .or_else(|| BaseDirs::new().map(|d| d.home_dir().join(".cache"))); + + #[cfg(not(target_os = "macos"))] + let cache_dir_op = BaseDirs::new().map(|d| d.cache_dir().to_owned()); + + let cache_dir = cache_dir_op.map(|d| d.join("bat"))?; + + Some(BatProjectDirs { cache_dir }) + } + + pub fn cache_dir(&self) -> &Path { + &self.cache_dir + } +} + +lazy_static! { + pub static ref PROJECT_DIRS: BatProjectDirs = BatProjectDirs::new() + .unwrap_or_else(|| panic!("Could not get home directory")); +} + +pub fn load_highlighting_assets() -> HighlightingAssets { + HighlightingAssets::from_cache(PROJECT_DIRS.cache_dir()) + .unwrap_or_else(|_| bat::assets::HighlightingAssets::from_binary()) +}