summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2022-01-06 08:35:13 +0100
committerCanop <cano.petrole@gmail.com>2022-01-06 08:35:13 +0100
commit1e3d68f84cc9f10a79905a837c2e46467fa8a952 (patch)
treea6236b38e8501968ab2726533c7016b666ba3964 /src
parent6c7f16446fdc81ca4cc5371c5d7a324c952da0d9 (diff)
Display images in high res on recent WezTerm
More specifically, this commit implements detection of recent enough WezTerm versions with the $TERM_PROGRAM and $TERM_PROGRAM_VERSION environment variables. Fix #473
Diffstat (limited to 'src')
-rw-r--r--src/kitty/detect_support.rs80
-rw-r--r--src/kitty/image_renderer.rs62
-rw-r--r--src/kitty/mod.rs1
-rw-r--r--src/skin/skin_entry.rs16
-rw-r--r--src/syntactic/syntactic_view.rs14
5 files changed, 100 insertions, 73 deletions
diff --git a/src/kitty/detect_support.rs b/src/kitty/detect_support.rs
new file mode 100644
index 0000000..db806d0
--- /dev/null
+++ b/src/kitty/detect_support.rs
@@ -0,0 +1,80 @@
+use {
+ cli_log::*,
+ std::{
+ env,
+ },
+};
+
+/// Determine whether Kitty's graphics protocol is supported
+/// by the terminal running broot.
+///
+/// This is called only once, and cached in the KittyManager's
+/// MaybeRenderer state
+#[allow(unreachable_code)]
+pub fn is_kitty_graphics_protocol_supported() -> bool {
+ debug!("is_kitty_graphics_protocol_supported ?");
+
+ #[cfg(not(unix))]
+ {
+ // because cell_size_in_pixels isn't implemented on Windows
+ debug!("no kitty support yet on Windows");
+ return false;
+ }
+
+ // we detect Kitty by the $TERM or $TERMINAL env var
+ for env_var in ["TERM", "TERMINAL"] {
+ if let Ok(env_val) = env::var(env_var) {
+ debug!("${} = {:?}", env_var, env_val);
+ let env_val = env_val.to_ascii_lowercase();
+ if env_val.contains("kitty") {
+ debug!(" -> this terminal seems to be Kitty");
+ return true;
+ }
+ }
+ }
+
+ // we detect Wezterm with the $TERM_PROGRAM env var and we
+ // check its version to be sure it's one with support
+ if let Ok(term_program) = env::var("TERM_PROGRAM") {
+ debug!("$TERM_PROGRAM = {:?}", term_program);
+ if term_program == "WezTerm" {
+ if let Ok(version) = env::var("TERM_PROGRAM_VERSION") {
+ debug!("$TERM_PROGRAM_VERSION = {:?}", version);
+ if &*version < "20220105-201556-91a423da" {
+ debug!("WezTerm's version predates Kitty Graphics protocol support");
+ } else {
+ debug!("this looks like a compatible version");
+ return true;
+ }
+ } else {
+ warn!("$TERM_PROGRAM_VERSION unexpectedly missing");
+ }
+ }
+ }
+
+ // Checking support with a proper CSI sequence should be the prefered way but
+ // it doesn't work reliably on wezterm and requires a wait on other terminals.
+ // As both Kitty and WezTerm set env vars allowing an easy detection, this
+ // CSI based querying isn't necessary right now.
+ // This feature is kept gated and should only be tried if other terminals
+ // appear and can't be detected without CSI sequence.
+ #[cfg(feature = "kitty-csi-check")]
+ {
+ let start = std::time::Instant::now();
+ const TIMEOUT_MS: isize = 400;
+ let s = match xterm_query::query("\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\\x1b[c", TIMEOUT_MS) {
+ Err(e) => {
+ debug!("xterm querying failed: {}", e);
+ false
+ }
+ Ok(response) => {
+ response.starts_with("\x1b_Gi=31;OK\x1b")
+ }
+ };
+ debug!("Xterm querying took {:?}", start.elapsed());
+ debug!("kitty protocol support: {:?}", s);
+ return s;
+ }
+ false
+}
+
diff --git a/src/kitty/image_renderer.rs b/src/kitty/image_renderer.rs
index 7282c27..58dab57 100644
--- a/src/kitty/image_renderer.rs
+++ b/src/kitty/image_renderer.rs
@@ -1,4 +1,5 @@
use {
+ super::detect_support::is_kitty_graphics_protocol_supported,
crate::{
display::{
cell_size_in_pixels,
@@ -19,14 +20,12 @@ use {
RgbaImage,
},
std::{
- env,
io::{self, Write},
},
tempfile,
termimad::Area,
};
-
/// How to send the image to kitty
///
/// Note that I didn't test yet the named shared memory
@@ -84,63 +83,13 @@ impl<'i> ImageData<'i> {
/// according to kitty's documentation
const CHUNK_SIZE: usize = 4096;
-/// this is called only once, and cached in the kitty manager's MaybeRenderer state
-#[allow(unreachable_code)]
-fn is_kitty_graphics_protocol_supported() -> bool {
- debug!("is_kitty_graphics_protocol_supported ?");
-
- #[cfg(not(unix))]
- {
- // because cell_size_in_pixels isn't implemented on Windows
- debug!("no kitty support yet on Windows");
- return false;
- }
-
- for env_var in ["TERM", "TERMINAL"] {
- if let Ok(env_val) = env::var(env_var) {
- debug!("{:?} = {:?}", env_var, env_val);
- let env_val = env_val.to_ascii_lowercase();
- for name in ["kitty", "wezterm"] {
- if env_val.contains(name) {
- debug!(" -> env var indicates kitty support");
- return true;
- }
- }
- }
- }
-
- // Checking support with a proper CSI sequence should be the prefered way but
- // it doesn't work reliably on wezterm and requires a wait on other terminal.
- // Only Kitty does supports it perfectly and it's not even necessary on this
- // terminal because we can just check the env var TERM.
- #[cfg(feature = "kitty-csi-check")]
- {
- let start = std::time::Instant::now();
- const TIMEOUT_MS: isize = 400;
- let s = match xterm_query::query("\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\\x1b[c", TIMEOUT_MS) {
- Err(e) => {
- debug!("xterm querying failed: {}", e);
- false
- }
- Ok(response) => {
- response.starts_with("\x1b_Gi=31;OK\x1b")
- }
- };
- debug!("Xterm querying took {:?}", start.elapsed());
- debug!("kitty protocol support: {:?}", s);
- return s;
- }
- false
-}
-
fn div_ceil(a: u32, b: u32) -> u32 {
a / b + (0 != a % b) as u32
}
-/// the image renderer, with knowledge of the
-/// console cells dimensions, and built only on Kitty.
-///
+/// The image renderer, with knowledge of the console cells
+/// dimensions, and built only on a compatible terminal
#[derive(Debug)]
pub struct KittyImageRenderer {
cell_width: u32,
@@ -150,7 +99,6 @@ pub struct KittyImageRenderer {
}
/// An image prepared for a precise area on screen
-///
struct KittyImage<'i> {
id: usize,
data: ImageData<'i>,
@@ -176,7 +124,7 @@ impl<'i> KittyImage<'i> {
area,
}
}
- /// render the image by sending multiple kitty escape sequence, each
+ /// Render the image by sending multiple kitty escape sequences, each
/// one with part of the image raw data (encoded as base64)
fn print_with_chunks(
&self,
@@ -207,7 +155,7 @@ impl<'i> KittyImage<'i> {
}
Ok(())
}
- /// render the image by writing the raw data in a temporary file
+ /// Render the image by writing the raw data in a temporary file
/// then giving to kitty the path to this file in the payload of
/// a unique kitty ecape sequence
pub fn print_with_temp_file(
diff --git a/src/kitty/mod.rs b/src/kitty/mod.rs
index 9e98787..adc9e45 100644
--- a/src/kitty/mod.rs
+++ b/src/kitty/mod.rs
@@ -1,3 +1,4 @@
+mod detect_support;
mod image_renderer;
mod image_set;
diff --git a/src/skin/skin_entry.rs b/src/skin/skin_entry.rs
index 5279107..8079f0e 100644
--- a/src/skin/skin_entry.rs
+++ b/src/skin/skin_entry.rs
@@ -1,6 +1,6 @@
-/// Manage conversion of a user provided string
-/// defining foreground and background colors into
-/// a string with TTY colors
+//! Manage conversion of a user provided string
+//! defining foreground and background colors into
+//! a string with TTY colors
use {
super::*,
@@ -14,7 +14,7 @@ use {
termimad::CompoundStyle,
};
-/// parsed content of a [skin] line of the conf.toml file
+/// Parsed content of a [skin] line of the conf.toml file
#[derive(Clone, Debug)]
pub struct SkinEntry {
focused: CompoundStyle,
@@ -31,7 +31,7 @@ impl SkinEntry {
pub fn get_unfocused(&self) -> &CompoundStyle {
self.unfocused.as_ref().unwrap_or(&self.focused)
}
- /// parse a string representation of a skin entry.
+ /// Parse a string representation of a skin entry.
///
/// The general form is either "<focused>" or "<focused> / <unfocused>":
/// It may be just the focused compound_style, or both
@@ -44,7 +44,7 @@ impl SkinEntry {
let mut parts = s.split('/');
let focused = parse_compound_style(parts.next().unwrap())?;
let unfocused = parts.next()
- .map(|p| parse_compound_style(p))
+ .map(parse_compound_style)
.transpose()?;
Ok(Self { focused, unfocused })
}
@@ -60,8 +60,6 @@ impl<'de> Deserialize<'de> for SkinEntry {
}
}
-
-
fn parse_attribute(s: &str) -> Result<Attribute, InvalidSkinError> {
match s {
"bold" => Ok(Bold),
@@ -82,7 +80,7 @@ fn parse_attribute(s: &str) -> Result<Attribute, InvalidSkinError> {
/// parse a sequence of space separated style attributes
fn parse_attributes(s: &str) -> Result<Vec<Attribute>, InvalidSkinError> {
- s.split_whitespace().map(|t| parse_attribute(t)).collect()
+ s.split_whitespace().map(parse_attribute).collect()
}
fn parse_compound_style(s: &str) -> Result<CompoundStyle, InvalidSkinError> {
diff --git a/src/syntactic/syntactic_view.rs b/src/syntactic/syntactic_view.rs
index 2e48c7c..c64bbc2 100644
--- a/src/syntactic/syntactic_view.rs
+++ b/src/syntactic/syntactic_view.rs
@@ -26,7 +26,7 @@ use {
termimad::{Area, CropWriter, SPACE_FILLING},
};
-/// a homogeneously colored piece of a line
+/// Homogeneously colored piece of a line
#[derive(Debug)]
pub struct Region {
pub fg: Color,
@@ -71,7 +71,7 @@ pub struct SyntacticView {
impl SyntacticView {
- /// return a prepared text view with syntax coloring if possible.
+ /// Return a prepared text view with syntax coloring if possible.
/// May return Ok(None) only when a pattern is given and there
/// was an event before the end of filtering.
pub fn new(
@@ -97,7 +97,7 @@ impl SyntacticView {
}
}
- /// return true when there was no interruption
+ /// Return true when there was no interruption
fn read_lines(
&mut self,
dam: &mut Dam,
@@ -150,7 +150,7 @@ impl SyntacticView {
highlighter
.highlight(&line, &SYNTAXER.syntax_set)
.iter()
- .map(|r| Region::from_syntect(r))
+ .map(Region::from_syntect)
.collect()
} else {
Vec::new()
@@ -172,8 +172,8 @@ impl SyntacticView {
Ok(true)
}
- /// (count of lines which can be seen when scrolling,
- /// total count including filtered ones)
+ /// Give the count of lines which can be seen when scrolling,
+ /// total count including filtered ones
pub fn line_counts(&self) -> (usize, usize) {
(self.lines.len(), self.total_lines_count)
}
@@ -451,7 +451,7 @@ fn is_thumb(y: usize, scrollbar: Option<(u16, u16)>) -> bool {
})
}
-/// tell whether the character is normal enough to be displayed by the
+/// Tell whether the character is normal enough to be displayed by the
/// syntactic view (if not we'll use a hex view)
fn is_char_printable(c: char) -> bool {
// the tab is printable because it's replaced by spaces