mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 07:46:12 +03:00
terminal: Screen.promptPath
This commit is contained in:
@ -1922,6 +1922,39 @@ pub fn selectPrompt(self: *Screen, pt: point.ScreenPoint) ?Selection {
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the change in x/y that is needed to reach "to" from "from"
|
||||
/// within a prompt. If "to" is before or after the prompt bounds then
|
||||
/// the result will be bounded to the prompt.
|
||||
///
|
||||
/// This feature requires shell integration. If shell integration is not
|
||||
/// enabled, this will always return zero for both x and y (no path).
|
||||
pub fn promptPath(
|
||||
self: *Screen,
|
||||
from: point.ScreenPoint,
|
||||
to: point.ScreenPoint,
|
||||
) struct {
|
||||
x: isize,
|
||||
y: isize,
|
||||
} {
|
||||
// Get our prompt bounds assuming "from" is at a prompt.
|
||||
const bounds = self.selectPrompt(from) orelse return .{ .x = 0, .y = 0 };
|
||||
|
||||
// Get our actual "to" point clamped to the bounds of the prompt.
|
||||
const to_clamped = if (bounds.contains(to))
|
||||
to
|
||||
else if (to.before(bounds.start))
|
||||
bounds.start
|
||||
else
|
||||
bounds.end;
|
||||
|
||||
// Basic math to calculate our path.
|
||||
const from_x: isize = @intCast(from.x);
|
||||
const from_y: isize = @intCast(from.y);
|
||||
const to_x: isize = @intCast(to_clamped.x);
|
||||
const to_y: isize = @intCast(to_clamped.y);
|
||||
return .{ .x = to_x - from_x, .y = to_y - from_y };
|
||||
}
|
||||
|
||||
/// Scroll behaviors for the scroll function.
|
||||
pub const Scroll = union(enum) {
|
||||
/// Scroll to the top of the scroll buffer. The first line of the
|
||||
@ -4722,6 +4755,7 @@ test "Screen: selectOutput" {
|
||||
try s.testWriteString("output3\n"); // 8
|
||||
try s.testWriteString("output3"); // 9
|
||||
}
|
||||
// zig fmt: on
|
||||
|
||||
var row = s.getRow(.{ .screen = 2 });
|
||||
row.setSemanticPrompt(.prompt);
|
||||
@ -4794,6 +4828,7 @@ test "Screen: selectPrompt basics" {
|
||||
try s.testWriteString("output3\n"); // 8
|
||||
try s.testWriteString("output3"); // 9
|
||||
}
|
||||
// zig fmt: on
|
||||
|
||||
var row = s.getRow(.{ .screen = 2 });
|
||||
row.setSemanticPrompt(.prompt);
|
||||
@ -4850,6 +4885,7 @@ test "Screen: selectPrompt prompt at start" {
|
||||
try s.testWriteString("output2\n"); // 2
|
||||
try s.testWriteString("output2\n"); // 3
|
||||
}
|
||||
// zig fmt: on
|
||||
|
||||
var row = s.getRow(.{ .screen = 0 });
|
||||
row.setSemanticPrompt(.prompt);
|
||||
@ -4887,6 +4923,7 @@ test "Screen: selectPrompt prompt at end" {
|
||||
try s.testWriteString("prompt1\n"); // 2
|
||||
try s.testWriteString("input1\n"); // 3
|
||||
}
|
||||
// zig fmt: on
|
||||
|
||||
var row = s.getRow(.{ .screen = 2 });
|
||||
row.setSemanticPrompt(.prompt);
|
||||
@ -4909,6 +4946,91 @@ test "Screen: selectPrompt prompt at end" {
|
||||
}
|
||||
}
|
||||
|
||||
test "Screen: promtpPath" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var s = try init(alloc, 15, 10, 0);
|
||||
defer s.deinit();
|
||||
|
||||
// zig fmt: off
|
||||
{
|
||||
// line number:
|
||||
try s.testWriteString("output1\n"); // 0
|
||||
try s.testWriteString("output1\n"); // 1
|
||||
try s.testWriteString("prompt2\n"); // 2
|
||||
try s.testWriteString("input2\n"); // 3
|
||||
try s.testWriteString("output2\n"); // 4
|
||||
try s.testWriteString("output2\n"); // 5
|
||||
try s.testWriteString("prompt3$ input3\n"); // 6
|
||||
try s.testWriteString("output3\n"); // 7
|
||||
try s.testWriteString("output3\n"); // 8
|
||||
try s.testWriteString("output3"); // 9
|
||||
}
|
||||
// zig fmt: on
|
||||
|
||||
var row = s.getRow(.{ .screen = 2 });
|
||||
row.setSemanticPrompt(.prompt);
|
||||
row = s.getRow(.{ .screen = 3 });
|
||||
row.setSemanticPrompt(.input);
|
||||
row = s.getRow(.{ .screen = 4 });
|
||||
row.setSemanticPrompt(.command);
|
||||
row = s.getRow(.{ .screen = 6 });
|
||||
row.setSemanticPrompt(.input);
|
||||
row = s.getRow(.{ .screen = 7 });
|
||||
row.setSemanticPrompt(.command);
|
||||
|
||||
// From is not in the prompt
|
||||
{
|
||||
const path = s.promptPath(
|
||||
.{ .x = 0, .y = 1 },
|
||||
.{ .x = 0, .y = 2 },
|
||||
);
|
||||
try testing.expectEqual(@as(isize, 0), path.x);
|
||||
try testing.expectEqual(@as(isize, 0), path.y);
|
||||
}
|
||||
|
||||
// Same line
|
||||
{
|
||||
const path = s.promptPath(
|
||||
.{ .x = 6, .y = 2 },
|
||||
.{ .x = 3, .y = 2 },
|
||||
);
|
||||
try testing.expectEqual(@as(isize, -3), path.x);
|
||||
try testing.expectEqual(@as(isize, 0), path.y);
|
||||
}
|
||||
|
||||
// Different lines
|
||||
{
|
||||
const path = s.promptPath(
|
||||
.{ .x = 6, .y = 2 },
|
||||
.{ .x = 3, .y = 3 },
|
||||
);
|
||||
try testing.expectEqual(@as(isize, -3), path.x);
|
||||
try testing.expectEqual(@as(isize, 1), path.y);
|
||||
}
|
||||
|
||||
// To is out of bounds before
|
||||
{
|
||||
const path = s.promptPath(
|
||||
.{ .x = 6, .y = 2 },
|
||||
.{ .x = 3, .y = 1 },
|
||||
);
|
||||
try testing.expectEqual(@as(isize, -6), path.x);
|
||||
try testing.expectEqual(@as(isize, 0), path.y);
|
||||
}
|
||||
|
||||
// To is out of bounds after
|
||||
{
|
||||
const path = s.promptPath(
|
||||
.{ .x = 6, .y = 2 },
|
||||
.{ .x = 3, .y = 9 },
|
||||
);
|
||||
try testing.expectEqual(@as(isize, 3), path.x);
|
||||
try testing.expectEqual(@as(isize, 1), path.y);
|
||||
}
|
||||
}
|
||||
|
||||
test "Screen: scrollRegionUp single" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
@ -5647,7 +5769,6 @@ test "Screen: selectionString, rectangle, more complex w/breaks" {
|
||||
try testing.expectEqualStrings(expected, contents);
|
||||
}
|
||||
|
||||
|
||||
test "Screen: dirty with getCellPtr" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
Reference in New Issue
Block a user