mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
typing jumps scroll to bottom
This commit is contained in:
2
TODO.md
2
TODO.md
@ -1,6 +1,8 @@
|
|||||||
Bugs:
|
Bugs:
|
||||||
|
|
||||||
* Underline should use freetype underline thickness hint
|
* Underline should use freetype underline thickness hint
|
||||||
|
* Any printing action forces scroll to jump to bottom, this makes it impossible
|
||||||
|
to scroll up while logs are coming in or something
|
||||||
|
|
||||||
Performance:
|
Performance:
|
||||||
|
|
||||||
|
@ -121,6 +121,15 @@ pub fn deinit(self: *Screen, alloc: Allocator) void {
|
|||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This returns true if the display area is anchored at the bottom currently.
|
||||||
|
pub fn displayIsBottom(self: Screen) bool {
|
||||||
|
return self.visible_offset == self.bottomOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bottomOffset(self: Screen) usize {
|
||||||
|
return self.bottom - self.rows;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns an iterator that can be used to iterate over all of the rows
|
/// Returns an iterator that can be used to iterate over all of the rows
|
||||||
/// from index zero.
|
/// from index zero.
|
||||||
pub fn rowIterator(self: *const Screen) RowIterator {
|
pub fn rowIterator(self: *const Screen) RowIterator {
|
||||||
@ -429,7 +438,12 @@ test "Screen: scrolling" {
|
|||||||
var s = try init(alloc, 3, 5, 0);
|
var s = try init(alloc, 3, 5, 0);
|
||||||
defer s.deinit(alloc);
|
defer s.deinit(alloc);
|
||||||
s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
||||||
|
|
||||||
|
try testing.expect(s.displayIsBottom());
|
||||||
|
|
||||||
|
// Scroll down, should still be bottom
|
||||||
s.scroll(.{ .delta = 1 });
|
s.scroll(.{ .delta = 1 });
|
||||||
|
try testing.expect(s.displayIsBottom());
|
||||||
|
|
||||||
// Test our row index
|
// Test our row index
|
||||||
try testing.expectEqual(@as(usize, 5), s.rowIndex(0));
|
try testing.expectEqual(@as(usize, 5), s.rowIndex(0));
|
||||||
@ -462,6 +476,7 @@ test "Screen: scroll down from 0" {
|
|||||||
defer s.deinit(alloc);
|
defer s.deinit(alloc);
|
||||||
s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
||||||
s.scroll(.{ .delta = -1 });
|
s.scroll(.{ .delta = -1 });
|
||||||
|
try testing.expect(s.displayIsBottom());
|
||||||
|
|
||||||
{
|
{
|
||||||
// Test our contents rotated
|
// Test our contents rotated
|
||||||
@ -494,6 +509,7 @@ test "Screen: scrollback" {
|
|||||||
|
|
||||||
// Scrolling to the bottom
|
// Scrolling to the bottom
|
||||||
s.scroll(.{ .bottom = {} });
|
s.scroll(.{ .bottom = {} });
|
||||||
|
try testing.expect(s.displayIsBottom());
|
||||||
|
|
||||||
{
|
{
|
||||||
// Test our contents rotated
|
// Test our contents rotated
|
||||||
@ -504,6 +520,7 @@ test "Screen: scrollback" {
|
|||||||
|
|
||||||
// Scrolling back should make it visible again
|
// Scrolling back should make it visible again
|
||||||
s.scroll(.{ .delta = -1 });
|
s.scroll(.{ .delta = -1 });
|
||||||
|
try testing.expect(!s.displayIsBottom());
|
||||||
|
|
||||||
{
|
{
|
||||||
// Test our contents rotated
|
// Test our contents rotated
|
||||||
|
@ -203,6 +203,9 @@ pub fn print(self: *Terminal, c: u21) !void {
|
|||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
|
// If we're not at the bottom, then we need to move there
|
||||||
|
if (!self.screen.displayIsBottom()) self.screen.scroll(.{ .bottom = {} });
|
||||||
|
|
||||||
// If we're soft-wrapping, then handle that first.
|
// If we're soft-wrapping, then handle that first.
|
||||||
if (self.cursor.pending_wrap and self.mode_autowrap) {
|
if (self.cursor.pending_wrap and self.mode_autowrap) {
|
||||||
// Mark that the cell is wrapped, which guarantees that there is
|
// Mark that the cell is wrapped, which guarantees that there is
|
||||||
@ -691,12 +694,15 @@ pub fn scrollDown(self: *Terminal, count: usize) void {
|
|||||||
|
|
||||||
/// Options for scrolling the viewport of the terminal grid.
|
/// Options for scrolling the viewport of the terminal grid.
|
||||||
pub const ScrollViewport = union(enum) {
|
pub const ScrollViewport = union(enum) {
|
||||||
|
/// Scroll to the top of the scrollback
|
||||||
|
top: void,
|
||||||
delta: isize,
|
delta: isize,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Scroll the viewport of the terminal grid.
|
/// Scroll the viewport of the terminal grid.
|
||||||
pub fn scrollViewport(self: *Terminal, behavior: ScrollViewport) void {
|
pub fn scrollViewport(self: *Terminal, behavior: ScrollViewport) void {
|
||||||
self.screen.scroll(switch (behavior) {
|
self.screen.scroll(switch (behavior) {
|
||||||
|
.top => .{ .top = {} },
|
||||||
.delta => |delta| .{ .delta_no_grow = delta },
|
.delta => |delta| .{ .delta_no_grow = delta },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -766,6 +772,41 @@ test "Terminal: soft wrap" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Terminal: print scrolls back to bottom" {
|
||||||
|
var t = try init(testing.allocator, 5, 2);
|
||||||
|
defer t.deinit(testing.allocator);
|
||||||
|
|
||||||
|
// Basic grid writing
|
||||||
|
for ("hello") |c| try t.print(c);
|
||||||
|
|
||||||
|
// Make newlines so we create scrollback
|
||||||
|
// 3 pushes hello off the screen
|
||||||
|
t.index();
|
||||||
|
t.index();
|
||||||
|
t.index();
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scroll to the top
|
||||||
|
t.scrollViewport(.{ .top = {} });
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("hello", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type
|
||||||
|
try t.print('A');
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("\nA", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test "Terminal: linefeed and carriage return" {
|
test "Terminal: linefeed and carriage return" {
|
||||||
var t = try init(testing.allocator, 80, 80);
|
var t = try init(testing.allocator, 80, 80);
|
||||||
defer t.deinit(testing.allocator);
|
defer t.deinit(testing.allocator);
|
||||||
|
Reference in New Issue
Block a user