mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
basic "index" implementation
This commit is contained in:
@ -195,6 +195,33 @@ pub fn decaln(self: *Terminal) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Move the cursor to the next line in the scrolling region, possibly scrolling.
|
||||||
|
///
|
||||||
|
/// If the cursor is outside of the scrolling region: move the cursor one line
|
||||||
|
/// down if it is not on the bottom-most line of the screen.
|
||||||
|
///
|
||||||
|
/// If the cursor is inside the scrolling region:
|
||||||
|
/// If the cursor is on the bottom-most line of the scrolling region:
|
||||||
|
/// invoke scroll up with amount=1
|
||||||
|
/// If the cursor is not on the bottom-most line of the scrolling region:
|
||||||
|
/// move the cursor one line down
|
||||||
|
///
|
||||||
|
/// This unsets the pending wrap state without wrapping.
|
||||||
|
pub fn index(self: *Terminal) void {
|
||||||
|
// TODO: outside of scrolling region
|
||||||
|
|
||||||
|
// If we're at the end of the screen, scroll up. This is surprisingly
|
||||||
|
// common because most terminals live with a full screen so we do this
|
||||||
|
// check first.
|
||||||
|
if (self.cursor.y == self.rows - 1) {
|
||||||
|
self.scrollUp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increase cursor by 1
|
||||||
|
self.cursor.y += 1;
|
||||||
|
}
|
||||||
|
|
||||||
/// Move the cursor to the previous line in the scrolling region, possibly
|
/// Move the cursor to the previous line in the scrolling region, possibly
|
||||||
/// scrolling.
|
/// scrolling.
|
||||||
///
|
///
|
||||||
@ -468,19 +495,7 @@ pub fn carriageReturn(self: *Terminal) void {
|
|||||||
|
|
||||||
/// Linefeed moves the cursor to the next line.
|
/// Linefeed moves the cursor to the next line.
|
||||||
pub fn linefeed(self: *Terminal) void {
|
pub fn linefeed(self: *Terminal) void {
|
||||||
const tracy = trace(@src());
|
self.index();
|
||||||
defer tracy.end();
|
|
||||||
|
|
||||||
// If we're at the end of the screen, scroll up. This is surprisingly
|
|
||||||
// common because most terminals live with a full screen so we do this
|
|
||||||
// check first.
|
|
||||||
if (self.cursor.y == self.rows - 1) {
|
|
||||||
self.scrollUp();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increase cursor by 1
|
|
||||||
self.cursor.y += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert amount lines at the current cursor row. The contents of the line
|
/// Insert amount lines at the current cursor row. The contents of the line
|
||||||
@ -998,6 +1013,39 @@ test "Terminal: reverseIndex from the top" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Terminal: index" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 2, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
t.index();
|
||||||
|
try t.print('A');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("\nA", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: index from the bottom" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 2, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
t.setCursorPos(5, 1);
|
||||||
|
try t.print('A');
|
||||||
|
t.index();
|
||||||
|
|
||||||
|
try t.print('B');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("\n\n\nA\nB", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test "Terminal: DECALN" {
|
test "Terminal: DECALN" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 2, 2);
|
var t = try init(alloc, 2, 2);
|
||||||
|
@ -97,7 +97,19 @@ pub fn Stream(comptime Handler: type) type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn csiDispatch(self: *Self, action: Parser.Action.CSI) !void {
|
fn csiDispatch(self: *Self, input: Parser.Action.CSI) !void {
|
||||||
|
// Handles aliases first
|
||||||
|
const action = switch (input.final) {
|
||||||
|
// Alias for set cursor position
|
||||||
|
'f' => blk: {
|
||||||
|
var copy = input;
|
||||||
|
copy.final = 'H';
|
||||||
|
break :blk copy;
|
||||||
|
},
|
||||||
|
|
||||||
|
else => input,
|
||||||
|
};
|
||||||
|
|
||||||
switch (action.final) {
|
switch (action.final) {
|
||||||
// CUU - Cursor Up
|
// CUU - Cursor Up
|
||||||
'A' => if (@hasDecl(T, "setCursorUp")) try self.handler.setCursorUp(
|
'A' => if (@hasDecl(T, "setCursorUp")) try self.handler.setCursorUp(
|
||||||
@ -281,16 +293,6 @@ pub fn Stream(comptime Handler: type) type {
|
|||||||
},
|
},
|
||||||
) else log.warn("unimplemented CSI callback: {}", .{action}),
|
) else log.warn("unimplemented CSI callback: {}", .{action}),
|
||||||
|
|
||||||
// Alias for set cursor position (H)
|
|
||||||
'f' => {
|
|
||||||
var alias = action;
|
|
||||||
alias.final = 'H';
|
|
||||||
|
|
||||||
// Try would be better here but recursive try on
|
|
||||||
// inferred error sets are not allowed.
|
|
||||||
return self.csiDispatch(alias);
|
|
||||||
},
|
|
||||||
|
|
||||||
// SM - Set Mode
|
// SM - Set Mode
|
||||||
'h' => if (@hasDecl(T, "setMode")) {
|
'h' => if (@hasDecl(T, "setMode")) {
|
||||||
for (action.params) |mode|
|
for (action.params) |mode|
|
||||||
|
Reference in New Issue
Block a user