mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
terminal: reverse index xterm audit
This commit is contained in:
@ -973,15 +973,15 @@ pub fn reverseIndex(self: *Terminal) !void {
|
|||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
// If the cursor is on the top-most line of the scroll region or
|
if (self.screen.cursor.y != self.scrolling_region.top or
|
||||||
// its on the top of the screen we scroll down.
|
self.screen.cursor.x < self.scrolling_region.left or
|
||||||
if (self.screen.cursor.y == self.scrolling_region.top or
|
self.screen.cursor.x > self.scrolling_region.right)
|
||||||
self.screen.cursor.y == 0)
|
|
||||||
{
|
{
|
||||||
try self.scrollDown(1);
|
self.cursorUp(1);
|
||||||
} else {
|
return;
|
||||||
self.screen.cursor.y -|= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try self.scrollDown(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set Cursor Position. Move cursor to the position indicated
|
// Set Cursor Position. Move cursor to the position indicated
|
||||||
@ -3346,6 +3346,134 @@ test "Terminal: reverseIndex top of scrolling region" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Terminal: reverseIndex top of screen" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
try t.print('A');
|
||||||
|
t.setCursorPos(2, 1);
|
||||||
|
try t.print('B');
|
||||||
|
t.setCursorPos(3, 1);
|
||||||
|
try t.print('C');
|
||||||
|
t.setCursorPos(1, 1);
|
||||||
|
try t.reverseIndex();
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("X\nA\nB\nC", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: reverseIndex not top of screen" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
try t.print('A');
|
||||||
|
t.setCursorPos(2, 1);
|
||||||
|
try t.print('B');
|
||||||
|
t.setCursorPos(3, 1);
|
||||||
|
try t.print('C');
|
||||||
|
t.setCursorPos(2, 1);
|
||||||
|
try t.reverseIndex();
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("X\nB\nC", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: reverseIndex top/bottom margins" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
try t.print('A');
|
||||||
|
t.setCursorPos(2, 1);
|
||||||
|
try t.print('B');
|
||||||
|
t.setCursorPos(3, 1);
|
||||||
|
try t.print('C');
|
||||||
|
t.setTopAndBottomMargin(2, 3);
|
||||||
|
t.setCursorPos(2, 1);
|
||||||
|
try t.reverseIndex();
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("A\n\nB", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: reverseIndex outside top/bottom margins" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
try t.print('A');
|
||||||
|
t.setCursorPos(2, 1);
|
||||||
|
try t.print('B');
|
||||||
|
t.setCursorPos(3, 1);
|
||||||
|
try t.print('C');
|
||||||
|
t.setTopAndBottomMargin(2, 3);
|
||||||
|
t.setCursorPos(1, 1);
|
||||||
|
try t.reverseIndex();
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("A\nB\nC", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: reverseIndex left/right margins" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
try t.printString("ABC");
|
||||||
|
t.setCursorPos(2, 1);
|
||||||
|
try t.printString("DEF");
|
||||||
|
t.setCursorPos(3, 1);
|
||||||
|
try t.printString("GHI");
|
||||||
|
t.modes.set(.enable_left_and_right_margin, true);
|
||||||
|
t.setLeftAndRightMargin(2, 3);
|
||||||
|
t.setCursorPos(1, 2);
|
||||||
|
try t.reverseIndex();
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("A\nDBC\nGEF\n HI", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: reverseIndex outside left/right margins" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
try t.printString("ABC");
|
||||||
|
t.setCursorPos(2, 1);
|
||||||
|
try t.printString("DEF");
|
||||||
|
t.setCursorPos(3, 1);
|
||||||
|
try t.printString("GHI");
|
||||||
|
t.modes.set(.enable_left_and_right_margin, true);
|
||||||
|
t.setLeftAndRightMargin(2, 3);
|
||||||
|
t.setCursorPos(1, 1);
|
||||||
|
try t.reverseIndex();
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("ABC\nDEF\nGHI", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test "Terminal: index" {
|
test "Terminal: index" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 2, 5);
|
var t = try init(alloc, 2, 5);
|
||||||
|
138
website/app/vt/ri/page.mdx
Normal file
138
website/app/vt/ri/page.mdx
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import VTSequence from "@/components/VTSequence";
|
||||||
|
|
||||||
|
# Reverse Index (RI)
|
||||||
|
|
||||||
|
<VTSequence sequence={["ESC", "M"]} />
|
||||||
|
|
||||||
|
Move the cursor up one cell, scrolling if necessary.
|
||||||
|
|
||||||
|
This sequence does not unset the pending wrap state.
|
||||||
|
|
||||||
|
If the cursor is exactly on the [top margin](/vt/decstbm) and is within
|
||||||
|
[left and right margins](/vt/decslrm), invoke [scroll down (SD)](/vt/sd)
|
||||||
|
with `n = 1`. The operation is complete.
|
||||||
|
|
||||||
|
Otherwise, scrolling isn't necessary. Perform a
|
||||||
|
[cursor up](/vt/cuu) operation with `n = 1`.
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
### RI V-1: No Scroll Region, Top of Screen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "A\n"
|
||||||
|
printf "B\n"
|
||||||
|
printf "C\n"
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033M" # reverse index
|
||||||
|
printf "X"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|Xc________|
|
||||||
|
|A_________|
|
||||||
|
|B_________|
|
||||||
|
|C_________|
|
||||||
|
```
|
||||||
|
|
||||||
|
### RI V-2: No Scroll Region, Not Top of Screen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "A\n"
|
||||||
|
printf "B\n"
|
||||||
|
printf "C\n"
|
||||||
|
printf "\033[2;1H"
|
||||||
|
printf "\033M" # reverse index
|
||||||
|
printf "X"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|Xc________|
|
||||||
|
|B_________|
|
||||||
|
|C_________|
|
||||||
|
```
|
||||||
|
|
||||||
|
### RI V-3: Top/Bottom Scroll Region
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "A\n"
|
||||||
|
printf "B\n"
|
||||||
|
printf "C\n"
|
||||||
|
printf "\033[2;3r" # scroll region
|
||||||
|
printf "\033[2;1H"
|
||||||
|
printf "\033M" # reverse index
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|A_________|
|
||||||
|
|c_________|
|
||||||
|
|B_________|
|
||||||
|
```
|
||||||
|
|
||||||
|
### RI V-4: Outside of Top/Bottom Scroll Region
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "A\n"
|
||||||
|
printf "B\n"
|
||||||
|
printf "C\n"
|
||||||
|
printf "\033[2;3r" # scroll region
|
||||||
|
printf "\033[1;1H"
|
||||||
|
printf "\033M" # reverse index
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|A_________|
|
||||||
|
|B_________|
|
||||||
|
|C_________|
|
||||||
|
```
|
||||||
|
|
||||||
|
### RI V-5: Left/Right Scroll Region
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "ABC\n"
|
||||||
|
printf "DEF\n"
|
||||||
|
printf "GHI\n"
|
||||||
|
printf "\033[?69h" # enable left/right margins
|
||||||
|
printf "\033[2;3s" # scroll region left/right
|
||||||
|
printf "\033[1;2H"
|
||||||
|
printf "\033M"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|A_________|
|
||||||
|
|DBC_______|
|
||||||
|
|GEF_______|
|
||||||
|
|_HI_______|
|
||||||
|
```
|
||||||
|
|
||||||
|
### RI V-6: Outside Left/Right Scroll Region
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "ABC\n"
|
||||||
|
printf "DEF\n"
|
||||||
|
printf "GHI\n"
|
||||||
|
printf "\033[?69h" # enable left/right margins
|
||||||
|
printf "\033[2;3s" # scroll region left/right
|
||||||
|
printf "\033[2;1H"
|
||||||
|
printf "\033M"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|ABC_______|
|
||||||
|
|DEF_______|
|
||||||
|
|GHI_______|
|
||||||
|
```
|
||||||
|
|
||||||
|
Cursor on the `A`.
|
Reference in New Issue
Block a user