mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
289 lines
9.4 KiB
Bash
289 lines
9.4 KiB
Bash
#!/bin/bash
|
||
|
||
# Test cursor row, column placement after sixel image is sent.
|
||
|
||
# After a sixel image is displayed, the text cursor is moved to the
|
||
# row of the last sixel cursor position, but the column stays the same
|
||
# as it was before the sixel image was sent.
|
||
#
|
||
# This can be thought of as sixel images always ending with an
|
||
# implicit Graphics Carriage Return (`$`).
|
||
|
||
# ADDENDUM: It is not as simple as I thought. When a row of sixels
|
||
# straddles two rows of text, the text cursor can be left on the upper row.
|
||
# It seems up to three lines of pixels may be beneath any words printed.
|
||
#
|
||
# The rule for when this happens is not obvious to me, but can be seen
|
||
# with images of height: 21, 22, 23, 24, 41, 42, 81, 82, 83, 84...
|
||
#
|
||
# My guess:
|
||
# for a sixel image of height h, let a=(h-1)%6 and b=(h-1)%20,
|
||
# then, the text will overlap the image when a>b.
|
||
#
|
||
# If that is the case, then the entire list of heights for which this
|
||
# will happen on the VT340's 480 pixel high screen is:
|
||
#
|
||
# 21 22 23 24 41 42 81 82 83 84
|
||
# 101 102 141 142 143 144 161 162
|
||
# 201 202 203 204 221 222 261 262 263 264 281 282
|
||
# 321 322 323 324 341 342 381 382 383 384
|
||
# 401 402 441 442 443 444 461 462
|
||
#
|
||
# Note that there are 48 entries, so that means there's a 10% chance
|
||
# if heights are chosen randomly from 1 to 480. However, if one were
|
||
# to always pick heights which are a multiple of the character cell
|
||
# height (20px), then the chances are 0% as there are no problematic
|
||
# heights divisible by 20.
|
||
|
||
|
||
# Sixel images often do *not* end with a `-` (Graphics New Line = GNL)
|
||
# which sends the sixel cursor down 6 pixels. Any text printed next
|
||
# will potentially overlap the last row of sixels!
|
||
|
||
# I am not yet positive, but I believe that, in general, applications
|
||
# should send sixel images without a GNL but then send `^J`, a text
|
||
# newline (NL), before displaying more text or graphics.
|
||
|
||
# IMPORTANT: sometimes neither a graphics nor a text newline is wanted.
|
||
# For example, if an image is full screen, either newline would cause
|
||
# the top line to scroll off the screen.
|
||
|
||
# | Text cursor column | Text cursor row
|
||
# --------|--------------------|-------------------------------------
|
||
# !GNL !NL| Unchanged | Overlapping last line of graphics
|
||
# !GNL NL| Column=1 | First line immediately after graphic (usually)
|
||
# GNL !NL| Unchanged | _Sometimes_ overlapping graphics
|
||
# GNL NL| Column=1 | First *or* second line after graphic
|
||
|
||
|
||
CSI=$'\e[' # Control Sequence Introducer
|
||
DCS=$'\eP' # Device Control String
|
||
ST=$'\e\\' # String Terminator
|
||
|
||
set_cursor_pos() {
|
||
# Home, top left is row 1, col 1.
|
||
local row=$1 col=$2
|
||
echo -n ${CSI}${row}';'${col}'H'
|
||
}
|
||
|
||
reset_palette() {
|
||
# Send DECRSTS to load colors from a Color Table Report
|
||
echo -n ${DCS}'2$p'
|
||
|
||
echo -n "0;2;0;0;0/" # VT color #0 is black and BG text color
|
||
|
||
echo -n "1;2;20;20;79/" # VT color #1 is blue
|
||
echo -n "2;2;79;13;13/" # VT color #2 is red
|
||
echo -n "3;2;20;79;20/" # VT color #3 is green
|
||
|
||
echo -n "4;2;79;20;79/" # VT color #4 is magenta
|
||
echo -n "5;2;20;79;79/" # VT color #5 is cyan
|
||
echo -n "6;2;79;79;20/" # VT color #6 is yellow
|
||
|
||
echo -n "7;2;46;46;46/" # VT color #7 is gray 50% and FG text color
|
||
echo -n "8;2;26;26;26/" # VT color #8 is gray 25%
|
||
|
||
echo -n "9;2;33;33;59/" # VT color #9 is pastel blue
|
||
echo -n "10;2;59;26;26/" # VT color #10 is pastel red
|
||
echo -n "11;2;33;59;33/" # VT color #11 is pastel green
|
||
|
||
echo -n "12;2;59;33;59/" # VT color #12 is pastel magenta
|
||
echo -n "13;2;33;59;59/" # VT color #13 is pastel cyan
|
||
echo -n "14;2;59;59;33/" # VT color #14 is pastel yellow
|
||
|
||
echo -n "15;2;79;79;79" # VT color #15 is gray 75% and BOLD text color
|
||
|
||
echo -n ${ST} # String Terminator
|
||
}
|
||
|
||
# Generate square of size w with final graphics new line removed
|
||
square() {
|
||
# Given a color index number and (optionally) a size, row, and column,
|
||
# draw a square with top left corner at (row, column) and of size×size px.
|
||
# Default size 100×100px (10cols, 5 rows)
|
||
|
||
local -i color=${1:-1} # Default is color index 1 (blue)
|
||
local -i size=${2:-100} # Size in pixels (defaults to 100)
|
||
local -i row=$3 column=$4 # If set to 0, cursor is not moved
|
||
|
||
if [[ row -ne 0 && column -ne 0 ]]; then
|
||
set_cursor_pos $row $column
|
||
fi
|
||
|
||
# Draw a square of the right color & size
|
||
squaresize $color $size
|
||
}
|
||
|
||
squaresize() {
|
||
# Helper for square() that uses convert to return a sixel square of
|
||
# the right color ($1) and size ($2).
|
||
|
||
# Similar to this but with variable size squares:
|
||
# echo -n ${DCS}'0;0;0q"1;1;100;100#'${color}'!100~-!100~-!100~-!100~-!100~-!100~-!100~-!100~-!100~-!100~-!100~-!100~-!100~-!100~-!100~-!100~-!100N'${ST}
|
||
|
||
|
||
local color=${1:-1} # Default color index is 1 (blue)
|
||
local size=${2:-100} # Default size is 100x100
|
||
|
||
# Get a sixel string
|
||
local sq=$(convert -geometry ${size}x${size} xc:black sixel:-)
|
||
|
||
# Remove ImageMagick's extraneous Graphic New Line at end of image.
|
||
sq=${sq%-??}$'\e\\'
|
||
|
||
# VT340s always used the same color register for the first sixel
|
||
# color defined no matter what number it was assigned. That means,
|
||
# each time we send a new sixel image, the previous one's color
|
||
# palette gets changed. We don't want squares of all the same
|
||
# color, so remove the color definition and just use the defaults.
|
||
sq=${sq/\#0;2;0;0;0/}
|
||
|
||
# And finally, switch to the proper index for the color we want.
|
||
echo -n ${sq//\#0/#${color}}
|
||
}
|
||
|
||
squaregnl() {
|
||
# Same as square(), but sends a graphics newline at the end of the sixels.
|
||
# (Sticks a `-` before the String Terminator, "Esc \")
|
||
sq=$(square "${@}")
|
||
echo -n ${sq%??}$'-\e\\'
|
||
}
|
||
|
||
|
||
main() {
|
||
clear
|
||
reset_palette
|
||
show_labels
|
||
neither_graphic_nor_text 96 4 4 31 # size, color, row, column
|
||
text_newline_only 96 9 4 1
|
||
text_newline_only 84 9 4 14
|
||
graphics_new_line_only 100 1 4 51
|
||
graphics_new_line_only 96 1 4 64
|
||
set_cursor_pos 1000 1
|
||
}
|
||
|
||
|
||
neither_graphic_nor_text() {
|
||
# Typically sixel images should not end with a Graphics New Line (GNL)
|
||
# However, if a text newline isn't sent, there will be overlap.
|
||
|
||
local -i size color row column
|
||
read size color row column <<<"$@"
|
||
|
||
set_cursor_pos $((row++)) $column
|
||
echo -n "Height $size"
|
||
set_cursor_pos $((row++)) $column
|
||
|
||
# Three squares sent as separate sixel images, indented +1
|
||
for i in {1..3}; do
|
||
square $((color++)) $size
|
||
tput cuf 1
|
||
done
|
||
|
||
echo -n "overlap?"
|
||
}
|
||
|
||
|
||
text_newline_only() {
|
||
# USING A TEXT NEWLINE (NL) after an sixel image that does NOT
|
||
# have GNL is probably the best way to be on the text line
|
||
# immediately below the image. However, the text will still
|
||
# occasionally overlap the last four rows of pixels.
|
||
|
||
# Also, if multiple images are intended to be shown, there will
|
||
# usually be a gap between them when using a text newline.
|
||
|
||
# Overlap happens because the height of a text cell is 20 pixels
|
||
# and the height of a sixel is 6.
|
||
# for (h=0; h<480; h++) if ((h-1)%6 > (h-1)%20 ) { h }
|
||
|
||
# Let the pixel position of the top of the graphics cursor be 'Yg'
|
||
# and let the pixel position of the top of the corresponding cell
|
||
# of text which the text cursor will be placed on be 'Yt'. Note
|
||
# that Yg is evenly divisible by 6 and Yt, by 20. Taking the
|
||
# remainder, r, after dividing Yg by 20 tells us how many pixels
|
||
# down into a row of text the last line of sixels started. When
|
||
# r==0, the sixels started at the top of the text row.
|
||
|
||
# When r = 14, the sixels covered the bottom six pixels on the row
|
||
# of text. When 14 < r < 20, the sixel line impinged by r - 14
|
||
# pixels into the text row below and there is a chance the next
|
||
# text printed will overlap.
|
||
|
||
|
||
local -i size color row column
|
||
read size color row column <<<"$@"
|
||
|
||
local -i offset
|
||
offset=$((column-1))
|
||
|
||
set_cursor_pos $row 1
|
||
|
||
if ((offset)); then tput cuf $((offset)); fi
|
||
echo "Height $size"
|
||
|
||
# Three squares, separated by text new lines and indented +1
|
||
for i in {1..3}; do
|
||
if ((offset)); then tput cuf $offset; fi
|
||
square $((color++)) $size
|
||
offset=offset+1
|
||
echo
|
||
done
|
||
|
||
tput cuf $((offset))
|
||
echo -n "overlap?"
|
||
}
|
||
|
||
graphics_new_line_only() {
|
||
# However, some sixel images end with a `-`, a Graphics New Line.
|
||
# This can be useful for writing another image starting at the same
|
||
# column without having to reposition the cursor.
|
||
#
|
||
# However, this runs the risk of having occasional overlap.
|
||
|
||
local -i size color row column
|
||
read size color row column <<<"$@"
|
||
|
||
set_cursor_pos $((row++)) $column
|
||
echo -n "Height $size"
|
||
set_cursor_pos $((row++)) $column
|
||
|
||
# Three squares, separated by graphics new lines and indented +1
|
||
for i in {1..3}; do
|
||
squaregnl $((color++)) $size
|
||
tput cuf 1
|
||
done
|
||
|
||
echo -n "overlap?"
|
||
}
|
||
|
||
|
||
show_labels() {
|
||
set_cursor_pos 1 10
|
||
echo -n "Should sixel images include a GNL ('-') at the end?"
|
||
|
||
set_cursor_pos 3 29
|
||
echo -n "Neither NL nor GNL"
|
||
set_cursor_pos 3 1
|
||
echo -n "Text New Line only"
|
||
set_cursor_pos 3 51
|
||
echo -n "Graphics New Line only"
|
||
|
||
set_cursor_pos 22 29
|
||
echo -n "Always overlaps" # Neither NL nor GNL
|
||
|
||
set_cursor_pos 22 3
|
||
echo -n "Overlaps a little" # NL only
|
||
set_cursor_pos 23 3
|
||
echo -n " Gaps a little" # NL only
|
||
|
||
set_cursor_pos 22 54
|
||
echo -n "Overlaps badly" # GNL only
|
||
set_cursor_pos 23 54
|
||
echo -n "Never gaps" # GNL only
|
||
}
|
||
|
||
|
||
main
|
||
|