| CODENOTIFIER | HelpYou are not signed inSign in |
Project: Editra
Revision: 55436
Author: CJP
Date: 03 Sep 2008 13:03:57
Changes:no changes really. just some more documentation and comments.
Files:| ... | ...@@ -20,7 +20,7 @@ | |
| 20 | 20 | __revision__ = "$Revision$" |
| 21 | 21 | |
| 22 | 22 | #-------------------------------------------------------------------------# |
| 23 | # Dependencies | |
| 23 | # Imports | |
| 24 | 24 | import re |
| 25 | 25 | import wx, wx.stc |
| 26 | 26 | |
| ... | ...@@ -30,7 +30,7 @@ | |
| 30 | 30 | import ed_stc |
| 31 | 31 | import ed_cmdbar |
| 32 | 32 | |
| 33 | # Vi command patterns | |
| 33 | # Vi command regex patterns | |
| 34 | 34 | VI_DCMD_RIGHT = '[bBcdeEGhHlLMwWy|{}$<>]' |
| 35 | 35 | VI_DOUBLE_P1 = re.compile('[cdy<>][0-9]*' + VI_DCMD_RIGHT) |
| 36 | 36 | VI_DOUBLE_P2 = re.compile('[0-9]*[cdy<>]' + VI_DCMD_RIGHT) |
| ... | ...@@ -39,6 +39,10 @@ | |
| 39 | 39 | NUM_PAT = re.compile('[0-9]*') |
| 40 | 40 | |
| 41 | 41 | #-------------------------------------------------------------------------# |
| 42 | # Use this base class to derive any new keyhandlers from. The keyhandler is | |
| 43 | # called upon by the active buffer when ever a key press event happens. The | |
| 44 | # handler then has the responsibility of deciding what to do with the key. | |
| 45 | # | |
| 42 | 46 | class KeyHandler: |
| 43 | 47 | """KeyHandler base class""" |
| 44 | 48 | def __init__(self, stc): |
| ... | ...@@ -85,6 +89,7 @@ | |
| 85 | 89 | return False |
| 86 | 90 | |
| 87 | 91 | #-------------------------------------------------------------------------# |
| 92 | ||
| 88 | 93 | class ViKeyHandler(KeyHandler): |
| 89 | 94 | """Defines a key handler for Vi emulation |
| 90 | 95 | @summary: Handles keypresses according to Vi emulation. |
| ... | ...@@ -98,10 +103,15 @@ | |
| 98 | 103 | |
| 99 | 104 | def __init__(self, stc): |
| 100 | 105 | KeyHandler.__init__(self, stc) |
| 101 | self.SetMode(ViKeyHandler.INSERT) | |
| 106 | ||
| 107 | # Attributes | |
| 108 | self.mode = 0 | |
| 102 | 109 | self.last = u'' |
| 103 | 110 | self.cmdcache = u'' |
| 104 | 111 | |
| 112 | # Use Insert mode by default | |
| 113 | self.SetMode(ViKeyHandler.INSERT) | |
| 114 | ||
| 105 | 115 | def ClearMode(self): |
| 106 | 116 | """Clear the mode back to default input mode""" |
| 107 | 117 | self.stc.SetCaretWidth(1) |
| ... | ...@@ -125,6 +135,8 @@ | |
| 125 | 135 | elif self.mode == ViKeyHandler.INSERT: |
| 126 | 136 | self.stc.SetCaretWidth(1) |
| 127 | 137 | msg = u'INSERT' |
| 138 | ||
| 139 | # Update status bar | |
| 128 | 140 | evt = ed_event.StatusEvent(ed_event.edEVT_STATUS, self.stc.GetId(), |
| 129 | 141 | msg, ed_glob.SB_BUFF) |
| 130 | 142 | wx.PostEvent(self.stc.GetTopLevelParent(), evt) |
| ... | ...@@ -169,16 +181,22 @@ | |
| 169 | 181 | # Add key to cache |
| 170 | 182 | self.cmdcache = self.cmdcache + unichr(key_code) |
| 171 | 183 | |
| 184 | # Don't process key if the cache is empty | |
| 172 | 185 | if not len(self.cmdcache): |
| 173 | 186 | return False |
| 174 | 187 | |
| 188 | # Check for repeat last action command | |
| 175 | 189 | if self.cmdcache != u'.': |
| 176 | 190 | cmd = self.cmdcache |
| 177 | 191 | else: |
| 178 | 192 | cmd = self.last |
| 193 | ||
| 194 | # Gather common needed data | |
| 179 | 195 | cpos = self.stc.GetCurrentPos() |
| 180 | 196 | cline = self.stc.LineFromPosition(cpos) |
| 181 | 197 | mw = self.stc.GetTopLevelParent() |
| 198 | ||
| 199 | # Check for change from NORMAL mode to Command mode | |
| 182 | 200 | if u':' in cmd: |
| 183 | 201 | self.cmdcache = u'' |
| 184 | 202 | mw.ShowCommandCtrl(ed_cmdbar.ID_CMD_CTRL) |
| ... | ...@@ -208,11 +226,14 @@ | |
| 208 | 226 | if mw is not None: |
| 209 | 227 | mw.ShowCommandCtrl(ed_cmdbar.ID_SEARCH_CTRL) |
| 210 | 228 | |
| 229 | # Return to insert mode | |
| 211 | 230 | if cmd in u'aAiI': |
| 212 | 231 | self.SetMode(ViKeyHandler.INSERT) |
| 213 | 232 | |
| 233 | # Save last command and clear cache | |
| 214 | 234 | self.last = cmd |
| 215 | 235 | self.cmdcache = u'' |
| 236 | ||
| 216 | 237 | # Repeatable 1 key commands |
| 217 | 238 | elif re.match(VI_SINGLE_REPEAT, cmd): |
| 218 | 239 | rcmd = cmd[-1] |
| ... | ...@@ -246,13 +267,17 @@ | |
| 246 | 267 | u'}' : self.stc.ParaDown, |
| 247 | 268 | u'~' : self.stc.InvertCase } |
| 248 | 269 | |
| 270 | # Command is a Put command | |
| 249 | 271 | if rcmd in u'pP': |
| 250 | 272 | success = False |
| 251 | 273 | newline = False |
| 274 | # Check the clipboard | |
| 252 | 275 | if wx.TheClipboard.Open(): |
| 253 | 276 | td = wx.TextDataObject() |
| 254 | 277 | success = wx.TheClipboard.GetData(td) |
| 255 | 278 | wx.TheClipboard.Close() |
| 279 | ||
| 280 | # We got the text from the clipboard so put it in the buffer | |
| 256 | 281 | if success: |
| 257 | 282 | text = td.GetText() |
| 258 | 283 | if text[-1] == '\n': |
| ... | ...@@ -288,6 +313,7 @@ | |
| 288 | 313 | elif rcmd == u'O': |
| 289 | 314 | kargs['before'] = True |
| 290 | 315 | |
| 316 | # Start an undo action so all changes can be rolled back at once | |
| 291 | 317 | self.stc.BeginUndoAction() |
| 292 | 318 | if rcmd in u'CD': # Cut line right |
| 293 | 319 | self.stc.SetSelection(cpos, |
| ... | ...@@ -300,14 +326,18 @@ | |
| 300 | 326 | self.stc.SetTargetEnd(self.stc.PositionFromLine(cline + repeat - 1)) |
| 301 | 327 | self.stc.LinesJoin() |
| 302 | 328 | elif rcmd == u'G': |
| 329 | # Goto line or to end depending on context | |
| 303 | 330 | if repeat == 1 and '1' not in cmd: |
| 304 | 331 | repeat = self.stc.GetLineCount() |
| 305 | 332 | self.stc.GotoLine(repeat - 1) |
| 306 | 333 | elif rcmd == u'+': |
| 334 | # Goto indent position at x lines from current line | |
| 307 | 335 | self.stc.GotoIndentPos(cline + repeat) |
| 308 | 336 | elif rcmd == u'-': |
| 337 | # Goto indent position at x lines before current line | |
| 309 | 338 | self.stc.GotoIndentPos(cline - repeat) |
| 310 | 339 | elif rcmd == u'|': |
| 340 | # Goto column number at current line | |
| 311 | 341 | self.stc.GotoColumn(repeat - 1) |
| 312 | 342 | else: |
| 313 | 343 | if not cmd_map.has_key(rcmd): |
| ... | ...@@ -315,6 +345,8 @@ | |
| 315 | 345 | run = cmd_map[rcmd] |
| 316 | 346 | for count in xrange(repeat): |
| 317 | 347 | run(*args, **kargs) |
| 348 | ||
| 349 | # Do a Put command that is to be repeated | |
| 318 | 350 | if rcmd == u'p': |
| 319 | 351 | if newline: |
| 320 | 352 | self.stc.GotoIndentPos(cline + repeat) |
| ... | ...@@ -330,16 +362,23 @@ | |
| 330 | 362 | elif rcmd in u'CoOs': |
| 331 | 363 | self.SetMode(ViKeyHandler.INSERT) |
| 332 | 364 | self.stc.EndUndoAction() |
| 365 | ||
| 366 | # Save this action and clear command cache | |
| 333 | 367 | self.last = cmd |
| 334 | 368 | self.cmdcache = u'' |
| 369 | ||
| 335 | 370 | # 2 key commands |
| 336 | 371 | elif re.match(VI_DOUBLE_P1, cmd) or \ |
| 337 | 372 | re.match(VI_DOUBLE_P2, cmd) or \ |
| 338 | 373 | re.match(re.compile('[cdy]0'), cmd): |
| 374 | ||
| 375 | # Handle repetitions | |
| 339 | 376 | if re.match(re.compile('[cdy]0'), cmd): |
| 340 | 377 | rcmd = cmd |
| 341 | 378 | else: |
| 342 | 379 | rcmd = re.sub(NUM_PAT, u'', cmd) |
| 380 | ||
| 381 | # Get the number of repetitions from the command string | |
| 343 | 382 | repeat = re.subn(re.compile(VI_DCMD_RIGHT), u'', cmd, 2)[0] |
| 344 | 383 | if repeat == u'': |
| 345 | 384 | repeat = 1 |
| ... | ...@@ -365,14 +404,18 @@ | |
| 365 | 404 | u'{' : self.stc.ParaUpExtend, |
| 366 | 405 | u'}' : self.stc.ParaDownExtend} |
| 367 | 406 | |
| 407 | # Select to end of line | |
| 368 | 408 | if u'$' in rcmd: |
| 369 | 409 | pos = self.stc.GetLineEndPosition(cline + repeat - \ |
| 370 | 410 | len(self.stc.GetEOLChar())) |
| 371 | 411 | self.stc.SetCurrentPos(pos) |
| 372 | 412 | elif u'G' in rcmd: |
| 373 | if repeat == 0: # invalid cmd | |
| 413 | # Check if command is valid | |
| 414 | if repeat == 0: | |
| 374 | 415 | self.cmdcache = u'' |
| 375 | 416 | return True |
| 417 | ||
| 418 | # Select to end of file | |
| 376 | 419 | if repeat == 1 and u'1' not in cmd: # Default eof |
| 377 | 420 | self.stc.SetAnchor(self.stc.GetLineEndPosition(cline - 1)) |
| 378 | 421 | repeat = self.stc.GetLength() |
| ... | ...@@ -395,6 +438,7 @@ | |
| 395 | 438 | lline = self.stc.GetLastVisibleLine() |
| 396 | 439 | |
| 397 | 440 | if u'M' in rcmd: |
| 441 | # Get the line in middle of visible lines | |
| 398 | 442 | repeat = self.stc.GetMiddleVisibleLine() + 1 |
| 399 | 443 | elif fline + repeat > lline: |
| 400 | 444 | repeat = lline |
| ... | ...@@ -402,9 +446,11 @@ | |
| 402 | 446 | repeat = fline + repeat |
| 403 | 447 | |
| 404 | 448 | if repeat > cline: |
| 449 | # Move selection lines after middle line | |
| 405 | 450 | self.stc.SetAnchor(self.stc.PositionFromLine(cline)) |
| 406 | 451 | self.stc.SetCurrentPos(self.stc.PositionFromLine(repeat)) |
| 407 | 452 | else: |
| 453 | # Move select lines before middle line | |
| 408 | 454 | self.stc.SetAnchor(self.stc.PositionFromLine(repeat - 1)) |
| 409 | 455 | self.stc.SetCurrentPos(self.stc.PositionFromLine(cline + 1)) |
| 410 | 456 | elif u'L' in rcmd: |
| ... | ...@@ -432,27 +478,36 @@ | |
| 432 | 478 | for x in xrange(repeat): |
| 433 | 479 | doit() |
| 434 | 480 | |
| 481 | # Begin Undo action so all changes can be rolled back in one undo | |
| 435 | 482 | self.stc.BeginUndoAction() |
| 436 | 483 | if re.match(re.compile('c|c' + VI_DCMD_RIGHT), rcmd): |
| 484 | # Cut to selection and enter insert mode | |
| 437 | 485 | if rcmd == u'cc': |
| 438 | 486 | self.stc.SetSelectionEnd(self.stc.GetSelectionEnd() - \ |
| 439 | 487 | len(self.stc.GetEOLChar())) |
| 440 | 488 | self.stc.Cut() |
| 441 | 489 | self.SetMode(ViKeyHandler.INSERT) |
| 442 | 490 | elif re.match(re.compile('d|d' + VI_DCMD_RIGHT), rcmd): |
| 491 | # Cut selection and stay in normal mode | |
| 443 | 492 | self.stc.Cut() |
| 444 | 493 | elif re.match(re.compile('y|y' + VI_DCMD_RIGHT), rcmd): |
| 494 | # Copy selection | |
| 445 | 495 | self.stc.Copy() |
| 446 | 496 | self.stc.GotoPos(cpos) |
| 447 | 497 | elif rcmd == u'<<': |
| 498 | # Unindent selection | |
| 448 | 499 | self.stc.BackTab() |
| 449 | 500 | elif rcmd == u'>>': |
| 501 | # Indent selection | |
| 450 | 502 | self.stc.Tab() |
| 451 | 503 | else: |
| 452 | 504 | pass |
| 453 | 505 | self.stc.EndUndoAction() |
| 506 | ||
| 454 | 507 | if rcmd in '<<>>' or rcmd[-1] == u'G': |
| 455 | 508 | self.stc.GotoIndentPos(cline) |
| 509 | ||
| 510 | # Save the completed command and clear cache | |
| 456 | 511 | self.last = cmd |
| 457 | 512 | self.cmdcache = u'' |
| 458 | 513 | elif re.match(VI_GCMDS, cmd): |