use crate::ported::colorscheme::{ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE};
pub fn attrs_to_tmux_attrs(attrs: Option<u32>) -> Vec<String> {
let Some(a) = attrs else {
return vec![
"nobold".to_string(),
"noitalics".to_string(),
"nounderscore".to_string(),
];
};
let mut ret: Vec<String> = Vec::with_capacity(3);
if a & ATTR_BOLD != 0 {
ret.push("bold".to_string());
} else {
ret.push("nobold".to_string());
}
if a & ATTR_ITALIC != 0 {
ret.push("italics".to_string());
} else {
ret.push("noitalics".to_string());
}
if a & ATTR_UNDERLINE != 0 {
ret.push("underscore".to_string());
} else {
ret.push("nounderscore".to_string());
}
ret
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ColorSpec {
pub cterm: u16,
pub truecolor: Option<u32>,
}
pub struct TmuxRenderer {
pub term_truecolor: bool,
}
impl TmuxRenderer {
pub fn new(term_truecolor: bool) -> Self {
Self { term_truecolor }
}
pub fn character_translations() -> Vec<(char, &'static str)> {
vec![('#', "##[]")]
}
pub fn hlstyle(
&self,
fg: Option<ColorSpec>,
bg: Option<ColorSpec>,
attrs: Option<u32>,
) -> String {
if attrs.is_none() && bg.is_none() && fg.is_none() {
return String::new();
}
let mut tmux_attrs: Vec<String> = Vec::new();
if let Some(f) = fg {
tmux_attrs.push(self.color_spec("fg", Some(f)));
}
if let Some(b) = bg {
tmux_attrs.push(self.color_spec("bg", Some(b)));
}
if let Some(a) = attrs {
tmux_attrs.extend(attrs_to_tmux_attrs(Some(a)));
}
format!("#[{}]", tmux_attrs.join(","))
}
fn color_spec(&self, channel: &str, color: Option<ColorSpec>) -> String {
let Some(c) = color else {
return format!("{}=default", channel);
};
if self.term_truecolor {
if let Some(rgb) = c.truecolor {
return format!("{}=#{:06x}", channel, rgb);
}
}
format!("{}=colour{}", channel, c.cterm)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn attrs_to_tmux_attrs_none_returns_all_no_prefixes() {
let r = attrs_to_tmux_attrs(None);
assert_eq!(r, vec!["nobold", "noitalics", "nounderscore"]);
}
#[test]
fn attrs_to_tmux_attrs_zero_returns_all_no_prefixes() {
let r = attrs_to_tmux_attrs(Some(0));
assert_eq!(r, vec!["nobold", "noitalics", "nounderscore"]);
}
#[test]
fn attrs_to_tmux_attrs_bold_only() {
let r = attrs_to_tmux_attrs(Some(ATTR_BOLD));
assert_eq!(r, vec!["bold", "noitalics", "nounderscore"]);
}
#[test]
fn attrs_to_tmux_attrs_italic_only() {
let r = attrs_to_tmux_attrs(Some(ATTR_ITALIC));
assert_eq!(r, vec!["nobold", "italics", "nounderscore"]);
}
#[test]
fn attrs_to_tmux_attrs_underline_only() {
let r = attrs_to_tmux_attrs(Some(ATTR_UNDERLINE));
assert_eq!(r, vec!["nobold", "noitalics", "underscore"]);
}
#[test]
fn attrs_to_tmux_attrs_all_three() {
let r = attrs_to_tmux_attrs(Some(ATTR_BOLD | ATTR_ITALIC | ATTR_UNDERLINE));
assert_eq!(r, vec!["bold", "italics", "underscore"]);
}
#[test]
fn character_translations_contains_hash_override() {
let t = TmuxRenderer::character_translations();
assert_eq!(t.len(), 1);
assert_eq!(t[0], ('#', "##[]"));
}
#[test]
fn hlstyle_no_args_returns_empty_string() {
let r = TmuxRenderer::new(false);
assert_eq!(r.hlstyle(None, None, None), "");
}
#[test]
fn hlstyle_fg_cterm_only_emits_colour_n() {
let r = TmuxRenderer::new(false);
let s = r.hlstyle(
Some(ColorSpec {
cterm: 231,
truecolor: Some(0xffffff),
}),
None,
None,
);
assert_eq!(s, "#[fg=colour231]");
}
#[test]
fn hlstyle_fg_truecolor_emits_hex() {
let r = TmuxRenderer::new(true);
let s = r.hlstyle(
Some(ColorSpec {
cterm: 231,
truecolor: Some(0xffaa00),
}),
None,
None,
);
assert_eq!(s, "#[fg=#ffaa00]");
}
#[test]
fn hlstyle_bg_emits_bg_directive() {
let r = TmuxRenderer::new(false);
let s = r.hlstyle(
None,
Some(ColorSpec {
cterm: 21,
truecolor: Some(0x0000ff),
}),
None,
);
assert_eq!(s, "#[bg=colour21]");
}
#[test]
fn hlstyle_attrs_emits_bold_italics_underline() {
let r = TmuxRenderer::new(false);
let s = r.hlstyle(None, None, Some(ATTR_BOLD | ATTR_UNDERLINE));
assert_eq!(s, "#[bold,noitalics,underscore]");
}
#[test]
fn hlstyle_combined_fg_bg_attrs_joins_with_commas() {
let r = TmuxRenderer::new(false);
let s = r.hlstyle(
Some(ColorSpec {
cterm: 231,
truecolor: None,
}),
Some(ColorSpec {
cterm: 21,
truecolor: None,
}),
Some(ATTR_BOLD),
);
assert_eq!(s, "#[fg=colour231,bg=colour21,bold,noitalics,nounderscore]");
}
#[test]
fn hlstyle_truecolor_without_rgb_falls_back_to_cterm() {
let r = TmuxRenderer::new(true);
let s = r.hlstyle(
Some(ColorSpec {
cterm: 42,
truecolor: None,
}),
None,
None,
);
assert_eq!(s, "#[fg=colour42]");
}
}