Ui-terminal-mojo

Repo: GitHub - rd4com/ui-terminal-mojo: terminal ui mojo programming language
Demo: ui-terminal-mojo/learn/learn_6_scalable_layouts.mojo at main · rd4com/ui-terminal-mojo · GitHub

Hello :waving_hand:

I worked on this terminal ui for a while,
based on LinearType for layout measurements,
and SIMD for events handlings, and more.

Because this was first steps into ui from scratch,
the philosophy had to become learn by building.
So far, it worked and features came out.

At first, SIMD came to the rescue for events,
because the terminal sends many numbers for key combos.
this was a small nightmare, and SIMD was there to solve that.
Then, adding shift_left[1]() turned the vector into a queue.

Now for user to create a layout, thing became really difficult,
the datastructure was a nested tree at first,
this introduced complexity, Variant, and recursion.

But there was no way to create an API that makes it possible to:

  • nested areas that scale the outer ones vertically and horizontally,
  • events on the fly with no callbacks
  • in the 60FPS loop
  • in an user-friendly way

So the LinearType solution emerged, for measuring :triangular_ruler:!
If we can only move the cursor below or after an measured area,
no squares/rectangles should overlap with the previous one.
(only building “on top of” previous things)

So it became possible to simplify the datastructure into a flat list.
Now each position is calculated and known at creation time,
and events can be handled in the loop with no callbacks.

───
API
───

The ui already has a small foundational API,
making it possible for a person to create all it’s already available widgets,
with only a few tools that don’t really need to change !
(but let’s give time to the design to evolve a little more)

ui.start_measuring()
..let any widgets do nested things..
some_measurement.peek_dimension()
some_measurement^.stop_measuring()

ui.move_cursor_after(some_completed_measurement^)
ui.move_cursor_below(some_completed_measurement^)

Text("Hello world") | Fg.green in ui

ui[-2].click()
ui[-1].hover()
ui[-1] |= Bg.magenta

start_border and end_border
(to use with measurement api, as borders are measured too!)

To keep it user-friendly,
things can be appended vertically by default with no measuring.
(below previous item)

───

I really hope you’ll all like it,
please share any feedback: positive and not positive :smiley:

out4
out2
out3

Please check the repo,
there are many examples,
and an step by step progressive walk-trough :+1:

6 Likes

This is pretty cool!

Thanks !

:up_button::adhesive_bandage: Fix version ! (pin to 25.4.0.dev2025050705)
(the mojoproject.toml was not pinned to the same version as locally)

The ui could not work for people that cloned the repo i think.
Sorry for the inconvenience, (learning by building), it should work now :green_circle:!
On the way, updated it for latest nightly :+1: