Commits

Ali Afshar committed 2866935

Initial Import

Comments (0)

Files changed (5)

+^build
+.coverage
+coverage
+moo_stub.so
+moo/.*.o
+moo/moo-pygtk.c
+moo/moomarshals.c
+moo/moomarshals.h
+moo/marshals.c
+moo/marshals.h
+moo/stock-moo.h
+moo/test
+^docs/build
+.ropeproject
+.*\.swp
+.*\.pyc
+tmp
+.pida-metadata
+pida.egg-info
+docs/_build
+.*\.*~
+externals
+dist
+MANIFEST

er/__init__.py

Empty file added.
+
+
+from collections import namedtuple
+
+
+NormalCommand = namedtuple('NormalCommand', 'command repeat range')
+
+
+no_range_commands = set(['CUT'])
+range_commands = set(['YANK', 'CHANGE'])
+ranges = {
+    'w': 'WORD',
+    'iw': 'IWORD',
+}
+
+
+class NormalCommandParser(object):
+    """
+    Parse normal mode commands
+    """
+
+    def __init__(self, keys):
+        self.keys = keys
+        self.reset()
+
+    def reset(self):
+        self.command = None
+        self.repeat = []
+        self.range = []
+
+    def parse(self, s):
+        self.reset()
+        return self.push(s)
+
+    def push(self, s):
+        for c in s:
+            if not self.command:
+                if c.isdigit():
+                    self.repeat.append(c)
+                else:
+                    self.command = c
+            else:
+                self.range.append(c)
+
+        r = None
+
+        com = self.keys.get(self.command)
+
+        if com is not None:
+
+            if self.repeat:
+                rep = int(''.join(self.repeat))
+            else:
+                rep = None
+
+            if self.range:
+                ran = ''.join(self.range)
+                if ran == self.command:
+                    ran = 'LINE'
+                else:
+                    ran = ranges.get(ran)
+
+            else:
+                ran = None
+
+            if com in no_range_commands:
+                r = (com, rep, None)
+            elif ran:
+                r = (com, rep, ran)
+
+
+        if r is not None:
+            self.reset()
+            return r
+
+
+import gtk, pango, gtk.gdk
+import gtksourceview2
+
+from pygtkhelpers.delegates import WindowView, SlaveView
+from pygtkhelpers.addons import GObjectPlugin, GObjectUserDataProxy
+
+
+
+def go_normal(e, v, b, event):
+    v.set_data('mode', 'normal')
+    v.set_overwrite(True)
+    i = b.get_iter_at_offset(b.get_property('cursor-position') - 1)
+    b.place_cursor(i)
+    return True
+
+
+def show_ex(e, v, b, event):
+    e.ex.popup(':')
+    return True
+
+def show_search(e, v, b, event):
+    e.ex.popup('/')
+    return True
+
+def go_ins(e, v, b, event):
+    v.set_overwrite(False)
+    v.set_data('mode', 'insert')
+    v.grab_focus()
+    return True
+
+def do_echo():
+    pass
+
+def passthrough(e, v, b, event):
+    return False
+
+kmap = {
+    'insert': {
+        'Escape': go_normal,
+    },
+    'normal': {
+        'colon': show_ex,
+        'slash': show_search,
+        'i': go_ins,
+        'Up': passthrough,
+        'Down': passthrough,
+        'Left': passthrough,
+        'Right': passthrough,
+        'Page_Up': passthrough,
+        'Page_Down': passthrough,
+    }
+}
+
+excom = {
+    'echo': do_echo,
+}
+
+class ModedEditor(GObjectPlugin):
+
+    addon_name = 'moded-editor'
+
+    def configure(self, **kw):
+        self._mode_data = GObjectUserDataProxy(self.widget)
+        self._mode_data.mode = 'normal'
+
+
+class ExView(gtksourceview2.View):
+
+    def __init__(self, ed):
+        self.e = ed
+        self.b = gtksourceview2.Buffer()
+        gtksourceview2.View.__init__(self, self.b)
+        fontName = 'Monospace 14'
+        pangoFont = pango.FontDescription(fontName)
+        self.modify_font(pangoFont)
+        self.connect('key-press-event', self._on_key_press_event)
+        self.set_no_show_all(True)
+
+    def _on_key_press_event(self, view, event):
+
+        key_name = gtk.gdk.keyval_name(event.keyval)
+        print key_name
+        if key_name == 'Return':
+            self.popdown()
+            command = self.b.get_text(self.b.get_start_iter(), self.b.get_end_iter())
+            if command.startswith('/'):
+                s = command[1:]
+                b = self.e.get_buffer()
+                i = b.get_start_iter()
+                print dir(gtksourceview2)
+                hi = b.create_tag('hi', background='yellow')
+                s, e = i.forward_search(s, flags=gtksourceview2.SEARCH_TEXT_ONLY)
+                b.apply_tag(hi, s, e)
+            return True
+        elif key_name == 'Escape':
+            self.popdown()
+            return True
+        else:
+            return False
+
+    def popup(self, prompt):
+        self.b.set_text(prompt)
+        self.show()
+        self.grab_focus()
+
+    def popdown(self):
+        self.hide()
+        self.e.grab_focus()
+
+class Editor(WindowView):
+
+    def create_ui(self):
+        lm = gtksourceview2.language_manager_get_default()
+        print lm.get_language_ids()
+        lang = lm.get_language('python')
+        v = gtksourceview2.View()
+        v.set_show_line_numbers(True)
+        v.set_wrap_mode(gtk.WRAP_WORD_CHAR)
+        v.set_show_line_marks(True)
+        b = gtksourceview2.Buffer()
+        b.set_highlight_syntax(True)
+        b.set_language(lang)
+        fontName = 'Monospace 10'
+        pangoFont = pango.FontDescription(fontName)
+        v.modify_font(pangoFont)
+        v.set_buffer(b)
+        b.set_text(open(__file__).read())
+        sw = gtk.ScrolledWindow()
+        sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+        sw.add(v)
+        vb = gtk.VBox()
+        ex = ExView(v)
+        vb.pack_start(sw)
+        vb.pack_start(ex, expand=False)
+        self.widget.add(vb)
+        self.widget.resize(300, 300)
+        self.v = v
+        self.b = b
+        self.ex = ex
+
+        self.v.set_overwrite(True)
+
+        ModedEditor(self.v)
+
+    def on_v__key_press_event(self, v, event):
+        mode = v.get_data('mode')
+        print event, mode
+        mmap  = kmap.get(mode)
+        key_name = gtk.gdk.keyval_name(event.keyval)
+        act = mmap.get(key_name)
+        print dir(event)
+        print [mmap, event.keyval, key_name, event.string]
+        print act
+        if act is not None:
+
+            return act(self, v, v.get_buffer(), event)
+        else:
+            if mode == 'insert':
+                return False
+            else:
+                return True
+
+
+
+if __name__ == '__main__':
+    e = Editor()
+    e.show_and_run()
+

tests/test_keystate.py

+
+from er.keystate import NormalCommandParser
+
+commands = {
+    'c': 'CHANGE',
+    'y': 'YANK',
+    'x': 'CUT',
+}
+
+parser = NormalCommandParser(commands)
+
+parse_command = parser.parse
+
+def test_basic_command():
+    assert parse_command('x') == ('CUT', None, None)
+
+def test_basic_repeat():
+    assert parse_command('10x') == ('CUT', 10, None)
+
+def test_basic_range():
+    assert parse_command('cw') == ('CHANGE', None, 'WORD')
+
+def test_implicit_range():
+    assert parse_command('cc') == ('CHANGE', None, 'LINE')
+
+def test_repeat_range():
+    assert parse_command('10yy') == ('YANK', 10, 'LINE')
+
+def test_repeat_explicit_range():
+    assert parse_command('10yw') == ('YANK', 10, 'WORD')
+
+def test_iword_range():
+    assert parse_command('ciw') == ('CHANGE', None, 'IWORD')
+
+def test_push():
+    parser.reset()
+    assert parser.push('x') == ('CUT', None, None)
+
+def test_push_multi():
+    parser.reset()
+    assert parser.push('1') == None
+    assert parser.push('9') == None
+    assert parser.push('x') == ('CUT', 19, None)
+
+def test_push_multi_range():
+    parser.reset()
+    assert parser.push('1') == None
+    assert parser.push('9') == None
+    assert parser.push('c') == None
+    assert parser.push('w') == ('CHANGE', 19, 'WORD')
+
+def test_push_incomplete():
+    parser.reset()
+    assert parser.push('10') == None
+