feat(terminal): multiline hyperlink support (#4264)
* working * done * docs(changelog): add PR
This commit is contained in:
parent
ed1f067f59
commit
2580564d50
5 changed files with 1384 additions and 2 deletions
|
|
@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
|||
* performance: consolidate renders (https://github.com/zellij-org/zellij/pull/4245)
|
||||
* feat: add plugin API to replace a pane with another existing pane (https://github.com/zellij-org/zellij/pull/4246)
|
||||
* feat: add "stack" keybinding and CLI action to add a stacked pane to the current pane (https://github.com/zellij-org/zellij/pull/4255)
|
||||
* fix: support multiline hyperlinks (https://github.com/zellij-org/zellij/pull/4264)
|
||||
|
||||
## [0.42.2] - 2025-04-15
|
||||
* refactor(terminal): track scroll_region as tuple rather than Option (https://github.com/zellij-org/zellij/pull/4082)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ use zellij_utils::{consts::VERSION, shared::version_number};
|
|||
|
||||
use crate::output::{CharacterChunk, OutputBuffer, SixelImageChunk};
|
||||
use crate::panes::alacritty_functions::{parse_number, xparse_color};
|
||||
use crate::panes::hyperlink_tracker::HyperlinkTracker;
|
||||
use crate::panes::link_handler::LinkHandler;
|
||||
use crate::panes::search::SearchResult;
|
||||
use crate::panes::selection::Selection;
|
||||
|
|
@ -363,6 +364,7 @@ pub struct Grid {
|
|||
explicitly_disable_kitty_keyboard_protocol: bool, // has kitty keyboard support been explicitly
|
||||
// disabled by user config?
|
||||
click: Click,
|
||||
hyperlink_tracker: HyperlinkTracker,
|
||||
}
|
||||
|
||||
const CLICK_TIME_THRESHOLD: u128 = 400; // Doherty Threshold
|
||||
|
|
@ -550,6 +552,7 @@ impl Grid {
|
|||
supports_kitty_keyboard_protocol: false,
|
||||
explicitly_disable_kitty_keyboard_protocol,
|
||||
click: Click::default(),
|
||||
hyperlink_tracker: HyperlinkTracker::new(),
|
||||
}
|
||||
}
|
||||
pub fn render_full_viewport(&mut self) {
|
||||
|
|
@ -1294,6 +1297,13 @@ impl Grid {
|
|||
}
|
||||
pub fn add_canonical_line(&mut self) {
|
||||
let (scroll_region_top, scroll_region_bottom) = self.scroll_region;
|
||||
self.hyperlink_tracker.update(
|
||||
'\n',
|
||||
&self.cursor,
|
||||
&mut self.viewport,
|
||||
&mut self.lines_above,
|
||||
&mut self.link_handler.borrow_mut(),
|
||||
);
|
||||
if self.cursor.y == scroll_region_bottom {
|
||||
// end of scroll region
|
||||
// when we have a scroll region set and we're at its bottom
|
||||
|
|
@ -1348,6 +1358,13 @@ impl Grid {
|
|||
terminal_character: TerminalCharacter,
|
||||
should_insert_character: bool,
|
||||
) {
|
||||
self.hyperlink_tracker.update(
|
||||
terminal_character.character,
|
||||
&self.cursor,
|
||||
&mut self.viewport,
|
||||
&mut self.lines_above,
|
||||
&mut self.link_handler.borrow_mut(),
|
||||
);
|
||||
// this function assumes the current line has enough room for terminal_character (that its
|
||||
// width has been checked beforehand)
|
||||
match self.viewport.get_mut(self.cursor.y) {
|
||||
|
|
@ -1477,6 +1494,7 @@ impl Grid {
|
|||
if self.cursor.y == self.height.saturating_sub(1) {
|
||||
if self.alternate_screen_state.is_none() {
|
||||
self.transfer_rows_to_lines_above(1);
|
||||
self.hyperlink_tracker.offset_cursor_lines(1);
|
||||
} else {
|
||||
self.viewport.remove(0);
|
||||
}
|
||||
|
|
|
|||
1344
zellij-server/src/panes/hyperlink_tracker.rs
Normal file
1344
zellij-server/src/panes/hyperlink_tracker.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -11,8 +11,8 @@ pub struct LinkHandler {
|
|||
}
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Link {
|
||||
id: Option<String>,
|
||||
uri: String,
|
||||
pub id: Option<String>,
|
||||
pub uri: String,
|
||||
}
|
||||
|
||||
impl LinkHandler {
|
||||
|
|
@ -49,6 +49,19 @@ impl LinkHandler {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_link_from_url(&mut self, url: String) -> LinkAnchor {
|
||||
let anchor = LinkAnchor::Start(self.link_index);
|
||||
self.links.insert(
|
||||
self.link_index,
|
||||
Link {
|
||||
id: Some(self.link_index.to_string()),
|
||||
uri: url,
|
||||
},
|
||||
);
|
||||
self.link_index += 1;
|
||||
anchor
|
||||
}
|
||||
|
||||
pub fn output_osc8(&self, link_anchor: Option<LinkAnchor>) -> Option<String> {
|
||||
link_anchor.and_then(|link| match link {
|
||||
LinkAnchor::Start(index) => {
|
||||
|
|
@ -74,6 +87,11 @@ impl LinkHandler {
|
|||
LinkAnchor::End => Some(format!("\u{1b}]8;;{}", TERMINATOR)),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn links(&self) -> HashMap<u16, Link> {
|
||||
self.links.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LinkHandler {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
pub mod alacritty_functions;
|
||||
pub mod grid;
|
||||
pub mod hyperlink_tracker;
|
||||
pub mod link_handler;
|
||||
pub mod selection;
|
||||
pub mod sixel;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue