ScreenSet
parent
368f4f565a
commit
3aff5f0aff
|
|
@ -186,7 +186,7 @@ const Mouse = struct {
|
|||
/// The point at which the left mouse click happened. This is in screen
|
||||
/// coordinates so that scrolling preserves the location.
|
||||
left_click_pin: ?*terminal.Pin = null,
|
||||
left_click_screen: terminal.ScreenType = .primary,
|
||||
left_click_screen: terminal.ScreenSet.Key = .primary,
|
||||
|
||||
/// The starting xpos/ypos of the left click. Note that if scrolling occurs,
|
||||
/// these will point to different "cells", but the xpos/ypos will stay
|
||||
|
|
@ -1065,7 +1065,7 @@ fn selectionScrollTick(self: *Surface) !void {
|
|||
|
||||
// If our screen changed while this is happening, we stop our
|
||||
// selection scroll.
|
||||
if (self.mouse.left_click_screen != t.active_screen) {
|
||||
if (self.mouse.left_click_screen != t.screens.active_key) {
|
||||
self.io.queueMessage(
|
||||
.{ .selection_scroll = false },
|
||||
.locked,
|
||||
|
|
@ -1703,7 +1703,7 @@ pub fn dumpTextLocked(
|
|||
// If our bottom right pin is before the viewport, then we can't
|
||||
// possibly have this text be within the viewport.
|
||||
const vp_tl_pin = self.io.terminal.screen.pages.getTopLeft(.viewport);
|
||||
const br_pin = sel.bottomRight(&self.io.terminal.screen);
|
||||
const br_pin = sel.bottomRight(self.io.terminal.screen);
|
||||
if (br_pin.before(vp_tl_pin)) break :viewport null;
|
||||
|
||||
// If our top-left pin is after the viewport, then we can't possibly
|
||||
|
|
@ -1714,7 +1714,7 @@ pub fn dumpTextLocked(
|
|||
log.warn("viewport bottom-right pin not found, bug?", .{});
|
||||
break :viewport null;
|
||||
};
|
||||
const tl_pin = sel.topLeft(&self.io.terminal.screen);
|
||||
const tl_pin = sel.topLeft(self.io.terminal.screen);
|
||||
if (vp_br_pin.before(tl_pin)) break :viewport null;
|
||||
|
||||
// We established that our top-left somewhere before the viewport
|
||||
|
|
@ -1984,7 +1984,7 @@ fn copySelectionToClipboards(
|
|||
var contents: std.ArrayList(apprt.ClipboardContent) = .empty;
|
||||
switch (format) {
|
||||
.plain => {
|
||||
var formatter: ScreenFormatter = .init(&self.io.terminal.screen, opts);
|
||||
var formatter: ScreenFormatter = .init(self.io.terminal.screen, opts);
|
||||
formatter.content = .{ .selection = sel };
|
||||
try formatter.format(&aw.writer);
|
||||
try contents.append(alloc, .{
|
||||
|
|
@ -1994,7 +1994,7 @@ fn copySelectionToClipboards(
|
|||
},
|
||||
|
||||
.vt => {
|
||||
var formatter: ScreenFormatter = .init(&self.io.terminal.screen, opts: {
|
||||
var formatter: ScreenFormatter = .init(self.io.terminal.screen, opts: {
|
||||
var copy = opts;
|
||||
copy.emit = .vt;
|
||||
break :opts copy;
|
||||
|
|
@ -2011,7 +2011,7 @@ fn copySelectionToClipboards(
|
|||
},
|
||||
|
||||
.html => {
|
||||
var formatter: ScreenFormatter = .init(&self.io.terminal.screen, opts: {
|
||||
var formatter: ScreenFormatter = .init(self.io.terminal.screen, opts: {
|
||||
var copy = opts;
|
||||
copy.emit = .html;
|
||||
break :opts copy;
|
||||
|
|
@ -2029,7 +2029,7 @@ fn copySelectionToClipboards(
|
|||
|
||||
.mixed => {
|
||||
// First, generate plain text with codepoint mappings applied
|
||||
var formatter: ScreenFormatter = .init(&self.io.terminal.screen, opts);
|
||||
var formatter: ScreenFormatter = .init(self.io.terminal.screen, opts);
|
||||
formatter.content = .{ .selection = sel };
|
||||
try formatter.format(&aw.writer);
|
||||
try contents.append(alloc, .{
|
||||
|
|
@ -2039,7 +2039,7 @@ fn copySelectionToClipboards(
|
|||
|
||||
assert(aw.written().len == 0);
|
||||
// Second, generate HTML without codepoint mappings
|
||||
formatter = .init(&self.io.terminal.screen, opts: {
|
||||
formatter = .init(self.io.terminal.screen, opts: {
|
||||
var copy = opts;
|
||||
copy.emit = .html;
|
||||
|
||||
|
|
@ -3098,7 +3098,7 @@ pub fn scrollCallback(
|
|||
// we convert to cursor keys. This only happens if we're:
|
||||
// (1) alt screen (2) no explicit mouse reporting and (3) alt
|
||||
// scroll mode enabled.
|
||||
if (self.io.terminal.active_screen == .alternate and
|
||||
if (self.io.terminal.screens.active_key == .alternate and
|
||||
self.io.terminal.flags.mouse_event == .none and
|
||||
self.io.terminal.modes.get(.mouse_alternate_scroll))
|
||||
{
|
||||
|
|
@ -3506,7 +3506,7 @@ pub fn mouseButtonCallback(
|
|||
{
|
||||
const pos = try self.rt_surface.getCursorPos();
|
||||
const point = self.posToViewport(pos.x, pos.y);
|
||||
const screen = &self.renderer_state.terminal.screen;
|
||||
const screen: *terminal.Screen = self.renderer_state.terminal.screen;
|
||||
const p = screen.pages.pin(.{ .viewport = point }) orelse {
|
||||
log.warn("failed to get pin for clicked point", .{});
|
||||
return false;
|
||||
|
|
@ -3681,7 +3681,7 @@ pub fn mouseButtonCallback(
|
|||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
const t: *terminal.Terminal = self.renderer_state.terminal;
|
||||
const screen = &self.renderer_state.terminal.screen;
|
||||
const screen: *terminal.Screen = self.renderer_state.terminal.screen;
|
||||
|
||||
const pos = try self.rt_surface.getCursorPos();
|
||||
const pin = pin: {
|
||||
|
|
@ -3717,14 +3717,15 @@ pub fn mouseButtonCallback(
|
|||
}
|
||||
|
||||
if (self.mouse.left_click_pin) |prev| {
|
||||
const pin_screen = t.getScreen(self.mouse.left_click_screen);
|
||||
pin_screen.pages.untrackPin(prev);
|
||||
if (t.screens.get(self.mouse.left_click_screen)) |pin_screen| {
|
||||
pin_screen.pages.untrackPin(prev);
|
||||
}
|
||||
self.mouse.left_click_pin = null;
|
||||
}
|
||||
|
||||
// Store it
|
||||
self.mouse.left_click_pin = pin;
|
||||
self.mouse.left_click_screen = t.active_screen;
|
||||
self.mouse.left_click_screen = t.screens.active_key;
|
||||
self.mouse.left_click_xpos = pos.x;
|
||||
self.mouse.left_click_ypos = pos.y;
|
||||
|
||||
|
|
@ -3808,7 +3809,7 @@ pub fn mouseButtonCallback(
|
|||
defer self.renderer_state.mutex.unlock();
|
||||
|
||||
// Get our viewport pin
|
||||
const screen = &self.renderer_state.terminal.screen;
|
||||
const screen: *terminal.Screen = self.renderer_state.terminal.screen;
|
||||
const pin = pin: {
|
||||
const pos = try self.rt_surface.getCursorPos();
|
||||
const pt_viewport = self.posToViewport(pos.x, pos.y);
|
||||
|
|
@ -3911,7 +3912,7 @@ fn clickMoveCursor(self: *Surface, to: terminal.Pin) !void {
|
|||
// Click to move cursor only works on the primary screen where prompts
|
||||
// exist. This means that alt screen multiplexers like tmux will not
|
||||
// support this feature. It is just too messy.
|
||||
if (t.active_screen != .primary) return;
|
||||
if (t.screens.active_key != .primary) return;
|
||||
|
||||
// This flag is only set if we've seen at least one semantic prompt
|
||||
// OSC sequence. If we've never seen that sequence, we can't possibly
|
||||
|
|
@ -3964,7 +3965,7 @@ fn linkAtPos(
|
|||
terminal.Selection,
|
||||
} {
|
||||
// Convert our cursor position to a screen point.
|
||||
const screen = &self.renderer_state.terminal.screen;
|
||||
const screen: *terminal.Screen = self.renderer_state.terminal.screen;
|
||||
const mouse_pin: terminal.Pin = mouse_pin: {
|
||||
const point = self.posToViewport(pos.x, pos.y);
|
||||
const pin = screen.pages.pin(.{ .viewport = point }) orelse {
|
||||
|
|
@ -4237,7 +4238,7 @@ pub fn cursorPosCallback(
|
|||
insp.mouse.last_xpos = pos.x;
|
||||
insp.mouse.last_ypos = pos.y;
|
||||
|
||||
const screen = &self.renderer_state.terminal.screen;
|
||||
const screen: *terminal.Screen = self.renderer_state.terminal.screen;
|
||||
insp.mouse.last_point = screen.pages.pin(.{ .viewport = .{
|
||||
.x = pos_vp.x,
|
||||
.y = pos_vp.y,
|
||||
|
|
@ -4303,7 +4304,7 @@ pub fn cursorPosCallback(
|
|||
// invalidate our pin or mouse state because if the screen switches
|
||||
// back then we can continue our selection.
|
||||
const t: *terminal.Terminal = self.renderer_state.terminal;
|
||||
if (self.mouse.left_click_screen != t.active_screen) break :select;
|
||||
if (self.mouse.left_click_screen != t.screens.active_key) break :select;
|
||||
|
||||
// All roads lead to requiring a re-render at this point.
|
||||
try self.queueRender();
|
||||
|
|
@ -4328,7 +4329,7 @@ pub fn cursorPosCallback(
|
|||
}
|
||||
|
||||
// Convert to points
|
||||
const screen = &t.screen;
|
||||
const screen: *terminal.Screen = t.screen;
|
||||
const pin = screen.pages.pin(.{
|
||||
.viewport = .{
|
||||
.x = pos_vp.x,
|
||||
|
|
@ -4357,7 +4358,7 @@ fn dragLeftClickDouble(
|
|||
self: *Surface,
|
||||
drag_pin: terminal.Pin,
|
||||
) !void {
|
||||
const screen = &self.io.terminal.screen;
|
||||
const screen: *terminal.Screen = self.io.terminal.screen;
|
||||
const click_pin = self.mouse.left_click_pin.?.*;
|
||||
|
||||
// Get the word closest to our starting click.
|
||||
|
|
@ -4397,7 +4398,7 @@ fn dragLeftClickTriple(
|
|||
self: *Surface,
|
||||
drag_pin: terminal.Pin,
|
||||
) !void {
|
||||
const screen = &self.io.terminal.screen;
|
||||
const screen: *terminal.Screen = self.io.terminal.screen;
|
||||
const click_pin = self.mouse.left_click_pin.?.*;
|
||||
|
||||
// Get the line selection under our current drag point. If there isn't a
|
||||
|
|
@ -4930,7 +4931,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
|||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
if (self.io.terminal.active_screen == .alternate) return false;
|
||||
if (self.io.terminal.screens.active_key == .alternate) return false;
|
||||
}
|
||||
|
||||
self.io.queueMessage(.{
|
||||
|
|
@ -4966,7 +4967,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
|||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
const sel = self.io.terminal.screen.selection orelse return false;
|
||||
const tl = sel.topLeft(&self.io.terminal.screen);
|
||||
const tl = sel.topLeft(self.io.terminal.screen);
|
||||
self.io.terminal.screen.scroll(.{ .pin = tl });
|
||||
}
|
||||
|
||||
|
|
@ -5220,7 +5221,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
|||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
|
||||
const screen = &self.io.terminal.screen;
|
||||
const screen: *terminal.Screen = self.io.terminal.screen;
|
||||
const sel = if (screen.selection) |*sel| sel else {
|
||||
// If we don't have a selection we do not perform this
|
||||
// action, allowing the keybind to fall through to the
|
||||
|
|
@ -5340,7 +5341,7 @@ fn writeScreenFile(
|
|||
.history => history: {
|
||||
// We do not support this for alternate screens
|
||||
// because they don't have scrollback anyways.
|
||||
if (self.io.terminal.active_screen == .alternate) {
|
||||
if (self.io.terminal.screens.active_key == .alternate) {
|
||||
break :history null;
|
||||
}
|
||||
|
||||
|
|
@ -5371,7 +5372,7 @@ fn writeScreenFile(
|
|||
};
|
||||
|
||||
const ScreenFormatter = terminal.formatter.ScreenFormatter;
|
||||
var formatter: ScreenFormatter = .init(&self.io.terminal.screen, .{
|
||||
var formatter: ScreenFormatter = .init(self.io.terminal.screen, .{
|
||||
.emit = switch (write_screen.emit) {
|
||||
.plain => .plain,
|
||||
.vt => .vt,
|
||||
|
|
@ -5384,7 +5385,7 @@ fn writeScreenFile(
|
|||
.palette = &self.io.terminal.colors.palette.current,
|
||||
});
|
||||
formatter.content = .{ .selection = sel.ordered(
|
||||
&self.io.terminal.screen,
|
||||
self.io.terminal.screen,
|
||||
.forward,
|
||||
) };
|
||||
try formatter.format(buf_writer);
|
||||
|
|
|
|||
|
|
@ -1578,7 +1578,7 @@ pub const CAPI = struct {
|
|||
defer surface.core_surface.renderer_state.mutex.unlock();
|
||||
|
||||
const core_sel = sel.core(
|
||||
&surface.core_surface.renderer_state.terminal.screen,
|
||||
surface.core_surface.renderer_state.terminal.screen,
|
||||
) orelse return false;
|
||||
|
||||
return readTextLocked(surface, core_sel, result);
|
||||
|
|
@ -2137,7 +2137,7 @@ pub const CAPI = struct {
|
|||
|
||||
// Get our word selection
|
||||
const sel = sel: {
|
||||
const screen = &surface.renderer_state.terminal.screen;
|
||||
const screen: *terminal.Screen = surface.renderer_state.terminal.screen;
|
||||
const pos = try ptr.getCursorPos();
|
||||
const pt_viewport = surface.posToViewport(pos.x, pos.y);
|
||||
const pin = screen.pages.pin(.{
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ fn renderScreenWindow(self: *Inspector) void {
|
|||
)) return;
|
||||
|
||||
const t = self.surface.renderer_state.terminal;
|
||||
const screen = &t.screen;
|
||||
const screen: *terminal.Screen = t.screen;
|
||||
|
||||
{
|
||||
_ = cimgui.c.igBeginTable(
|
||||
|
|
@ -324,7 +324,7 @@ fn renderScreenWindow(self: *Inspector) void {
|
|||
}
|
||||
{
|
||||
_ = cimgui.c.igTableSetColumnIndex(1);
|
||||
cimgui.c.igText("%s", @tagName(t.active_screen).ptr);
|
||||
cimgui.c.igText("%s", @tagName(t.screens.active_key).ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1066,7 +1066,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||
bg: terminal.color.RGB,
|
||||
fg: terminal.color.RGB,
|
||||
screen: terminal.Screen,
|
||||
screen_type: terminal.ScreenType,
|
||||
screen_type: terminal.ScreenSet.Key,
|
||||
mouse: renderer.State.Mouse,
|
||||
preedit: ?renderer.State.Preedit,
|
||||
cursor_color: ?terminal.color.RGB,
|
||||
|
|
@ -1207,7 +1207,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||
.bg = bg,
|
||||
.fg = fg,
|
||||
.screen = screen_copy,
|
||||
.screen_type = state.terminal.active_screen,
|
||||
.screen_type = state.terminal.screens.active_key,
|
||||
.mouse = state.mouse,
|
||||
.preedit = preedit,
|
||||
.cursor_color = state.terminal.colors.cursor.get(),
|
||||
|
|
@ -2317,7 +2317,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||
self: *Self,
|
||||
wants_rebuild: bool,
|
||||
screen: *terminal.Screen,
|
||||
screen_type: terminal.ScreenType,
|
||||
screen_type: terminal.ScreenSet.Key,
|
||||
mouse: renderer.State.Mouse,
|
||||
preedit: ?renderer.State.Preedit,
|
||||
cursor_style_: ?renderer.CursorStyle,
|
||||
|
|
|
|||
|
|
@ -609,7 +609,7 @@ test "matchset osc8" {
|
|||
// Initialize our terminal
|
||||
var t = try Terminal.init(alloc, .{ .cols = 10, .rows = 10 });
|
||||
defer t.deinit(alloc);
|
||||
const s = &t.screen;
|
||||
const s: *terminal.Screen = t.screen;
|
||||
|
||||
try t.printString("ABC");
|
||||
try t.screen.startHyperlink("http://example.com", null);
|
||||
|
|
@ -624,7 +624,7 @@ test "matchset osc8" {
|
|||
{
|
||||
var match = try set.matchSet(
|
||||
alloc,
|
||||
&t.screen,
|
||||
t.screen,
|
||||
.{ .x = 2, .y = 0 },
|
||||
inputpkg.ctrlOrSuper(.{}),
|
||||
);
|
||||
|
|
@ -635,7 +635,7 @@ test "matchset osc8" {
|
|||
// Match over link
|
||||
var match = try set.matchSet(
|
||||
alloc,
|
||||
&t.screen,
|
||||
t.screen,
|
||||
.{ .x = 3, .y = 0 },
|
||||
inputpkg.ctrlOrSuper(.{}),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -178,8 +178,15 @@ pub const CharsetState = struct {
|
|||
pub const Options = struct {
|
||||
cols: size.CellCountInt,
|
||||
rows: size.CellCountInt,
|
||||
|
||||
/// The maximum size of scrollback in bytes. Zero means unlimited. Any
|
||||
/// other value will be clamped to support a minimum of the active area.
|
||||
max_scrollback: usize = 0,
|
||||
|
||||
/// The total storage limit for Kitty images in bytes for this
|
||||
/// screen. Kitty image storage is per-screen.
|
||||
kitty_image_storage_limit: usize = 320 * 1000 * 1000, // 320MB
|
||||
|
||||
/// A simple, default terminal. If you rely on specific dimensions or
|
||||
/// scrollback (or lack of) then do not use this directly. This is just
|
||||
/// for callers that need some defaults.
|
||||
|
|
@ -215,7 +222,7 @@ pub fn init(
|
|||
errdefer pages.untrackPin(page_pin);
|
||||
const page_rac = page_pin.rowAndCell();
|
||||
|
||||
return .{
|
||||
var result: Screen = .{
|
||||
.alloc = alloc,
|
||||
.pages = pages,
|
||||
.no_scrollback = opts.max_scrollback == 0,
|
||||
|
|
@ -227,6 +234,18 @@ pub fn init(
|
|||
.page_cell = page_rac.cell,
|
||||
},
|
||||
};
|
||||
|
||||
if (comptime build_options.kitty_graphics) {
|
||||
// This can't fail because the storage is always empty at this point
|
||||
// and the only fail-able case is that we have to evict images.
|
||||
result.kitty_images.setLimit(
|
||||
alloc,
|
||||
&result,
|
||||
opts.kitty_image_storage_limit,
|
||||
) catch unreachable;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Screen) void {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
/// A ScreenSet holds multiple terminal screens. This is initially created
|
||||
/// to handle simple primary vs alternate screens, but could be extended
|
||||
/// in the future to handle N screens.
|
||||
///
|
||||
/// One of the goals of this is to allow lazy initialization of screens
|
||||
/// as needed. The primary screen is always initialized, but the alternate
|
||||
/// screen may not be until first used.
|
||||
const ScreenSet = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Screen = @import("Screen.zig");
|
||||
|
||||
/// The possible keys for screens in the screen set.
|
||||
pub const Key = enum(u1) {
|
||||
primary,
|
||||
alternate,
|
||||
};
|
||||
|
||||
/// The key value of the currently active screen. Useful for simple
|
||||
/// comparisons, e.g. "is this screen the primary screen".
|
||||
active_key: Key,
|
||||
|
||||
/// The active screen pointer.
|
||||
active: *Screen,
|
||||
|
||||
/// All screens that are initialized.
|
||||
all: std.EnumMap(Key, *Screen),
|
||||
|
||||
pub fn init(
|
||||
alloc: Allocator,
|
||||
opts: Screen.Options,
|
||||
) !ScreenSet {
|
||||
// We need to initialize our initial primary screen
|
||||
const screen = try alloc.create(Screen);
|
||||
errdefer alloc.destroy(screen);
|
||||
screen.* = try .init(alloc, opts);
|
||||
return .{
|
||||
.active_key = .primary,
|
||||
.active = screen,
|
||||
.all = .init(.{ .primary = screen }),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *ScreenSet, alloc: Allocator) void {
|
||||
// Destroy all initialized screens
|
||||
var it = self.all.iterator();
|
||||
while (it.next()) |entry| {
|
||||
entry.value.*.deinit();
|
||||
alloc.destroy(entry.value.*);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the screen for the given key, if it is initialized.
|
||||
pub fn get(self: *const ScreenSet, key: Key) ?*Screen {
|
||||
return self.all.get(key);
|
||||
}
|
||||
|
||||
/// Get the screen for the given key, initializing it if necessary.
|
||||
pub fn getInit(
|
||||
self: *ScreenSet,
|
||||
alloc: Allocator,
|
||||
key: Key,
|
||||
opts: Screen.Options,
|
||||
) !*Screen {
|
||||
if (self.get(key)) |screen| return screen;
|
||||
const screen = try alloc.create(Screen);
|
||||
errdefer alloc.destroy(screen);
|
||||
screen.* = try .init(alloc, opts);
|
||||
self.all.put(key, screen);
|
||||
return screen;
|
||||
}
|
||||
|
||||
/// Remove a key from the set. The primary screen cannot be removed (asserted).
|
||||
pub fn remove(
|
||||
self: *ScreenSet,
|
||||
alloc: Allocator,
|
||||
key: Key,
|
||||
) void {
|
||||
assert(key != .primary);
|
||||
if (self.all.fetchRemove(key)) |screen| {
|
||||
screen.deinit();
|
||||
alloc.destroy(screen);
|
||||
}
|
||||
}
|
||||
|
||||
/// Switch the active screen to the given key. Requires that the
|
||||
/// screen is initialized.
|
||||
pub fn switchTo(self: *ScreenSet, key: Key) void {
|
||||
self.active_key = key;
|
||||
self.active = self.all.get(key).?;
|
||||
}
|
||||
|
||||
test ScreenSet {
|
||||
const alloc = testing.allocator;
|
||||
var set: ScreenSet = try .init(alloc, .default);
|
||||
defer set.deinit(alloc);
|
||||
try testing.expectEqual(.primary, set.active_key);
|
||||
|
||||
// Initialize a secondary screen
|
||||
_ = try set.getInit(alloc, .alternate, .default);
|
||||
set.switchTo(.alternate);
|
||||
try testing.expectEqual(.alternate, set.active_key);
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@ const size = @import("size.zig");
|
|||
const pagepkg = @import("page.zig");
|
||||
const style = @import("style.zig");
|
||||
const Screen = @import("Screen.zig");
|
||||
const ScreenSet = @import("ScreenSet.zig");
|
||||
const Page = pagepkg.Page;
|
||||
const Cell = pagepkg.Cell;
|
||||
const Row = pagepkg.Row;
|
||||
|
|
@ -38,18 +39,17 @@ const log = std.log.scoped(.terminal);
|
|||
/// Default tabstop interval
|
||||
const TABSTOP_INTERVAL = 8;
|
||||
|
||||
/// Screen type is an enum that tracks whether a screen is primary or alternate.
|
||||
pub const ScreenType = enum(u1) {
|
||||
primary,
|
||||
alternate,
|
||||
};
|
||||
/// The currently active screen. To get the type of screen this is,
|
||||
/// inspect screens.active_key instead.
|
||||
///
|
||||
/// Note: long term I'd like to get rid of this and force everyone
|
||||
/// to go through screens instead but there's SO MUCH code that relies
|
||||
/// on this property existing and it was really nasty to change all of
|
||||
/// that today.
|
||||
screen: *Screen,
|
||||
|
||||
/// Screen is the current screen state. The "active_screen" field says what
|
||||
/// the current screen is. The backup screen is the opposite of the active
|
||||
/// screen.
|
||||
active_screen: ScreenType,
|
||||
screen: Screen,
|
||||
secondary_screen: Screen,
|
||||
/// The set of screens behind this terminal (e.g. primary vs alternate).
|
||||
screens: ScreenSet,
|
||||
|
||||
/// Whether we're currently writing to the status line (DECSASD and DECSSDT).
|
||||
/// We don't support a status line currently so we just black hole this
|
||||
|
|
@ -221,12 +221,19 @@ pub fn init(
|
|||
) !Terminal {
|
||||
const cols = opts.cols;
|
||||
const rows = opts.rows;
|
||||
|
||||
var screen_set: ScreenSet = try .init(alloc, .{
|
||||
.cols = cols,
|
||||
.rows = rows,
|
||||
.max_scrollback = opts.max_scrollback,
|
||||
});
|
||||
errdefer screen_set.deinit(alloc);
|
||||
|
||||
return .{
|
||||
.cols = cols,
|
||||
.rows = rows,
|
||||
.active_screen = .primary,
|
||||
.screen = try .init(alloc, .{ .cols = cols, .rows = rows, .max_scrollback = opts.max_scrollback }),
|
||||
.secondary_screen = try .init(alloc, .{ .cols = cols, .rows = rows, .max_scrollback = 0 }),
|
||||
.screen = screen_set.active,
|
||||
.screens = screen_set,
|
||||
.tabstops = try .init(alloc, cols, TABSTOP_INTERVAL),
|
||||
.scrolling_region = .{
|
||||
.top = 0,
|
||||
|
|
@ -245,8 +252,7 @@ pub fn init(
|
|||
|
||||
pub fn deinit(self: *Terminal, alloc: Allocator) void {
|
||||
self.tabstops.deinit(alloc);
|
||||
self.screen.deinit();
|
||||
self.secondary_screen.deinit();
|
||||
self.screens.deinit(alloc);
|
||||
self.pwd.deinit(alloc);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
|
@ -266,7 +272,7 @@ pub fn vtHandler(self: *Terminal) ReadonlyHandler {
|
|||
|
||||
/// The general allocator we should use for this terminal.
|
||||
fn gpa(self: *Terminal) Allocator {
|
||||
return self.screen.alloc;
|
||||
return self.screens.active.alloc;
|
||||
}
|
||||
|
||||
/// Print UTF-8 encoded string to the terminal.
|
||||
|
|
@ -1074,7 +1080,7 @@ pub fn markSemanticPrompt(self: *Terminal, p: SemanticPrompt) void {
|
|||
/// If the shell integration doesn't exist, this will always return false.
|
||||
pub fn cursorIsAtPrompt(self: *Terminal) bool {
|
||||
// If we're on the secondary screen, we're never at a prompt.
|
||||
if (self.active_screen == .alternate) return false;
|
||||
if (self.screens.active_key == .alternate) return false;
|
||||
|
||||
// Reverse through the active
|
||||
const start_x, const start_y = .{ self.screen.cursor.x, self.screen.cursor.y };
|
||||
|
|
@ -2202,7 +2208,7 @@ pub fn eraseDisplay(
|
|||
// at a prompt scrolls the screen contents prior to clearing.
|
||||
// Most shells send `ESC [ H ESC [ 2 J` so we can't just check
|
||||
// our current cursor position. See #905
|
||||
if (self.active_screen == .primary) at_prompt: {
|
||||
if (self.screens.active_key == .primary) at_prompt: {
|
||||
// Go from the bottom of the active up and see if we're
|
||||
// at a prompt.
|
||||
const active_br = self.screen.pages.getBottomRight(
|
||||
|
|
@ -2531,25 +2537,22 @@ pub fn resize(
|
|||
self.tabstops = try .init(alloc, cols, 8);
|
||||
}
|
||||
|
||||
// If we're making the screen smaller, dealloc the unused items.
|
||||
if (self.active_screen == .primary) {
|
||||
if (self.flags.shell_redraws_prompt) {
|
||||
self.screen.clearPrompt();
|
||||
}
|
||||
|
||||
if (self.modes.get(.wraparound)) {
|
||||
try self.screen.resize(cols, rows);
|
||||
} else {
|
||||
try self.screen.resizeWithoutReflow(cols, rows);
|
||||
}
|
||||
try self.secondary_screen.resizeWithoutReflow(cols, rows);
|
||||
// Resize primary screen, which supports reflow
|
||||
const primary = self.screens.get(.primary).?;
|
||||
if (self.screens.active_key == .primary and
|
||||
self.flags.shell_redraws_prompt)
|
||||
{
|
||||
primary.clearPrompt();
|
||||
}
|
||||
if (self.modes.get(.wraparound)) {
|
||||
try primary.resize(cols, rows);
|
||||
} else {
|
||||
try self.screen.resizeWithoutReflow(cols, rows);
|
||||
if (self.modes.get(.wraparound)) {
|
||||
try self.secondary_screen.resize(cols, rows);
|
||||
} else {
|
||||
try self.secondary_screen.resizeWithoutReflow(cols, rows);
|
||||
}
|
||||
try primary.resizeWithoutReflow(cols, rows);
|
||||
}
|
||||
|
||||
// Alternate screen, if it exists, doesn't reflow
|
||||
if (self.screens.get(.alternate)) |alt| {
|
||||
try alt.resizeWithoutReflow(cols, rows);
|
||||
}
|
||||
|
||||
// Whenever we resize we just mark it as a screen clear
|
||||
|
|
@ -2581,14 +2584,6 @@ pub fn getPwd(self: *const Terminal) ?[]const u8 {
|
|||
return self.pwd.items;
|
||||
}
|
||||
|
||||
/// Get the screen pointer for the given type.
|
||||
pub fn getScreen(self: *Terminal, t: ScreenType) *Screen {
|
||||
return if (self.active_screen == t)
|
||||
&self.screen
|
||||
else
|
||||
&self.secondary_screen;
|
||||
}
|
||||
|
||||
/// Switch to the given screen type (alternate or primary).
|
||||
///
|
||||
/// This does NOT handle behaviors such as clearing the screen,
|
||||
|
|
@ -2604,40 +2599,60 @@ pub fn getScreen(self: *Terminal, t: ScreenType) *Screen {
|
|||
/// more than two screens in the future if needed. There isn't
|
||||
/// currently a spec for this, but it is something I think might
|
||||
/// be useful in the future.
|
||||
pub fn switchScreen(self: *Terminal, t: ScreenType) ?*Screen {
|
||||
pub fn switchScreen(self: *Terminal, key: ScreenSet.Key) !?*Screen {
|
||||
// If we're already on the requested screen we do nothing.
|
||||
if (self.active_screen == t) return null;
|
||||
if (self.screens.active_key == key) return null;
|
||||
const old = self.screens.active;
|
||||
|
||||
// We always end hyperlink state when switching screens.
|
||||
// We need to do this on the original screen.
|
||||
self.screen.endHyperlink();
|
||||
old.endHyperlink();
|
||||
|
||||
// Switch the screens
|
||||
const old = self.screen;
|
||||
self.screen = self.secondary_screen;
|
||||
self.secondary_screen = old;
|
||||
self.active_screen = t;
|
||||
// Switch the screens/
|
||||
const new = self.screens.get(key) orelse new: {
|
||||
const primary = self.screens.get(.primary).?;
|
||||
break :new try self.screens.getInit(
|
||||
old.alloc,
|
||||
key,
|
||||
.{
|
||||
.cols = self.cols,
|
||||
.rows = self.rows,
|
||||
.max_scrollback = switch (key) {
|
||||
.primary => primary.pages.explicit_max_size,
|
||||
.alternate => 0,
|
||||
},
|
||||
|
||||
// Inherit our Kitty image storage limit from the primary
|
||||
// screen if we have to initialize.
|
||||
.kitty_image_storage_limit = primary.kitty_images.total_limit,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
// The new screen should not have any hyperlinks set
|
||||
assert(self.screen.cursor.hyperlink_id == 0);
|
||||
assert(new.cursor.hyperlink_id == 0);
|
||||
|
||||
// Bring our charset state with us
|
||||
self.screen.charset = old.charset;
|
||||
new.charset = old.charset;
|
||||
|
||||
// Clear our selection
|
||||
self.screen.clearSelection();
|
||||
new.clearSelection();
|
||||
|
||||
if (comptime build_options.kitty_graphics) {
|
||||
// Mark kitty images as dirty so they redraw. Without this set
|
||||
// the images will remain where they were (the dirty bit on
|
||||
// the screen only tracks the terminal grid, not the images).
|
||||
self.screen.kitty_images.dirty = true;
|
||||
new.kitty_images.dirty = true;
|
||||
}
|
||||
|
||||
// Mark our terminal as dirty to redraw the grid.
|
||||
self.flags.dirty.clear = true;
|
||||
|
||||
return &self.secondary_screen;
|
||||
// Finalize the switch
|
||||
self.screens.switchTo(key);
|
||||
self.screen = new;
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
/// Switch screen via a mode switch (e.g. mode 47, 1047, 1049).
|
||||
|
|
@ -2653,7 +2668,7 @@ pub fn switchScreenMode(
|
|||
self: *Terminal,
|
||||
mode: SwitchScreenMode,
|
||||
enabled: bool,
|
||||
) void {
|
||||
) !void {
|
||||
// The behavior in this function is completely based on reading
|
||||
// the xterm source, specifically "charproc.c" for
|
||||
// `srm_ALTBUF`, `srm_OPT_ALTBUF`, and `srm_OPT_ALTBUF_CURSOR`.
|
||||
|
|
@ -2665,7 +2680,7 @@ pub fn switchScreenMode(
|
|||
|
||||
// If we're disabling 1047 and we're on alt screen then
|
||||
// we clear the screen.
|
||||
.@"1047" => if (!enabled and self.active_screen == .alternate) {
|
||||
.@"1047" => if (!enabled and self.screens.active_key == .alternate) {
|
||||
self.eraseDisplay(.complete, false);
|
||||
},
|
||||
|
||||
|
|
@ -2675,8 +2690,8 @@ pub fn switchScreenMode(
|
|||
}
|
||||
|
||||
// Switch screens first to whatever we're going to.
|
||||
const to: ScreenType = if (enabled) .alternate else .primary;
|
||||
const old_ = self.switchScreen(to);
|
||||
const to: ScreenSet.Key = if (enabled) .alternate else .primary;
|
||||
const old_ = try self.switchScreen(to);
|
||||
|
||||
switch (mode) {
|
||||
// For these modes, we need to copy the cursor. We only copy
|
||||
|
|
@ -2697,7 +2712,7 @@ pub fn switchScreenMode(
|
|||
// Mode 1049 restores cursor on the primary screen when
|
||||
// we disable it.
|
||||
.@"1049" => if (enabled) {
|
||||
assert(self.active_screen == .alternate);
|
||||
assert(self.screens.active_key == .alternate);
|
||||
self.eraseDisplay(.complete, false);
|
||||
|
||||
// When we enter alt screen with 1049, we always copy the
|
||||
|
|
@ -2714,7 +2729,7 @@ pub fn switchScreenMode(
|
|||
};
|
||||
}
|
||||
} else {
|
||||
assert(self.active_screen == .primary);
|
||||
assert(self.screens.active_key == .primary);
|
||||
self.restoreCursor() catch |err| {
|
||||
log.warn(
|
||||
"restore cursor on switch screen failed to={} err={}",
|
||||
|
|
@ -2765,17 +2780,16 @@ pub fn plainStringUnwrapped(self: *Terminal, alloc: Allocator) ![]const u8 {
|
|||
/// this will reuse the existing memory. In the latter case, memory may
|
||||
/// be wasted (since its unused) but it isn't leaked.
|
||||
pub fn fullReset(self: *Terminal) void {
|
||||
// Reset our screens
|
||||
self.screen.reset();
|
||||
self.secondary_screen.reset();
|
||||
|
||||
// Ensure we're back on primary screen
|
||||
if (self.active_screen != .primary) {
|
||||
const old = self.screen;
|
||||
self.screen = self.secondary_screen;
|
||||
self.secondary_screen = old;
|
||||
self.active_screen = .primary;
|
||||
}
|
||||
self.screens.switchTo(.primary);
|
||||
self.screens.remove(
|
||||
self.screens.active.alloc,
|
||||
.alternate,
|
||||
);
|
||||
self.screen = self.screens.active;
|
||||
|
||||
// Reset our screens
|
||||
self.screens.active.reset();
|
||||
|
||||
// Rest our basic state
|
||||
self.modes.reset();
|
||||
|
|
@ -10757,7 +10771,7 @@ test "Terminal: cursorIsAtPrompt alternate screen" {
|
|||
try testing.expect(t.cursorIsAtPrompt());
|
||||
|
||||
// Secondary screen is never a prompt
|
||||
t.switchScreenMode(.@"1049", true);
|
||||
try t.switchScreenMode(.@"1049", true);
|
||||
try testing.expect(!t.cursorIsAtPrompt());
|
||||
t.markSemanticPrompt(.prompt);
|
||||
try testing.expect(!t.cursorIsAtPrompt());
|
||||
|
|
@ -10841,7 +10855,7 @@ test "Terminal: fullReset clears alt screen kitty keyboard state" {
|
|||
var t = try init(testing.allocator, .{ .cols = 10, .rows = 10 });
|
||||
defer t.deinit(testing.allocator);
|
||||
|
||||
t.switchScreenMode(.@"1049", true);
|
||||
try t.switchScreenMode(.@"1049", true);
|
||||
t.screen.kitty_keyboard.push(.{
|
||||
.disambiguate = true,
|
||||
.report_events = false,
|
||||
|
|
@ -10849,10 +10863,10 @@ test "Terminal: fullReset clears alt screen kitty keyboard state" {
|
|||
.report_all = true,
|
||||
.report_associated = true,
|
||||
});
|
||||
t.switchScreenMode(.@"1049", false);
|
||||
try t.switchScreenMode(.@"1049", false);
|
||||
|
||||
t.fullReset();
|
||||
try testing.expectEqual(0, t.secondary_screen.kitty_keyboard.current().int());
|
||||
try testing.expect(t.screens.get(.alternate) == null);
|
||||
}
|
||||
|
||||
test "Terminal: fullReset default modes" {
|
||||
|
|
@ -11164,8 +11178,8 @@ test "Terminal: mode 47 alt screen plain" {
|
|||
try t.printString("1A");
|
||||
|
||||
// Go to alt screen with mode 47
|
||||
t.switchScreenMode(.@"47", true);
|
||||
try testing.expectEqual(ScreenType.alternate, t.active_screen);
|
||||
try t.switchScreenMode(.@"47", true);
|
||||
try testing.expectEqual(.alternate, t.screens.active_key);
|
||||
|
||||
// Screen should be empty
|
||||
{
|
||||
|
|
@ -11184,8 +11198,8 @@ test "Terminal: mode 47 alt screen plain" {
|
|||
}
|
||||
|
||||
// Go back to primary
|
||||
t.switchScreenMode(.@"47", false);
|
||||
try testing.expectEqual(ScreenType.primary, t.active_screen);
|
||||
try t.switchScreenMode(.@"47", false);
|
||||
try testing.expectEqual(.primary, t.screens.active_key);
|
||||
|
||||
// Primary screen should still have the original content
|
||||
{
|
||||
|
|
@ -11195,8 +11209,8 @@ test "Terminal: mode 47 alt screen plain" {
|
|||
}
|
||||
|
||||
// Go back to alt screen with mode 47
|
||||
t.switchScreenMode(.@"47", true);
|
||||
try testing.expectEqual(ScreenType.alternate, t.active_screen);
|
||||
try t.switchScreenMode(.@"47", true);
|
||||
try testing.expectEqual(.alternate, t.screens.active_key);
|
||||
|
||||
// Screen should retain content
|
||||
{
|
||||
|
|
@ -11215,8 +11229,8 @@ test "Terminal: mode 47 copies cursor both directions" {
|
|||
try t.setAttribute(.{ .direct_color_fg = .{ .r = 0xFF, .g = 0, .b = 0x7F } });
|
||||
|
||||
// Go to alt screen with mode 47
|
||||
t.switchScreenMode(.@"47", true);
|
||||
try testing.expectEqual(ScreenType.alternate, t.active_screen);
|
||||
try t.switchScreenMode(.@"47", true);
|
||||
try testing.expectEqual(.alternate, t.screens.active_key);
|
||||
|
||||
// Verify that our style is set
|
||||
{
|
||||
|
|
@ -11230,8 +11244,8 @@ test "Terminal: mode 47 copies cursor both directions" {
|
|||
try t.setAttribute(.{ .direct_color_fg = .{ .r = 0, .g = 0xFF, .b = 0 } });
|
||||
|
||||
// Go back to primary
|
||||
t.switchScreenMode(.@"47", false);
|
||||
try testing.expectEqual(ScreenType.primary, t.active_screen);
|
||||
try t.switchScreenMode(.@"47", false);
|
||||
try testing.expectEqual(.primary, t.screens.active_key);
|
||||
|
||||
// Verify that our style is still set
|
||||
{
|
||||
|
|
@ -11251,8 +11265,8 @@ test "Terminal: mode 1047 alt screen plain" {
|
|||
try t.printString("1A");
|
||||
|
||||
// Go to alt screen with mode 47
|
||||
t.switchScreenMode(.@"1047", true);
|
||||
try testing.expectEqual(ScreenType.alternate, t.active_screen);
|
||||
try t.switchScreenMode(.@"1047", true);
|
||||
try testing.expectEqual(.alternate, t.screens.active_key);
|
||||
|
||||
// Screen should be empty
|
||||
{
|
||||
|
|
@ -11271,8 +11285,8 @@ test "Terminal: mode 1047 alt screen plain" {
|
|||
}
|
||||
|
||||
// Go back to primary
|
||||
t.switchScreenMode(.@"1047", false);
|
||||
try testing.expectEqual(ScreenType.primary, t.active_screen);
|
||||
try t.switchScreenMode(.@"1047", false);
|
||||
try testing.expectEqual(.primary, t.screens.active_key);
|
||||
|
||||
// Primary screen should still have the original content
|
||||
{
|
||||
|
|
@ -11282,8 +11296,8 @@ test "Terminal: mode 1047 alt screen plain" {
|
|||
}
|
||||
|
||||
// Go back to alt screen with mode 1047
|
||||
t.switchScreenMode(.@"1047", true);
|
||||
try testing.expectEqual(ScreenType.alternate, t.active_screen);
|
||||
try t.switchScreenMode(.@"1047", true);
|
||||
try testing.expectEqual(.alternate, t.screens.active_key);
|
||||
|
||||
// Screen should be empty
|
||||
{
|
||||
|
|
@ -11302,8 +11316,8 @@ test "Terminal: mode 1047 copies cursor both directions" {
|
|||
try t.setAttribute(.{ .direct_color_fg = .{ .r = 0xFF, .g = 0, .b = 0x7F } });
|
||||
|
||||
// Go to alt screen with mode 47
|
||||
t.switchScreenMode(.@"1047", true);
|
||||
try testing.expectEqual(ScreenType.alternate, t.active_screen);
|
||||
try t.switchScreenMode(.@"1047", true);
|
||||
try testing.expectEqual(.alternate, t.screens.active_key);
|
||||
|
||||
// Verify that our style is set
|
||||
{
|
||||
|
|
@ -11317,8 +11331,8 @@ test "Terminal: mode 1047 copies cursor both directions" {
|
|||
try t.setAttribute(.{ .direct_color_fg = .{ .r = 0, .g = 0xFF, .b = 0 } });
|
||||
|
||||
// Go back to primary
|
||||
t.switchScreenMode(.@"1047", false);
|
||||
try testing.expectEqual(ScreenType.primary, t.active_screen);
|
||||
try t.switchScreenMode(.@"1047", false);
|
||||
try testing.expectEqual(.primary, t.screens.active_key);
|
||||
|
||||
// Verify that our style is still set
|
||||
{
|
||||
|
|
@ -11338,8 +11352,8 @@ test "Terminal: mode 1049 alt screen plain" {
|
|||
try t.printString("1A");
|
||||
|
||||
// Go to alt screen with mode 47
|
||||
t.switchScreenMode(.@"1049", true);
|
||||
try testing.expectEqual(ScreenType.alternate, t.active_screen);
|
||||
try t.switchScreenMode(.@"1049", true);
|
||||
try testing.expectEqual(.alternate, t.screens.active_key);
|
||||
|
||||
// Screen should be empty
|
||||
{
|
||||
|
|
@ -11358,8 +11372,8 @@ test "Terminal: mode 1049 alt screen plain" {
|
|||
}
|
||||
|
||||
// Go back to primary
|
||||
t.switchScreenMode(.@"1049", false);
|
||||
try testing.expectEqual(ScreenType.primary, t.active_screen);
|
||||
try t.switchScreenMode(.@"1049", false);
|
||||
try testing.expectEqual(.primary, t.screens.active_key);
|
||||
|
||||
// Primary screen should still have the original content
|
||||
{
|
||||
|
|
@ -11377,8 +11391,8 @@ test "Terminal: mode 1049 alt screen plain" {
|
|||
}
|
||||
|
||||
// Go back to alt screen with mode 1049
|
||||
t.switchScreenMode(.@"1049", true);
|
||||
try testing.expectEqual(ScreenType.alternate, t.active_screen);
|
||||
try t.switchScreenMode(.@"1049", true);
|
||||
try testing.expectEqual(.alternate, t.screens.active_key);
|
||||
|
||||
// Screen should be empty
|
||||
{
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ pub const TerminalFormatter = struct {
|
|||
}
|
||||
}
|
||||
|
||||
var screen_formatter: ScreenFormatter = .init(&self.terminal.screen, self.opts);
|
||||
var screen_formatter: ScreenFormatter = .init(self.terminal.screen, self.opts);
|
||||
screen_formatter.content = self.content;
|
||||
screen_formatter.extra = self.extra.screen;
|
||||
screen_formatter.pin_map = self.pin_map;
|
||||
|
|
@ -4231,7 +4231,7 @@ test "Screen plain single line" {
|
|||
var pin_map: std.ArrayList(Pin) = .empty;
|
||||
defer pin_map.deinit(alloc);
|
||||
|
||||
var formatter: ScreenFormatter = .init(&t.screen, .plain);
|
||||
var formatter: ScreenFormatter = .init(t.screen, .plain);
|
||||
formatter.pin_map = .{ .alloc = alloc, .map = &pin_map };
|
||||
|
||||
try formatter.format(&builder.writer);
|
||||
|
|
@ -4268,7 +4268,7 @@ test "Screen plain multiline" {
|
|||
var pin_map: std.ArrayList(Pin) = .empty;
|
||||
defer pin_map.deinit(alloc);
|
||||
|
||||
var formatter: ScreenFormatter = .init(&t.screen, .plain);
|
||||
var formatter: ScreenFormatter = .init(t.screen, .plain);
|
||||
formatter.pin_map = .{ .alloc = alloc, .map = &pin_map };
|
||||
|
||||
try formatter.format(&builder.writer);
|
||||
|
|
@ -4316,7 +4316,7 @@ test "Screen plain with selection" {
|
|||
var pin_map: std.ArrayList(Pin) = .empty;
|
||||
defer pin_map.deinit(alloc);
|
||||
|
||||
var formatter: ScreenFormatter = .init(&t.screen, .plain);
|
||||
var formatter: ScreenFormatter = .init(t.screen, .plain);
|
||||
formatter.content = .{ .selection = .init(
|
||||
t.screen.pages.pin(.{ .active = .{ .x = 0, .y = 1 } }).?,
|
||||
t.screen.pages.pin(.{ .active = .{ .x = 4, .y = 1 } }).?,
|
||||
|
|
@ -4361,7 +4361,7 @@ test "Screen vt with cursor position" {
|
|||
var pin_map: std.ArrayList(Pin) = .empty;
|
||||
defer pin_map.deinit(alloc);
|
||||
|
||||
var formatter: ScreenFormatter = .init(&t.screen, .vt);
|
||||
var formatter: ScreenFormatter = .init(t.screen, .vt);
|
||||
formatter.extra.cursor = true;
|
||||
formatter.pin_map = .{ .alloc = alloc, .map = &pin_map };
|
||||
|
||||
|
|
@ -4420,7 +4420,7 @@ test "Screen vt with style" {
|
|||
var pin_map: std.ArrayList(Pin) = .empty;
|
||||
defer pin_map.deinit(alloc);
|
||||
|
||||
var formatter: ScreenFormatter = .init(&t.screen, .vt);
|
||||
var formatter: ScreenFormatter = .init(t.screen, .vt);
|
||||
formatter.extra.style = true;
|
||||
formatter.pin_map = .{ .alloc = alloc, .map = &pin_map };
|
||||
|
||||
|
|
@ -4472,7 +4472,7 @@ test "Screen vt with hyperlink" {
|
|||
var pin_map: std.ArrayList(Pin) = .empty;
|
||||
defer pin_map.deinit(alloc);
|
||||
|
||||
var formatter: ScreenFormatter = .init(&t.screen, .vt);
|
||||
var formatter: ScreenFormatter = .init(t.screen, .vt);
|
||||
formatter.extra.hyperlink = true;
|
||||
formatter.pin_map = .{ .alloc = alloc, .map = &pin_map };
|
||||
|
||||
|
|
@ -4532,7 +4532,7 @@ test "Screen vt with protection" {
|
|||
var pin_map: std.ArrayList(Pin) = .empty;
|
||||
defer pin_map.deinit(alloc);
|
||||
|
||||
var formatter: ScreenFormatter = .init(&t.screen, .vt);
|
||||
var formatter: ScreenFormatter = .init(t.screen, .vt);
|
||||
formatter.extra.protection = true;
|
||||
formatter.pin_map = .{ .alloc = alloc, .map = &pin_map };
|
||||
|
||||
|
|
@ -4584,7 +4584,7 @@ test "Screen vt with kitty keyboard" {
|
|||
var pin_map: std.ArrayList(Pin) = .empty;
|
||||
defer pin_map.deinit(alloc);
|
||||
|
||||
var formatter: ScreenFormatter = .init(&t.screen, .vt);
|
||||
var formatter: ScreenFormatter = .init(t.screen, .vt);
|
||||
formatter.extra.kitty_keyboard = true;
|
||||
formatter.pin_map = .{ .alloc = alloc, .map = &pin_map };
|
||||
|
||||
|
|
@ -4638,7 +4638,7 @@ test "Screen vt with charsets" {
|
|||
var pin_map: std.ArrayList(Pin) = .empty;
|
||||
defer pin_map.deinit(alloc);
|
||||
|
||||
var formatter: ScreenFormatter = .init(&t.screen, .vt);
|
||||
var formatter: ScreenFormatter = .init(t.screen, .vt);
|
||||
formatter.extra.charsets = true;
|
||||
formatter.pin_map = .{ .alloc = alloc, .map = &pin_map };
|
||||
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ fn display(
|
|||
result.placement_id,
|
||||
p,
|
||||
) catch |err| {
|
||||
p.deinit(&terminal.screen);
|
||||
p.deinit(terminal.screen);
|
||||
encodeError(&result, err);
|
||||
return result;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ pub const ImageStorage = struct {
|
|||
|
||||
// Deinit the placement and remove it
|
||||
const image_id = entry.key_ptr.image_id;
|
||||
entry.value_ptr.deinit(&t.screen);
|
||||
entry.value_ptr.deinit(t.screen);
|
||||
self.placements.removeByPtr(entry.key_ptr);
|
||||
if (delete_images) self.deleteIfUnused(alloc, image_id);
|
||||
}
|
||||
|
|
@ -247,7 +247,7 @@ pub const ImageStorage = struct {
|
|||
|
||||
.id => |v| self.deleteById(
|
||||
alloc,
|
||||
&t.screen,
|
||||
t.screen,
|
||||
v.image_id,
|
||||
v.placement_id,
|
||||
v.delete,
|
||||
|
|
@ -257,7 +257,7 @@ pub const ImageStorage = struct {
|
|||
const img = self.imageByNumber(v.image_number) orelse break :newest;
|
||||
self.deleteById(
|
||||
alloc,
|
||||
&t.screen,
|
||||
t.screen,
|
||||
img.id,
|
||||
v.placement_id,
|
||||
v.delete,
|
||||
|
|
@ -332,7 +332,7 @@ pub const ImageStorage = struct {
|
|||
const img = self.imageById(entry.key_ptr.image_id) orelse continue;
|
||||
const rect = entry.value_ptr.rect(img, t) orelse continue;
|
||||
if (rect.top_left.x <= x and rect.bottom_right.x >= x) {
|
||||
entry.value_ptr.deinit(&t.screen);
|
||||
entry.value_ptr.deinit(t.screen);
|
||||
self.placements.removeByPtr(entry.key_ptr);
|
||||
if (v.delete) self.deleteIfUnused(alloc, img.id);
|
||||
}
|
||||
|
|
@ -364,7 +364,7 @@ pub const ImageStorage = struct {
|
|||
var target_pin_copy = target_pin;
|
||||
target_pin_copy.x = rect.top_left.x;
|
||||
if (target_pin_copy.isBetween(rect.top_left, rect.bottom_right)) {
|
||||
entry.value_ptr.deinit(&t.screen);
|
||||
entry.value_ptr.deinit(t.screen);
|
||||
self.placements.removeByPtr(entry.key_ptr);
|
||||
if (v.delete) self.deleteIfUnused(alloc, img.id);
|
||||
}
|
||||
|
|
@ -387,7 +387,7 @@ pub const ImageStorage = struct {
|
|||
|
||||
if (entry.value_ptr.z == v.z) {
|
||||
const image_id = entry.key_ptr.image_id;
|
||||
entry.value_ptr.deinit(&t.screen);
|
||||
entry.value_ptr.deinit(t.screen);
|
||||
self.placements.removeByPtr(entry.key_ptr);
|
||||
if (v.delete) self.deleteIfUnused(alloc, image_id);
|
||||
}
|
||||
|
|
@ -411,7 +411,7 @@ pub const ImageStorage = struct {
|
|||
while (it.next()) |entry| {
|
||||
if (entry.key_ptr.image_id >= v.first or entry.key_ptr.image_id <= v.last) {
|
||||
const image_id = entry.key_ptr.image_id;
|
||||
entry.value_ptr.deinit(&t.screen);
|
||||
entry.value_ptr.deinit(t.screen);
|
||||
self.placements.removeByPtr(entry.key_ptr);
|
||||
if (v.delete) self.deleteIfUnused(alloc, image_id);
|
||||
}
|
||||
|
|
@ -498,7 +498,7 @@ pub const ImageStorage = struct {
|
|||
const rect = entry.value_ptr.rect(img, t) orelse continue;
|
||||
if (target_pin.isBetween(rect.top_left, rect.bottom_right)) {
|
||||
if (filter) |f| if (!f(filter_ctx, entry.value_ptr.*)) continue;
|
||||
entry.value_ptr.deinit(&t.screen);
|
||||
entry.value_ptr.deinit(t.screen);
|
||||
self.placements.removeByPtr(entry.key_ptr);
|
||||
if (delete_unused) self.deleteIfUnused(alloc, img.id);
|
||||
}
|
||||
|
|
@ -825,7 +825,7 @@ test "storage: add placement with zero placement id" {
|
|||
t.height_px = 100;
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1, .width = 50, .height = 50 });
|
||||
try s.addImage(alloc, .{ .id = 2, .width = 25, .height = 25 });
|
||||
try s.addPlacement(alloc, 1, 0, .{ .location = .{ .pin = try trackPin(&t, .{ .x = 25, .y = 25 }) } });
|
||||
|
|
@ -853,7 +853,7 @@ test "storage: delete all placements and images" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1 });
|
||||
try s.addImage(alloc, .{ .id = 2 });
|
||||
try s.addImage(alloc, .{ .id = 3 });
|
||||
|
|
@ -876,7 +876,7 @@ test "storage: delete all placements and images preserves limit" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
s.total_limit = 5000;
|
||||
try s.addImage(alloc, .{ .id = 1 });
|
||||
try s.addImage(alloc, .{ .id = 2 });
|
||||
|
|
@ -901,7 +901,7 @@ test "storage: delete all placements" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1 });
|
||||
try s.addImage(alloc, .{ .id = 2 });
|
||||
try s.addImage(alloc, .{ .id = 3 });
|
||||
|
|
@ -924,7 +924,7 @@ test "storage: delete all placements by image id" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1 });
|
||||
try s.addImage(alloc, .{ .id = 2 });
|
||||
try s.addImage(alloc, .{ .id = 3 });
|
||||
|
|
@ -947,7 +947,7 @@ test "storage: delete all placements by image id and unused images" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1 });
|
||||
try s.addImage(alloc, .{ .id = 2 });
|
||||
try s.addImage(alloc, .{ .id = 3 });
|
||||
|
|
@ -970,7 +970,7 @@ test "storage: delete placement by specific id" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1 });
|
||||
try s.addImage(alloc, .{ .id = 2 });
|
||||
try s.addImage(alloc, .{ .id = 3 });
|
||||
|
|
@ -1000,7 +1000,7 @@ test "storage: delete intersecting cursor" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1, .width = 50, .height = 50 });
|
||||
try s.addImage(alloc, .{ .id = 2, .width = 25, .height = 25 });
|
||||
try s.addPlacement(alloc, 1, 1, .{ .location = .{ .pin = try trackPin(&t, .{ .x = 0, .y = 0 }) } });
|
||||
|
|
@ -1032,7 +1032,7 @@ test "storage: delete intersecting cursor plus unused" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1, .width = 50, .height = 50 });
|
||||
try s.addImage(alloc, .{ .id = 2, .width = 25, .height = 25 });
|
||||
try s.addPlacement(alloc, 1, 1, .{ .location = .{ .pin = try trackPin(&t, .{ .x = 0, .y = 0 }) } });
|
||||
|
|
@ -1064,7 +1064,7 @@ test "storage: delete intersecting cursor hits multiple" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1, .width = 50, .height = 50 });
|
||||
try s.addImage(alloc, .{ .id = 2, .width = 25, .height = 25 });
|
||||
try s.addPlacement(alloc, 1, 1, .{ .location = .{ .pin = try trackPin(&t, .{ .x = 0, .y = 0 }) } });
|
||||
|
|
@ -1090,7 +1090,7 @@ test "storage: delete by column" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1, .width = 50, .height = 50 });
|
||||
try s.addImage(alloc, .{ .id = 2, .width = 25, .height = 25 });
|
||||
try s.addPlacement(alloc, 1, 1, .{ .location = .{ .pin = try trackPin(&t, .{ .x = 0, .y = 0 }) } });
|
||||
|
|
@ -1122,7 +1122,7 @@ test "storage: delete by column 1x1" {
|
|||
t.height_px = 100;
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1, .width = 1, .height = 1 });
|
||||
try s.addPlacement(alloc, 1, 1, .{ .location = .{ .pin = try trackPin(&t, .{ .x = 0, .y = 0 }) } });
|
||||
try s.addPlacement(alloc, 1, 2, .{ .location = .{ .pin = try trackPin(&t, .{ .x = 1, .y = 0 }) } });
|
||||
|
|
@ -1156,7 +1156,7 @@ test "storage: delete by row" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1, .width = 50, .height = 50 });
|
||||
try s.addImage(alloc, .{ .id = 2, .width = 25, .height = 25 });
|
||||
try s.addPlacement(alloc, 1, 1, .{ .location = .{ .pin = try trackPin(&t, .{ .x = 0, .y = 0 }) } });
|
||||
|
|
@ -1188,7 +1188,7 @@ test "storage: delete by row 1x1" {
|
|||
t.height_px = 100;
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1, .width = 1, .height = 1 });
|
||||
try s.addPlacement(alloc, 1, 1, .{ .location = .{ .pin = try trackPin(&t, .{ .y = 0 }) } });
|
||||
try s.addPlacement(alloc, 1, 2, .{ .location = .{ .pin = try trackPin(&t, .{ .y = 1 }) } });
|
||||
|
|
@ -1220,7 +1220,7 @@ test "storage: delete images by range 1" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1 });
|
||||
try s.addImage(alloc, .{ .id = 2 });
|
||||
try s.addImage(alloc, .{ .id = 3 });
|
||||
|
|
@ -1245,7 +1245,7 @@ test "storage: delete images by range 2" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1 });
|
||||
try s.addImage(alloc, .{ .id = 2 });
|
||||
try s.addImage(alloc, .{ .id = 3 });
|
||||
|
|
@ -1270,7 +1270,7 @@ test "storage: delete images by range 3" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1 });
|
||||
try s.addImage(alloc, .{ .id = 2 });
|
||||
try s.addImage(alloc, .{ .id = 3 });
|
||||
|
|
@ -1295,7 +1295,7 @@ test "storage: delete images by range 4" {
|
|||
const tracked = t.screen.pages.countTrackedPins();
|
||||
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
try s.addImage(alloc, .{ .id = 1 });
|
||||
try s.addImage(alloc, .{ .id = 2 });
|
||||
try s.addImage(alloc, .{ .id = 3 });
|
||||
|
|
|
|||
|
|
@ -1180,7 +1180,7 @@ test "unicode render placement: dog 4x2" {
|
|||
var t = try terminal.Terminal.init(alloc, .{ .cols = 100, .rows = 100 });
|
||||
defer t.deinit(alloc);
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
|
||||
const image: Image = .{ .id = 1, .width = 500, .height = 306 };
|
||||
try s.addImage(alloc, image);
|
||||
|
|
@ -1247,7 +1247,7 @@ test "unicode render placement: dog 2x2 with blank cells" {
|
|||
var t = try terminal.Terminal.init(alloc, .{ .cols = 100, .rows = 100 });
|
||||
defer t.deinit(alloc);
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
|
||||
const image: Image = .{ .id = 1, .width = 500, .height = 306 };
|
||||
try s.addImage(alloc, image);
|
||||
|
|
@ -1313,7 +1313,7 @@ test "unicode render placement: dog 1x1" {
|
|||
var t = try terminal.Terminal.init(alloc, .{ .cols = 100, .rows = 100 });
|
||||
defer t.deinit(alloc);
|
||||
var s: ImageStorage = .{};
|
||||
defer s.deinit(alloc, &t.screen);
|
||||
defer s.deinit(alloc, t.screen);
|
||||
|
||||
const image: Image = .{ .id = 1, .width = 500, .height = 306 };
|
||||
try s.addImage(alloc, image);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ pub const Point = point.Point;
|
|||
pub const ReadonlyHandler = stream_readonly.Handler;
|
||||
pub const ReadonlyStream = stream_readonly.Stream;
|
||||
pub const Screen = @import("Screen.zig");
|
||||
pub const ScreenType = Terminal.ScreenType;
|
||||
pub const ScreenSet = @import("ScreenSet.zig");
|
||||
pub const Scrollbar = PageList.Scrollbar;
|
||||
pub const Selection = @import("Selection.zig");
|
||||
pub const SizeReportStyle = csi.SizeReportStyle;
|
||||
|
|
|
|||
|
|
@ -391,7 +391,7 @@ test "simple search" {
|
|||
defer s.deinit();
|
||||
try s.nextSlice("Fizz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: ScreenSearch = try .init(alloc, &t.screen, "Fizz");
|
||||
var search: ScreenSearch = try .init(alloc, t.screen, "Fizz");
|
||||
defer search.deinit();
|
||||
try search.searchAll();
|
||||
try testing.expectEqual(2, search.active_results.items.len);
|
||||
|
|
@ -444,7 +444,7 @@ test "simple search with history" {
|
|||
for (0..list.rows) |_| try s.nextSlice("\r\n");
|
||||
try s.nextSlice("hello.");
|
||||
|
||||
var search: ScreenSearch = try .init(alloc, &t.screen, "Fizz");
|
||||
var search: ScreenSearch = try .init(alloc, t.screen, "Fizz");
|
||||
defer search.deinit();
|
||||
try search.searchAll();
|
||||
try testing.expectEqual(0, search.active_results.items.len);
|
||||
|
|
@ -482,7 +482,7 @@ test "reload active with history change" {
|
|||
try s.nextSlice("Fizz\r\n");
|
||||
|
||||
// Start up our search which will populate our initial active area.
|
||||
var search: ScreenSearch = try .init(alloc, &t.screen, "Fizz");
|
||||
var search: ScreenSearch = try .init(alloc, t.screen, "Fizz");
|
||||
defer search.deinit();
|
||||
try search.searchAll();
|
||||
{
|
||||
|
|
@ -562,7 +562,7 @@ test "active change contents" {
|
|||
defer s.deinit();
|
||||
try s.nextSlice("Fuzz\r\nBuzz\r\nFizz\r\nBang");
|
||||
|
||||
var search: ScreenSearch = try .init(alloc, &t.screen, "Fizz");
|
||||
var search: ScreenSearch = try .init(alloc, t.screen, "Fizz");
|
||||
defer search.deinit();
|
||||
try search.searchAll();
|
||||
try testing.expectEqual(1, search.active_results.items.len);
|
||||
|
|
|
|||
|
|
@ -233,9 +233,9 @@ pub const Handler = struct {
|
|||
self.terminal.scrolling_region.right = self.terminal.cols - 1;
|
||||
},
|
||||
|
||||
.alt_screen_legacy => self.terminal.switchScreenMode(.@"47", enabled),
|
||||
.alt_screen => self.terminal.switchScreenMode(.@"1047", enabled),
|
||||
.alt_screen_save_cursor_clear_enter => self.terminal.switchScreenMode(.@"1049", enabled),
|
||||
.alt_screen_legacy => try self.terminal.switchScreenMode(.@"47", enabled),
|
||||
.alt_screen => try self.terminal.switchScreenMode(.@"1047", enabled),
|
||||
.alt_screen_save_cursor_clear_enter => try self.terminal.switchScreenMode(.@"1049", enabled),
|
||||
|
||||
.save_cursor => if (enabled) {
|
||||
self.terminal.saveCursor();
|
||||
|
|
@ -527,18 +527,18 @@ test "alt screen" {
|
|||
|
||||
// Write to primary screen
|
||||
try s.nextSlice("Primary");
|
||||
try testing.expectEqual(Terminal.ScreenType.primary, t.active_screen);
|
||||
try testing.expectEqual(.primary, t.screens.active_key);
|
||||
|
||||
// Switch to alt screen
|
||||
try s.nextSlice("\x1B[?1049h");
|
||||
try testing.expectEqual(Terminal.ScreenType.alternate, t.active_screen);
|
||||
try testing.expectEqual(.alternate, t.screens.active_key);
|
||||
|
||||
// Write to alt screen
|
||||
try s.nextSlice("Alt");
|
||||
|
||||
// Switch back to primary
|
||||
try s.nextSlice("\x1B[?1049l");
|
||||
try testing.expectEqual(Terminal.ScreenType.primary, t.active_screen);
|
||||
try testing.expectEqual(.primary, t.screens.active_key);
|
||||
|
||||
const str = try t.plainString(testing.allocator);
|
||||
defer testing.allocator.free(str);
|
||||
|
|
|
|||
|
|
@ -246,16 +246,15 @@ pub fn init(self: *Termio, alloc: Allocator, opts: termio.Options) !void {
|
|||
errdefer term.deinit(alloc);
|
||||
|
||||
// Set the image size limits
|
||||
try term.screen.kitty_images.setLimit(
|
||||
alloc,
|
||||
&term.screen,
|
||||
opts.config.image_storage_limit,
|
||||
);
|
||||
try term.secondary_screen.kitty_images.setLimit(
|
||||
alloc,
|
||||
&term.secondary_screen,
|
||||
opts.config.image_storage_limit,
|
||||
);
|
||||
var it = term.screens.all.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const screen: *terminalpkg.Screen = entry.value.*;
|
||||
try screen.kitty_images.setLimit(
|
||||
alloc,
|
||||
screen,
|
||||
opts.config.image_storage_limit,
|
||||
);
|
||||
}
|
||||
|
||||
// Set our default cursor style
|
||||
term.screen.cursor.cursor_style = opts.config.cursor_style;
|
||||
|
|
@ -451,16 +450,15 @@ pub fn changeConfig(self: *Termio, td: *ThreadData, config: *DerivedConfig) !voi
|
|||
};
|
||||
|
||||
// Set the image size limits
|
||||
try self.terminal.screen.kitty_images.setLimit(
|
||||
self.alloc,
|
||||
&self.terminal.screen,
|
||||
config.image_storage_limit,
|
||||
);
|
||||
try self.terminal.secondary_screen.kitty_images.setLimit(
|
||||
self.alloc,
|
||||
&self.terminal.secondary_screen,
|
||||
config.image_storage_limit,
|
||||
);
|
||||
var it = self.terminal.screens.all.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const screen: *terminalpkg.Screen = entry.value.*;
|
||||
try screen.kitty_images.setLimit(
|
||||
self.alloc,
|
||||
screen,
|
||||
config.image_storage_limit,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Resize the terminal.
|
||||
|
|
@ -578,7 +576,7 @@ pub fn clearScreen(self: *Termio, td: *ThreadData, history: bool) !void {
|
|||
// emulator-level screen clear, this messes up the running programs
|
||||
// knowledge of where the cursor is and causes rendering issues. So,
|
||||
// for alt screen, we do nothing.
|
||||
if (self.terminal.active_screen == .alternate) return;
|
||||
if (self.terminal.screens.active_key == .alternate) return;
|
||||
|
||||
// Clear our selection
|
||||
self.terminal.screen.clearSelection();
|
||||
|
|
|
|||
|
|
@ -583,15 +583,15 @@ pub const StreamHandler = struct {
|
|||
},
|
||||
|
||||
.alt_screen_legacy => {
|
||||
self.terminal.switchScreenMode(.@"47", enabled);
|
||||
try self.terminal.switchScreenMode(.@"47", enabled);
|
||||
},
|
||||
|
||||
.alt_screen => {
|
||||
self.terminal.switchScreenMode(.@"1047", enabled);
|
||||
try self.terminal.switchScreenMode(.@"1047", enabled);
|
||||
},
|
||||
|
||||
.alt_screen_save_cursor_clear_enter => {
|
||||
self.terminal.switchScreenMode(.@"1049", enabled);
|
||||
try self.terminal.switchScreenMode(.@"1049", enabled);
|
||||
},
|
||||
|
||||
// Mode 1048 is xterm's conditional save cursor depending
|
||||
|
|
|
|||
Loading…
Reference in New Issue