glow icon indicating copy to clipboard operation
glow copied to clipboard

When output is redirected, terminal capabilities are ignored and colors are illegible

Open AndydeCleyre opened this issue 1 year ago β€’ 14 comments

Describe the bug When output is redirected/piped, terminal capabilities are ignored and colors are illegible.

Setup

  • Ubuntu 22.04 LTS
  • Zsh
  • Wezterm
  • tmux
  • en_US.UTF-8

To Reproduce

  1. Given a markdown README.md . . .
  2. Run:
$ CLICOLOR_FORCE=1 glow --style dark README.md | head

Source Code

Sample README

Expected behavior

The colors should be the same as they are when | head is omitted, and the header titles should have enough contrast to be easily read.

Screenshots

image

Additional context

See discussion at https://github.com/charmbracelet/glow/issues/440#issuecomment-2358748595

AndydeCleyre avatar Oct 17 '24 04:10 AndydeCleyre

Thanks for the excellent report.Β As mentioned, this looks like a regression. Off the cuff I'd guess it's downsampling to 4-bit ANSI (i.e. the 16 user-definable terminal colors; the first two rows in the following chart).

image

meowgorithm avatar Oct 17 '24 15:10 meowgorithm

It's the behavior of termenv, which glow uses. See https://github.com/muesli/termenv/blob/82936c5ea257b458deb5238e6093773b42c43773/termenv.go#L104.

In short, when being piped, it detects that no terminal capabilities are available, hence no color profile will be chosen. If you force the color output with CLICOLOR_FORCE=1 when no color profile is detected, it will fallback to 4-color ANSI.

folliehiyuki avatar Oct 18 '24 18:10 folliehiyuki

Aha, there we have it. Technically speaking CLICOLOR_FORCE=1 COLORTERM=truecolor glow-s dark filename.md | head should work, but it looks like it may have regressed upstream.

Alternatively, we could introduce a flag like glow --force-color-profile.

glow --force-color-profile=truecolor
glow --force-color-profile=ansi256
glow --force-color-profile=ansi
glow --force-color-profile=notty

meowgorithm avatar Oct 18 '24 20:10 meowgorithm

instead of the --force-color-profile flag, just use whatever value COLORTERM env var contains

Chaitanyabsprip avatar Oct 19 '24 05:10 Chaitanyabsprip

That’s fine by me, but termenv will need to be corrected upstream.

meowgorithm avatar Oct 19 '24 12:10 meowgorithm

https://github.com/charmbracelet/glow/issues/21#issuecomment-2467020125

script -q -c "glow README.md" | tail -n +2

nikelborm avatar Nov 11 '24 00:11 nikelborm

After some digging, I found something interesting.

bash -c "echo date_before_script: \$(date); script -q -c 'echo date_before_glow: \$(date); glow README.md; echo date_after_glow: \$(date)' > temp; cat temp; echo date_after_script: \$(date)" > temp2

Instead of > temp2 in the end you can use | sed '3d' to remove bad line and

with following README.md:

# header

1. _something_
2. *bold*


temp2 looks like this:

date_before_script: Mon Nov 11 04:22:13 MSK 2024
date_before_glow: Mon Nov 11 04:22:13 MSK 2024
]10;?\[6n]11;?\[6n]11;?\[6n
[38;5;228;48;5;63;1m[0m[38;5;228;48;5;63;1m[0m  [38;5;228;48;5;63;1m [0m[38;5;228;48;5;63;1mheader[0m[38;5;228;48;5;63;1m [0m[38;5;252m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[0m
[0m  [38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m
[38;5;252m[0m[38;5;252m[0m  [38;5;252m1[0m[38;5;252m. [0m[38;5;252;3msomething[0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m
[38;5;252m[0m[38;5;252m[0m  [38;5;252m2[0m[38;5;252m. [0m[38;5;252;3mbold[0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m

date_after_glow: Mon Nov 11 04:22:28 MSK 2024
date_after_script: Mon Nov 11 04:22:28 MSK 2024

Pairs of dates are exactly the same. Long execution is glow's or some other internally used library's responsibility. And for me it's always exactly 15 f***ing seconds. TTY is allocated immediately. And first line, that breaks output, is printed by glow too.

@eric-saintetienne (pinging because I think you'll be interested about it too because you did the same stuff here: https://github.com/charmbracelet/glow/issues/21#issuecomment-2360703369)

I tried tracing the program. I created following script:

#!/bin/bash

/bin/bash -c "echo date_before_script: \$(/sbin/date); /sbin/script -q -c 'echo date_before_glow: \$(/sbin/date); SHLVL=1 COLUMNS=180 LINES=49 /sbin/glow README.md; echo date_after_glow: \$(/sbin/date)' > temp; /sbin/cat temp; echo date_after_script: \$(/sbin/date)" > temp2

And then I'm running it

sudo strace ./sh

What I get

trace log
execve("./sh", ["./sh"], 0x7ffcd70817c0 /* 17 vars */) = 0
brk(NULL)                               = 0x5ae528cfd000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=194599, ...}) = 0
mmap(NULL, 194599, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a28493000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/libreadline.so.8", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=343064, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x758a28491000
mmap(NULL, 350904, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x758a2843b000
mmap(0x758a28450000, 188416, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15000) = 0x758a28450000
mmap(0x758a2847e000, 36864, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x43000) = 0x758a2847e000
mmap(0x758a28487000, 36864, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x4b000) = 0x758a28487000
mmap(0x758a28490000, 2744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x758a28490000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340_\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
fstat(3, {st_mode=S_IFREG|0755, st_size=2014520, ...}) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2034616, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x758a2824a000
mmap(0x758a2826e000, 1511424, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x24000) = 0x758a2826e000
mmap(0x758a283df000, 319488, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x195000) = 0x758a283df000
mmap(0x758a2842d000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e3000) = 0x758a2842d000
mmap(0x758a28433000, 31672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x758a28433000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/libncursesw.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=453896, ...}) = 0
mmap(NULL, 453856, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x758a281db000
mmap(0x758a281e8000, 290816, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xd000) = 0x758a281e8000
mmap(0x758a2822f000, 90112, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x54000) = 0x758a2822f000
mmap(0x758a28245000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6a000) = 0x758a28245000
close(3)                                = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x758a281d9000
arch_prctl(ARCH_SET_FS, 0x758a281d9b80) = 0
set_tid_address(0x758a281d9e50)         = 338133
set_robust_list(0x758a281d9e60, 24)     = 0
rseq(0x758a281da4a0, 0x20, 0, 0x53053053) = 0
mprotect(0x758a2842d000, 16384, PROT_READ) = 0
mprotect(0x758a28245000, 16384, PROT_READ) = 0
mprotect(0x758a28487000, 12288, PROT_READ) = 0
mprotect(0x5ae513c4d000, 12288, PROT_READ) = 0
mprotect(0x758a284fd000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x758a28493000, 194599)          = 0
openat(AT_FDCWD, "/dev/tty", O_RDWR|O_NONBLOCK) = 3
close(3)                                = 0
getrandom("\x9f\x6e\x12\xb3\x3b\xe2\x4e\x66", 8, GRND_NONBLOCK) = 8
brk(NULL)                               = 0x5ae528cfd000
brk(0x5ae528d1e000)                     = 0x5ae528d1e000
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=3055776, ...}) = 0
mmap(NULL, 3055776, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a27e00000
close(3)                                = 0
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2998, ...}) = 0
read(3, "# Locale name alias data base.\n#"..., 4096) = 2998
read(3, "", 4096)                       = 0
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=258, ...}) = 0
mmap(NULL, 258, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a284c2000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/gconv/gconv-modules.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=27010, ...}) = 0
mmap(NULL, 27010, PROT_READ, MAP_SHARED, 3, 0) = 0x758a284bb000
close(3)                                = 0
futex(0x758a2843272c, FUTEX_WAKE_PRIVATE, 2147483647) = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=23, ...}) = 0
mmap(NULL, 23, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a284ba000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_TELEPHONE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_TELEPHONE", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=47, ...}) = 0
mmap(NULL, 47, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a284b9000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_ADDRESS", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_ADDRESS", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=127, ...}) = 0
mmap(NULL, 127, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a284b8000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_NAME", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_NAME", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=62, ...}) = 0
mmap(NULL, 62, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a284b7000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_PAPER", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_PAPER", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=34, ...}) = 0
mmap(NULL, 34, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a284b6000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFDIR|0755, st_size=30, ...}) = 0
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MESSAGES/SYS_LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=48, ...}) = 0
mmap(NULL, 48, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a284b5000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_MONETARY", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MONETARY", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=270, ...}) = 0
mmap(NULL, 270, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a284b4000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_COLLATE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_COLLATE", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=1406, ...}) = 0
mmap(NULL, 1406, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a284b3000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_TIME", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_TIME", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=3360, ...}) = 0
mmap(NULL, 3360, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a284b2000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_NUMERIC", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_NUMERIC", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=50, ...}) = 0
mmap(NULL, 50, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a284b1000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=360460, ...}) = 0
mmap(NULL, 360460, PROT_READ, MAP_PRIVATE, 3, 0) = 0x758a28180000
close(3)                                = 0
getuid()                                = 0
getgid()                                = 0
geteuid()                               = 0
getegid()                               = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
rt_sigaction(SIGCHLD, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGCHLD, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x758a282871d0}, 8) = 0
rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, 8) = 0
rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, 8) = 0
rt_sigaction(SIGTSTP, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGTSTP, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, 8) = 0
rt_sigaction(SIGTTIN, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGTTIN, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, 8) = 0
rt_sigaction(SIGTTOU, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGTTOU, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
rt_sigaction(SIGQUIT, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, 8) = 0
uname({sysname="Linux", nodename="archhost", ...}) = 0
getcwd("/tmp/tmp.zGlsz5be5c", 4096)     = 20
getpid()                                = 338133
getppid()                               = 338130
getpid()                                = 338133
getppid()                               = 338130
getpid()                                = 338133
getppid()                               = 338130
getpgrp()                               = 338130
ioctl(2, TIOCGPGRP, [338130])           = 0
rt_sigaction(SIGCHLD, {sa_handler=0x5ae513b93a60, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x758a282871d0}, 8) = 0
prlimit64(0, RLIMIT_NPROC, NULL, {rlim_cur=54025, rlim_max=54025}) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
openat(AT_FDCWD, "./sh", O_RDONLY)      = 3
newfstatat(AT_FDCWD, "./sh", {st_mode=S_IFREG|0755, st_size=289, ...}, 0) = 0
ioctl(3, TCGETS, 0x7ffd50ed22c0)        = -1 ENOTTY (Inappropriate ioctl for device)
lseek(3, 0, SEEK_CUR)                   = 0
read(3, "#!/bin/bash\n\n\n/bin/bash -c \"echo"..., 80) = 80
lseek(3, 0, SEEK_SET)                   = 0
prlimit64(0, RLIMIT_NOFILE, NULL, {rlim_cur=1024, rlim_max=512*1024}) = 0
fcntl(255, F_GETFD)                     = -1 EBADF (Bad file descriptor)
dup2(3, 255)                            = 255
close(3)                                = 0
fcntl(255, F_SETFD, FD_CLOEXEC)         = 0
fcntl(255, F_GETFL)                     = 0x8000 (flags O_RDONLY|O_LARGEFILE)
fstat(255, {st_mode=S_IFREG|0755, st_size=289, ...}) = 0
lseek(255, 0, SEEK_CUR)                 = 0
read(255, "#!/bin/bash\n\n\n/bin/bash -c \"echo"..., 289) = 289
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
rt_sigprocmask(SIG_BLOCK, [INT TERM CHLD], [], 8) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x758a281d9e50) = 338134
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGINT, {sa_handler=0x5ae513b961e0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, 8) = 0
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 338134
rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=0x5ae513b961e0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, 8) = 0
ioctl(2, TIOCGWINSZ, {ws_row=78, ws_col=288, ws_xpixel=3456, ws_ypixel=2106}) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=338134, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, 0x7ffd50ed1210, WNOHANG, NULL) = -1 ECHILD (No child processes)
rt_sigreturn({mask=[]})                 = 0
read(255, "", 289)                      = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
exit_group(0)                           = ?
+++ exited with 0 +++

The most important part is where and how it hangs:

rt_sigaction(SIGINT, {sa_handler=0x5ae513b961e0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x758a282871d0}, 8) = 0
wait4(-1,

it hangs in this state with uncompleted line for 15 seconds. Here's the most interesting part. remember the trash line? Its three equal parts (]11;?\[6n) are being printed with equal noticeable time intervals one by one.

That's how stuff appears in a temp file:

  1. immediately after start file becomes:
date_before_glow: Mon Nov 11 05:19:21 MSK 2024
]10;?\[6n
  1. exactly after 5 second hanging file becomes:
date_before_glow: Mon Nov 11 05:25:08 MSK 2024
]10;?\[6n]11;?\[6n
  1. exactly after another 5 second hanging file becomes:
date_before_glow: Mon Nov 11 05:25:08 MSK 2024
]10;?\[6n]11;?\[6n]11;?\[6n
  1. exactly after YET ANOTHER 5 second hanging file becomes:
date_before_glow: Mon Nov 11 05:28:21 MSK 2024
]10;?\[6n]11;?\[6n]11;?\[6n
[38;5;228;48;5;63;1m[0m[38;5;228;48;5;63;1m[0m  [38;5;228;48;5;63;1m [0m[38;5;228;48;5;63;1mheader[0m[38;5;228;48;5;63;1m [0m[38;5;252m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[0m
[0m  [38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m
[38;5;252m[0m[38;5;252m[0m  [38;5;252m1[0m[38;5;252m. [0m[38;5;252;3msomething[0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m
[38;5;252m[0m[38;5;252m[0m  [38;5;252m2[0m[38;5;252m. [0m[38;5;252;3mbold[0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m[38;5;252m [0m

date_after_glow: Mon Nov 11 05:28:36 MSK 2024

Based on that, I conclude that it hangs each time AFTER it printed ]10;?\[6n. I don't know what's the f**k is going on. May be some kind of awaiting before output buffer filled, and flushing it when timeout expires? But why the f**k doesn't this shit appear in other case we run glow? πŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈ

Also interesting observation: I'm 99.99% sure that glow uses something similar with gh-cli under the hood to beatify Markdown. I went ahead and run the same test, but with a different command: gh repo view. Guess how many ]11;?\[6n in it's output?

  • 1

Guess how long it executes? 06:30:36 -- 06:30:42 (6 sec)

  • 5 (seconds) * 1 (]11;?\[6n) + 1 (second -- overhead to make a call to github API)

I tried to decode this ANSI code using this cheatsheet and this character inspector. In the end this seems like a command, to make some kind of cursor shift and then to request cursor position (ESC[6n).

And probably this artifitial TTY takes too long to respond and is being cutoff on timeout? πŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈ

Also I have a hypothesis about what's up with all the trash symbols being triggered by printing ]11;?\[6n -- I have no idea how ANSI works, but maybe that's the response with cursor position that was asked by ESC[6n? πŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈπŸ€·πŸ»β€β™€οΈ

Ideas?

nikelborm avatar Nov 11 '24 02:11 nikelborm

Until the fix is made somewhere, you can just use bat Prints more-less acceptable colored .md file.

bat --style=plain --color=always "$file"

nikelborm avatar Nov 11 '24 03:11 nikelborm

If only there was a way to find and disable this cursor shift with following cursor position request... πŸ˜‰πŸ˜‰

Would be nice if somebody from the team will help identify libraries or pieces of code playing the role here and how to disable them, so we will have a quite nice workaround πŸ˜‰πŸ˜‰

Here are common libraries between GitHub CLI and Glow. I assume the stuff we're looking is inside one of them:

(click to expand)
  • https://github.com/alecthomas/chroma
  • https://github.com/aymanbagabas/go-osc52
  • https://github.com/aymerick/douceur
  • https://github.com/charmbracelet/glamour
  • https://github.com/charmbracelet/lipgloss
  • https://github.com/dlclark/regexp2
  • https://github.com/fsnotify/fsnotify
  • https://github.com/gorilla/css
  • https://github.com/hashicorp/hcl
  • https://github.com/inconshreveable/mousetrap
  • https://github.com/lucasb-eyer/go-colorful
  • https://github.com/magiconair/properties
  • https://github.com/mattn/go-isatty
  • https://github.com/mattn/go-runewidth
  • https://github.com/microcosm-cc/bluemonday
  • https://github.com/mitchellh/go-homedir
  • https://github.com/mitchellh/mapstructure
  • https://github.com/muesli/reflow
  • https://github.com/muesli/termenv
  • https://github.com/pelletier/go-toml
  • https://github.com/rivo/uniseg
  • https://github.com/spf13/afero
  • https://github.com/spf13/cast
  • https://github.com/spf13/cobra
  • https://github.com/spf13/pflag
  • https://github.com/spf13/viper
  • https://github.com/subosito/gotenv
  • https://github.com/yuin/goldmark
  • https://github.com/yuin/goldmark-emoji
  • https://golang.org/x/exp
  • https://golang.org/x/net
  • https://golang.org/x/sync
  • https://golang.org/x/sys
  • https://golang.org/x/term
  • https://golang.org/x/text
  • https://gopkg.in/ini.v1
  • https://gopkg.in/yaml.v3

I assume (honestly nothing more that intuition) it's either muesli/reflow or muesli/termenv because the same issue (https://github.com/muesli/termenv/issues/136) appears to be there.

nikelborm avatar Nov 11 '24 04:11 nikelborm

My findings didn't end there.

I tried to create new theme based on https://github.com/charmbracelet/glamour/blob/master/styles/dark.json and run it with new theme. I changed all margin fields from 2 to 0.

Timing improved. Now it runs 5 seconds faster.

Before

time /bin/bash -c "echo date_before_script: \$(/sbin/date); /sbin/script -q -c 'echo date_before_glow: \$(/sbin/date); SHLVL=1 COLUMNS=180 LINES=49 /sbin/glow README.md; echo date_after_glow: \$(/sbin/date)' > temp; /sbin/cat temp; echo date_after_script: \$(/sbin/date)" > temp2
real	0m15.059s
user	0m0.021s
sys	0m0.015s
cat temp2 | sed '3d'
date_before_script: Sat Nov 16 00:06:52 MSK 2024
date_before_glow: Sat Nov 16 00:06:52 MSK 2024
   header                                                                         
                                                                                  
  1. something                                                                    
  2. bold                                                                         

date_after_glow: Sat Nov 16 00:07:07 MSK 2024
date_after_script: Sat Nov 16 00:07:07 MSK 2024

3rd line:

]10;?\[6n]11;?\[6n]11;?\[6n

After

time /bin/bash -c "echo date_before_script: \$(/sbin/date); /sbin/script -q -c 'echo date_before_glow: \$(/sbin/date); SHLVL=1 COLUMNS=180 LINES=49 /sbin/glow -s ./mystyle.json README.md; echo date_after_glow: \$(/sbin/date)' > temp; /sbin/cat temp; echo date_after_script: \$(/sbin/date)" > temp2
real	0m10.054s
user	0m0.020s
sys	0m0.015s
cat temp2 | sed '3d'
date_before_script: Sat Nov 16 00:10:52 MSK 2024
date_before_glow: Sat Nov 16 00:10:52 MSK 2024
 header                                                                         
                                                                                
1. something                                                                    
2. bold                                                                         

date_after_glow: Sat Nov 16 00:11:02 MSK 2024
date_after_script: Sat Nov 16 00:11:02 MSK 2024

3rd line:

]10;?\[6n]11;?\[6n

Edited theme:

{
  "document": {
    "block_prefix": "\n",
    "block_suffix": "\n",
    "color": "252",
    "margin": 0
  },
  "block_quote": {
    "indent": 1,
    "indent_token": "β”‚ "
  },
  "paragraph": {},
  "list": {
    "level_indent": 2
  },
  "heading": {
    "block_suffix": "\n",
    "color": "39",
    "bold": true
  },
  "h1": {
    "prefix": " ",
    "suffix": " ",
    "color": "228",
    "background_color": "63",
    "bold": true
  },
  "h2": {
    "prefix": "## "
  },
  "h3": {
    "prefix": "### "
  },
  "h4": {
    "prefix": "#### "
  },
  "h5": {
    "prefix": "##### "
  },
  "h6": {
    "prefix": "###### ",
    "color": "35",
    "bold": false
  },
  "text": {},
  "strikethrough": {
    "crossed_out": true
  },
  "emph": {
    "italic": true
  },
  "strong": {
    "bold": true
  },
  "hr": {
    "color": "240",
    "format": "\n--------\n"
  },
  "item": {
    "block_prefix": "β€’ "
  },
  "enumeration": {
    "block_prefix": ". "
  },
  "task": {
    "ticked": "[βœ“] ",
    "unticked": "[ ] "
  },
  "link": {
    "color": "30",
    "underline": true
  },
  "link_text": {
    "color": "35",
    "bold": true
  },
  "image": {
    "color": "212",
    "underline": true
  },
  "image_text": {
    "color": "243",
    "format": "Image: {{.text}} β†’"
  },
  "code": {
    "prefix": " ",
    "suffix": " ",
    "color": "203",
    "background_color": "236"
  },
  "code_block": {
    "color": "244",
    "margin": 0,
    "chroma": {
      "text": {
        "color": "#C4C4C4"
      },
      "error": {
        "color": "#F1F1F1",
        "background_color": "#F05B5B"
      },
      "comment": {
        "color": "#676767"
      },
      "comment_preproc": {
        "color": "#FF875F"
      },
      "keyword": {
        "color": "#00AAFF"
      },
      "keyword_reserved": {
        "color": "#FF5FD2"
      },
      "keyword_namespace": {
        "color": "#FF5F87"
      },
      "keyword_type": {
        "color": "#6E6ED8"
      },
      "operator": {
        "color": "#EF8080"
      },
      "punctuation": {
        "color": "#E8E8A8"
      },
      "name": {
        "color": "#C4C4C4"
      },
      "name_builtin": {
        "color": "#FF8EC7"
      },
      "name_tag": {
        "color": "#B083EA"
      },
      "name_attribute": {
        "color": "#7A7AE6"
      },
      "name_class": {
        "color": "#F1F1F1",
        "underline": true,
        "bold": true
      },
      "name_constant": {},
      "name_decorator": {
        "color": "#FFFF87"
      },
      "name_exception": {},
      "name_function": {
        "color": "#00D787"
      },
      "name_other": {},
      "literal": {},
      "literal_number": {
        "color": "#6EEFC0"
      },
      "literal_date": {},
      "literal_string": {
        "color": "#C69669"
      },
      "literal_string_escape": {
        "color": "#AFFFD7"
      },
      "generic_deleted": {
        "color": "#FD5B5B"
      },
      "generic_emph": {
        "italic": true
      },
      "generic_inserted": {
        "color": "#00D787"
      },
      "generic_strong": {
        "bold": true
      },
      "generic_subheading": {
        "color": "#777777"
      },
      "background": {
        "background_color": "#373737"
      }
    }
  },
  "table": {},
  "definition_list": {},
  "definition_term": {},
  "definition_description": {
    "block_prefix": "\n🠢 "
  },
  "html_block": {},
  "html_span": {}
}

It is definitely faster and definitely because of reducing amount of escape sequences which are being attempted to be printed by glow.

nikelborm avatar Nov 15 '24 21:11 nikelborm

Next I'm gonna look for how margin is used and can we remove 2 ANSI sequences left

nikelborm avatar Nov 15 '24 21:11 nikelborm

Came here via the other thread, after gradually realizing my intermittent problem with ANSI garble and big slow downs was coming from glow and maybe related to stuff like CLICOLOR_FORCE / COLORTERM, pty, and pipes. I had different scripts using a docker-glow and a snap-glow at different times in different places, basically the same in terms of output though. This comment https://github.com/charmbracelet/glow/issues/440#issuecomment-2307992634 got me to check the versions of each.

I can confirm downgrading just fixes this, and https://hub.docker.com/layers/charmcli/glow/v1.5.1 works for my use-case as expected. No breaking changes by using a lower version everywhere, but my usage is noninteractive, not passing any flags, and not using external config.

mattvonrocketstein avatar Mar 16 '25 20:03 mattvonrocketstein

I also had to downgrade to version 1.5.1. It works well.

AmaruCoder avatar Jun 16 '25 05:06 AmaruCoder

Hi guys, out of curiosity but it there any news on this? Has an upstream issue been opened? Thanks!

carlosedp avatar Oct 16 '25 20:10 carlosedp