1# Copyright (c) 2011, Tomohiro Kusumi
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are met:
6#
7# 1. Redistributions of source code must retain the above copyright notice, this
8#    list of conditions and the following disclaimer.
9# 2. Redistributions in binary form must reproduce the above copyright notice,
10#    this list of conditions and the following disclaimer in the documentation
11#    and/or other materials provided with the distribution.
12#
13# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24import sys
25
26from . import console
27from . import edit
28from . import extension
29from . import kbd
30from . import literal
31from . import methods
32from . import panel
33from . import screen
34from . import setting
35from . import util
36
37VISUAL = "VISUAL"
38VISUAL_LINE = "VISUAL LINE"
39VISUAL_BLOCK = "VISUAL BLOCK"
40
41class _visual_methods (object):
42    def init(self):
43        if setting.color_visual is None:
44            if screen.use_alt_chgat():
45                self.__chgat_head = self.__alt_chgat_head
46                self.__chgat_tail = self.__alt_chgat_tail
47                self.__chgat_single = self.__alt_chgat_single
48                self.__chgat_inside = self.__alt_chgat_inside
49                self.__chgat_outside = self.__alt_chgat_outside
50        else:
51            if screen.use_alt_chgat():
52                self.__chgat_head = self.__alt_chgat_head_attr
53                self.__chgat_tail = self.__alt_chgat_tail_attr
54                self.__chgat_single = self.__alt_chgat_single_attr
55                self.__chgat_outside = self.__alt_chgat_outside_attr
56            else: # default
57                self.__chgat_head = self.__chgat_head_attr
58                self.__chgat_tail = self.__chgat_tail_attr
59                self.__chgat_single = self.__chgat_single_attr
60                self.__chgat_outside = self.__chgat_outside_attr
61
62    def update_visual(self, full):
63        if not self.fileops.has_region():
64            return # last repaint before exit
65        t = self.fileops.get_region_type()
66        if t == VISUAL_BLOCK:
67            self.__update_block_visual(full)
68        else:
69            self.__update_visual(t, full)
70        pos = self.fileops.get_pos()
71        self.page_update_search(pos)
72        self.chgat_cursor(pos, screen.A_COLOR_CURRENT, screen.A_COLOR_CURRENT,
73            False)
74
75    def __update_visual(self, t, full):
76        pos = self.fileops.get_pos()
77        ppos = self.fileops.get_prev_pos()
78        if self.in_same_page(pos, ppos):
79            self.chgat_posstr(ppos, screen.A_NONE)
80        else:
81            full = True
82        self.chgat_posstr(pos, self.attr_posstr)
83
84        beg = self.fileops.get_region_origin()
85        end = pos
86        if beg > end:
87            beg, end = end, beg
88        mapx = self.bufmap.x
89        if t == VISUAL_LINE:
90            beg -= beg % mapx
91            end += (mapx - 1 - end % mapx)
92        if setting.use_unit_based and (end % setting.bytes_per_unit == 0):
93            end += (setting.bytes_per_unit - 1) # round up before set region
94        self.fileops.set_region_range(beg, end, self.bufmap)
95
96        pgo = self.get_page_offset()
97        npgo = self.get_next_page_offset()
98        if beg < pgo:
99            beg = pgo
100        if end > npgo - 1:
101            end = npgo - 1
102        lcur = pgo
103
104        l = []
105        if not full:
106            a = self.get_line_offset(pos)
107            b = self.get_line_offset(ppos)
108            if a == b:
109                l = [a]
110            else:
111                if a < b:
112                    a, b = b, a
113                l = [b + i for i in util.get_xrange(0, a - b + mapx, mapx)]
114
115        limit = self.fileops.get_max_pos()
116        y = self.offset.y
117        x = self.offset.x
118        for _ in util.get_xrange(self.bufmap.y):
119            if lcur > limit:
120                break
121            lnext = lcur + mapx
122            if full or (lcur in l):
123                head = lcur <= beg < lnext
124                tail = lcur <= end < lnext
125                if head and tail:
126                    self.__chgat_single(y, x, beg, end, lcur)
127                elif head:
128                    self.__chgat_head(y, x, beg, lcur)
129                elif tail:
130                    self.__chgat_tail(y, x, end, lcur)
131                elif beg < lcur < end:
132                    self.__chgat_inside(y, x, lcur)
133                else:
134                    self.__chgat_outside(y, x, lcur)
135            lcur = lnext
136            y += 1
137
138    def __update_block_visual(self, full):
139        pos = self.fileops.get_pos()
140        ppos = self.fileops.get_prev_pos()
141        if self.in_same_page(pos, ppos):
142            self.chgat_posstr(ppos, screen.A_NONE)
143        else:
144            full = True
145        self.chgat_posstr(pos, self.attr_posstr)
146
147        beg = self.fileops.get_region_origin()
148        end = pos
149        if beg > end:
150            beg, end = end, beg
151        mapx = self.bufmap.x
152        d1 = beg % mapx
153        d2 = end % mapx
154        lbeg = beg - d1
155        lend = end - d2
156        if d1 > d2:
157            d2, d1 = d1, d2
158        if setting.use_unit_based:
159            d2 += (setting.bytes_per_unit - 1) # round up before set region
160        self.fileops.set_region_range(lbeg + d1, lend + d2, self.bufmap)
161
162        lcur = self.get_page_offset()
163        lpos = self.get_line_offset(pos)
164        lppos = self.get_line_offset(ppos)
165        lr = abs(pos - ppos) != mapx # move left/right
166
167        l = []
168        if not full:
169            a, b = lpos, lppos
170            if a == b:
171                l = [a]
172            else:
173                if a < b:
174                    a, b = b, a
175                l = [b + i for i in util.get_xrange(0, a - b + mapx, mapx)]
176
177        limit = self.fileops.get_max_pos()
178        y = self.offset.y
179        x = self.offset.x
180        for _ in util.get_xrange(self.bufmap.y):
181            if lcur > limit:
182                break
183            if full or lr or (lcur in l):
184                # XXX second and third conditionals are redundant
185                if lbeg <= lcur <= lend:
186                    self.__chgat_single(y, x, lcur + d1, lcur + d2, lcur)
187                elif lppos <= lcur < lbeg and lpos == lbeg and lppos < lpos:
188                    self.__chgat_outside(y, x, lcur) # down
189                elif lend < lcur <= lppos and lpos == lend and lpos < lppos:
190                    self.__chgat_outside(y, x, lcur) # up
191                elif lppos < lbeg: # jump down to other side of region
192                    self.__chgat_outside(y, x, lcur)
193                elif lend < lppos: # jump up to other side of region
194                    self.__chgat_outside(y, x, lcur)
195            lcur += mapx
196            y += 1
197
198    def post_fill_line(self, y, x, buf):
199        if not self.cell[1]:
200            return
201        # need to drop visual color from space within unit
202        upl, xpu = self.get_units_per_line(len(buf))
203        for i in util.get_xrange(upl):
204            extra = ' ' * self.cell[1]
205            pos = x + self.get_unit_width(i + 1) - len(extra)
206            if pos < self.get_size_x():
207                # pos + len(extra) - 1 still needs to fit
208                self.addstr(y, pos, extra)
209
210    # head
211    def __chgat_head(self, y, x, beg, offset):
212        pos = self.get_cell_width(beg - offset)
213        siz = self.get_cell_edge(self.bufmap.x) - pos
214        self.chgat(y, x, pos)
215        if x + pos < self.get_size_x():
216            self.chgat(y, x + pos, siz, self.attr_visual)
217
218    def __alt_chgat_head(self, y, x, beg, offset):
219        pos = self.get_cell_width(beg - offset)
220        buf = self.fileops.read(offset, self.bufmap.x)
221        s = self.get_str_line(buf)
222        d = self.get_cell_edge(self.bufmap.x) - len(s)
223        if d > 0:
224            s += ' ' * d
225        self.addstr(y, x, s[:pos])
226        if x + pos < self.get_size_x():
227            self.addstr(y, x + pos, s[pos:], self.attr_visual)
228
229    def __chgat_head_attr(self, y, x, beg, offset):
230        pos = self.get_cell_width(beg - offset)
231        siz = self.get_cell_edge(self.bufmap.x) - pos
232        buf = self.fileops.read(offset, beg - offset)
233        self.fill_line(y, x, buf, screen.A_NONE,
234            self.get_units_per_line(len(buf)))
235        self.post_fill_line(y, x, buf)
236        if x + pos < self.get_size_x():
237            self.chgat(y, x + pos, siz, self.attr_visual)
238
239    def __alt_chgat_head_attr(self, y, x, beg, offset):
240        pos = self.get_cell_width(beg - offset)
241        buf = self.fileops.read(offset, self.bufmap.x)
242        s = self.get_str_line(buf)
243        d = self.get_cell_edge(self.bufmap.x) - len(s)
244        if d > 0:
245            s += ' ' * d
246        buf = self.fileops.read(offset, beg - offset)
247        self.fill_line(y, x, buf, screen.A_NONE,
248            self.get_units_per_line(len(buf)))
249        self.post_fill_line(y, x, buf)
250        if x + pos < self.get_size_x():
251            self.addstr(y, x + pos, s[pos:], self.attr_visual)
252
253    # tail
254    def __chgat_tail(self, y, x, end, offset):
255        pos = self.get_cell_edge(end - offset + 1)
256        siz = self.get_cell_edge(self.bufmap.x) - pos
257        self.chgat(y, x, pos, self.attr_visual)
258        if x + pos < self.get_size_x():
259            self.chgat(y, x + pos, siz)
260
261    def __alt_chgat_tail(self, y, x, end, offset):
262        pos = self.get_cell_edge(end - offset + 1)
263        buf = self.fileops.read(offset, self.bufmap.x)
264        s = self.get_str_line(buf)
265        d = pos - len(s)
266        if d > 0:
267            s += ' ' * d
268        self.addstr(y, x, s[:pos], self.attr_visual)
269        if x + pos < self.get_size_x():
270            self.addstr(y, x + pos, s[pos:])
271
272    def __chgat_tail_attr(self, y, x, end, offset):
273        siz = self.get_cell_edge(end - offset + 1)
274        self.chgat(y, x, siz, self.attr_visual)
275        if end + 1 <= self.fileops.get_max_pos():
276            self.__chgat_tail_attr_clear(y, x, end, offset)
277
278    def __alt_chgat_tail_attr(self, y, x, end, offset):
279        siz = self.get_cell_edge(end - offset + 1)
280        buf = self.fileops.read(offset, self.bufmap.x)
281        s = self.get_str_line(buf)
282        d = siz - len(s)
283        if d > 0:
284            s += ' ' * d
285        self.addstr(y, x, s[:siz], self.attr_visual)
286        if end + 1 <= self.fileops.get_max_pos():
287            self.__chgat_tail_attr_clear(y, x, end, offset)
288
289    def __chgat_tail_attr_clear(self, y, x, end, offset):
290        num = end - offset + 1
291        buf = self.fileops.read(end + 1, self.bufmap.x - num)
292        pos = self.get_cell_width(num)
293        xx = self.fill_line_nth(y, x + pos, buf, num, screen.A_NONE)
294        self.post_fill_line(y, xx, buf)
295        if (end + 1) % self.bufmap.x: # not rightmost
296            # clear right side of newly fill'd line (needed when moving left/up)
297            unitlen = setting.bytes_per_unit
298            if (num % unitlen) == 0:
299                self.addstr(y, x + pos - 1, ' ' * self.cell[1])
300            else:
301                skip = unitlen - (num % unitlen)
302                skip *= self.cell[2]
303                xx = x + pos + skip
304                if xx <= self.get_size_x() - 1:
305                    # xx + len(...) - 1 still needs to fit
306                    self.addstr(y, xx, ' ' * self.cell[1])
307
308    # single
309    def __chgat_single(self, y, x, beg, end, offset):
310        pos = self.get_cell_width(beg - offset)
311        siz = self.get_cell_distance(beg, end)
312        wid = self.get_cell_edge(self.bufmap.x)
313        self.chgat(y, x, wid)
314        if x + pos < self.get_size_x():
315            self.chgat(y, x + pos, siz, self.attr_visual)
316
317    def __alt_chgat_single(self, y, x, beg, end, offset):
318        pos = self.get_cell_width(beg - offset)
319        siz = self.get_cell_distance(beg, end)
320        end = pos + siz
321        buf = self.fileops.read(offset, self.bufmap.x)
322        s = self.get_str_line(buf)
323        d = end - len(s)
324        if d > 0:
325            s += ' ' * d
326        self.addstr(y, x, s[:pos])
327        if x + pos < self.get_size_x():
328            self.addstr(y, x + pos, s[pos:end], self.attr_visual)
329        if x + end < self.get_size_x():
330            self.addstr(y, x + end, s[end:])
331
332    def __chgat_single_attr(self, y, x, beg, end, offset):
333        pos = self.get_cell_width(beg - offset)
334        siz = self.get_cell_distance(beg, end)
335        buf = self.fileops.read(offset, self.bufmap.x)
336        self.fill_line(y, x, buf, screen.A_NONE,
337            self.get_units_per_line(len(buf)))
338        self.post_fill_line(y, x, buf)
339        if x + pos < self.get_size_x():
340            self.chgat(y, x + pos, siz, self.attr_visual)
341
342    def __alt_chgat_single_attr(self, y, x, beg, end, offset):
343        pos = self.get_cell_width(beg - offset)
344        siz = self.get_cell_distance(beg, end)
345        end = pos + siz
346        buf = self.fileops.read(offset, self.bufmap.x)
347        s = self.get_str_line(buf)
348        d = end - len(s)
349        if d > 0:
350            s += ' ' * d
351        buf = self.fileops.read(offset, self.bufmap.x)
352        self.fill_line(y, x, buf, screen.A_NONE,
353            self.get_units_per_line(len(buf)))
354        self.post_fill_line(y, x, buf)
355        if x + pos < self.get_size_x():
356            self.addstr(y, x + pos, s[pos:end], self.attr_visual)
357
358    # inside
359    def __chgat_inside(self, y, x, offset):
360        self.__chgat_body(y, x, offset, self.attr_visual)
361
362    def __alt_chgat_inside(self, y, x, offset):
363        self.__alt_chgat_body(y, x, offset, self.attr_visual)
364
365    # outside
366    def __chgat_outside(self, y, x, offset):
367        self.__chgat_body(y, x, offset, screen.A_NONE)
368
369    def __alt_chgat_outside(self, y, x, offset):
370        self.__alt_chgat_body(y, x, offset, screen.A_NONE)
371
372    def __chgat_outside_attr(self, y, x, offset):
373        self.__chgat_body_attr(y, x, offset, screen.A_NONE)
374
375    def __alt_chgat_outside_attr(self, y, x, offset):
376        self.__chgat_body_attr(y, x, offset, screen.A_NONE)
377
378    # body
379    def __chgat_body(self, y, x, offset, attr):
380        siz = self.get_cell_edge(self.bufmap.x)
381        self.chgat(y, x, siz, attr)
382
383    def __alt_chgat_body(self, y, x, offset, attr):
384        buf = self.fileops.read(offset, self.bufmap.x)
385        s = self.get_str_line(buf)
386        d = self.get_cell_edge(self.bufmap.x) - len(s)
387        if d > 0:
388            s += ' ' * d
389        self.addstr(y, x, s, attr)
390
391    def __chgat_body_attr(self, y, x, offset, attr):
392        buf = self.fileops.read(offset, self.bufmap.x)
393        if self.fileops.get_region_type() == VISUAL_LINE and \
394            len(buf) != self.bufmap.x:
395            self.clrl(y, x) # clear last line beyond max position
396        self.fill_line(y, x, buf, attr,
397            self.get_units_per_line(len(buf)))
398        self.post_fill_line(y, x, buf)
399
400class BinaryCanvas (panel.BinaryCanvas, _visual_methods):
401    def __init__(self, siz, pos):
402        self.init()
403        super(BinaryCanvas, self).__init__(siz, pos)
404
405    def fill(self, low):
406        self.require_full_repaint()
407        super(BinaryCanvas, self).fill(low)
408        self.update_visual(True)
409
410    def update_highlight(self, low, range_update):
411        self.require_full_repaint()
412        self.update_visual(False)
413
414class TextCanvas (panel.TextCanvas, _visual_methods):
415    def __init__(self, siz, pos):
416        self.init()
417        super(TextCanvas, self).__init__(siz, pos)
418
419    def fill(self, low):
420        self.require_full_repaint()
421        super(TextCanvas, self).fill(low)
422        self.update_visual(True)
423
424    def update_highlight(self, low, range_update):
425        self.require_full_repaint()
426        self.update_visual(False)
427
428class ExtBinaryCanvas (extension.ExtBinaryCanvas, _visual_methods):
429    def __init__(self, siz, pos):
430        self.init()
431        super(ExtBinaryCanvas, self).__init__(siz, pos)
432
433    def fill(self, low):
434        self.require_full_repaint()
435        super(ExtBinaryCanvas, self).fill(low)
436        self.update_visual(True)
437
438    def update_highlight(self, low, range_update):
439        self.require_full_repaint()
440        self.update_visual(False)
441
442class _console (console.Console):
443    def init_method(self):
444        this = sys.modules[__name__]
445        self.add_method(literal.up           , methods, "cursor_up")
446        self.add_method(literal.down         , methods, "cursor_down")
447        self.add_method(literal.left         , methods, "cursor_left")
448        self.add_method(literal.right        , methods, "cursor_right")
449        self.add_method(literal.gg           , methods, "cursor_head")
450        self.add_method(literal.G            , methods, "cursor_tail")
451        self.add_method(literal.zero         , methods, "cursor_lhead")
452        self.add_method(literal.doller       , methods, "cursor_ltail")
453        self.add_method(literal.H            , methods, "cursor_phead")
454        self.add_method(literal.M            , methods, "cursor_pcenter")
455        self.add_method(literal.L            , methods, "cursor_ptail")
456        self.add_method(literal.w            , methods, "cursor_next_char")
457        self.add_method(literal.b            , methods, "cursor_prev_char")
458        self.add_method(literal.parens_end   , methods, "cursor_next_zero")
459        self.add_method(literal.parens_beg   , methods, "cursor_prev_zero")
460        self.add_method(literal.bracket1_end , methods, "cursor_next_nonzero")
461        self.add_method(literal.bracket1_beg , methods, "cursor_prev_nonzero")
462        self.add_method(literal.bracket2_end , methods, "end_read_delayed_input")
463        self.add_method(literal.bracket2_beg , methods, "start_read_delayed_input")
464        self.add_method(literal.go           , methods, "cursor_to")
465        self.add_method(literal.sh           , methods, "cursor_sector_left")
466        self.add_method(literal.sl           , methods, "cursor_sector_right")
467        self.add_method(literal.szero        , methods, "cursor_sector_shead")
468        self.add_method(literal.sdoller      , methods, "cursor_sector_stail")
469        self.add_method(literal.sgo          , methods, "cursor_sector_to")
470        self.add_method(literal.ctrlb        , methods, "cursor_pprev")
471        self.add_method(literal.ctrlu        , methods, "cursor_hpprev")
472        self.add_method(literal.ctrlf        , methods, "cursor_pnext")
473        self.add_method(literal.ctrld        , methods, "cursor_hpnext")
474        self.add_method(literal.mouse        , methods, "handle_mouse_event_visual")
475        self.add_method(literal.resize       , methods, "resize_container")
476        self.add_method(literal.ctrll        , methods, "refresh_container")
477        self.add_method(literal.ctrlw_w      , this,    "_queue_input")
478        self.add_method(literal.ctrlw_W      , this,    "_queue_input")
479        self.add_method(literal.ctrlw_t      , this,    "_queue_input")
480        self.add_method(literal.ctrlw_b      , this,    "_queue_input")
481        self.add_method(literal.ctrlw_s      , this,    "_queue_input")
482        self.add_method(literal.s_split      , this,    "_queue_input")
483        self.add_method(literal.s_vsplit     , this,    "_queue_input")
484        self.add_method(literal.ctrlw_plus   , methods, "inc_workspace_height")
485        self.add_method(literal.ctrlw_minus  , methods, "dec_workspace_height")
486        self.add_method(literal.s_close      , this,    "_queue_input")
487        self.add_method(literal.s_only       , this,    "_queue_input")
488        self.add_method(literal.s_e          , this,    "_queue_input")
489        self.add_method(literal.s_bdelete    , this,    "_queue_input")
490        self.add_method(literal.s_bfirst     , this,    "_queue_input")
491        self.add_method(literal.s_blast      , this,    "_queue_input")
492        self.add_method(literal.s_bnext      , this,    "_queue_input")
493        self.add_method(literal.s_bprev      , this,    "_queue_input")
494        self.add_method(literal.s_set        , methods, "set_option")
495        self.add_method(literal.s_auto       , methods, "set_auto")
496        self.add_method(literal.ctrlg        , this,    "_queue_input")
497        self.add_method(literal.g_ctrlg      , this,    "_queue_input")
498        self.add_method(literal.s_self       , this,    "_queue_input")
499        self.add_method(literal.s_pwd        , this,    "_queue_input")
500        self.add_method(literal.s_date       , this,    "_queue_input")
501        self.add_method(literal.s_kmod       , this,    "_queue_input")
502        self.add_method(literal.s_fobj       , this,    "_queue_input")
503        self.add_method(literal.s_bufsiz     , this,    "_queue_input")
504        self.add_method(literal.s_meminfo    , this,    "_queue_input")
505        self.add_method(literal.s_osdep      , this,    "_queue_input")
506        self.add_method(literal.s_screen     , this,    "_queue_input")
507        self.add_method(literal.s_platform   , this,    "_queue_input")
508        self.add_method(literal.s_hostname   , this,    "_queue_input")
509        self.add_method(literal.s_term       , this,    "_queue_input")
510        self.add_method(literal.s_lang       , this,    "_queue_input")
511        self.add_method(literal.s_version    , this,    "_queue_input")
512        self.add_method(literal.s_sector     , this,    "_queue_input")
513        self.add_method(literal.s_argv       , this,    "_queue_input")
514        self.add_method(literal.s_args       , this,    "_queue_input")
515        self.add_method(literal.s_md5        , this,    "_show_md5")
516        self.add_method(literal.s_sha1       , this,    "_show_sha1")
517        self.add_method(literal.s_sha224     , this,    "_show_sha224")
518        self.add_method(literal.s_sha256     , this,    "_show_sha256")
519        self.add_method(literal.s_sha384     , this,    "_show_sha384")
520        self.add_method(literal.s_sha512     , this,    "_show_sha512")
521        self.add_method(literal.s_sha3_224   , this,    "_show_sha3_224")
522        self.add_method(literal.s_sha3_256   , this,    "_show_sha3_256")
523        self.add_method(literal.s_sha3_384   , this,    "_show_sha3_384")
524        self.add_method(literal.s_sha3_512   , this,    "_show_sha3_512")
525        self.add_method(literal.s_cmp        , this,    "_queue_input")
526        self.add_method(literal.s_cmpneg     , this,    "_queue_input")
527        self.add_method(literal.s_cmpnext    , this,    "_queue_input")
528        self.add_method(literal.s_cmpnextneg , this,    "_queue_input")
529        self.add_method(literal.s_cmpr       , this,    "_queue_input")
530        self.add_method(literal.s_cmprneg    , this,    "_queue_input")
531        self.add_method(literal.s_cmprnext   , this,    "_queue_input")
532        self.add_method(literal.s_cmprnextneg, this,    "_queue_input")
533        self.add_method(literal.ctrla        , this,    "_inc_number")
534        self.add_method(literal.ctrlx        , this,    "_dec_number")
535        self.add_method(literal.period       , this,    "_queue_input")
536        self.add_method(literal.toggle       , this,    "_toggle")
537        self.add_method(literal.ror          , this,    "_rotate_right")
538        self.add_method(literal.rol          , this,    "_rotate_left")
539        self.add_method(literal.bswap        , this,    "_swap_bytes")
540        self.add_method(literal.delete       , this,    "_delete")
541        self.add_method(literal.X            , this,    "_delete")
542        self.add_method(literal.D            , this,    "_delete")
543        self.add_method(literal.u            , this,    "_queue_input")
544        self.add_method(literal.U            , this,    "_queue_input")
545        self.add_method(literal.ctrlr        , this,    "_queue_input")
546        self.add_method(literal.reg_reg      , methods, "start_register")
547        self.add_method(literal.m_reg        , this,    "_queue_input")
548        self.add_method(literal.backtick_reg , this,    "_queue_input")
549        self.add_method(literal.s_delmarks   , this,    "_queue_input")
550        self.add_method(literal.s_delmarksneg, this,    "_queue_input")
551        self.add_method(literal.q_reg        , methods, "start_record")
552        self.add_method(literal.atsign_reg   , methods, "replay_record")
553        self.add_method(literal.atsign_at    , methods, "replay_record")
554        self.add_method(literal.atsign_colon , methods, "replay_bind")
555        self.add_method(literal.s_bind       , this,    "_queue_input")
556        self.add_method(literal.bit_and      , this,    "_logical_bit_operation")
557        self.add_method(literal.bit_or       , this,    "_logical_bit_operation")
558        self.add_method(literal.bit_xor      , this,    "_logical_bit_operation")
559        self.add_method(literal.y            , this,    "_yank")
560        self.add_method(literal.Y            , this,    "_yank")
561        self.add_method(literal.P            , this,    "_put")
562        self.add_method(literal.p            , this,    "_put")
563        self.add_method(literal.O            , this,    "_put")
564        self.add_method(literal.o            , this,    "_put")
565        self.add_method(literal.s_w          , this,    "_save_buffer")
566        self.add_method(literal.s_wneg       , this,    "_force_save_buffer")
567        self.add_method(literal.s_wq         , this,    "_save_buffer_quit")
568        #self.add_method(literal.s_x         , None,    None)
569        self.add_method(literal.s_q          , this,    "_queue_input")
570        self.add_method(literal.s_qneg       , this,    "_queue_input")
571        self.add_method(literal.s_qa         , this,    "_queue_input")
572        self.add_method(literal.s_qaneg      , this,    "_queue_input")
573        self.add_method(literal.s_open_md5   , this,    "_open_md5")
574        self.add_method(literal.s_open_sha1  , this,    "_open_sha1")
575        self.add_method(literal.s_open_sha224, this,    "_open_sha224")
576        self.add_method(literal.s_open_sha256, this,    "_open_sha256")
577        self.add_method(literal.s_open_sha384, this,    "_open_sha384")
578        self.add_method(literal.s_open_sha512, this,    "_open_sha512")
579        self.add_method(literal.s_open_sha3_224, this,  "_open_sha3_224")
580        self.add_method(literal.s_open_sha3_256, this,  "_open_sha3_256")
581        self.add_method(literal.s_open_sha3_384, this,  "_open_sha3_384")
582        self.add_method(literal.s_open_sha3_512, this,  "_open_sha3_512")
583        self.add_method(literal.s_open_b64e  , this,    "_open_base64_encode")
584        self.add_method(literal.s_open_b64d  , this,    "_open_base64_decode")
585        self.add_method(literal.s_open_b32e  , this,    "_open_base32_encode")
586        self.add_method(literal.s_open_b32d  , this,    "_open_base32_decode")
587        self.add_method(literal.s_open_b16e  , this,    "_open_base16_encode")
588        self.add_method(literal.s_open_b16d  , this,    "_open_base16_decode")
589        self.add_method(literal.s_open_b85e  , this,    "_open_base85_encode")
590        self.add_method(literal.s_open_b85d  , this,    "_open_base85_decode")
591        self.add_method(literal.s_fsearchw   , methods, "search_word_forward")
592        self.add_method(literal.s_rsearchw   , methods, "search_word_backward")
593        self.add_method(literal.n            , methods, "search_word_next_forward")
594        self.add_method(literal.N            , methods, "search_word_next_backward")
595        self.add_method(literal.fsearchc     , methods, "search_char_forward")
596        self.add_method(literal.rsearchc     , methods, "search_char_backward")
597        self.add_method(literal.fsearchcb    , methods, "search_char_forward_before")
598        self.add_method(literal.rsearchcb    , methods, "search_char_backward_before")
599        self.add_method(literal.semicolon    , methods, "search_char_next_forward")
600        self.add_method(literal.comma        , methods, "search_char_next_backward")
601        self.add_method(literal.escape       , this,    "_escape_visual")
602        #self.add_method(literal.i           , None,    None)
603        #self.add_method(literal.I           , None,    None)
604        #self.add_method(literal.a           , None,    None)
605        #self.add_method(literal.A           , None,    None)
606        self.add_method(literal.R            , this,    "_enter_edit_replace")
607        self.add_method(literal.r            , this,    "_do_edit_replace")
608        self.add_method(literal.v            , this,    "_enter_visual")
609        self.add_method(literal.V            , this,    "_enter_line_visual")
610        self.add_method(literal.ctrlv        , this,    "_enter_block_visual")
611        for li in literal.get_ext_literals():
612            self.add_method(li, this, "_queue_input")
613
614    def handle_signal(self):
615        _exit_visual(self)
616        return kbd.INTERRUPT
617
618    def handle_invalid_literal(self, li):
619        self.co.flash("Not a visual command " + li.str)
620        return _exit_visual(self)
621
622    def set_banner(self):
623        console.set_banner(self.co.get_region_type())
624
625class Console (_console):
626    pass
627
628class ExtConsole (_console):
629    pass
630
631def _queue_input(self, amp, opc, args, raw):
632    if raw[0] in literal.get_slow_ords():
633        raw.append(kbd.ENTER)
634    self.co.queue_input(raw)
635    return _exit_visual(self)
636
637def _enter_visual(self, amp, opc, args, raw):
638    return __enter_visual(self, VISUAL)
639
640def _enter_line_visual(self, amp, opc, args, raw):
641    return __enter_visual(self, VISUAL_LINE)
642
643def _enter_block_visual(self, amp, opc, args, raw):
644    return __enter_visual(self, VISUAL_BLOCK)
645
646def __enter_visual(self, visual_type):
647    if self.co.get_region_type() == visual_type:
648        return _exit_visual(self)
649    else:
650        self.co.set_region_type(visual_type)
651        return self.set_console(util.get_class(self))
652
653def _escape_visual(self, amp, opc, args, raw):
654    methods.escape(self, amp, opc, args, raw)
655    return _exit_visual(self)
656
657def _exit_visual(self, amp=None, opc=None, args=None, raw=None):
658    self.co.cleanup_region()
659    # Repaint to ensure space between units are cleared before exit.
660    # This is not a must since consoles are repainted on dispatch.
661    self.co.lrepaint()
662    return self.set_console(None)
663
664def _(a, b):
665    def _exit(fn):
666        def _method(self, amp, opc, args, raw):
667            _fn = b if _in_block_visual(self) else a
668            ret = _fn(self, amp, opc, args, raw)
669            if ret == methods.QUIT:
670                return methods.QUIT
671            assert ret != methods.REWIND
672            assert ret != methods.CONTINUE
673            return fn(self, amp, opc, args, raw)
674        return _method
675    return _exit
676
677def _in_block_visual(self):
678    return self.co.get_region_type() == VISUAL_BLOCK
679
680@_(methods.range_show_md5, methods.block_show_md5)
681def _show_md5(self, amp, opc, args, raw):
682    return _exit_visual(self)
683
684@_(methods.range_show_sha1, methods.block_show_sha1)
685def _show_sha1(self, amp, opc, args, raw):
686    return _exit_visual(self)
687
688@_(methods.range_show_sha224, methods.block_show_sha224)
689def _show_sha224(self, amp, opc, args, raw):
690    return _exit_visual(self)
691
692@_(methods.range_show_sha256, methods.block_show_sha256)
693def _show_sha256(self, amp, opc, args, raw):
694    return _exit_visual(self)
695
696@_(methods.range_show_sha384, methods.block_show_sha384)
697def _show_sha384(self, amp, opc, args, raw):
698    return _exit_visual(self)
699
700@_(methods.range_show_sha512, methods.block_show_sha512)
701def _show_sha512(self, amp, opc, args, raw):
702    return _exit_visual(self)
703
704@_(methods.range_show_sha3_224, methods.block_show_sha3_224)
705def _show_sha3_224(self, amp, opc, args, raw):
706    return _exit_visual(self)
707
708@_(methods.range_show_sha3_256, methods.block_show_sha3_256)
709def _show_sha3_256(self, amp, opc, args, raw):
710    return _exit_visual(self)
711
712@_(methods.range_show_sha3_384, methods.block_show_sha3_384)
713def _show_sha3_384(self, amp, opc, args, raw):
714    return _exit_visual(self)
715
716@_(methods.range_show_sha3_512, methods.block_show_sha3_512)
717def _show_sha3_512(self, amp, opc, args, raw):
718    return _exit_visual(self)
719
720@_(methods.range_inc_number, methods.block_inc_number)
721def _inc_number(self, amp, opc, args, raw):
722    return _exit_visual(self)
723
724@_(methods.range_dec_number, methods.block_dec_number)
725def _dec_number(self, amp, opc, args, raw):
726    return _exit_visual(self)
727
728@_(methods.range_toggle, methods.block_toggle)
729def _toggle(self, amp, opc, args, raw):
730    return _exit_visual(self)
731
732@_(methods.range_rotate_right, methods.block_rotate_right)
733def _rotate_right(self, amp, opc, args, raw):
734    return _exit_visual(self)
735
736@_(methods.range_rotate_left, methods.block_rotate_left)
737def _rotate_left(self, amp, opc, args, raw):
738    return _exit_visual(self)
739
740@_(methods.range_swap_bytes, methods.block_swap_bytes)
741def _swap_bytes(self, amp, opc, args, raw):
742    return _exit_visual(self)
743
744@_(methods.range_delete, methods.block_delete)
745def _delete(self, amp, opc, args, raw):
746    return _exit_visual(self)
747
748@_(methods.range_logical_bit_operation, methods.block_logical_bit_operation)
749def _logical_bit_operation(self, amp, opc, args, raw):
750    return _exit_visual(self)
751
752@_(methods.range_yank, methods.block_yank)
753def _yank(self, amp, opc, args, raw):
754    return _exit_visual(self)
755
756@_(methods.range_put, methods.block_put)
757def _put(self, amp, opc, args, raw):
758    return _exit_visual(self)
759
760@_(methods.range_save_buffer, methods.block_save_buffer)
761def _save_buffer(self, amp, opc, args, raw):
762    return _exit_visual(self)
763
764@_(methods.range_force_save_buffer, methods.block_force_save_buffer)
765def _force_save_buffer(self, amp, opc, args, raw):
766    return _exit_visual(self)
767
768@_(methods.range_save_buffer_quit, methods.block_save_buffer_quit)
769def _save_buffer_quit(self, amp, opc, args, raw):
770    return _exit_visual(self)
771
772@_(methods.range_open_md5, methods.block_open_md5)
773def _open_md5(self, amp, opc, args, raw):
774    return _exit_visual(self)
775
776@_(methods.range_open_sha1, methods.block_open_sha1)
777def _open_sha1(self, amp, opc, args, raw):
778    return _exit_visual(self)
779
780@_(methods.range_open_sha224, methods.block_open_sha224)
781def _open_sha224(self, amp, opc, args, raw):
782    return _exit_visual(self)
783
784@_(methods.range_open_sha256, methods.block_open_sha256)
785def _open_sha256(self, amp, opc, args, raw):
786    return _exit_visual(self)
787
788@_(methods.range_open_sha384, methods.block_open_sha384)
789def _open_sha384(self, amp, opc, args, raw):
790    return _exit_visual(self)
791
792@_(methods.range_open_sha512, methods.block_open_sha512)
793def _open_sha512(self, amp, opc, args, raw):
794    return _exit_visual(self)
795
796@_(methods.range_open_sha3_224, methods.block_open_sha3_224)
797def _open_sha3_224(self, amp, opc, args, raw):
798    return _exit_visual(self)
799
800@_(methods.range_open_sha3_256, methods.block_open_sha3_256)
801def _open_sha3_256(self, amp, opc, args, raw):
802    return _exit_visual(self)
803
804@_(methods.range_open_sha3_384, methods.block_open_sha3_384)
805def _open_sha3_384(self, amp, opc, args, raw):
806    return _exit_visual(self)
807
808@_(methods.range_open_sha3_512, methods.block_open_sha3_512)
809def _open_sha3_512(self, amp, opc, args, raw):
810    return _exit_visual(self)
811
812@_(methods.range_open_base64_encode, methods.block_open_base64_encode)
813def _open_base64_encode(self, amp, opc, args, raw):
814    return _exit_visual(self)
815
816@_(methods.range_open_base64_decode, methods.block_open_base64_decode)
817def _open_base64_decode(self, amp, opc, args, raw):
818    return _exit_visual(self)
819
820@_(methods.range_open_base32_encode, methods.block_open_base32_encode)
821def _open_base32_encode(self, amp, opc, args, raw):
822    return _exit_visual(self)
823
824@_(methods.range_open_base32_decode, methods.block_open_base32_decode)
825def _open_base32_decode(self, amp, opc, args, raw):
826    return _exit_visual(self)
827
828@_(methods.range_open_base16_encode, methods.block_open_base16_encode)
829def _open_base16_encode(self, amp, opc, args, raw):
830    return _exit_visual(self)
831
832@_(methods.range_open_base16_decode, methods.block_open_base16_decode)
833def _open_base16_decode(self, amp, opc, args, raw):
834    return _exit_visual(self)
835
836@_(methods.range_open_base85_encode, methods.block_open_base85_encode)
837def _open_base85_encode(self, amp, opc, args, raw):
838    return _exit_visual(self)
839
840@_(methods.range_open_base85_decode, methods.block_open_base85_decode)
841def _open_base85_decode(self, amp, opc, args, raw):
842    return _exit_visual(self)
843
844@_(methods.range_delete, methods.block_delete)
845def _enter_edit_replace(self, amp, opc, args, raw):
846    self.co.cleanup_region()
847    arg = edit.Arg(amp=methods.get_int(amp))
848    return self.set_console(edit.get_replace_class(), arg)
849
850def _do_edit_replace(self, amp, opc, args, raw):
851    if _in_block_visual(self):
852        cls = edit.get_block_replace_class()
853    else:
854        cls = edit.get_range_replace_class()
855    arg = edit.Arg(limit=edit.get_input_limit(),
856        start=self.co.get_region_range()[0])
857    return self.set_console(cls, arg)
858