Skip to content

Commit

Permalink
feat!: auto switch between dark and light icons/flavors based on term…
Browse files Browse the repository at this point in the history
…inal backgrounds (#1946)
  • Loading branch information
sxyazi committed Nov 25, 2024
1 parent 1277b01 commit dc1a741
Show file tree
Hide file tree
Showing 30 changed files with 1,778 additions and 863 deletions.
2 changes: 1 addition & 1 deletion cspell.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"language":"en","flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod","fdfind","Rustc","rustc","Sysinfo","ffprobe","vframes"],"version":"0.2"}
{"version":"0.2","flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod","fdfind","Rustc","rustc","Sysinfo","ffprobe","vframes","luma"],"language":"en"}
23 changes: 16 additions & 7 deletions scripts/icons/generate.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,25 @@ function dump(map)
list[#list + 1] = { name = k, text = v.icon, fg_dark = v.fg_dark, fg_light = v.fg_light }
end
table.sort(list, function(a, b) return a.name:lower() < b.name:lower() end)
local dark, light = "", ""
for _, v in ipairs(list) do
-- stylua: ignore
print(string.format('\t{ name = "%s", text = "%s", fg_dark = "%s", fg_light = "%s" },', v.name, v.text, v.fg_dark, v.fg_light))
dark = dark .. string.format('\t{ name = "%s", text = "%s", fg = "%s" },\n', v.name, v.text, v.fg_dark)
light = light .. string.format('\t{ name = "%s", text = "%s", fg = "%s" },\n', v.name, v.text, v.fg_light)
end
return dark, light
end

print("files = [")
dump(rearrange("files"))
print("]")
function save(typ, files, exts)
local p = string.format("../../yazi-config/preset/theme+%s.toml", typ)
local s = io.open(p, "r"):read("*a")
s = s:gsub("files = %[\n(.-)\n%]", string.format("files = [\n%s]", files))
s = s:gsub("exts = %[\n(.-)\n%]", string.format("exts = [\n%s]", exts))
io.open(p, "w"):write(s)
end

local dark_files, light_files = dump(rearrange("files"))
local dark_exts, light_exts = dump(rearrange("exts"))

print("exts = [")
dump(rearrange("exts"))
print("]")
save("dark", dark_files, dark_exts)
save("light", light_files, light_exts)
40 changes: 19 additions & 21 deletions yazi-adapter/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ use ratatui::layout::Rect;
use tracing::warn;
use yazi_shared::env_exists;

use super::{Iip, Kgp, KgpOld};
use crate::{Chafa, Emulator, SHOWN, Sixel, TMUX, Ueberzug, WSL};
use crate::{Brand, Emulator, SHOWN, TMUX, WSL, drivers};

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Adapter {
Expand Down Expand Up @@ -42,12 +41,12 @@ impl Adapter {
}

match self {
Self::Kgp => Kgp::image_show(path, max).await,
Self::KgpOld => KgpOld::image_show(path, max).await,
Self::Iip => Iip::image_show(path, max).await,
Self::Sixel => Sixel::image_show(path, max).await,
Self::X11 | Self::Wayland => Ueberzug::image_show(path, max).await,
Self::Chafa => Chafa::image_show(path, max).await,
Self::Kgp => drivers::Kgp::image_show(path, max).await,
Self::KgpOld => drivers::KgpOld::image_show(path, max).await,
Self::Iip => drivers::Iip::image_show(path, max).await,
Self::Sixel => drivers::Sixel::image_show(path, max).await,
Self::X11 | Self::Wayland => drivers::Ueberzug::image_show(path, max).await,
Self::Chafa => drivers::Chafa::image_show(path, max).await,
}
}

Expand All @@ -57,12 +56,12 @@ impl Adapter {

pub fn image_erase(self, area: Rect) -> Result<()> {
match self {
Self::Kgp => Kgp::image_erase(area),
Self::KgpOld => KgpOld::image_erase(area),
Self::Iip => Iip::image_erase(area),
Self::Sixel => Sixel::image_erase(area),
Self::X11 | Self::Wayland => Ueberzug::image_erase(area),
Self::Chafa => Chafa::image_erase(area),
Self::Kgp => drivers::Kgp::image_erase(area),
Self::KgpOld => drivers::KgpOld::image_erase(area),
Self::Iip => drivers::Iip::image_erase(area),
Self::Sixel => drivers::Sixel::image_erase(area),
Self::X11 | Self::Wayland => drivers::Ueberzug::image_erase(area),
Self::Chafa => drivers::Chafa::image_erase(area),
}
}

Expand All @@ -72,7 +71,7 @@ impl Adapter {
#[inline]
pub(super) fn shown_store(area: Rect) { SHOWN.set(Some(area)); }

pub(super) fn start(self) { Ueberzug::start(self); }
pub(super) fn start(self) { drivers::Ueberzug::start(self); }

#[inline]
pub(super) fn needs_ueberzug(self) -> bool {
Expand All @@ -81,15 +80,14 @@ impl Adapter {
}

impl Adapter {
pub fn matches() -> Self {
let emulator = Emulator::detect();
if matches!(emulator, Emulator::Microsoft) {
pub fn matches(emulator: Emulator) -> Self {
if matches!(emulator.kind.left(), Some(Brand::Microsoft)) {
return Self::Sixel;
} else if *WSL && matches!(emulator, Emulator::WezTerm) {
} else if *WSL && matches!(emulator.kind.left(), Some(Brand::WezTerm)) {
return Self::KgpOld;
}

let mut protocols = emulator.adapters();
let mut protocols = emulator.adapters().to_owned();
#[cfg(windows)]
protocols.retain(|p| *p == Self::Iip);
if env_exists("ZELLIJ_SESSION_NAME") {
Expand All @@ -101,7 +99,7 @@ impl Adapter {
return *p;
}

let supported_compositor = Ueberzug::supported_compositor();
let supported_compositor = drivers::Ueberzug::supported_compositor();
match env::var("XDG_SESSION_TYPE").unwrap_or_default().as_str() {
"x11" => return Self::X11,
"wayland" if supported_compositor => return Self::Wayland,
Expand Down
119 changes: 119 additions & 0 deletions yazi-adapter/src/brand.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
use tracing::warn;
use yazi_shared::env_exists;

use crate::Mux;

#[derive(Clone, Copy, Debug)]
pub enum Brand {
Kitty,
Konsole,
Iterm2,
WezTerm,
Foot,
Ghostty,
Microsoft,
Rio,
BlackBox,
VSCode,
Tabby,
Hyper,
Mintty,
Neovim,
Apple,
Urxvt,
}

impl Brand {
pub fn from_env() -> Option<Self> {
use Brand as B;

if env_exists("NVIM_LOG_FILE") && env_exists("NVIM") {
return Some(Self::Neovim);
}

let vars = [
("KITTY_WINDOW_ID", B::Kitty),
("KONSOLE_VERSION", B::Konsole),
("ITERM_SESSION_ID", B::Iterm2),
("WEZTERM_EXECUTABLE", B::WezTerm),
("GHOSTTY_RESOURCES_DIR", B::Ghostty),
("WT_Session", B::Microsoft),
("VSCODE_INJECTION", B::VSCode),
("TABBY_CONFIG_DIRECTORY", B::Tabby),
];
match vars.into_iter().find(|&(s, _)| env_exists(s)) {
Some((_, brand)) => return Some(brand),
None => warn!("[Adapter] No special environment variables detected"),
}

let (term, program) = B::env();
match program.as_str() {
"iTerm.app" => return Some(B::Iterm2),
"WezTerm" => return Some(B::WezTerm),
"ghostty" => return Some(B::Ghostty),
"rio" => return Some(B::Rio),
"BlackBox" => return Some(B::BlackBox),
"vscode" => return Some(B::VSCode),
"Tabby" => return Some(B::Tabby),
"Hyper" => return Some(B::Hyper),
"mintty" => return Some(B::Mintty),
"Apple_Terminal" => return Some(B::Apple),
_ => warn!("[Adapter] Unknown TERM_PROGRAM: {program}"),
}
match term.as_str() {
"xterm-kitty" => return Some(B::Kitty),
"foot" => return Some(B::Foot),
"foot-extra" => return Some(B::Foot),
"xterm-ghostty" => return Some(B::Ghostty),
"rio" => return Some(B::Rio),
"rxvt-unicode-256color" => return Some(B::Urxvt),
_ => warn!("[Adapter] Unknown TERM: {term}"),
}
None
}

pub(super) fn from_csi(resp: &str) -> Option<Self> {
let names = [
("kitty", Self::Kitty),
("Konsole", Self::Konsole),
("iTerm2", Self::Iterm2),
("WezTerm", Self::WezTerm),
("foot", Self::Foot),
("ghostty", Self::Ghostty),
];
names.into_iter().find(|&(n, _)| resp.contains(n)).map(|(_, b)| b)
}

pub(super) fn adapters(self) -> &'static [crate::Adapter] {
use Brand as B;

use crate::Adapter as A;

match self {
B::Kitty => &[A::Kgp],
B::Konsole => &[A::KgpOld],
B::Iterm2 => &[A::Iip, A::Sixel],
B::WezTerm => &[A::Iip, A::Sixel],
B::Foot => &[A::Sixel],
B::Ghostty => &[A::Kgp],
B::Microsoft => &[A::Sixel],
B::Rio => &[A::Iip, A::Sixel],
B::BlackBox => &[A::Sixel],
B::VSCode => &[A::Iip, A::Sixel],
B::Tabby => &[A::Iip, A::Sixel],
B::Hyper => &[A::Iip, A::Sixel],
B::Mintty => &[A::Iip],
B::Neovim => &[],
B::Apple => &[],
B::Urxvt => &[],
}
}

fn env() -> (String, String) {
let (term, program) = Mux::term_program();
(
term.unwrap_or(std::env::var("TERM").unwrap_or_default()),
program.unwrap_or(std::env::var("TERM_PROGRAM").unwrap_or_default()),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ use tokio::process::Command;

use crate::{Adapter, Emulator};

pub(super) struct Chafa;
pub(crate) struct Chafa;

impl Chafa {
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
let output = Command::new("chafa")
.args([
"-f",
Expand Down Expand Up @@ -64,7 +64,7 @@ impl Chafa {
})
}

pub(super) fn image_erase(area: Rect) -> Result<()> {
pub(crate) fn image_erase(area: Rect) -> Result<()> {
let s = " ".repeat(area.width as usize);
Emulator::move_lock((0, 0), |stderr| {
for y in area.top()..area.bottom() {
Expand Down
9 changes: 4 additions & 5 deletions yazi-adapter/src/iip.rs → yazi-adapter/src/drivers/iip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ use image::{DynamicImage, ExtendedColorType, ImageEncoder, codecs::{jpeg::JpegEn
use ratatui::layout::Rect;
use yazi_config::PREVIEW;

use super::image::Image;
use crate::{CLOSE, Emulator, START, adapter::Adapter};
use crate::{CLOSE, Emulator, Image, START, adapter::Adapter};

pub(super) struct Iip;
pub(crate) struct Iip;

impl Iip {
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
let img = Image::downscale(path, max).await?;
let area = Image::pixel_area((img.width(), img.height()), max);
let b = Self::encode(img).await?;
Expand All @@ -26,7 +25,7 @@ impl Iip {
})
}

pub(super) fn image_erase(area: Rect) -> Result<()> {
pub(crate) fn image_erase(area: Rect) -> Result<()> {
let s = " ".repeat(area.width as usize);
Emulator::move_lock((0, 0), |stderr| {
for y in area.top()..area.bottom() {
Expand Down
9 changes: 4 additions & 5 deletions yazi-adapter/src/kgp.rs → yazi-adapter/src/drivers/kgp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ use crossterm::{cursor::MoveTo, queue};
use image::DynamicImage;
use ratatui::layout::Rect;

use super::image::Image;
use crate::{CLOSE, ESCAPE, Emulator, START, adapter::Adapter};
use crate::{CLOSE, ESCAPE, Emulator, START, adapter::Adapter, image::Image};

static DIACRITICS: [char; 297] = [
'\u{0305}',
Expand Down Expand Up @@ -310,10 +309,10 @@ static DIACRITICS: [char; 297] = [
'\u{1D244}',
];

pub(super) struct Kgp;
pub(crate) struct Kgp;

impl Kgp {
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
let img = Image::downscale(path, max).await?;
let area = Image::pixel_area((img.width(), img.height()), max);

Expand All @@ -329,7 +328,7 @@ impl Kgp {
})
}

pub(super) fn image_erase(area: Rect) -> Result<()> {
pub(crate) fn image_erase(area: Rect) -> Result<()> {
let s = " ".repeat(area.width as usize);
Emulator::move_lock((0, 0), |stderr| {
for y in area.top()..area.bottom() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ use base64::{Engine, engine::general_purpose};
use image::DynamicImage;
use ratatui::layout::Rect;

use super::image::Image;
use crate::{CLOSE, ESCAPE, Emulator, START, adapter::Adapter};
use crate::{CLOSE, ESCAPE, Emulator, Image, START, adapter::Adapter};

pub(super) struct KgpOld;
pub(crate) struct KgpOld;

impl KgpOld {
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
let img = Image::downscale(path, max).await?;
let area = Image::pixel_area((img.width(), img.height()), max);
let b = Self::encode(img).await?;
Expand All @@ -26,7 +25,7 @@ impl KgpOld {
}

#[inline]
pub(super) fn image_erase(_: Rect) -> Result<()> {
pub(crate) fn image_erase(_: Rect) -> Result<()> {
let mut stderr = LineWriter::new(stderr());
write!(stderr, "{}_Gq=2,a=d,d=A{}\\{}", START, ESCAPE, CLOSE)?;
stderr.flush()?;
Expand Down
1 change: 1 addition & 0 deletions yazi-adapter/src/drivers/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
yazi_macro::mod_flat!(chafa iip kgp kgp_old sixel ueberzug);
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use yazi_config::PREVIEW;

use crate::{CLOSE, ESCAPE, Emulator, Image, START, adapter::Adapter};

pub(super) struct Sixel;
pub(crate) struct Sixel;

impl Sixel {
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
let img = Image::downscale(path, max).await?;
let area = Image::pixel_area((img.width(), img.height()), max);
let b = Self::encode(img).await?;
Expand All @@ -25,7 +25,7 @@ impl Sixel {
})
}

pub(super) fn image_erase(area: Rect) -> Result<()> {
pub(crate) fn image_erase(area: Rect) -> Result<()> {
let s = " ".repeat(area.width as usize);
Emulator::move_lock((0, 0), |stderr| {
for y in area.top()..area.bottom() {
Expand Down
Loading

0 comments on commit dc1a741

Please sign in to comment.