aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/terminal/c/paste.zig
blob: bce6a5658d502fbc00ff8f29f6b633948825b346 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
const std = @import("std");
const lib = @import("../lib.zig");
const paste = @import("../../input/paste.zig");
const Result = @import("result.zig").Result;

pub fn is_safe(data: ?[*]const u8, len: usize) callconv(lib.calling_conv) bool {
    const slice: []const u8 = if (data) |v| v[0..len] else &.{};
    return paste.isSafe(slice);
}

pub fn encode(
    data: ?[*]u8,
    data_len: usize,
    bracketed: bool,
    out_: ?[*]u8,
    out_len: usize,
    out_written: *usize,
) callconv(lib.calling_conv) Result {
    const slice: []u8 = if (data) |v| v[0..data_len] else &.{};
    const result = paste.encode(slice, .{ .bracketed = bracketed });

    const total = result[0].len + result[1].len + result[2].len;
    out_written.* = total;

    const out: []u8 = if (out_) |o| o[0..out_len] else &.{};
    if (out.len < total) return .out_of_space;

    var offset: usize = 0;
    for (result) |segment| {
        @memcpy(out[offset..][0..segment.len], segment);
        offset += segment.len;
    }

    return .success;
}

test "encode bracketed" {
    const testing = std.testing;
    const input = try testing.allocator.dupe(u8, "hello");
    defer testing.allocator.free(input);
    var buf: [64]u8 = undefined;
    var written: usize = 0;
    const result = encode(input.ptr, input.len, true, &buf, buf.len, &written);
    try testing.expectEqual(.success, result);
    try testing.expectEqualStrings("\x1b[200~hello\x1b[201~", buf[0..written]);
}

test "encode unbracketed no newlines" {
    const testing = std.testing;
    const input = try testing.allocator.dupe(u8, "hello");
    defer testing.allocator.free(input);
    var buf: [64]u8 = undefined;
    var written: usize = 0;
    const result = encode(input.ptr, input.len, false, &buf, buf.len, &written);
    try testing.expectEqual(.success, result);
    try testing.expectEqualStrings("hello", buf[0..written]);
}

test "encode unbracketed newlines" {
    const testing = std.testing;
    const input = try testing.allocator.dupe(u8, "hello\nworld");
    defer testing.allocator.free(input);
    var buf: [64]u8 = undefined;
    var written: usize = 0;
    const result = encode(input.ptr, input.len, false, &buf, buf.len, &written);
    try testing.expectEqual(.success, result);
    try testing.expectEqualStrings("hello\rworld", buf[0..written]);
}

test "encode strip unsafe bytes" {
    const testing = std.testing;
    const input = try testing.allocator.dupe(u8, "hel\x1blo\x00world");
    defer testing.allocator.free(input);
    var buf: [64]u8 = undefined;
    var written: usize = 0;
    const result = encode(input.ptr, input.len, true, &buf, buf.len, &written);
    try testing.expectEqual(.success, result);
    try testing.expectEqualStrings("\x1b[200~hel lo world\x1b[201~", buf[0..written]);
}

test "encode with insufficient buffer" {
    const testing = std.testing;
    const input = try testing.allocator.dupe(u8, "hello");
    defer testing.allocator.free(input);
    var buf: [1]u8 = undefined;
    var written: usize = 0;
    const result = encode(input.ptr, input.len, true, &buf, buf.len, &written);
    try testing.expectEqual(.out_of_space, result);
    try testing.expectEqual(17, written);
}

test "encode with null buffer" {
    const testing = std.testing;
    const input = try testing.allocator.dupe(u8, "hello");
    defer testing.allocator.free(input);
    var written: usize = 0;
    const result = encode(input.ptr, input.len, true, null, 0, &written);
    try testing.expectEqual(.out_of_space, result);
    try testing.expectEqual(17, written);
}

test "is_safe with safe data" {
    const testing = std.testing;
    const safe = "hello world";
    try testing.expect(is_safe(safe.ptr, safe.len));
}

test "is_safe with newline" {
    const testing = std.testing;
    const unsafe = "hello\nworld";
    try testing.expect(!is_safe(unsafe.ptr, unsafe.len));
}

test "is_safe with bracketed paste end" {
    const testing = std.testing;
    const unsafe = "hello\x1b[201~world";
    try testing.expect(!is_safe(unsafe.ptr, unsafe.len));
}

test "is_safe with empty data" {
    const testing = std.testing;
    const empty = "";
    try testing.expect(is_safe(empty.ptr, 0));
}

test "is_safe with null empty data" {
    const testing = std.testing;
    try testing.expect(is_safe(null, 0));
}