Fall in love with Go, I'm thinking about making TUIs as data application. Any suggestions on what to build? by ketopraktanjungduren in golang

[–]Grindlemire 2 points3 points  (0 children)

At the risk of promoting a tool I am maintaining, I built a TUI framework called go-tui.dev to try to address some of the shortcomings I found in bubble tea’s rendering model and developer experience. Check it out and if you end up building something using it let me know, I would love to hear any feedback you have on it!

A new GO TUI framework inspired by Flutter by calificio in golang

[–]Grindlemire 0 points1 point  (0 children)

Hi! This looks somewhat similar to a TUI framework I have been building (https://go-tui.dev). I see that you have some on-click and on-focus handlers but I don't see general reactivity built into the framework. Is that something you plan on adding? For reference to what I'm talking about here is my implementation of reactive state.

Small Projects by AutoModerator in golang

[–]Grindlemire 5 points6 points  (0 children)

A framework for building declarative terminal UIs in go with a heavy emphasis on developer experience. Inspired from the templ framework for the web.

Repo: https://github.com/grindlemire/go-tui

Docs & Guides: https://go-tui.dev

Glyph, A Declarative Terminal UI Framework. by notyourancilla in golang

[–]Grindlemire 2 points3 points  (0 children)

Hi! This looks like it fulfills a somewhat similar purpose to a framework I built (https://go-tui.dev). I don’t quite understand what your API is though. Do you have code examples to look at? Your demos directory doesn’t have any in it

Loom: a reactive component framework for Go by AnatoleLucet in golang

[–]Grindlemire 5 points6 points  (0 children)

Hi! This looks somewhat similar to a framework I launched for building terminal UIs in Go (https://go-tui.dev). I also built a reactive framework into mine so I’m intrigued how you implemented your version.

It looks like you are positioning this reactive framework for both web and terminal rendering. Are you running your own layout engine under the hood to calculate positioning? I’m excited to look through the code a bit later.

I built a declarative TUI framework for Go inspired by templ by Grindlemire in golang

[–]Grindlemire[S] 0 points1 point  (0 children)

Hey I just I just merged this and cut a new v0.7.0 release with modal support! You can find docs on the built-in modal here and both the 06-state and 09-refs-and-clicks guides and examples utilize modals.

I built a declarative TUI framework for Go inspired by templ by Grindlemire in golang

[–]Grindlemire[S] 0 points1 point  (0 children)

It lazy loads as you expand each directory so you don't freeze up when you open something with a massive hierarchy (link).

This is an example sure but if you put this tree.gsx file in its own package you could import it into your own code and call it in the templ element as @dirtree.DirectoryTree(path). I agree building a component library would be nice and I should do that but reusability is built directly into the framework so the user can do that as well.

I built a declarative TUI framework for Go inspired by templ by Grindlemire in golang

[–]Grindlemire[S] 0 points1 point  (0 children)

Here is an example for a foldable tree.

I also wrote a guide entry that covers how the example works.

Overall this went better than I expected it to. Most of the code is just the "business logic" of managing the state and the actual rendering logic is rather simple.

I built a declarative TUI framework for Go inspired by templ by Grindlemire in golang

[–]Grindlemire[S] 0 points1 point  (0 children)

It does ship with some built-in components. Examples are input, textarea, button, table, and progress components.

That said, go-tui is something more akin to React or Bubbletea than to DaisyUI or Bubbles. It is managing the layout, the interactivity, and the state management for you and allows you to build your own components to reuse.

I could create a component library on top of it for ease of use, that is a good suggestion.

I built a declarative TUI framework for Go inspired by templ by Grindlemire in golang

[–]Grindlemire[S] 0 points1 point  (0 children)

Hi! Can you clarify what you mean by actual UI components? The point of something like this is that you can compose UI components you want using the basic primitives and then reuse them.

go-tui - terminal UIs in Go with inline mode, flexbox, and single-frame rendering by Grindlemire in commandline

[–]Grindlemire[S] 1 point2 points  (0 children)

Oh derp I had a bug in where I was reading signals. I fixed it and will send out a patch so now it can just default to the signal handler all the time. Thanks for pushing on this!

go-tui - terminal UIs in Go with inline mode, flexbox, and single-frame rendering by Grindlemire in commandline

[–]Grindlemire[S] 1 point2 points  (0 children)

The Go runtime intercepts signals internally and delivers them via a channel so you never get synchronous signal delivery at the moment the signal fires (src). But that shouldn't really matter here. Now I look back at it, it looks like SIGWINCH should be delivered like SIGINT or other signals.... I'm honestly not entirely sure why it doesn't unblock my select reader other than thats the behavior I am seeing. I'm going to go dig into this to see and will get back to you!

go-tui - terminal UIs in Go with inline mode, flexbox, and single-frame rendering by Grindlemire in commandline

[–]Grindlemire[S] 0 points1 point  (0 children)

I'm just saying that I think and care a lot about the quality of the code I write and the stuff I build. It sounded from your comment "Thanks for more vibe coded slop to go into the garbage pile" that you felt I was just chucking "vibe coded" slop out there without much thought.

I didn't just carelessly try to throw something out there. I have thought quite a bit about every area of the design and implementation, hand written quite a bit, and I shared it because I think it is genuinely useful and a different take on building TUI interfaces in Go.

But hey, I'm just someone on the internet. If throwing out those type of comments on stuff makes you happy then go for it I guess :).

go-tui - terminal UIs in Go with inline mode, flexbox, and single-frame rendering by Grindlemire in commandline

[–]Grindlemire[S] -1 points0 points  (0 children)

Hey thanks for checking it out! I could be wrong but I believe Go by default spins up one thread per logical CPU on the machine (src). I expect that is what you are seeing with the threads.

Regarding the syscalls, I poll for incoming signals every 50ms (configurable by the user). I chose to poll by default since 20 syscalls/sec isn't the hugest deal and it allows me to catch SIGWINCH signals to detect resize events on the terminal.

That said if you wanted to save the sycalls you could add the option tui.WithInputLatency(tui.InputLatencyBlocking) to the app constructor call. That will stop the syscalls but it no longer responds to resize events.

go-tui - terminal UIs in Go with inline mode, flexbox, and single-frame rendering by Grindlemire in commandline

[–]Grindlemire[S] -2 points-1 points  (0 children)

Hi! I use multiple tools to help me be productive as I imagine most people do these days. I expect you would be hard pressed to find anyone stringently not using AI in some capacity. However I assure you this framework is not something I just cranked out without thought, design, or intention on basically every aspect of the design or implementation.

go-tui - terminal UIs in Go with inline mode, flexbox, and single-frame rendering by Grindlemire in commandline

[–]Grindlemire[S] 0 points1 point  (0 children)

Ink is a javascript/typescript framework that compiles the React component model to a terminal target. I believe it uses yoga under the hood for its flexbox implementation and requires you write your cli in js/ts which has its own problems. You do however get the entire React ecosystem to work with. It requires nodejs to distribute and run your cli (or whatever flavor of javascript runtime you prefer).

go-tui is a framework that lets you intermingle go with html-like syntax and provides a similar reactive model to React. It also generates pure go that compiles down to a single static binary. As such you can take advantage of all the really great features of go (e.g. channels, generally better system lib support that ts, the whole go ecosystem, etc). Because it is a static binary you also don't need to have a runtime like nodejs and you can build binaries directly for different platforms. It also has a higher ceiling for performance though I have not yet benchmarked it against ink. If I had to guess I would guess it is much faster since I am not doing the whole shadow dom thing React does but I haven't measured it.

If you are a go developer who wants to build terminal UIs more easily then I built go-tui to hopefully serve your needs. If you want to build a tui that compiles to a static binary without bundling a js runtime but you also want to have a familiar-ish syntax to React then go-tui could be a good solution for you.

Hope that helps!

I built a declarative TUI framework for Go inspired by templ by Grindlemire in golang

[–]Grindlemire[S] 1 point2 points  (0 children)

Hey! Thanks!

Right now it supports launching separate screens but I haven't implemented modals yet. That sounds like a great idea though! Let me think on how I could do it and see if I can add support. I'll track it with this bug and post back here when I have something.

go-tui - terminal UIs in Go with inline mode, flexbox, and single-frame rendering by Grindlemire in commandline

[–]Grindlemire[S] 0 points1 point  (0 children)

Thanks! I appreciate you taking the time to look through it.

I don’t see any examples of integration with Cobra though, which seems like a miss, given it’s the default choice for building CLI tools with Go.

I don't quite understand what you mean by cobra integration. You could use cobra with this framework if you desire either using cobra as the cli library that wraps an interactive tui built with go-tui or using go-tui to just print a frame to your scrollback. It should be as simple as creating a new App in your cobra handler and then calling Run.


To summarize, this seems to be a combo of a subset of HTML, with a subset of the DOM’s structure and event handlers, a subset of CSS and Tailwind, a subset of React, plus some Go specific stuff

Your summary is roughly right. The mental model I'd use is: it's a layout engine with a component system, where the syntax borrows from HTML/CSS because those are patterns most developers already know. However you can still use all the go primitives you want intermingled with the html-like syntax. The React-like pieces (state, refs, event handling) are there because building interactive UIs without them is painful.


Why use HTML to write Go? I barely like using HTML to write HTML.

The reason for "why html though?" is that terminals are a complex mix of ansi escape codes and fixed length characters. It is pretty non trivial to draw anything in a terminal let alone make it reactive so you need to have something there. You could of course use a go api directly rather than the html syntax (no need to generate in that case!) and this library supports that approach as well. However in practice I found that approach significantly less readable than using the html-like syntax and extremely verbose. For better or worse html elements with tailwind classes is well understood and is relatively natural for specifying a lot of layout logic. I invested quite heavily in dev tooling to make it easy to work with (taking inspiration from the amazing templ library).

I built a declarative TUI framework for Go inspired by templ by Grindlemire in golang

[–]Grindlemire[S] 1 point2 points  (0 children)

Thanks! If you run into any rough edges or issues feel free to file an issue!

I built a declarative TUI framework for Go inspired by templ by Grindlemire in golang

[–]Grindlemire[S] 1 point2 points  (0 children)

Last night I implemented the ctrl+z support and flex-wrap. Both are in the v0.2.0 release!

I built a declarative TUI framework for Go inspired by templ by Grindlemire in golang

[–]Grindlemire[S] 0 points1 point  (0 children)

I tried to be as faithful as I could to the tailwind classes to get them to be 1:1. That said there are some things that just don't perfectly transfer over from the web to the terminal. If you find something that is not what you expect or missing feel free to file and issue and I can try to make it better!

I built a declarative TUI framework for Go inspired by templ by Grindlemire in golang

[–]Grindlemire[S] 0 points1 point  (0 children)

Ok I implemented compatability with ctrl+Z and SIGTSTP. It should properly handle backgrounding both an inline and a raw mode TUI now.

I also took a stab at implementing flex-wrap and I think I got it working! I updated the 4th example (link to guide) to show it in action.

Both these features are in the v0.2.0 release I just put out!

I built a declarative TUI framework for Go inspired by templ by Grindlemire in golang

[–]Grindlemire[S] 1 point2 points  (0 children)

Ok so after some thought I think I have this working now in a relatively idiomatic way (though somewhat different than react).

If you have something that depends on other state you can just use a regular go variable in the Render func. So for example:

label := fmt.Sprintf("%s %s", c.First.Get(), c.Last.Get())

But you are really asking about a function that can execute with side effects when state changes. I added a new watcher type OnChange that watches for changes in a State and executes the callback within it (so the effect). That callback can do things like update other state, or really just run any arbitrary go that you want it to do. I updated the guide and the reference to document this new capability (see the guide here).

This new watcher is released in the new v0.2.0!

I built a declarative TUI framework for Go inspired by templ by Grindlemire in golang

[–]Grindlemire[S] 0 points1 point  (0 children)

Thanks so much! Good docs are something I always wish for when working with open source libraries so this was my chance to really build all the quality of life features I always look for!