Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ANSI code support for colors, etc. #363

Closed
tculp opened this issue Aug 23, 2020 · 16 comments
Closed

ANSI code support for colors, etc. #363

tculp opened this issue Aug 23, 2020 · 16 comments

Comments

@tculp
Copy link

tculp commented Aug 23, 2020

Is there existing support for setting content with ANSI-coded colors, such as writing the raw, colorized output of a command to the screen?

For example:
A command such as echo -e "\e[033;32mhi" will output hi in green. I can get setContent to print this to the screen using code like:

package main

import (
  "github.com/gdamore/tcell"
  "github.com/gdamore/tcell/encoding"
  "time"
  "os/exec"
  "bytes"
)

func main() {
  cmd := exec.Command("echo", "-e", "\\e[033;32mhi")
  var out bytes.Buffer
  cmd.Stdout = &out
  cmd.Run()
  time.Sleep(time.Second * 2)

  encoding.Register()
  scn, _ := tcell.NewScreen()
  scn.Init()
  scn.Clear()
  scn.SetContent(0, 0, ' ', []rune(out.String()), tcell.StyleDefault)
  scn.Show()
  time.Sleep(time.Second * 2)
  scn.Fini()

... will print _hi in green text.

However, this seems like a hack more than a supported feature, and relies on the main rune existing. In this case, a space (represented by an underscore). The combining characters are only appended, instead of pre-pended like they should be for ansi codes.

Is there any defined way to do this the right way? Would the SetContent function need another argument that takes combining runes that get added before the main rune? Should there be a function that merely adds a combining rune without a main rune, so that a cell can get an ansi code without immediately adding any main rune at all?

@gdamore
Copy link
Owner

gdamore commented Aug 23, 2020

What you're doing is indeed a hack, and is not supported. You should use the color support built into tcell natively instead.

Is there some compelling reason you want to use escape sequences in particular? (Are you trying to build some kind of terminal widget?)

@tculp
Copy link
Author

tculp commented Aug 23, 2020

Exactly, specifically something similar to tmux, where I will be running arbitrary commands and so want terminal output to look the same as native where possible

@gdamore
Copy link
Owner

gdamore commented Aug 24, 2020

In that case you should actually capture and parse the escape sequences yourself. You could then select the right colors etc.

This would have the benefit that it would do the right thing on any terminal not just xterm compatible ones. For example it would render properly on a legacy windows console.

@tculp
Copy link
Author

tculp commented Aug 24, 2020

Based on the sheer amount of data present (thinking of something like scrolling through a 2000+ line tmux buffer), I have concerns over the performance impact of parsing that amount of data compared to a regular run of a command

@gdamore
Copy link
Owner

gdamore commented Aug 24, 2020

Unless you're running this on an ancient 10MHz CPU or something, the cost to parse the escape sequences is not going to be enormous. Compared to the cost of sending those bytes to the physical console, it's in the noise.

@tculp
Copy link
Author

tculp commented Aug 26, 2020

That may be true, but it seems to me like, though not best in all cases, the library shouldn't require scanning for such escape sequences, parsing, calling the library functions that replace them, just to (I'm guessing) re-add them to the output when sending it to the physical console. Partially due to performance, but also to avoid having to write a complicated compatibility layer.

I think there should be support to just set the content of a cell(s) to the raw bytes outputted by another program (SetRawContent?), rather than introducing potential bugs or artifacts in the output that wouldn't be present natively.

Additionally, since many terminals and existing command-line tools have features that this library may not support currently, (strikethrough, underline, blink, etc. see #256 and #332 ), this would provide a fallback that could allow for output from such programs to be displayed properly when it might not be possible now.

@gdamore
Copy link
Owner

gdamore commented Aug 26, 2020

Well, what you want won't be portable at all to different kinds of terminals. For example, it won't do anything useful at all on a Windows 8 console.

If you want to have direct control over rendering the terminal output, then tcell probably isn't the right library for you. The purpose of tcell is to provide an abstraction layer that provides portability and consistency.

We could in theory build a richer abstraction layer that does that parsing for you, creating a virtual terminal widget of some sort, and I've in fact contemplated that. But its a fair bit of work, and I haven't had time to do it.

I'm vehemently opposed to doing any kind of "passthrough" where we just write random escape escape sequences to the backing terminal. Very definitely if that's what you want, you need something that isn't tcell.

@tculp
Copy link
Author

tculp commented Aug 29, 2020

I see. For the portability, there are some aspects of the program that could benefit from the portability and consistency. Thinking of tmux, the UI, status bars, etc. should be portable and work on all terminals. However, if the commands someone is running in a pane only works for xterm, then converting that output to a portable format is potentially dangerous and out of scope. Maybe I'll have to find something else, fork tcell, or write it from scratch.

@gdamore
Copy link
Owner

gdamore commented Aug 29, 2020 via email

@tculp
Copy link
Author

tculp commented Aug 29, 2020

It's not a terminal emulator, so it doesn't parse the escape sequences. Tmux doesn't, it just passes the output to the terminal using ncurses

@gdamore
Copy link
Owner

gdamore commented Aug 29, 2020 via email

@tculp
Copy link
Author

tculp commented Aug 30, 2020

As far as I can tell that's what it does (looking mainly at https://github.com/tmux/tmux/blob/master/tty.c), though admittedly tmux doesn't have the most readable code.

@gdamore
Copy link
Owner

gdamore commented Aug 31, 2020

Actually, looking at the file, I think the reverse is true. It has code to lookup specific capabilities, like italics, and send those precise abilities. Which is presumably based on a desire to provide that functionality after translating.

That is sustained by examination of other files in the tmux code as well -- I see lots of places where translations are made for both input and output. And for color there is even an effort to map 24-bit color to 256 depending on what the underlying terminal supports.

In fact, the color parsing is in input.c, where it translates sgr sequences on input to specific values.

tmux is anything but a dumb passthrough.

@tculp
Copy link
Author

tculp commented Sep 3, 2020

Huh, so it is. Looking at input.c it's especially clear; I hadn't thought to look in that file.

Also, I just found tview's ANSIWriter, which may itself act as the layer I need

@gdamore
Copy link
Owner

gdamore commented Oct 14, 2020

Can we close this for now here?

@makew0rld
Copy link

Also, I just found tview's ANSIWriter, which may itself act as the layer I need

This is the solution I was going to propose. You should check out cview though!

@tculp tculp closed this as completed Nov 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants