aboutsummaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/term/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty_terminal/src/term/mod.rs')
-rw-r--r--alacritty_terminal/src/term/mod.rs110
1 files changed, 110 insertions, 0 deletions
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs
index 1808f3aa..1e87ec8a 100644
--- a/alacritty_terminal/src/term/mod.rs
+++ b/alacritty_terminal/src/term/mod.rs
@@ -1,6 +1,7 @@
//! Exports the `Term` type which is a high-level API for the Grid.
use std::cmp::{max, min};
+use std::fmt::Write;
use std::ops::{Index, IndexMut, Range};
use std::sync::Arc;
use std::{mem, ptr, str};
@@ -9,12 +10,16 @@ use bitflags::bitflags;
use log::{debug, trace};
use serde::{Deserialize, Serialize};
use unicode_width::UnicodeWidthChar;
+use vte::Params;
use crate::ansi::{
self, Attr, CharsetIndex, Color, CursorShape, CursorStyle, Handler, NamedColor, StandardCharset,
};
use crate::config::Config;
use crate::event::{Event, EventListener};
+use crate::graphics::{
+ sixel, GraphicCell, GraphicData, Graphics, TextureRef, UpdateQueues, MAX_GRAPHIC_DIMENSIONS,
+};
use crate::grid::{Dimensions, Grid, GridIterator, Scroll};
use crate::index::{self, Boundary, Column, Direction, Line, Point, Side};
use crate::selection::{Selection, SelectionRange};
@@ -62,6 +67,8 @@ bitflags! {
const ALTERNATE_SCROLL = 0b0000_1000_0000_0000_0000;
const VI = 0b0001_0000_0000_0000_0000;
const URGENCY_HINTS = 0b0010_0000_0000_0000_0000;
+ const SIXEL_SCROLLING = 0b0100_0000_0000_0000_0000;
+ const SIXEL_PRIV_PALETTE = 0b1000_0000_0000_0000_0000;
const ANY = std::u32::MAX;
}
}
@@ -72,6 +79,8 @@ impl Default for TermMode {
| TermMode::LINE_WRAP
| TermMode::ALTERNATE_SCROLL
| TermMode::URGENCY_HINTS
+ | TermMode::SIXEL_SCROLLING
+ | TermMode::SIXEL_PRIV_PALETTE
}
}
@@ -269,6 +278,9 @@ pub struct Term<T> {
/// Information about cell dimensions.
cell_width: usize,
cell_height: usize,
+
+ /// Data to add graphics to a grid.
+ graphics: Graphics,
}
impl<T> Term<T> {
@@ -320,6 +332,7 @@ impl<T> Term<T> {
selection: None,
cell_width: size.cell_width as usize,
cell_height: size.cell_height as usize,
+ graphics: Graphics::default(),
}
}
@@ -470,6 +483,12 @@ impl<T> Term<T> {
&mut self.grid
}
+ /// Get queues to update graphic data. If both queues are empty, it returns
+ /// `None`.
+ pub fn graphics_take_queues(&mut self) -> Option<UpdateQueues> {
+ self.graphics.take_queues()
+ }
+
/// Resize terminal to new dimensions.
pub fn resize(&mut self, size: SizeInfo) {
self.cell_width = size.cell_width as usize;
@@ -1578,6 +1597,10 @@ impl<T: EventListener> Handler for Term<T> {
style.blinking = true;
self.event_proxy.send_event(Event::CursorBlinkingChange(true));
},
+ ansi::Mode::SixelScrolling => self.mode.insert(TermMode::SIXEL_SCROLLING),
+ ansi::Mode::SixelPrivateColorRegisters => {
+ self.mode.insert(TermMode::SIXEL_PRIV_PALETTE)
+ },
}
}
@@ -1620,6 +1643,11 @@ impl<T: EventListener> Handler for Term<T> {
style.blinking = false;
self.event_proxy.send_event(Event::CursorBlinkingChange(false));
},
+ ansi::Mode::SixelScrolling => self.mode.remove(TermMode::SIXEL_SCROLLING),
+ ansi::Mode::SixelPrivateColorRegisters => {
+ self.graphics.sixel_shared_palette = None;
+ self.mode.remove(TermMode::SIXEL_PRIV_PALETTE);
+ },
}
}
@@ -1742,6 +1770,88 @@ impl<T: EventListener> Handler for Term<T> {
let text = format!("\x1b[8;{};{}t", self.screen_lines(), self.columns());
self.event_proxy.send_event(Event::PtyWrite(text));
}
+
+ fn start_sixel_graphic(&mut self, params: &Params) -> Option<Box<sixel::Parser>> {
+ let palette = self.graphics.sixel_shared_palette.take();
+ Some(Box::new(sixel::Parser::new(params, palette)))
+ }
+
+ fn insert_graphic(&mut self, graphic: GraphicData, palette: Option<Vec<Rgb>>) {
+ // Store last palette if we receive a new one, and it is shared.
+ if let Some(palette) = palette {
+ if !self.mode.contains(TermMode::SIXEL_PRIV_PALETTE) {
+ self.graphics.sixel_shared_palette = Some(palette);
+ }
+ }
+
+ if graphic.width > MAX_GRAPHIC_DIMENSIONS.0 || graphic.height > MAX_GRAPHIC_DIMENSIONS.1 {
+ return;
+ }
+
+ let width = graphic.width as u16;
+ let height = graphic.height as u16;
+
+ if width == 0 || height == 0 {
+ return;
+ }
+
+ // Add the graphic data to the pending queue.
+ let graphic_id = self.graphics.next_id();
+ self.graphics.pending.push(GraphicData { id: graphic_id, ..graphic });
+
+ // If SIXEL_SCROLLING is enabled, the start of the graphic is the
+ // cursor position, and the grid can be scrolled if the graphic is
+ // larger than the screen. The cursor is moved to the next line
+ // after the graphic.
+ //
+ // If it is disabled, the graphic starts at (0, 0), the grid is never
+ // scrolled, and the cursor position is unmodified.
+
+ let scrolling = self.mode.contains(TermMode::SIXEL_SCROLLING);
+
+ // Fill the cells under the graphic.
+ //
+ // The cell in the first column contains a reference to the graphic,
+ // with the offset from the start. Rest of the cells are empty.
+
+ let left = if scrolling { self.grid.cursor.point.column.0 } else { 0 };
+
+ let texture = Arc::new(TextureRef {
+ id: graphic_id,
+ remove_queue: Arc::downgrade(&self.graphics.remove_queue),
+ });
+
+ for (top, offset_y) in (0..).zip((0..height).step_by(self.cell_height)) {
+ let line = if scrolling {
+ self.grid.cursor.point.line
+ } else {
+ // Check if the image is beyond the screen limit.
+ if top >= self.screen_lines().0 {
+ break;
+ }
+
+ Line(top)
+ };
+
+ // Store a reference to the graphic in the first column.
+ let graphic_cell = GraphicCell { texture: texture.clone(), offset_x: 0, offset_y };
+ let mut cell = Cell::default();
+ cell.set_graphic(graphic_cell);
+ self.grid[line][Column(left)] = cell;
+
+ for col in left + 1..self.cols().0 {
+ self.grid[line][Column(col)] = Cell::default();
+ }
+
+ if scrolling {
+ self.linefeed();
+ }
+ }
+
+ if scrolling {
+ self.carriage_return();
+ }
+ }
}
/// Terminal version for escape sequence reports.