Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Failing after 39s
237 lines
9.7 KiB
Markdown
237 lines
9.7 KiB
Markdown
# zterm Terminal User Interface Library
|
|
|
|
`zterm` is a terminal user interface library to implement terminal (fullscreen or inline) applications.
|
|
|
|
> [!NOTE]
|
|
> Only builds using the master version are tested to work.
|
|
|
|
## Demo
|
|
|
|
Clone this repository and run `zig build --help` to see the available examples. Run a given example as follows:
|
|
|
|
```sh
|
|
zig build --release=safe -Dexample=input run
|
|
```
|
|
|
|
> [!NOTE]
|
|
> Every example application can be quitted using `ctrl+c`.
|
|
|
|
See the [wiki](https://gitea.yves-biener/yves-biener/zterm) for a showcase of the examples and the further details.
|
|
|
|
## Usage
|
|
|
|
To add or update `zterm` as a dependency in your project run the following command:
|
|
|
|
```sh
|
|
zig fetch --save git+https://gitea.yves-biener.de/yves-biener/zterm
|
|
```
|
|
|
|
Add the dependency to your module as follows in your _build.zig_:
|
|
|
|
```zig
|
|
const zterm: *Dependency = b.dependency("zterm", .{
|
|
.target = target,
|
|
.optimize = optimize,
|
|
});
|
|
// ...
|
|
exe.root_module.addImport("zterm", zterm.module("zterm"));
|
|
```
|
|
|
|
---
|
|
## Design Goals
|
|
|
|
This project draws heavy inspiration from
|
|
[clay](https://github.com/nicbarker/clay) in the way the layout is declared by
|
|
the user. As terminal applications usually are rendered in intermediate mode,
|
|
the rendering is also part of the event loop. Such that every time an event
|
|
happens a render call will usually be done as well. However this is not strickly
|
|
necessary and can be separated to have a fixed rendering of every 16ms (i.e. for
|
|
60 fps), etc.
|
|
|
|
There is only one generic container which contains properties and elements (or
|
|
children) which can also be containers, such that each layout in the end is
|
|
a tree.
|
|
|
|
The library is designed to be very basic and not to provide any more complex
|
|
elements such as input fields, drop-down menu's, buttons, etc. Some of them are
|
|
either easy to implement yourself, specific for you needs or a too complex to
|
|
be provided by the library effectively. For these use-cases there may be other
|
|
libraries that build on top of this one to provide the complex elements as some
|
|
sort of pre-built elements for you to use in your application (or you create
|
|
them yourself).
|
|
|
|
There are only very few system events, that are used by the built-in containers
|
|
and properties accordingly. For you own widgets (i.e. a collection of elements)
|
|
you can extend the events to include your own events to communicate between
|
|
elements, effect the control flow and the corresponding generated layouts and
|
|
much more.
|
|
|
|
As this is a terminal based layout library it also provides a rendering pipeline
|
|
alongside the event loop implementation. Usually the event loop is waiting
|
|
blocking and will only cause a re-draw (**intermediate mode**) after each event.
|
|
Even though the each frame is regenerated from scratch each render loop, the
|
|
corresponding application is still pretty performant as the renderer uses a
|
|
double buffered intermediate mode implementation to only apply the changes from
|
|
each frame to the next to the terminal.
|
|
|
|
This library is also designed to work accordingly in ssh hosted environments,
|
|
such that an application created using this library can be accessed directly
|
|
via ssh. This provides security through the ssh protocol and can defer the
|
|
synchronization process, as users may access the same running instance. Which is
|
|
the primary use-case for myself to create this library in the first place.
|
|
|
|
---
|
|
## Roadmap
|
|
|
|
- [ ] Container rendering
|
|
- [x] Layout
|
|
- [x] direction
|
|
- [x] vertical
|
|
- [x] horizontal
|
|
- [x] padding
|
|
- [x] gap
|
|
- [x] sizing (removed - for now at least)
|
|
- width
|
|
- height
|
|
- options
|
|
- fit
|
|
- grow
|
|
- fixed
|
|
- percent
|
|
- [x] Border
|
|
- [x] sides
|
|
- [x] corners
|
|
- [x] separators
|
|
- [x] Rectangle
|
|
- [ ] User control
|
|
- [x] event loop handling
|
|
- [x] mouse support
|
|
- [x] user content
|
|
- [ ] Default `Element` implementations
|
|
- [ ] Scrollable
|
|
- [x] user input handling
|
|
- [x] vertical
|
|
- [x] horizontal
|
|
- [x] mouse input
|
|
- [ ] scroll bar(s) rendering
|
|
- [ ] vertical
|
|
- [ ] horizontal
|
|
- [ ] Content alignment (i.e. standard calculations done with the provided `Size`)
|
|
- [x] User input
|
|
- [x] single line
|
|
- [x] multi line
|
|
- [x] min size (provide size to use which would be a minimal size - as if the actual size is smaller then the `Container` will scroll and otherwise the contents expand to the available space instead?)
|
|
- [ ] image support through kitty protocol (**later**)
|
|
- [ ] Inline rendering (**later**)
|
|
- [ ] Examples
|
|
- [ ] Layouts
|
|
- [x] vertical
|
|
- [x] horizontal
|
|
- [x] grid
|
|
- [ ] mixed (some sort of form)
|
|
- [ ] Elements
|
|
- [ ] Button
|
|
- [ ] Text Input field
|
|
- [ ] User input handling
|
|
- [ ] Popup-menu
|
|
- [ ] Scrollable Content (i.e. show long text of an except of something and other smaller `Container`)
|
|
- [ ] min size
|
|
- [ ] mouse scrolling aware of mouse position (i.e. through multiple different scrollable `Container`)
|
|
- [ ] Launch sub-applications (not inside of a `Container` but during the application workflow, like an editor)
|
|
- [ ] Styles
|
|
- [ ] Text styles
|
|
- [ ] Color palette
|
|
- [ ] Testability
|
|
- [ ] snapshot ability to safe current screen (from `Renderer`) to test against
|
|
- [ ] try to integrate them into the library itself such that they also serve as examples on how to test
|
|
|
|
Decorations should respect the layout and the viewport accordingly. This means
|
|
that scrollbars are always visible (except there is no need to have a scrollbar)
|
|
irrelevant depending on the size of the content. The rectangle apply to all
|
|
cells of the content (and may be overwritten by child elements contents).
|
|
The border of an element should be around independent of the scrolling of the
|
|
contents, just like padding.
|
|
|
|
For most of the `Element`s a standalone implementation would not make a lot
|
|
of sense due to the complexity of the user application states. Therefore the
|
|
library should instead provide small examples to show how you can implement
|
|
such user fields yourself and connect them using your own event system loops to
|
|
communicate with other `Container`s and/or `Element`s.
|
|
|
|
### Scrollable contents
|
|
|
|
Contents that is scrollable should be done *virtually* through the contents of
|
|
the `Container`. This means each container contents implements scrolling for
|
|
itself if required.
|
|
|
|
This still has one issue: Layout of child elements that are already too large
|
|
(i.e. or become too small). The library could provide automatic rendering of a
|
|
scrollbar given the right parameters however. The scrolling input action would
|
|
then also be implemented by the user.
|
|
|
|
Open questions are regarding the sizing options (i.e. how is the size of a
|
|
`Container` actually controlled?, how should it be controlled?, etc.). There
|
|
should be support for the child elements to provide some kind of 'list'
|
|
functionality built-in.
|
|
|
|
**REMINDER**: (mostly for myself) The library should be and remain simple. This
|
|
means that some code for using the library may be duplicated, but this is not
|
|
the main goal. Others may provide more re-usable code snippets that build on top
|
|
of this library instead.
|
|
|
|
### User specific event handling and content rendering
|
|
|
|
For interactions controlled by the user each container can use an `Element`
|
|
interface which contains functions which are called by the `Container`
|
|
during event handling (i.e. `fn handle(..)`) and during rendering (i.e. `fn
|
|
content(..)`) to provide user specific content and user interaction. The
|
|
`Element` may be stateful, but may also be stateless and then be re-used in
|
|
multiple different `Container`s.
|
|
|
|
Composing multiple `Element`s currently requires the implementation of a wrapper
|
|
which contains the `Element`s that need to be handled (should work pretty well
|
|
for stateless `Element`s). Such *stateless* `Element`s may be provided by this
|
|
library.
|
|
|
|
### Input
|
|
|
|
How is the user input handled in the containers? Should there be active
|
|
containers? Some input may happen for a specific container (i.e. when using
|
|
mouse input). How would I handle scrolling for outer and inner elements of
|
|
a container?
|
|
|
|
### Documentation
|
|
|
|
A wiki should be created containing a bright overview of the structure and usage
|
|
of the library. For details it should refer to the examples. The documentation
|
|
should be minimal in terms of updateability in case the library changes. Maybe
|
|
some documentation could be derived from the code documentation (there is a tool
|
|
for this if I recall correctly).
|
|
|
|
Afterwards this README file contents can be updated to provide an actual
|
|
overview of the library in a short form containing links to the detailed
|
|
information required for usage.
|
|
|
|
The documentation may contain tips about how to implement corresponding event
|
|
loops or how to design own `Element`s. And also on how to test accordingly and
|
|
use the library itself for examples on how to design the test cases.
|
|
|
|
### Archive
|
|
|
|
The alignment and sizing options only make sense if both are available. For
|
|
this the current implementation has the viewport size and the content size too
|
|
linked. Therefore they have both been removed (at least for now):
|
|
|
|
- *fit*: adjust virtual space of container by the size of its children (i.e. a
|
|
container needs to be able to get the necessary size of its children)
|
|
- *grow*: use as much space as available (what exactly would be the difference
|
|
between this option and *fit*?)
|
|
- *fixed*: use exactly as much cells (in the specified direction)
|
|
|
|
- *center*: elements should have their anchor be placed accordingly to their
|
|
size and the viewport size.
|
|
- *left*: the anchor remains at zero (relative to the location of the
|
|
container on the screen) -> similar to the current implementation!
|
|
- *right*: the anchor is fixed to the right side (i.e. size of the contents -
|
|
size of the viewport)
|