pmacs3/term.py

715 lines
21 KiB
Python

import os, re, string
from point import Point
# NOTE: i should write a python module to build a statemachine from a terminfo
# entry. otherwise this project is probably hopeless.
def show(c):
if c in string.ascii_letters + string.digits + string.punctuation + ' ':
return c
else:
return '\\%03o' % ord(c)
cbuffer_map = {
'black': 'B',
'blue': 'b',
'cyan': 'c',
'default': 'd',
'green': 'g',
'magenta': 'm',
'red': 'r',
'white': 'w',
'yellow': 'y',
}
def make_cbuf(fg, bg, xt):
if 'bold' in xt and fg == 'default': fg = 'cyan'
if 'italic' in xt and fg == 'default': fg = 'yellow'
if 'underline' in xt and fg == 'default': fg = 'green'
if 'inverse' in xt and fg == 'default': fg = 'magenta'
if 'strike' in xt and fg == 'default': fg = 'red'
if 'bold' in xt:
return '[%s:%s:*]' % (cbuffer_map[fg], cbuffer_map[bg])
else:
return '[%s:%s]' % (cbuffer_map[fg], cbuffer_map[bg])
class Dumb:
name = 'dumb'
cbuf = False
# style info
_fg = 'default'
_bg = 'default'
_xt = set()
def _term_insert(self, s):
assert self.i <= len(self.outc)
if self.i == len(self.outc):
self.outc.append(s)
else:
self.outc[self.i] = s
self.i += 1
def term_do_clear(self):
self.outs = ''
self.i = 0
self.outc = []
if self.cbuf:
self._term_insert(make_cbuf(self._fg, self._bg, self._xt))
def term_do_clear_bol(self):
pass
def term_do_clear_eol(self):
del self.outc[self.i:]
if self.cbuf:
self._term_insert(make_cbuf(self._fg, self._bg, self._xt))
def term_do_clear_eos(self):
pass
def term_do_home(self):
self.outs = ''
self.i = 0
self.outc = []
if self.cbuf: self._term_insert(make_cbuf(self._fg, self._bg, self._xt))
def term_do_backspace(self):
self.i = max(0, self.i - 1)
def term_do_tab(self):
self._term_insert(' ')
def term_do_newline(self):
self.outs += ''.join(self.outc) + '\n'
self.i = 0
self.outc = []
if self.cbuf: self._term_insert(make_cbuf(self._fg, self._bg, self._xt))
def term_do_creturn(self):
self.i = 0
def term_do_esc(self, c):
pass
def term_do_delete(self):
if self.i < len(self.outc):
del self.outc[self.i]
def term_handle_ctl(self, c):
n = ord(c)
if n == 8:
self.term_do_backspace()
elif n == 9:
self.term_do_tab()
elif n == 10:
self.term_do_newline()
elif n == 12:
self.term_do_clear()
elif n == 13:
self.term_do_creturn()
elif n == 27:
self.term_do_esc(c)
elif n == 127:
self.term_do_delete()
def term_handle_print(self, c):
if self.cbuf:
if c in ('\\', '[', ']'):
self._term_insert('\\')
self._term_insert(c)
def term_handle_8bit(self, c):
pass
def term_handle(self, c):
n = ord(c)
assert n >= 0 and n < 256
if n <= 27 or n == 127:
self.term_handle_ctl(c)
elif n < 127:
self.term_handle_print(c)
else:
self.term_handle_8bit(c)
def term_receive(self, s):
for c in s:
self.term_handle(c)
def term_filter(self, s):
self.i = 0
self.outc = []
self.outs = ""
self.term_receive(s)
return self.outs + ''.join(self.outc)
class XTerm(Dumb):
name = 'xterm'
termtype = 'xterm'
comment_re = re.compile('^ *#')
header_re = re.compile('^[a-zA-Z0-9]+\|')
bool_re = re.compile('^([a-zA-Z0-9]+)$')
num_re = re.compile('^([a-zA-Z0-9]+)#(.+)$')
str_re = re.compile('^([a-zA-Z0-9]+)=(.+)$')
style_re = re.compile(r'^\033\[[0-9;]*m')
text_signal_re = re.compile(r'^\033\][0-9]+;.+\007')
cup_re = re.compile(r'^\033\[[0-9]+;[0-9]+H')
callbacks = {
'clear': 'term_do_clear',
'home': 'term_do_home',
'rmm': 'term_nop',
'smm': 'term_nop',
'bold': 'term_nop',
'op': 'term_nop', #original color-pair
'cup': 'term_nop', #hmmm?
'cnorm': 'term_nop', #make cursor normal
'civis': 'term_nop', #make cursor inviz
'cvvis': 'term_nop', #make cursor bold
'smcup': 'term_nop', #enter cup mode
'rmcup': 'term_nop', #leave cup mode
'smacs': 'term_nop', #orig charset
'rmacs': 'term_nop', #
'smso': 'term_nop', #enter standout
'rmso': 'term_nop', #leave standout
'smul': 'term_nop', #enter underline
'rmul': 'term_nop', #leave underline
'smkx': 'term_nop', #enter keypad junk
'rmkx': 'term_nop', #leave keypad junk
'ed': 'term_do_clear_eos',
'el': 'term_do_clear_eol',
#'el1': 'term_nop',
}
def __init__(self, cbuf=False):
self.debug = False
self.cbuf = cbuf
# style info
self._fg = 'default'
self._bg = 'default'
self._xt = set()
self._meta = []
f = os.popen('infocmp %s' % self.termtype, 'r')
self.sequences = {}
for line in f:
if self.comment_re.match(line) or self.header_re.match(line):
continue
for field in [x.strip() for x in line.split(',')]:
if not field:
continue
elif self.bool_re.match(field) or self.num_re.match(field):
continue
m = self.str_re.match(field)
assert m, "huh?? %r" % field
name, val = m.groups()
if len(val) > 3 and val[:3] == '\\E[' and val[3] in '0123456789':
continue
elif val.startswith('\\E'):
#if val == '\\E[1m':
# raise Exception("NONONONO")
self.sequences[val.replace('\\E', '\033')] = name
f.close()
def parse_style(self, s):
# starts with '\033[' and ends with 'm'
s2 = s[2:-1]
#if s not in ('\x1b[0m', '\x1b[22m'):
# raise Exception('argh: %r' % s)
if s2 == '':
l = ['0']
else:
l = s2.split(';')
for n in l:
if n == '0':
self._fg = 'default'
self._bg = 'default'
self._xt = set()
# xtra attributes
elif n == '1': self._xt.add('bold')
elif n == '3': self._xt.add('italic')
elif n == '4': self._xt.add('underline')
elif n == '7': self._xt.add('inverse')
elif n == '9': self._xt.add('strike')
elif n == '22': self._xt.discard('bold')
elif n == '23': self._xt.discard('italic')
elif n == '24': self._xt.discard('underline')
elif n == '27': self._xt.discard('inverse')
elif n == '29': self._xt.discard('strike')
# foreground
elif n == '30': self._fg = 'black'
elif n == '31': self._fg = 'red'
elif n == '32': self._fg = 'green'
elif n == '33': self._fg = 'yellow'
elif n == '34': self._fg = 'blue'
elif n == '35': self._fg = 'magenta'
elif n == '36': self._fg = 'cyan'
elif n == '37': self._fg = 'white'
elif n == '39': self._fg = 'default'
# background
elif n == '40': self._bg = 'black'
elif n == '41': self._bg = 'red'
elif n == '42': self._bg = 'green'
elif n == '43': self._bg = 'yellow'
elif n == '44': self._bg = 'blue'
elif n == '45': self._bg = 'magenta'
elif n == '46': self._bg = 'cyan'
elif n == '47': self._bg = 'white'
elif n == '49': self._bg = 'default'
def term_do_style(self):
if self.cbuf: self._term_insert(make_cbuf(self._fg, self._bg, self._xt))
def term_nop(self, *args):
pass
def term_filter(self, s):
self._meta = []
return Dumb.term_filter(self, s)
def term_do_esc(self, c):
self._meta.append(c)
def term_handle(self, c):
#UGHGHGHGH
if self._meta:
self._meta.append(c)
s = ''.join(self._meta)
if s.startswith('\x1b[H') and not '\x1b[H\x1b[2J'.startswith(s):
self._meta = self._meta[3:]
if self._meta[0] != '\x1b':
for c2 in self._meta[:-1]:
Dumb.term_handle(self, c2)
self._meta = []
if self._meta:
s = ''.join(self._meta)
if s in self.sequences:
name = self.sequences[s]
if self.debug:
self._term_insert('<%s>' % name)
elif name in self.callbacks:
f = getattr(self, self.callbacks[name])
f()
else:
self._term_insert('<%s>' % name)
# certain sequences shouldn't get removed immediately; ugh
if name not in ['home']:
self._meta = []
elif self.style_re.match(s):
self.parse_style(s)
self.term_do_style()
self._meta = []
elif self.text_signal_re.match(s):
self._meta = []
elif self.cup_re.match(s):
self._meta = []
elif s.endswith('\n'):
self._term_insert(''.join([show(c) for c in self._meta]))
self._meta = []
else:
Dumb.term_handle(self, c)
# terminfo junk
boolean_settings = [
['cpi_changes_res', 'cpix'],
['cr_cancels_micro_mode', 'crxm'],
['dest_tabs_magic_smso', 'xt'],
['eat_newline_glitch', 'xenl'],
['erase_overstrike', 'eo'],
['generic_type', 'gn'],
['hard_copy', 'hc'],
['hard_cursor', 'chts'],
['has_meta_key', 'km'],
['has_print_wheel', 'daisy'],
['has_status_line', 'hs'],
['hue_lightness_saturation', 'hls'],
['insert_null_glitch', 'in'],
['lpi_changes_res', 'lpix'],
['memory_above', 'da'],
['memory_below', 'db'],
['move_insert_mode', 'mir'],
['move_standout_mode', 'msgr'],
['needs_xon_xoff', 'nxon'],
['no_esc_ctlc', 'xsb'],
['no_pad_char', 'npc'],
['non_dest_scroll_region', 'ndscr'],
['non_rev_rmcup', 'nrrmc'],
['over_strike', 'os'],
['prtr_silent', 'mc5i'],
['row_addr_glitch', 'xvpa'],
['semi_auto_right_margin', 'sam'],
['status_line_esc_ok', 'eslok'],
['tilde_glitch', 'hz'],
['transparent_underline', 'ul'],
['xon_xoff', 'xon'],
]
number_settings = [
['columns', 'cols'],
['init_tabs', 'it'],
['label_height', 'lh'],
['label_width', 'lw'],
['lines', 'lines'],
['lines_of_memory', 'lm'],
['magic_cookie_glitch', 'xmc'],
['max_attributes', 'ma'],
['max_colors', 'colors'],
['max_pairs', 'pairs'],
['maximum_windows', 'wnum'],
['no_color_video', 'ncv'],
['num_labels', 'nlab'],
['padding_baud_rate', 'pb'],
['virtual_terminal', 'vt'],
['width_status_line', 'wsl'],
]
string_settings = [
['acs_chars', 'acsc'],
['back_tab', 'cbt'],
['bell', 'bel'],
['carriage_return', 'cr'],
['change_char_pitch', 'cpi'],
['change_line_pitch', 'lpi'],
['change_res_horz', 'chr'],
['change_res_vert', 'cvr'],
['change_scroll_region', 'csr'],
['char_padding', 'rmp'],
['clear_all_tabs', 'tbc'],
['clear_margins', 'mgc'],
['clear_screen', 'clear'],
['clr_bol', 'el1'],
['clr_eol', 'el'],
['clr_eos', 'ed'],
['column_address', 'hpa'],
['command_character', 'cmdch'],
['create_window', 'cwin'],
['cursor_address', 'cup'],
['cursor_down', 'cud1'],
['cursor_home', 'home'],
['cursor_invisible', 'civis'],
['cursor_left', 'cub1'],
['cursor_mem_address', 'mrcup'],
['cursor_normal', 'cnorm'],
['cursor_right', 'cuf1'],
['cursor_to_ll', 'll'],
['cursor_up', 'cuu1'],
['cursor_visible', 'cvvis'],
['define_char', 'defc'],
['delete_character', 'dch1'],
['delete_line', 'dl1'],
['dial_phone', 'dial'],
['dis_status_line', 'dsl'],
['display_clock', 'dclk'],
['down_half_line', 'hd'],
['ena_acs', 'enacs'],
['enter_alt_charset_mode', 'smacs'],
['enter_am_mode', 'smam'],
['enter_blink_mode', 'blink'],
['enter_bold_mode', 'bold'],
['enter_ca_mode', 'smcup'],
['enter_delete_mode', 'smdc'],
['enter_dim_mode', 'dim'],
['enter_doublewide_mode', 'swidm'],
['enter_draft_quality', 'sdrfq'],
['enter_insert_mode', 'smir'],
['enter_italics_mode', 'sitm'],
['enter_leftward_mode', 'slm'],
['enter_micro_mode', 'smicm'],
['enter_near_letter_quality', 'snlq'],
['enter_normal_quality', 'snrmq'],
['enter_protected_mode', 'prot'],
['enter_reverse_mode', 'rev'],
['enter_secure_mode', 'invis'],
['enter_shadow_mode', 'sshm'],
['enter_standout_mode', 'smso'],
['enter_subscript_mode', 'ssubm'],
['enter_superscript_mode', 'ssupm'],
['enter_underline_mode', 'smul'],
['enter_upward_mode', 'sum'],
['enter_xon_mode', 'smxon'],
['erase_chars', 'ech'],
['exit_alt_charset_mode', 'rmacs'],
['exit_am_mode', 'rmam'],
['exit_attribute_mode', 'sgr0'],
['exit_ca_mode', 'rmcup'],
['exit_delete_mode', 'rmdc'],
['exit_doublewide_mode', 'rwidm'],
['exit_insert_mode', 'rmir'],
['exit_italics_mode', 'ritm'],
['exit_leftward_mode', 'rlm'],
['exit_micro_mode', 'rmicm'],
['exit_shadow_mode', 'rshm'],
['exit_standout_mode', 'rmso'],
['exit_subscript_mode', 'rsubm'],
['exit_superscript_mode', 'rsupm'],
['exit_underline_mode', 'rmul'],
['exit_upward_mode', 'rum'],
['exit_xon_mode', 'rmxon'],
['fixed_pause', 'pause'],
['flash_hook', 'hook'],
['flash_screen', 'flash'],
['form_feed', 'ff'],
['from_status_line', 'fsl'],
['goto_window', 'wingo'],
['hangup', 'hup'],
['init_1string', 'is1'],
['init_2string', 'is2'],
['init_3string', 'is3'],
['init_file', 'if'],
['init_prog', 'iprog'],
['initialize_color', 'initc'],
['initialize_pair', 'initp'],
['insert_character', 'ich1'],
['insert_line', 'il1'],
['insert_padding', 'ip'],
['key_a1', 'ka1'],
['key_a3', 'ka3'],
['key_b2', 'kb2'],
['key_backspace', 'kbs'],
['key_beg', 'kbeg'],
['key_btab', 'kcbt'],
['key_c1', 'kc1'],
['key_c3', 'kc3'],
['key_cancel', 'kcan'],
['key_catab', 'ktbc'],
['key_clear', 'kclr'],
['key_close', 'kclo'],
['key_command', 'kcmd'],
['key_copy', 'kcpy'],
['key_create', 'kcrt'],
['key_ctab', 'kctab'],
['key_dc', 'kdch1'],
['key_dl', 'kdl1'],
['key_down', 'kcud1'],
['key_eic', 'krmir'],
['key_end', 'kend'],
['key_enter', 'kent'],
['key_eol', 'kel'],
['key_eos', 'ked'],
['key_exit', 'kext'],
['key_f0', 'kf0'],
['key_f1', 'kf1'],
['key_f10', 'kf10'],
['key_f11', 'kf11'],
['key_f12', 'kf12'],
['key_f13', 'kf13'],
['key_f14', 'kf14'],
['key_f15', 'kf15'],
['key_f16', 'kf16'],
['key_f17', 'kf17'],
['key_f18', 'kf18'],
['key_f19', 'kf19'],
['key_f2', 'kf2'],
['key_f20', 'kf20'],
['key_f21', 'kf21'],
['key_f22', 'kf22'],
['key_f23', 'kf23'],
['key_f24', 'kf24'],
['key_f25', 'kf25'],
['key_f26', 'kf26'],
['key_f27', 'kf27'],
['key_f28', 'kf28'],
['key_f29', 'kf29'],
['key_f3', 'kf3'],
['key_f30', 'kf30'],
['key_f31', 'kf31'],
['key_f32', 'kf32'],
['key_f33', 'kf33'],
['key_f34', 'kf34'],
['key_f35', 'kf35'],
['key_f36', 'kf36'],
['key_f37', 'kf37'],
['key_f38', 'kf38'],
['key_f39', 'kf39'],
['key_f4', 'kf4'],
['key_f40', 'kf40'],
['key_f41', 'kf41'],
['key_f42', 'kf42'],
['key_f43', 'kf43'],
['key_f44', 'kf44'],
['key_f45', 'kf45'],
['key_f46', 'kf46'],
['key_f47', 'kf47'],
['key_f48', 'kf48'],
['key_f49', 'kf49'],
['key_f5', 'kf5'],
['key_f50', 'kf50'],
['key_f51', 'kf51'],
['key_f52', 'kf52'],
['key_f53', 'kf53'],
['key_f54', 'kf54'],
['key_f55', 'kf55'],
['key_f56', 'kf56'],
['key_f57', 'kf57'],
['key_f58', 'kf58'],
['key_f59', 'kf59'],
['key_f6', 'kf6'],
['key_f60', 'kf60'],
['key_f61', 'kf61'],
['key_f62', 'kf62'],
['key_f63', 'kf63'],
['key_f7', 'kf7'],
['key_f8', 'kf8'],
['key_f9', 'kf9'],
['key_find', 'kfnd'],
['key_help', 'khlp'],
['key_home', 'khome'],
['key_ic', 'kich1'],
['key_il', 'kil1'],
['key_left', 'kcub1'],
['key_ll', 'kll'],
['key_mark', 'kmrk'],
['key_message', 'kmsg'],
['key_move', 'kmov'],
['key_next', 'knxt'],
['key_npage', 'knp'],
['key_open', 'kopn'],
['key_options', 'kopt'],
['key_ppage', 'kpp'],
['key_previous', 'kprv'],
['key_print', 'kprt'],
['key_redo', 'krdo'],
['key_reference', 'kref'],
['key_refresh', 'krfr'],
['key_replace', 'krpl'],
['key_restart', 'krst'],
['key_resume', 'kres'],
['key_right', 'kcuf1'],
['key_save', 'ksav'],
['key_sbeg', 'kBEG'],
['key_scancel', 'kCAN'],
['key_scommand', 'kCMD'],
['key_scopy', 'kCPY'],
['key_screate', 'kCRT'],
['key_sdc', 'kDC'],
['key_sdl', 'kDL'],
['key_select', 'kslt'],
['key_send', 'kEND'],
['key_seol', 'kEOL'],
['key_sexit', 'kEXT'],
['key_sf', 'kind'],
['key_sfind', 'kFND'],
['key_shelp', 'kHLP'],
['key_shome', 'kHOM'],
['key_sic', 'kIC'],
['key_sleft', 'kLFT'],
['key_smessage', 'kMSG'],
['key_smove', 'kMOV'],
['key_snext', 'kNXT'],
['key_soptions', 'kOPT'],
['key_sprevious', 'kPRV'],
['key_sprint', 'kPRT'],
['key_sr', 'kri'],
['key_sredo', 'kRDO'],
['key_sreplace', 'kRPL'],
['key_sright', 'kRIT'],
['key_srsume', 'kRES'],
['key_ssave', 'kSAV'],
['key_ssuspend', 'kSPD'],
['key_stab', 'khts'],
['key_sundo', 'kUND'],
['key_suspend', 'kspd'],
['key_undo', 'kund'],
['key_up', 'kcuu1'],
['keypad_local', 'rmkx'],
['keypad_xmit', 'smkx'],
['lab_f0', 'lf0'],
['lab_f1', 'lf1'],
['lab_f10', 'lf10'],
['lab_f2', 'lf2'],
['lab_f3', 'lf3'],
['lab_f4', 'lf4'],
['lab_f5', 'lf5'],
['lab_f6', 'lf6'],
['lab_f7', 'lf7'],
['lab_f8', 'lf8'],
['lab_f9', 'lf9'],
['label_format', 'fln'],
['label_off', 'rmln'],
['label_on', 'smln'],
['meta_off', 'rmm'],
['meta_on', 'smm'],
['micro_column_address', 'mhpa'],
['micro_down', 'mcud1'],
['micro_left', 'mcub1'],
['micro_right', 'mcuf1'],
['micro_row_address', 'mvpa'],
['micro_up', 'mcuu1'],
['newline', 'nel'],
['order_of_pins', 'porder'],
['orig_colors', 'oc'],
['orig_pair', 'op'],
['pad_char', 'pad'],
['parm_dch', 'dch'],
['parm_delete_line', 'dl'],
['parm_down_cursor', 'cud'],
['parm_down_micro', 'mcud'],
['parm_ich', 'ich'],
['parm_index', 'indn'],
['parm_insert_line', 'il'],
['parm_left_cursor', 'cub'],
['parm_left_micro', 'mcub'],
['parm_right_cursor', 'cuf'],
['parm_right_micro', 'mcuf'],
['parm_rindex', 'rin'],
['parm_up_cursor', 'cuu'],
['parm_up_micro', 'mcuu'],
['pkey_key', 'pfkey'],
['pkey_local', 'pfloc'],
['pkey_xmit', 'pfx'],
['plab_norm', 'pln'],
['print_screen', 'mc0'],
['prtr_non', 'mc5p'],
['prtr_off', 'mc4'],
['prtr_on', 'mc5'],
['pulse', 'pulse'],
['quick_dial', 'qdial'],
['remove_clock', 'rmclk'],
['repeat_char', 'rep'],
['req_for_input', 'rfi'],
['reset_1string', 'rs1'],
['reset_2string', 'rs2'],
['reset_3string', 'rs3'],
['reset_file', 'rf'],
['restore_cursor', 'rc'],
['row_address', 'vpa'],
['save_cursor', 'sc'],
['scroll_forward', 'ind'],
['scroll_reverse', 'ri'],
['select_char_set', 'scs'],
['set_attributes', 'sgr'],
['set_background', 'setb'],
['set_bottom_margin', 'smgb'],
['set_bottom_margin_parm', 'smgbp'],
['set_clock', 'sclk'],
['set_color_pair', 'scp'],
['set_foreground', 'setf'],
['set_left_margin', 'smgl'],
['set_left_margin_parm', 'smglp'],
['set_right_margin', 'smgr'],
['set_right_margin_parm', 'smgrp'],
['set_tab', 'hts'],
['set_top_margin', 'smgt'],
['set_top_margin_parm', 'smgtp'],
['set_window', 'wind'],
['start_bit_image', 'sbim'],
['start_char_set_def', 'scsd'],
['stop_bit_image', 'rbim'],
['stop_char_set_def', 'rcsd'],
['subscript_characters', 'subcs'],
['superscript_characters', 'supcs'],
['tab', 'ht'],
['these_cause_cr', 'docr'],
['to_status_line', 'tsl'],
['tone', 'tone'],
['underline_char', 'uc'],
['up_half_line', 'hu'],
['user0', 'u0'],
['user1', 'u1'],
['user2', 'u2'],
['user3', 'u3'],
['user4', 'u4'],
['user5', 'u5'],
['user6', 'u6'],
['user7', 'u7'],
['user8', 'u8'],
['user9', 'u9'],
['wait_tone', 'wait'],
['xoff_character', 'xoffc'],
['xon_character', 'xonc'],
['zero_motion', 'zerom'],
]