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.
https://media.discordapp.net/attachments/1180540066188243024/1283496534272381078/atleg.png?ex=66e334cb&is=66e1e34b&hm=cbb2a701317368834944794d3562495e6b2d768197a492e319e84e0d7ec7b3a1&=&format=webp&quality=lossless&width=1057&height=1057
128 Replies
And heres that code's results
Here is also something I cooked up in a few minutes: a grayscale ramp
The main reason the code is cluttered is because the library is no where near done :P
Slightly improved tests
At least some🌷cute🌺 improvements
Added support for color descriptors
So you can now do stuff like
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
Here is that with a .c extention so you can have some highlighting and a preview
And of course the output of these builds is all successful
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.
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 futurethis guy comes with a new project in a new programming language each week
C, C++, Rust, Go, Insitux, Objective-C, now Zig
🤣
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
What is even this lol
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
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
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
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
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
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 withis now done like
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.zigPretty 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
Moves the cursor by a number of rows and columns
Which is unlike
moveCursorTo
which sets the row and columnAlright yeah as I understood it
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
And if you resize the terminal, will the text also re-fit?
Something like this which is from a project called vt100utils
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 languageOr make a simple implementation of HTML-compatible code
I'm guessing you're using double buffering
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
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
Also this is the source code of this test
And once again heres that as a .c file
just saw that atleg means "avoid terminal legacy"
ehhh i don't think that's C
more like Go
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 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
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
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
- 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)
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
This hero
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...
Another great resource
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
If you'd like to take a look
Color cubes are now on two seperate rows
I also added a
clear
function to the Attribute
structImproved grayscale ramp
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
I also now make a few assumptions which help atleg be more stable with input. For example
and
and
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
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
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
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
(ITerm2) does work
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 resultsAlright, knowing this I can finally finish my implementation of SGR mouse sequences
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.
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 regardlessI 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
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
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
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!I suggest renaming this library to "nblesses" :)
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
"rename is time"?
Sorry but that sounded like broken English to me
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.Sorry, it is
I didn't mean that
I mean "is in due time"
oh
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
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?
Binary built with
zig build -Dtarget=x86_64-linux -Doptimize=ReleaseSmall
so it should run on WSL fineAs a bonus here is also a typeracer clone, compiled under the same command
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 :PI 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
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
Nevertheless the program itself works fine in Alacritty
Ah good. Alright I think I found the issue with ^C and ^W not being fixed
Thank you for testin' it out
Yw
Don't mind this below
Before running
input
test
After running input
test
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
againLemme check stty output
Wait it's the same but I get this issue
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
This is what I get after
What about if you run
stty -a
Is that before or after?
After
After the
reset
command:
Ok, so I guess I did forget to reset something.
Meld does display a difference
Left is after atleg, right is after reset
Diff format:
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 issueGonna try it when I'll arrive at home
Alright, thank you!
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'.GitHub
atleg/src/input.zig at main · ZackeryRSmith/atleg
avoid terminal legacy. Contribute to ZackeryRSmith/atleg development by creating an account on GitHub.
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
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
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
Then you should look into terminfo
at least on unix platforms
Not sure about windows
I've thought about it for Posix platforms
I use the Windows api to do something similar to Terminfo
lmao sorry for being like 10 days late
it works perfectly on WSL
^^
Don't worry about it! I'm glad it works well, thank you for testing it out for me
Unknown User•9mo ago
Message Not Public
Sign In & Join Server To View
Hello
Unknown User•9mo ago
Message Not Public
Sign In & Join Server To View
Nice to meet you too
why has progress stopped on this?
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.
I would like to use it for a terminal text editor
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
I'm going to be restarting from scratch here. I don't know how far this will end up going but I want to try again. I've been having issues programming lately so I want to just sit down and do something I always have done in these times. Mess around with terminals.
Atleg as an initial concept was quite nice, but it's way to intertwined with the Linux terminal that adding Windows support would prove difficult. So with this new attempt I will be going at things differently.
For simplicity though I will be starting off very small and slowly build up as I want certain features. I am a little unsure on what the goal of Atleg is. Originally its “Avoid Terminal LEGacy”. Which is still the hope but now I want it cross-platform.
TL;DR
I got new plans for the direction of this project, aka restarting. I’m going to stop stressing about so many things which have stopped me from being able to work on projects as of late. Expect to see some slightly interesting things in the next few days.
What language is atleg in?
Zig
^
Although the hope would eventually be C binds. So Atleg would at some point support C++, JS, and so on
Are you planning on making any use of the windows api?
A bit torn on that idea but I likely will for some things
Especially if it's detected that ANSI support isn't enabled