mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 09:16:11 +03:00
implement delete line
This commit is contained in:
14
conformance/csi_dl.zig
Normal file
14
conformance/csi_dl.zig
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//! Delete Line (DL) - Esc [ M
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
try stdout.print("A\nB\nC\nD", .{});
|
||||||
|
try stdout.print("\x1B[2A", .{}); // cursor up
|
||||||
|
try stdout.print("\x1B[M", .{});
|
||||||
|
try stdout.print("E\n", .{});
|
||||||
|
try stdout.print("\x1B[B", .{});
|
||||||
|
|
||||||
|
// const stdin = std.io.getStdIn().reader();
|
||||||
|
// _ = try stdin.readByte();
|
||||||
|
}
|
@ -394,6 +394,45 @@ pub fn linefeed(self: *Terminal, alloc: Allocator) void {
|
|||||||
self.cursor.y += 1;
|
self.cursor.y += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes amount lines from the current cursor row down. The remaining lines
|
||||||
|
/// to the bottom margin are shifted up and space from the bottom margin up is
|
||||||
|
/// filled with empty lines.
|
||||||
|
///
|
||||||
|
/// If the current cursor position is outside of the current scroll region it
|
||||||
|
/// does nothing. If amount is greater than the remaining number of lines in the
|
||||||
|
/// scrolling region it is adjusted down.
|
||||||
|
///
|
||||||
|
/// In left and right margin mode the margins are respected; lines are only
|
||||||
|
/// scrolled in the scroll region.
|
||||||
|
///
|
||||||
|
/// If the cell movement splits a multi cell character that character cleared,
|
||||||
|
/// by replacing it by spaces, keeping its current attributes. All other
|
||||||
|
/// cleared space is colored according to the current SGR state.
|
||||||
|
///
|
||||||
|
/// Moves the cursor to the left margin.
|
||||||
|
pub fn deleteLines(self: *Terminal, alloc: Allocator, count: usize) void {
|
||||||
|
// TODO: scroll region bounds
|
||||||
|
|
||||||
|
// Move the cursor to the left margin
|
||||||
|
self.cursor.x = 0;
|
||||||
|
|
||||||
|
// Remaining number of lines in the scrolling region
|
||||||
|
const rem = self.scrolling_region.bottom - self.cursor.y;
|
||||||
|
|
||||||
|
// If the count is more than our remaining lines, we adjust down.
|
||||||
|
const count2 = @minimum(count, rem);
|
||||||
|
|
||||||
|
// Scroll up the count amount.
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < count2) : (i += 1) {
|
||||||
|
self.scrollUpRegion(
|
||||||
|
alloc,
|
||||||
|
self.cursor.y,
|
||||||
|
self.scrolling_region.bottom,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Scroll the text up by one row.
|
/// Scroll the text up by one row.
|
||||||
pub fn scrollUp(self: *Terminal, alloc: Allocator) void {
|
pub fn scrollUp(self: *Terminal, alloc: Allocator) void {
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
@ -414,6 +453,38 @@ pub fn scrollUp(self: *Terminal, alloc: Allocator) void {
|
|||||||
self.screen.items.len -= 1;
|
self.screen.items.len -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Scroll the given region up.
|
||||||
|
///
|
||||||
|
/// Top and bottom are 0-indexed.
|
||||||
|
fn scrollUpRegion(
|
||||||
|
self: *Terminal,
|
||||||
|
alloc: Allocator,
|
||||||
|
top: usize,
|
||||||
|
bottom: usize,
|
||||||
|
) void {
|
||||||
|
const tracy = trace(@src());
|
||||||
|
defer tracy.end();
|
||||||
|
|
||||||
|
// If we have no items, scrolling does nothing.
|
||||||
|
if (self.screen.items.len <= top) return;
|
||||||
|
|
||||||
|
// Clear the first line
|
||||||
|
self.screen.items[top].deinit(alloc);
|
||||||
|
|
||||||
|
// Only go to the end of the region OR the end of our lines.
|
||||||
|
const end = @minimum(bottom, self.screen.items.len - 1);
|
||||||
|
|
||||||
|
var i: usize = top;
|
||||||
|
while (i < end) : (i += 1) {
|
||||||
|
self.screen.items[i] = self.screen.items[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blank our last line if we have space.
|
||||||
|
if (i < self.screen.items.len) {
|
||||||
|
self.screen.items[i] = .{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Scroll the text down by one row.
|
/// Scroll the text down by one row.
|
||||||
/// TODO: test
|
/// TODO: test
|
||||||
pub fn scrollDown(self: *Terminal, alloc: Allocator) !void {
|
pub fn scrollDown(self: *Terminal, alloc: Allocator) !void {
|
||||||
@ -602,3 +673,34 @@ test "Terminal: setScrollingRegion" {
|
|||||||
try testing.expectEqual(@as(usize, 0), t.scrolling_region.top);
|
try testing.expectEqual(@as(usize, 0), t.scrolling_region.top);
|
||||||
try testing.expectEqual(@as(usize, t.rows - 1), t.scrolling_region.bottom);
|
try testing.expectEqual(@as(usize, t.rows - 1), t.scrolling_region.bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Terminal: setScrollingRegion" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 80, 80);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
// Initial value
|
||||||
|
try t.print(alloc, 'A');
|
||||||
|
t.carriageReturn();
|
||||||
|
t.linefeed(alloc);
|
||||||
|
try t.print(alloc, 'B');
|
||||||
|
t.carriageReturn();
|
||||||
|
t.linefeed(alloc);
|
||||||
|
try t.print(alloc, 'C');
|
||||||
|
t.carriageReturn();
|
||||||
|
t.linefeed(alloc);
|
||||||
|
try t.print(alloc, 'D');
|
||||||
|
|
||||||
|
t.cursorUp(2);
|
||||||
|
t.deleteLines(alloc, 1);
|
||||||
|
|
||||||
|
try t.print(alloc, 'E');
|
||||||
|
t.carriageReturn();
|
||||||
|
t.linefeed(alloc);
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("A\nE\nD\n", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -47,7 +47,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||||||
//log.debug("char: {}", .{c});
|
//log.debug("char: {}", .{c});
|
||||||
const actions = self.parser.next(c);
|
const actions = self.parser.next(c);
|
||||||
for (actions) |action_opt| {
|
for (actions) |action_opt| {
|
||||||
//if (action_opt) |action| log.info("action: {}", .{action});
|
if (action_opt) |action| log.info("action: {}", .{action});
|
||||||
switch (action_opt orelse continue) {
|
switch (action_opt orelse continue) {
|
||||||
.print => |p| if (@hasDecl(T, "print")) try self.handler.print(p),
|
.print => |p| if (@hasDecl(T, "print")) try self.handler.print(p),
|
||||||
.execute => |code| try self.execute(code),
|
.execute => |code| try self.execute(code),
|
||||||
|
Reference in New Issue
Block a user