gdamore / tcell

Tcell is an alternate terminal package, similar in some ways to termbox, but better in others.
Apache License 2.0
4.52k stars 306 forks source link

virtual terminal widget? (like tmux) #244

Closed tjstebbing closed 1 year ago

tjstebbing commented 5 years ago

I'm just curious about how I could create a tty proxy widget / terminal emulator widget that I could use to embed $EDITOR inside a tcell (tview) app. See https://github.com/rivo/tview/issues/178

tobimensch commented 5 years ago

I want to have something like that for browsh (github.com/browsh-org/browsh).

One way would be to implement full vt100 emulation in go/tcell, basically reinvent a basic terminal multiplexer or at least a basic terminal emulator. While possible, to get it completely right for all types of terminal applications, with all the escape sequences from xterm and with features like truecolor support, would be a major project.

A more hackish alternative to that would be to use the real tmux as a proxy for running the application that is to be embedded. Tmux has commands for getting the current screen, sending keys and getting the current cursor position. Tmux would need to be started in the background from within your go application, then you could create a special tmux session just for the one application you want to embed with exactly the dimensions it is intended to have inside tcell.

Use the tmux capture-pane command for polling the tmux pane's screen. Use tmux send-keys for sending keystrokes to the pane. Tmux has cursor_x and cursor_y variables for getting a pane's current cursor position. You'll want that to emulate the cursor inside tcell.

I've not yet implemented this, but I'm confident that it'll work. I can only guess how the performance of this solution is, as you'll have to poll tmux for changes constantly, there's another layer of indirection, which could make it a bit slower and less reliable than native tmux. Tmux provides hooks for activity, maybe those could be used instead of blindly using capture-pane every X milliseconds. One issue is also tcell's limited ability to register complex key events, some key events will simply not be able to get forwarded. A big advantage in this solution is that tmux is tried and tested, and you wouldn't spend much time reinventing the wheel.

gdamore commented 5 years ago

I think it would be preferable to create a new virtual terminal widget. It wouldn't be that hard to do if you settle on a subset of the semantics. (Full xterm is horrible.) It turns out that most programs use only a fraction of the full capability of a terminal -- tcell itself included! -- so as long as your new terminal doesn't advertise capabilities it doesn't have, it should be fine.

Of course it's better if we can find existing well-known terminal that meets this requirement. I'm not sure what those might be, but maybe something like the embedded emacs terminal might satisfy the need?

I would probably implement this widget as a separate package, rather than embedding it in tcell itself. (It could be a "subpackage" of tcell.) The rationale being to avoid having to carry that code into tcell applications that don't need it.

gdamore commented 5 years ago

One challenge in all this is virtual terminal support. A real virtual terminal should have a pty -- as you're going to want programs to be able to link their input and output to the terminal widget, and it isn't particularly clear that there is a good way to do that for general 'executed' programs other than by providing a pty.

Sadly this is incredibly non portable.

ddevault commented 5 years ago

For anyone curious, I have implemented this here:

https://git.sr.ht/~sircmpwn/aerc2/tree/master/widgets/terminal.go

gdamore commented 5 years ago

There is also pkg/term which has a Pty module.

I'm going to be changing tcell in the future so that the screen layer sits on a "Tty" which will be an extensible interface. This should enable a bunch of uses, including using Pty's from pkg/term.

ddevault commented 5 years ago

I'm not sure I understand what you're suggesting. Do you mean having tcell render to an arbitrary pty? I think the issue at hand here is allocating a pty for running arbitrary processes in and using tcell to render their terminal tmux-style. Which is what the library I linked to does.

ricochet1k commented 4 years ago

I have a frontend-agnostic terminal emulator project here: https://github.com/ricochet1k/termemu/

microo8 commented 2 years ago

I've stolen the termutil package from https://github.com/liamg/darktile and made a virtual terminal widget for tcell https://git.sr.ht/~ghost08/tcell-term It's not perfect, but it does the job. Sixels too :)

rockorager commented 1 year ago

To anyone coming across this, I built off what @microo8 had started: https://git.sr.ht/~rockorager/tcell-term

This one implements the views.Widget interface, making it very easy to integrate into tcell applications.

gdamore commented 1 year ago

I'm closing this as there is nothing more that I think tcell needs to do here.