terminfo: basic Source structure and can encode

This commit is contained in:
Mitchell Hashimoto
2023-06-23 19:22:16 -07:00
parent 8d40fba9ce
commit 3ec8ce8063
3 changed files with 111 additions and 0 deletions

View File

@ -190,6 +190,7 @@ test {
// Libraries
_ = @import("segmented_pool.zig");
_ = @import("terminal/main.zig");
_ = @import("terminfo/main.zig");
// TODO
_ = @import("blocking_queue.zig");

98
src/terminfo/Source.zig Normal file
View File

@ -0,0 +1,98 @@
//! Terminfo source format. This can be used to encode terminfo files.
//! This cannot parse terminfo source files yet because it isn't something
//! I need to do but this can be added later.
//!
//! Background: https://invisible-island.net/ncurses/man/terminfo.5.html
const Source = @This();
const std = @import("std");
/// The set of names for the terminal. These match the TERM environment variable
/// and are used to look up this terminal. Historically, the final name in the
/// list was the most common name for the terminal and contains spaces and
/// other characters. See terminfo(5) for details.
names: []const []const u8,
/// The set of capabilities in this terminfo file.
capabilities: []const Capability,
/// A capability in a terminfo file. This also includes any "use" capabilities
/// since they behave just like other capabilities as documented in terminfo(5).
pub const Capability = struct {
/// The name of capability. This is the "Cap-name" value in terminfo(5).
name: []const u8,
value: Value,
pub const Value = union(enum) {
/// Canceled value, i.e. suffixed with @
canceled: void,
/// Boolean values are always true if they exist so there is no value.
boolean: void,
/// Numeric values are always "unsigned decimal integers". The size
/// of the integer is unspecified in terminfo(5). I chose 32-bits
/// because it is a common integer size but this may be wrong.
numeric: u32,
string: []const u8,
};
};
/// Encode as a terminfo source file. The encoding is always done in a
/// human-readable format with whitespace. Fields are always written in the
/// order of the slices on this struct; this will not do any reordering.
pub fn encode(self: Source, writer: anytype) !void {
// Encode the names in the order specified
for (self.names, 0..) |name, i| {
if (i != 0) try writer.writeAll("|");
try writer.writeAll(name);
}
try writer.writeAll(",\n");
// Encode each of the capabilities in the order specified
for (self.capabilities) |cap| {
try writer.writeAll("\t");
try writer.writeAll(cap.name);
switch (cap.value) {
.canceled => try writer.writeAll("@"),
.boolean => {},
.numeric => |v| try writer.print("#{d}", .{v}),
.string => |v| try writer.print("={s}", .{v}),
}
try writer.writeAll(",\n");
}
}
test "encode" {
const src: Source = .{
.names = &.{
"ghostty",
"xterm-ghostty",
"Ghostty",
},
.capabilities = &.{
.{ .name = "am", .value = .{ .boolean = {} } },
.{ .name = "ccc", .value = .{ .canceled = {} } },
.{ .name = "colors", .value = .{ .numeric = 256 } },
.{ .name = "bel", .value = .{ .string = "^G" } },
},
};
// Encode
var buf: [1024]u8 = undefined;
var buf_stream = std.io.fixedBufferStream(&buf);
try src.encode(buf_stream.writer());
const expected =
\\ghostty|xterm-ghostty|Ghostty,
\\ am,
\\ ccc@,
\\ colors#256,
\\ bel=^G,
\\
;
try std.testing.expectEqualStrings(@as([]const u8, expected), buf_stream.getWritten());
}

12
src/terminfo/main.zig Normal file
View File

@ -0,0 +1,12 @@
//! Package terminfo provides functionality related to terminfo/termcap files.
//!
//! At the time of writing this comment, the focus is on generating terminfo
//! files so that we can maintain our terminfo in Zig instead of hand-writing
//! the archaic (imo) terminfo format by hand. But eventually we may want to
//! extract this into a more full-featured library on its own.
pub const Source = @import("Source.zig");
test {
@import("std").testing.refAllDecls(@This());
}