mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
@ -256,7 +256,10 @@ pub fn expandPath(alloc: Allocator, cmd: []const u8) !?[]u8 {
|
|||||||
const full_path = path_buf[0..path_len :0];
|
const full_path = path_buf[0..path_len :0];
|
||||||
|
|
||||||
// Stat it
|
// Stat it
|
||||||
const f = std.fs.openFileAbsolute(full_path, .{}) catch |err| switch (err) {
|
const f = std.fs.cwd().openFile(
|
||||||
|
full_path,
|
||||||
|
.{},
|
||||||
|
) catch |err| switch (err) {
|
||||||
error.FileNotFound => continue,
|
error.FileNotFound => continue,
|
||||||
error.AccessDenied => {
|
error.AccessDenied => {
|
||||||
// Accumulate this and return it later so we can try other
|
// Accumulate this and return it later so we can try other
|
||||||
|
@ -9,7 +9,7 @@ const Config = @import("../config.zig").Config;
|
|||||||
pub const Message = union(enum) {
|
pub const Message = union(enum) {
|
||||||
/// Represents a write request. Magic number comes from the max size
|
/// Represents a write request. Magic number comes from the max size
|
||||||
/// we want this union to be.
|
/// we want this union to be.
|
||||||
pub const WriteReq = termio.MessageData(u8, 256);
|
pub const WriteReq = termio.MessageData(u8, 255);
|
||||||
|
|
||||||
/// Set the title of the surface.
|
/// Set the title of the surface.
|
||||||
/// TODO: we should change this to a "WriteReq" style structure in
|
/// TODO: we should change this to a "WriteReq" style structure in
|
||||||
|
@ -378,7 +378,11 @@ fn doAction(self: *Parser, action: TransitionAction, c: u8) ?Action {
|
|||||||
self.param_acc *|= 10;
|
self.param_acc *|= 10;
|
||||||
}
|
}
|
||||||
self.param_acc +|= c - '0';
|
self.param_acc +|= c - '0';
|
||||||
self.param_acc_idx += 1;
|
|
||||||
|
// Increment our accumulator index. If we overflow then
|
||||||
|
// we're out of bounds and we exit immediately.
|
||||||
|
self.param_acc_idx, const overflow = @addWithOverflow(self.param_acc_idx, 1);
|
||||||
|
if (overflow > 0) break :param null;
|
||||||
|
|
||||||
// The client is expected to perform no action.
|
// The client is expected to perform no action.
|
||||||
break :param null;
|
break :param null;
|
||||||
@ -388,6 +392,9 @@ fn doAction(self: *Parser, action: TransitionAction, c: u8) ?Action {
|
|||||||
break :osc_put null;
|
break :osc_put null;
|
||||||
},
|
},
|
||||||
.csi_dispatch => csi_dispatch: {
|
.csi_dispatch => csi_dispatch: {
|
||||||
|
// Ignore too many parameters
|
||||||
|
if (self.params_idx >= MAX_PARAMS) break :csi_dispatch null;
|
||||||
|
|
||||||
// Finalize parameters if we have one
|
// Finalize parameters if we have one
|
||||||
if (self.param_acc_idx > 0) {
|
if (self.param_acc_idx > 0) {
|
||||||
self.params[self.params_idx] = self.param_acc;
|
self.params[self.params_idx] = self.param_acc;
|
||||||
@ -904,3 +911,22 @@ test "csi followed by utf8" {
|
|||||||
try testing.expect(a[2] == null);
|
try testing.expect(a[2] == null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "csi: too many params" {
|
||||||
|
var p = init();
|
||||||
|
_ = p.next(0x1B);
|
||||||
|
_ = p.next('[');
|
||||||
|
for (0..100) |_| {
|
||||||
|
_ = p.next('1');
|
||||||
|
_ = p.next(';');
|
||||||
|
}
|
||||||
|
_ = p.next('1');
|
||||||
|
|
||||||
|
{
|
||||||
|
const a = p.next('C');
|
||||||
|
try testing.expect(p.state == .ground);
|
||||||
|
try testing.expect(a[0] == null);
|
||||||
|
try testing.expect(a[1] == null);
|
||||||
|
try testing.expect(a[2] == null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -969,43 +969,52 @@ pub fn Stream(comptime Handler: type) type {
|
|||||||
.change_window_title => |title| {
|
.change_window_title => |title| {
|
||||||
if (@hasDecl(T, "changeWindowTitle")) {
|
if (@hasDecl(T, "changeWindowTitle")) {
|
||||||
try self.handler.changeWindowTitle(title);
|
try self.handler.changeWindowTitle(title);
|
||||||
|
return;
|
||||||
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
||||||
},
|
},
|
||||||
|
|
||||||
.clipboard_contents => |clip| {
|
.clipboard_contents => |clip| {
|
||||||
if (@hasDecl(T, "clipboardContents")) {
|
if (@hasDecl(T, "clipboardContents")) {
|
||||||
try self.handler.clipboardContents(clip.kind, clip.data);
|
try self.handler.clipboardContents(clip.kind, clip.data);
|
||||||
|
return;
|
||||||
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
||||||
},
|
},
|
||||||
|
|
||||||
.prompt_start => |v| {
|
.prompt_start => |v| {
|
||||||
if (@hasDecl(T, "promptStart")) switch (v.kind) {
|
if (@hasDecl(T, "promptStart")) {
|
||||||
|
switch (v.kind) {
|
||||||
.primary, .right => try self.handler.promptStart(v.aid, v.redraw),
|
.primary, .right => try self.handler.promptStart(v.aid, v.redraw),
|
||||||
.continuation => try self.handler.promptContinuation(v.aid),
|
.continuation => try self.handler.promptContinuation(v.aid),
|
||||||
|
}
|
||||||
|
return;
|
||||||
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
||||||
},
|
},
|
||||||
|
|
||||||
.prompt_end => {
|
.prompt_end => {
|
||||||
if (@hasDecl(T, "promptEnd")) {
|
if (@hasDecl(T, "promptEnd")) {
|
||||||
try self.handler.promptEnd();
|
try self.handler.promptEnd();
|
||||||
|
return;
|
||||||
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
||||||
},
|
},
|
||||||
|
|
||||||
.end_of_input => {
|
.end_of_input => {
|
||||||
if (@hasDecl(T, "endOfInput")) {
|
if (@hasDecl(T, "endOfInput")) {
|
||||||
try self.handler.endOfInput();
|
try self.handler.endOfInput();
|
||||||
|
return;
|
||||||
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
||||||
},
|
},
|
||||||
|
|
||||||
.end_of_command => |end| {
|
.end_of_command => |end| {
|
||||||
if (@hasDecl(T, "endOfCommand")) {
|
if (@hasDecl(T, "endOfCommand")) {
|
||||||
try self.handler.endOfCommand(end.exit_code);
|
try self.handler.endOfCommand(end.exit_code);
|
||||||
|
return;
|
||||||
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
||||||
},
|
},
|
||||||
|
|
||||||
.report_pwd => |v| {
|
.report_pwd => |v| {
|
||||||
if (@hasDecl(T, "reportPwd")) {
|
if (@hasDecl(T, "reportPwd")) {
|
||||||
try self.handler.reportPwd(v.value);
|
try self.handler.reportPwd(v.value);
|
||||||
|
return;
|
||||||
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1017,12 +1026,14 @@ pub fn Stream(comptime Handler: type) type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
try self.handler.setMouseShape(shape);
|
try self.handler.setMouseShape(shape);
|
||||||
|
return;
|
||||||
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
||||||
},
|
},
|
||||||
|
|
||||||
.report_default_color => |v| {
|
.report_default_color => |v| {
|
||||||
if (@hasDecl(T, "reportDefaultColor")) {
|
if (@hasDecl(T, "reportDefaultColor")) {
|
||||||
try self.handler.reportDefaultColor(v.kind, v.terminator);
|
try self.handler.reportDefaultColor(v.kind, v.terminator);
|
||||||
|
return;
|
||||||
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1031,6 +1042,13 @@ pub fn Stream(comptime Handler: type) type {
|
|||||||
else
|
else
|
||||||
log.warn("unimplemented OSC command: {}", .{cmd}),
|
log.warn("unimplemented OSC command: {}", .{cmd}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fall through for when we don't have a handler.
|
||||||
|
if (@hasDecl(T, "oscUnimplemented")) {
|
||||||
|
try self.handler.oscUnimplemented(cmd);
|
||||||
|
} else {
|
||||||
|
log.warn("unimplemented OSC command: {s}", .{@tagName(cmd)});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configureCharset(
|
fn configureCharset(
|
||||||
@ -1598,3 +1616,28 @@ test "stream: insert characters" {
|
|||||||
for ("\x1B[?42@") |c| try s.next(c);
|
for ("\x1B[?42@") |c| try s.next(c);
|
||||||
try testing.expect(!s.handler.called);
|
try testing.expect(!s.handler.called);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "stream: too many csi params" {
|
||||||
|
const H = struct {
|
||||||
|
pub fn setCursorRight(self: *@This(), v: u16) !void {
|
||||||
|
_ = v;
|
||||||
|
_ = self;
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var s: Stream(H) = .{ .handler = .{} };
|
||||||
|
try s.nextSlice("\x1B[1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1C");
|
||||||
|
}
|
||||||
|
|
||||||
|
test "stream: csi param too long" {
|
||||||
|
const H = struct {
|
||||||
|
pub fn setCursorRight(self: *@This(), v: u16) !void {
|
||||||
|
_ = v;
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var s: Stream(H) = .{ .handler = .{} };
|
||||||
|
try s.nextSlice("\x1B[1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111C");
|
||||||
|
}
|
||||||
|
@ -90,8 +90,9 @@ pub fn MessageData(comptime Elem: type, comptime small_size: comptime_int) type
|
|||||||
pub const Small = struct {
|
pub const Small = struct {
|
||||||
pub const Max = small_size;
|
pub const Max = small_size;
|
||||||
pub const Array = [Max]Elem;
|
pub const Array = [Max]Elem;
|
||||||
|
pub const Len = std.math.IntFittingRange(0, small_size);
|
||||||
data: Array = undefined,
|
data: Array = undefined,
|
||||||
len: u8 = 0,
|
len: Len = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Alloc = struct {
|
pub const Alloc = struct {
|
||||||
@ -182,3 +183,14 @@ test "MessageData init alloc" {
|
|||||||
try testing.expect(io == .alloc);
|
try testing.expect(io == .alloc);
|
||||||
io.alloc.alloc.free(io.alloc.data);
|
io.alloc.alloc.free(io.alloc.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "MessageData small fits non-u8 sized data" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
const len = 500;
|
||||||
|
const Data = MessageData(u8, len);
|
||||||
|
const input: []const u8 = "X" ** len;
|
||||||
|
const io = try Data.init(alloc, input);
|
||||||
|
try testing.expect(io == .small);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user