atleg

atleg is a zig library (with c & c++ bindings planned) offering a simple, low-level and allocation free abstraction for creating TUI programs. atleg takes care of wrangling the terminal, but unlike other TUI libraries it does not get in the way when you want to render the interface. The text attribute code can be used independently, so atleg is also useful for non-TUI terminal programs that still want fancy text. Despite being a modern library written in a modern language, atleg will always be held back by the countless legacy interfaces and hacks it tries to abstract away from you. This is inevitable.
No description
122 Replies
Dumb Bird
Dumb Bird8mo ago
Wow... I seriousy get worse with project logos Anyway here is some chats stolen from good ol' #💾┃other-languages ----------------------- When will I stop, more color in the terminal, but now in zig...
test "RGB thing" {
const std = @import("std");
const print = std.debug.print;
const stdout = std.io.getStdOut().writer();

// formatting issue with zig tests
print("\n", .{});

// TODO: need a function for resetting all color :P
var reset_attrib: Self = Self{};
reset_attrib.fg = Self.Color.none;
reset_attrib.bg = Self.Color.none;

for (0..6) |r| {
for (0..6) |g| {
for (0..6) |b| {
// calculate normalized RGB values
const norm_r: u8 = @truncate((r * 255) / 5);
const norm_g: u8 = @truncate((g * 255) / 5);
const norm_b: u8 = @truncate((b * 255) / 5);

var attrib: Self = Self{};
attrib.bg = Self.Color{ .rgb = .{ norm_r, norm_g, norm_b } };

try attrib.dump(stdout);
print("H", .{});
}
try Self.dump(reset_attrib, stdout);
}
print("\n", .{});
}
}
test "RGB thing" {
const std = @import("std");
const print = std.debug.print;
const stdout = std.io.getStdOut().writer();

// formatting issue with zig tests
print("\n", .{});

// TODO: need a function for resetting all color :P
var reset_attrib: Self = Self{};
reset_attrib.fg = Self.Color.none;
reset_attrib.bg = Self.Color.none;

for (0..6) |r| {
for (0..6) |g| {
for (0..6) |b| {
// calculate normalized RGB values
const norm_r: u8 = @truncate((r * 255) / 5);
const norm_g: u8 = @truncate((g * 255) / 5);
const norm_b: u8 = @truncate((b * 255) / 5);

var attrib: Self = Self{};
attrib.bg = Self.Color{ .rgb = .{ norm_r, norm_g, norm_b } };

try attrib.dump(stdout);
print("H", .{});
}
try Self.dump(reset_attrib, stdout);
}
print("\n", .{});
}
}
Heres that code with highlighting (because well duh)
Dumb Bird
Dumb Bird8mo ago
No description
Dumb Bird
Dumb Bird8mo ago
And heres that code's results
Dumb Bird
Dumb Bird8mo ago
No description
Dumb Bird
Dumb Bird8mo ago
Here is also something I cooked up in a few minutes: a grayscale ramp
test "grayscale ramp" {
const std = @import("std");
const print = std.debug.print;
const stdout = std.io.getStdOut().writer();

// formatting issue with zig tests
print("\n", .{});

// TODO: need a function for resetting all color :P
var reset_attrib: Self = Self{};
reset_attrib.fg = Self.Color.none;
reset_attrib.bg = Self.Color.none;

for (0..24) |i| {
const gray_value: u8 = @truncate(i * 10 + 8);

var attrib: Self = Self{};
attrib.bg = Self.Color{ .rgb = .{ gray_value, gray_value, gray_value } };

try attrib.dump(stdout);
print("H", .{});
}

// cleanup
try reset_attrib.dump(stdout);
print("\n", .{});
}
test "grayscale ramp" {
const std = @import("std");
const print = std.debug.print;
const stdout = std.io.getStdOut().writer();

// formatting issue with zig tests
print("\n", .{});

// TODO: need a function for resetting all color :P
var reset_attrib: Self = Self{};
reset_attrib.fg = Self.Color.none;
reset_attrib.bg = Self.Color.none;

for (0..24) |i| {
const gray_value: u8 = @truncate(i * 10 + 8);

var attrib: Self = Self{};
attrib.bg = Self.Color{ .rgb = .{ gray_value, gray_value, gray_value } };

try attrib.dump(stdout);
print("H", .{});
}

// cleanup
try reset_attrib.dump(stdout);
print("\n", .{});
}
Dumb Bird
Dumb Bird8mo ago
No description
Dumb Bird
Dumb Bird8mo ago
No description
Dumb Bird
Dumb Bird8mo ago
The main reason the code is cluttered is because the library is no where near done :P
Dumb Bird
Dumb Bird8mo ago
No description
Dumb Bird
Dumb Bird8mo ago
Slightly improved tests At least some🌷cute🌺 improvements Added support for color descriptors So you can now do stuff like
try parseColorDescriptor("0xffffff");
// or
try parseColorDescriptor("0");
// or
try parseColorDescriptor("blue");
// or even HTML
try parseColorDescriptor("x11:cintcream");
try parseColorDescriptor("0xffffff");
// or
try parseColorDescriptor("0");
// or
try parseColorDescriptor("blue");
// or even HTML
try parseColorDescriptor("x11:cintcream");
Implemented Kitty Keyboard protocol support Added mouse support 1000 not 1003 which has limitations As it's limited to the following maximum XY values 255 - 32 = 223 I hope to switch to SRG, or at least use SRG when the terminal's size is greater than 223x223 or mouse movement is being used I took the easy route as SRG is more annoying to parse ----------------------- Boom now thats over All development will be moved into here as to not clutter up #💾┃other-languages with my junk nobody wants to see Implemented most of the parsers for input If you'd like to see my tests here they are
Dumb Bird
Dumb Bird8mo ago
Here is that with a .c extention so you can have some highlighting and a preview
Dumb Bird
Dumb Bird8mo ago
And of course the output of these builds is all successful
Dumb Bird
Dumb Bird8mo ago
No description
Dumb Bird
Dumb Bird8mo ago
parseInputDescriptor is a way to live less in the past, letting atleg deal with the pain of legacy features it makes it easy to represent complex sequences, as you can see in the tests atleg uses an Input struct to represent ... well input This is more of a novilty and nothing you actually need to worry as atleg abstracts it all for you, but for example something like "ctrl+alt+f" is represented as Input{ .content = .{ .codepoint = 'f' }, .mod_ctrl = true, .mod_alt = true } Something to note is that you can use the short form of mod names.
+-----+------+-------+
| Alt | Ctrl | Super |
+=====+======+=======+
| M | C | S |
+-----+------+-------+
| A | Ctrl | Super |
+-----+------+-------+
| Alt | | |
+-----+------+-------+
+-----+------+-------+
| Alt | Ctrl | Super |
+=====+======+=======+
| M | C | S |
+-----+------+-------+
| A | Ctrl | Super |
+-----+------+-------+
| Alt | | |
+-----+------+-------+
For those that don't know, M is Meta during the 1970s and 1980s, keyboards on machines running Unix systems often had three modifier keys Ctrl, Shift, and Meta As much as I'd love to not use M at all, it's still widly accepted and used in a varity of programs (vim for example). As such I've kept it in But it may very well be removed in the future
anic17
anic178mo ago
this guy comes with a new project in a new programming language each week C, C++, Rust, Go, Insitux, Objective-C, now Zig
Dumb Bird
Dumb Bird8mo ago
🤣 It's true, I like messing with new languages (hope that's not a bad thing 😓 ) Currently I find Zig the most likable Added many functions for interacting with the Terminal Like cooking and uncooking the terminal And a writer for dealing with stdout Using this writer instead of directly using stdout allows TUI applications to use screen caching along with waiting until the screen has been fully rendered before trying to continue writing reading input functions fetching the terminal size setting the window title Working on a writer for restrictions size for example This will tie in a lot later when making the TUI, for example text within a box stays within the bounds of that box
anic17
anic178mo ago
What is even this lol
Dumb Bird
Dumb Bird8mo ago
Pretty much just raw mode the writer is now buffered for performance Limiting the number of syscalls and going through tons of abstraction layers, this makes writing to stdout faster
Dumb Bird
Dumb Bird8mo ago
Dumb Bird
Dumb Bird7mo ago
Just a small test A bit of messing around I spawned some terminals and resized them Just to test the sigwich capture Working on an input demo / test Wow that took a while, huh? Well here it is
Dumb Bird
Dumb Bird7mo ago
Dumb Bird
Dumb Bird7mo ago
This took a lot of time due to the number of bugs and things ironed out in the library I am going to continue creating things in the library to find pot holes and just general things to fix Here is the code for the curious
Dumb Bird
Dumb Bird7mo ago
Keep in mind this code is less then perfect but works quite well dispite all that Here is the file with a .c extention so you can see a preview
Dumb Bird
Dumb Bird7mo ago
Dumb Bird
Dumb Bird7mo ago
many things about this test can be removed or cleaned up, which will happen in the near future Typeracer clone in the terminal... again... this reminds me of something
Dumb Bird
Dumb Bird7mo ago
Dumb Bird
Dumb Bird7mo ago
Oh did I meantion the lineWriter I'm sure I did... I haven't been keeping up to date Oh my... time to do that. Alright get ready for a spam Added several new functions for moving the cursor like - moveCursorBy - moveCursorToCol - moveCursorByLine A function for resetting the terminal attribute previously done with
.setAttribute(.{});
.setAttribute(.{});
is now done like
.resetAttribute();
.resetAttribute();
Well both still work, up to you which you'd like to use The LineWriter has gained some new functions too Like - padByte - padAmount - padAmountByte Currently only working with a byte as the underlying writer uses writeByteNTimes I will implement codepoint support as not being able to use things like unicode is annoying That might be all the important stuff, I doubt anyone cares about the underlying improvements I made to the system now onto the work in progress stuff a block writer which unlike a line reader which well works with a single line (or any given width as a restriction) uses a height along with a width Maybe a start position? But I doubt it It isn't really a bad idea, the line reader could use something similar But doing so adds extra overhead Yeah I think for a block writer I will have a starting col and row I guess the only thing now is how should that be specified By the current cursor position, or by a row and col passed I honestly have no idea on how I want to do this so I'm going to go grab a piece of paper and write (+ draw) some ideas I still have no idea, so the best idea I have right now is to polish what I have so far and polish it well I do have many // BUG:, // TODO:, and // FIXME:'s in my code Drats first things first though I got to improve my build.zig
anic17
anic177mo ago
Pretty pretty :upvote: What does the first function do It moves by a specified X,Y I guess? Here we got flex in terminal Honestly it's very impressive what you're doing Seems like a bit terminal CSS
Dumb Bird
Dumb Bird7mo ago
Moves the cursor by a number of rows and columns Which is unlike moveCursorTo which sets the row and column
anic17
anic177mo ago
Alright yeah as I understood it
Dumb Bird
Dumb Bird7mo ago
Pretty much yes, the hope is to have "content aware" text. So I can have text inside a box and it stays in the box and resizes in the box
anic17
anic177mo ago
And if you resize the terminal, will the text also re-fit?
Dumb Bird
Dumb Bird7mo ago
Something like this which is from a project called vt100utils
No description
Dumb Bird
Dumb Bird7mo ago
yes atleg can monitor SIGWINCH so handling terminal resizes is easy And rendering is also very efficent I've been messing around with dirty writing as well, and efficent caching I improved my build.zig so now you can build and run atleg demos easily zig build -Demo=input for example Compiles and runs this test That gives me a neat idea... Once I finish atleg I want to try making an html and css like system in the terminal I think that would be neat, to create TUI's using an almost html like language
anic17
anic177mo ago
Or make a simple implementation of HTML-compatible code I'm guessing you're using double buffering
Dumb Bird
Dumb Bird7mo ago
No actually, the way the atleg works is it uses a RenderContext which stores the changes and then it just writes the whole frame at once. for example here is some example code
fn render() !void {
var rc = try term.getRenderContext();
defer rc.done() catch {}; // calls rc.done at the end of the scopes life

// we can clear the terminal
try rc.clear();

// move the cursor
try rc.moveCursorTo(10, 10);

// clear all color
try rc.resetAttribute();

// but nothing is actually displayed until rc.done() is called
}
fn render() !void {
var rc = try term.getRenderContext();
defer rc.done() catch {}; // calls rc.done at the end of the scopes life

// we can clear the terminal
try rc.clear();

// move the cursor
try rc.moveCursorTo(10, 10);

// clear all color
try rc.resetAttribute();

// but nothing is actually displayed until rc.done() is called
}
As rendering everything at once causes no flicker This is something that I tinkered with a while ago and found double buffering can be useful. That is if you don't have a system like the one shown above As instead of now writing many times, we write once to clear all overhead and it's very fast flushing should only be done once too as that invokes a system call which is well, slow You would think clearing the screen would cause flicker as we clear the terminal every frame But it doesn't as we do it all at once, in a single write which nearly entirely eliminates flicker Actually let me do some stress tests to back up my statement, once second Building off this test I will add colors and also intentionally do dumb unoptimal things to show that even with bad code flickering isn't an issue I've been writing a bunch of tests but I can't seem to get my terminal to even flicker which is nice, but most of that should be attributed to modern terminals being ridiculously fast
Dumb Bird
Dumb Bird7mo ago
Also this is the source code of this test
Dumb Bird
Dumb Bird7mo ago
And once again heres that as a .c file
Dumb Bird
Dumb Bird7mo ago
And that code creates this
anic17
anic177mo ago
just saw that atleg means "avoid terminal legacy" ehhh i don't think that's C more like Go
Dumb Bird
Dumb Bird5mo ago
Yeah but using go results in a weirder looking syntax highlighting Yes it does a few hacky things to entirly abstract terminal legacy from the user Atleg is back, well sorta I have the inner drive for terminals, like I always do... No matter what I do I always come back to terminal, and recently something has tickled my toes in just a way to force me back into the terminal That being the rust framework ratatui It's a TUI library that's just, well, amazing. I want one, but I want it Zig Mainly because Rust always has seemed like a black box which I just say "I'm not smart enough to understand", and this is how many people feel So why not just bring a TUI library to Zig? During that thought I said "atleg". This library which may seem redundant at first, just another terminal control library thrown into space. Actually is pretty cool It's missing some really core features, like full and proper unicode support Atleg is also pretty darn fast at rendering text as it optimizes the number of syscalls it needs to make. Along with limiting the number of times flush needs to be called So, what's the TL;DR of all this? Well Atleg will be getting a little makeover, in fact an entire rewrite. Why the rewrite? I deem it to be a necessary step to make something that can be smoothly used in a TUI library. I will also be created a proper readme and documentation. MAJOR FEATURES PLANNED - Full unicode support - Multithread safe (and maybe async support with zig 0.12) - An integrated way to handle events - Mouse events (press, release, position, button, drag) IMPLEMENTED - Terminal resizes - A sort of poll/read API - Interrupt signal (^C) - End of file (^D) - Terminal stop (^Z) - CROSS PLATFORM SUPPORT!!!! :WindowsXP: 🍎:linux: (for right now Windows 10 & 11 will only be supported, but I hope to go as low as Windows 7 maybe XP) So I guess it's time to actually work on atleg rewrite Now you may wonder why I am saying this now 6 hours after my original message Well I'm just cool like that, and as I'm sick I took a nap I'm going to be planning on how I want to implement the cross platform-ness Then I must test manyyyyyyy things, as things like to be left undocumented or hard to find documentation for I also need to mess with threads and async in Zig before I can work on atleg Dealing with everything in a cross platform way seems to be stumping me pretty hard I think I'll need to do some tests to sort out my thoughts Well that would be the best idea, as I'd like to know the differences of Linux vs Windows as far as terminal stuff goes So I think for right now I'm going to ignore platform dependent stuff. I'll define a common interface between the systems like moving the cursor and such Wrote a few convenience functions for creating sequences
/// Creates a control sequence.
/// Prepends provided sequence with the control sequence introducer `ESC [` (`\x1B[`).
///
/// Example:
/// csi("?1049h") -> "\x1B[?1049h"
pub inline fn csi(comptime s: []const u8) []const u8 {
return "\x1B[" ++ s;
}

/// Creates an escape sequence.
/// Prepends provided sequence with the `ESC` (`\x1B`) character.
///
/// Example:
/// esc("7") -> "\x1B7"
pub inline fn esc(comptime s: []const u8) []const u8 {
return "\x1B" ++ s;
}

/// Creates a select graphic rendition sequence.
/// Prepends provided sequence with the `ESC[` (`\x1B[`) character and appends `m` character.
///
/// Example:
/// sgr("0") -> "\x1B[0m"
pub inline fn sgr(comptime s: []const u8) []const u8 {
return "\x1B[" ++ s ++ "m";
}
/// Creates a control sequence.
/// Prepends provided sequence with the control sequence introducer `ESC [` (`\x1B[`).
///
/// Example:
/// csi("?1049h") -> "\x1B[?1049h"
pub inline fn csi(comptime s: []const u8) []const u8 {
return "\x1B[" ++ s;
}

/// Creates an escape sequence.
/// Prepends provided sequence with the `ESC` (`\x1B`) character.
///
/// Example:
/// esc("7") -> "\x1B7"
pub inline fn esc(comptime s: []const u8) []const u8 {
return "\x1B" ++ s;
}

/// Creates a select graphic rendition sequence.
/// Prepends provided sequence with the `ESC[` (`\x1B[`) character and appends `m` character.
///
/// Example:
/// sgr("0") -> "\x1B[0m"
pub inline fn sgr(comptime s: []const u8) []const u8 {
return "\x1B[" ++ s ++ "m";
}
I think I'll make a parser of some kind, which matches a sequence to one that atleg supports, otherwise it junks the sequence Being able to convert a sequence to atleg calls (like cursor movement for example) may be handy? Just a note that terminal cursor movement should be represented by u16 Want some fun documentation for mouse events? Me neither, but here is this
9 -> X10 mouse reporting, for compatibility with X10's xterm, reports on button press. 1000 -> X11 mouse reporting, reports on button press and release. 1001 -> highlight reporting, useful for reporting mouse highlights. 1002 -> button movement reporting, reports movement when a button is pressed. 1003 -> all movement reporting, reports all movements. 1006 -> report back as decimal values (xterm, many other terminal emulators, but not urxvt) 1015 -> report back as decimal values (urxvt, xterm, other terminal emulators, some applications find it complex to parse) 1005 -> report back encoded as utf-8 (xterm, urxvt, broken in several ways)
Dumb Bird
Dumb Bird5mo ago
No description
Dumb Bird
Dumb Bird5mo ago
Stack Overflow
List of ANSI color escape sequences
On most terminals it is possible to colorize output using the \033 ANSI escape sequence. I'm looking for a list of all supported colors and options (like bright and blinking). As there are probably
Dumb Bird
Dumb Bird5mo ago
This hero
Dumb Bird
Dumb Bird5mo ago
ANSI escape code
ANSI escape sequences are a standard for in-band signaling to control cursor location, color, font styling, and other options on video text terminals and terminal emulators. Certain sequences of bytes, most starting with an ASCII escape character and a bracket character, are embedded into text. The terminal interprets these sequences as command...
Dumb Bird
Dumb Bird5mo ago
Another great resource
Dumb Bird
Dumb Bird5mo ago
No description
Dumb Bird
Dumb Bird5mo ago
No description
Dumb Bird
Dumb Bird5mo ago
So color is back up and working with atleg :) I've also made it a point to make docs for everything while I'm coding it now I'm doing it in a way that Zig's autodoc will save me from having to write all the documentation out seperate from the code Atleg now supports more (and less) escape sequences
Dumb Bird
Dumb Bird5mo ago
If you'd like to take a look
Dumb Bird
Dumb Bird5mo ago
No description
Dumb Bird
Dumb Bird5mo ago
Color cubes are now on two seperate rows I also added a clear function to the Attribute struct
Dumb Bird
Dumb Bird5mo ago
Improved grayscale ramp
No description
Dumb Bird
Dumb Bird5mo ago
No description
Dumb Bird
Dumb Bird5mo ago
A bunch of passing input tests Now just refining the input system, trying my best to make it stable and bullet proof The parser now does a basic check that has never caused a problem for me, and probably never will. Just to be safe though I wrote a small check
// check if buffer is long enough
if (self.bytes.?.len < advance)
return Input{ .content = .unknown };
// check if buffer is long enough
if (self.bytes.?.len < advance)
return Input{ .content = .unknown };
I also now make a few assumptions which help atleg be more stable with input. For example
// Pretty much all common escape sequences begin with '['. All of them
// are at least three bytes long, so if we have less, this likely is
// just a press of the escape key followed by a press of the '[' key.
if (self.bytes.?[1] == '[' and self.bytes.?.len > 2) {
// There are two types of '[' escape sequences.
if (ascii.isDigit(self.bytes.?[2])) {
return self.numericEscapeSequence();
} else if (self.bytes.?[2] == 'M') {
return self.legacyMouseEscapeSequence();
} else {
return self.singleLetterEscapeSequence();
}
}
// Pretty much all common escape sequences begin with '['. All of them
// are at least three bytes long, so if we have less, this likely is
// just a press of the escape key followed by a press of the '[' key.
if (self.bytes.?[1] == '[' and self.bytes.?.len > 2) {
// There are two types of '[' escape sequences.
if (ascii.isDigit(self.bytes.?[2])) {
return self.numericEscapeSequence();
} else if (self.bytes.?[2] == 'M') {
return self.legacyMouseEscapeSequence();
} else {
return self.singleLetterEscapeSequence();
}
}
and
// This may be either a M-[a-z] code, or we accidentally received an
// escape key press and a letter key press together. There is literally
// no way to differentiate. However the second case is less likely.
if (ascii.isAlphabetic(self.bytes.?[1]) and ascii.isLower(self.bytes.?[1])) {
defer self.advanceBufferBy("\x1Ba".len);
return Input{ .content = .{ .codepoint = self.bytes.?[1] }, .mod_alt = true };
}
// This may be either a M-[a-z] code, or we accidentally received an
// escape key press and a letter key press together. There is literally
// no way to differentiate. However the second case is less likely.
if (ascii.isAlphabetic(self.bytes.?[1]) and ascii.isLower(self.bytes.?[1])) {
defer self.advanceBufferBy("\x1Ba".len);
return Input{ .content = .{ .codepoint = self.bytes.?[1] }, .mod_alt = true };
}
and
fn singleLetterEscapeSequence(self: *Self) Input {
const ev = singleLetterSpecialInput(self.bytes.?[2]) orelse {
// Oh, turns out this is not an escape sequence. Well
// this is awkward... Let's hope / pretend that the next
// few bytes can be interpreted on their own. Well, it
// might actually be an escape sequence after all, just
// one that we don't know yet. Would be pretty nice to
// just skip it. But we have literally no idea how long
// this sequence is supposed to be, so it's safer to
// just treat it as separate content pressed.
self.advanceBufferBy(1);
return Input{ .content = .escape };
};
self.advanceBufferBy("\x1B[A".len);
return ev;
}
fn singleLetterEscapeSequence(self: *Self) Input {
const ev = singleLetterSpecialInput(self.bytes.?[2]) orelse {
// Oh, turns out this is not an escape sequence. Well
// this is awkward... Let's hope / pretend that the next
// few bytes can be interpreted on their own. Well, it
// might actually be an escape sequence after all, just
// one that we don't know yet. Would be pretty nice to
// just skip it. But we have literally no idea how long
// this sequence is supposed to be, so it's safer to
// just treat it as separate content pressed.
self.advanceBufferBy(1);
return Input{ .content = .escape };
};
self.advanceBufferBy("\x1B[A".len);
return ev;
}
Although the input parser supports legacy mouse movement atleg doesn't actually have a way of enabling legacy mouse movement in the first place This may be an issue? Ok, if SGR isn't supported it will automaticly start using legacy mouse movement instead
Dumb Bird
Dumb Bird5mo ago
No description
Dumb Bird
Dumb Bird5mo ago
Added a test for legacy mouse sequences I have spent quite a while working on implementing mouse support for both CSI and SGR which I have now done, but I also worked on a easy way for mouse events to be categorized despite the big differences between CSI and SGR Gotta say, I love tagged unions They have made atleg's api so pretty, and makes creating a cross platform api much easier Here is the new legacy input test
test "input parser: Legacy mouse sequences" {
const testing = std.testing;
var parser = inputParser("\x1B[M A3\x1B[M!()\x1B[M\"Na\x1B[M#xO\x1B[M0z;\x1B[M1[Y\x1B[M2fu\x1B[M3 \x1B[M@-@\x1B[MA=<");
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 32, .y = 18, .event = .{ .pressed = .left } } } },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 7, .y = 8, .event = .{ .pressed = .middle } } } },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 45, .y = 64, .event = .{ .pressed = .right } } } },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 87, .y = 46, .event = .{ .released = .unknown } } } },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 89, .y = 26, .event = .{ .pressed = .left } } }, .mod_ctrl = true },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 58, .y = 56, .event = .{ .pressed = .middle } } }, .mod_ctrl = true },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 69, .y = 84, .event = .{ .pressed = .right } } }, .mod_ctrl = true },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 0, .y = 0, .event = .{ .released = .unknown } } }, .mod_ctrl = true },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 12, .y = 31, .event = .{ .scrolled = .up } } } },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 28, .y = 27, .event = .{ .scrolled = .down } } } },
parser.next().?,
);
try testing.expect(parser.next() == null);

std.debug.print("OK\n", .{});
}
test "input parser: Legacy mouse sequences" {
const testing = std.testing;
var parser = inputParser("\x1B[M A3\x1B[M!()\x1B[M\"Na\x1B[M#xO\x1B[M0z;\x1B[M1[Y\x1B[M2fu\x1B[M3 \x1B[M@-@\x1B[MA=<");
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 32, .y = 18, .event = .{ .pressed = .left } } } },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 7, .y = 8, .event = .{ .pressed = .middle } } } },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 45, .y = 64, .event = .{ .pressed = .right } } } },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 87, .y = 46, .event = .{ .released = .unknown } } } },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 89, .y = 26, .event = .{ .pressed = .left } } }, .mod_ctrl = true },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 58, .y = 56, .event = .{ .pressed = .middle } } }, .mod_ctrl = true },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 69, .y = 84, .event = .{ .pressed = .right } } }, .mod_ctrl = true },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 0, .y = 0, .event = .{ .released = .unknown } } }, .mod_ctrl = true },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 12, .y = 31, .event = .{ .scrolled = .up } } } },
parser.next().?,
);
try testing.expectEqual(
Input{ .content = .{ .mouse = .{ .x = 28, .y = 27, .event = .{ .scrolled = .down } } } },
parser.next().?,
);
try testing.expect(parser.next() == null);

std.debug.print("OK\n", .{});
}
It seems messy thanks to me having to be pretty explicit when writing a test. So it may help to see the raw data types
...
mouse: struct { x: usize, y: usize, event: MouseEvent },
};

pub const MouseEvent = union(enum) {
/// Pressed mouse button. Contains the button that was pressed.
pressed: MouseButton,
/// Released mouse button. Contains the button that was released.
released: MouseButton,
/// Moved the mouse cursor while pressing the contained mouse button.
dragged: MouseButton,
/// Moved the mouse cursor while not pressing a mouse button.
moved: void,
/// Scrolled mouse wheel either
/// - up (away from the user)
/// - down (towards the user)
/// - right (mostly on a laptop touchpad)
/// - left (mostly on a laptop touchpad)
scrolled: enum { up, down, right, left },
};
pub const MouseButton = enum {
/// Used during some CSI cases where legacy mouse tracking doesn't
/// report the button. For example, cases where a button was released
unknown,
/// also known as btn1 or lmb
left,
/// also known as btn2 or mmb
middle,
/// also known as btn3 or rmb
right,
};
...
mouse: struct { x: usize, y: usize, event: MouseEvent },
};

pub const MouseEvent = union(enum) {
/// Pressed mouse button. Contains the button that was pressed.
pressed: MouseButton,
/// Released mouse button. Contains the button that was released.
released: MouseButton,
/// Moved the mouse cursor while pressing the contained mouse button.
dragged: MouseButton,
/// Moved the mouse cursor while not pressing a mouse button.
moved: void,
/// Scrolled mouse wheel either
/// - up (away from the user)
/// - down (towards the user)
/// - right (mostly on a laptop touchpad)
/// - left (mostly on a laptop touchpad)
scrolled: enum { up, down, right, left },
};
pub const MouseButton = enum {
/// Used during some CSI cases where legacy mouse tracking doesn't
/// report the button. For example, cases where a button was released
unknown,
/// also known as btn1 or lmb
left,
/// also known as btn2 or mmb
middle,
/// also known as btn3 or rmb
right,
};
If I want to know the mouse event I can do mouse.event, if I know the event was a press and I want to know the key being pressed I can do mouse.event.pressed Compared to the old way I did it with a .button and a .state this is a better way I am nearly done with the input system now I've mainly focused on things that are cross platform, but the real crux of atleg will come when implementing the Term struct (ITerm2) doesn't work
echo -e "\e[?1000h\e[?1002h\e[?1003h\e[?1015h\e[?1006h"
echo -e "\e[?1006l\e[?1015l\e[?1003l\e[?1002l\e[?1000l"
echo -e "\e[?1000h\e[?1002h\e[?1003h\e[?1015h\e[?1006h"
echo -e "\e[?1006l\e[?1015l\e[?1003l\e[?1002l\e[?1000l"
(ITerm2) does work
echo -e "\e[?1000h\e[?1002h\e[?1003h\e[?1015h"
echo -e "\e[?1015l\e[?1003l\e[?1002l\e[?1000l"
echo -e "\e[?1000h\e[?1002h\e[?1003h\e[?1015h"
echo -e "\e[?1015l\e[?1003l\e[?1002l\e[?1000l"
The button which gets reported seems out-of-line with XTerms documentation My first idea is the shell may be consuming the sequences As I assume ITerm2 supports SGR mouse tracking, and it wouldn't make sense for all of the mouse input to be consumed when setting 1006 I'll have to write a script to put my terminal in raw mode Which I should have done a while ago Never mind all that, my suspicion was correct The shell must have been consuming the sequence After some modification of the original atleg to display SGR mouse sequences I get some good results
Dumb Bird
Dumb Bird5mo ago
Dumb Bird
Dumb Bird5mo ago
Alright, knowing this I can finally finish my implementation of SGR mouse sequences
Dumb Bird
Dumb Bird5mo ago
Going back to what @earth's god and @polyzium said here https://discord.com/channels/728958932210679869/747400155845623899/1180517940840386621, I will be implementing shift as a modifier at some point soon.
Discord
Discord - A New Way to Chat with Friends & Communities
Discord is the easiest way to communicate over voice, video, and text. Chat, hang out, and stay close with your friends and communities.
Dumb Bird
Dumb Bird5mo ago
The idea where shift+a = A not S-a, I agree with, but for many cases this just isn't good enough for me For example if someone holds shift while move the mouse, it's easy to detect that it's being modified by shift but with my current system there is no way to express that it's being modified by shift As such shift+a will still be equal to A, as A is a codepoint not an escape sequence. But escape sequences have the .mod_shift field I don't plan on going back to the input parser to implement shift of everything, as of right now that would be a little too much work I will do it, but I would much rather focus on completing Windows support then work on more input support Atleg really struggles with Zalgo text, I would like to fix this, as it breaks everything... The terminal not being cooked properly comes down to me forgetting to errdefer but regardless
Dumb Bird
Dumb Bird5mo ago
No description
No description
Dumb Bird
Dumb Bird5mo ago
I shouldn't be allowed to code at night... Anyway reverted back to my old, much better system. Some small changes for adapting both mouse handling systems Although messy mouse support both CSI and SGR are finished Can the code be improved? Yes, definitely. But does it work? Yes, definitely. I have also made mouse testing much more verbose. Making sure it checks for all mods. This is just to make sure the parser is correct It's much better to be verbose in testing, then to regret it later SGR tracking should cover all the bases I guess this would be revealed later on in atleg's life, but for right now I'm pretty darn sure I have everything other than modifying shift implemented. For the meantime I will be writing test hell for SGR mouse input. Yes, every single possible case :) Boom for the love of all tests that are testy
Dumb Bird
Dumb Bird5mo ago
No description
Dumb Bird
Dumb Bird5mo ago
I am now pretty damn confident that atleg covers nearly everything input related The parser can take: Unicode, Ascii, and Escape sequences The input.zig file clocks in at about 1593 lines of code Most of which are tests for the input system, which clocks in around 539 lines I am aware that lib c integration with atleg is wonky. This is thanks to some still unfixed issues with zigs standard library. Added back the color_descriptor Now time to work on the crux of everything term.zig Well, I still need to think about writing... at least a little bit A line writer isn't a bad idea, but is this atlegs job? I don't really think so, but maybe it is. I plan on creating a TUI library with Zig, something along the lines of DumbTUI
anic17
anic175mo ago
I mean, if your biggest concern is zalgo, try to fix it But I don't think it's necessary to add zalgo support, it only breaks things
Dumb Bird
Dumb Bird5mo ago
Yeah that's the plan, I don't actually care about supporting it at all The main issue is that atleg should NEVER mess with the original terminals state after the application has quit Even if an error occurs, the terminal should ALWAYS be restored Thankfully zig has defer and errdefer so for the most part this is the case But for Zalgo text it breaks the input parser but the text is still in the input stream. So it leaks out into whatever runs next, which is likely a shell @earth's god is there a way to set the Windows terminal to a "raw state" like how you can on Linux by using termios Or is this not even a required thing on Windows. I really lack Windows terminal knowledge like I have with Unix systems Sorry for the ping I'm aware I'll be working with Windows API, you can just point me where I need to look and that'll be more than sufficient. Thank you Anic!
polyzium
polyzium5mo ago
I suggest renaming this library to "nblesses" :)
Dumb Bird
Dumb Bird5mo ago
Ha, I've thought of something along those lines before (I was thinking ncures, although your idea is better) It's honestly not a bad idea 🤔 It was named atleg as the library hopes to Avoid Terminal LEgacy Which it does a pretty damn good job of I do think a rename is time though, atleg isn't the most appealing or rememberable name
polyzium
polyzium5mo ago
"rename is time"? Sorry but that sounded like broken English to me
anic17
anic175mo ago
you mean output raw characters without the console parsing them? I believe SetConsoleMode has a ENABLE_PROCESSED_OUTPUT flag that can be disabled or similar ENABLE_PROCESSED_OUTPUT 0x0001 _Characters written by the WriteFile or WriteConsole function or echoed by the ReadFile or ReadConsole function are parsed for ASCII control sequences, and the correct action is performed. Backspace, tab, bell, carriage return, and line feed characters are processed. It should be enabled when using control sequences or when ENABLE_VIRTUAL_TERMINALPROCESSING is set.
Dumb Bird
Dumb Bird5mo ago
Sorry, it is I didn't mean that I mean "is in due time"
polyzium
polyzium5mo ago
oh
Dumb Bird
Dumb Bird5mo ago
Yeah, I just tried getting my thoughts out quickly and my fingers didn't keep up Ah yes, thank you, this is just what I needed Zig is a bit silly, and I have to bind SetConsoleMode myself. Here is how I do it
const std = @import("std");
const windows = std.os.windows;

pub extern "kernel32" fn SetConsoleMode(in_hConsoleHandle: windows.HANDLE, in_dwMode: windows.DWORD) callconv(windows.WINAPI) windows.BOOL;
const std = @import("std");
const windows = std.os.windows;

pub extern "kernel32" fn SetConsoleMode(in_hConsoleHandle: windows.HANDLE, in_dwMode: windows.DWORD) callconv(windows.WINAPI) windows.BOOL;
I haven't gotten much to the Windows side of atleg yet, but I did bring back linux support. I want to entirly rewrite term.zig which I hope to do soon I did however rewrite the build system I also went and changed up the input demo to support the SGR sequences If anyone on Linux would like to try out the input system that would be nice. It should support every single keyboard to exist. At least it should be able to understand what you've pressed I know we've had tons of keyboard stuggles @earth's god, if possible would you be able to run it in WSL and mess around with it?
Dumb Bird
Dumb Bird5mo ago
Dumb Bird
Dumb Bird5mo ago
Binary built with zig build -Dtarget=x86_64-linux -Doptimize=ReleaseSmall so it should run on WSL fine
Dumb Bird
Dumb Bird5mo ago
Dumb Bird
Dumb Bird5mo ago
As a bonus here is also a typeracer clone, compiled under the same command
Dumb Bird
Dumb Bird5mo ago
The typeracer clone doesn't capture SIGWINCH so changing your terminal size won't get recognized like it will when running input Forgot to pin this a while ago :P
polyzium
polyzium5mo ago
I think you forgot to set the terminal back to its regular mode Shortcuts like ^C and ^W don't work after running and types 9;5u
Dumb Bird
Dumb Bird5mo ago
Huh, let me look into that. I do set the terminal back to regular mode, or rather it's original Termios config So it's weird it's doing that
polyzium
polyzium5mo ago
Nevertheless the program itself works fine in Alacritty
Dumb Bird
Dumb Bird5mo ago
Ah good. Alright I think I found the issue with ^C and ^W not being fixed Thank you for testin' it out
polyzium
polyzium5mo ago
Yw
Dumb Bird
Dumb Bird5mo ago
Don't mind this below Before running input test
❯ stty
speed 38400 baud;
lflags: echoe echok echoke echoctl pendin
iflags: -ixon iutf8
oflags: -oxtabs
cflags: cs8 -parenb

❯ stty -a
speed 38400 baud; 25 rows; 80 columns;
lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl
-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
-extproc
iflags: -istrip icrnl -inlcr -igncr -ixon -ixoff ixany imaxbel iutf8
-ignbrk brkint -inpck -ignpar -parmrk
oflags: opost onlcr -oxtabs -onocr -onlret
cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow
-dtrflow -mdmbuf
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;
min = 1; quit = ^\; reprint = ^R; start = ^Q; status = ^T;
stop = ^S; susp = ^Z; time = 0; werase = ^W;
❯ stty
speed 38400 baud;
lflags: echoe echok echoke echoctl pendin
iflags: -ixon iutf8
oflags: -oxtabs
cflags: cs8 -parenb

❯ stty -a
speed 38400 baud; 25 rows; 80 columns;
lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl
-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
-extproc
iflags: -istrip icrnl -inlcr -igncr -ixon -ixoff ixany imaxbel iutf8
-ignbrk brkint -inpck -ignpar -parmrk
oflags: opost onlcr -oxtabs -onocr -onlret
cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow
-dtrflow -mdmbuf
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;
min = 1; quit = ^\; reprint = ^R; start = ^Q; status = ^T;
stop = ^S; susp = ^Z; time = 0; werase = ^W;
After running input test
❯ stty
speed 38400 baud;
lflags: echoe echok echoke echoctl pendin
iflags: -ixon iutf8
oflags: -oxtabs
cflags: cs8 -parenb

❯ stty -a
speed 38400 baud; 25 rows; 80 columns;
lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl
-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
-extproc
iflags: -istrip icrnl -inlcr -igncr -ixon -ixoff ixany imaxbel iutf8
-ignbrk brkint -inpck -ignpar -parmrk
oflags: opost onlcr -oxtabs -onocr -onlret
cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow
-dtrflow -mdmbuf
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;
min = 1; quit = ^\; reprint = ^R; start = ^Q; status = ^T;
stop = ^S; susp = ^Z; time = 0; werase = ^W;
❯ stty
speed 38400 baud;
lflags: echoe echok echoke echoctl pendin
iflags: -ixon iutf8
oflags: -oxtabs
cflags: cs8 -parenb

❯ stty -a
speed 38400 baud; 25 rows; 80 columns;
lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl
-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
-extproc
iflags: -istrip icrnl -inlcr -igncr -ixon -ixoff ixany imaxbel iutf8
-ignbrk brkint -inpck -ignpar -parmrk
oflags: opost onlcr -oxtabs -onocr -onlret
cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow
-dtrflow -mdmbuf
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;
min = 1; quit = ^\; reprint = ^R; start = ^Q; status = ^T;
stop = ^S; susp = ^Z; time = 0; werase = ^W;
These are 1:1 It's odd that you're getting this issue because the terminal is being reset to it's original state. Let me download Alacritty and see if I get the same issue Ah yes now I get the same issue Let me run stty again
polyzium
polyzium5mo ago
Lemme check stty output Wait it's the same but I get this issue
Dumb Bird
Dumb Bird5mo ago
❯ stty
speed 9600 baud;
lflags: echoe echoke echoctl pendin
iflags: -ixon iutf8
oflags: -oxtabs
cflags: cs8 -parenb
❯ stty
speed 9600 baud;
lflags: echoe echoke echoctl pendin
iflags: -ixon iutf8
oflags: -oxtabs
cflags: cs8 -parenb
This is what I get after running But I get the same before That means the termios settings are the same So I don't really know where this issue is coming from
polyzium
polyzium5mo ago
speed 38400 baud; line = 0;
-brkint -imaxbel iutf8
speed 38400 baud; line = 0;
-brkint -imaxbel iutf8
This is what I get after
Dumb Bird
Dumb Bird5mo ago
What about if you run stty -a
polyzium
polyzium5mo ago
speed 38400 baud; rows 37; columns 100; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany
-imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho
-extproc
speed 38400 baud; rows 37; columns 100; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany
-imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho
-extproc
Dumb Bird
Dumb Bird5mo ago
Is that before or after?
polyzium
polyzium5mo ago
After After the reset command:
speed 38400 baud; rows 37; columns 100; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany imaxbel
iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho
-extproc
speed 38400 baud; rows 37; columns 100; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany imaxbel
iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho
-extproc
Dumb Bird
Dumb Bird5mo ago
Ok, so I guess I did forget to reset something.
polyzium
polyzium5mo ago
Meld does display a difference
No description
polyzium
polyzium5mo ago
Left is after atleg, right is after reset Diff format:
--- <unnamed>
+++ <unnamed>
@@ -3,8 +3,8 @@
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
--ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany
--imaxbel iutf8
+-ignbrk brkint ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany imaxbel
+iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho
-extproc
--- <unnamed>
+++ <unnamed>
@@ -3,8 +3,8 @@
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
--ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany
--imaxbel iutf8
+-ignbrk brkint ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany imaxbel
+iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho
-extproc
Dumb Bird
Dumb Bird5mo ago
Yes, thank you this should help me a bit. I dont seem to have this issue with ITerm2, Konsole, Kitty, or Tabby. I'll have to look into it further Ok so this output means - brkint Signal INTR on break. - ignpar Ignore parity errors. I need to disable those, alright I'll do that and see if it fixes the issue
anic17
anic175mo ago
Gonna try it when I'll arrive at home
Dumb Bird
Dumb Bird5mo ago
Alright, thank you!
KeithBrown7526
KeithBrown75264mo ago
// Why not shift? Because it is not always trivial to detect and because it is
// not entirely clear how some things should be handled. Should 'A' be parsed
// into a lowercase 'a' with the Shift modifier or an uppercase 'A' with the
// Shift modifier or an uppercase 'A' without Shift? No idea. So let's just
// avoid it for now.
// Why not shift? Because it is not always trivial to detect and because it is
// not entirely clear how some things should be handled. Should 'A' be parsed
// into a lowercase 'a' with the Shift modifier or an uppercase 'A' with the
// Shift modifier or an uppercase 'A' without Shift? No idea. So let's just
// avoid it for now.
I feel like pressing it would be Shift + a and if caps lock is enabled then it would be Shift + A which would be be inputting a lowercase 'a'.
KeithBrown7526
KeithBrown75264mo ago
GitHub
atleg/src/input.zig at main · ZackeryRSmith/atleg
avoid terminal legacy. Contribute to ZackeryRSmith/atleg development by creating an account on GitHub.
Dumb Bird
Dumb Bird4mo ago
This comment is out dated, the newer versions of atleg exclude it an opt for using the system as you mentioned Although shift isn't really supported widely in atleg yet :P
polyzium
polyzium4mo ago
Terminals do not send a separate Shift keypress, at least Konsole does not. I am afraid you'd have to rely on the uppercase lowercase trick
Dumb Bird
Dumb Bird4mo ago
Yes, but shift is handled in different ways depending on the terminal and keyboard protocol being used. This is why I haven't added much support for shift presses in atleg The Kitty keyboard protocol (which atleg supports) allows detecting shift as a separate thing
polyzium
polyzium4mo ago
Then you should look into terminfo at least on unix platforms Not sure about windows
Dumb Bird
Dumb Bird4mo ago
I've thought about it for Posix platforms I use the Windows api to do something similar to Terminfo
anic17
anic174mo ago
lmao sorry for being like 10 days late it works perfectly on WSL ^^
Dumb Bird
Dumb Bird4mo ago
Don't worry about it! I'm glad it works well, thank you for testing it out for me
Dumb Bird
Dumb Bird4mo ago
No description
Unknown User
Unknown User4mo ago
Message Not Public
Sign In & Join Server To View
Dumb Bird
Dumb Bird4mo ago
Hello
Unknown User
Unknown User4mo ago
Message Not Public
Sign In & Join Server To View
Dumb Bird
Dumb Bird4mo ago
Nice to meet you too
KeithBrown7526
KeithBrown75263mo ago
why has progress stopped on this?
Dumb Bird
Dumb Bird3mo ago
Any reason you need progress to keep going? Atleg is nearly a finished product, the only reason it was halted was due to other things coming up that needed to be addressed The other thing that stopped me was confusion on how the api should be done for IO If you need this for something let me know and I will help you, or fix any bugs you have while using it Atleg also has a few unexpected bugs which are very challenging to debug, but if you do need this I will fix them.
KeithBrown7526
KeithBrown75263mo ago
I would like to use it for a terminal text editor
Dumb Bird
Dumb Bird3w ago
Atleg is 100% capable to do that, development has definitely slowed down. Like with any of my projects if someone wants to use it and needs support I will always be on top of it Only issue is that Atleg is not currently compatible with Windows. Is that an issue? I would like to keep this in mind Zig has some builtin stuffs for most of the Windows API Very useful :) Alright welcome back atleg Going to delete anything related to IO in atleg As this is now expected to be done by you. Want to output something to the terminal? Why have to go through creating a line writer, and dealing with all this abstraction I've been breaking Zig's design guidelines, lets stop that now atleg isn't a tui, it's a simple library for avoiding the necessity to be a 🤓 to make terminal programs As such even things like padding a string isn't the job of atleg