mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-09 05:35:19 +02:00
That is, eight bit control codes. When in S8C1T mode, kitty will send only eight bit control codes to the client.
458 lines
11 KiB
Python
458 lines
11 KiB
Python
#!/usr/bin/env python
|
|
# vim:fileencoding=utf-8
|
|
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
|
|
import re
|
|
from binascii import unhexlify, hexlify
|
|
|
|
|
|
def safe_print(*a, **k):
|
|
try:
|
|
print(*a, **k)
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
names = 'xterm-kitty', 'KovIdTTY'
|
|
|
|
termcap_aliases = {
|
|
'TN': 'name'
|
|
}
|
|
|
|
bool_capabilities = {
|
|
# auto_right_margin (terminal has automatic margins)
|
|
'am',
|
|
# can_change (terminal can redefine existing colors)
|
|
'ccc',
|
|
# has_meta key (i.e. sets the eight bit)
|
|
'km',
|
|
# prtr_silent (printer will not echo on screen)
|
|
'mc5i',
|
|
# move_insert_mode (safe to move while in insert mode)
|
|
'mir',
|
|
# move_standout_mode (safe to move while in standout mode)
|
|
'msgr',
|
|
# no_pad_char (pad character does not exist)
|
|
'npc',
|
|
# eat_newline_glitch (newline ignored after 80 columns)
|
|
'xenl',
|
|
# has extra status line (window title)
|
|
'hs',
|
|
|
|
# The following are entries from termite's terminfo that we dont need
|
|
# # background color erase
|
|
# 'bce',
|
|
}
|
|
|
|
termcap_aliases.update({
|
|
'am': 'am',
|
|
'cc': 'ccc',
|
|
'km': 'km',
|
|
'5i': 'mc5i',
|
|
'mi': 'mir',
|
|
'ms': 'msgr',
|
|
'NP': 'npc',
|
|
'xn': 'xenl',
|
|
'hs': 'hs',
|
|
})
|
|
|
|
numeric_capabilities = {
|
|
# maximum number of colors on screen
|
|
'colors': 256,
|
|
'cols': 80,
|
|
'lines': 24,
|
|
# tabs initially every # spaces
|
|
'it': 8,
|
|
# maximum number of color-pairs on the screen
|
|
'pairs': 32767,
|
|
}
|
|
|
|
termcap_aliases.update({
|
|
'Co': 'colors',
|
|
'pa': 'pairs',
|
|
'li': 'lines',
|
|
'co': 'cols',
|
|
'it': 'it',
|
|
})
|
|
|
|
string_capabilities = {
|
|
# graphics charset pairs
|
|
'acsc': r'++\,\,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~',
|
|
# The audible bell character
|
|
'bel': r'^G',
|
|
# Escape code for bold
|
|
'bold': r'\E[1m',
|
|
# Back tab
|
|
'cbt': r'\E[Z',
|
|
'kcbt': r'\E[Z',
|
|
# Make cursor invisible
|
|
'civis': r'\E[?25l',
|
|
# Clear screen
|
|
'clear': r'\E[H\E[2J',
|
|
# Make cursor appear normal
|
|
'cnorm': r'\E[?12l\E[?25h',
|
|
# Carriage return
|
|
'cr': r'^M', # CR (carriage return \r)
|
|
# Change scroll region
|
|
'csr': r'\E[%i%p1%d;%p2%dr',
|
|
# Move cursor to the left by the specified amount
|
|
'cub': r'\E[%p1%dD',
|
|
'cub1': r'^H', # BS (backspace)
|
|
# Move cursor down specified number of lines
|
|
'cud': r'\E[%p1%dB',
|
|
'cud1': r'^J', # LF (line-feed \n)
|
|
# Move cursor to the right by the specified amount
|
|
'cuf': r'\E[%p1%dC',
|
|
'cuf1': r'\E[C',
|
|
# Move cursor up specified number of lines
|
|
'cuu': r'\E[%p1%dA',
|
|
'cuu1': r'\E[A',
|
|
# Move cursor to specified location
|
|
'cup': r'\E[%i%p1%d;%p2%dH',
|
|
# Make cursor very visible
|
|
'cvvis': r'\E[?12;25h',
|
|
# Delete the specified number of characters
|
|
'dch': r'\E[%p1%dP',
|
|
'dch1': r'\E[P',
|
|
# Turn on half bright mode
|
|
'dim': r'\E[2m',
|
|
# Delete the specified number of lines
|
|
'dl': r'\E[%p1%dM',
|
|
'dl1': r'\E[M',
|
|
# Erase specified number of characters
|
|
'ech': r'\E[%p1%dX',
|
|
# Clear to end of screen
|
|
'ed': r'\E[J',
|
|
# Clear to end of line
|
|
'el': r'\E[K',
|
|
# Clear to start of line
|
|
'el1': r'\E[1K',
|
|
# visible bell
|
|
'flash': r'\E[?5h$<100/>\E[?5l',
|
|
# Home cursor
|
|
'home': r'\E[H',
|
|
# Move cursor to column
|
|
'hpa': r'\E[%i%p1%dG',
|
|
# Move to next tab
|
|
'ht': r'^I',
|
|
# Set tabstop at current position
|
|
'hts': r'\EH',
|
|
# Insert specified number of characters
|
|
'ich': r'\E[%p1%d@',
|
|
# Insert specified number of lines
|
|
'il': r'\E[%p1%dL',
|
|
'il1': r'\E[L',
|
|
# scroll up by specified amount
|
|
'ind': r'^J',
|
|
'indn': r'\E[%p1%dS',
|
|
# initialize color (set dynamic colors)
|
|
'initc': r'\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\',
|
|
# Set all colors to original values
|
|
'oc': r'\E]104\007',
|
|
# turn on blank mode (characters invisible)
|
|
# 'invis': r'\E[8m',
|
|
# Backspace
|
|
'kbs': r'\177',
|
|
# Left
|
|
'kcub1': r'\EOD',
|
|
# Down
|
|
'kcud1': r'\EOB',
|
|
# Right
|
|
'kcuf1': r'\EOC',
|
|
# Up
|
|
'kcuu1': r'\EOA',
|
|
# Function keys
|
|
'kf1': r'\EOP',
|
|
'kf2': r'\EOQ',
|
|
'kf3': r'\EOR',
|
|
'kf4': r'\EOS',
|
|
'kf5': r'\E[15~',
|
|
'kf6': r'\E[17~',
|
|
'kf7': r'\E[18~',
|
|
'kf8': r'\E[19~',
|
|
'kf9': r'\E[20~',
|
|
'kf10': r'\E[21~',
|
|
'kf11': r'\E[23~',
|
|
'kf12': r'\E[24~',
|
|
# Home
|
|
'khome': r'\EOH',
|
|
# End
|
|
'kend': r'\EOF',
|
|
# Insert character key
|
|
'kich1': r'\E[2~',
|
|
# Delete character key
|
|
'kdch1': r'\E[3~',
|
|
# Mouse event has occurred
|
|
'kmous': r'\E[M',
|
|
# Page down
|
|
'knp': r'\E[6~',
|
|
# Page up
|
|
'kpp': r'\E[5~',
|
|
# Scroll backwards (reverse index)
|
|
'kri': r'\E[1;2A',
|
|
# scroll forwards (index)
|
|
'kind': r'\E[1;2B',
|
|
# Restore cursor
|
|
'rc': r'\E8',
|
|
# Reverse video
|
|
'rev': r'\E[7m',
|
|
# Scroll backwards the specified number of lines (reverse index)
|
|
'ri': r'\EM',
|
|
'rin': r'\E[%p1%dT',
|
|
# Turn off automatic margins
|
|
'rmam': r'\E[?7l',
|
|
# Exit alternate screen
|
|
'rmcup': r'\E[?1049l',
|
|
# Exit insert mode
|
|
'rmir': r'\E[4l',
|
|
# Exit application keypad mode
|
|
'rmkx': r'\E[?1l',
|
|
# Exit standout mode
|
|
'rmso': r'\E[27m',
|
|
# Exit underline mode
|
|
'rmul': r'\E[24m',
|
|
# Reset string1
|
|
'rs1': r'\Ec',
|
|
# Save cursor
|
|
'sc': r'\E7',
|
|
# Set background color
|
|
'setab': r'\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m',
|
|
# Set foreground color
|
|
'setaf': r'\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m',
|
|
# Set attributes
|
|
'sgr': r'%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m',
|
|
# Clear all attributes
|
|
'sgr0': r'\E(B\E[m',
|
|
# Reset color pair to its original value
|
|
'op': r'\E[39;49m',
|
|
# Turn on automatic margins
|
|
'smam': r'\E[?7h',
|
|
# Start alternate screen
|
|
'smcup': r'\E[?1049h',
|
|
# Enster insert mode
|
|
'smir': r'\E[4h',
|
|
# Enter application keymap mode
|
|
'smkx': r'\E[?1h',
|
|
# Enter standout mode
|
|
'smso': r'\E[7m',
|
|
# Enter underline mode
|
|
'smul': r'\E[4m',
|
|
# Clear all tab stops
|
|
'tbc': r'\E[3g',
|
|
# To status line (used to set window titles)
|
|
'tsl': r'\E]2;',
|
|
# From status line (end window title string)
|
|
'fsl': r'^G',
|
|
# Disable status line (clear window title)
|
|
'dsl': r'\E]2;\007',
|
|
# Move to specified line
|
|
'vpa': r'\E[%i%p1%dd',
|
|
# Enter italics mode
|
|
'sitm': r'\E[3m',
|
|
# Leave italics mode
|
|
'ritm': r'\E[23m',
|
|
# Select alternate charset
|
|
'smacs': r'\E(0',
|
|
'rmacs': r'\E(B',
|
|
# Shifted keys
|
|
'kRIT': r'\E[1;2C',
|
|
'kLFT': r'\E[1;2D',
|
|
'kEND': r'\E[1;2F',
|
|
'kHOM': r'\E[1;2H',
|
|
# Special keys
|
|
'khlp': r'',
|
|
'kund': r'',
|
|
'ka1': r'',
|
|
'ka3': r'',
|
|
'kc1': r'',
|
|
'kc3': r'',
|
|
|
|
# The following are entries from termite's terminfo that we dont need
|
|
# # display status line
|
|
# 'dsl': r'\E]2;\007',
|
|
# # return from status line
|
|
# 'fsl': r'^G',
|
|
# # turn on blank mode, (characters invisible)
|
|
# 'invis': r'\E[8m',
|
|
# # init2 string
|
|
# 'is2': r'\E[!p\E[?3;4l\E[4l\E>',
|
|
# # Enter/send key
|
|
# 'kent': r'\EOM',
|
|
# # reset2
|
|
# 'rs2': r'\E[!p\E[?3;4l\E[4l\E>',
|
|
}
|
|
|
|
termcap_aliases.update({
|
|
'ac': 'acsc',
|
|
'bl': 'bel',
|
|
'md': 'bold',
|
|
'bt': 'cbt',
|
|
'kB': 'kcbt',
|
|
'cl': 'clear',
|
|
'vi': 'civis',
|
|
'vs': 'cvvis',
|
|
've': 'cnorm',
|
|
'cr': 'cr',
|
|
'cs': 'csr',
|
|
'LE': 'cub',
|
|
'le': 'cub1',
|
|
'DO': 'cud',
|
|
'do': 'cud1',
|
|
'UP': 'cuu',
|
|
'up': 'cuu1',
|
|
'nd': 'cuf1',
|
|
'RI': 'cuf',
|
|
'cm': 'cup',
|
|
'DC': 'dch',
|
|
'dc': 'dch1',
|
|
'mh': 'dim',
|
|
'DL': 'dl',
|
|
'dl': 'dl1',
|
|
'ec': 'ech',
|
|
'cd': 'ed',
|
|
'ce': 'el',
|
|
'cb': 'el1',
|
|
'vb': 'flash',
|
|
'ho': 'home',
|
|
'ch': 'hpa',
|
|
'ta': 'ht',
|
|
'st': 'hts',
|
|
'IC': 'ich',
|
|
'AL': 'il',
|
|
'al': 'il1',
|
|
'sf': 'ind',
|
|
'SF': 'indn',
|
|
'Ic': 'initc',
|
|
'oc': 'oc',
|
|
# 'mk': 'invis',
|
|
'kb': 'kbs',
|
|
'kl': 'kcub1',
|
|
'kd': 'kcud1',
|
|
'kr': 'kcuf1',
|
|
'ku': 'kcuu1',
|
|
'k1': 'kf1',
|
|
'k2': 'kf2',
|
|
'k3': 'kf3',
|
|
'k4': 'kf4',
|
|
'k5': 'kf5',
|
|
'k6': 'kf6',
|
|
'k7': 'kf7',
|
|
'k8': 'kf8',
|
|
'k9': 'kf9',
|
|
'k;': 'kf10',
|
|
'F1': 'kf11',
|
|
'F2': 'kf12',
|
|
'kh': 'khome',
|
|
'@7': 'kend',
|
|
'kI': 'kich1',
|
|
'kD': 'kdch1',
|
|
'Km': 'kmous',
|
|
'kN': 'knp',
|
|
'kP': 'kpp',
|
|
'kR': 'kri',
|
|
'kF': 'kind',
|
|
'rc': 'rc',
|
|
'mr': 'rev',
|
|
'sr': 'ri',
|
|
'SR': 'rin',
|
|
'RA': 'rmam',
|
|
'te': 'rmcup',
|
|
'ei': 'rmir',
|
|
'se': 'rmso',
|
|
'ue': 'rmul',
|
|
'r1': 'rs1',
|
|
'sc': 'sc',
|
|
'AB': 'setab',
|
|
'AF': 'setaf',
|
|
'sa': 'sgr',
|
|
'me': 'sgr0',
|
|
'op': 'op',
|
|
'SA': 'smam',
|
|
'ti': 'smcup',
|
|
'im': 'smir',
|
|
'so': 'smso',
|
|
'us': 'smul',
|
|
'ct': 'tbc',
|
|
'cv': 'vpa',
|
|
'ZH': 'sitm',
|
|
'ZR': 'ritm',
|
|
'as': 'smacs',
|
|
'ae': 'rmacs',
|
|
'ks': 'smkx',
|
|
'ke': 'rmkx',
|
|
'#2': 'kHOM',
|
|
'#4': 'kLFT',
|
|
'*7': 'kEND',
|
|
'%i': 'kRIT',
|
|
'%1': 'khlp',
|
|
'&8': 'kund',
|
|
'K1': 'ka1',
|
|
'K3': 'ka3',
|
|
'K4': 'kc1',
|
|
'K5': 'kc3',
|
|
'ts': 'tsl',
|
|
'fs': 'fsl',
|
|
'ds': 'dsl',
|
|
|
|
|
|
# 'ut': 'bce',
|
|
# 'ds': 'dsl',
|
|
# 'fs': 'fsl',
|
|
# 'mk': 'invis',
|
|
# 'is': 'is2',
|
|
# '@8': 'kent',
|
|
# 'r2': 'rs2',
|
|
})
|
|
|
|
queryable_capabilities = numeric_capabilities.copy()
|
|
queryable_capabilities.update(string_capabilities)
|
|
extra = (bool_capabilities | numeric_capabilities.keys() | string_capabilities.keys()) - set(termcap_aliases.values())
|
|
if extra:
|
|
raise Exception('Termcap aliases not complete, missing: {}'.format(extra))
|
|
del extra
|
|
|
|
|
|
def generate_terminfo():
|
|
ans = ['|'.join(names)]
|
|
ans.extend(sorted(bool_capabilities))
|
|
ans.extend('{}#{}'.format(k, numeric_capabilities[k]) for k in sorted(numeric_capabilities))
|
|
ans.extend('{}={}'.format(k, string_capabilities[k]) for k in sorted(string_capabilities))
|
|
return ',\n\t'.join(ans) + ',\n'
|
|
|
|
|
|
octal_escape = re.compile(r'\\([0-7]{3})')
|
|
escape_escape = re.compile(r'\\[eE]')
|
|
|
|
|
|
def key_as_bytes(name):
|
|
ans = string_capabilities[name]
|
|
ans = octal_escape.sub(lambda m: chr(int(m.group(1), 8)), ans)
|
|
ans = escape_escape.sub('\033', ans)
|
|
return ans.encode('ascii')
|
|
|
|
|
|
def get_capabilities(query_string):
|
|
from .fast_data_types import ERROR_PREFIX
|
|
ans = []
|
|
try:
|
|
for q in query_string.split(';'):
|
|
name = qname = unhexlify(q).decode('utf-8')
|
|
if name == 'TN':
|
|
val = names[0]
|
|
else:
|
|
try:
|
|
val = queryable_capabilities[name]
|
|
except KeyError:
|
|
try:
|
|
qname = termcap_aliases[name]
|
|
val = queryable_capabilities[qname]
|
|
except Exception as e:
|
|
safe_print(ERROR_PREFIX, 'Unknown terminfo property:', name)
|
|
raise
|
|
if qname in string_capabilities and '%' not in val:
|
|
val = key_as_bytes(qname).decode('ascii')
|
|
ans.append(q + '=' + hexlify(str(val).encode('utf-8')).decode('ascii'))
|
|
return '1+r' + ';'.join(ans)
|
|
except Exception:
|
|
return '0+r' + query_string
|