summaryrefslogtreecommitdiff
path: root/tui/termfo/term.h.zsh
diff options
context:
space:
mode:
Diffstat (limited to 'tui/termfo/term.h.zsh')
-rwxr-xr-xtui/termfo/term.h.zsh427
1 files changed, 427 insertions, 0 deletions
diff --git a/tui/termfo/term.h.zsh b/tui/termfo/term.h.zsh
new file mode 100755
index 0000000..aba713b
--- /dev/null
+++ b/tui/termfo/term.h.zsh
@@ -0,0 +1,427 @@
+#!/usr/bin/env zsh
+[ "${ZSH_VERSION:-}" = "" ] && echo >&2 "Only works with zsh" && exit 1 # Just in case people type "bash term.h.zsh".
+setopt err_exit no_unset no_clobber pipefail
+
+# TODO: also look at capalias and infoalias in Caps-ncurses.
+#
+# https://github.com/benhoyt/goawk can run from within Go; that might actually
+# be quite nice for this and removes the dependency on zsh and awk.
+
+src=${1:-~/ncurses}
+if [[ ! -d $src ]]; then
+ print >&2 "ncurses source not in $src; can't generate term.h.go"
+ print >&2 'Usage: term.h.zsh [source-tree]'
+ exit 1
+fi
+
+main() {
+ mkdir -p caps scaps keys
+ caps >|caps/caps.go
+ scaps >|scaps/scaps.go
+ caps_table >|caps/table.go
+ keys >|keys/keys.go
+ gofmt -w caps/caps.go scaps/scaps.go caps/table.go keys/keys.go
+}
+
+funs=$(<<'EOF'
+ function ucfirst(s) {
+ return toupper(substr(s, 1, 1)) substr(s, 2)
+ }
+
+ function camelCase(s) {
+ while (i = index(s, "_"))
+ s = substr(s, 0, i-1) toupper(substr(s, i+1, 1)) substr(s, i+2)
+ return ucfirst(s)
+ }
+EOF
+)
+
+# Print package header.
+# pkg pkgname [pkgcomment] [add-version] [import]
+pkg() {
+ print '// Code generated by term.h.zsh; DO NOT EDIT.\n'
+ (( $# > 1 && ${#2:-} > 0 )) && print "// Package $1 $2"
+ print "package $1\n"
+ (( $# > 2 )) && print $3
+ if (( $# < 4 )); then
+ print '// CursesVersion is the version of curses this data was generated with, as [implementation]-[version].'
+ awk '{printf "const CursesVersion = `ncurses-%s.%s`\n\n", $2, $3 }' $src/VERSION
+ fi
+ return 0
+}
+
+cap_ignore=$(<<-'EOF'
+ BEGIN {
+ ignore["tilde_glitch"] = 1 # Hacks for ancient hardware terms.
+ ignore["eat_newline_glitch"] = 1
+ ignore["insert_null_glitch"] = 1
+ ignore["col_addr_glitch"] = 1
+ ignore["row_addr_glitch"] = 1
+ ignore["magic_cookie_glitch"] = 1
+ ignore["magic_cookie_glitch_ul"] = 1
+ ignore["ceol_standout_glitch"] = 1
+ ignore["hard_cursor"] = 1
+ ignore["no_esc_ctlc"] = 1
+ ignore["new_line_delay"] = 1
+ ignore["carriage_return_delay"] = 1
+ ignore["no_correctly_working_cr"] = 1
+ ignore["crt_no_scrolling"] = 1
+ ignore["linefeed_if_not_lf"] = 1
+ ignore["backspace_if_not_bs"] = 1
+ ignore["linefeed_is_newline"] = 1
+ ignore["backspace_delay"] = 1
+ ignore["horizontal_tab_delay"] = 1
+ ignore["other_non_function_keys"] = 1
+ ignore["number_of_function_keys"] = 1
+ ignore["arrow_key_map"] = 1
+ ignore["return_does_clr_eol"] = 1
+ ignore["dest_tabs_magic_smso"] = 1
+ ignore["non_dest_scroll_region"] = 1
+ ignore["non_rev_rmcup"] = 1
+ ignore["padding_baud_rate"] = 1
+ ignore["has_print_wheel"] = 1 # No vaguely modern terminal has this.
+ ignore["set_left_margin"] = 1
+ ignore["set_right_margin"] = 1
+ ignore["set_bottom_margin"] = 1
+ ignore["set_bottom_margin_parm"] = 1
+ ignore["set_top_margin"] = 1
+ ignore["set_top_margin_parm"] = 1
+ ignore["set_tb_margin"] = 1
+ ignore["order_of_pins"] = 1
+ ignore["lines_of_memory"] = 1
+ ignore["output_res_char"] = 1
+ ignore["output_res_line"] = 1
+ ignore["wide_char_size"] = 1
+ ignore["enter_doublewide_mode"] = 1
+ ignore["exit_doublewide_mode"] = 1
+ ignore["hue_lightness_saturation"] = 1
+ ignore["fixed_pause"] = 1
+ ignore["hangup"] = 1
+ ignore["dial_phone"] = 1
+ ignore["pulse"] = 1
+ ignore["flash_hook"] = 1
+ ignore["quick_dial"] = 1
+ ignore["wait_tone"] = 1
+ ignore["tone"] = 1
+ ignore["set_clock"] = 1
+ ignore["display_clock"] = 1
+ ignore["remove_clock"] = 1
+ ignore["create_window"] = 1
+ ignore["goto_window"] = 1
+ ignore["set_window"] = 1
+ ignore["maximum_windows"] = 1
+ ignore["number_of_pins"] = 1
+ ignore["plab_norm"] = 1
+ ignore["label_format"] = 1
+ ignore["num_labels"] = 1
+ ignore["label_height"] = 1
+ ignore["label_width"] = 1
+ ignore["label_on"] = 1
+ ignore["label_off"] = 1
+ ignore["lab_f0"] = 1
+ ignore["lab_f1"] = 1
+ ignore["lab_f10"] = 1
+ ignore["lab_f2"] = 1
+ ignore["lab_f3"] = 1
+ ignore["lab_f4"] = 1
+ ignore["lab_f5"] = 1
+ ignore["lab_f6"] = 1
+ ignore["lab_f7"] = 1
+ ignore["lab_f8"] = 1
+ ignore["lab_f9"] = 1
+ ignore["semi_auto_right_margin"] = 1
+ ignore["enter_draft_quality"] = 1
+ ignore["enter_near_letter_quality"] = 1
+ ignore["enter_normal_quality"] = 1
+ ignore["generic_type"] = 1
+ ignore["set_left_margin_parm"] = 1 # Setting margins kind-of in e.g. xterm, but it's pretty broken and useless.
+ ignore["set_right_margin_parm"] = 1
+ ignore["set_lr_margin"] = 1
+ ignore["clear_margins"] = 1
+ ignore["auto_left_margin"] = 1 # I can't figure out what these "automatic margins" do, or how they work. So I'm going to guess it's not really useful.
+ ignore["auto_right_margin"] = 1
+ ignore["enter_am_mode"] = 1
+ ignore["exit_am_mode"] = 1
+ ignore["cr_cancels_micro_mode"] = 1 # "Micro mode", whatever that is; only on QNX 4.
+ ignore["max_micro_address"] = 1
+ ignore["max_micro_jump"] = 1
+ ignore["micro_col_size"] = 1
+ ignore["micro_line_size"] = 1
+ ignore["enter_micro_mode"] = 1
+ ignore["exit_micro_mode"] = 1
+ ignore["micro_column_address"] = 1
+ ignore["micro_down"] = 1
+ ignore["micro_left"] = 1
+ ignore["micro_right"] = 1
+ ignore["micro_row_address"] = 1
+ ignore["micro_up"] = 1
+ ignore["parm_down_micro"] = 1
+ ignore["parm_left_micro"] = 1
+ ignore["parm_right_micro"] = 1
+ ignore["parm_up_micro"] = 1
+ ignore["prtr_silent"] = 1 # Printer support; no one has that.
+ ignore["prtr_non"] = 1
+ ignore["set_pglen_inch"] = 1
+ ignore["change_char_pitch"] = 1
+ ignore["change_line_pitch"] = 1
+ ignore["output_res_horz_inch"] = 1
+ ignore["output_res_vert_inch"] = 1
+ ignore["dot_vert_spacing"] = 1
+ ignore["dot_horz_spacing"] = 1
+ ignore["buffer_capacity"] = 1
+ ignore["print_rate"] = 1
+ ignore["print_screen"] = 1
+ ignore["prtr_off"] = 1
+ ignore["prtr_on"] = 1
+ ignore["prtr_non"] = 1
+ ignore["start_bit_image"] = 1
+ ignore["stop_bit_image"] = 1
+ ignore["these_cause_cr"] = 1
+ ignore["hard_copy"] = 1
+ ignore["bit_image_entwining"] = 1 # Not supported by anything.
+ ignore["bit_image_type"] = 1
+ ignore["bit_image_repeat"] = 1
+ ignore["bit_image_newline"] = 1
+ ignore["bit_image_carriage_return"] = 1
+ ignore["define_bit_image_region"] = 1
+ ignore["end_bit_image_region"] = 1
+
+ # dsl / disable_status_line
+ # kitty = clear window title
+
+ names[""] = ""
+ }
+EOF
+)
+
+# Generate caps/caps.go
+caps() {
+ pkg caps 'contains a list of all terminfo capabilities.'
+ cat <<-'EOF'
+ // Cap represents a capability as listed in a terminfo file.
+ type Cap struct {
+ Short string // Short terminfo name
+ Long string // Longer variable name from term.h
+ Desc string // Description from terminfo(5)
+ }
+ EOF
+
+ print "var ("
+ awk <$src/include/Caps "$funs $cap_ignore $(<<-'EOF'
+ /^[^#]/ {
+ # TODO: breaks too much
+ # if (ignore[$1] != "" || match($1, "^key_"))
+ # next
+ name = names[$1]
+ if (name == "")
+ name = camelCase($1)
+ printf "\t%s = &Cap{`%s`, `%s`, `%s", name, $2, $1, $8
+ for (i=9; i<=NF; i++)
+ printf " %s", $i
+ print "`}"
+ }
+ EOF
+ )"
+
+ print '\n// Extentions'
+ awk <$src/include/Caps-ncurses "$funs $cap_ignore $(<<-'EOF'
+ $1 == "used_by" { used_by = $2 }
+ $1 == "userdef" {
+ # Some entries are listed more than once (xm and RGB).
+ # TODO: append the descriptions?
+ if (uniq[$2])
+ next
+ uniq[$2] = 1
+
+ printf "\t%s = &Cap{`%s`, `%s`, `%s", camelCase($2), $2, $1, $5
+ for (i=6; i<=NF; i++)
+ printf " %s", $i
+ printf " (%s)`}\n", used_by
+ }
+ EOF
+ )"
+ print ")"
+}
+
+# Generage scaps/scaps.go
+scaps() {
+ pkg scaps 'contains a list of all terminfo capabilities.' 'import "zgo.at/termfo/caps"'
+
+ print "var ("
+ awk <$src/include/Caps "$funs $(<<-'EOF'
+ /^[^#]/ {
+ print "\t" ucfirst($2) " = caps." camelCase($1)
+ }
+ EOF
+ )"
+
+ print '\n// Extentions'
+ awk <$src/include/Caps-ncurses "$funs $(<<-'EOF'
+ $1 == "used_by" { used_by = $2 }
+ $1 == "userdef" {
+ if (uniq[$2])
+ next
+ uniq[$2] = 1
+ print "\t" ucfirst($2) " = caps." ucfirst($2)
+ }
+ EOF
+ )"
+ print ")"
+}
+
+# Generate caps/table.go
+caps_table() {
+ pkg caps '' '' 'no-version'
+ print "var unused *Cap = nil\n"
+
+ for t in bool num str; do
+ tu=${t[1]:u}${t[2,-1]}
+ print "var Table${tu}s = []*Cap{"
+ awk <$src/include/Caps "$funs $cap_ignore ${$(<<-'EOF'
+ /^[^#]/ && $3 == "TYPE" {
+ name = names[$1]
+ if (name == "")
+ name = camelCase($1)
+ # TODO: breaks too much
+ # if (ignore[$1] != "" || match($1, "^key_"))
+ # name = "unused"
+ print name ","
+ }
+ EOF
+ )//TYPE/$t}"
+
+ print '\n// Extensions'
+ awk <$src/include/Caps-ncurses "$funs $cap_ignore ${$(<<-'EOF'
+ $1 == "userdef" && $3 == "TYPE" {
+ print camelCase($2) ","
+ }
+ EOF
+ )//TYPE/$t}"
+ print "}\n"
+ done
+}
+
+# List all key caps.
+keys() {
+ pkg keys '' 'import "zgo.at/termfo/caps"'
+ # pkg keys '' ''
+
+ awk <$src/include/Caps "$funs $(<<-'EOF'
+ BEGIN {
+ print "// Keys maps caps.Cap to Key constants"
+ print "var Keys = map[*caps.Cap]Key{"
+ # print "var Keys = map[Key]string{"
+ i = -1
+
+ # Obscure keys present on very old devices; most people have neither
+ # heard nor used any of these devices or keys, so there's not much
+ # point including them. Can still use the termCaps if you really
+ # want to, just don't need a shortcut for them.
+ #
+ # Some of these are still useful codes to send, but they're just not
+ # keys (anymore).
+ #
+ # Use ./cmd/termfo to print terminals which have a certain capability.
+ ignore["Catab"] = 1
+ ignore["Ctab"] = 1
+ ignore["Dl"] = 1; ignore["Sdl"] = 1
+ ignore["Eic"] = 1
+ ignore["Eol"] = 1; ignore["Seol"] = 1
+ ignore["Eos"] = 1
+ ignore["Il"] = 1
+ ignore["Sr"] = 1
+ ignore["Sf"] = 1
+ ignore["Clear"] = 1
+ ignore["F0"] = 1
+ ignore["Ll"] = 1
+ ignore["Stab"] = 1
+ ignore["A1"] = 1
+ ignore["A3"] = 1
+ ignore["B2"] = 1
+ ignore["C1"] = 1
+ ignore["C3"] = 1
+ ignore["Beg"] = 1; ignore["Sbeg"] = 1
+ ignore["Cancel"] = 1; ignore["Scancel"] = 1
+ ignore["Close"] = 1; ignore["Close"] = 1
+ ignore["Command"] = 1; ignore["Scommand"] = 1
+ ignore["Copy"] = 1; ignore["Scopy"] = 1
+ ignore["Create"] = 1; ignore["Screate"] = 1
+ ignore["Exit"] = 1; ignore["Sexit"] = 1
+ ignore["Find"] = 1; ignore["Sfind"] = 1
+ ignore["Help"] = 1; ignore["Shelp"] = 1
+ ignore["Mark"] = 1; ignore["Smark"] = 1
+ ignore["Message"] = 1; ignore["Smessage"] = 1
+ ignore["Move"] = 1; ignore["Smove"] = 1
+ ignore["Next"] = 1; ignore["Snext"] = 1
+ ignore["Open"] = 1; ignore["Sopen"] = 1
+ ignore["Options"] = 1; ignore["Soptions"] = 1
+ ignore["Save"] = 1; ignore["Ssave"] = 1
+ ignore["Previous"] = 1; ignore["Sprevious"] = 1
+ ignore["Print"] = 1; ignore["Sprint"] = 1
+ ignore["Redo"] = 1; ignore["Sredo"] = 1
+ ignore["Reference"] = 1; ignore["sreference"] = 1
+ ignore["Refresh"] = 1; ignore["srefresh"] = 1
+ ignore["Replace"] = 1; ignore["Sreplace"] = 1
+ ignore["Restart"] = 1; ignore["srestart"] = 1
+ ignore["Resume"] = 1; ignore["Srsume"] = 1
+ ignore["Suspend"] = 1; ignore["Ssuspend"] = 1
+ ignore["Undo"] = 1; ignore["Sundo"] = 1
+ ignore["Select"] = 1; ignore["Sselect"] = 1
+
+ # Rename some things for clarity.
+ rename["Ic"] = "Insert"; rename["Sic"] = "ShiftInsert"
+ rename["Dc"] = "Delete"; rename["Sdc"] = "ShiftDelete"
+ rename["Ppage"] = "PageUp"
+ rename["Npage"] = "PageDown"
+ rename["Btab"] = "BackTab"
+ rename["Shome"] = "ShiftHome"
+ rename["Send"] = "ShiftEnd"
+ rename["Sleft"] = "ShiftLeft"
+ rename["Sright"] = "ShiftRight"
+ }
+
+ /^[^#]/ && $3 == "str" {
+ i++
+ }
+
+ $5 ~ /^KEY_/ {
+ name = toupper(substr($1, 5, 1)) substr($1, 6)
+ if (ignore[name] != "")
+ next
+ if (match(name, /^F([2-9][0-9]|1[3-9])/)) # Who has 64 function keys?!
+ next
+ if (rename[name] != "")
+ name = rename[name]
+ allkeys[name] = ""
+
+ # TODO: should print:
+ # var Keys = map[Key]string{
+ # F1: "\x1bOP",
+ # }
+ # printf "\t%s: \"%s\",\n", name, "TODO"
+ printf "\tcaps.TableStrs[%d]: %s,\n", i, name
+ }
+
+ END {
+ print "}\n"
+
+ print "// List of all key sequences we know about. This excludes most obscure ones not"
+ print "// present on modern devices."
+ print "const ("
+ print "// Special key used to signal errors."
+ print "UnknownSequence Key = iota + (1 << 32)\n"
+ for (k in allkeys) # TODO: weird order?
+ print k
+ print ")"
+
+ print "// Names of named key constants."
+ print "var keyNames = map[Key]string{"
+ for (k in allkeys)
+ printf "\t%s: `%s`,\n", k, k
+ print "}\n"
+ }
+ EOF
+ )"
+}
+
+main