| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279 |
- # -*- coding: utf-8 -*-
- # *****************************************************************************
- # Copyright (C) 2003-2006 Gary Bishop.
- # Copyright (C) 2006-2020 Michael Graz. <mgraz@plan10.com>
- # Copyright (C) 2006-2020 Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
- # Copyright (C) 2020 Bassem Girgis. <brgirgis@gmail.com>
- #
- # Distributed under the terms of the BSD License. The full license is in
- # the file COPYING, distributed as part of this software.
- # *****************************************************************************
- import os
- import pyreadline3.lineeditor.lineobj as lineobj
- from pyreadline3.logger import log
- from . import basemode
- class ViMode(basemode.BaseMode):
- mode = "vi"
- def __init__(self, rlobj):
- super().__init__(rlobj)
- self.__vi_insert_mode = None
- def __repr__(self):
- return "<ViMode>"
- def process_keyevent(self, keyinfo):
- def nop(e):
- pass
- keytuple = keyinfo.tuple()
- # Process exit keys. Only exit on empty line
- if keytuple in self.exit_dispatch:
- if lineobj.EndOfLine(self.l_buffer) == 0:
- raise EOFError
- dispatch_func = self.key_dispatch.get(keytuple, self.vi_key)
- log("readline from keyboard:%s->%s" % (keytuple, dispatch_func))
- r = None
- if dispatch_func:
- r = dispatch_func(keyinfo)
- self.l_buffer.push_undo()
- self.previous_func = dispatch_func
- if r:
- self._update_line()
- return True
- return False
- # Methods below here are bindable emacs functions
- def init_editing_mode(self, e): # (M-C-j)
- """Initialize vi editingmode"""
- self.show_all_if_ambiguous = "on"
- self.key_dispatch = {}
- self.__vi_insert_mode = None
- self._vi_command = None
- self._vi_command_edit = None
- self._vi_key_find_char = None
- self._vi_key_find_direction = True
- self._vi_yank_buffer = None
- self._vi_multiplier1 = ""
- self._vi_multiplier2 = ""
- self._vi_undo_stack = []
- self._vi_undo_cursor = -1
- self._vi_current = None
- self._vi_search_text = ""
- self._vi_search_position = 0
- self.vi_save_line()
- self.vi_set_insert_mode(True)
- # make ' ' to ~ self insert
- for c in range(ord(" "), 127):
- self._bind_key("%s" % chr(c), self.vi_key)
- self._bind_key("BackSpace", self.vi_backspace)
- self._bind_key("Escape", self.vi_escape)
- self._bind_key("Return", self.vi_accept_line)
- self._bind_key("Left", self.backward_char)
- self._bind_key("Right", self.forward_char)
- self._bind_key("Home", self.beginning_of_line)
- self._bind_key("End", self.end_of_line)
- self._bind_key("Delete", self.delete_char)
- self._bind_key("Control-d", self.vi_eof)
- self._bind_key("Control-z", self.vi_eof)
- self._bind_key("Control-r", self.vi_redo)
- self._bind_key("Up", self.vi_arrow_up)
- self._bind_key("Control-p", self.vi_up)
- self._bind_key("Down", self.vi_arrow_down)
- self._bind_key("Control-n", self.vi_down)
- self._bind_key("Tab", self.vi_complete)
- # self._bind_key('Control-e', self.emacs)
- def vi_key(self, e):
- if not self._vi_command:
- self._vi_command = ViCommand(self)
- elif self._vi_command.is_end:
- if self._vi_command.is_edit:
- self._vi_command_edit = self._vi_command
- self._vi_command = ViCommand(self)
- self._vi_command.add_char(e.char)
- def vi_error(self):
- self._bell()
- def vi_get_is_insert_mode(self):
- return self.__vi_insert_mode
- vi_is_insert_mode = property(vi_get_is_insert_mode)
- def vi_escape(self, e):
- if self.vi_is_insert_mode:
- if self._vi_command:
- self._vi_command.add_char(e.char)
- else:
- self._vi_command = ViCommand(self)
- self.vi_set_insert_mode(False)
- self.l_buffer.point = lineobj.PrevChar
- elif self._vi_command and self._vi_command.is_replace_one:
- self._vi_command.add_char(e.char)
- else:
- self.vi_error()
- def vi_backspace(self, e):
- if self._vi_command:
- self._vi_command.add_char(e.char)
- else:
- self._vi_do_backspace(self._vi_command)
- def _vi_do_backspace(self, vi_cmd):
- if self.vi_is_insert_mode or (self._vi_command and self._vi_command.is_search):
- if self.l_buffer.point > 0:
- self.l_buffer.point -= 1
- if self.l_buffer.overwrite:
- try:
- prev = self._vi_undo_stack[self._vi_undo_cursor][1][
- self.l_buffer.point
- ]
- self.l_buffer.line_buffer[self.l_buffer.point] = prev
- except IndexError:
- del self.l_buffer.line_buffer[self.l_buffer.point]
- else:
- self.vi_save_line()
- del self.l_buffer.line_buffer[self.l_buffer.point]
- def vi_accept_line(self, e):
- if self._vi_command and self._vi_command.is_search:
- self._vi_command.do_search()
- return False
- self._vi_command = None
- self.vi_set_insert_mode(True)
- self._vi_undo_stack = []
- self._vi_undo_cursor = -1
- self._vi_current = None
- if self.l_buffer.line_buffer:
- self.add_history(self.l_buffer.copy())
- return self.accept_line(e)
- def vi_eof(self, e):
- raise EOFError
- def vi_set_insert_mode(self, value):
- if self.__vi_insert_mode == value:
- return
- self.__vi_insert_mode = value
- if value:
- self.vi_save_line()
- self.cursor_size = 25
- else:
- self.cursor_size = 100
- def vi_undo_restart(self):
- tpl_undo = (
- self.l_buffer.point,
- self.l_buffer.line_buffer[:],
- )
- self._vi_undo_stack = [tpl_undo]
- self._vi_undo_cursor = 0
- def vi_save_line(self):
- if self._vi_undo_stack and self._vi_undo_cursor >= 0:
- del self._vi_undo_stack[self._vi_undo_cursor + 1 :]
- # tpl_undo = (self.l_buffer.point, self.l_buffer[:], )
- tpl_undo = (
- self.l_buffer.point,
- self.l_buffer.line_buffer[:],
- )
- if (
- not self._vi_undo_stack
- or self._vi_undo_stack[self._vi_undo_cursor][1] != tpl_undo[1]
- ):
- self._vi_undo_stack.append(tpl_undo)
- self._vi_undo_cursor += 1
- def vi_undo_prepare(self):
- if self._vi_undo_cursor == len(self._vi_undo_stack) - 1:
- self.vi_save_line()
- def vi_undo(self, do_pop=True):
- self.vi_undo_prepare()
- if not self._vi_undo_stack or self._vi_undo_cursor <= 0:
- self.vi_error()
- return
- self._vi_undo_cursor -= 1
- self.vi_undo_assign()
- def vi_undo_all(self):
- self.vi_undo_prepare()
- if self._vi_undo_cursor > 0:
- self._vi_undo_cursor = 0
- self.vi_undo_assign()
- else:
- self.vi_error()
- def vi_undo_assign(self):
- tpl_undo = self._vi_undo_stack[self._vi_undo_cursor]
- self.l_buffer.line_buffer = tpl_undo[1][:]
- self.l_buffer.point = tpl_undo[0]
- def vi_redo(self, e):
- if self._vi_undo_cursor >= len(self._vi_undo_stack) - 1:
- self.vi_error()
- return
- self._vi_undo_cursor += 1
- self.vi_undo_assign()
- def vi_search(self, rng):
- for i in rng:
- line_history = self._history.history[i]
- pos = line_history.get_line_text().find(self._vi_search_text)
- if pos >= 0:
- self._vi_search_position = i
- self._history.history_cursor = i
- self.l_buffer.line_buffer = list(line_history.line_buffer)
- self.l_buffer.point = pos
- self.vi_undo_restart()
- return True
- self._bell()
- return False
- def vi_search_first(self):
- text = "".join(self.l_buffer.line_buffer[1:])
- if text:
- self._vi_search_text = text
- self._vi_search_position = len(self._history.history) - 1
- elif self._vi_search_text:
- self._vi_search_position -= 1
- else:
- self.vi_error()
- self.vi_undo()
- return
- if not self.vi_search(list(range(self._vi_search_position, -1, -1))):
- # Here: search text not found
- self.vi_undo()
- def vi_search_again_backward(self):
- self.vi_search(list(range(self._vi_search_position - 1, -1, -1)))
- def vi_search_again_forward(self):
- self.vi_search(
- list(range(self._vi_search_position + 1, len(self._history.history)))
- )
- def vi_up(self, e):
- if self._history.history_cursor == len(self._history.history):
- self._vi_current = self.l_buffer.line_buffer[:]
- # self._history.previous_history (e)
- self._history.previous_history(self.l_buffer)
- if self.vi_is_insert_mode:
- self.end_of_line(e)
- else:
- self.beginning_of_line(e)
- self.vi_undo_restart()
- def vi_down(self, e):
- if self._history.history_cursor >= len(self._history.history):
- self.vi_error()
- return
- if self._history.history_cursor < len(self._history.history) - 1:
- # self._history.next_history (e)
- self._history.next_history(self.l_buffer)
- if self.vi_is_insert_mode:
- self.end_of_line(e)
- else:
- self.beginning_of_line(e)
- self.vi_undo_restart()
- elif self._vi_current is not None:
- self._history.history_cursor = len(self._history.history)
- self.l_buffer.line_buffer = self._vi_current
- self.end_of_line(e)
- if not self.vi_is_insert_mode and self.l_buffer.point > 0:
- self.l_buffer.point -= 1
- self._vi_current = None
- else:
- self.vi_error()
- return
- def vi_arrow_up(self, e):
- self.vi_set_insert_mode(True)
- self.vi_up(e)
- self.vi_save_line()
- def vi_arrow_down(self, e):
- self.vi_set_insert_mode(True)
- self.vi_down(e)
- self.vi_save_line()
- def vi_complete(self, e):
- text = self.l_buffer.get_line_text()
- if text and not text.isspace():
- return self.complete(e)
- else:
- return self.vi_key(e)
- # vi input states
- # sequence of possible states are in the order below
- _VI_BEGIN = "vi_begin"
- _VI_MULTI1 = "vi_multi1"
- _VI_ACTION = "vi_action"
- _VI_MULTI2 = "vi_multi2"
- _VI_MOTION = "vi_motion"
- _VI_MOTION_ARGUMENT = "vi_motion_argument"
- _VI_REPLACE_ONE = "vi_replace_one"
- _VI_TEXT = "vi_text"
- _VI_SEARCH = "vi_search"
- _VI_END = "vi_end"
- # vi helper class
- class ViCommand:
- def __init__(self, readline):
- self.readline = readline
- self.lst_char = []
- self.state = _VI_BEGIN
- self.action = self.movement
- self.motion = None
- self.motion_argument = None
- self.text = None
- self.pos_motion = None
- self.is_edit = False
- self.is_overwrite = False
- self.is_error = False
- self.is_star = False
- self.delete_left = 0
- self.delete_right = 0
- self.readline._vi_multiplier1 = ""
- self.readline._vi_multiplier2 = ""
- self.set_override_multiplier(0)
- self.skip_multipler = False
- self.tabstop = 4
- self.dct_fcn = {
- ord("$"): self.key_dollar,
- ord("^"): self.key_hat,
- ord(";"): self.key_semicolon,
- ord(","): self.key_comma,
- ord("%"): self.key_percent,
- ord("."): self.key_dot,
- ord("/"): self.key_slash,
- ord("*"): self.key_star,
- ord("|"): self.key_bar,
- ord("~"): self.key_tilde,
- 8: self.key_backspace,
- }
- def add_char(self, char):
- self.lst_char.append(char)
- if self.state == _VI_BEGIN and self.readline.vi_is_insert_mode:
- self.readline.vi_save_line()
- self.state = _VI_TEXT
- if self.state == _VI_SEARCH:
- if char == "\x08": # backspace
- self.key_backspace(char)
- else:
- self.set_text(char)
- return
- if self.state == _VI_TEXT:
- if char == "\x1b": # escape
- self.escape(char)
- elif char == "\x09": # tab
- ts = self.tabstop
- ws = " " * (ts - (self.readline.l_buffer.point % ts))
- self.set_text(ws)
- elif char == "\x08": # backspace
- self.key_backspace(char)
- else:
- self.set_text(char)
- return
- if self.state == _VI_MOTION_ARGUMENT:
- self.set_motion_argument(char)
- return
- if self.state == _VI_REPLACE_ONE:
- self.replace_one(char)
- return
- try:
- fcn_instance = self.dct_fcn[ord(char)]
- except BaseException:
- fcn_instance = getattr(self, "key_%s" % char, None)
- if fcn_instance:
- fcn_instance(char)
- return
- if char.isdigit():
- self.key_digit(char)
- return
- # Here: could not process key
- self.error()
- def set_text(self, text):
- if self.text is None:
- self.text = text
- else:
- self.text += text
- self.set_buffer(text)
- def set_buffer(self, text):
- for char in text:
- if not self.char_isprint(char):
- continue
- # self.readline.l_buffer.insert_text(char)
- # continue
- # #overwrite in l_buffer obj
- if self.is_overwrite:
- if self.readline.l_buffer.point < len(
- self.readline.l_buffer.line_buffer
- ):
- # self.readline.l_buffer[self.l_buffer.point]=char
- self.readline.l_buffer.line_buffer[self.readline.l_buffer.point] = (
- char
- )
- else:
- # self.readline.l_buffer.insert_text(char)
- self.readline.l_buffer.line_buffer.append(char)
- else:
- # self.readline.l_buffer.insert_text(char)
- self.readline.l_buffer.line_buffer.insert(
- self.readline.l_buffer.point, char
- )
- self.readline.l_buffer.point += 1
- def replace_one(self, char):
- if char == "\x1b": # escape
- self.end()
- return
- self.is_edit = True
- self.readline.vi_save_line()
- times = self.get_multiplier()
- cursor = self.readline.l_buffer.point
- self.readline.l_buffer.line_buffer[cursor : cursor + times] = char * times
- if times > 1:
- self.readline.l_buffer.point += times - 1
- self.end()
- def char_isprint(self, char):
- return ord(char) >= ord(" ") and ord(char) <= ord("~")
- def key_dollar(self, char):
- self.motion = self.motion_end_in_line
- self.delete_right = 1
- self.state = _VI_MOTION
- self.apply()
- def key_hat(self, char):
- self.motion = self.motion_beginning_of_line
- self.state = _VI_MOTION
- self.apply()
- def key_0(self, char):
- if self.state in [_VI_BEGIN, _VI_ACTION]:
- self.key_hat(char)
- else:
- self.key_digit(char)
- def key_digit(self, char):
- if self.state in [_VI_BEGIN, _VI_MULTI1]:
- self.readline._vi_multiplier1 += char
- self.readline._vi_multiplier2 = ""
- self.state = _VI_MULTI1
- elif self.state in [_VI_ACTION, _VI_MULTI2]:
- self.readline._vi_multiplier2 += char
- self.state = _VI_MULTI2
- def key_w(self, char):
- if self.action == self.change:
- self.key_e(char)
- return
- self.motion = self.motion_word_short
- self.state = _VI_MOTION
- self.apply()
- def key_W(self, char):
- if self.action == self.change:
- self.key_E(char)
- return
- self.motion = self.motion_word_long
- self.state = _VI_MOTION
- self.apply()
- def key_e(self, char):
- self.motion = self.motion_end_short
- self.state = _VI_MOTION
- self.delete_right = 1
- self.apply()
- def key_E(self, char):
- self.motion = self.motion_end_long
- self.state = _VI_MOTION
- self.delete_right = 1
- self.apply()
- def key_b(self, char):
- self.motion = self.motion_back_short
- self.state = _VI_MOTION
- self.apply()
- def key_B(self, char):
- self.motion = self.motion_back_long
- self.state = _VI_MOTION
- self.apply()
- def key_f(self, char):
- self.readline._vi_key_find_direction = True
- self.motion = self.motion_find_char_forward
- self.delete_right = 1
- self.state = _VI_MOTION_ARGUMENT
- def key_F(self, char):
- self.readline._vi_key_find_direction = False
- self.motion = self.motion_find_char_backward
- self.delete_left = 1
- self.state = _VI_MOTION_ARGUMENT
- def key_t(self, char):
- self.motion = self.motion_to_char_forward
- self.delete_right = 1
- self.state = _VI_MOTION_ARGUMENT
- def key_T(self, char):
- self.motion = self.motion_to_char_backward
- self.state = _VI_MOTION_ARGUMENT
- def key_j(self, char):
- self.readline.vi_down(ViEvent(char))
- self.state = _VI_END
- def key_k(self, char):
- self.readline.vi_up(ViEvent(char))
- self.state = _VI_END
- def key_semicolon(self, char):
- if self.readline._vi_key_find_char is None:
- self.error()
- return
- if self.readline._vi_key_find_direction:
- self.motion = self.motion_find_char_forward
- else:
- self.motion = self.motion_find_char_backward
- self.set_motion_argument(self.readline._vi_key_find_char)
- def key_comma(self, char):
- if self.readline._vi_key_find_char is None:
- self.error()
- return
- if self.readline._vi_key_find_direction:
- self.motion = self.motion_find_char_backward
- else:
- self.motion = self.motion_find_char_forward
- self.set_motion_argument(self.readline._vi_key_find_char)
- def key_percent(self, char):
- """find matching <([{}])>"""
- self.motion = self.motion_matching
- self.delete_right = 1
- self.state = _VI_MOTION
- self.apply()
- def key_dot(self, char):
- vi_cmd_edit = self.readline._vi_command_edit
- if not vi_cmd_edit:
- return
- if vi_cmd_edit.is_star:
- self.key_star(char)
- return
- if self.has_multiplier():
- count = self.get_multiplier()
- else:
- count = 0
- # Create the ViCommand object after getting multiplier from self
- # Side effect of the ViCommand creation is resetting of global
- # multipliers
- vi_cmd = ViCommand(self.readline)
- if count >= 1:
- vi_cmd.set_override_multiplier(count)
- vi_cmd_edit.set_override_multiplier(count)
- elif vi_cmd_edit.override_multiplier:
- vi_cmd.set_override_multiplier(vi_cmd_edit.override_multiplier)
- for char in vi_cmd_edit.lst_char:
- vi_cmd.add_char(char)
- if vi_cmd_edit.is_overwrite and self.readline.l_buffer.point > 0:
- self.readline.l_buffer.point -= 1
- self.readline.vi_set_insert_mode(False)
- self.end()
- def key_slash(self, char):
- self.readline.vi_save_line()
- self.readline.l_buffer.line_buffer = ["/"]
- self.readline.l_buffer.point = 1
- self.state = _VI_SEARCH
- def key_star(self, char):
- self.is_star = True
- self.is_edit = True
- self.readline.vi_save_line()
- completions = self.readline._get_completions()
- if completions:
- text = " ".join(completions) + " "
- self.readline.l_buffer.line_buffer[
- self.readline.begidx : self.readline.endidx + 1
- ] = list(text)
- prefix_len = self.readline.endidx - self.readline.begidx
- self.readline.l_buffer.point += len(text) - prefix_len
- self.readline.vi_set_insert_mode(True)
- else:
- self.error()
- self.state = _VI_TEXT
- def key_bar(self, char):
- self.motion = self.motion_column
- self.state = _VI_MOTION
- self.apply()
- def key_tilde(self, char):
- self.is_edit = True
- self.readline.vi_save_line()
- for i in range(self.get_multiplier()):
- try:
- c = self.readline.l_buffer.line_buffer[self.readline.l_buffer.point]
- if c.isupper():
- self.readline.l_buffer.line_buffer[self.readline.l_buffer.point] = (
- c.lower()
- )
- elif c.islower():
- self.readline.l_buffer.line_buffer[self.readline.l_buffer.point] = (
- c.upper()
- )
- self.readline.l_buffer.point += 1
- except IndexError:
- break
- self.end()
- def key_h(self, char):
- self.motion = self.motion_left
- self.state = _VI_MOTION
- self.apply()
- def key_backspace(self, char):
- if self.state in [_VI_TEXT, _VI_SEARCH]:
- if self.text and len(self.text):
- self.text = self.text[:-1]
- try:
- # Remove backspaces for potential dot command
- self.lst_char.pop()
- self.lst_char.pop()
- except IndexError:
- pass
- else:
- self.key_h(char)
- self.readline._vi_do_backspace(self)
- if self.state == _VI_SEARCH and not (self.readline.l_buffer.line_buffer):
- self.state = _VI_BEGIN
- def key_l(self, char):
- self.motion = self.motion_right
- self.state = _VI_MOTION
- self.apply()
- def key_i(self, char):
- self.is_edit = True
- self.state = _VI_TEXT
- self.readline.vi_set_insert_mode(True)
- def key_I(self, char):
- self.is_edit = True
- self.state = _VI_TEXT
- self.readline.vi_set_insert_mode(True)
- self.readline.l_buffer.point = 0
- def key_a(self, char):
- self.is_edit = True
- self.state = _VI_TEXT
- self.readline.vi_set_insert_mode(True)
- if len(self.readline.l_buffer.line_buffer):
- self.readline.l_buffer.point += 1
- def key_A(self, char):
- self.is_edit = True
- self.state = _VI_TEXT
- self.readline.vi_set_insert_mode(True)
- self.readline.l_buffer.point = len(self.readline.l_buffer.line_buffer)
- def key_d(self, char):
- self.is_edit = True
- self.state = _VI_ACTION
- self.action = self.delete
- def key_D(self, char):
- self.is_edit = True
- self.state = _VI_ACTION
- self.action = self.delete_end_of_line
- self.apply()
- def key_x(self, char):
- self.is_edit = True
- self.state = _VI_ACTION
- self.action = self.delete_char
- self.apply()
- def key_X(self, char):
- self.is_edit = True
- self.state = _VI_ACTION
- self.action = self.delete_prev_char
- self.apply()
- def key_s(self, char):
- self.is_edit = True
- i1 = self.readline.l_buffer.point
- i2 = self.readline.l_buffer.point + self.get_multiplier()
- self.skip_multipler = True
- self.readline.vi_set_insert_mode(True)
- del self.readline.l_buffer.line_buffer[i1:i2]
- self.state = _VI_TEXT
- def key_S(self, char):
- self.is_edit = True
- self.readline.vi_set_insert_mode(True)
- self.readline.l_buffer.line_buffer = []
- self.readline.l_buffer.point = 0
- self.state = _VI_TEXT
- def key_c(self, char):
- self.is_edit = True
- self.state = _VI_ACTION
- self.action = self.change
- def key_C(self, char):
- self.is_edit = True
- self.readline.vi_set_insert_mode(True)
- del self.readline.l_buffer.line_buffer[self.readline.l_buffer.point :]
- self.state = _VI_TEXT
- def key_r(self, char):
- self.state = _VI_REPLACE_ONE
- def key_R(self, char):
- self.is_edit = True
- self.is_overwrite = True
- self.readline.l_buffer.overwrite = True
- self.readline.vi_set_insert_mode(True)
- self.state = _VI_TEXT
- def key_y(self, char):
- self._state = _VI_ACTION
- self.action = self.yank
- def key_Y(self, char):
- self.readline._vi_yank_buffer = self.readline.l_buffer.get_line_text()
- self.end()
- def key_p(self, char):
- if not self.readline._vi_yank_buffer:
- return
- self.is_edit = True
- self.readline.vi_save_line()
- self.readline.l_buffer.point += 1
- self.readline.l_buffer.insert_text(
- self.readline._vi_yank_buffer * self.get_multiplier()
- )
- self.readline.l_buffer.point -= 1
- self.state = _VI_END
- def key_P(self, char):
- if not self.readline._vi_yank_buffer:
- return
- self.is_edit = True
- self.readline.vi_save_line()
- self.readline.l_buffer.insert_text(
- self.readline._vi_yank_buffer * self.get_multiplier()
- )
- self.readline.l_buffer.point -= 1
- self.state = _VI_END
- def key_u(self, char):
- self.readline.vi_undo()
- self.state = _VI_END
- def key_U(self, char):
- self.readline.vi_undo_all()
- self.state = _VI_END
- def key_v(self, char):
- editor = ViExternalEditor(self.readline.l_buffer.line_buffer)
- self.readline.l_buffer.line_buffer = list(editor.result)
- self.readline.l_buffer.point = 0
- self.is_edit = True
- self.state = _VI_END
- def error(self):
- self.readline._bell()
- self.is_error = True
- def state_is_end(self):
- return self.state == _VI_END
- is_end = property(state_is_end)
- def state_is_search(self):
- return self.state == _VI_SEARCH
- is_search = property(state_is_search)
- def state_is_replace_one(self):
- return self.state == _VI_REPLACE_ONE
- is_replace_one = property(state_is_replace_one)
- def do_search(self):
- self.readline.vi_search_first()
- self.state = _VI_END
- def key_n(self, char):
- self.readline.vi_search_again_backward()
- self.state = _VI_END
- def key_N(self, char):
- self.readline.vi_search_again_forward()
- self.state = _VI_END
- def motion_beginning_of_line(self, line, index=0, count=1, **kw):
- return 0
- def motion_end_in_line(self, line, index=0, count=1, **kw):
- return max(0, len(self.readline.l_buffer.line_buffer) - 1)
- def motion_word_short(self, line, index=0, count=1, **kw):
- return vi_pos_word_short(line, index, count)
- def motion_word_long(self, line, index=0, count=1, **kw):
- return vi_pos_word_long(line, index, count)
- def motion_end_short(self, line, index=0, count=1, **kw):
- return vi_pos_end_short(line, index, count)
- def motion_end_long(self, line, index=0, count=1, **kw):
- return vi_pos_end_long(line, index, count)
- def motion_back_short(self, line, index=0, count=1, **kw):
- return vi_pos_back_short(line, index, count)
- def motion_back_long(self, line, index=0, count=1, **kw):
- return vi_pos_back_long(line, index, count)
- def motion_find_char_forward(self, line, index=0, count=1, char=None):
- self.readline._vi_key_find_char = char
- return vi_pos_find_char_forward(line, char, index, count)
- def motion_find_char_backward(self, line, index=0, count=1, char=None):
- self.readline._vi_key_find_char = char
- return vi_pos_find_char_backward(line, char, index, count)
- def motion_to_char_forward(self, line, index=0, count=1, char=None):
- return vi_pos_to_char_forward(line, char, index, count)
- def motion_to_char_backward(self, line, index=0, count=1, char=None):
- return vi_pos_to_char_backward(line, char, index, count)
- def motion_left(self, line, index=0, count=1, char=None):
- return max(0, index - count)
- def motion_right(self, line, index=0, count=1, char=None):
- return min(len(line), index + count)
- def motion_matching(self, line, index=0, count=1, char=None):
- return vi_pos_matching(line, index)
- def motion_column(self, line, index=0, count=1, char=None):
- return max(0, count - 1)
- def has_multiplier(self):
- return (
- self.override_multiplier
- or self.readline._vi_multiplier1
- or self.readline._vi_multiplier2
- )
- def get_multiplier(self):
- if self.override_multiplier:
- return int(self.override_multiplier)
- if self.readline._vi_multiplier1 == "":
- m1 = 1
- else:
- m1 = int(self.readline._vi_multiplier1)
- if self.readline._vi_multiplier2 == "":
- m2 = 1
- else:
- m2 = int(self.readline._vi_multiplier2)
- return m1 * m2
- def set_override_multiplier(self, count):
- self.override_multiplier = count
- def apply(self):
- if self.motion:
- self.pos_motion = self.motion(
- self.readline.l_buffer.line_buffer,
- self.readline.l_buffer.point,
- self.get_multiplier(),
- char=self.motion_argument,
- )
- if self.pos_motion < 0:
- self.error()
- return
- self.action()
- if self.state != _VI_TEXT:
- self.end()
- def movement(self):
- if self.pos_motion <= len(self.readline.l_buffer.line_buffer):
- self.readline.l_buffer.point = self.pos_motion
- else:
- self.readline.l_buffer.point = len(self.readline.l_buffer.line_buffer) - 1
- def yank(self):
- if self.pos_motion > self.readline.l_buffer.point:
- s = self.readline.l_buffer.line_buffer[
- self.readline.l_buffer.point : self.pos_motion + self.delete_right
- ]
- else:
- index = max(0, self.pos_motion - self.delete_left)
- s = self.readline.l_buffer.line_buffer[
- index : self.readline.l_buffer.point + self.delete_right
- ]
- self.readline._vi_yank_buffer = s
- def delete(self):
- self.readline.vi_save_line()
- self.yank()
- # point=lineobj.Point(self.readline.l_buffer)
- # pm=self.pos_motion
- # del self.readline.l_buffer[point:pm]
- # return
- if self.pos_motion > self.readline.l_buffer.point:
- del self.readline.l_buffer.line_buffer[
- self.readline.l_buffer.point : self.pos_motion + self.delete_right
- ]
- if self.readline.l_buffer.point > len(self.readline.l_buffer.line_buffer):
- self.readline.l_buffer.point = len(self.readline.l_buffer.line_buffer)
- else:
- index = max(0, self.pos_motion - self.delete_left)
- del self.readline.l_buffer.line_buffer[
- index : self.readline.l_buffer.point + self.delete_right
- ]
- self.readline.l_buffer.point = index
- def delete_end_of_line(self):
- self.readline.vi_save_line()
- # del self.readline.l_buffer [self.readline.l_buffer.point : ]
- line_text = self.readline.l_buffer.get_line_text()
- line_text = line_text[: self.readline.l_buffer.point]
- self.readline.l_buffer.set_line(line_text)
- if self.readline.l_buffer.point > 0:
- self.readline.l_buffer.point -= 1
- def delete_char(self):
- # point=lineobj.Point(self.readline.l_buffer)
- # del self.readline.l_buffer[point:point+self.get_multiplier ()]
- # return
- self.pos_motion = self.readline.l_buffer.point + self.get_multiplier()
- self.delete()
- end = max(0, len(self.readline.l_buffer) - 1)
- if self.readline.l_buffer.point > end:
- self.readline.l_buffer.point = end
- def delete_prev_char(self):
- self.pos_motion = self.readline.l_buffer.point - self.get_multiplier()
- self.delete()
- def change(self):
- self.readline.vi_set_insert_mode(True)
- self.delete()
- self.skip_multipler = True
- self.state = _VI_TEXT
- def escape(self, char):
- if self.state == _VI_TEXT:
- if not self.skip_multipler:
- times = self.get_multiplier()
- if times > 1 and self.text:
- extra = self.text * (times - 1)
- self.set_buffer(extra)
- self.state = _VI_END
- def set_motion_argument(self, char):
- self.motion_argument = char
- self.apply()
- def end(self):
- self.state = _VI_END
- if self.readline.l_buffer.point >= len(self.readline.l_buffer.line_buffer):
- self.readline.l_buffer.point = max(
- 0, len(self.readline.l_buffer.line_buffer) - 1
- )
- class ViExternalEditor:
- def __init__(self, line):
- if isinstance(line, type([])):
- line = "".join(line)
- file_tmp = self.get_tempfile()
- fp_tmp = self.file_open(file_tmp, "w")
- fp_tmp.write(line)
- fp_tmp.close()
- self.run_editor(file_tmp)
- fp_tmp = self.file_open(file_tmp, "r")
- self.result = fp_tmp.read()
- fp_tmp.close()
- self.file_remove(file_tmp)
- def get_tempfile(self):
- import tempfile
- return tempfile.mktemp(prefix="readline-", suffix=".py")
- def file_open(self, filename, mode):
- return open(filename, mode)
- def file_remove(self, filename):
- os.remove(filename)
- def get_editor(self):
- try:
- return os.environ["EDITOR"]
- except KeyError:
- return "notepad" # ouch
- def run_editor(self, filename):
- cmd = "%s %s" % (
- self.get_editor(),
- filename,
- )
- self.run_command(cmd)
- def run_command(self, command):
- os.system(command)
- class ViEvent:
- def __init__(self, char):
- self.char = char
- # vi standalone functions
- def vi_is_word(char):
- log(
- "xx vi_is_word: type(%s), %s"
- % (
- type(char),
- char,
- )
- )
- return char.isalpha() or char.isdigit() or char == "_"
- def vi_is_space(char):
- return char.isspace()
- def vi_is_word_or_space(char):
- return vi_is_word(char) or vi_is_space(char)
- def vi_pos_word_short(line, index=0, count=1):
- try:
- for i in range(count):
- in_word = vi_is_word(line[index])
- if not in_word:
- while not vi_is_word(line[index]):
- index += 1
- else:
- while vi_is_word(line[index]):
- index += 1
- while vi_is_space(line[index]):
- index += 1
- return index
- except IndexError:
- return len(line)
- def vi_pos_word_long(line, index=0, count=1):
- try:
- for i in range(count):
- in_space = vi_is_space(line[index])
- if not in_space:
- while not vi_is_space(line[index]):
- index += 1
- while vi_is_space(line[index]):
- index += 1
- return index
- except IndexError:
- return len(line)
- def vi_pos_end_short(line, index=0, count=1):
- try:
- for i in range(count):
- index += 1
- while vi_is_space(line[index]):
- index += 1
- in_word = vi_is_word(line[index])
- if not in_word:
- while not vi_is_word_or_space(line[index]):
- index += 1
- else:
- while vi_is_word(line[index]):
- index += 1
- return index - 1
- except IndexError:
- return max(0, len(line) - 1)
- def vi_pos_end_long(line, index=0, count=1):
- try:
- for i in range(count):
- index += 1
- while vi_is_space(line[index]):
- index += 1
- while not vi_is_space(line[index]):
- index += 1
- return index - 1
- except IndexError:
- return max(0, len(line) - 1)
- class vi_list(list):
- """This is a list that cannot have a negative index"""
- def __getitem__(self, key):
- try:
- if int(key) < 0:
- raise IndexError
- except ValueError:
- pass
- return list.__getitem__(self, key)
- def vi_pos_back_short(line, index=0, count=1):
- line = vi_list(line)
- try:
- for i in range(count):
- index -= 1
- while vi_is_space(line[index]):
- index -= 1
- in_word = vi_is_word(line[index])
- if in_word:
- while vi_is_word(line[index]):
- index -= 1
- else:
- while not vi_is_word_or_space(line[index]):
- index -= 1
- return index + 1
- except IndexError:
- return 0
- def vi_pos_back_long(line, index=0, count=1):
- line = vi_list(line)
- try:
- for i in range(count):
- index -= 1
- while vi_is_space(line[index]):
- index -= 1
- while not vi_is_space(line[index]):
- index -= 1
- return index + 1
- except IndexError:
- return 0
- def vi_pos_find_char_forward(line, char, index=0, count=1):
- try:
- for i in range(count):
- index += 1
- while line[index] != char:
- index += 1
- return index
- except IndexError:
- return -1
- def vi_pos_find_char_backward(line, char, index=0, count=1):
- try:
- for i in range(count):
- index -= 1
- while True:
- if index < 0:
- return -1
- if line[index] == char:
- break
- index -= 1
- return index
- except IndexError:
- return -1
- def vi_pos_to_char_forward(line, char, index=0, count=1):
- index = vi_pos_find_char_forward(line, char, index, count)
- if index > 0:
- return index - 1
- return index
- def vi_pos_to_char_backward(line, char, index=0, count=1):
- index = vi_pos_find_char_backward(line, char, index, count)
- if index >= 0:
- return index + 1
- return index
- _vi_dct_matching = {
- "<": (">", +1),
- ">": ("<", -1),
- "(": (")", +1),
- ")": ("(", -1),
- "[": ("]", +1),
- "]": ("[", -1),
- "{": ("}", +1),
- "}": ("{", -1),
- }
- def vi_pos_matching(line, index=0):
- """find matching <([{}])>"""
- anchor = None
- target = None
- delta = 1
- count = 0
- try:
- while True:
- if anchor is None:
- # first find anchor
- try:
- target, delta = _vi_dct_matching[line[index]]
- anchor = line[index]
- count = 1
- except KeyError:
- index += 1
- continue
- else:
- # Here the anchor has been found
- # Need to get corresponding target
- if index < 0:
- return -1
- if line[index] == anchor:
- count += 1
- elif line[index] == target:
- count -= 1
- if count == 0:
- return index
- index += delta
- except IndexError:
- return -1
|