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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
const std = @import("std");
const vaxis = @import("vaxis");
const ghostty_vt = @import("ghostty-vt");
extern "c" fn forkpty(
amaster: *c_int,
name: ?[*:0]u8,
termp: ?*const anyopaque,
winp: ?*const std.posix.winsize,
) c_int;
extern "c" fn execvp(
file: [*:0]const u8,
argv: [*:null]const ?[*:0]const u8,
) c_int;
// basic file navigation
// basic shell io
// basic layouting: for now following acme and ad
// * /home/goblin/05-genizah/plan9port/src/cmd/acme
// * /home/goblin/05-genizah/ad
// * /usr/lib/zig
// * ../03-plano
// right click and enter on lines to open files at specified lines
pub const Command = struct {
prev: ?*Command = null,
pub var value: union(enum) {
close,
ping,
nop,
quit,
tick,
key_press: vaxis.Key,
winsize: vaxis.Winsize,
mouse: vaxis.Mouse,
} = .nop;
};
const Loop = vaxis.Loop(@TypeOf(Command.value));
const MAX_FILES: usize = 0x200;
fn ticker(io: std.Io, loop: *Loop) void {
while (true) {
io.sleep(.fromMilliseconds(2), .awake) catch return;
_ = loop.tryPostEvent(.tick) catch return;
}
}
fn fork_pty(argv: [:0]const u8, ws: std.posix.winsize) std.Io.File {
var master: c_int = undefined;
const pid = forkpty(&master, null, null, &ws);
if (pid == 0) {
_ = execvp(argv, &.{});
std.process.exit(0);
}
// not sure about the false here
const f: std.Io.File = .{ .handle = master, .flags = .{ .nonblocking = false } };
return f;
}
const nrows = 16;
const ncols = 80;
pub fn main(init: std.process.Init) !void {
const io = init.io;
const gpa = init.gpa;
var term: ghostty_vt.Terminal = try .init(gpa, .{
.cols = ncols,
.rows = nrows,
});
defer term.deinit(gpa);
var tty_reader = term.vtStream();
defer tty_reader.deinit();
// const str = try term.plainString(gpa);
var tty_buf: [0x10000]u8 = undefined;
var tty = try vaxis.Tty.init(io, &tty_buf);
var vx = try vaxis.init(io, gpa, init.environ_map, .{});
defer vx.deinit(gpa, tty.writer());
const pty_master = fork_pty("/usr/bin/bash", .{
.row = nrows,
.col = ncols,
.xpixel = 0,
.ypixel = 0,
});
var write_buf: [0x100]u8 = undefined;
var writer = pty_master.writer(io, &write_buf);
std.debug.print("written {}\n", .{try writer.interface.write("ls -la /\r\n")});
try writer.flush();
var read_buf: [0x400]u8 = undefined;
var reader = pty_master.readerStreaming(io, &read_buf);
try io.sleep(.fromMilliseconds(200), .real);
const str = try reader.interface.readAlloc(gpa, 0x400);
tty_reader.nextSlice(str);
defer gpa.free(str);
const tty_str = try term.plainString(gpa);
defer gpa.free(tty_str);
// std.debug.print("{s}", .{tty_str});
// try vx.setMouseMode(tty.writer(), true);
var loop: Loop = .init(io, &tty, &vx);
try loop.start();
defer loop.stop();
while (true) {
const event = try loop.nextEvent();
const win = vx.window();
const win_child = win.child(.{
.border = .{ .where = .all },
.height = nrows,
.width = ncols,
});
_ = win_child.printSegment(.{ .text = tty_str }, .{});
switch (event) {
.key_press => |key| {
if (key.matches('c', .{ .ctrl = true })) {
break;
}
},
.winsize => |ws| try vx.resize(gpa, tty.writer(), ws),
else => {},
}
try vx.render(tty.writer());
}
}
|