Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 180 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
> sixel-tmux : a terminal multiplexer that properly display graphics because it does not eat escape sequences

### What is sixel-tmux

sixel-tmux is a fork of tmux, with just one goal: having the most reliable support of graphics.

In a console, this means:
1. ANSI blocks and box-drawing characters <https://en.wikipedia.org/wiki/Box-drawing_character> to display ASCII and ANSI art <https://en.wikipedia.org/wiki/ANSI_art>
2. ANSI escape codes, with a focus on SGR parameters <https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters> to render text attributes
3. and the best of all: sixel graphics <https://en.wikipedia.org/wiki/Sixel> to display graphs <https://github.com/csdvrx/sixel-gnuplot>

This seems very simple requirements, yet a regular tmux fails on all 3:
1. ANSI art is corrupted,
2. some SGR parameters are supported, but the more exotic features like overline do not work, and some sequences may be intercepted and improperly changed
3. sixels are not supported.

For a proper support of all these features, sixel-tmux is necessary but
not sufficient: the terminal must be able to decode and render the sequences
passed by sixel-tmux.

Therefore, a separate test suite <https://github.com/csdvrx/sixel-testsuite>
is provided to first check if a terminal can achieve these goals.

If you are dissatisfied by your current terminal, please consider mlterm
<http://mlterm.sourceforge.net/> or mintty <https://mintty.github.io/> that are
tested and known to work well.

Microsoft Window Terminal is very promising, but does not support sixels yet.
Please upvote the feature request <https://github.com/microsoft/Terminal/issues/448>

You can find a longer list of alternative terminals and terminal multiplexers through
related works such as <https://github.com/gizak/termui/pull/233>

## Usage

First, use to test-suite to see what your terminal supports:

For the colors:
1. start by 16-colors.sh
2. then try 256-colors.pl
3. see if you are lucky and can use a 24 bits palette with 24-bit-color.sh
4. if it works, try to switch the 16 colors palette between Solarized dark and light with toggle-solarized-dark.sh and toggle-solarized-light.sh

In the final test, after displaying the 4 continous color lines without bands
or sudden breaks, your screen should switch to a black background then back to
a clear yellowish background.

For the fonts:
1. start with `cat font-ansi-blocks.txt` to see block drawing characters and a test bear
2. run `font-vt100.sh` to see the basic box drawing characters
2. `cat font-ansi-box.txt` to see the full set of box drawing characters
3. `cat font-dec.txt` to check DEC VT220 extra characters
4. `cat font-test-all.txt` to check unicode support and overall support of the drawing characters

In the final test, boxes should be properly aligned, and lines should intersect cleanly.

If the font test fails, you may need to change your font as it may not support every character.

Alternatively, when using mlterm you can tell it to extend your preferred font with one or more other fonts, for example:
ISO8859_1 = Iosevka SS04 18
ISO8859_15 = Iosevka SS04 18
ISO10646_UCS2_1 =Iosevka SS04 18
ISO10646_UCS2_1_BOLD = Iosevka SS04 18
U+2500-25ff=Segoe UI Symbol
U+25C6 = Tera Special # Diamond ◆
U+2409 = Tera Special # Horizontal tab ␉
U+240C = Tera Special # Form feed ␌
U+240D = Tera Special # Carrier return ␍
U+240A = Tera Special # Linefeed ␊
U+2424 = Tera Special # Newline ␤
U+240B = Tera Special # Vertical tab ␋
U+23BA = Tera Special # Horizontal line 1 ⎺
U+23BB = Tera Special # Horizontal line 3 ⎻
U+2500 = Tera Special # Horizontal line 5 ─
U+23BC = Tera Special # Horizontal line 7 ⎼
U+23BD = Tera Special # Horizontal line 9 ⎽

When everything works to your satisfaction, install libevent2 and ncurses, then
compile with: `./configure && make && make -j8 install`

Then:
1. install sixel-tmux.terminfo: `tic sixel-tmux.terminfo; tic -o ~/.terminfo sixel-tmux.terminfo`
2. start sixel-tmux: `sixel-tmux`
3. select sixel-tmux: `export TERM=sixel-tmux`
4. verify sixel-tmux is used: `tput smglr|base64` should return GzcbWz82OWgbWyVpJXAxJWQ7JXAyJWRzGzg=

You can then run the test-suite <https://github.com/csdvrx/sixel-testsuite> to check if what was working in your terminal before sixel-tmux is still working.

If it isn't, oops: it means sixel-tmux broke something. Patches are welcome!

### Current status and tests failed

Sixels fully work, but images are not redrawn when returning from another buffer (snake.six)

Overlines are not working yet (ansi-vte52.sh)

Ansi blocks are separated until you move to another buffer and back (font-ansi-blocks.txt)

24-bit mode is not supported (24-bit-color.sh)

dynamic switching of the 16 colors palette is not working (toggle-solarized-dark.sh/toggle-solarized-light.sh)

vertical split does not plays well with ansi and sixel

### Example inside mintty

Here is what my terminal looks like while I am editing this file in VIM

![mintty running tmux split window and displaying sixels inside](https://raw.githubusercontent.com/csdvrx/sixel-tmux/master/sixel-tmux.jpg)

### Why a fork

To support slow terminal with little bandwith, tmux started implementing
some controversial features after version 2.3. For example, when a lot of text
arrives, tmux start silently discarding the output until a redraw can be done.

Bug reports <https://github.com/tmux/tmux/issues/1019#issuecomment-318284445>
<https://github.com/tmux/tmux/issues/1502#issuecomment-429710887> mention
serious issues, such as being unable to cat a long text file without some parts
being cut off, so this questionable feature for slow terminals impacts many usecases.

Among other things, it breaks sixel support. Even when not using sixels, it
seems very wrong for tmux to be taking the initiative of silently discarding
parts of the outputs, without providing any command line flags to override that
"feature".

As it can't be disabled, this anti-feature is not just a questionable default,
but a perverse feature: I believe breaking the integrity of the output of
whatever command was run, with no recourse, is not acceptable for a terminal multiplexer.

Also, refusing to even provide a command-line toggle to opt-out is not
respectful of the end user freedom: no one should have to track patches to
allow basic functionality like properly displaying long text files!

The maintainer explicitely said several times that even if a patch was provided
to support sixels, the functionality would never be added to tmux, and it would
have to be a fork
<https://github.com/tmux/tmux/issues/44#issuecomment-119755304>

By becoming a permanent fork of tmux, sixel-tmux will do just what was asked.

sixel-tmux is not just made for sixels but for all graphical things that can no
longer be properly displayed inside tmux, including long text files.

Unfortunately, a permanent fork seems necessary as the problem seems to be more
general, and spreading: tmux intercept and improperly rewrites various escapes
codes, breaking other things
<https://github.com/tmux/tmux/issues/1391#issuecomment-403267557>

At this point, it is very unlikely that tmux will be fixed: all these
questionable choices start piling up, and make the correct display of what is
not just simple plain text inside tmux harder and harder.

This is a sad situation as tmux was one of the best terminal multiplexer, and
supported what GNU screen couldn't when too many questionable choices had been
accumulated and frozen in over 32 years of spaghetti code.

Therefore, all patches adding functionality to sixel-tmux are welcome-
including cleanups, and ports of tmux features. Even the features that may affect the
proper display of graphics and text are welcome, as long as they are off by
default since obscure usecases like limited bandwidth are now as rare as
serial ports.

### History

Hayaki Saito <https://github.com/saitoha/tmux-SIXEL> wrote a patch and released
a tmux-sixel fork in 2015. As tmux keep adding features, Chris Steinbach
<https://github.com/ChrisSteinbach/tmux-sixel> tried to integrate them in
tmux-sixel. Patches were released by others to add to the version of tmux
officialy packaged by distributions to have tmux-sixel features, like Mehdi
Abaakouk <https://gist.github.com/sileht/8759089d5620da763bb456a0ae82e4d0>

Yatao Li <https://github.com/yatli/tmux> had a branch that was the closet to upstream
tmux, but the most recent changes dated from 2017 and some sixel isues remained.

When I tried them, none had full support for ANSI SGR parameters. In 2019, as
there was no recent activity on any of these, I forked the most recent branch,
fixed the remaining issues to have good sixel support at least in the current
buffer, added the missing SGR parameters I needed, and fixed issues brough by
the inclusion of unavoidable anti-features in mainline tmux.
83 changes: 83 additions & 0 deletions README.tmux
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
Note on tmux-sixel

This fork has been created to make it a little easier to keep the sixel support
patch provided by Hayaki Saito working (see https://github.com/saitoha).

-----------

Welcome to tmux!

tmux is a "terminal multiplexer", it enables a number of terminals (or windows)
to be accessed and controlled from a single terminal. tmux is intended to be a
simple, modern, BSD-licensed alternative to programs such as GNU screen.

This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.

tmux depends on libevent 2.x. Download it from:

http://libevent.org

It also depends on ncurses, available from:

http://invisible-island.net/ncurses/

To build and install tmux from a release tarball, use:

$ ./configure && make
$ sudo make install

tmux can use the utempter library to update utmp(5), if it is installed - run
configure with --enable-utempter to enable this.

To get and build the latest from version control:

$ git clone https://github.com/tmux/tmux.git
$ cd tmux
$ sh autogen.sh
$ ./configure && make

(Note that this requires at least a working C compiler, make, autoconf,
automake, pkg-config as well as libevent and ncurses libraries and headers.)

For more information see http://git-scm.com. Patches should be sent by email to
the mailing list at tmux-users@googlegroups.com or submitted through GitHub at
https://github.com/tmux/tmux/issues.

For documentation on using tmux, see the tmux.1 manpage. It can be viewed from
the source tree with:

$ nroff -mdoc tmux.1|less

A small example configuration in example_tmux.conf.

A vim(1) syntax file is available at:

https://github.com/ericpruitt/tmux.vim
https://raw.githubusercontent.com/ericpruitt/tmux.vim/master/vim/syntax/tmux.vim

And a bash(1) completion file at:

https://github.com/imomaliev/tmux-bash-completion

For debugging, running tmux with -v or -vv will generate server and client log
files in the current directory.

tmux mailing lists are available. For general discussion and bug reports:

https://groups.google.com/forum/#!forum/tmux-users

And for Git commit emails:

https://groups.google.com/forum/#!forum/tmux-git

Subscribe by sending an email to <tmux-users+subscribe@googlegroups.com>.

Bug reports, feature suggestions and especially code contributions are most
welcome. Please send by email to:

tmux-users@googlegroups.com

This file and the CHANGES, FAQ, SYNCING and TODO files are licensed under the
ISC license. All other files have a license and copyright notice at their start.

-- Nicholas Marriott <nicholas.marriott@gmail.com>
56 changes: 35 additions & 21 deletions attributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,25 @@
const char *
attributes_tostring(int attr)
{
static char buf[128];
static char buf[512];
size_t len;

if (attr == 0)
return ("none");

len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s",
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s",
(attr & GRID_ATTR_BRIGHT) ? "bright," : "",
(attr & GRID_ATTR_DIM) ? "dim," : "",
(attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "",
(attr & GRID_ATTR_BLINK)? "blink," : "",
(attr & GRID_ATTR_REVERSE) ? "reverse," : "",
(attr & GRID_ATTR_HIDDEN) ? "hidden," : "",
(attr & GRID_ATTR_ITALICS) ? "italics," : "",
(attr & GRID_ATTR_STRIKETHROUGH) ? "strikethrough," : "");
(attr & GRID_ATTR_STRIKETHROUGH) ? "strikethrough," : "",
(attr & GRID_ATTR_UNDERSCORE_2) ? "double-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "",
(attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "");
if (len > 0)
buf[len - 1] = '\0';

Expand All @@ -52,6 +56,25 @@ attributes_fromstring(const char *str)
const char delimiters[] = " ,|";
int attr;
size_t end;
u_int i;
struct {
const char* name;
int attr;
} table[] = {
{ "bright", GRID_ATTR_BRIGHT },
{ "bold", GRID_ATTR_BRIGHT },
{ "dim", GRID_ATTR_DIM },
{ "underscore", GRID_ATTR_UNDERSCORE },
{ "blink", GRID_ATTR_BLINK },
{ "reverse", GRID_ATTR_REVERSE },
{ "hidden", GRID_ATTR_HIDDEN },
{ "italics", GRID_ATTR_ITALICS },
{ "strikethrough", GRID_ATTR_STRIKETHROUGH },
{ "double-underscore", GRID_ATTR_UNDERSCORE_2 },
{ "curly-underscore", GRID_ATTR_UNDERSCORE_3 },
{ "dotted-underscore", GRID_ATTR_UNDERSCORE_4 },
{ "dashed-underscore", GRID_ATTR_UNDERSCORE_5 }
};

if (*str == '\0' || strcspn(str, delimiters) == 0)
return (-1);
Expand All @@ -64,24 +87,15 @@ attributes_fromstring(const char *str)
attr = 0;
do {
end = strcspn(str, delimiters);
if ((end == 6 && strncasecmp(str, "bright", end) == 0) ||
(end == 4 && strncasecmp(str, "bold", end) == 0))
attr |= GRID_ATTR_BRIGHT;
else if (end == 3 && strncasecmp(str, "dim", end) == 0)
attr |= GRID_ATTR_DIM;
else if (end == 10 && strncasecmp(str, "underscore", end) == 0)
attr |= GRID_ATTR_UNDERSCORE;
else if (end == 5 && strncasecmp(str, "blink", end) == 0)
attr |= GRID_ATTR_BLINK;
else if (end == 7 && strncasecmp(str, "reverse", end) == 0)
attr |= GRID_ATTR_REVERSE;
else if (end == 6 && strncasecmp(str, "hidden", end) == 0)
attr |= GRID_ATTR_HIDDEN;
else if (end == 7 && strncasecmp(str, "italics", end) == 0)
attr |= GRID_ATTR_ITALICS;
else if (end == 13 && strncasecmp(str, "strikethrough", end) == 0)
attr |= GRID_ATTR_STRIKETHROUGH;
else
for (i = 0; i < nitems(table); i++) {
if (end != strlen(table[i].name))
continue;
if (strncasecmp(str, table[i].name, end) == 0) {
attr |= table[i].attr;
break;
}
}
if (i == nitems(table))
return (-1);
str += end + strspn(str + end, delimiters);
} while (*str != '\0');
Expand Down
16 changes: 12 additions & 4 deletions grid.c
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,11 @@ grid_string_cells_code(const struct grid_cell *lastgc,
{ GRID_ATTR_BLINK, 5 },
{ GRID_ATTR_REVERSE, 7 },
{ GRID_ATTR_HIDDEN, 8 },
{ GRID_ATTR_STRIKETHROUGH, 9 }
{ GRID_ATTR_STRIKETHROUGH, 9 },
{ GRID_ATTR_UNDERSCORE_2, 42 },
{ GRID_ATTR_UNDERSCORE_3, 43 },
{ GRID_ATTR_UNDERSCORE_4, 44 },
{ GRID_ATTR_UNDERSCORE_5, 45 },
};
n = 0;

Expand All @@ -779,11 +783,15 @@ grid_string_cells_code(const struct grid_cell *lastgc,
else
strlcat(buf, "\033[", len);
for (i = 0; i < n; i++) {
if (i + 1 < n)
xsnprintf(tmp, sizeof tmp, "%d;", s[i]);
else
if (s[i] < 10)
xsnprintf(tmp, sizeof tmp, "%d", s[i]);
else {
xsnprintf(tmp, sizeof tmp, "%d:%d", s[i] / 10,
s[i] % 10);
}
strlcat(buf, tmp, len);
if (i + 1 < n)
strlcat(buf, ";", len);
}
strlcat(buf, "m", len);
}
Expand Down
Loading