mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: switch to kitty unicode placeholders for Ghostty image previewing (#1427)
This commit is contained in:
parent
f865910481
commit
5df6873957
9 changed files with 45 additions and 42 deletions
11
.github/ISSUE_TEMPLATE/bug.yml
vendored
11
.github/ISSUE_TEMPLATE/bug.yml
vendored
|
|
@ -29,16 +29,7 @@ body:
|
||||||
attributes:
|
attributes:
|
||||||
label: "`yazi --debug` output"
|
label: "`yazi --debug` output"
|
||||||
description: Please run `yazi --debug` and paste the debug information here.
|
description: Please run `yazi --debug` and paste the debug information here.
|
||||||
value: |
|
render: Shell
|
||||||
<details>
|
|
||||||
|
|
||||||
```sh
|
|
||||||
##### ↓↓↓ Paste the output here: ↓↓↓ #####
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
|
|
|
||||||
11
.github/ISSUE_TEMPLATE/feature.yml
vendored
11
.github/ISSUE_TEMPLATE/feature.yml
vendored
|
|
@ -8,16 +8,7 @@ body:
|
||||||
attributes:
|
attributes:
|
||||||
label: "`yazi --debug` output"
|
label: "`yazi --debug` output"
|
||||||
description: Please run `yazi --debug` and paste the debug information here.
|
description: Please run `yazi --debug` and paste the debug information here.
|
||||||
value: |
|
render: Shell
|
||||||
<details>
|
|
||||||
|
|
||||||
```sh
|
|
||||||
##### ↓↓↓ Paste the output here: ↓↓↓ #####
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ https://github.com/sxyazi/yazi/assets/17523360/92ff23fa-0cd5-4f04-b387-894c12265
|
||||||
| WezTerm | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
| WezTerm | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||||
| Mintty (Git Bash) | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
| Mintty (Git Bash) | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||||
| foot | [Sixel graphics format](https://www.vt100.net/docs/vt3xx-gp/chapter14.html) | ✅ Built-in |
|
| foot | [Sixel graphics format](https://www.vt100.net/docs/vt3xx-gp/chapter14.html) | ✅ Built-in |
|
||||||
| Ghostty | [Kitty old protocol](https://github.com/sxyazi/yazi/blob/main/yazi-adapter/src/kitty_old.rs) | ✅ Built-in |
|
| Ghostty | [Kitty unicode placeholders](https://sw.kovidgoyal.net/kitty/graphics-protocol/#unicode-placeholders) | ✅ Built-in |
|
||||||
| Black Box | [Sixel graphics format](https://www.vt100.net/docs/vt3xx-gp/chapter14.html) | ✅ Built-in |
|
| Black Box | [Sixel graphics format](https://www.vt100.net/docs/vt3xx-gp/chapter14.html) | ✅ Built-in |
|
||||||
| VSCode | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
| VSCode | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||||
| Tabby | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
| Tabby | [Inline images protocol](https://iterm2.com/documentation-images.html) | ✅ Built-in |
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,8 @@ impl Adapter {
|
||||||
pub fn image_erase(self, area: Rect) -> Result<()> {
|
pub fn image_erase(self, area: Rect) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Self::Kitty => Kitty::image_erase(area),
|
Self::Kitty => Kitty::image_erase(area),
|
||||||
Self::Iterm2 => Iterm2::image_erase(area),
|
|
||||||
Self::KittyOld => KittyOld::image_erase(area),
|
Self::KittyOld => KittyOld::image_erase(area),
|
||||||
|
Self::Iterm2 => Iterm2::image_erase(area),
|
||||||
Self::Sixel => Sixel::image_erase(area),
|
Self::Sixel => Sixel::image_erase(area),
|
||||||
Self::X11 | Self::Wayland => Ueberzug::image_erase(area),
|
Self::X11 | Self::Wayland => Ueberzug::image_erase(area),
|
||||||
Self::Chafa => Chafa::image_erase(area),
|
Self::Chafa => Chafa::image_erase(area),
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ impl Emulator {
|
||||||
Self::Iterm2 => vec![Adapter::Iterm2, Adapter::Sixel],
|
Self::Iterm2 => vec![Adapter::Iterm2, Adapter::Sixel],
|
||||||
Self::WezTerm => vec![Adapter::Iterm2, Adapter::Sixel],
|
Self::WezTerm => vec![Adapter::Iterm2, Adapter::Sixel],
|
||||||
Self::Foot => vec![Adapter::Sixel],
|
Self::Foot => vec![Adapter::Sixel],
|
||||||
Self::Ghostty => vec![Adapter::KittyOld],
|
Self::Ghostty => vec![Adapter::Kitty],
|
||||||
Self::BlackBox => vec![Adapter::Sixel],
|
Self::BlackBox => vec![Adapter::Sixel],
|
||||||
Self::VSCode => vec![Adapter::Iterm2, Adapter::Sixel],
|
Self::VSCode => vec![Adapter::Iterm2, Adapter::Sixel],
|
||||||
Self::Tabby => vec![Adapter::Iterm2, Adapter::Sixel],
|
Self::Tabby => vec![Adapter::Iterm2, Adapter::Sixel],
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{path::PathBuf, str::FromStr, time::{SystemTime, UNIX_EPOCH}};
|
use std::{borrow::Cow, path::PathBuf, str::FromStr, time::{SystemTime, UNIX_EPOCH}};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -29,6 +29,22 @@ impl Preview {
|
||||||
let time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards");
|
let time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards");
|
||||||
self.cache_dir.join(format!("{prefix}-{}", time.as_nanos() / 1000))
|
self.cache_dir.join(format!("{prefix}-{}", time.as_nanos() / 1000))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn indent(&self) -> Cow<'static, str> {
|
||||||
|
match self.tab_size {
|
||||||
|
0 => Cow::Borrowed(""),
|
||||||
|
1 => Cow::Borrowed(" "),
|
||||||
|
2 => Cow::Borrowed(" "),
|
||||||
|
3 => Cow::Borrowed(" "),
|
||||||
|
4 => Cow::Borrowed(" "),
|
||||||
|
5 => Cow::Borrowed(" "),
|
||||||
|
6 => Cow::Borrowed(" "),
|
||||||
|
7 => Cow::Borrowed(" "),
|
||||||
|
8 => Cow::Borrowed(" "),
|
||||||
|
n => Cow::Owned(" ".repeat(n as usize)),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Preview {
|
impl FromStr for Preview {
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ impl<'a> Input<'a> {
|
||||||
if let Some(syntax) = syntaxes.find_syntax_by_name("Bourne Again Shell (bash)") {
|
if let Some(syntax) = syntaxes.find_syntax_by_name("Bourne Again Shell (bash)") {
|
||||||
let mut h = HighlightLines::new(syntax, theme);
|
let mut h = HighlightLines::new(syntax, theme);
|
||||||
let regions = h.highlight_line(self.cx.input.value(), syntaxes)?;
|
let regions = h.highlight_line(self.cx.input.value(), syntaxes)?;
|
||||||
return Ok(Highlighter::to_line_widget(regions, &" ".repeat(PREVIEW.tab_size as usize)));
|
return Ok(Highlighter::to_line_widget(regions, &PREVIEW.indent()));
|
||||||
}
|
}
|
||||||
bail!("Failed to find syntax")
|
bail!("Failed to find syntax")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,15 +34,13 @@ function Status:style()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Status:mode()
|
function Status:mode()
|
||||||
local mode = tostring(self._tab.mode):upper()
|
local mode = tostring(self._tab.mode):sub(1, 3):upper()
|
||||||
if mode == "UNSET" then
|
|
||||||
mode = "UN-SET"
|
|
||||||
end
|
|
||||||
|
|
||||||
local style = self:style()
|
local style = self:style()
|
||||||
return ui.Line {
|
return ui.Line {
|
||||||
ui.Span(THEME.status.separator_open):fg(style.bg),
|
ui.Span(THEME.status.separator_open):fg(style.bg),
|
||||||
ui.Span(" " .. mode .. " "):style(style),
|
ui.Span(" " .. mode .. " "):style(style),
|
||||||
|
ui.Span(THEME.status.separator_close):fg(style.bg):bg(THEME.status.separator_style.fg),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -106,11 +104,11 @@ function Status:percentage()
|
||||||
end
|
end
|
||||||
|
|
||||||
if percent == 0 then
|
if percent == 0 then
|
||||||
percent = " Top "
|
percent = " Top "
|
||||||
elseif percent == 100 then
|
elseif percent == 100 then
|
||||||
percent = " Bot "
|
percent = " Bot "
|
||||||
else
|
else
|
||||||
percent = string.format(" %3d%% ", percent)
|
percent = string.format(" %2d%% ", percent)
|
||||||
end
|
end
|
||||||
|
|
||||||
local style = self:style()
|
local style = self:style()
|
||||||
|
|
@ -126,6 +124,7 @@ function Status:position()
|
||||||
|
|
||||||
local style = self:style()
|
local style = self:style()
|
||||||
return ui.Line {
|
return ui.Line {
|
||||||
|
ui.Span(THEME.status.separator_open):fg(style.bg):bg(THEME.status.separator_style.fg),
|
||||||
ui.Span(string.format(" %2d/%-2d ", cursor + 1, length)):style(style),
|
ui.Span(string.format(" %2d/%-2d ", cursor + 1, length)):style(style),
|
||||||
ui.Span(THEME.status.separator_close):fg(style.bg),
|
ui.Span(THEME.status.separator_close):fg(style.bg),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
26
yazi-plugin/src/external/highlighter.rs
vendored
26
yazi-plugin/src/external/highlighter.rs
vendored
|
|
@ -60,9 +60,9 @@ impl Highlighter {
|
||||||
let mut reader = BufReader::new(File::open(&self.path).await?);
|
let mut reader = BufReader::new(File::open(&self.path).await?);
|
||||||
|
|
||||||
let syntax = Self::find_syntax(&self.path).await;
|
let syntax = Self::find_syntax(&self.path).await;
|
||||||
let mut plain = syntax.is_err();
|
let mut plain = syntax.is_err() as u8;
|
||||||
|
|
||||||
let mut before = Vec::with_capacity(if plain { 0 } else { skip });
|
let mut before = Vec::with_capacity(if plain == 0 { skip } else { 0 });
|
||||||
let mut after = Vec::with_capacity(limit);
|
let mut after = Vec::with_capacity(limit);
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
@ -73,8 +73,11 @@ impl Highlighter {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !plain && (buf.len() > 5000 || buf.contains(&0x1b)) {
|
if plain == 0 && buf.len() > 5000 {
|
||||||
plain = true;
|
plain = 1;
|
||||||
|
drop(mem::take(&mut before));
|
||||||
|
} else if plain == 0 && buf.contains(&0x1b) {
|
||||||
|
plain = 2;
|
||||||
drop(mem::take(&mut before));
|
drop(mem::take(&mut before));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,7 +89,7 @@ impl Highlighter {
|
||||||
|
|
||||||
if i > skip {
|
if i > skip {
|
||||||
after.push(String::from_utf8_lossy(&buf).into_owned());
|
after.push(String::from_utf8_lossy(&buf).into_owned());
|
||||||
} else if !plain {
|
} else if plain == 0 {
|
||||||
before.push(String::from_utf8_lossy(&buf).into_owned());
|
before.push(String::from_utf8_lossy(&buf).into_owned());
|
||||||
}
|
}
|
||||||
buf.clear();
|
buf.clear();
|
||||||
|
|
@ -96,11 +99,14 @@ impl Highlighter {
|
||||||
return Err(PeekError::Exceed(i.saturating_sub(limit)));
|
return Err(PeekError::Exceed(i.saturating_sub(limit)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if plain {
|
if plain == 0 {
|
||||||
let indent = " ".repeat(PREVIEW.tab_size as usize);
|
|
||||||
Ok(Text::from(after.join("").replace('\x1b', "^[").replace('\t', &indent)))
|
|
||||||
} else {
|
|
||||||
Self::highlight_with(before, after, syntax.unwrap()).await
|
Self::highlight_with(before, after, syntax.unwrap()).await
|
||||||
|
} else if plain == 1 {
|
||||||
|
Ok(Text::from(after.join("").replace('\t', &PREVIEW.indent())))
|
||||||
|
} else if plain == 2 {
|
||||||
|
Ok(Text::from(after.join("").replace('\x1b', "^[").replace('\t', &PREVIEW.indent())))
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,7 +127,7 @@ impl Highlighter {
|
||||||
h.highlight_line(&line, syntaxes).map_err(|e| anyhow!(e))?;
|
h.highlight_line(&line, syntaxes).map_err(|e| anyhow!(e))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let indent = " ".repeat(PREVIEW.tab_size as usize);
|
let indent = PREVIEW.indent();
|
||||||
let mut lines = Vec::with_capacity(after.len());
|
let mut lines = Vec::with_capacity(after.len());
|
||||||
for line in after {
|
for line in after {
|
||||||
if ticket != INCR.load(Ordering::Relaxed) {
|
if ticket != INCR.load(Ordering::Relaxed) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue