1
###############################################################################
3
# Purpose: Editra's Vi Emulation Key Handler #
4
# Author: Cody Precord <cprecord@editra.org> #
5
# Copyright: (c) 2008 Cody Precord <staff@editra.org> #
6
# License: wxWindows License #
7
###############################################################################
10
KeyHandler interface for implementing extended key action handling in Editra's
11
main text editting buffer.
13
@summary: Custom keyhandler interface
17
__author__ = "Cody Precord <cprecord@editra.org>"
18
__svnid__ = "$Id: ed_keyh.py 70747 2012-02-29 01:33:35Z CJP $"
19
__revision__ = "$Revision: 70747 $"
21
#-------------------------------------------------------------------------#
35
#-------------------------------------------------------------------------#
36
# Use this base class to derive any new keyhandlers from. The keyhandler is
37
# called upon by the active buffer when ever a key press event happens. The
38
# handler then has the responsibility of deciding what to do with the key.
40
class KeyHandler(object):
41
"""KeyHandler base class"""
42
def __init__(self, stc):
43
super(KeyHandler, self).__init__()
47
self._blockmode = False
49
STC = property(lambda self: self.stc)
50
BlockMode = property(lambda self: self._blockmode,
51
lambda self,m:setattr(self,'_blockmode', m))
54
"""Clear any key input modes to normal input mode"""
55
evt = ed_event.StatusEvent(ed_event.edEVT_STATUS, self.stc.Id,
57
wx.PostEvent(self.stc.TopLevelParent, evt)
59
def GetHandlerName(self):
60
"""Get the name of this handler
66
def PreProcessKey(self, key_code, ctrldown=False,
67
cmddown=False, shiftdown=False, altdown=False):
68
"""Pre process any keys before they get to the char handler
69
@param key_code: Raw keycode
70
@keyword ctrldown: Is the control key down
71
@keyword cmddown: Is the Command key down (Mac osx)
72
@keyword shiftdown: Is the Shift key down
73
@keyword altdown: Is the Alt key down
79
def ProcessKey(self, key_code, ctrldown=False,
80
cmddown=False, shiftdown=False, altdown=False):
81
"""Process the key and return True if it was processed and
82
false if it was not. The key is recieved at EVT_CHAR.
83
@param key_code: Raw keycode
84
@keyword ctrldown: Is the control key down
85
@keyword cmddown: Is the Command key down (Mac osx)
86
@keyword shiftdown: Is the Shift key down
87
@keyword altdown: Is the Alt key down
93
#-------------------------------------------------------------------------#
95
class ViKeyHandler(KeyHandler):
96
"""Defines a key handler for Vi emulation
97
@summary: Handles key presses according to Vi emulation.
101
# Vi Mode declarations
107
def __init__(self, stc, use_normal_default=False):
108
super(ViKeyHandler, self).__init__(stc)
114
self.commander = ed_vim.EditraCommander(self)
117
# Insert mode by default
118
if use_normal_default:
124
"""Clear the mode back to default input mode"""
125
# TODO:CJP when newer scintilla is available in 2.9 use
126
# blockcaret methods.
127
self.STC.SetLineCaret()
128
self.BlockMode = False
129
self.last = self.cmdcache = u''
130
super(ViKeyHandler, self).ClearMode()
132
def GetHandlerName(self):
133
"""Get the name of this handler"""
136
def _SetMode(self, newmode, msg):
137
"""Set the keyhandlers mode
138
@param newmode: New mode name to change to
141
self.buffer = u'' # Clear buffer from last mode
144
evt = ed_event.StatusEvent(ed_event.edEVT_STATUS, self.stc.GetId(),
145
msg, ed_glob.SB_BUFF)
146
wx.PostEvent(self.stc.GetTopLevelParent(), evt)
148
def InsertMode(self):
149
"""Change to insert mode"""
150
self.stc.SetLineCaret()
151
self.stc.SetOvertype(False)
152
self.BlockMode = False
153
self._SetMode(ViKeyHandler.INSERT, u"INSERT")
155
def ReplaceMode(self):
156
"""Change to replace mode
157
This really just insert mode with overtype set to true
160
self.stc.SetLineCaret()
161
self.stc.SetOvertype(True)
162
self._SetMode(ViKeyHandler.INSERT, u"REPLACE")
164
def NormalMode(self):
165
"""Change to normal (command) mode"""
166
if self.IsInsertMode():
167
self.commander.SetLastInsertedText(self.buffer)
169
self.stc.SetOvertype(False)
170
self.stc.SetBlockCaret()
171
self.BlockMode = True
172
self.commander.Deselect()
173
self.commander.InsertRepetition()
174
self._SetMode(ViKeyHandler.NORMAL, u'NORMAL')
176
def VisualMode(self):
177
"""Change to visual (selection) mode"""
178
self.stc.SetBlockCaret()
179
self.BlockMode = True
180
self.stc.SetOvertype(False)
181
self._SetMode(ViKeyHandler.VISUAL, u'VISUAL')
182
self.commander.StartSelection()
184
def IsInsertMode(self):
185
"""Test if we are in insert mode"""
186
return self.mode == ViKeyHandler.INSERT
188
def IsNormalMode(self):
189
"""Test if we are in normal mode"""
190
return self.mode == ViKeyHandler.NORMAL
192
def IsVisualMode(self):
193
"""Test if we are in visual mode"""
194
return self.mode == ViKeyHandler.VISUAL
196
def PreProcessKey(self, key_code, ctrldown=False,
197
cmddown=False, shiftdown=False, altdown=False):
198
"""Pre process any keys before they get to the char handler
199
@param key_code: Raw keycode
200
@keyword ctrldown: Is the control key down
201
@keyword cmddown: Is the Command key down (Mac osx)
202
@keyword shiftdown: Is the Shift key down
203
@keyword altdown: Is the Alt key down
207
if not shiftdown and key_code == wx.WXK_ESCAPE:
208
# If Vi emulation is active go into Normal mode and
209
# pass the key event to the char handler by not processing
213
elif (ctrldown or cmddown) and key_code == ord('['):
216
elif key_code in (wx.WXK_RETURN, wx.WXK_BACK,
217
wx.WXK_RIGHT, wx.WXK_LEFT) and \
218
not self.IsInsertMode():
219
# swallow enter key in normal and visual modes
220
# HACK: we have to do it form here because ProcessKey
221
# is only called on Char events, not Key events,
222
# and the Enter key does not generate a Char event.
223
self.ProcessKey(key_code)
228
def ProcessKey(self, key_code, ctrldown=False,
229
cmddown=False, shiftdown=False, altdown=False):
230
"""Processes keys and decided whether to interpret them as vim commands
231
or normal insert text
233
@param key_code: Raw key code
234
@keyword cmddown: Command/Ctrl key is down
235
@keyword shiftdown: Shift Key is down
236
@keyword altdown : Alt key is down
239
if ctrldown or cmddown or altdown:
242
# Mode may change after processing the key, so we need to remember
243
# whether this was a command or not
244
f_cmd = self.IsNormalMode() or self.IsVisualMode()
246
self._ProcessKey(key_code)
249
if self.IsNormalMode():
250
if self.stc.GetTopLevelParent():
251
evt = ed_event.StatusEvent(ed_event.edEVT_STATUS,
253
u"NORMAL %s" % self.buffer,
255
wx.PostEvent(self.stc.GetTopLevelParent(), evt)
260
# If we're in insert mode we must return False
261
# so the text gets inserted into the editor
264
def _ProcessKey(self, key_code):
265
"""The real processing of keys"""
266
char = unichr(key_code)
267
if self.IsNormalMode() or self.IsVisualMode():
269
if ed_vim.Parse(self.buffer, self.commander):
270
# command was handled (or invalid) so clear buffer
273
if self.IsVisualMode():
274
self.commander.ExtendSelection()
276
elif self.IsInsertMode():
279
def InsertText(self, pos, text):
280
"""Insert text and store it in the buffer if we're in insert mode
281
i.e. as if it was typed in
284
self.stc.InsertText(pos, text)
285
if self.IsInsertMode():
b'\\ No newline at end of file'