#@+leo-ver=4-thin
#@+node:mork.20041030164547:@thin temacs.py
'''temacs is a binding module for the Tkinter Text widget.
Using the setBufferStrokes def will bind callbacks to the widget.'''
#@@language python
#@@tabwidth -4
__version__ = ".55"
#@<< version history >>
#@+node:mork.20041101100635:<<version history>>
#@+at
#
# .5
# This was a fairly major shift for temacs.
# -- Changed structure from pure functional to Object Oriented. Emacs is
# the central class in the temacs package now.
# The changes wrought by this are quite extensive.
# -- worked on complicated control logic, turned some parts into Objects
# that are state Handlers and Managers
# -- fixed a bug in block indentation. If the first line was blank it
# throw an Exception. It now finds the first text line.
# -- added the ability to add extensions. see 'how to write an Emacs
# extension' section. Also look at exampleTemacsExtension.py
# for a simple example as to how this works.
# -- fixed control-left control-right up so they do what Emacs does. This
# has ramifications for delete previous word as well,
# since that command relies on the control-left command to do its work.
# -- added the ability to change the keystrokes via the
# reconfigureKeyStroke method. This method is largely untested.
# -- last count: at around 204 keystrokes and commands( note some commands
# and keystrokes are the same,
# just different ways of accesing the functionality.
# -- enhanced incremental search so that if the search doesnt find anything
# it will start again either at the top or bottom, depending
# on which direction it is going. This is a nice little enhancement.
# -- enhanced Tabing with alt-x, so that the user can cycle through the
# matches. Added Tracker class to accomplish this.
# This will speed up the use of the Alt-x commands and expose
# functionality that is hard for a user to remember by keystroke.
# -- added Control-x and regular keystroke commands to Alt-x commands. Ive
# focused on the ones Ive found most usefull. This might be
# the best way to access rectangle functionality and registers.
# -- Created a better organized Outline. There are several organizing
# nodes now. Its easier to find things when looking for them.
# -- Added killing append to system clipboard. The clipboard gets set with
# every kill. Control - y will return the fresh clipboard kill as well as
# Alt-y. This will be very nice to have.
# -- Added ability to test standalone. Just type: python temacs.py and a
# simple Editor will appear.
# -- New commands and keystrokes:
# Control-j ( insert newline and tab )
# added goto-char
# added set-fill-column ( Control-x f )
# added center-line ( Alt- s )
# added center-region ( see node 'fill column and centering' to see
# what these do )
# ( these buffer ops have to be configured so the Emacs instance knows
# what is a 'buffer' in the environment,
# see 'buffer recognition and alterers' node )
# append-to-buffer
# prepend-to-buffer
# copy-to-buffer
# insert-buffer
# list-buffer ( aka Control-x Control-b )
# switch-to-buffer ( aka Control-x b )
# kill-buffer ( aka Control-x k )
# rename-buffer
#
#
# 0.51 EKR: Minor stylistic changes.
#
# 0.55:
# added:
# Control-z or 'iconify-or-deiconfify-frame'
# Control-x Esc Esc - executes last Alt-x command( repeat-complex-command
# )
# Control-x Control-c shutdown code, as well as a replacement hook if
# configured to do so.
# re-search-forward, re-search-backward - simple Alt-x regular expression
# commands
# Control-Alt-s, Control-Alt-r - regular expression cousins of incremental
# search( which makes me think that I need to change isearch to python based
# searches instead of the Tcl way..
# diff - does a diff on 2 files and adds it as a buffer
# what-line
# keep-lines and flush-lines, two fun new text manipulation commands!(see
# help text )
# make-directory and remove-directory, two commands that remove and add
# directories.
# delete-file - removes a file
# search-forward search-backward, searchs backward and forward for a word,
# non-incrementally. Accessed by Conrtrol-s Enter and Control-r
# word-search-forward and word-search-backward, incredible! You search
# for a group of words ignoring punctuation. This is mighty stuff, dont know
# if Ill use it, but I like what I see.
# replace-regex - like replace-string but uses a python regular expression
# for the match.
# query-replace-regex( Control-Alt-% ) -like query-replace but with a
# python regular expression
# Esc Esc :, Alt-:, eval-expression - these evaluate a Python expression
# in the minibuffer and puts the value in the current buffer. This I think is
# different than what Emacs does, but I think it makes the value more
# accessible if its in the current buffer. Nice little calculator too.
# tabify, untabify - turns spaces to tabs and tabs into spaces( current
# does it on 4 spaces to one tab ).
# indent-relative - a very nice command that indents from the insert point
# until it matches the indentation of a word in the above line.
# changed:
# replace-string command now will operate on a selection if there is one.
# Also the function now uses string functionality to replace the
# strings instead of using the Tk Text widget to do the job.
# dynamic expansion now will expand with the '-' character, which helps
# greatly in some cases. Alot of work for a what will hopefully be a long
# term gain. Also will now use quoted strings as actual completion targets,
# thank goodness.
# fixed:
# sort-lines will now clear its state after sorting the lines.
# Alt-!(shell-command, Alt-|(shell-command-on-region) --now temacs allows
# one to execute shell commands. I dont see a shell being added to temacs, so
# thats one area where it will probably not stray.
# total 26 new commands added
# fixed up: sort-lines and its cousins, if nothing is selected the command
# is deactivated.
#@-at
#@-node:mork.20041101100635:<<version history>>
#@nl
#@<< documentation >>
#@+node:ekr.20041106101311:<< documentation >>
#@@nocolor
#@+others
#@+node:mork.20041101203748:How to write an Emacs extension
#@+at
# Emacs instances offer the user the ability to add functionality
# to itself. This is accomplished through the Emacs extendAltX method.
# Functions passed in should not be methods
# but just plain functions.
#
# An example:
# def burp( self, event ):
# print 'burp %s' % self #This will print info about the Emacs
# instance
# self.stopControlX( event ) #every extension should call this or the
# function will be called for each keystroke.
# #To be more precise, it should be called when
# the function has completely cycled through.
# ei.extendAltX( 'burp', burp ) #burp has been added as an Alt-x command and
# the burp function has become
# #a method of the Emacs instance. self, will
# now reflect this.
#
# accessing it through the Alt-X interface will be done like so
# Alt-x
# burp ( Hit return , alternatively the user could type b and hit the tab
# button )
#
# Each function/method will be called with two parameters:
# self -- which is the Emacs instance
# event -- which is an Tkinter Event instance.
# self gives the extension writer the ability to access the Emacs intances
# functionality
# event gives the user the ability to access the Text widget that the
# Emacs instance is bound to.
# the preferred way to do so is like this:
# tbuffer = event.widget
#@-at
#@nonl
#@-node:mork.20041101203748:How to write an Emacs extension
#@+node:mork.20041102081834:Coding convenions
#@+at
#
# tbuffer - a Tkinter Text widget. Would be called buffer, but this shadows a
# Python builin. This is the widget carried
# by the events in the Emacs instancs. Can be accessed like so 'event.widget'
# svar - a Tkinter StringVar widget. This should hold what the minibuffer is
# showing currently. Can
# be acquired by 'self.getSvarLabel'.
#
#
#
#@-at
#@-node:mork.20041102081834:Coding convenions
#@+node:mork.20041102082911:Known bugs
#@+at
#
# .5
#
# - control-u seems kinda flaky. Will enhance in the next iteration and make
# less flaky. :)
# - digit-arguments seem pretty flaky as well.
# --- These are no longer flaky. A simple change to calling
# self.keyboardQuit, has eliminated the flakiness Ive seen. :)
# This was centered on using a command that wasnt a commadn like typing
# 99a, made it burp! You can also see the commands
# as they are done in the Editor. For example 'Control-u 99 a' will type
# 'a' 99 times in the editor. Or
# 'Control-u 99 Control-_' will undo the last 99 changes, thats if the
# Emacs instance has been configure with an undoer.
#@-at
#@nonl
#@-node:mork.20041102082911:Known bugs
#@+node:mork.20041102103822:Future directions
#@+at
#
# 1. Continue adding the keystroke command names to the Alt-x mechanism. Much
# of this has already been done.
# 2. Maybe make it possible for the user to add state to the MC_StateManager
# instance. This could allow the extension writer
# to create specific state based extension functions. They may already be
# able to do this.
# 3. When python 2.4 is official, look at subprocess module and decide if it
# can be used to run exterior commands. Pythons current
# cross platform process commands, dont seem too cross platform at this
# point. subprocess hopefully will fix this.
# 4. Continue migrating statefull commands to the MC_StateManager class.
# 5. Add ability for a user to learn the keystroke for a command. The Help
# Text should be considered a definitive source of
# information, but it may be quicker for the user to just ask. This will be
# accomplished by adding the 'where-is' command or
# 'Control-h w'. Not essential at this point, and will be done when we are
# entering a polish iteration.
# 6. Maybe add the ability for the user to evaluate Python expressions.
# Vanilla Emacs has the ability to do something with
# Lisp expressions, so it may make sense to do this with Python since Python
# is what this is built out of.
# 7. Maybe add Emacs variables for the commands. Ive noticed that you can set
# Emac variables to change some of the behavior
# in subtle ways. A dictionary should be used to implement this, adding 1000
# attributes to the Emacs class doesnt seem like a good idea.
# 8 Maybe add local abbreviations 'Control-x a i l'
#@-at
#@nonl
#@-node:mork.20041102103822:Future directions
#@+node:mork.20041104095745:A Note on Alt-X
#@+at
# Alt-x is the mechanism by which the user should be able to access any
# command in the Emacs instance.
# The first steps in developing temacs was focused on the keystrokes. Though
# in reality the keystrokes
# are just ways to access the commands.
#
# To initiate a command type Alt-x
# Start typing the command name
# Press Tab. If the command does not come up, continue pressing Tab.
# If you placed the correct prefix in the minibuffer, eventually the command
# will appear.
#
#
# This will help a user to quickly cycle through commands and select the one
# they want, even if they can somewhat remember what
# the spelling is.
#@-at
#@nonl
#@-node:mork.20041104095745:A Note on Alt-X
#@+node:mork.20041122151944:A Note on the volume of methods
#@+at
# originally when this project started it was not envisioned that there would
# be that many emacs like commands and stuff implemented.
# But then things changed, it grew. At one point there were too many
# functions for the module to be flexible and understandable anymore.
#
# The first reaction in the development was to decompose the pure module
# approach to an object approach. This has helped immensely in
# making temacs more manageable. But, an Emacs instance now has over 200+
# methods in it. If it continues to grow, there may be
# the need to decompose the families of methods into their own objects. This
# could have two benefits:
# 1. More intellectually managable.
# 2. Swapable functionality. Though its possible to do so now with python,
# this could be made much easier by having all
# calls to a certain family be made through the __call__ operator. Then
# swaping could be simply done by changing the object
# the call is made to.
#
#
# We will see if this approach may be taken. At this point I can say for
# certain that the original pure functional design was a mistake, but one that
# was correctable by using Leo and pychecker. Without these 2 tools, I think
# it may have been better to start over from scratch.
#@-at
#@-node:mork.20041122151944:A Note on the volume of methods
#@+node:mork.20041126091717:plans for .7
#@+at
#
# I believe in .7 the transition from one big Emacs object to an Emacs object
# composed of many method-family objects
# will begin. This may be as a big as a transition as the change from the
# flat module structure to the Emacs class based
# structure. The .6 cycle Ill reserve for improving the functionality and
# documentation. The current command crop may be
# froze in that cycle.
#@-at
#@nonl
#@-node:mork.20041126091717:plans for .7
#@+node:mork.20041123150836:the master command is the center of an Emacs instance
#@+at
#
# just a short note to anyone, including myself, that is working on temacs.
# Currently all( well all the ones that we have registered interest in ) key
# events get
# routed through:
#
# def masterCommand( self, event, method , stroke):
#
#
# to understand the flow of the Emacs class, you need to understand this
# method. Everything goes through it, there are no sidecuts or anything.
# This offers the implementor complete control over what happens, and for the
# stateful commands it is essential to
# keep states from being corrupted.
#
#
# dont mess with this method lightly.
#@-at
#@-node:mork.20041123150836:the master command is the center of an Emacs instance
#@+node:mork.20041122152311:adding stateful commands to temacs
#@+at
# Ive noticed a general strategy that works for adding commands that need
# state to develop.
#
# 1. Create a start method. This sets the mcStateManager into a specific
# state
# 2. Create a process method. This watches events as they happen in the state
# 3. Create endpoint methods. These perform the final steps in processing the
# stateful command.
#
#
# This general strategy works well so far. A whole family of methods can be
# created in this manner. Steps 1 and 2
# could be combined but at a cost of more complexity, so Id recommend keeping
# them separate.
#@-at
#@-node:mork.20041122152311:adding stateful commands to temacs
#@+node:mork.20041123150144:how to mix python regular expressions and the Text widget
#@+at
# Using python regular expressions and the Text widget may seem difficult but
# in reality it is very easy.
# A simple formula:
# 1. get the text you are interested in from the Text widget.
# 2. Do a python regex on it, get the start value from the match object:
# match.start()
# 3. This gives you the position in the text widget where the regex matched.
# Change the 'insert' point
# in the Text like so:
#
# tbuffer.mark_set( 'insert', 'insert +%sc' % match.start() )
#
#
# this will change the insert point to where the match started. Since you can
# move forward in the Text widget
# by the character amount, bridging python regexes and Text is a simple
# operation.
# Need to go after the match, just use
# match.end() instead of match.start().
#
# I puzzled over this for awhile, so this note is a reminder that it is easy.
# See the implementation for query-replace-regex for
# an example. Doing this with just plain string can follow a similar pattern.
#
#@-at
#@@c
#@nonl
#@-node:mork.20041123150144:how to mix python regular expressions and the Text widget
#@-others
#@nonl
#@-node:ekr.20041106101311:<< documentation >>
#@nl
#@<< imports >>
#@+node:mork.20041030164547.1:<< imports >>
# pretty low level imports. These may be all the imports the module needs
import leoGlobals as g # ekr
import Tkinter
import string
import weakref
import new
import sys
import re
import os
#@-node:mork.20041030164547.1:<< imports >>
#@nl
#@+others
#@+node:mork.20041104102456:Emacs helper classes
#@+others
#@+node:mork.20041031131847:class ControlXHandler
class ControlXHandler:
'''The ControlXHandler manages how the Control-X based commands operate on the
Emacs instance.'''
#@ @+others
#@+node:mork.20041031162953:__init__
def __init__( self, emacs ):
self.emacs = emacs
self.previous = []
self.rect_commands = {
'o': emacs.openRectangle,
'c': emacs.clearRectangle,
't': emacs.stringRectangle,
'y': emacs.yankRectangle,
'd': emacs.deleteRectangle,
'k': emacs.killRectangle,
'r': emacs.activateRectangleMethods,
}
self.variety_commands = {
'period': emacs.setFillPrefix,
'parenleft': emacs.startKBDMacro,
'parenright' : emacs.stopKBDMacro,
'semicolon': emacs.setCommentColumn,
'Tab': emacs.tabIndentRegion,
'u': lambda event: emacs.doUndo( event, 2 ),
'equal': emacs.lineNumber,
'h': emacs.selectAll,
'f': emacs.setFillColumn,
'b': lambda event, which = 'switch-to-buffer': emacs.setInBufferMode( event, which ),
'k': lambda event, which = 'kill-buffer': emacs.setInBufferMode( event, which ),
}
self.abbreviationDispatch = {
'a': lambda event: emacs.abbreviationDispatch( event, 1 ),
'a i': lambda event: emacs.abbreviationDispatch( event, 2 ),
}
self.register_commands ={
1: emacs.setNextRegister,
2: emacs.executeRegister,
}
#@-node:mork.20041031162953:__init__
#@+node:mork.20041031132342:__call__
def __call__( self, event , stroke ):
self.previous.insert( 0, event.keysym )
emacs = self.emacs
if len( self.previous ) > 10: self.previous.pop()
if stroke in ('<Key>', '<Escape>' ):
return self.processKey( event )
if stroke in emacs.xcommands:
emacs.xcommands[ stroke ]( event )
if stroke != '<Control-b>': emacs.keyboardQuit( event )
return 'break'
#@nonl
#@-node:mork.20041031132342:__call__
#@+node:mork.20041031133146:processKey
def processKey( self, event ):
emacs = self.emacs
previous = self.previous
if event.keysym in ( 'Shift_L', 'Shift_R' ):
return
if emacs.sRect:
return emacs.stringRectangle( event )
if ( event.keysym == 'r' and emacs.rectanglemode == 0 ) and not emacs.registermode:
return self.processRectangle( event )
elif self.rect_commands.has_key( event.keysym ) and emacs.rectanglemode == 1:
return self.processRectangle( event )
if self.register_commands.has_key( emacs.registermode ):
self.register_commands[ emacs.registermode ]( event )
return 'break'
if self.variety_commands.has_key( event.keysym ):
emacs.stopControlX( event )
return self.variety_commands[ event.keysym ]( event )
#if emacs.sRect:
# return emacs.stringRectangle( event )
# #return 'break'
if event.keysym in ( 'a', 'i' , 'e'):
if self.processAbbreviation( event ): return 'break'
if event.keysym == 'g':
svar, label = emacs.getSvarLabel( event )
l = svar.get()
if self.abbreviationDispatch.has_key( l ):
emacs.stopControlX( event )
return self.abbreviationDispatch[ l ]( event )
#if l == 'a':
# emacs.stopControlX( event )
# return emacs.abbreviationDispatch( event, 1 )
#elif l == 'a i':
# emacs.stopControlX( event )
# return emacs.abbreviationDispatch( event, 2 )
if event.keysym == 'e':
emacs.stopControlX( event )
return emacs.executeLastMacro( event )
if event.keysym == 'x' and previous[ 1 ] not in ( 'Control_L', 'Control_R'):
event.keysym = 's'
emacs.setNextRegister( event )
return 'break'
if event.keysym == 'Escape':
if len( previous ) > 1:
if previous[ 1 ] == 'Escape':
return emacs.repeatComplexCommand( event )
#if event.keysym == 'r':
# return emacs.activateRectangleMethods( event )
#if self.rect_commands.has_key( event.keysym ):# and emacs.registermode == 1:
# return self.processRectangle( event )
#if emacs.registermode == 1:
# emacs.setNextRegister( event )
# return 'break'
#elif emacs.registermode == 2:
# emacs.executeRegister( event )
# return 'break'
#if self.register_commands.has_key( emacs.registermode ):
# print 'register commands'
# self.register_commands[ emacs.registermode ]( event )
# return 'break'
#if event.keysym == 'r':
# return emacs.activateRectangleMethods( event )
# emacs.registermode = 1
# svar = emacs.svars[ event.widget ]
# svar.set( 'C - x r' )
# return 'break'
#if event.keysym== 'h':
# emacs.stopControlX( event )
# event.widget.tag_add( 'sel', '1.0', 'end' )
#tag_add( 'sel', '1.0', 'end' ) return 'break'
#if event.keysym == 'equal':
# emacs.lineNumber( event )
# return 'break'
#if event.keysym == 'u':
# emacs.stopControlX( event )
# return emacs.doUndo( event, 2 )
#@-node:mork.20041031133146:processKey
#@+node:mork.20041031134709:processRectangle
def processRectangle( self, event ):
self.rect_commands[ event.keysym ]( event )
return 'break'
#if event.keysym == 'o':
# emacs.openRectangle( event )
# return 'break'
#if event.keysym == 'c':
# emacs.clearRectangle( event )
# return 'break'
#if event.keysym == 't':
# emacs.stringRectangle( event )
# return 'break'
#if event.keysym == 'y':
# emacs.yankRectangle( event )
# return 'break'
#if event.keysym == 'd':
# emacs.deleteRectangle( event )
# return 'break'
#if event.keysym == 'k':
# emacs.killRectangle( event )
# return 'break'
#@-node:mork.20041031134709:processRectangle
#@+node:mork.20041031135748:processAbbreviation
def processAbbreviation( self, event ):
emacs = self.emacs
svar, label = emacs.getSvarLabel( event )
if svar.get() != 'a' and event.keysym == 'a':
svar.set( 'a' )
return 'break'
elif svar.get() == 'a':
if event.char == 'i':
svar.set( 'a i' )
elif event.char == 'e':
emacs.stopControlX( event )
event.char = ''
emacs.expandAbbrev( event )
return 'break'
#@nonl
#@-node:mork.20041031135748:processAbbreviation
#@-others
#@-node:mork.20041031131847:class ControlXHandler
#@+node:mork.20041031145157:class MC_StateManager
class MC_StateManager:
'''MC_StateManager manages the state that the Emacs instance has entered and
routes key events to the right method, dependent upon the state in the MC_StateManager'''
#@ @+others
#@+node:mork.20041031162857:__init__
def __init__( self, emacs ):
self.emacs = emacs
self.state = None
self.states = {}
#@ <<statecommands>>
#@+node:mork.20041031150125:<<statecommands>>
# EKR: used only below.
def eA( event ):
if self.emacs.expandAbbrev( event ) :
return 'break'
self.stateCommands = { #1 == one parameter, 2 == all
'uC': ( 2, emacs.universalDispatch ),
'controlx': ( 2, emacs.doControlX ),
'isearch':( 2, emacs.iSearch ),
'goto': ( 1, emacs.Goto ),
'zap': ( 1, emacs.zapTo ),
'howM': ( 1, emacs.howMany ),
'abbrevMode': ( 1, emacs.abbrevCommand1 ),
'altx': ( 1, emacs.doAlt_X ),
'qlisten': ( 1, emacs.masterQR ),
'rString': ( 1, emacs.replaceString ),
'negativeArg':( 2, emacs.negativeArgument ),
'abbrevOn': ( 1, eA ),
'set-fill-column': ( 1, emacs.setFillColumn ),
'chooseBuffer': ( 1, emacs.chooseBuffer ),
'renameBuffer': ( 1, emacs.renameBuffer ),
're_search': ( 1, emacs.re_search ),
'alterlines': ( 1, emacs.processLines ),
'make_directory': ( 1, emacs.makeDirectory ),
'remove_directory': ( 1, emacs.removeDirectory ),
'delete_file': ( 1, emacs.deleteFile ),
'nonincr-search': ( 2, emacs.nonincrSearch ),
'word-search':( 1, emacs.wordSearch ),
'last-altx': ( 1, emacs.executeLastAltX ),
'escape': ( 1, emacs.watchEscape ),
'subprocess': ( 1, emacs.subprocesser ),
}
#@nonl
#@-node:mork.20041031150125:<<statecommands>>
#@nl
#@nonl
#@-node:mork.20041031162857:__init__
#@+node:mork.20041031162857.1:setState
def setState( self, state, value ):
self.state = state
self.states[ state ] = value
#@nonl
#@-node:mork.20041031162857.1:setState
#@+node:mork.20041031162857.2:getState
def getState( self, state ):
return self.states.get(state,False)
#@nonl
#@-node:mork.20041031162857.2:getState
#@+node:mork.20041031162857.3:hasState
def hasState( self ):
if self.state:
return self.states[ self.state ]
#@-node:mork.20041031162857.3:hasState
#@+node:mork.20041124094511:whichState
def whichState( self ):
return self.state
#@-node:mork.20041124094511:whichState
#@+node:mork.20041031162857.4:__call__
def __call__( self, *args ):
if self.state:
which = self.stateCommands[ self.state ]
# EKR: which[0] is a flag: 1 == one parameter, 2 == all
# EKR: which[1] is the function.
if which[ 0 ] == 1:
return which[ 1 ]( args[ 0 ] )
else:
return which[ 1 ]( *args )
#@-node:mork.20041031162857.4:__call__
#@+node:mork.20041031162857.5:clear
def clear( self ):
self.state = None
for z in self.states.keys():
self.states[ z ] = False
#@nonl
#@-node:mork.20041031162857.5:clear
#@-others
#@-node:mork.20041031145157:class MC_StateManager
#@+node:mork.20041101083527:class MC_KeyStrokeManager (hard-coded keystrokes)
class MC_KeyStrokeManager:
#@ @+others
#@+node:mork.20041101083527.1:__init__
def __init__( self, emacs ):
self.emacs = emacs
#@ <<keystrokes>>
#@+node:mork.20041101083527.2:<<keystrokes>> (hard-coded keystrokes)
self.keystrokes = {
'<Control-s>': ( 2, emacs.startIncremental ),
'<Control-r>': ( 2, emacs.startIncremental ),
'<Alt-g>': ( 1, emacs.startGoto ),
'<Alt-z>': ( 1, emacs.startZap ),
'<Alt-percent>': ( 1, emacs.masterQR ) ,
'<Control-Alt-w>': ( 1, lambda event: 'break' ),
}
#@nonl
#@-node:mork.20041101083527.2:<<keystrokes>> (hard-coded keystrokes)
#@nl
#@-node:mork.20041101083527.1:__init__
#@+node:mork.20041101084148:hasKeyStroke
def hasKeyStroke( self, stroke ):
return self.keystrokes.has_key( stroke )
#@nonl
#@-node:mork.20041101084148:hasKeyStroke
#@+node:mork.20041101084148.1:__call__
def __call__( self, event, stroke ):
kstroke = self.keystrokes[ stroke ]
if 0: # EKR: this would be better:
numberOfArgs,func = self.keystrokes[ stroke ]
if numberOfArgs == 1:
return func(event)
else:
return func(event,stroke)
# EKR: which[0] is the number of params.
# EKR: which[1] is the function.
if kstroke[ 0 ] == 1:
return kstroke[ 1 ]( event )
else:
return kstroke[ 1 ]( event, stroke )
#@nonl
#@-node:mork.20041101084148.1:__call__
#@-others
#@nonl
#@-node:mork.20041101083527:class MC_KeyStrokeManager (hard-coded keystrokes)
#@+node:mork.20041102131352:class Tracker
class Tracker:
'''A class designed to allow the user to cycle through a list
and to change the list as deemed appropiate.'''
#@ @+others
#@+node:mork.20041102131352.1:init
def __init__( self ):
self.tablist = []
self.prefix = None
self.ng = self._next()
#@nonl
#@-node:mork.20041102131352.1:init
#@+node:mork.20041102131352.2:setTabList
def setTabList( self, prefix, tlist ):
self.prefix = prefix
self.tablist = tlist
#@-node:mork.20041102131352.2:setTabList
#@+node:mork.20041102131352.3:_next
def _next( self ):
while 1:
tlist = self.tablist
if not tlist: yield ''
for z in self.tablist:
if tlist != self.tablist:
break
yield z
#@-node:mork.20041102131352.3:_next
#@+node:mork.20041102132710:next
def next( self ):
return self.ng.next()
#@-node:mork.20041102132710:next
#@+node:mork.20041102160313:clear
def clear( self ):
self.tablist = []
self.prefix = None
#@-node:mork.20041102160313:clear
#@-others
#@nonl
#@-node:mork.20041102131352:class Tracker
#@-others
#@-node:mork.20041104102456:Emacs helper classes
#@+node:mork.20041030165020:class Emacs
class Emacs:
'''The Emacs class binds to a Tkinter Text widget and adds Emac derived keystrokes and commands
to it.'''
Emacs_instances = weakref.WeakKeyDictionary()
global_killbuffer = []
global_registers = {}
lossage = [] ### EKR: list( ' ' * 100 )
#@ @+others
#@+node:mork.20041030165020.1:Emacs.__init__
def __init__( self , tbuffer = None , minibuffer = None, useGlobalKillbuffer = False, useGlobalRegisters = False):
'''Sets up Emacs instance.
If a Tkinter Text widget and Tkinter Label are passed in
via the tbuffer and minibuffer parameters, these are bound to.
Otherwise an explicit call to setBufferStrokes must be done.
useGlobalRegisters set to True indicates that the Emacs instance should use a class attribute that functions
as a global register.
useGlobalKillbuffer set to True indicates that the Emacs instances should use a class attribute that functions
as a global killbuffer.'''
self.mbuffers = {}
self.svars = {}
#self.isearch = False
self.tailEnds = {} #functions to execute at the end of many Emac methods. Configurable by environment.
self.undoers = {} #Emacs instance tracks undoers given to it.
self.store = {'rlist': [], 'stext': ''}
#macros
self.lastMacro = None
self.macs = []
self.macro = []
self.namedMacros = {}
self.macroing = False
self.dynaregex = re.compile( r'[%s%s\-_]+' %( string.ascii_letters, string.digits ) ) #for dynamic abbreviations
self.altx_history = []
self.keysymhistory = []
#This section sets up the buffer data structures
self.bufferListGetters = {}
self.bufferSetters = {}
self.bufferGotos = {}
self.bufferDeletes = {}
self.renameBuffers = {}
self.bufferDict = None
self.bufferTracker = Tracker()
self.bufferCommands = {
'append-to-buffer': self.appendToBuffer,
'prepend-to-buffer': self.prependToBuffer,
'copy-to-buffer': self.copyToBuffer,
'insert-buffer': self.insertToBuffer,
'switch-to-buffer': self.switchToBuffer,
'kill-buffer': self.killBuffer,
}
self.swapSpots = []
self.ccolumn = '0'
#self.howM = False
self.reset = False
if useGlobalKillbuffer:
self.killbuffer = Emacs.global_killbuffer
else:
self.killbuffer = []
self.kbiterator = self.iterateKillBuffer()
#self.controlx = False
self.csr = { '<Control-s>': 'for', '<Control-r>':'bak' }
self.pref = None
#self.zap = False
#self.goto = False
self.previousStroke = ''
if useGlobalRegisters:
self.registers = Emacs.global_registers
else:
self.registers = {}
#registers
self.regMeth = None
self.regMeths, self.regText = self.addRegisterItems()
#Abbreviations
self.abbrevMode = False
self.abbrevOn = False # determines if abbreviations are on for masterCommand and toggle abbreviations
self.abbrevs = {}
self.regXRpl = None # EKR: a generator: calling self.regXRpl.next() get the next value.
self.regXKey = None
self.fillPrefix = '' #for fill prefix functions
self.fillColumn = 70 #for line centering
self.registermode = False #for rectangles and registers
self.qQ = None
self.qR = None
#self.qlisten = False
#self.lqR = Tkinter.StringVar()
#self.lqR.set( 'Query with: ' ) # replaced with using the svar and self.mcStateManager
self.qgetQuery = False
#self.lqQ = Tkinter.StringVar()
#self.lqQ.set( 'Replace with:' )# replaced with using the svar and self.mcStateManager
self.qgetReplace = False
self.qrexecute = False
self.querytype = 'normal'
#self.rString = False
#These attributes are for replace-string and replace-regex
self._sString = ''
self._rpString = ''
self._useRegex = False
self.sRect = False #State indicating string rectangle. May be moved to MC_StateManager
self.krectangle = None #The kill rectangle
self.rectanglemode = 0 #Determines what state the rectangle system is in.
self.last_clipboard = None #For interacting with system clipboard.
self.negativeArg = False
self.negArgs = { '<Alt-c>': self.changePreviousWord,
'<Alt-u>' : self.changePreviousWord,
'<Alt-l>': self.changePreviousWord } #For negative argument functionality
#self.altx = False
#Alt-X commands.
self.doAltX = self.addAltXCommands()
self.axTabList = Tracker()
self.x_hasNumeric = [ 'sort-lines' , 'sort-fields']
#self.uC = False
#These attributes are for the universal command functionality.
self.uCstring = string.digits + '\b'
self.uCdict = { '<Alt-x>' : self.alt_X }
self.cbDict = self.addCallBackDict()# Creates callback dictionary, primarily used in the master command
self.xcommands = self.addXCommands() # Creates the X commands dictionary
self.cxHandler = ControlXHandler( self ) #Creates the handler for Control-x commands
self.mcStateManager = MC_StateManager( self ) #Manages state for the master command
self.kstrokeManager = MC_KeyStrokeManager( self ) #Manages some keystroke state for the master command.
self.shutdownhook = None #If this is set via setShutdownHook, it is executed instead of sys.exit when Control-x Control-c is fired
self.shuttingdown = False #indicates that the Emacs instance is shutting down and no work needs to be done.
if tbuffer and minibuffer:
self.setBufferStrokes( tbuffer, minibuffer )
#@-node:mork.20041030165020.1:Emacs.__init__
#@+node:mork.20041030164547.41:getHelpText
def getHelpText():
'''This returns a string that describes what all the
keystrokes do with a bound Text widget.'''
help_t = [ 'Buffer Keyboard Commands:',
'----------------------------------------\n',
'<Control-p>: move up one line',
'<Control-n>: move down one line',
'<Control-f>: move forward one char',
'<Conftol-b>: move backward one char',
'<Control-o>: insert newline',
'<Control-Alt-o> : insert newline and indent',
'<Control-j>: insert newline and tab',
'<Alt-<> : move to start of Buffer',
'<Alt- >' +' >: move to end of Buffer',
'<Control a>: move to start of line',
'<Control e> :move to end of line',
'<Alt-Up>: move to start of line',
'<Alt-Down>: move to end of line',
'<Alt b>: move one word backward',
'<Alt f> : move one word forward',
'<Control - Right Arrow>: move one word forward',
'<Control - Left Arrow>: move one word backwards',
'<Alt-m> : move to beginning of indentation',
'<Alt-g> : goto line number',
'<Control-v>: scroll forward one screen',
'<Alt-v>: scroll up one screen',
'<Alt-a>: move back one sentence',
'<Alt-e>: move forward one sentence',
'<Alt-}>: move forward one paragraph',
'<Alt-{>: move backwards one paragraph',
'<Alt-:> evaluate a Python expression in the minibuffer and insert the value in the current buffer',
'Esc Esc : evaluate a Python expression in the minibuffer and insert the value in the current buffer',
'<Control-x . >: set fill prefix',
'<Alt-q>: fill paragraph',
'<Alt-h>: select current or next paragraph',
'<Control-x Control-@>: pop global mark',
'<Control-u>: universal command, repeats the next command n times.',
'<Alt -n > : n is a number. Processes the next command n times.',
'<Control-x (>: start definition of kbd macro',
'<Control-x ) > : stop definition of kbd macro',
'<Control-x e : execute last macro defined',
'<Control-u Control-x ( >: execute last macro and edit',
'<Control-x Esc Esc >: execute last complex command( last Alt-x command',
'<Control-x Control-c >: save buffers kill Emacs',
'''<Control-x u > : advertised undo. This function utilizes the environments.
If the buffer is not configure explicitly, there is no operation.''',
'<Control-_>: advertised undo. See above',
'<Control-z>: iconfify frame',
'----------------------------------------\n',
'<Delete> : delete previous character',
'<Control d>: delete next character',
'<Control k> : delete from cursor to end of line. Text goes to kill buffer',
'<Alt d>: delete word. Word goes to kill buffer',
'<Alt Delete>: delete previous word. Word goes to kill buffer',
'<Alt k >: delete current sentence. Sentence goes to kill buffer',
'<Control x Delete>: delete previous sentence. Sentence goes to kill buffer',
'<Control y >: yank last deleted text segment from\n kill buffer and inserts it.',
'<Alt y >: cycle and yank through kill buffer.\n',
'<Alt z >: zap to typed letter. Text goes to kill buffer',
'<Alt-^ >: join this line to the previous one',
'<Alt-\ >: delete surrounding spaces',
'<Alt-s> >: center line in current fill column',
'<Control-Alt-w>: next kill is appended to kill buffer\n'
'----------------------------------------\n',
'<Alt c>: Capitalize the word the cursor is under.',
'<Alt u>: Uppercase the characters in the word.',
'<Alt l>: Lowercase the characters in the word.',
'----------------------------------------\n',
'<Alt t>: Mark word for word swapping. Marking a second\n word will swap this word with the first',
'<Control-t>: Swap characters',
'<Ctrl-@>: Begin marking region.',
'<Ctrl-W>: Kill marked region',
'<Alt-W>: Copy marked region',
'<Ctrl-x Ctrl-u>: uppercase a marked region',
'<Ctrl-x Ctrl-l>: lowercase a marked region',
'<Ctrl-x h>: mark entire buffer',
'<Alt-Ctrl-backslash>: indent region to indentation of line 1 of the region.',
'<Ctrl-x tab> : indent region by 1 tab',
'<Control-x Control-x> : swap point and mark',
'<Control-x semicolon>: set comment column',
'<Alt-semicolon>: indent to comment column',
'----------------------------------------\n',
'M-! cmd -- Run the shell command line cmd and display the output',
'M-| cmd -- Run the shell command line cmd with region contents as input',
'----------------------------------------\n',
'<Control-x a e>: Expand the abbrev before point (expand-abbrev). This is effective even when Abbrev mode is not enabled',
'<Control-x a g>: Define an abbreviation for previous word',
'<Control-x a i g>: Define a word as abbreviation for word before point, or in point',
'----------------------------------------\n',
'<Control s>: forward search, using pattern in Mini buffer.\n',
'<Control r>: backward search, using pattern in Mini buffer.\n' ,
'<Control s Enter>: search forward for a word, nonincremental\n',
'<Control r Enter>: search backward for a word, nonincremental\n',
'<Control s Enter Control w>: Search for words, ignoring details of punctuation',
'<Control r Enter Control w>: Search backward for words, ignoring details of punctuation',
'<Control-Alt s>: forward regular expression search, using pattern in Mini buffer\n',
'<Control-Alt r>: backward regular expression search, using pattern in Mini buffer\n',
'''<Alt-%>: begin query search/replace. n skips to next match. y changes current match.
q or Return exits. ! to replace all remaining matches with no more questions''',
'''<Control Alt %> begin regex search replace, like Alt-%''',
'<Alt-=>: count lines and characters in regions',
'<Alt-( >: insert parentheses()',
'<Alt-) >: move past close',
'<Control-x Control-t>: transpose lines.',
'<Control-x Control-o>: delete blank lines' ,
'<Control-x r s>: save region to register',
'<Control-x r i>: insert to buffer from register',
'<Control-x r +>: increment register',
'<Control-x r n>: insert number 0 to register',
'<Control-x r space > : point insert point to register',
'<Control-x r j > : jump to register',
'<Control-x x>: save region to register',
'<Control-x r r> : save rectangle to register',
'<Control-x r o>: open up rectangle',
'<Control-x r c> : clear rectangle',
'<Control-x r d> : delete rectangle',
'<Control-x r t> : replace rectangle with string',
'<Control-x r k> : kill rectangle',
'<Control-x r y> : yank rectangle',
'<Control-g> : keyboard quit\n',
'<Control-x = > : position of cursor',
'<Control-x . > : set fill prefix',
'<Control-x f > : set the fill column',
'<Control-x Control-b > : display the buffer list',
'<Control-x b > : switch to buffer',
'<Control-x k > : kill the specified buffer',
'----------------------------------------\n',
'<Alt - - Alt-l >: lowercase previous word',
'<Alt - - Alt-u>: uppercase previous word',
'<Alt - - Alt-c>: capitalise previous word',
'----------------------------------------\n',
'<Alt-/ >: dynamic expansion',
'<Control-Alt-/>: dynamic expansion. Expands to common prefix in buffer\n'
'----------------------------------------\n',
'Alt-x commands:\n',
'(Pressing Tab will result in auto completion of the options if an appropriate match is found',
'replace-string - replace string with string',
'replace-regex - replace python regular expression with string',
'append-to-register - append region to register',
'prepend-to-register - prepend region to register\n'
'sort-lines - sort selected lines',
'sort-columns - sort by selected columns',
'reverse-region - reverse selected lines',
'sort-fields - sort by fields',
'abbrev-mode - toggle abbrev mode on/off',
'kill-all-abbrevs - kill current abbreviations',
'expand-region-abbrevs - expand all abrevs in region',
'read-abbrev-file - read abbreviations from file',
'write-abbrev-file - write abbreviations to file',
'list-abbrevs - list abbrevs in minibuffer',
'fill-region-as-paragraph - treat region as one paragraph and add fill prefix',
'fill-region - fill paragraphs in region with fill prefix',
'close-rectangle - close whitespace rectangle',
'how-many - counts occurances of python regular expression',
'kill-paragraph - delete from cursor to end of paragraph',
'backward-kill-paragraph - delete from cursor to start of paragraph',
'backward-kill-sentence - delete from the cursor to the start of the sentence',
'name-last-kbd-macro - give the last kbd-macro a name',
'insert-keyboard-macro - save macros to file',
'load-file - load a macro file',
'kill-word - delete the word the cursor is on',
'kill-line - delete form the cursor to end of the line',
'kill-sentence - delete the sentence the cursor is on',
'kill-region - delete a marked region',
'yank - restore what you have deleted',
'backward-kill-word - delete previous word',
'backward-delete-char - delete previous character',
'delete-char - delete character under cursor' ,
'isearch-forward - start forward incremental search',
'isearch-backward - start backward incremental search',
'isearch-forward-regexp - start forward regular expression incremental search',
'isearch-backward-regexp - start backward return expression incremental search',
'capitalize-word - capitalize the current word',
'upcase-word - switch word to upper case',
'downcase-word - switch word to lower case',
'indent-region - indent region to first line in region',
'indent-rigidly - indent region by a tab',
'indent-relative - Indent from point to under an indentation point in the previous line',
'set-mark-command - mark the beginning or end of a region',
'kill-rectangle - kill the rectangle',
'delete-rectangle - delete the rectangle',
'yank-rectangle - yank the rectangle',
'open-rectangle - open the rectangle',
'clear-rectangle - clear the rectangle',
'copy-to-register - copy selection to register',
'insert-register - insert register into buffer',
'copy-rectangle-to-register - copy buffer rectangle to register',
'jump-to-register - jump to position in register',
'point-to-register - insert point into register',
'number-to-register - insert number into register',
'increment-register - increment number in register',
'view-register - view what register contains',
'beginning-of-line - move to the beginning of the line',
'end-of-line - move to the end of the line',
'beginning-of-buffer - move to the beginning of the buffer',
'end-of-buffer - move to the end of the buffer',
'newline-and-indent - insert a newline and tab',
'keyboard-quit - abort current command',
'iconify-or-deiconify-frame - iconfiy current frame',
'advertised-undo - undo the last operation',
'back-to-indentation - move to first non-blank character of line',
'delete-indentation - join this line to the previous one',
'view-lossage - see the last 100 characters typed',
'transpose-chars - transpose two letters',
'transpose-words - transpose two words',
'transpose-line - transpose two lines',
'flush-lines - delete lines that match regex',
'keep-lines - keep lines that only match regex',
'insert-file - insert file at current position',
'save-buffer - save file',
'split-line - split line at cursor. indent to column of cursor',
'upcase-region - Upper case region',
'downcase-region - lower case region',
'goto-line - goto a line in the buffer',
'what-line - display what line the cursor is on',
'goto-char - goto a char in the buffer',
'set-fill-column - sets the fill column',
'center-line - centers the current line within the fill column',
'center-region - centers the current region within the fill column',
'forward-char - move the cursor forward one char',
'backward-char - move the cursor backward one char',
'previous-line - move the cursor up one line',
'next-line - move the cursor down one line',
'universal-argument - Repeat the next command "n" times',
'digit-argument - Repeat the next command "n" times',
'set-fill-prefix - Sets the prefix from the insert point to the start of the line',
'scroll-up - scrolls up one screen',
'scroll-down - scrolls down one screen',
'append-to-buffer - Append region to a specified buffer',
'prepend-to-buffer - Prepend region to a specified buffer',
'copy-to-buffer - Copy region to a specified buffer, deleting the previous contents',
'insert-buffer - Insert the contents of a specified buffer into current buffer at point',
'list-buffers - Display the buffer list',
'switch-to-buffer - switch to a different buffer, if it does not exits, it is created.',
'kill-buffer - kill the specified buffer',
'rename-buffer - rename the buffer',
'query-replace - query buffer for pattern and replace it. The user will be asked for a pattern, and for text to replace the pattern with.',
'query-replace-regex - query buffer with regex and replace it. The user will be asked for a pattern, and for text to replace the regex matches with.',
'inverse-add-global-abbrev - add global abbreviation from previous word. Will ask user for word to expand to',
'expand-abbrev - Expand the abbrev before point. This is effective even when Abbrev mode is not enabled',
're-search-forward - do a python regular expression search forward',
're-search-backward - do a python regular expression search backward',
'diff - compares two files, displaying the differences in an Emacs buffer named *diff*',
'make-directory - create a new directory',
'remove-directory - remove an existing directory if its empty',
'delete-file - remove an existing file',
'search-forward - search forward for a word',
'search-backward - search backward for a word',
'word-search-forward - Search for words, ignoring details of punctuation.',
'word-search-backward - Search backward for words, ignoring details of punctuation',
'repeat-complex-command - repeat the last Alt-x command',
'eval-expression - evaluate a Python expression and put the value in the current buffer',
'tabify - turn the selected text\'s spaces into tabs',
'untabify - turn the selected text\'s tabs into spaces',
'shell-command -Run the shell command line cmd and display the output',
'shell-command-on-region -Run the shell command line cmd with region contents as input',
]
return '\n'.join( help_t )
getHelpText = staticmethod( getHelpText )
#@-node:mork.20041030164547.41:getHelpText
#@+node:mork.20041030164547.43:masterCommand
#self.controlx = False
#self.csr = { '<Control-s>': 'for', '<Control-r>':'bak' }
#self.pref = None
#self.zap = False
#self.goto = False
#self.previousStroke = ''
def masterCommand( self, event, method , stroke):
'''The masterCommand is the central routing method of the Emacs method.
All commands and keystrokes pass through here.'''
special = event.keysym in ('Control_L','Control_R','Alt_L','Alt-R','Shift_L','Shift_R')
inserted = not special or len(self.keysymhistory) == 0 or self.keysymhistory[0] != event.keysym
# Don't add multiple special characters to history.
if inserted:
self.keysymhistory.insert(0,event.keysym)
if len(event.char) > 0:
if len(Emacs.lossage) > 99: Emacs.lossage.pop()
Emacs.lossage.insert(0,event.char)
if 1: # traces
print event.keysym,stroke
g.trace(self.keysymhistory)
g.trace(Emacs.lossage)
if 0:
#@ << old insert code >>
#@+node:ekr.20050527112828:<< old insert code >>
Emacs.lossage.reverse()
Emacs.lossage.append( event.char ) #Then we add the new char. Hopefully this will keep Python from allocating a new array each time.
Emacs.lossage.reverse()
self.keysymhistory.reverse()
self.keysymhistory.append( event.keysym )
self.keysymhistory.reverse()
#@nonl
#@-node:ekr.20050527112828:<< old insert code >>
#@nl
if self.macroing:
if self.macroing == 2 and stroke != '<Control-x>':
return self.nameLastMacro( event )
elif self.macroing == 3 and stroke != '<Control-x>':
return self.getMacroName( event )
else:
self.recordKBDMacro( event, stroke )
if stroke == '<Control-g>':
self.previousStroke = stroke
return self.keyboardQuit( event )
if self.mcStateManager.hasState():
self.previousStroke = stroke
return self.mcStateManager( event, stroke ) # EKR: Invoke the __call__ method.
if self.kstrokeManager.hasKeyStroke( stroke ):
self.previousStroke = stroke
return self.kstrokeManager( event, stroke ) # EKR: Invoke the __call__ method.
#@ << old code >>
#@+node:ekr.20050527084754:<< old code >>
#if self.uC:
# self.previousStroke = stroke
# return self.universalDispatch( event, stroke )
#if self.controlx:
# self.previousStroke = stroke
# return self.doControlX( event, stroke )
#if stroke in ('<Control-s>', '<Control-r>' ):
# self.previousStroke = stroke
# return self.startIncremental( event, stroke )
#if self.isearch:
# return self.iSearch( event )
#if stroke == '<Alt-g>':
# self.previousStroke = stroke
# return self.startGoto( event )
#if self.goto:
# return self.Goto( event )
#if stroke == '<Alt-z>':
# self.previousStroke = stroke
# return self.startZap( event )
#if self.zap:
# return self.zapTo( event )
#@nonl
#@-node:ekr.20050527084754:<< old code >>
#@nl
if self.regXRpl: # EKR: a generator.
try:
self.regXKey = event.keysym
self.regXRpl.next() # EKR: next() may throw StopIteration.
finally:
return 'break'
#@ << old code 2 >>
#@+node:ekr.20050527084754.1:<< old code 2 >>
#if self.howM:
# return self.howMany( event )
#if self.abbrevMode:
# return self.abbrevCommand1( event )
#if self.altx:
# return self.doAlt_X( event )
#if stroke == '<Alt-percent>':
# self.previousStroke = stroke
# return self.masterQR( event )
#if self.qlisten:
# return self.masterQR( event )
#if self.rString:
# return self.replaceString( event )
#if self.negativeArg:
# return self.negativeArgument( event, stroke )
#if stroke == '<Control-Alt-w>':
# self.previousStroke = '<Control-Alt-w>'
# return 'break'
#@nonl
#@-node:ekr.20050527084754.1:<< old code 2 >>
#@nl
if self.abbrevOn:
if self.expandAbbrev( event ) :
return 'break'
if method:
rt = method( event )
self.previousStroke = stroke
return rt
#@nonl
#@-node:mork.20041030164547.43:masterCommand
#@+node:mork.20041102082023:keyboardQuit
def keyboardQuit( self, event ):
'''This method cleans the Emacs instance of state and ceases current operations.'''
return self.stopControlX( event )#This method will eventually contain the stopControlX code.
#@-node:mork.20041102082023:keyboardQuit
#@+node:mork.20041031182258:add command dictionary methods
#@+at
# These methods create the dispatch dictionarys that the
# Emacs instance uses to execute specific keystrokes and commands.
# Dont mess with it if you dont understand this section, without these
# dictionarys
# the Emacs system cant work.
#
#@-at
#@@c
#@+others
#@+node:mork.20041030183331:addCallBackDict (creates cbDict)
def addCallBackDict( self ):
'''This method adds a dictionary to the Emacs instance through which the masterCommand can
call the specified method.'''
cbDict = {
'Alt-less' : lambda event, spot = '1.0' : self.moveTo( event, spot ),
'Alt-greater': lambda event, spot = 'end' : self.moveTo( event, spot ),
'Control-Right': lambda event, way = 1: self.moveword( event, way ),
'Control-Left': lambda event, way = -1: self.moveword( event, way ),
'Control-a': lambda event, spot = 'insert linestart': self.moveTo( event, spot ),
'Control-e': lambda event, spot = 'insert lineend': self.moveTo( event, spot ),
'Alt-Up': lambda event, spot = 'insert linestart': self.moveTo( event, spot ),
'Alt-Down': lambda event, spot = 'insert lineend': self.moveTo( event, spot ),
'Alt-f': lambda event, way = 1: self.moveword( event, way ),
'Alt-b' : lambda event, way = -1: self.moveword( event, way ),
'Control-o': self.insertNewLine,
'Control-k': lambda event, frm = 'insert', to = 'insert lineend': self.kill( event, frm, to) ,
'Alt-d': lambda event, frm = 'insert wordstart', to = 'insert wordend': self.kill( event,frm, to ),
'Alt-Delete': lambda event: self.deletelastWord( event ),
"Control-y": lambda event, frm = 'insert', which = 'c': self.walkKB( event, frm, which),
"Alt-y": lambda event , frm = "insert", which = 'a': self.walkKB( event, frm, which ),
"Alt-k": lambda event : self.killsentence( event ),
'Control-s' : None,
'Control-r' : None,
'Alt-c': lambda event, which = 'cap' : self.capitalize( event, which ),
'Alt-u': lambda event, which = 'up' : self.capitalize( event, which ),
'Alt-l': lambda event, which = 'low' : self.capitalize( event, which ),
'Alt-t': lambda event, sw = self.swapSpots: self.swapWords( event, sw ),
'Alt-x': self.alt_X,
'Control-x': self.startControlX,
'Control-g': self.keyboardQuit,
'Control-Shift-at': self.setRegion,
'Control-w': lambda event, which = 'd' :self.killRegion( event, which ),
'Alt-w': lambda event, which = 'c' : self.killRegion( event, which ),
'Control-t': self.swapCharacters,
'Control-u': None,
'Control-l': None,
'Alt-z': None,
'Control-i': None,
'Alt-Control-backslash': self.indentRegion,
'Alt-m' : self.backToIndentation,
'Alt-asciicircum' : self.deleteIndentation,
'Control-d': self.deleteNextChar,
'Alt-backslash': self.deleteSpaces,
'Alt-g': None,
'Control-v' : lambda event, way = 'south': self.screenscroll( event, way ),
'Alt-v' : lambda event, way = 'north' : self.screenscroll( event, way ),
'Alt-equal': self.countRegion,
'Alt-parenleft': self.insertParentheses,
'Alt-parenright': self.movePastClose,
'Alt-percent' : None,
'Control-c': None,
'Delete': lambda event, which = 'BackSpace': self.manufactureKeyPress( event, which ),
'Control-p': lambda event, which = 'Up': self.manufactureKeyPress( event, which ),
'Control-n': lambda event, which = 'Down': self.manufactureKeyPress( event, which ),
'Control-f': lambda event, which = 'Right':self.manufactureKeyPress( event, which ),
'Control-b': lambda event, which = 'Left': self.manufactureKeyPress( event, which ),
'Control-Alt-w': None,
'Alt-a': lambda event, which = 'bak': self.prevNexSentence( event, which ),
'Alt-e': lambda event, which = 'for': self.prevNexSentence( event, which ),
'Control-Alt-o': self.insertNewLineIndent,
'Control-j': self.insertNewLineAndTab,
'Alt-minus': self.negativeArgument,
'Alt-slash': self.dynamicExpansion,
'Control-Alt-slash': self.dynamicExpansion2,
'Control-u': lambda event, keystroke = '<Control-u>': self.universalDispatch( event, keystroke ),
'Alt-braceright': lambda event, which = 1: self.movingParagraphs( event, which ),
'Alt-braceleft': lambda event , which = 0: self.movingParagraphs( event, which ),
'Alt-q': self.fillParagraph,
'Alt-h': self.selectParagraph,
'Alt-semicolon': self.indentToCommentColumn,
'Alt-0': lambda event, stroke = '<Alt-0>', number = 0: self.numberCommand( event, stroke, number ) ,
'Alt-1': lambda event, stroke = '<Alt-1>', number = 1: self.numberCommand( event, stroke, number ) ,
'Alt-2': lambda event, stroke = '<Alt-2>', number = 2: self.numberCommand( event, stroke, number ) ,
'Alt-3': lambda event, stroke = '<Alt-3>', number = 3: self.numberCommand( event, stroke, number ) ,
'Alt-4': lambda event, stroke = '<Alt-4>', number = 4: self.numberCommand( event, stroke, number ) ,
'Alt-5': lambda event, stroke = '<Alt-5>', number = 5: self.numberCommand( event, stroke, number ) ,
'Alt-6': lambda event, stroke = '<Alt-6>', number = 6: self.numberCommand( event, stroke, number ) ,
'Alt-7': lambda event, stroke = '<Alt-7>', number = 7: self.numberCommand( event, stroke, number ) ,
'Alt-8': lambda event, stroke = '<Alt-8>', number = 8: self.numberCommand( event, stroke, number ) ,
'Alt-9': lambda event, stroke = '<Alt-9>', number = 9: self.numberCommand( event, stroke, number ) ,
'Control-underscore': self.doUndo,
'Alt-s': self.centerLine,
'Control-z': self.suspend,
'Control-Alt-s': lambda event, stroke='<Control-s>': self.startIncremental( event, stroke, which='regexp' ),
'Control-Alt-r': lambda event, stroke='<Control-r>': self.startIncremental( event, stroke, which='regexp' ),
'Control-Alt-percent': lambda event: self.startRegexReplace() and self.masterQR( event ),
'Escape': self.watchEscape,
'Alt-colon': self.startEvaluate,
'Alt-exclam': self.startSubprocess,
'Alt-bar': lambda event: self.startSubprocess( event, which = 1 ),
}
return cbDict
#@nonl
#@-node:mork.20041030183331:addCallBackDict (creates cbDict)
#@+node:mork.20041030183633:addXCommands
def addXCommands( self ):
xcommands = {
'<Control-t>': self.transposeLines,
'<Control-u>': lambda event , way ='up': self.upperLowerRegion( event, way ),
'<Control-l>': lambda event , way ='low': self.upperLowerRegion( event, way ),
'<Control-o>': self.removeBlankLines,
'<Control-i>': self.insertFile,
'<Control-s>': self.saveFile,
'<Control-x>': self.exchangePointMark,
'<Control-c>': self.shutdown,
'<Control-b>': self.listBuffers,
'<Control-Shift-at>': lambda event: event.widget.selection_clear(),
'<Delete>' : lambda event, back = True: self.killsentence( event, back ),
}
return xcommands
#@nonl
#@-node:mork.20041030183633:addXCommands
#@+node:mork.20041030190903:addAltXCommands
def addAltXCommands( self ):
#many of the simpler methods need self.keyboardQuit( event ) appended to the end to stop the Alt-x mode.
doAltX= {
'prepend-to-register': self.prependToRegister,
'append-to-register': self.appendToRegister,
'replace-string': self.replaceString,
'replace-regex': lambda event: self.activateReplaceRegex() and self.replaceString( event ),
'sort-lines': self.sortLines,
'sort-columns': self.sortColumns,
'reverse-region': self.reverseRegion,
'sort-fields': self.sortFields,
'abbrev-mode': self.toggleAbbrevMode,
'kill-all-abbrevs': self.killAllAbbrevs,
'expand-region-abbrevs': self.regionalExpandAbbrev,
'write-abbrev-file': self.writeAbbreviations,
'read-abbrev-file': self.readAbbreviations,
'fill-region-as-paragraph': self.fillRegionAsParagraph,
'fill-region': self.fillRegion,
'close-rectangle': self.closeRectangle,
'how-many': self.startHowMany,
'kill-paragraph': self.killParagraph,
'backward-kill-paragraph': self.backwardKillParagraph,
'backward-kill-sentence': lambda event: self.keyboardQuit( event ) and self.killsentence( event, back = True ),
'name-last-kbd-macro': self.nameLastMacro,
'load-file': self.loadMacros,
'insert-keyboard-macro' : self.getMacroName,
'list-abbrevs': self.listAbbrevs,
'kill-word': lambda event, frm = 'insert wordstart', to = 'insert wordend': self.kill( event,frm, to ) and self.keyboardQuit( event ),
'kill-line': lambda event, frm = 'insert', to = 'insert lineend': self.kill( event, frm, to) and self.keyboardQuit( event ),
'kill-sentence': lambda event : self.killsentence( event ) and self.keyboardQuit( event ),
'kill-region': lambda event, which = 'd' :self.killRegion( event, which ) and self.keyboardQuit( event ),
'yank': lambda event, frm = 'insert', which = 'c': self.walkKB( event, frm, which) and self.keyboardQuit( event ),
'yank-pop' : lambda event , frm = "insert", which = 'a': self.walkKB( event, frm, which ) and self.keyboardQuit( event ),
'backward-kill-word': lambda event: self.deletelastWord( event ) and self.keyboardQuit( event ),
'backward-delete-char':lambda event, which = 'BackSpace': self.manufactureKeyPress( event, which ) and self.keyboardQuit( event ),
'delete-char': lambda event: self.deleteNextChar( event ) and self.keyboardQuit( event ) ,
'isearch-forward': lambda event: self.keyboardQuit( event ) and self.startIncremental( event, '<Control-s>' ),
'isearch-backward': lambda event: self.keyboardQuit( event ) and self.startIncremental( event, '<Control-r>' ),
'isearch-forward-regexp': lambda event: self.keyboardQuit( event ) and self.startIncremental( event, '<Control-s>', which = 'regexp' ),
'isearch-backward-regexp': lambda event: self.keyboardQuit( event ) and self.startIncremental( event, '<Control-r>', which = 'regexp' ),
'capitalize-word': lambda event, which = 'cap' : self.capitalize( event, which ) and self.keyboardQuit( event ),
'upcase-word': lambda event, which = 'up' : self.capitalize( event, which ) and self.keyboardQuit( event ),
'downcase-word': lambda event, which = 'low' : self.capitalize( event, which ) and self.keyboardQuit( event ),
'indent-region': lambda event: self.indentRegion( event ) and self.keyboardQuit( event ),
'indent-rigidly': lambda event: self.tabIndentRegion( event ) and self.keyboardQuit( event ),
'indent-relative': self.indent_relative,
'set-mark-command': lambda event: self.setRegion( event ) and self.keyboardQuit( event ),
'kill-rectangle': lambda event: self.killRectangle( event ),
'delete-rectangle': lambda event: self.deleteRectangle( event ),
'yank-rectangle': lambda event: self.yankRectangle( event ),
'open-rectangle': lambda event: self.openRectangle( event ),
'clear-rectangle': lambda event: self.clearRectangle( event ),
'copy-to-register': lambda event: self.setEvent( event, 's' ) and self.setNextRegister( event ),
'insert-register': lambda event: self.setEvent( event, 'i' ) and self.setNextRegister( event ),
'copy-rectangle-to-register': lambda event: self.setEvent( event, 'r' ) and self.setNextRegister( event ),
'jump-to-register': lambda event: self.setEvent( event, 'j' ) and self.setNextRegister( event ),
'point-to-register': lambda event: self.setEvent( event, 'space' ) and self.setNextRegister( event ),
'number-to-register': lambda event: self.setEvent( event, 'n' ) and self.setNextRegister( event ),
'increment-register': lambda event: self.setEvent( event, 'plus' ) and self.setNextRegister( event ),
'view-register': lambda event: self.setEvent( event, 'view' ) and self.setNextRegister( event ),
'beginning-of-line': lambda event, spot = 'insert linestart': self.moveTo( event, spot ) and self.keyboardQuit( event ),
'end-of-line': lambda event, spot = 'insert lineend': self.moveTo( event, spot ) and self.keyboardQuit( event ),
'keyboard-quit': lambda event: self.keyboardQuit( event ),
'advertised-undo': lambda event: self.doUndo( event ) and self.keyboardQuit( event ),
'back-to-indentation': lambda event: self.backToIndentation( event ) and self.keyboardQuit( event ),
'delete-indentation': lambda event: self.deleteIndentation( event ) and self.keyboardQuit( event ),
'view-lossage': lambda event: self.viewLossage( event ),
'transpose-chars': lambda event : self.swapCharacters( event ) and self.keyboardQuit( event ),
'transpose-words': lambda event, sw = self.swapSpots: self.swapWords( event, sw ) and self.keyboardQuit( event ),
'transpose-lines': lambda event: self.transposeLines( event ) and self.keyboardQuit( event ),
'insert-file' : lambda event: self.insertFile( event ) and self.keyboardQuit( event ),
'save-buffer' : lambda event: self.saveFile( event ) and self.keyboardQuit( event ),
'split-line' : lambda event: self.insertNewLineIndent( event ) and self.keyboardQuit( event ),
'upcase-region': lambda event: self.upperLowerRegion( event, 'up' ) and self.keyboardQuit( event ),
'downcase-region': lambda event: self.upperLowerRegion( event , 'low' ) and self.keyboardQuit( event ),
'dabbrev-expands': lambda event: self.dynamicExpansion( event ) and self.keyboardQuit( event ),
'dabbrev-completion': lambda event: self.dynamicExpansion2( event ) and self.keyboardQuit( event ),
'goto-line': lambda event: self.startGoto( event ),
'goto-char': lambda event: self.startGoto( event, True ),
'set-fill-prefix': lambda event: self.setFillPrefix( event ) and self.keyboardQuit( event ),
'set-fill-column': lambda event: self.setFillColumn( event ),
'center-line': lambda event: self.centerLine( event ) and self.keyboardQuit( event ),
'center-region': lambda event: self.centerRegion( event ) and self.keyboardQuit( event ),
'forward-char': lambda event, which = 'Right': self.keyboardQuit( event ) and self.manufactureKeyPress( event, which ),
'backward-char': lambda event, which = 'Left': self.keyboardQuit( event ) and self.manufactureKeyPress( event, which ),
'previous-line': lambda event, which = 'Up': self.keyboardQuit( event ) and self.manufactureKeyPress( event, which ),
'next-line': lambda event, which = 'Down': self.keyboardQuit( event ) and self.manufactureKeyPress( event, which ),
'digit-argument': lambda event: self.universalDispatch( event, '' ),
'universal-argument': lambda event: self.universalDispatch( event, '' ),
'newline-and-indent': lambda event: self.insertNewLineAndTab( event ) and self.keyboardQuit( event ),
'beginning-of-buffer': lambda event, spot = '1.0' : self.moveTo( event, spot ) and self.keyboardQuit( event ),
'end-of-buffer': lambda event, spot = 'end' : self.moveTo( event, spot ) and self.keyboardQuit( event ),
'scroll-up': lambda event, way = 'north' : self.screenscroll( event, way ) and self.keyboardQuit( event ),
'scroll-down': lambda event, way = 'south': self.screenscroll( event, way ) and self.keyboardQuit( event ),
'copy-to-buffer': lambda event, which = 'copy-to-buffer': self.setInBufferMode( event, which ),
'insert-buffer': lambda event, which = 'insert-buffer': self.setInBufferMode( event, which ),
'append-to-buffer': lambda event , which = 'append-to-buffer': self.setInBufferMode( event, which ),
'prepend-to-buffer': lambda event, which = 'prepend-to-buffer': self.setInBufferMode( event, which ),
'switch-to-buffer': lambda event, which = 'switch-to-buffer': self.setInBufferMode( event, which ),
'list-buffers' : lambda event: self.listBuffers( event ),
'kill-buffer' : lambda event, which = 'kill-buffer': self.setInBufferMode( event, which ),
'rename-buffer': lambda event: self.renameBuffer( event ),
'query-replace': lambda event: self.masterQR( event ),
'query-replace-regex': lambda event: self.startRegexReplace() and self.masterQR( event ),
'inverse-add-global-abbrev': lambda event: self.abbreviationDispatch( event, 2 ) ,
'expand-abbrev': lambda event : self.keyboardQuit( event ) and self.expandAbbrev( event ),
'iconfify-or-deiconify-frame': lambda event: self.suspend( event ) and self.keyboardQuit( event ),
'save-buffers-kill-emacs': lambda event: self.keyboardQuit( event ) and self.shutdown( event ),
're-search-forward': lambda event: self.reStart( event ),
're-search-backward': lambda event: self.reStart( event, which = 'backward' ),
'diff': self.diff,
'what-line': self.whatLine,
'flush-lines': lambda event: self.startLines( event ),
'keep-lines': lambda event: self.startLines( event, which = 'keep' ),
'make-directory': lambda event: self.makeDirectory( event ),
'remove-directory': lambda event: self.removeDirectory( event ),
'delete-file': lambda event: self.deleteFile( event ),
'search-forward': lambda event: self.startNonIncrSearch( event, 'for' ),
'search-backward': lambda event: self.startNonIncrSearch( event, 'bak' ),
'word-search-forward': lambda event : self.startWordSearch( event, 'for' ),
'word-search-backward': lambda event: self.startWordSearch( event, 'bak' ),
'repeat-complex-command': lambda event: self.repeatComplexCommand( event ),
'eval-expression': self.startEvaluate,
'tabify': self.tabify,
'untabify': lambda event: self.tabify( event, which = 'untabify' ),
'shell-command': self.startSubprocess,
'shell-command-on-region': lambda event: self.startSubprocess( event, which=1 ),
}
#Note: if we are reusing some of the cbDict lambdas we need to alter many by adding: self.keyboardQuit( event )
#Otherwise the darn thing just sits in Alt-X land. Putting the 'and self.keyboardQuit( event )' part in the killbuffer
#and yanking it out for each new item, works well. Adding it to a register might be good to.
return doAltX
#@nonl
#@-node:mork.20041030190903:addAltXCommands
#@+node:mork.20041030190729:addRegisterItems
def addRegisterItems( self ):
regMeths = {
's' : self.copyToRegister,
'i' : self.insertFromRegister,
'n': self.numberToRegister,
'plus': self.incrementRegister,
'space': self.pointToRegister,
'j': self.jumpToRegister,
'a': lambda event , which = 'a': self._ToReg( event, which ),
'p': lambda event , which = 'p': self._ToReg( event, which ),
'r': self.copyRectangleToRegister,
'view' : self.viewRegister,
}
regText = {
's' : 'copy to register',
'i' : 'insert from register',
'plus': 'increment register',
'n' : 'number to register',
'p' : 'prepend to register',
'a' : 'append to register',
'space' : 'point to register',
'j': 'jump to register',
'r': 'rectangle to register',
'view': 'view register',
}
return regMeths, regText
#@nonl
#@-node:mork.20041030190729:addRegisterItems
#@-others
#@nonl
#@-node:mork.20041031182258:add command dictionary methods
#@+node:mork.20041031183614:general utility methods
#@+at
# These methods currently do not have a specific class that they belong
# to.
#
#@-at
#@@c
#@+others
#@+node:mork.20041031195549:buffer altering methods
#@+others
#@+node:mork.20041030164547.31:moveTo
def moveTo( self, event, spot ):
tbuffer = event.widget
tbuffer.mark_set( Tkinter.INSERT, spot )
tbuffer.see( spot )
return 'break'
#@-node:mork.20041030164547.31:moveTo
#@+node:mork.20041030164547.33:moveword
def moveword( self, event, way ):
'''This function moves the cursor to the next word, direction dependent on the way parameter'''
tbuffer = event.widget
#i = way
ind = tbuffer.index( 'insert' )
if way == 1:
ind = tbuffer.search( '\w', 'insert', stopindex = 'end', regexp=True )
if ind:
nind = '%s wordend' % ind
else:
nind = 'end'
else:
ind = tbuffer.search( '\w', 'insert -1c', stopindex= '1.0', regexp = True, backwards = True )
if ind:
nind = '%s wordstart' % ind
else:
nind = '1.0'
tbuffer.mark_set( 'insert', nind )
tbuffer.see( 'insert' )
tbuffer.event_generate( '<Key>' )
tbuffer.update_idletasks()
return 'break'
#@nonl
#@-node:mork.20041030164547.33:moveword
#@+node:mork.20041030164547.39:capitalize
def capitalize( self, event, which ):
tbuffer = event.widget
text = tbuffer.get( 'insert wordstart', 'insert wordend' )
i = tbuffer.index( 'insert' )
if text == ' ': return 'break'
tbuffer.delete( 'insert wordstart', 'insert wordend' )
if which == 'cap':
text = text.capitalize()
if which == 'low':
text = text.lower()
if which == 'up':
text = text.upper()
tbuffer.insert( 'insert', text )
tbuffer.mark_set( 'insert', i )
return 'break'
#@-node:mork.20041030164547.39:capitalize
#@+node:mork.20041030164547.40:swapWords
def swapWords( self, event , swapspots ):
tbuffer = event.widget
txt = tbuffer.get( 'insert wordstart', 'insert wordend' )
if txt == ' ' : return 'break'
i = tbuffer.index( 'insert wordstart' )
if len( swapspots ) != 0:
def swp( find, ftext, lind, ltext ):
tbuffer.delete( find, '%s wordend' % find )
tbuffer.insert( find, ltext )
tbuffer.delete( lind, '%s wordend' % lind )
tbuffer.insert( lind, ftext )
swapspots.pop()
swapspots.pop()
return 'break'
if tbuffer.compare( i , '>', swapspots[ 1 ] ):
return swp( i, txt, swapspots[ 1 ], swapspots[ 0 ] )
elif tbuffer.compare( i , '<', swapspots[ 1 ] ):
return swp( swapspots[ 1 ], swapspots[ 0 ], i, txt )
else:
return 'break'
else:
swapspots.append( txt )
swapspots.append( i )
return 'break'
#@-node:mork.20041030164547.40:swapWords
#@+node:mork.20041030164547.103:insertParentheses
def insertParentheses( self, event ):
tbuffer = event.widget
tbuffer.insert( 'insert', '()' )
tbuffer.mark_set( 'insert', 'insert -1c' )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.103:insertParentheses
#@+node:mork.20041123095436:replace-string and replace-regex
#@+at
# both commands use the replaceString method, differentiated by a state
# variable
#
#@-at
#@@c
#@+others
#@+node:mork.20041030164547.115:replaceString
#self.rString = False
#self._sString = ''
#self._rpString = ''
def replaceString( self, event ):
svar, label = self.getSvarLabel( event )
if event.keysym in ( 'Control_L', 'Control_R' ):
return
rS = self.mcStateManager.getState( 'rString' )
regex = self._useRegex
if not rS:
#self.rString = 1
self.mcStateManager.setState( 'rString', 1 )
self._sString = ''
self._rpString = ''
if regex:
svar.set( 'Replace Regex' )
else:
svar.set( 'Replace String' )
return
if event.keysym == 'Return':
#self.rString = self.rString + 1
rS = rS + 1
self.mcStateManager.setState( 'rString', rS )
#return 'break'
if rS == 1:
svar.set( '' )
#self.rString = self.rString + 1
rS = rS + 1
self.mcStateManager.setState( 'rString', rS )
if rS == 2:
self.setSvar( event, svar )
self._sString = svar.get()
return 'break'
if rS == 3:
if regex:
svar.set( 'Replace regex %s with:' % self._sString )
else:
svar.set( 'Replace string %s with:' % self._sString )
self.mcStateManager.setState( 'rString',rS + 1 )
#self.rString = self.rString + 1
return 'break'
if rS == 4:
svar.set( '' )
#self.rString = self.rString + 1
rS = rS + 1
self.mcStateManager.setState( 'rString', rS )
if rS == 5:
self.setSvar( event, svar )
self._rpString = svar.get()
return 'break'
if rS == 6:
tbuffer = event.widget
i = 'insert'
end = 'end'
ct = 0
if tbuffer.tag_ranges( 'sel' ):
i = tbuffer.index( 'sel.first' )
end = tbuffer.index( 'sel.last' )
if regex:
txt = tbuffer.get( i, end )
try:
pattern = re.compile( self._sString )
except:
self.keyboardQuit( event )
svar.set( "Illegal regular expression" )
return 'break'
ct = len( pattern.findall( txt ) )
if ct:
ntxt = pattern.sub( self._rpString, txt )
tbuffer.delete( i, end )
tbuffer.insert( i, ntxt )
else:
txt = tbuffer.get( i, end )
ct = txt.count( self._sString )
if ct:
ntxt = txt.replace( self._sString, self._rpString )
tbuffer.delete( i, end )
tbuffer.insert( i, ntxt )
svar.set( 'Replaced %s occurances' % ct )
#label.configure( background = 'lightgrey' )
self.setLabelGrey( label )
#self.rString = False
self.mcStateManager.clear()
self._useRegex = False
#self.mcStateManager.setState( 'rString', False )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.115:replaceString
#@+node:mork.20041123095123:activateReplaceRegex
def activateReplaceRegex( self ):
'''This method turns regex replace on for replaceString'''
self._useRegex = True
return True
#@-node:mork.20041123095123:activateReplaceRegex
#@-others
#@nonl
#@-node:mork.20041123095436:replace-string and replace-regex
#@+node:mork.20041030164547.116:swapCharacters
def swapCharacters( self, event ):
tbuffer = event.widget
i = tbuffer.index( 'insert' )
c1 = tbuffer.get( 'insert', 'insert +1c' )
c2 = tbuffer.get( 'insert -1c', 'insert' )
tbuffer.delete( 'insert -1c', 'insert' )
tbuffer.insert( 'insert', c1 )
tbuffer.delete( 'insert', 'insert +1c' )
tbuffer.insert( 'insert', c2 )
tbuffer.mark_set( 'insert', i )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.116:swapCharacters
#@+node:mork.20041123095507:insert new line methods
#@+others
#@+node:mork.20041030164547.117:insertNewLine
def insertNewLine( self,event ):
tbuffer = event.widget
i = tbuffer.index( 'insert' )
tbuffer.insert( 'insert', '\n' )
tbuffer.mark_set( 'insert', i )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.117:insertNewLine
#@+node:mork.20041030164547.131:insertNewLineIndent
#self.negArgs = { '<Alt-c>': changePreviousWord,
#'<Alt-u>' : changePreviousWord,
#'<Alt-l>': changePreviousWord }
def insertNewLineIndent( self, event ):
tbuffer = event.widget
txt = tbuffer.get( 'insert linestart', 'insert lineend' )
txt = self.getWSString( txt )
i = tbuffer.index( 'insert' )
tbuffer.insert( i, txt )
tbuffer.mark_set( 'insert', i )
return self.insertNewLine( event )
#@-node:mork.20041030164547.131:insertNewLineIndent
#@+node:mork.20041103135515:insertNewLineAndTab
def insertNewLineAndTab( self, event ):
'''Insert a newline and tab'''
tbuffer = event.widget
self.insertNewLine( event )
i = tbuffer.index( 'insert +1c' )
tbuffer.insert( i, '\t' )
tbuffer.mark_set( 'insert', '%s lineend' % i )
return self._tailEnd( tbuffer )
#@-node:mork.20041103135515:insertNewLineAndTab
#@-others
#@nonl
#@-node:mork.20041123095507:insert new line methods
#@+node:mork.20041030164547.148:transposeLines
def transposeLines( self, event ):
tbuffer = event.widget
i = tbuffer.index( 'insert' )
i1, i2 = i.split( '.' )
i1 = str( int( i1 ) -1 )
if i1 != '0':
l2 = tbuffer.get( 'insert linestart', 'insert lineend' )
tbuffer.delete( 'insert linestart-1c', 'insert lineend' )
tbuffer.insert( i1+'.0', l2 +'\n')
else:
l2 = tbuffer.get( '2.0', '2.0 lineend' )
tbuffer.delete( '2.0', '2.0 lineend' )
tbuffer.insert( '1.0', l2 + '\n' )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.148:transposeLines
#@+node:mork.20041030164547.130:changePreviousWord
def changePreviousWord( self, event, stroke ):
tbuffer = event.widget
i = tbuffer.index( 'insert' )
self.moveword( event, -1 )
if stroke == '<Alt-c>':
self.capitalize( event, 'cap' )
elif stroke =='<Alt-u>':
self.capitalize( event, 'up' )
elif stroke == '<Alt-l>':
self.capitalize( event, 'low' )
tbuffer.mark_set( 'insert', i )
self.stopControlX( event )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.130:changePreviousWord
#@+node:mork.20041030164547.150:removeBlankLines
def removeBlankLines( self, event ):
tbuffer = event.widget
i = tbuffer.index( 'insert' )
i1, i2 = i.split( '.' )
i1 = int( i1 )
dindex = []
if tbuffer.get( 'insert linestart', 'insert lineend' ).strip() == '':
while 1:
if str( i1 )+ '.0' == '1.0' :
break
i1 = i1 - 1
txt = tbuffer.get( '%s.0' % i1, '%s.0 lineend' % i1 )
txt = txt.strip()
if len( txt ) == 0:
dindex.append( '%s.0' % i1)
dindex.append( '%s.0 lineend' % i1 )
elif dindex:
tbuffer.delete( '%s-1c' % dindex[ -2 ], dindex[ 1 ] )
tbuffer.event_generate( '<Key>' )
tbuffer.update_idletasks()
break
else:
break
i = tbuffer.index( 'insert' )
i1, i2 = i.split( '.' )
i1 = int( i1 )
dindex = []
while 1:
if tbuffer.index( '%s.0 lineend' % i1 ) == tbuffer.index( 'end' ):
break
i1 = i1 + 1
txt = tbuffer.get( '%s.0' % i1, '%s.0 lineend' % i1 )
txt = txt.strip()
if len( txt ) == 0:
dindex.append( '%s.0' % i1 )
dindex.append( '%s.0 lineend' % i1 )
elif dindex:
tbuffer.delete( '%s-1c' % dindex[ 0 ], dindex[ -1 ] )
tbuffer.event_generate( '<Key>' )
tbuffer.update_idletasks()
break
else:
break
#@-node:mork.20041030164547.150:removeBlankLines
#@+node:mork.20041030164547.101:screenscroll
def screenscroll( self, event, way = 'north' ):
tbuffer = event.widget
chng = self.measure( tbuffer )
i = tbuffer.index( 'insert' )
if way == 'north':
#top = chng[ 1 ]
i1, i2 = i.split( '.' )
i1 = int( i1 ) - chng[ 0 ]
else:
#bottom = chng[ 2 ]
i1, i2 = i.split( '.' )
i1 = int( i1 ) + chng[ 0 ]
tbuffer.mark_set( 'insert', '%s.%s' % ( i1, i2 ) )
tbuffer.see( 'insert' )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.101:screenscroll
#@+node:mork.20041030164547.22:exchangePointMark
def exchangePointMark( self, event ):
if not self._chckSel( event ):
return
tbuffer = event.widget
s1 = tbuffer.index( 'sel.first' )
s2 = tbuffer.index( 'sel.last' )
i = tbuffer.index( 'insert' )
if i == s1:
tbuffer.mark_set( 'insert', s2 )
else:
tbuffer.mark_set('insert', s1 )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.22:exchangePointMark
#@+node:mork.20041030164547.96:backToIndentation
def backToIndentation( self, event ):
tbuffer = event.widget
i = tbuffer.index( 'insert linestart' )
i2 = tbuffer.search( r'\w', i, stopindex = '%s lineend' % i, regexp = True )
tbuffer.mark_set( 'insert', i2 )
tbuffer.update_idletasks()
return 'break'
#@-node:mork.20041030164547.96:backToIndentation
#@+node:mork.20041124130434:indent-relative
def indent_relative( self, event ):
tbuffer = event.widget
i = tbuffer.index( 'insert' )
l,c = i.split( '.' )
c2 = int( c )
l2 = int( l ) - 1
if l2 < 1: return self.keyboardQuit( event )
txt = tbuffer.get( '%s.%s' % (l2, c2 ), '%s.0 lineend' % l2 )
if len( txt ) <= len( tbuffer.get( 'insert', 'insert lineend' ) ):
tbuffer.insert( 'insert', '\t' )
else:
reg = re.compile( '(\s+)' )
ntxt = reg.split( txt )
replace_word = re.compile( '\w' )
for z in ntxt:
if z.isspace():
tbuffer.insert( 'insert', z )
break
else:
z = replace_word.subn( ' ', z )
tbuffer.insert( 'insert', z[ 0 ] )
tbuffer.update_idletasks()
self.keyboardQuit( event )
return self._tailEnd( tbuffer )
#@-node:mork.20041124130434:indent-relative
#@+node:mork.20041030164547.129:negativeArgument
#self.negativeArg = False
def negativeArgument( self, event, stroke = None ):
#global negativeArg
svar, label = self.getSvarLabel( event )
svar.set( "Negative Argument" )
label.configure( background = 'lightblue' )
nA = self.mcStateManager.getState( 'negativeArg' )
if not nA:
self.mcStateManager.setState( 'negativeArg', True )
#self.negativeArg = True
if nA:
if self.negArgs.has_key( stroke ):
self.negArgs[ stroke ]( event , stroke)
return 'break'
#@-node:mork.20041030164547.129:negativeArgument
#@+node:mork.20041030164547.114:movePastClose
def movePastClose( self, event ):
tbuffer = event.widget
i = tbuffer.search( '(', 'insert' , backwards = True ,stopindex = '1.0' )
icheck = tbuffer.search( ')', 'insert', backwards = True, stopindex = '1.0' )
if '' == i:
return 'break'
if icheck:
ic = tbuffer.compare( i, '<', icheck )
if ic:
return 'break'
i2 = tbuffer.search( ')', 'insert' ,stopindex = 'end' )
i2check = tbuffer.search( '(', 'insert', stopindex = 'end' )
if '' == i2:
return 'break'
if i2check:
ic2 = tbuffer.compare( i2, '>', i2check )
if ic2:
return 'break'
ib = tbuffer.index( 'insert' )
tbuffer.mark_set( 'insert', '%s lineend +1c' % i2 )
if tbuffer.index( 'insert' ) == tbuffer.index( '%s lineend' % ib ):
tbuffer.insert( 'insert' , '\n')
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.114:movePastClose
#@+node:mork.20041030164547.119:prevNexSentence
def prevNexSentence( self, event , way ):
tbuffer = event.widget
if way == 'bak':
i = tbuffer.search( '.', 'insert', backwards = True, stopindex = '1.0' )
if i:
i2 = tbuffer.search( '.', i, backwards = True, stopindex = '1.0' )
if not i2:
i2 = '1.0'
if i2:
i3 = tbuffer.search( '\w', i2, stopindex = i, regexp = True )
if i3:
tbuffer.mark_set( 'insert', i3 )
else:
tbuffer.mark_set( 'insert', '1.0' )
else:
i = tbuffer.search( '.', 'insert', stopindex = 'end' )
if i:
tbuffer.mark_set( 'insert', '%s +1c' %i )
else:
tbuffer.mark_set( 'insert', 'end' )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.119:prevNexSentence
#@+node:mork.20041031202438:selectAll
def selectAll( event ):
event.widget.tag_add( 'sel', '1.0', 'end' )
return 'break'
#@-node:mork.20041031202438:selectAll
#@+node:mork.20041120195951:suspend
def suspend( self, event ):
widget = event.widget
widget.winfo_toplevel().iconify()
#@-node:mork.20041120195951:suspend
#@-others
#@nonl
#@-node:mork.20041031195549:buffer altering methods
#@+node:mork.20041031195908:informational methods
#@+others
#@+node:mork.20041030164547.118:lineNumber
def lineNumber( self, event ):
self.stopControlX( event )
svar, label = self.getSvarLabel( event )
tbuffer = event.widget
i = tbuffer.index( 'insert' )
i1, i2 = i.split( '.' )
c = tbuffer.get( 'insert', 'insert + 1c' )
txt = tbuffer.get( '1.0', 'end' )
txt2 = tbuffer.get( '1.0', 'insert' )
perc = len( txt ) * .01
perc = int( len( txt2 ) / perc )
svar.set( 'Char: %s point %s of %s(%s%s) Column %s' %( c, len( txt2), len( txt), perc,'%', i1 ) )
return 'break'
#@-node:mork.20041030164547.118:lineNumber
#@+node:mork.20041102161859:viewLossage
def viewLossage( self, event ):
svar, label = self.getSvarLabel( event )
loss = ''.join( Emacs.lossage )
self.keyboardQuit( event )
svar.set( loss )
#@nonl
#@-node:mork.20041102161859:viewLossage
#@+node:mork.20041121195816:whatLine
def whatLine( self, event ):
tbuffer = event.widget
svar, label = self.getSvarLabel( event )
i = tbuffer.index( 'insert' )
i1, i2 = i.split( '.' )
self.keyboardQuit( event )
svar.set( "Line %s" % i1 )
#@-node:mork.20041121195816:whatLine
#@-others
#@nonl
#@-node:mork.20041031195908:informational methods
#@+node:mork.20041031195908.1:pure utility methods
#@+others
#@+node:mork.20041102151939:setEvent
def setEvent( self, event, l ):
event.keysym = l
return event
#@-node:mork.20041102151939:setEvent
#@+node:mork.20041030164547.127:getWSString
def getWSString( self, txt ):
ntxt = []
for z in txt:
if z == '\t':
ntxt.append( z )
else:
ntxt.append( ' ' )
return ''.join( ntxt )
#@-node:mork.20041030164547.127:getWSString
#@+node:mork.20041030164547.135:findPre
def findPre( self, a, b ):
st = ''
for z in a:
st1 = st + z
if b.startswith( st1 ):
st = st1
else:
return st
return st
#@-node:mork.20041030164547.135:findPre
#@+node:mork.20041030164547.100:measure
def measure( self, tbuffer ):
i = tbuffer.index( 'insert' )
i1, i2 = i.split( '.' )
start = int( i1 )
watch = 0
ustart = start
pone = 1
top = i
bottom = i
while pone:
ustart = ustart - 1
if ustart < 0:
break
ds = '%s.0' % ustart
pone = tbuffer.dlineinfo( ds )
if pone:
top = ds
watch = watch + 1
pone = 1
ustart = start
while pone:
ustart = ustart +1
ds = '%s.0' % ustart
pone = tbuffer.dlineinfo( ds )
if pone:
bottom = ds
watch = watch + 1
return watch , top, bottom
#@-node:mork.20041030164547.100:measure
#@+node:mork.20041030164547.95:manufactureKeyPress
def manufactureKeyPress( self, event, which ):
tbuffer = event.widget
tbuffer.event_generate( '<Key>', keysym = which )
tbuffer.update_idletasks()
return 'break'
#@nonl
#@-node:mork.20041030164547.95:manufactureKeyPress
#@+node:mork.20041030164547.83:changecbDict
def changecbDict( self, changes ):
for z in changes:
if self.cbDict.has_key( z ):
self.cbDict[ z ] = self.changes[ z ]
#@-node:mork.20041030164547.83:changecbDict
#@+node:mork.20041030164547.92:removeRKeys
def removeRKeys( self, widget ):
mrk = 'sel'
widget.tag_delete( mrk )
widget.unbind( '<Left>' )
widget.unbind( '<Right>' )
widget.unbind( '<Up>' )
widget.unbind( '<Down>' )
#@-node:mork.20041030164547.92:removeRKeys
#@+node:mork.20041030164547.142:_findMatch2
def _findMatch2( self, svar, fdict = None ):#, fdict = self.doAltX ):
'''This method returns a sorted list of matches.'''
if not fdict:
fdict = self.doAltX
txt = svar.get()
if not txt.isspace() and txt != '':
txt = txt.strip()
pmatches = filter( lambda a : a.startswith( txt ), fdict )
else:
pmatches = []
pmatches.sort()
return pmatches
#if pmatches:
# #mstring = reduce( self.findPre, pmatches )
# #return mstring
#return txt
#@-node:mork.20041030164547.142:_findMatch2
#@+node:mork.20041102133805:_findMatch
def _findMatch( self, svar, fdict = None ):#, fdict = self.doAltX ):
'''This method finds the first match it can find in a sorted list'''
if not fdict:
fdict = self.doAltX
txt = svar.get()
pmatches = filter( lambda a : a.startswith( txt ), fdict )
pmatches.sort()
if pmatches:
mstring = reduce( self.findPre, pmatches )
return mstring
return txt
#@-node:mork.20041102133805:_findMatch
#@-others
#@nonl
#@-node:mork.20041031195908.1:pure utility methods
#@-others
#@nonl
#@-node:mork.20041031183614:general utility methods
#@+node:mork.20041120223251:shutdown methods
#@+others
#@+node:mork.20041120222336:shutdown
def shutdown( self, event ):
self.shuttingdown = True
if self.shutdownhook:
self.shutdownhook()
else:
sys.exit( 0 )
#@nonl
#@-node:mork.20041120222336:shutdown
#@+node:mork.20041120223251.1:setShutdownHook
def setShutdownHook( self, hook ):
self.shutdownhook = hook
#@nonl
#@-node:mork.20041120223251.1:setShutdownHook
#@-others
#@nonl
#@-node:mork.20041120223251:shutdown methods
#@+node:mork.20041031182215:Label( minibuffer ) and svar methods
#@+at
# Two closely related categories under this one heading. Svars are the
# internals of the minibuffer
# and the labels are the presentation of those internals
#
#@-at
#@@c
#@+others
#@+node:mork.20041102183901:label( minibuffer ) methods
#@+node:mork.20041030164547.2:setLabelGrey
def setLabelGrey( self, label ):
label.configure( background = 'lightgrey' )
#@-node:mork.20041030164547.2:setLabelGrey
#@+node:mork.20041030164547.3:setLabelBlue
def setLabelBlue( self ,label ):
label.configure( background = 'lightblue' )
#@-node:mork.20041030164547.3:setLabelBlue
#@+node:mork.20041030164547.86:resetMiniBuffer
def resetMiniBuffer( self, event ):
svar, label = self.getSvarLabel( event )
svar.set( '' )
label.configure( background = 'lightgrey' )
#@-node:mork.20041030164547.86:resetMiniBuffer
#@-node:mork.20041102183901:label( minibuffer ) methods
#@+node:mork.20041031182943:svar methods
#@+at
# These methods get and alter the Svar variable which is a Tkinter
# StringVar. This StringVar contains what is displayed in the minibuffer.
#@-at
#@@c
#@+others
#@+node:mork.20041030164547.112:getSvarLabel
def getSvarLabel( self, event ):
'''returns the StringVar and Label( minibuffer ) for a specific Text editor'''
svar = self.svars[ event.widget ]
label = self.mbuffers[ event.widget ]
return svar, label
#@-node:mork.20041030164547.112:getSvarLabel
#@+node:mork.20041030164547.113:setSvar
def setSvar( self, event, svar ):
'''Alters the StringVar svar to represent the change in the event.
It mimics what would happen with the keyboard and a Text editor
instead of plain accumalation.'''
t = svar.get()
if event.char == '\b':
if len( t ) == 1:
t = ''
else:
t = t[ 0 : -1 ]
svar.set( t )
else:
t = t + event.char
svar.set( t )
#@-node:mork.20041030164547.113:setSvar
#@-others
#@nonl
#@-node:mork.20041031182943:svar methods
#@-others
#@nonl
#@-node:mork.20041031182215:Label( minibuffer ) and svar methods
#@+node:mork.20041031194746:configurable methods
#@+at
# These methods contain methods by which an Emacs instance is extended,
# changed, added to , etc...
#
#@-at
#@@c
#@+others
#@+node:mork.20041031182643:tailEnd methods
#@+others
#@+node:mork.20041030164547.4:_tailEnd
def _tailEnd( self, tbuffer ):
'''This returns the tailEnd function that has been configure for the tbuffer parameter.'''
if self.tailEnds.has_key( tbuffer ):
return self.tailEnds[ tbuffer ]( tbuffer )
else:
return 'break'
#@-node:mork.20041030164547.4:_tailEnd
#@+node:mork.20041030164547.5:setTailEnd
#self.tailEnds = {}
def setTailEnd( self, tbuffer , tailCall ):
'''This method sets a ending call that is specific for a particular Text widget.
Some environments require that specific end calls be made after a keystroke
or command is executed.'''
self.tailEnds[ tbuffer ] = tailCall
#@-node:mork.20041030164547.5:setTailEnd
#@-others
#@nonl
#@-node:mork.20041031182643:tailEnd methods
#@+node:mork.20041031182643.1:undoer methods
#@+at
# Emacs requires an undo mechanism be added from the environment.
# If there is no undo mechanism added, there will be no undo functionality
# in the instance.
#@-at
#@@c
#@+others
#@+node:mork.20041030164547.6:setUndoer
#self.undoers = {}
def setUndoer( self, tbuffer, undoer ):
'''This method sets the undoer method for the Emacs instance.'''
self.undoers[ tbuffer ] = undoer
#@-node:mork.20041030164547.6:setUndoer
#@+node:mork.20041030164547.7:doUndo
def doUndo( self, event, amount = 1 ):
tbuffer = event.widget
if self.undoers.has_key( tbuffer ):
for z in xrange( amount ):
self.undoers[ tbuffer ]()
return 'break'
#@-node:mork.20041030164547.7:doUndo
#@-others
#@nonl
#@-node:mork.20041031182643.1:undoer methods
#@+node:mork.20041030164547.30:setBufferStrokes
#mbuffers = {}
#svars = {}
def setBufferStrokes( self, tbuffer, label ):
'''setBufferStrokes takes a Tk Text widget called 'tbuffer'. 'stext' is a function or method
that when called will return the value of the search text. 'rtext' is a function or method
that when called will return the value of the replace text. It is this method and
getHelpText that users of the temacs module should call. The rest are callback functions
that enable the Emacs emulation.'''
g.trace(tbuffer,label)
Emacs.Emacs_instances[ tbuffer ] = self
def cb( evstring ):
_cb = None
if self.cbDict.has_key( evstring ):
_cb = self.cbDict[ evstring ]
evstring = '<%s>' % evstring
if evstring != '<Key>':
# g.trace(evstring)
tbuffer.bind( evstring, lambda event, meth = _cb: self.masterCommand( event, meth , evstring) )
else:
# g.trace('+',evstring)
tbuffer.bind( evstring, lambda event, meth = _cb: self.masterCommand( event, meth , evstring), '+' )
# EKR: create one binding for each entry in cbDict.
for z in self.cbDict:
cb( z )
self.mbuffers[ tbuffer ] = label
self.svars[ tbuffer ] = Tkinter.StringVar()
def setVar( event ):
label = self.mbuffers[ event.widget ]
svar = self.svars[ event.widget ]
label.configure( textvariable = svar )
tbuffer.bind( '<FocusIn>', setVar, '+' )
def scrollTo( event ):
event.widget.see( 'insert' )
#tbuffer.bind( '<Enter>', scrollTo, '+' )
# EKR: This _adds_ a binding for all <Key> events, so _all_ key events go through masterCommand.
cb( 'Key' )
#@-node:mork.20041030164547.30:setBufferStrokes
#@+node:mork.20041101190309:extendAltX
def extendAltX( self, name, function ):
'''A simple method that extends the functions Alt-X offers.'''
nfunction = new.instancemethod( function, self, Emacs ) #making it an instance method allows the function to be passed 'self'.
self.doAltX[ name ] = nfunction
#@-node:mork.20041101190309:extendAltX
#@+node:mork.20041102094716:reconfigureKeyStroke
def reconfigureKeyStroke( self, tbuffer, keystroke , set_to ):
'''This method allows the user to reconfigure what a keystroke does.
This feature is alpha at best, and untested.'''
if self.cbDict.has_key( set_to ):
command = self.cbDict[ set_to ]
self.cbDict[ keystroke ] = command
evstring = '<%s>' % keystroke
tbuffer.bind( evstring, lambda event, meth = command: self.masterCommand( event, meth , evstring) )
#@nonl
#@-node:mork.20041102094716:reconfigureKeyStroke
#@+node:mork.20041103155347:buffer recognition and alterers
#@+at
# an Emacs instance does not have knowledge of what is considered a buffer
# in the environment.
# It must be configured by the user so that it can operate on the other
# buffers. Otherwise
# these methods will be useless.
#
#@-at
#@@c
#@+others
#@+node:mork.20041104094826:configure buffer methods
#@+others
#@+node:mork.20041103155347.1:setBufferGetter
def setBufferListGetter( self, buffer, method ):
#Sets a method that returns a buffer name and its text, and its insert position.
self.bufferListGetters[ buffer ] = method
#@-node:mork.20041103155347.1:setBufferGetter
#@+node:mork.20041103155347.2:setBufferSetter
def setBufferSetter( self, buffer, method ):
#Sets a method that takes a buffer name and the new contents.
self.bufferSetters[ buffer ] = method
#@nonl
#@-node:mork.20041103155347.2:setBufferSetter
#@+node:mork.20041103155347.3:getBufferDict
def getBufferDict( self, event ):
tbuffer = event.widget
meth = self.bufferListGetters[ tbuffer ]
return meth()
#@nonl
#@-node:mork.20041103155347.3:getBufferDict
#@+node:mork.20041103162147:setBufferData
def setBufferData( self, event, name, data ):
tbuffer = event.widget
meth = self.bufferSetters[ tbuffer ]
meth( name, data )
#@nonl
#@-node:mork.20041103162147:setBufferData
#@+node:mork.20041103191311:setBufferGoto
def setBufferGoto( self, tbuffer, method ):
self.bufferGotos[ tbuffer ] = method
#@nonl
#@-node:mork.20041103191311:setBufferGoto
#@+node:mork.20041104090224:setBufferDelete
def setBufferDelete( self, tbuffer, method ):
self.bufferDeletes[ tbuffer ] = method
#@-node:mork.20041104090224:setBufferDelete
#@+node:mork.20041104092349:setBufferRename
def setBufferRename( self, buffer, method ):
self.renameBuffers[ buffer ] = method
#@nonl
#@-node:mork.20041104092349:setBufferRename
#@-others
#@nonl
#@-node:mork.20041104094826:configure buffer methods
#@+node:mork.20041104094826.1:buffer operations
#@+others
#@+node:mork.20041103155347.4:appendToBuffer
def appendToBuffer( self, event, name ):
tbuffer = event.widget
try:
txt = tbuffer.get( 'sel.first', 'sel.last' )
bdata = self.bufferDict[ name ]
bdata = '%s%s' % ( bdata, txt )
self.setBufferData( event, name, bdata )
except Exception, x:
pass
return self.keyboardQuit( event )
#@nonl
#@-node:mork.20041103155347.4:appendToBuffer
#@+node:mork.20041103155347.5:prependToBuffer
def prependToBuffer( self, event, name ):
tbuffer = event.widget
try:
txt = tbuffer.get( 'sel.first', 'sel.last' )
bdata = self.bufferDict[ name ]
bdata = '%s%s' % ( txt, bdata )
self.setBufferData( event, name, bdata )
except Exception, x:
pass
return self.keyboardQuit( event )
#@nonl
#@-node:mork.20041103155347.5:prependToBuffer
#@+node:mork.20041103155347.6:insertToBuffer
def insertToBuffer( self, event, name ):
tbuffer = event.widget
bdata = self.bufferDict[ name ]
tbuffer.insert( 'insert', bdata )
self._tailEnd( tbuffer )
return self.keyboardQuit( event )
#@-node:mork.20041103155347.6:insertToBuffer
#@+node:mork.20041103190332:listBuffers
def listBuffers( self, event ):
bdict = self.getBufferDict( event )
list = bdict.keys()
list.sort()
svar, label = self.getSvarLabel( event )
data = '\n'.join( list )
self.keyboardQuit( event )
svar.set( data )
return 'break'
#@nonl
#@-node:mork.20041103190332:listBuffers
#@+node:mork.20041103155347.7:copyToBuffer
def copyToBuffer( self, event, name ):
tbuffer = event.widget
try:
txt = tbuffer.get( 'sel.first', 'sel.last' )
self.setBufferData( event, name, txt )
except Exception, x:
pass
return self.keyboardQuit( event )
#@-node:mork.20041103155347.7:copyToBuffer
#@+node:mork.20041103191311.1:switchToBuffer
def switchToBuffer( self, event, name ):
method = self.bufferGotos[ event.widget ]
self.keyboardQuit( event )
method( name )
return 'break'
#@-node:mork.20041103191311.1:switchToBuffer
#@+node:mork.20041104090224.1:killBuffer
def killBuffer( self, event, name ):
method = self.bufferDeletes[ event.widget ]
self.keyboardQuit( event )
method( name )
return 'break'
#@-node:mork.20041104090224.1:killBuffer
#@+node:mork.20041104092058:renameBuffer
def renameBuffer( self, event ):
svar, label = self.getSvarLabel( event )
if not self.mcStateManager.getState( 'renameBuffer' ):
self.mcStateManager.setState( 'renameBuffer', True )
svar.set( '' )
label.configure( background = 'lightblue' )
return 'break'
if event.keysym == 'Return':
nname = svar.get()
self.keyboardQuit( event )
self.renameBuffers[ event.widget ]( nname )
else:
self.setSvar( event, svar )
return 'break'
#@nonl
#@-node:mork.20041104092058:renameBuffer
#@+node:mork.20041103161202:chooseBuffer
def chooseBuffer( self, event ):
svar, label = self.getSvarLabel( event )
state = self.mcStateManager.getState( 'chooseBuffer' )
if state.startswith( 'start' ):
state = state[ 5: ]
self.mcStateManager.setState( 'chooseBuffer', state )
svar.set( '' )
if event.keysym == 'Tab':
stext = svar.get().strip()
if self.bufferTracker.prefix and stext.startswith( self.bufferTracker.prefix ):
svar.set( self.bufferTracker.next() ) #get next in iteration
else:
prefix = svar.get()
pmatches = []
for z in self.bufferDict.keys():
if z.startswith( prefix ):
pmatches.append( z )
self.bufferTracker.setTabList( prefix, pmatches )
svar.set( self.bufferTracker.next() ) #begin iteration on new lsit
return 'break'
elif event.keysym == 'Return':
bMode = self.mcStateManager.getState( 'chooseBuffer' )
return self.bufferCommands[ bMode ]( event, svar.get() )
else:
self.setSvar( event, svar )
return 'break'
#@-node:mork.20041103161202:chooseBuffer
#@+node:mork.20041103161202.1:setInBufferMode
def setInBufferMode( self, event, which ):
self.keyboardQuit( event )
tbuffer = event.widget
self.mcStateManager.setState( 'chooseBuffer', 'start%s' % which )
svar, label = self.getSvarLabel( event )
label.configure( background = 'lightblue' )
svar.set( 'Choose Buffer Name:' )
self.bufferDict = self.getBufferDict( event )
return 'break'
#@nonl
#@-node:mork.20041103161202.1:setInBufferMode
#@-others
#@nonl
#@-node:mork.20041104094826.1:buffer operations
#@-others
#@nonl
#@-node:mork.20041103155347:buffer recognition and alterers
#@-others
#@nonl
#@-node:mork.20041031194746:configurable methods
#@+node:mork.20041031155753:macro methods
#@+at
# general macro methods.
#
#@-at
#@@c
#@+others
#@+node:mork.20041030164547.8:startKBDMacro
#self.lastMacro = None
#self.macs = []
#self.macro = []
#self.namedMacros = {}
#self.macroing = False
def startKBDMacro( self, event ):
svar, label = self.getSvarLabel( event )
svar.set( 'Recording Keyboard Macro' )
label.configure( background = 'lightblue' )
self.macroing = True
return 'break'
#@-node:mork.20041030164547.8:startKBDMacro
#@+node:mork.20041030164547.9:recordKBDMacro
def recordKBDMacro( self, event, stroke ):
if stroke != '<Key>':
self.macro.append( (stroke, event.keycode, event.keysym, event.char) )
elif stroke == '<Key>':
if event.keysym != '??':
self.macro.append( ( event.keycode, event.keysym ) )
return
#@-node:mork.20041030164547.9:recordKBDMacro
#@+node:mork.20041030164547.10:stopKBDMacro
def stopKBDMacro( self, event ):
#global macro, lastMacro, macroing
if self.macro:
self.macro = self.macro[ : -4 ]
self.macs.insert( 0, self.macro )
self.lastMacro = self.macro
self.macro = []
self.macroing = False
svar, label = self.getSvarLabel( event )
svar.set( 'Keyboard macro defined' )
label.configure( background = 'lightgrey' )
return 'break'
#@-node:mork.20041030164547.10:stopKBDMacro
#@+node:mork.20041030164547.11:_executeMacro
def _executeMacro( self, macro, tbuffer ):
for z in macro:
if len( z ) == 2:
tbuffer.event_generate( '<Key>', keycode = z[ 0 ], keysym = z[ 1 ] )
else:
meth = z[ 0 ].lstrip( '<' ).rstrip( '>' )
method = self.cbDict[ meth ]
ev = Tkinter.Event()
ev.widget = tbuffer
ev.keycode = z[ 1 ]
ev.keysym = z[ 2 ]
ev.char = z[ 3 ]
self.masterCommand( ev , method, '<%s>' % meth )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.11:_executeMacro
#@+node:mork.20041030164547.12:executeLastMacro
def executeLastMacro( self, event ):
tbuffer = event.widget
if self.lastMacro:
return self._executeMacro( self.lastMacro, tbuffer )
return 'break'
#@-node:mork.20041030164547.12:executeLastMacro
#@+node:mork.20041030164547.13:nameLastMacro
def nameLastMacro( self, event ):
'''Names the last macro defined.'''
#global macroing
svar, label = self.getSvarLabel( event )
if not self.macroing :
self.macroing = 2
svar.set( '' )
self.setLabelBlue( label )
return 'break'
if event.keysym == 'Return':
name = svar.get()
self._addToDoAltX( name, self.lastMacro )
svar.set( '' )
self.setLabelBlue( label )
self.macroing = False
self.stopControlX( event )
return 'break'
self.setSvar( event, svar )
return 'break'
#@-node:mork.20041030164547.13:nameLastMacro
#@+node:mork.20041030164547.14:_addToDoAltX
def _addToDoAltX( self, name, macro ):
'''Adds macro to Alt-X commands.'''
if not self.doAltX.has_key( name ):
def exe( event, macro = macro ):
self.stopControlX( event )
return self._executeMacro( macro, event.widget )
self.doAltX[ name ] = exe
self.namedMacros[ name ] = macro
return True
else:
return False
#@-node:mork.20041030164547.14:_addToDoAltX
#@+node:mork.20041030164547.15:loadMacros
def loadMacros( self,event ):
'''Asks for a macro file name to load.'''
import tkFileDialog
f = tkFileDialog.askopenfile()
if f == None: return 'break'
else:
return self._loadMacros( f )
#@-node:mork.20041030164547.15:loadMacros
#@+node:mork.20041030164547.16:_loadMacros
def _loadMacros( self, f ):
'''Loads a macro file into the macros dictionary.'''
import cPickle
macros = cPickle.load( f )
for z in macros:
self._addToDoAltX( z, macros[ z ] )
return 'break'
#@-node:mork.20041030164547.16:_loadMacros
#@+node:mork.20041030164547.17:getMacroName
def getMacroName( self, event ):
'''A method to save your macros to file.'''
#global macroing
svar, label = self.getSvarLabel( event )
if not self.macroing:
self.macroing = 3
svar.set('')
self.setLabelBlue( label )
return 'break'
if event.keysym == 'Return':
self.macroing = False
self.saveMacros( event, svar.get() )
return 'break'
if event.keysym == 'Tab':
svar.set( self._findMatch( svar, self.namedMacros ) )
return 'break'
self.setSvar( event, svar )
return 'break'
#@-node:mork.20041030164547.17:getMacroName
#@+node:mork.20041030164547.18:saveMacros
def saveMacros( self, event, macname ):
'''Asks for a file name and saves it.'''
import tkFileDialog
name = tkFileDialog.asksaveasfilename()
if name:
f = file( name, 'a+' )
f.seek( 0 )
if f:
self._saveMacros( f, macname )
return 'break'
#@-node:mork.20041030164547.18:saveMacros
#@+node:mork.20041030164547.19:_saveMacros
def _saveMacros( self, f , name ):
'''Saves the macros as a pickled dictionary'''
import cPickle
fname = f.name
try:
macs = cPickle.load( f )
except:
macs = {}
f.close()
if self.namedMacros.has_key( name ):
macs[ name ] = self.namedMacros[ name ]
f = file( fname, 'w' )
cPickle.dump( macs, f )
f.close()
#@-node:mork.20041030164547.19:_saveMacros
#@-others
#@nonl
#@-node:mork.20041031155753:macro methods
#@+node:mork.20041031194703:comment column methods
#@+others
#@+node:mork.20041030164547.20:setCommentColumn
#self.ccolumn = '0'
def setCommentColumn( self, event ):
#global ccolumn
cc= event.widget.index( 'insert' )
cc1, cc2 = cc.split( '.' )
self.ccolumn = cc2
return 'break'
#@-node:mork.20041030164547.20:setCommentColumn
#@+node:mork.20041030164547.21:indentToCommentColumn
def indentToCommentColumn( self, event ):
tbuffer = event.widget
i = tbuffer.index( 'insert lineend' )
i1, i2 = i.split( '.' )
i2 = int( i2 )
c1 = int( self.ccolumn )
if i2 < c1:
wsn = c1 - i2
tbuffer.insert( 'insert lineend', ' '* wsn )
if i2 >= c1:
tbuffer.insert( 'insert lineend', ' ')
tbuffer.mark_set( 'insert', 'insert lineend' )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.21:indentToCommentColumn
#@-others
#@nonl
#@-node:mork.20041031194703:comment column methods
#@+node:mork.20041031182709:how many methods
#@+others
#@+node:mork.20041030164547.23:howMany
#self.howM = False
def howMany( self, event ):
#global howM
svar, label = self.getSvarLabel( event )
if event.keysym == 'Return':
tbuffer = event.widget
txt = tbuffer.get( '1.0', 'end' )
import re
reg1 = svar.get()
reg = re.compile( reg1 )
i = reg.findall( txt )
svar.set( '%s occurances found of %s' % (len(i), reg1 ) )
self.setLabelGrey( label )
#self.howM = False
self.mcStateManager.setState( 'howM', False )
return 'break'
self.setSvar( event, svar )
return 'break'
#@-node:mork.20041030164547.23:howMany
#@+node:mork.20041030164547.24:startHowMany
def startHowMany( self, event ):
#global howM
#self.howM = True
self.mcStateManager.setState( 'howM', True )
svar, label = self.getSvarLabel( event )
svar.set( '' )
self.setLabelBlue( label )
return 'break'
#@-node:mork.20041030164547.24:startHowMany
#@-others
#@nonl
#@-node:mork.20041031182709:how many methods
#@+node:mork.20041031155913:paragraph methods
#@+others
#@+node:mork.20041030164547.25:selectParagraph
def selectParagraph( self, event ):
tbuffer = event.widget
txt = tbuffer.get( 'insert linestart', 'insert lineend' )
txt = txt.lstrip().rstrip()
i = tbuffer.index( 'insert' )
if not txt:
while 1:
i = tbuffer.index( '%s + 1 lines' % i )
txt = tbuffer.get( '%s linestart' % i, '%s lineend' % i )
txt = txt.lstrip().rstrip()
if txt:
self._selectParagraph( tbuffer, i )
break
if tbuffer.index( '%s lineend' % i ) == tbuffer.index( 'end' ):
return 'break'
if txt:
while 1:
i = tbuffer.index( '%s - 1 lines' % i )
txt = tbuffer.get( '%s linestart' % i, '%s lineend' % i )
txt = txt.lstrip().rstrip()
if not txt or tbuffer.index( '%s linestart' % i ) == tbuffer.index( '1.0' ):
if not txt:
i = tbuffer.index( '%s + 1 lines' % i )
self._selectParagraph( tbuffer, i )
break
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.25:selectParagraph
#@+node:mork.20041030164547.26:_selectParagraph
def _selectParagraph( self, tbuffer, start ):
i2 = start
while 1:
txt = tbuffer.get( '%s linestart' % i2, '%s lineend' % i2 )
if tbuffer.index( '%s lineend' % i2 ) == tbuffer.index( 'end' ):
break
txt = txt.lstrip().rstrip()
if not txt: break
else:
i2 = tbuffer.index( '%s + 1 lines' % i2 )
tbuffer.tag_add( 'sel', '%s linestart' % start, '%s lineend' % i2 )
tbuffer.mark_set( 'insert', '%s lineend' % i2 )
#@-node:mork.20041030164547.26:_selectParagraph
#@+node:mork.20041030164547.27:killParagraph
def killParagraph( self, event ):
tbuffer = event.widget
i = tbuffer.index( 'insert' )
txt = tbuffer.get( 'insert linestart', 'insert lineend' )
if not txt.rstrip().lstrip():
i = tbuffer.search( r'\w', i, regexp = True, stopindex = 'end' )
self._selectParagraph( tbuffer, i )
i2 = tbuffer.index( 'insert' )
self.kill( event, i, i2 )
tbuffer.mark_set( 'insert', i )
tbuffer.selection_clear()
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.27:killParagraph
#@+node:mork.20041030164547.28:backwardKillParagraph
def backwardKillParagraph( self, event ):
tbuffer = event.widget
i = tbuffer.index( 'insert' )
i2 = i
txt = tbuffer.get( 'insert linestart', 'insert lineend' )
if not txt.rstrip().lstrip():
self.movingParagraphs( event, -1 )
i2 = tbuffer.index( 'insert' )
self.selectParagraph( event )
i3 = tbuffer.index( 'sel.first' )
self.kill( event, i3, i2 )
tbuffer.mark_set( 'insert', i )
tbuffer.selection_clear()
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.28:backwardKillParagraph
#@-others
#@nonl
#@-node:mork.20041031155913:paragraph methods
#@+node:mork.20041031181929:kill methods
#@+at
# These methods add text to the killbuffer.
#@-at
#@@c
#@+others
#@+node:mork.20041030164547.34:kill
def kill( self, event, frm, to ):
tbuffer = event.widget
text = tbuffer.get( frm, to )
self.addToKillBuffer( text )
tbuffer.clipboard_clear()
tbuffer.clipboard_append( text )
if frm == 'insert' and to =='insert lineend' and tbuffer.index( frm ) == tbuffer.index( to ):
tbuffer.delete( 'insert', 'insert lineend +1c' )
self.addToKillBuffer( '\n' )
else:
tbuffer.delete( frm, to )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.34:kill
#@+node:mork.20041030164547.36:walkKB
def walkKB( self, event, frm, which ):# kb = self.iterateKillBuffer() ):
#if not kb1:
# kb1.append( self.iterateKillBuffer() )
#kb = kb1[ 0 ]
#global reset
tbuffer = event.widget
i = tbuffer.index( 'insert' )
t , t1 = i.split( '.' )
clip_text = self.getClipboard( tbuffer )
if self.killbuffer or clip_text:
if which == 'c':
self.reset = True
if clip_text:
txt = clip_text
else:
txt = self.kbiterator.next()
tbuffer.tag_delete( 'kb' )
tbuffer.insert( frm, txt, ('kb') )
tbuffer.mark_set( 'insert', i )
else:
if clip_text:
txt = clip_text
else:
txt = self.kbiterator.next()
t1 = str( int( t1 ) + len( txt ) )
r = tbuffer.tag_ranges( 'kb' )
if r and r[ 0 ] == i:
tbuffer.delete( r[ 0 ], r[ -1 ] )
tbuffer.tag_delete( 'kb' )
tbuffer.insert( frm, txt, ('kb') )
tbuffer.mark_set( 'insert', i )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.36:walkKB
#@+node:mork.20041030164547.35:deletelastWord
def deletelastWord( self, event ):
#tbuffer = event.widget
#i = tbuffer.get( 'insert' )
self.moveword( event, -1 )
self.kill( event, 'insert', 'insert wordend')
self.moveword( event ,1 )
return 'break'
#@-node:mork.20041030164547.35:deletelastWord
#@+node:mork.20041030164547.37:killsentence
def killsentence( self, event, back = False ):
tbuffer = event.widget
i = tbuffer.search( '.' , 'insert', stopindex = 'end' )
if back:
i = tbuffer.search( '.' , 'insert', backwards = True, stopindex = '1.0' )
if i == '':
return 'break'
i2 = tbuffer.search( '.' , i, backwards = True , stopindex = '1.0' )
if i2 == '':
i2 = '1.0'
return self.kill( event, i2, '%s + 1c' % i )
#return self.kill( event , '%s +1c' % i, 'insert' )
else:
i = tbuffer.search( '.' , 'insert', stopindex = 'end' )
i2 = tbuffer.search( '.', 'insert', backwards = True, stopindex = '1.0' )
if i2 == '':
i2 = '1.0'
else:
i2 = i2 + ' + 1c '
if i == '': return 'break'
return self.kill( event, i2, '%s + 1c' % i )
#@-node:mork.20041030164547.37:killsentence
#@+node:mork.20041030164547.91:killRegion
def killRegion( self, event, which ):
mrk = 'sel'
tbuffer = event.widget
trange = tbuffer.tag_ranges( mrk )
if len( trange ) != 0:
txt = tbuffer.get( trange[ 0 ] , trange[ -1 ] )
if which == 'd':
tbuffer.delete( trange[ 0 ], trange[ -1 ] )
self.addToKillBuffer( txt )
tbuffer.clipboard_clear()
tbuffer.clipboard_append( txt )
self.removeRKeys( tbuffer )
return 'break'
#@-node:mork.20041030164547.91:killRegion
#@+node:mork.20041030164547.42:addToKillBuffer
#self.killbuffer = []
def addToKillBuffer( self, text ):
#global reset
self.reset = True
if self.previousStroke in ( '<Control-k>', '<Control-w>' ,
'<Alt-d>', '<Alt-Delete', '<Alt-z>', '<Delete>',
'<Control-Alt-w>' ) and len( self.killbuffer):
self.killbuffer[ 0 ] = self.killbuffer[ 0 ] + text
return
self.killbuffer.insert( 0, text )
#@-node:mork.20041030164547.42:addToKillBuffer
#@+node:mork.20041030164547.29:iterateKillBuffer
#self.reset = False
def iterateKillBuffer( self ):
#global reset
while 1:
if self.killbuffer:
self.last_clipboard = None
for z in self.killbuffer:
if self.reset:
self.reset = False
break
yield z
#@-node:mork.20041030164547.29:iterateKillBuffer
#@+node:mork.20041103120919:getClipboard
def getClipboard( self, tbuffer ):
ctxt = None
try:
ctxt = tbuffer.selection_get( selection='CLIPBOARD' )
if ctxt != self.last_clipboard or not self.killbuffer:
self.last_clipboard = ctxt
if self.killbuffer and self.killbuffer[ 0 ] == ctxt:
return None
return ctxt
else:
return None
except:
return None
return None
#@nonl
#@-node:mork.20041103120919:getClipboard
#@-others
#@nonl
#@-node:mork.20041031181929:kill methods
#@+node:mork.20041031155642:register methods
#@+at
# These methods add things to the registers( a-z )
#
#@-at
#@@c
#@+others
#@+node:mork.20041030164547.44:copyToRegister
#self.registers = {}
def copyToRegister( self, event ):
if not self._chckSel( event ):
return
if event.keysym in string.letters:
event.keysym = event.keysym.lower()
tbuffer = event.widget
txt = tbuffer.get( 'sel.first', 'sel.last' )
self.registers[ event.keysym ] = txt
return
self.stopControlX( event )
#@-node:mork.20041030164547.44:copyToRegister
#@+node:mork.20041030164547.45:copyRectangleToRegister
def copyRectangleToRegister( self, event ):
if not self._chckSel( event ):
return
if event.keysym in string.letters:
event.keysym = event.keysym.lower()
tbuffer = event.widget
r1, r2, r3, r4 = self.getRectanglePoints( event )
rect = []
while r1 <= r3:
txt = tbuffer.get( '%s.%s' %( r1, r2 ), '%s.%s' %( r1, r4 ) )
rect.append( txt )
r1 = r1 +1
self.registers[ event.keysym ] = rect
self.stopControlX( event )
#@-node:mork.20041030164547.45:copyRectangleToRegister
#@+node:mork.20041030164547.46:prependToRegister
def prependToRegister( self, event ):
#global regMeth, registermode, controlx, registermode
event.keysym = 'p'
self.setNextRegister( event )
self.mcStateManager.setState( 'controlx', False )
#self.controlx = True
#@-node:mork.20041030164547.46:prependToRegister
#@+node:mork.20041030164547.47:appendToRegister
def appendToRegister( self, event ):
#global regMeth, registermode, controlx
event.keysym = 'a'
self.setNextRegister( event )
self.mcStateManager.setState( 'controlx', True )
#self.controlx = True
#@-node:mork.20041030164547.47:appendToRegister
#@+node:mork.20041030164547.49:_ToReg
def _ToReg( self, event , which):
if not self._chckSel( event ):
return
if self._checkIfRectangle( event ):
return
if event.keysym in string.letters:
event.keysym = event.keysym.lower()
tbuffer = event.widget
if not self.registers.has_key( event.keysym ):
self.registers[ event.keysym ] = ''
txt = tbuffer.get( 'sel.first', 'sel.last' )
rtxt = self.registers[ event.keysym ]
if self.which == 'p':
txt = txt + rtxt
else:
txt = rtxt + txt
self.registers[ event.keysym ] = txt
return
#@-node:mork.20041030164547.49:_ToReg
#@+node:mork.20041030164547.48:_chckSel
def _chckSel( self, event ):
if not 'sel' in event.widget.tag_names():
return False
if not event.widget.tag_ranges( 'sel' ):
return False
return True
#@-node:mork.20041030164547.48:_chckSel
#@+node:mork.20041030164547.50:_checkIfRectangle
def _checkIfRectangle( self, event ):
if self.registers.has_key( event.keysym ):
if isinstance( self.registers[ event.keysym ], list ):
svar, label = self.getSvarLabel( event )
self.stopControlX( event )
svar.set( "Register contains Rectangle, not text" )
return True
return False
#@-node:mork.20041030164547.50:_checkIfRectangle
#@+node:mork.20041030164547.51:insertFromRegister
def insertFromRegister( self, event ):
tbuffer = event.widget
if self.registers.has_key( event.keysym ):
if isinstance( self.registers[ event.keysym ], list ):
self.yankRectangle( event, self.registers[ event.keysym ] )
else:
tbuffer.insert( 'insert', self.registers[ event.keysym ] )
tbuffer.event_generate( '<Key>' )
tbuffer.update_idletasks()
self.stopControlX( event )
#@-node:mork.20041030164547.51:insertFromRegister
#@+node:mork.20041030164547.52:incrementRegister
def incrementRegister( self, event ):
if self.registers.has_key( event.keysym ):
if self._checkIfRectangle( event ):
return
if self.registers[ event.keysym ] in string.digits:
i = self.registers[ event.keysym ]
i = str( int( i ) + 1 )
self.registers[ event.keysym ] = i
else:
self.invalidRegister( event, 'number' )
return
self.stopControlX( event )
#@-node:mork.20041030164547.52:incrementRegister
#@+node:mork.20041030164547.53:numberToRegister
def numberToRegister( self, event ):
if event.keysym in string.letters:
self.registers[ event.keysym.lower() ] = str( 0 )
self.stopControlX( event )
#@-node:mork.20041030164547.53:numberToRegister
#@+node:mork.20041030164547.54:pointToRegister
def pointToRegister( self, event ):
if event.keysym in string.letters:
tbuffer = event.widget
self.registers[ event.keysym.lower() ] = tbuffer.index( 'insert' )
self.stopControlX( event )
#@-node:mork.20041030164547.54:pointToRegister
#@+node:mork.20041030164547.55:jumpToRegister
def jumpToRegister( self, event ):
if event.keysym in string.letters:
if self._checkIfRectangle( event ):
return
tbuffer = event.widget
i = self.registers[ event.keysym.lower() ]
i2 = i.split( '.' )
if len( i2 ) == 2:
if i2[ 0 ].isdigit() and i2[ 1 ].isdigit():
pass
else:
self.invalidRegister( event, 'index' )
return
else:
self.invalidRegister( event, 'index' )
return
tbuffer.mark_set( 'insert', i )
tbuffer.event_generate( '<Key>' )
tbuffer.update_idletasks()
self.stopControlX( event )
#@-node:mork.20041030164547.55:jumpToRegister
#@+node:mork.20041030164547.56:invalidRegister
def invalidRegister( self, event, what ):
self.deactivateRegister( event )
svar, label = self.getSvarLabel( event )
svar.set( 'Register does not contain valid %s' % what)
return
#@-node:mork.20041030164547.56:invalidRegister
#@+node:mork.20041030164547.57:setNextRegister
def setNextRegister( self, event ):
#global regMeth, registermode
if event.keysym == 'Shift':
return
if self.regMeths.has_key( event.keysym ):
self.mcStateManager.setState( 'controlx', True )
self.regMeth = self.regMeths[ event.keysym ]
self.registermode = 2
svar = self.svars[ event.widget ]
svar.set( self.regText[ event.keysym ] )
return
self.stopControlX( event )
#@-node:mork.20041030164547.57:setNextRegister
#@+node:mork.20041030164547.58:executeRegister
def executeRegister( self, event ):
self.regMeth( event )
if self.registermode:
self.stopControlX( event )
return
#@-node:mork.20041030164547.58:executeRegister
#@+node:mork.20041030164547.59:deactivateRegister
def deactivateRegister( self, event ):
#global registermode, regMeth
svar, label = self.getSvarLabel( event )
svar.set( '' )
self.setLabelGrey( label )
self.registermode = False
self.regMeth = None
#@-node:mork.20041030164547.59:deactivateRegister
#@+node:mork.20041102151545:viewRegister
def viewRegister( self, event ):
self.stopControlX( event )
if event.keysym in string.letters:
text = self.registers[ event.keysym.lower() ]
svar, label = self.getSvarLabel( event )
svar.set( text )
#@nonl
#@-node:mork.20041102151545:viewRegister
#@-others
#@nonl
#@-node:mork.20041031155642:register methods
#@+node:mork.20041031181701:abbreviation methods
#@+at
#
# type some text, set its abbreviation with Control-x a i g, type the text
# for abbreviation expansion
# type Control-x a e ( or Alt-x expand-abbrev ) to expand abbreviation
# type Alt-x abbrev-on to turn on automatic abbreviation expansion
# Alt-x abbrev-on to turn it off
#
# an example:
# type:
# frogs
# after typing 's' type Control-x a i g. This will turn the minibuffer
# blue, type in your definition. For example: turtles.
#
# Now in the buffer type:
# frogs
# after typing 's' type Control-x a e. This will turn the 'frogs' into:
# turtles
#
#
#
#@-at
#@@c
#@+others
#@+node:mork.20041030164547.60:abbreviationDispatch
#self.abbrevMode = False
#self.abbrevOn = False
#self.abbrevs = {}
def abbreviationDispatch( self, event, which ):
#global abbrevMode
#if not self.abbrevMode:
aM = self.mcStateManager.getState( 'abbrevMode' )
if not aM:
#self.abbrevMode = which
self.mcStateManager.setState( 'abbrevMode', which )
svar, label = self.getSvarLabel( event )
svar.set( '' )
self.setLabelBlue( label )
return 'break'
if aM:
self.abbrevCommand1( event )
return 'break'
#@-node:mork.20041030164547.60:abbreviationDispatch
#@+node:mork.20041030164547.61:abbrevCommand1
def abbrevCommand1( self, event ):
#global abbrevMode
if event.keysym == 'Return':
tbuffer = event.widget
word = tbuffer.get( 'insert -1c wordstart', 'insert -1c wordend' )
if word == ' ': return
svar, label = self.getSvarLabel( event )
aM = self.mcStateManager.getState( 'abbrevMode' )
if aM == 1:
self.abbrevs[ svar.get() ] = word
elif aM == 2:
self.abbrevs[ word ] = svar.get()
#self.abbrevMode = False
#self.mcStateManager.setState( 'abbrevMode', False )
self.keyboardQuit( event )
self.resetMiniBuffer( event )
return 'break'
svar, label = self.getSvarLabel( event )
self.setSvar( event, svar )
return 'break'
#@-node:mork.20041030164547.61:abbrevCommand1
#@+node:mork.20041030164547.62:expandAbbrev
def expandAbbrev( self,event ):
tbuffer = event.widget
word = tbuffer.get( 'insert -1c wordstart', 'insert -1c wordend' )
c = event.char.strip()
if c: #We have to do this because this method is called from Alt-x and Control-x, we get two differnt types of data and tbuffer states.
word = '%s%s' %( word, event.char )
if self.abbrevs.has_key( word ):
tbuffer.delete( 'insert -1c wordstart', 'insert -1c wordend' )
tbuffer.insert( 'insert', self.abbrevs[ word ] )
return self._tailEnd( tbuffer )
#return True
else: return False
#@-node:mork.20041030164547.62:expandAbbrev
#@+node:mork.20041030164547.63:regionalExpandAbbrev
#self.regXRpl = None
#self.regXKey = None
def regionalExpandAbbrev( self, event ):
#global regXRpl
if not self._chckSel( event ):
return
tbuffer = event.widget
i1 = tbuffer.index( 'sel.first' )
i2 = tbuffer.index( 'sel.last' )
ins = tbuffer.index( 'insert' )
#@ << define a new generator searchXR >>
#@+node:ekr.20050527111832:<< define a new generator searchXR >>
# EKR: This is a generator (it contains a yield).
# EKR: To make this work we must define a new generator for each call to regionalExpandAbbrev.
def searchXR( i1 , i2, ins, event ):
tbuffer.tag_add( 'sXR', i1, i2 )
while i1:
tr = tbuffer.tag_ranges( 'sXR' )
if not tr: break
i1 = tbuffer.search( r'\w', i1, stopindex = tr[ 1 ] , regexp = True )
if i1:
word = tbuffer.get( '%s wordstart' % i1, '%s wordend' % i1 )
tbuffer.tag_delete( 'found' )
tbuffer.tag_add( 'found', '%s wordstart' % i1, '%s wordend' % i1 )
tbuffer.tag_config( 'found', background = 'yellow' )
if self.abbrevs.has_key( word ):
svar, label = self.getSvarLabel( event )
svar.set( 'Replace %s with %s? y/n' % ( word, self.abbrevs[ word ] ) )
yield None
if self.regXKey == 'y':
ind = tbuffer.index( '%s wordstart' % i1 )
tbuffer.delete( '%s wordstart' % i1, '%s wordend' % i1 )
tbuffer.insert( ind, self.abbrevs[ word ] )
i1 = '%s wordend' % i1
tbuffer.mark_set( 'insert', ins )
tbuffer.selection_clear()
tbuffer.tag_delete( 'sXR' )
tbuffer.tag_delete( 'found' )
svar, label = self.getSvarLabel( event )
svar.set( '' )
self.setLabelGrey( label )
self._setRAvars()
#@nonl
#@-node:ekr.20050527111832:<< define a new generator searchXR >>
#@nl
# EKR: the 'result' of calling searchXR is a generator object.
self.regXRpl = searchXR( i1, i2, ins, event)
self.regXRpl.next() # Call it the first time.
return 'break'
#@nonl
#@-node:mork.20041030164547.63:regionalExpandAbbrev
#@+node:mork.20041030164547.64:_setRAvars
def _setRAvars( self ):
#global regXRpl, regXKey
self.regXRpl = self.regXKey = None
#@-node:mork.20041030164547.64:_setRAvars
#@+node:mork.20041030164547.65:killAllAbbrevs
def killAllAbbrevs( self, event ):
#global abbrevs
self.abbrevs = {}
return self.keyboardQuit( event )
#@-node:mork.20041030164547.65:killAllAbbrevs
#@+node:mork.20041030164547.66:toggleAbbrevMode
def toggleAbbrevMode( self, event ):
#global abbrevOn
#aO = self.mcStateManager.getState( 'abbrevOn' )
svar, label = self.getSvarLabel( event )
if self.abbrevOn:
self.abbrevOn = False
self.keyboardQuit( event )
svar.set( "Abbreviations are Off" )
#self.mcStateManager.setState( 'abbrevOn', False ) #This doesnt work too well with the mcStateManager
else:
self.abbrevOn = True
self.keyboardQuit( event )
svar.set( "Abbreviations are On" )
#self.mcStateManager.setState( 'abbrevOn', True )
#@-node:mork.20041030164547.66:toggleAbbrevMode
#@+node:mork.20041030164547.67:listAbbrevs
def listAbbrevs( self, event ):
svar, label = self.getSvarLabel( event )
txt = ''
for z in self.abbrevs:
txt = '%s%s=%s\n' %( txt, z, self.abbrevs[ z ] )
svar.set( '' )
svar.set( txt )
return 'break'
#@-node:mork.20041030164547.67:listAbbrevs
#@+node:mork.20041030164547.68:readAbbreviations
def readAbbreviations( self, event ):
import tkFileDialog
f = tkFileDialog.askopenfile()
if f == None: return 'break'
return self._readAbbrevs( f )
#@-node:mork.20041030164547.68:readAbbreviations
#@+node:mork.20041030164547.69:_readAbbrevs
def _readAbbrevs( self, f ):
for x in f:
a, b = x.split( '=' )
b = b[ : -1 ]
self.abbrevs[ a ] = b
f.close()
return 'break'
#@-node:mork.20041030164547.69:_readAbbrevs
#@+node:mork.20041030164547.70:writeAbbreviations
def writeAbbreviations( self, event ):
import tkFileDialog
f = tkFileDialog.asksaveasfile()
if f == None: return 'break'
return self._writeAbbrevs( f )
#@-node:mork.20041030164547.70:writeAbbreviations
#@+node:mork.20041030164547.71:_writeAbbrevs
def _writeAbbrevs( self, f ):
for x in self.abbrevs:
f.write( '%s=%s\n' %( x, self.abbrevs[ x ] ) )
f.close()
return 'break'
#@-node:mork.20041030164547.71:_writeAbbrevs
#@-others
#@nonl
#@-node:mork.20041031181701:abbreviation methods
#@+node:mork.20041031182137:paragraph methods
#@+at
#
# untested as of yet for .5 conversion.
#
#@-at
#@@c
#@+others
#@+node:mork.20041030164547.72:movingParagraphs
def movingParagraphs( self, event, way ):
tbuffer = event.widget
i = tbuffer.index( 'insert' )
if way == 1:
while 1:
txt = tbuffer.get( '%s linestart' % i, '%s lineend' %i )
txt = txt.rstrip().lstrip()
if not txt:
i = tbuffer.search( r'\w', i, regexp = True, stopindex = 'end' )
i = '%s' %i
break
else:
i = tbuffer.index( '%s + 1 lines' % i )
if tbuffer.index( '%s linestart' % i ) == tbuffer.index( 'end' ):
i = tbuffer.search( r'\w', 'end', backwards = True, regexp = True, stopindex = '1.0' )
i = '%s + 1c' % i
break
else:
while 1:
txt = tbuffer.get( '%s linestart' % i, '%s lineend' %i )
txt = txt.rstrip().lstrip()
if not txt:
i = tbuffer.search( r'\w', i, backwards = True, regexp = True, stopindex = '1.0' )
i = '%s +1c' %i
break
else:
i = tbuffer.index( '%s - 1 lines' % i )
if tbuffer.index( '%s linestart' % i ) == '1.0':
i = tbuffer.search( r'\w', '1.0', regexp = True, stopindex = 'end' )
break
if i :
tbuffer.mark_set( 'insert', i )
tbuffer.see( 'insert' )
return self._tailEnd( tbuffer )
return 'break'
#@-node:mork.20041030164547.72:movingParagraphs
#@+node:mork.20041030164547.74:fillParagraph
def fillParagraph( self, event ):
tbuffer = event.widget
txt = tbuffer.get( 'insert linestart', 'insert lineend' )
txt = txt.lstrip().rstrip()
if txt:
i = tbuffer.index( 'insert' )
i2 = i
txt2 = txt
while txt2:
pi2 = tbuffer.index( '%s - 1 lines' % i2)
txt2 = tbuffer.get( '%s linestart' % pi2, '%s lineend' % pi2 )
if tbuffer.index( '%s linestart' % pi2 ) == '1.0':
i2 = tbuffer.search( '\w', '1.0', regexp = True, stopindex = 'end' )
break
if txt2.lstrip().rstrip() == '': break
i2 = pi2
i3 = i
txt3 = txt
while txt3:
pi3 = tbuffer.index( '%s + 1 lines' %i3 )
txt3 = tbuffer.get( '%s linestart' % pi3, '%s lineend' % pi3 )
if tbuffer.index( '%s lineend' % pi3 ) == tbuffer.index( 'end' ):
i3 = tbuffer.search( '\w', 'end', backwards = True, regexp = True, stopindex = '1.0' )
break
if txt3.lstrip().rstrip() == '': break
i3 = pi3
ntxt = tbuffer.get( '%s linestart' %i2, '%s lineend' %i3 )
ntxt = self._addPrefix( ntxt )
tbuffer.delete( '%s linestart' %i2, '%s lineend' % i3 )
tbuffer.insert( i2, ntxt )
tbuffer.mark_set( 'insert', i )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.74:fillParagraph
#@+node:mork.20041030164547.76:fillRegionAsParagraph
def fillRegionAsParagraph( self, event ):
if not self._chckSel( event ):
return
tbuffer = event.widget
i1 = tbuffer.index( 'sel.first linestart' )
i2 = tbuffer.index( 'sel.last lineend' )
txt = tbuffer.get( i1, i2 )
txt = self._addPrefix( txt )
tbuffer.delete( i1, i2 )
tbuffer.insert( i1, txt )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.76:fillRegionAsParagraph
#@-others
#@nonl
#@-node:mork.20041031182137:paragraph methods
#@+node:mork.20041031182916:fill prefix methods
#@+others
#@+node:mork.20041030164547.73:setFillPrefix
#self.fillPrefix = ''
def setFillPrefix( self, event ):
#global fillPrefix
tbuffer = event.widget
txt = tbuffer.get( 'insert linestart', 'insert' )
self.fillPrefix = txt
return 'break'
#@-node:mork.20041030164547.73:setFillPrefix
#@+node:mork.20041030164547.75:_addPrefix
def _addPrefix( self, ntxt ):
ntxt = ntxt.split( '.' )
ntxt = map( lambda a: self.fillPrefix+a, ntxt )
ntxt = '.'.join( ntxt )
return ntxt
#@-node:mork.20041030164547.75:_addPrefix
#@-others
#@nonl
#@-node:mork.20041031182916:fill prefix methods
#@+node:mork.20041103085329:fill column and centering
#@+at
# These methods are currently just used in tandem to center the line or
# region within the fill column.
# for example, dependent upon the fill column, this text:
#
# cats
# raaaaaaaaaaaats
# mats
# zaaaaaaaaap
#
# may look like
#
# cats
# raaaaaaaaaaaats
# mats
# zaaaaaaaaap
# after an center-region command via Alt-x.
#
#
#@-at
#@@c
#@+others
#@+node:mork.20041103085329.1:centerLine
def centerLine( self, event ):
'''Centers line within current fillColumn'''
tbuffer = event.widget
ind = tbuffer.index( 'insert linestart' )
txt = tbuffer.get( 'insert linestart', 'insert lineend' )
txt = txt.strip()
if len( txt ) >= self.fillColumn: return self._tailEnd( tbuffer )
amount = ( self.fillColumn - len( txt ) ) / 2
ws = ' ' * amount
col, nind = ind.split( '.' )
ind = tbuffer.search( '\w', 'insert linestart', regexp = True, stopindex = 'insert lineend' )
if not ind: return 'break'
tbuffer.delete( 'insert linestart', '%s' % ind )
tbuffer.insert( 'insert linestart', ws )
return self._tailEnd( tbuffer )
#@-node:mork.20041103085329.1:centerLine
#@+node:mork.20041103095628:centerRegion
def centerRegion( self, event ):
'''This method centers the current region within the fill column'''
tbuffer = event.widget
start = tbuffer.index( 'sel.first linestart' )
sindex , x = start.split( '.' )
sindex = int( sindex )
end = tbuffer.index( 'sel.last linestart' )
eindex , x = end.split( '.' )
eindex = int( eindex )
while sindex <= eindex:
txt = tbuffer.get( '%s.0 linestart' % sindex , '%s.0 lineend' % sindex )
txt = txt.strip()
if len( txt ) >= self.fillColumn:
sindex = sindex + 1
continue
amount = ( self.fillColumn - len( txt ) ) / 2
ws = ' ' * amount
ind = tbuffer.search( '\w', '%s.0' % sindex, regexp = True, stopindex = '%s.0 lineend' % sindex )
if not ind:
sindex = sindex + 1
continue
tbuffer.delete( '%s.0' % sindex , '%s' % ind )
tbuffer.insert( '%s.0' % sindex , ws )
sindex = sindex + 1
return self._tailEnd( tbuffer )
#@-node:mork.20041103095628:centerRegion
#@+node:mork.20041103085329.2:setFillColumn
def setFillColumn( self, event ):
if self.mcStateManager.getState( 'set-fill-column' ):
if event.keysym == 'Return':
svar, label = self.getSvarLabel( event )
value = svar.get()
if value.isdigit():
self.fillColumn = int( value )
return self.keyboardQuit( event )
elif event.char.isdigit() or event.char == '\b':
svar, label = self.getSvarLabel( event )
self.setSvar( event, svar )
return 'break'
return 'break'
else:
self.mcStateManager.setState( 'set-fill-column', 1 )
svar, label = self.getSvarLabel( event )
svar.set( '' )
label.configure( background = 'lightblue' )
return 'break'
#@-node:mork.20041103085329.2:setFillColumn
#@-others
#@-node:mork.20041103085329:fill column and centering
#@+node:mork.20041031183136:region methods
#@+others
#@+node:mork.20041030164547.77:fillRegion
def fillRegion( self, event ):
if not self._chckSel( event ):
return
tbuffer = event.widget
#i = tbuffer.index( 'insert' )
s1 = tbuffer.index( 'sel.first' )
s2 = tbuffer.index( 'sel.last' )
tbuffer.mark_set( 'insert', s1 )
self.movingParagraphs( event, -1 )
if tbuffer.index( 'insert linestart' ) == '1.0':
self.fillParagraph( event )
while 1:
self.movingParagraphs( event, 1 )
if tbuffer.compare( 'insert', '>', s2 ):
break
self.fillParagraph( event )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.77:fillRegion
#@+node:mork.20041030164547.87:setRegion
def setRegion( self, event ):
mrk = 'sel'
tbuffer = event.widget
def extend( event ):
widget = event.widget
widget.mark_set( 'insert', 'insert + 1c' )
if self.inRange( widget, mrk ):
widget.tag_remove( mrk, 'insert -1c' )
else:
widget.tag_add( mrk, 'insert -1c' )
widget.tag_configure( mrk, background = 'lightgrey' )
self.testinrange( widget )
return 'break'
def truncate( event ):
widget = event.widget
widget.mark_set( 'insert', 'insert -1c' )
if self.inRange( widget, mrk ):
self.testinrange( widget )
widget.tag_remove( mrk, 'insert' )
else:
widget.tag_add( mrk, 'insert' )
widget.tag_configure( mrk, background = 'lightgrey' )
self.testinrange( widget )
return 'break'
def up( event ):
widget = event.widget
if not self.testinrange( widget ):
return 'break'
widget.tag_add( mrk, 'insert linestart', 'insert' )
i = widget.index( 'insert' )
i1, i2 = i.split( '.' )
i1 = str( int( i1 ) - 1 )
widget.mark_set( 'insert', i1+'.'+i2)
widget.tag_add( mrk, 'insert', 'insert lineend + 1c' )
if self.inRange( widget, mrk ,l = '-1c', r = '+1c') and widget.index( 'insert' ) != '1.0':
widget.tag_remove( mrk, 'insert', 'end' )
return 'break'
def down( event ):
widget = event.widget
if not self.testinrange( widget ):
return 'break'
widget.tag_add( mrk, 'insert', 'insert lineend' )
i = widget.index( 'insert' )
i1, i2 = i.split( '.' )
i1 = str( int( i1 ) + 1 )
widget.mark_set( 'insert', i1 +'.'+i2 )
widget.tag_add( mrk, 'insert linestart -1c', 'insert' )
if self.inRange( widget, mrk , l = '-1c', r = '+1c' ):
widget.tag_remove( mrk, '1.0', 'insert' )
return 'break'
extend( event )
tbuffer.bind( '<Right>', extend, '+' )
tbuffer.bind( '<Left>', truncate, '+' )
tbuffer.bind( '<Up>', up, '+' )
tbuffer.bind( '<Down>', down, '+' )
return 'break'
#@-node:mork.20041030164547.87:setRegion
#@+node:mork.20041030164547.93:indentRegion
def indentRegion( self, event ):
tbuffer = event.widget
mrk = 'sel'
trange = tbuffer.tag_ranges( mrk )
if len( trange ) != 0:
ind = tbuffer.search( '\w', '%s linestart' % trange[ 0 ], stopindex = 'end', regexp = True )
if not ind : return
text = tbuffer.get( '%s linestart' % ind , '%s lineend' % ind)
sstring = text.lstrip()
sstring = sstring[ 0 ]
ws = text.split( sstring )
if len( ws ) > 1:
ws = ws[ 0 ]
else:
ws = ''
s , s1 = trange[ 0 ].split( '.' )
e , e1 = trange[ -1 ].split( '.' )
s = int( s )
s = s + 1
e = int( e ) + 1
for z in xrange( s , e ):
t2 = tbuffer.get( '%s.0' %z , '%s.0 lineend'%z)
t2 = t2.lstrip()
t2 = ws + t2
tbuffer.delete( '%s.0' % z , '%s.0 lineend' %z)
tbuffer.insert( '%s.0' % z, t2 )
tbuffer.event_generate( '<Key>' )
tbuffer.update_idletasks()
self.removeRKeys( tbuffer )
return 'break'
#@-node:mork.20041030164547.93:indentRegion
#@+node:mork.20041030164547.94:tabIndentRegion
def tabIndentRegion( self,event ):
tbuffer = event.widget
if not self._chckSel( event ):
return
i = tbuffer.index( 'sel.first' )
i2 = tbuffer.index( 'sel.last' )
i = tbuffer.index( '%s linestart' %i )
i2 = tbuffer.index( '%s linestart' % i2)
while 1:
tbuffer.insert( i, '\t' )
if i == i2: break
i = tbuffer.index( '%s + 1 lines' % i )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.94:tabIndentRegion
#@+node:mork.20041030164547.102:countRegion
def countRegion( self, event ):
tbuffer = event.widget
txt = tbuffer.get( 'sel.first', 'sel.last')
svar = self.svars[ tbuffer ]
lines = 1
chars = 0
for z in txt:
if z == '\n': lines = lines + 1
else:
chars = chars + 1
svar.set( 'Region has %s lines, %s characters' %( lines, chars ) )
return 'break'
#@-node:mork.20041030164547.102:countRegion
#@+node:mork.20041030164547.138:reverseRegion
def reverseRegion( self, event ):
tbuffer = event.widget
if not self._chckSel( event ):
return
ins = tbuffer.index( 'insert' )
is1 = tbuffer.index( 'sel.first' )
is2 = tbuffer.index( 'sel.last' )
txt = tbuffer.get( '%s linestart' % is1, '%s lineend' %is2 )
tbuffer.delete( '%s linestart' % is1, '%s lineend' %is2 )
txt = txt.split( '\n' )
txt.reverse()
istart = is1.split( '.' )
istart = int( istart[ 0 ] )
for z in txt:
tbuffer.insert( '%s.0' % istart, '%s\n' % z )
istart = istart + 1
tbuffer.mark_set( 'insert', ins )
self.mcStateManager.clear()
self.resetMiniBuffer( event )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.138:reverseRegion
#@+node:mork.20041030164547.149:upperLowerRegion
def upperLowerRegion( self, event, way ):
tbuffer = event.widget
mrk = 'sel'
trange = tbuffer.tag_ranges( mrk )
if len( trange ) != 0:
text = tbuffer.get( trange[ 0 ] , trange[ -1 ] )
i = tbuffer.index( 'insert' )
if text == ' ': return 'break'
tbuffer.delete( trange[ 0 ], trange[ -1 ] )
if way == 'low':
text = text.lower()
if way == 'up':
text = text.upper()
tbuffer.insert( 'insert', text )
tbuffer.mark_set( 'insert', i )
self.removeRKeys( tbuffer )
return 'break'
#@-node:mork.20041030164547.149:upperLowerRegion
#@-others
#@nonl
#@-node:mork.20041031183136:region methods
#@+node:mork.20041122190403:searching
#@+at
# A tremendous variety of searching methods are available.
#
#@-at
#@@c
#@+others
#@+node:mork.20041031182837:incremental search methods
#@+at
# These methods enable the incremental search functionality.
#
#@-at
#@@c
#@+others
#@+node:mork.20041030164547.79:startIncremental
def startIncremental( self, event, stroke, which='normal' ):
#global isearch, pref
#widget = event.widget
#if self.isearch:
isearch = self.mcStateManager.getState( 'isearch' )
if isearch:
self.search( event, way = self.csr[ stroke ], useregex = self.useRegex() )
self.pref = self.csr[ stroke ]
self.scolorizer( event )
return 'break'
else:
svar, label = self.getSvarLabel( event )
#self.isearch = True'
self.mcStateManager.setState( 'isearch', which )
self.pref = self.csr[ stroke ]
label.configure( background = 'lightblue' )
label.configure( textvariable = svar )
return 'break'
#@-node:mork.20041030164547.79:startIncremental
#@+node:mork.20041030164547.38:search
def search( self, event, way , useregex=False):
'''This method moves the insert spot to position that matches the pattern in the minibuffer'''
tbuffer = event.widget
svar, label = self.getSvarLabel( event )
stext = svar.get()
if stext == '': return 'break'
try:
if way == 'bak': #Means search backwards.
i = tbuffer.search( stext, 'insert', backwards = True, stopindex = '1.0' , regexp = useregex )
if not i: #If we dont find one we start again at the bottom of the buffer.
i = tbuffer.search( stext, 'end', backwards = True, stopindex = 'insert', regexp = useregex)
else: #Since its not 'bak' it means search forwards.
i = tbuffer.search( stext, "insert + 1c", stopindex = 'end', regexp = useregex )
if not i: #If we dont find one we start at the top of the buffer.
i = tbuffer.search( stext, '1.0', stopindex = 'insert', regexp = useregex )
except:
return 'break'
if not i or i.isspace(): return 'break'
tbuffer.mark_set( 'insert', i )
tbuffer.see( 'insert' )
#@-node:mork.20041030164547.38:search
#@+node:mork.20041030164547.80:iSearch
def iSearch( self, event, stroke ):
if len( event.char ) == 0: return
if stroke in self.csr: return self.startIncremental( event, stroke )
svar, label = self.getSvarLabel( event )
if event.keysym == 'Return':
if svar.get() == '':
return self.startNonIncrSearch( event, self.pref )
else:
return self.stopControlX( event )
#return self._tailEnd( event.widget )
widget = event.widget
label.configure( textvariable = svar )
#if event.keysym == 'Return':
# return self.stopControlX( event )
self.setSvar( event, svar )
if event.char != '\b':
stext = svar.get()
z = widget.search( stext , 'insert' , stopindex = 'insert +%sc' % len( stext ) )
if not z:
self.search( event, self.pref, useregex= self.useRegex() )
self.scolorizer( event )
return 'break'
#@-node:mork.20041030164547.80:iSearch
#@+node:mork.20041030164547.153:scolorizer
def scolorizer( self, event ):
tbuffer = event.widget
svar, label = self.getSvarLabel( event )
stext = svar.get()
tbuffer.tag_delete( 'color' )
tbuffer.tag_delete( 'color1' )
if stext == '': return 'break'
ind = '1.0'
while ind:
try:
ind = tbuffer.search( stext, ind, stopindex = 'end', regexp = self.useRegex() )
except:
break
if ind:
i, d = ind.split('.')
d = str(int( d ) + len( stext ))
index = tbuffer.index( 'insert' )
if ind == index:
tbuffer.tag_add( 'color1', ind, '%s.%s' % (i,d) )
tbuffer.tag_add( 'color', ind, '%s.%s' % (i, d) )
ind = i +'.'+d
tbuffer.tag_config( 'color', foreground = 'red' )
tbuffer.tag_config( 'color1', background = 'lightblue' )
#@-node:mork.20041030164547.153:scolorizer
#@+node:mork.20041121125455:useRegex
def useRegex( self ):
isearch = self.mcStateManager.getState( 'isearch' )
risearch = False
if isearch != 'normal':
risearch=True
return risearch
#@nonl
#@-node:mork.20041121125455:useRegex
#@-others
#@nonl
#@-node:mork.20041031182837:incremental search methods
#@+node:mork.20041122154604:non-incremental search methods
#@+at
# Accessed by Control-s Enter or Control-r Enter. Alt-x forward-search or
# backward-search, just looks for words...
#
#
#@-at
#@@c
#@+others
#@+node:mork.20041122154604.1:nonincrSearch
def nonincrSearch( self, event, stroke ):
if event.keysym in ('Control_L', 'Control_R' ): return
state = self.mcStateManager.getState( 'nonincr-search' )
svar, label = self.getSvarLabel( event )
if state.startswith( 'start' ):
state = state[ 5: ]
self.mcStateManager.setState( 'nonincr-search', state )
svar.set( '' )
if svar.get() == '' and stroke=='<Control-w>':
return self.startWordSearch( event, state )
if event.keysym == 'Return':
tbuffer = event.widget
i = tbuffer.index( 'insert' )
word = svar.get()
if state == 'for':
s = tbuffer.search( word, i , stopindex = 'end' )
if s:
s = tbuffer.index( '%s +%sc' %( s, len( word ) ) )
else:
s = tbuffer.search( word,i, stopindex = '1.0', backwards = True )
if s:
tbuffer.mark_set( 'insert', s )
self.keyboardQuit( event )
return self._tailEnd( tbuffer )
else:
self.setSvar( event, svar )
return 'break'
#@-node:mork.20041122154604.1:nonincrSearch
#@+node:mork.20041122155708:startNonIncrSearch
def startNonIncrSearch( self, event, which ):
self.keyboardQuit( event )
tbuffer = event.widget
self.mcStateManager.setState( 'nonincr-search', 'start%s' % which )
svar, label = self.getSvarLabel( event )
self.setLabelBlue( label )
svar.set( 'Search:' )
return 'break'
#@-node:mork.20041122155708:startNonIncrSearch
#@-others
#@nonl
#@-node:mork.20041122154604:non-incremental search methods
#@+node:mork.20041122171601:word search methods
#@+at
#
# Control-s(r) Enter Control-w words Enter, pattern entered is treated as
# a regular expression.
#
# for example in the buffer we see:
# cats......................dogs
# if we are after this and we enter the backwards look, search for 'cats
# dogs' if will take us to the match.
#
#@-at
#@@c
#@+others
#@+node:mork.20041122171601.1:startWordSearch
def startWordSearch( self, event, which ):
self.keyboardQuit( event )
tbuffer = event.widget
self.mcStateManager.setState( 'word-search', 'start%s' % which )
svar, label = self.getSvarLabel( event )
self.setLabelBlue( label )
if which == 'bak':
txt = 'Backward'
else:
txt = 'Forward'
svar.set( 'Word Search %s:' % txt )
return 'break'
#@-node:mork.20041122171601.1:startWordSearch
#@+node:mork.20041122171601.2:wordSearch
def wordSearch( self, event ):
state = self.mcStateManager.getState( 'word-search' )
svar, label = self.getSvarLabel( event )
if state.startswith( 'start' ):
state = state[ 5: ]
self.mcStateManager.setState( 'word-search', state )
svar.set( '' )
if event.keysym == 'Return':
tbuffer = event.widget
i = tbuffer.index( 'insert' )
words = svar.get().split()
sep = '[%s%s]+' %( string.punctuation, string.whitespace )
pattern = sep.join( words )
cpattern = re.compile( pattern )
if state == 'for':
txt = tbuffer.get( 'insert', 'end' )
match = cpattern.search( txt )
if not match: return self.keyboardQuit( event )
end = match.end()
else:
txt = tbuffer.get( '1.0', 'insert' ) #initially the reverse words formula for Python Cookbook was going to be used.
a = re.split( pattern, txt ) #that didnt quite work right. This one apparently does.
if len( a ) > 1:
b = re.findall( pattern, txt )
end = len( a[ -1 ] ) + len( b[ -1 ] )
else:
return self.keyboardQuit( event )
wdict ={ 'for': 'insert +%sc', 'bak': 'insert -%sc' }
tbuffer.mark_set( 'insert', wdict[ state ] % end )
tbuffer.see( 'insert' )
self.keyboardQuit( event )
return self._tailEnd( tbuffer )
else:
self.setSvar( event, svar )
return 'break'
#@nonl
#@-node:mork.20041122171601.2:wordSearch
#@-others
#@nonl
#@-node:mork.20041122171601:word search methods
#@+node:mork.20041121103034:re-search methods
#@+at
# For the re-search-backward and re-search-forward Alt-x commands
#
#@-at
#@@c
#@+others
#@+node:mork.20041121103034.1:reStart
def reStart( self, event, which='forward' ):
self.keyboardQuit( event )
tbuffer = event.widget
self.mcStateManager.setState( 're_search', 'start%s' % which )
svar, label = self.getSvarLabel( event )
label.configure( background = 'lightblue' )
svar.set( 'RE Search:' )
return 'break'
#@-node:mork.20041121103034.1:reStart
#@+node:mork.20041121103034.2:re_search
def re_search( self, event ):
svar, label = self.getSvarLabel( event )
state = self.mcStateManager.getState( 're_search' )
if state.startswith( 'start' ):
state = state[ 5: ]
self.mcStateManager.setState( 're_search', state )
svar.set( '' )
if event.keysym == 'Return':
tbuffer = event.widget
pattern = svar.get()
cpattern = re.compile( pattern )
end = None
if state == 'forward':
txt = tbuffer.get( 'insert', 'end' )
match = cpattern.search( txt )
end = match.end()
else:
txt = tbuffer.get( '1.0', 'insert' ) #initially the reverse words formula for Python Cookbook was going to be used.
a = re.split( pattern, txt ) #that didnt quite work right. This one apparently does.
if len( a ) > 1:
b = re.findall( pattern, txt )
end = len( a[ -1 ] ) + len( b[ -1 ] )
if end:
wdict ={ 'forward': 'insert +%sc', 'backward': 'insert -%sc' }
tbuffer.mark_set( 'insert', wdict[ state ] % end )
self._tailEnd( tbuffer )
tbuffer.see( 'insert' )
return self.keyboardQuit( event )
else:
self.setSvar( event, svar )
return 'break'
#@-node:mork.20041121103034.2:re_search
#@-others
#@nonl
#@-node:mork.20041121103034:re-search methods
#@-others
#@nonl
#@-node:mork.20041122190403:searching
#@+node:mork.20041121140620:diff methods
#@+at
# the diff command, accessed by Alt-x diff. Creates a buffer and puts the
# diff between 2 files into it.
#
#@-at
#@@c
#@+others
#@+node:mork.20041121140620.1:diff
def diff( self, event ):
try:
f, name = self.getReadableTextFile()
txt1 = f.read()
f.close()
f2, name2 = self.getReadableTextFile()
txt2 = f2.read()
f2.close()
except:
return self.keyboardQuit( event )
self.switchToBuffer( event, "*diff* of ( %s , %s )" %( name, name2 ) )
import difflib
data = difflib.ndiff( txt1, txt2 )
idata = []
for z in data:
idata.append( z )
tbuffer = event.widget
tbuffer.delete( '1.0', 'end' )
tbuffer.insert( '1.0', ''.join( idata ) )
self._tailEnd( tbuffer )
return self.keyboardQuit( event )
#@-node:mork.20041121140620.1:diff
#@-others
#@nonl
#@-node:mork.20041121140620:diff methods
#@+node:mork.20041031182332:Zap methods
#@+at
# These methods start and execute the Zap to functionality.
#@-at
#@@c
#@+others
#@+node:mork.20041030164547.81:startZap
def startZap( self, event ):
#global zap
#self.zap = True
self.mcStateManager.setState( 'zap', True )
svar, label = self.getSvarLabel( event )
label.configure( background = 'lightblue' )
svar.set( 'Zap To Character' )
return 'break'
#@-node:mork.20041030164547.81:startZap
#@+node:mork.20041030164547.82:zapTo
def zapTo( self, event ):
#global zap
widget = event.widget
s = string.ascii_letters + string.digits + string.punctuation
if len( event.char ) != 0 and event.char in s:
#self.zap = False
self.mcStateManager.setState( 'zap', False )
i = widget.search( event.char , 'insert', stopindex = 'end' )
self.resetMiniBuffer( event )
if i:
t = widget.get( 'insert', '%s+1c'% i )
self.addToKillBuffer( t )
widget.delete( 'insert', '%s+1c' % i)
return 'break'
else:
return 'break'
#@-node:mork.20041030164547.82:zapTo
#@-others
#@nonl
#@-node:mork.20041031182332:Zap methods
#@+node:mork.20041031181740:ControlX methods
#@+others
#@+node:mork.20041030164547.84:startControlX
def startControlX( self, event ):
'''This method starts the Control-X command sequence.'''
#global controlx
#self.controlx = True
self.mcStateManager.setState( 'controlx', True )
svar, label = self.getSvarLabel( event )
svar.set( 'Control - X' )
label.configure( background = 'lightblue' )
return 'break'
#@-node:mork.20041030164547.84:startControlX
#@+node:mork.20041030164547.85:stopControlX
def stopControlX( self, event ): #This will all be migrated to keyboardQuit eventually.
'''This method clears the state of the Emacs instance'''
#global controlx, rstring, isearch, sRect,negativeArg, uC, howM, altx
#self.altx = False
#self.howM = False
#self.controlx = False
#self.isearch = False
if self.shuttingdown: return
self.sRect = False
#self.uC = False
#self.negativeArg = False
self.mcStateManager.clear()
event.widget.tag_delete( 'color' )
event.widget.tag_delete( 'color1' )
if self.registermode:
self.deactivateRegister( event )
self.rectanglemode = 0
self.bufferMode = None
#self.rString = False
self.resetMiniBuffer( event )
event.widget.update_idletasks()
return 'break'
#@-node:mork.20041030164547.85:stopControlX
#@+node:mork.20041030164547.78:doControlX
#self.registermode = False
def doControlX( self, event, stroke, previous = [] ):
#global registermode
"""previous.insert( 0, event.keysym )
if len( previous ) > 10: previous.pop()
if stroke == '<Key>':
if event.keysym in ( 'Shift_L', 'Shift_R' ):
return
if event.keysym == 'period':
self.stopControlX( event )
return self.setFillPrefix( event )
if event.keysym == 'parenleft':
self.stopControlX( event )
return self.startKBDMacro( event )
if event.keysym == 'parenright':
self.stopControlX( event )
return self.stopKBDMacro( event )
if event.keysym == 'semicolon':
self.stopControlX( event )
return self.setCommentColumn( event )
if event.keysym == 'Tab':
self.stopControlX( event )
return self.tabIndentRegion( event )
if self.sRect:
self.stringRectangle( event )
return 'break'
if event.keysym in ( 'a', 'i' , 'e'):
svar, label = self.getSvarLabel( event )
if svar.get() != 'a' and event.keysym == 'a':
svar.set( 'a' )
return 'break'
elif svar.get() == 'a':
if event.char == 'i':
svar.set( 'a i' )
elif event.char == 'e':
self.stopControlX( event )
event.char = ''
self.expandAbbrev( event )
return 'break'
if event.keysym == 'g':
svar, label = self.getSvarLabel( event )
l = svar.get()
if l == 'a':
self.stopControlX( event )
return self.abbreviationDispatch( event, 1 )
elif l == 'a i':
self.stopControlX( event )
return self.abbreviationDispatch( event, 2 )
if event.keysym == 'e':
self.stopControlX( event )
return self.executeLastMacro( event )
if event.keysym == 'x' and previous[ 1 ] not in ( 'Control_L', 'Control_R'):
event.keysym = 's'
self.setNextRegister( event )
return 'break'
if event.keysym == 'o' and self.registermode == 1:
self.openRectangle( event )
return 'break'
if event.keysym == 'c' and self.registermode == 1:
self.clearRectangle( event )
return 'break'
if event.keysym == 't' and self.registermode == 1:
self.stringRectangle( event )
return 'break'
if event.keysym == 'y' and self.registermode == 1:
self.yankRectangle( event )
return 'break'
if event.keysym == 'd' and self.registermode == 1:
self.deleteRectangle( event )
return 'break'
if event.keysym == 'k' and self.registermode == 1:
self.killRectangle( event )
return 'break'
if self.registermode == 1:
self.setNextRegister( event )
return 'break'
elif self.registermode == 2:
self.executeRegister( event )
return 'break'
if event.keysym == 'r':
self.registermode = 1
svar = self.svars[ event.widget ]
svar.set( 'C - x r' )
return 'break'
if event.keysym== 'h':
self.stopControlX( event )
event.widget.tag_add( 'sel', '1.0', 'end' )
return 'break'
if event.keysym == 'equal':
self.lineNumber( event )
return 'break'
if event.keysym == 'u':
self.stopControlX( event )
return self.doUndo( event, 2 )
if stroke in self.xcommands:
self.xcommands[ stroke ]( event )
self.stopControlX( event )
return 'break' """
return self.cxHandler( event, stroke )
#@-node:mork.20041030164547.78:doControlX
#@-others
#@nonl
#@-node:mork.20041031181740:ControlX methods
#@+node:mork.20041031183614.1:range methods
#@+others
#@+node:mork.20041030164547.88:inRange
def inRange( self, widget, range, l = '', r = '' ):
ranges = widget.tag_ranges( range )
#i = widget.index( 'insert' )
for z in xrange( 0, len( ranges) , 2 ):
z1 = z + 1
l1 = 'insert%s' %l
r1 = 'insert%s' % r
if widget.compare( l1, '>=', ranges[ z ]) and widget.compare( r1, '<=', ranges[ z1] ):
return True
return False
#@-node:mork.20041030164547.88:inRange
#@+node:mork.20041030164547.89:contRanges
def contRanges( self, widget, range ):
ranges = widget.tag_ranges( range)
t1 = widget.get( ranges[ 0 ], ranges[ -1 ] )
t2 = []
for z in xrange( 0, len( ranges) , 2 ):
z1 = z + 1
t2.append( widget.get( ranges[ z ], ranges[ z1 ] ) )
t2 = '\n'.join( t2 )
return t1 == t2
#@-node:mork.20041030164547.89:contRanges
#@+node:mork.20041030164547.90:testinrange
def testinrange( self, widget ):
mrk = 'sel'
#ranges = widget.tag_ranges( mrk)
if not self.inRange( widget , mrk) or not self.contRanges( widget, mrk ):
self.removeRKeys( widget )
return False
return True
#@-node:mork.20041030164547.90:testinrange
#@-others
#@nonl
#@-node:mork.20041031183614.1:range methods
#@+node:mork.20041031182402:delete methods
#@+others
#@+node:mork.20041030164547.97:deleteIndentation
def deleteIndentation( self, event ):
tbuffer = event.widget
txt = tbuffer.get( 'insert linestart' , 'insert lineend' )
txt = ' %s' % txt.lstrip()
tbuffer.delete( 'insert linestart' , 'insert lineend +1c' )
i = tbuffer.index( 'insert - 1c' )
tbuffer.insert( 'insert -1c', txt )
tbuffer.mark_set( 'insert', i )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.97:deleteIndentation
#@+node:mork.20041030164547.98:deleteNextChar
def deleteNextChar( self,event ):
tbuffer = event.widget
i = tbuffer.index( 'insert' )
tbuffer.delete( i, '%s +1c' % i )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.98:deleteNextChar
#@+node:mork.20041030164547.99:deleteSpaces
def deleteSpaces( self, event , insertspace = False):
tbuffer = event.widget
char = tbuffer.get( 'insert', 'insert + 1c ' )
if char.isspace():
i = tbuffer.index( 'insert' )
wf = tbuffer.search( r'\w', i, stopindex = '%s lineend' % i, regexp = True )
wb = tbuffer.search( r'\w', i, stopindex = '%s linestart' % i, regexp = True, backwards = True )
if '' in ( wf, wb ):
return 'break'
tbuffer.delete( '%s +1c' %wb, wf )
if insertspace:
tbuffer.insert( 'insert', ' ' )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.99:deleteSpaces
#@-others
#@nonl
#@-node:mork.20041031182402:delete methods
#@+node:mork.20041031181701.1:query replace methods
#@+at
# These methods handle the query-replace and query-replace-regex
# commands. They need to be fully migrated
# to the self.mcStateManager mechanism, which should simplify things
# greatly, or at least the amount of variables its required
# so far.
#
#@-at
#@@c
#@+others
#@+node:mork.20041030164547.107:qreplace
def qreplace( self, event ):
if event.keysym == 'y':
self._qreplace( event )
return
elif event.keysym in ( 'q', 'Return' ):
self.quitQSearch( event )
elif event.keysym == 'exclam':
while self.qrexecute:
self._qreplace( event )
elif event.keysym in ( 'n', 'Delete'):
#i = event.widget.index( 'insert' )
event.widget.mark_set( 'insert', 'insert +%sc' % len( self.qQ ) )
self.qsearch( event )
event.widget.see( 'insert' )
#@-node:mork.20041030164547.107:qreplace
#@+node:mork.20041030164547.108:_qreplace
def _qreplace( self, event ):
i = event.widget.tag_ranges( 'qR' )
event.widget.delete( i[ 0 ], i[ 1 ] )
event.widget.insert( 'insert', self.qR )
self.qsearch( event )
#@-node:mork.20041030164547.108:_qreplace
#@+node:mork.20041030164547.109:getQuery
#self.qgetQuery = False
#self.lqQ = Tkinter.StringVar()
#self.lqQ.set( 'Replace with:' )
def getQuery( self, event ):
#global qQ, qgetQuery, qgetReplace
l = event.keysym
svar, label = self.getSvarLabel( event )
label.configure( textvariable = svar )
if l == 'Return':
self.qgetQuery = False
self.qgetReplace = True
self.qQ = svar.get()
svar.set( "Replace with:" )
self.mcStateManager.setState( 'qlisten', 'replace-caption' )
#label.configure( textvariable = self.lqQ)
return
if self.mcStateManager.getState( 'qlisten' ) == 'replace-caption':
svar.set( '' )
self.mcStateManager.setState( 'qlisten', True )
self.setSvar( event, svar )
#@-node:mork.20041030164547.109:getQuery
#@+node:mork.20041030164547.110:getReplace
#self.qgetReplace = False
def getReplace( self, event ):
#global qR, qgetReplace, qrexecute
l = event.keysym
svar, label = self.getSvarLabel( event )
label.configure( textvariable = svar )
if l == 'Return':
self.qgetReplace = False
self.qR = svar.get()
self.qrexecute = True
ok = self.qsearch( event )
if self.querytype == 'regex' and ok:
tbuffer = event.widget
range = tbuffer.tag_ranges( 'qR' )
txt = tbuffer.get( range[ 0 ], range[ 1 ] )
svar.set( 'Replace %s with %s y/n(! for all )' %( txt, self.qR ) )
elif ok:
svar.set( 'Replace %s with %s y/n(! for all )' %( self.qQ, self.qR ) )
#self.qrexecute = True
#ok = self.qsearch( event )
return
if self.mcStateManager.getState( 'qlisten' ) == 'replace-caption':
svar.set( '' )
self.mcStateManager.setState( 'qlisten', True )
self.setSvar( event, svar )
#@-node:mork.20041030164547.110:getReplace
#@+node:mork.20041030164547.111:masterQR
#self.qrexecute = False
def masterQR( self, event ):
if self.qgetQuery:
self.getQuery( event )
elif self.qgetReplace:
self.getReplace( event )
elif self.qrexecute:
self.qreplace( event )
else:
#svar, label = self.getSvarLabel( event )
#svar.set( '' )
self.listenQR( event )
return 'break'
#@-node:mork.20041030164547.111:masterQR
#@+node:mork.20041123113640:startRegexReplace
def startRegexReplace( self ):
self.querytype = 'regex'
return True
#@-node:mork.20041123113640:startRegexReplace
#@+node:mork.20041031194858:query search methods
#@+others
#@+node:mork.20041030164547.104:listenQR
#self.qQ = None
#self.qR = None
#self.qlisten = False
#self.lqR = Tkinter.StringVar()
#self.lqR.set( 'Query with: ' )
def listenQR( self, event ):
#global qgetQuery, qlisten
#self.qlisten = True
self.mcStateManager.setState( 'qlisten', 'replace-caption' )
#tbuffer = event.widget
svar, label = self.getSvarLabel( event )
self.setLabelBlue( label )
if self.querytype == 'regex':
svar.set( "Regex Query with:" )
else:
svar.set( "Query with:" )
#label.configure( background = 'lightblue' , textvariable = self.lqR)
self.qgetQuery = True
#@-node:mork.20041030164547.104:listenQR
#@+node:mork.20041030164547.105:qsearch
def qsearch( self, event ):
if self.qQ:
tbuffer = event.widget
tbuffer.tag_delete( 'qR' )
svar, label = self.getSvarLabel( event )
if self.querytype == 'regex':
try:
regex = re.compile( self.qQ )
except:
self.keyboardQuit( event )
svar.set( "Illegal regular expression" )
txt = tbuffer.get( 'insert', 'end' )
match = regex.search( txt )
if match:
start = match.start()
end = match.end()
length = end - start
tbuffer.mark_set( 'insert', 'insert +%sc' % start )
tbuffer.update_idletasks()
tbuffer.tag_add( 'qR', 'insert', 'insert +%sc' % length )
tbuffer.tag_config( 'qR', background = 'lightblue' )
txt = tbuffer.get( 'insert', 'insert +%sc' % length )
svar.set( "Replace %s with %s? y/n(! for all )" % ( txt, self.qR ) )
return True
else:
i = tbuffer.search( self.qQ, 'insert', stopindex = 'end' )
if i:
tbuffer.mark_set( 'insert', i )
tbuffer.update_idletasks()
tbuffer.tag_add( 'qR', 'insert', 'insert +%sc'% len( self.qQ ) )
tbuffer.tag_config( 'qR', background = 'lightblue' )
self._tailEnd( tbuffer )
return True
self.quitQSearch( event )
return False
#@-node:mork.20041030164547.105:qsearch
#@+node:mork.20041030164547.106:quitQSearch
def quitQSearch( self,event ):
#global qQ, qR, qlisten, qrexecute
event.widget.tag_delete( 'qR' )
self.qQ = None
self.qR = None
#self.qlisten = False
self.mcStateManager.setState( 'qlisten', False )
self.qrexecute = False
svar, label = self.getSvarLabel( event )
svar.set( '' )
label.configure( background = 'lightgrey' )
#self.keyboardQuit( event )
self.querytype = 'normal'
self._tailEnd( event.widget )
#event.widget.event_generate( '<Key>' )
#event.widget.update_idletasks()
#@-node:mork.20041030164547.106:quitQSearch
#@-others
#@nonl
#@-node:mork.20041031194858:query search methods
#@-others
#@nonl
#@-node:mork.20041031181701.1:query replace methods
#@+node:mork.20041031155313:Rectangles methods
#@+others
#@+node:mork.20041031202908:activateRectangleMethods
def activateRectangleMethods( self, event ):
self.rectanglemode = 1
svar = self.svars[ event.widget ]
svar.set( 'C - x r' )
return 'break'
#@-node:mork.20041031202908:activateRectangleMethods
#@+node:mork.20041030164547.120:openRectangle
def openRectangle( self, event ):
if not self._chckSel( event ):
return
tbuffer = event.widget
r1, r2, r3, r4 = self.getRectanglePoints( event )
lth = ' ' * ( r4 - r2 )
self.stopControlX( event )
while r1 <= r3:
tbuffer.insert( '%s.%s' % ( r1, r2 ) , lth)
r1 = r1 + 1
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.120:openRectangle
#@+node:mork.20041030164547.121:clearRectangle
def clearRectangle( self, event ):
if not self._chckSel( event ):
return
tbuffer = event.widget
r1, r2, r3, r4 = self.getRectanglePoints( event )
lth = ' ' * ( r4 - r2 )
self.stopControlX( event )
while r1 <= r3:
tbuffer.delete( '%s.%s' % ( r1, r2 ) , '%s.%s' % ( r1, r4 ) )
tbuffer.insert( '%s.%s' % ( r1, r2 ) , lth)
r1 = r1 + 1
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.121:clearRectangle
#@+node:mork.20041030164547.122:deleteRectangle
def deleteRectangle( self, event ):
if not self._chckSel( event ):
return
tbuffer = event.widget
r1, r2, r3, r4 = self.getRectanglePoints( event )
#lth = ' ' * ( r4 - r2 )
self.stopControlX( event )
while r1 <= r3:
tbuffer.delete( '%s.%s' % ( r1, r2 ) , '%s.%s' % ( r1, r4 ) )
r1 = r1 + 1
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.122:deleteRectangle
#@+node:mork.20041030164547.123:stringRectangle
#self.sRect = False
def stringRectangle( self, event ):
#global sRect
svar, label = self.getSvarLabel( event )
if not self.sRect:
self.sRect = 1
svar.set( 'String rectangle :' )
self.setLabelBlue( label )
return 'break'
if event.keysym == 'Return':
self.sRect = 3
if self.sRect == 1:
svar.set( '' )
self.sRect = 2
if self.sRect == 2:
self.setSvar( event, svar )
return 'break'
if self.sRect == 3:
if not self._chckSel( event ):
self.stopControlX( event )
return
tbuffer = event.widget
r1, r2, r3, r4 = self.getRectanglePoints( event )
lth = svar.get()
#self.stopControlX( event )
while r1 <= r3:
tbuffer.delete( '%s.%s' % ( r1, r2 ), '%s.%s' % ( r1, r4 ) )
tbuffer.insert( '%s.%s' % ( r1, r2 ) , lth )
r1 = r1 + 1
#i = tbuffer.index( 'insert' )
#tbuffer.mark_set( 'insert', 'insert wordend' )
#tbuffer.tag_remove( 'sel', '1.0', 'end' )
#return self._tailEnd( tbuffer )
self.stopControlX( event )
return self._tailEnd( tbuffer )
#return 'break'
#return 'break'
#tbuffer.mark_set( 'insert', i )
#return 'break'
#@-node:mork.20041030164547.123:stringRectangle
#@+node:mork.20041030164547.124:killRectangle
#self.krectangle = None
def killRectangle( self, event ):
#global krectangle
if not self._chckSel( event ):
return
tbuffer = event.widget
r1, r2, r3, r4 = self.getRectanglePoints( event )
#lth = ' ' * ( r4 - r2 )
self.stopControlX( event )
self.krectangle = []
while r1 <= r3:
txt = tbuffer.get( '%s.%s' % ( r1, r2 ) , '%s.%s' % ( r1, r4 ) )
self.krectangle.append( txt )
tbuffer.delete( '%s.%s' % ( r1, r2 ) , '%s.%s' % ( r1, r4 ) )
r1 = r1 + 1
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.124:killRectangle
#@+node:mork.20041030164547.125:closeRectangle
def closeRectangle( self, event ):
if not self._chckSel( event ):
return
tbuffer = event.widget
r1, r2, r3, r4 = self.getRectanglePoints( event )
ar1 = r1
txt = []
while ar1 <= r3:
txt.append( tbuffer.get( '%s.%s' %( ar1, r2 ), '%s.%s' %( ar1, r4 ) ) )
ar1 = ar1 + 1
for z in txt:
if z.lstrip().rstrip():
return
while r1 <= r3:
tbuffer.delete( '%s.%s' %(r1, r2 ), '%s.%s' %( r1, r4 ) )
r1 = r1 + 1
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.125:closeRectangle
#@+node:mork.20041030164547.126:yankRectangle
def yankRectangle( self, event , krec = None ):
self.stopControlX( event )
if not krec:
krec = self.krectangle
if not krec:
return 'break'
tbuffer = event.widget
txt = tbuffer.get( 'insert linestart', 'insert' )
txt = self.getWSString( txt )
i = tbuffer.index( 'insert' )
i1, i2 = i.split( '.' )
i1 = int( i1 )
for z in krec:
txt2 = tbuffer.get( '%s.0 linestart' % i1, '%s.%s' % ( i1, i2 ) )
if len( txt2 ) != len( txt ):
amount = len( txt ) - len( txt2 )
z = txt[ -amount : ] + z
tbuffer.insert( '%s.%s' %( i1, i2 ) , z )
if tbuffer.index( '%s.0 lineend +1c' % i1 ) == tbuffer.index( 'end' ):
tbuffer.insert( '%s.0 lineend' % i1, '\n' )
i1 = i1 + 1
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.126:yankRectangle
#@+node:mork.20041030164547.128:getRectanglePoints
def getRectanglePoints( self, event ):
tbuffer = event.widget
i = tbuffer.index( 'sel.first' )
i2 = tbuffer.index( 'sel.last' )
r1, r2 = i.split( '.' )
r3, r4 = i2.split( '.' )
r1 = int( r1 )
r2 = int( r2 )
r3 = int( r3 )
r4 = int( r4 )
return r1, r2, r3, r4
#@-node:mork.20041030164547.128:getRectanglePoints
#@-others
#@nonl
#@-node:mork.20041031155313:Rectangles methods
#@+node:mork.20041031181701.2:dynamic abbreviations methods
#@+others
#@+node:mork.20041030164547.132:dynamicExpansion
def dynamicExpansion( self, event ):#, store = {'rlist': [], 'stext': ''} ):
tbuffer = event.widget
rlist = self.store[ 'rlist' ]
stext = self.store[ 'stext' ]
i = tbuffer.index( 'insert -1c wordstart' )
i2 = tbuffer.index( 'insert -1c wordend' )
txt = tbuffer.get( i, i2 )
dA = tbuffer.tag_ranges( 'dA' )
tbuffer.tag_delete( 'dA' )
def doDa( txt, from_ = 'insert -1c wordstart', to_ = 'insert -1c wordend' ):
tbuffer.delete( from_, to_ )
tbuffer.insert( 'insert', txt, 'dA' )
return self._tailEnd( tbuffer )
if dA:
dA1, dA2 = dA
dtext = tbuffer.get( dA1, dA2 )
if dtext.startswith( stext ) and i2 == dA2: #This seems reasonable, since we cant get a whole word that has the '-' char in it, we do a good guess
if rlist:
txt = rlist.pop()
else:
txt = stext
tbuffer.delete( dA1, dA2 )
dA2 = dA1 #since the text is going to be reread, we dont want to include the last dynamic abbreviation
self.getDynamicList( tbuffer, txt, rlist )
return doDa( txt, dA1, dA2 )
else:
dA = None
if not dA:
self.store[ 'stext' ] = txt
self.store[ 'rlist' ] = rlist = []
self.getDynamicList( tbuffer, txt, rlist )
if not rlist:
return 'break'
txt = rlist.pop()
return doDa( txt )
#@-node:mork.20041030164547.132:dynamicExpansion
#@+node:mork.20041030164547.133:dynamicExpansion2
def dynamicExpansion2( self, event ):
tbuffer = event.widget
i = tbuffer.index( 'insert -1c wordstart' )
i2 = tbuffer.index( 'insert -1c wordend' )
txt = tbuffer.get( i, i2 )
rlist = []
self.getDynamicList( tbuffer, txt, rlist )
dEstring = reduce( self.findPre, rlist )
if dEstring:
tbuffer.delete( i , i2 )
tbuffer.insert( i, dEstring )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.133:dynamicExpansion2
#@+node:mork.20041030164547.134:getDynamicList
def getDynamicList( self, tbuffer, txt , rlist ):
ttext = tbuffer.get( '1.0', 'end' )
items = self.dynaregex.findall( ttext ) #make a big list of what we are considering a 'word'
if items:
for word in items:
if not word.startswith( txt ) or word == txt: continue #dont need words that dont match or == the pattern
if word not in rlist:
rlist.append( word )
else:
rlist.remove( word )
rlist.append( word )
#@-node:mork.20041030164547.134:getDynamicList
#@-others
#@nonl
#@-node:mork.20041031181701.2:dynamic abbreviations methods
#@+node:mork.20041031183018:sort methods
#@+others
#@+node:mork.20041030164547.136:sortLines
def sortLines( self, event , which = None ):
tbuffer = event.widget
if not self._chckSel( event ):
return self.keyboardQuit( event )
i = tbuffer.index( 'sel.first' )
i2 = tbuffer.index( 'sel.last' )
is1 = i.split( '.' )
is2 = i2.split( '.' )
txt = tbuffer.get( '%s.0' % is1[ 0 ], '%s.0 lineend' % is2[ 0 ] )
ins = tbuffer.index( 'insert' )
txt = txt.split( '\n' )
tbuffer.delete( '%s.0' % is1[ 0 ], '%s.0 lineend' % is2[ 0 ] )
txt.sort()
if which:
txt.reverse()
inum = int(is1[ 0 ])
for z in txt:
tbuffer.insert( '%s.0' % inum, '%s\n' % z )
inum = inum + 1
tbuffer.mark_set( 'insert', ins )
self.keyboardQuit( event )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.136:sortLines
#@+node:mork.20041030164547.137:sortColumns
def sortColumns( self, event ):
tbuffer = event.widget
if not self._chckSel( event ):
return self.keyboardQuit( event )
ins = tbuffer.index( 'insert' )
is1 = tbuffer.index( 'sel.first' )
is2 = tbuffer.index( 'sel.last' )
sint1, sint2 = is1.split( '.' )
sint2 = int( sint2 )
sint3, sint4 = is2.split( '.' )
sint4 = int( sint4 )
txt = tbuffer.get( '%s.0' % sint1, '%s.0 lineend' % sint3 )
tbuffer.delete( '%s.0' % sint1, '%s.0 lineend' % sint3 )
columns = []
i = int( sint1 )
i2 = int( sint3 )
while i <= i2:
t = tbuffer.get( '%s.%s' %( i, sint2 ), '%s.%s' % ( i, sint4 ) )
columns.append( t )
i = i + 1
txt = txt.split( '\n' )
zlist = zip( columns, txt )
zlist.sort()
i = int( sint1 )
for z in xrange( len( zlist ) ):
tbuffer.insert( '%s.0' % i, '%s\n' % zlist[ z ][ 1 ] )
i = i + 1
tbuffer.mark_set( 'insert', ins )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.137:sortColumns
#@+node:mork.20041030164547.139:sortFields
def sortFields( self, event, which = None ):
tbuffer = event.widget
if not self._chckSel( event ):
return self.keyboardQuit( event )
ins = tbuffer.index( 'insert' )
is1 = tbuffer.index( 'sel.first' )
is2 = tbuffer.index( 'sel.last' )
txt = tbuffer.get( '%s linestart' % is1, '%s lineend' % is2 )
txt = txt.split( '\n' )
fields = []
import re
fn = r'\w+'
frx = re.compile( fn )
for z in txt:
f = frx.findall( z )
if not which:
fields.append( f[ 0 ] )
else:
i = int( which )
if len( f ) < i:
return self._tailEnd( tbuffer )
i = i - 1
fields.append( f[ i ] )
nz = zip( fields, txt )
nz.sort()
tbuffer.delete( '%s linestart' % is1, '%s lineend' % is2 )
i = is1.split( '.' )
#i2 = is2.split( '.' )
int1 = int( i[ 0 ] )
for z in nz:
tbuffer.insert( '%s.0' % int1, '%s\n'% z[1] )
int1 = int1 + 1
tbuffer.mark_set( 'insert' , ins )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.139:sortFields
#@-others
#@nonl
#@-node:mork.20041031183018:sort methods
#@+node:mork.20041031181929.1:Alt_X methods
#@+at
# These methods control the Alt-x command functionality.
#
#@-at
#@@c
#@+others
#@+node:mork.20041030164547.140:alt_X
#self.altx = False
def alt_X( self, event , which = None):
#global altx
if which:
self.mcStateManager.setState( 'altx', which )
else:
self.mcStateManager.setState( 'altx', 'True' )
svar, label = self.getSvarLabel( event )
if which:
svar.set( '%s M-x:' % which )
else:
svar.set( 'M-x:' )
self.setLabelBlue( label )
return 'break'
#@-node:mork.20041030164547.140:alt_X
#@+node:mork.20041030164547.141:doAlt_X
def doAlt_X( self, event ):
'''This method executes the correct Alt-X command'''
svar, label = self.getSvarLabel( event )
if svar.get().endswith( 'M-x:' ):
self.axTabList.clear() #clear the list, new Alt-x command is in effect
svar.set( '' )
if event.keysym == 'Return':
txt = svar.get()
if self.doAltX.has_key( txt ):
if txt != 'repeat-complex-command':
self.altx_history.reverse()
self.altx_history.append( txt )
self.altx_history.reverse()
aX = self.mcStateManager.getState( 'altx' )
if aX.isdigit() and txt in self.x_hasNumeric:
self.doAltX[ txt]( event, aX )
else:
self.doAltX[ txt ]( event )
else:
self.keyboardQuit( event )
svar.set('Command does not exist' )
#self.altx = False
#self.mcStateManager.setState( 'altx', False )
return 'break'
if event.keysym == 'Tab':
stext = svar.get().strip()
if self.axTabList.prefix and stext.startswith( self.axTabList.prefix ):
svar.set( self.axTabList.next() ) #get next in iteration
else:
prefix = svar.get()
pmatches = self._findMatch2( svar )
self.axTabList.setTabList( prefix, pmatches )
svar.set( self.axTabList.next() ) #begin iteration on new lsit
return 'break'
else:
self.axTabList.clear() #clear the list, any other character besides tab indicates that a new prefix is in effect.
self.setSvar( event, svar )
return 'break'
#@-node:mork.20041030164547.141:doAlt_X
#@+node:mork.20041123093234:execute last altx methods
#@+others
#@+node:mork.20041122223754:executeLastAltX
def executeLastAltX( self, event ):
if event.keysym == 'Return' and self.altx_history:
last = self.altx_history[ 0 ]
self.doAltX[ last ]( event )
return 'break'
else:
return self.keyboardQuit( event )
#@-node:mork.20041122223754:executeLastAltX
#@+node:mork.20041122225107:repeatComplexCommand
def repeatComplexCommand( self, event ):
self.keyboardQuit( event )
if self.altx_history:
svar, label = self.getSvarLabel( event )
self.setLabelBlue( label )
svar.set( "Redo: %s" % self.altx_history[ 0 ] )
self.mcStateManager.setState( 'last-altx', True )
return 'break'
#@-node:mork.20041122225107:repeatComplexCommand
#@-others
#@nonl
#@-node:mork.20041123093234:execute last altx methods
#@-others
#@nonl
#@-node:mork.20041031181929.1:Alt_X methods
#@+node:mork.20041031155455:universal methods
#@+others
#@+node:mork.20041030164547.143:universalDispatch
#self.uC = False
def universalDispatch( self, event, stroke ):
#global uC
uC = self.mcStateManager.getState( 'uC' )
if not uC:
#self.uC = 1
self.mcStateManager.setState( 'uC', 1 )
svar, label = self.getSvarLabel( event )
svar.set( '' )
self.setLabelBlue( label )
elif uC == 1:
self.universalCommand1( event, stroke )
elif uC == 2:
self.universalCommand3( event, stroke )
return 'break'
#@-node:mork.20041030164547.143:universalDispatch
#@+node:mork.20041030164547.144:universalCommand1
#import string
#self.uCstring = string.digits + '\b'
def universalCommand1( self, event, stroke ):
#global uC
if event.char not in self.uCstring:
return self.universalCommand2( event, stroke )
svar, label = self.getSvarLabel( event )
self.setSvar( event, svar )
if event.char != '\b':
svar.set( '%s ' %svar.get() )
#@-node:mork.20041030164547.144:universalCommand1
#@+node:mork.20041030164547.145:universalCommand2
def universalCommand2( self, event , stroke ):
#global uC
#self.uC = False
#self.mcStateManager.setState( 'uC', False )
svar, label = self.getSvarLabel( event )
txt = svar.get()
self.keyboardQuit( event )
txt = txt.replace( ' ', '' )
self.resetMiniBuffer( event )
if not txt.isdigit(): #This takes us to macro state. For example Control-u Control-x ( will execute the last macro and begin editing of it.
if stroke == '<Control-x>':
#self.uC = 2
self.mcStateManager.setState( 'uC', 2 )
return self.universalCommand3( event, stroke )
return self._tailEnd( event.widget )
if self.uCdict.has_key( stroke ): #This executes the keystroke 'n' number of times.
self.uCdict[ stroke ]( event , txt )
else:
tbuffer = event.widget
i = int( txt )
stroke = stroke.lstrip( '<' ).rstrip( '>' )
if self.cbDict.has_key( stroke ):
for z in xrange( i ):
method = self.cbDict[ stroke ]
ev = Tkinter.Event()
ev.widget = event.widget
ev.keysym = event.keysym
ev.keycode = event.keycode
ev.char = event.char
self.masterCommand( ev , method, '<%s>' % stroke )
else:
for z in xrange( i ):
tbuffer.event_generate( '<Key>', keycode = event.keycode, keysym = event.keysym )
self._tailEnd( tbuffer )
#@-node:mork.20041030164547.145:universalCommand2
#@+node:mork.20041030164547.146:universalCommand3
#self.uCdict = { '<Alt-x>' : alt_X }
def universalCommand3( self, event, stroke ):
svar, label = self.getSvarLabel( event )
svar.set( 'Control-u %s' % stroke.lstrip( '<' ).rstrip( '>' ) )
self.setLabelBlue( label )
if event.keysym == 'parenleft':
self.keyboardQuit( event )
self.startKBDMacro( event )
self.executeLastMacro( event )
return 'break'
#@-node:mork.20041030164547.146:universalCommand3
#@+node:mork.20041030164547.147:numberCommand
def numberCommand( self, event, stroke, number ):
self.universalDispatch( event, stroke )
tbuffer = event.widget
tbuffer.event_generate( '<Key>', keysym = number )
return 'break'
#@-node:mork.20041030164547.147:numberCommand
#@-others
#@nonl
#@-node:mork.20041031155455:universal methods
#@+node:mork.20041121201041:line methods
#@+at
#
# flush-lines
# Delete each line that contains a match for regexp, operating on the text
# after point. In Transient Mark mode, if the region is active, the
# command operates on the region instead.
#
#
# keep-lines
# Delete each line that does not contain a match for regexp, operating on
# the text after point. In Transient Mark mode, if the region is active,
# the command operates on the region instead.
#
#@-at
#@@c
#@+others
#@+node:mork.20041121201041.1:alterLines
def alterLines( self, event, which ):
tbuffer = event.widget
i = tbuffer.index( 'insert' )
end = 'end'
if tbuffer.tag_ranges( 'sel' ):
i = tbuffer.index( 'sel.first' )
end = tbuffer.index( 'sel.last' )
txt = tbuffer.get( i, end )
tlines = txt.splitlines( True )
if which == 'flush':
keeplines = list( tlines )
else:
keeplines = []
svar, label = self.getSvarLabel( event )
pattern = svar.get()
try:
regex = re.compile( pattern )
for n , z in enumerate( tlines ):
f = regex.findall( z )
if which == 'flush' and f:
keeplines[ n ] = None
elif f:
keeplines.append( z )
except Exception,x:
return
if which == 'flush':
keeplines = [ x for x in keeplines if x != None ]
tbuffer.delete( i, end )
tbuffer.insert( i, ''.join( keeplines ) )
tbuffer.mark_set( 'insert', i )
self._tailEnd( tbuffer )
#@-node:mork.20041121201041.1:alterLines
#@+node:mork.20041121210221:processLines
def processLines( self, event ):
svar, label = self.getSvarLabel( event )
state = self.mcStateManager.getState( 'alterlines' )
if state.startswith( 'start' ):
state = state[ 5: ]
self.mcStateManager.setState( 'alterlines', state )
svar.set( '' )
if event.keysym == 'Return':
self.alterLines( event, state )
return self.keyboardQuit( event )
else:
self.setSvar( event, svar )
return 'break'
#@nonl
#@-node:mork.20041121210221:processLines
#@+node:mork.20041121201112:startLines
def startLines( self , event, which = 'flush' ):
self.keyboardQuit( event )
tbuffer = event.widget
self.mcStateManager.setState( 'alterlines', 'start%s' % which )
svar, label = self.getSvarLabel( event )
label.configure( background = 'lightblue' )
return 'break'
#@-node:mork.20041121201112:startLines
#@-others
#@nonl
#@-node:mork.20041121201041:line methods
#@+node:mork.20041031160002:goto methods
#@+at
# These methods take the user to a specific line or a specific character
# in the buffer
#
#
#@-at
#@@c
#@+others
#@+node:mork.20041030164547.154:startGoto
def startGoto( self, event , ch = False):
#global goto
#self.goto = True
if not ch:
self.mcStateManager.setState( 'goto', 1 )
else:
self.mcStateManager.setState( 'goto', 2 )
#label = self.mbuffers[ event.widget ]
svar , label = self.getSvarLabel( event )
svar.set( '' )
label.configure( background = 'lightblue' )
return 'break'
#@-node:mork.20041030164547.154:startGoto
#@+node:mork.20041030164547.155:Goto
def Goto( self, event ):
#global goto
widget = event.widget
svar, label = self.getSvarLabel( event )
if event.keysym == 'Return':
i = svar.get()
self.resetMiniBuffer( event )
#self.goto = False
state = self.mcStateManager.getState( 'goto' )
self.mcStateManager.setState( 'goto', False )
if i.isdigit():
if state == 1:
widget.mark_set( 'insert', '%s.0' % i )
elif state == 2:
widget.mark_set( 'insert', '1.0 +%sc' % i )
widget.event_generate( '<Key>' )
widget.update_idletasks()
widget.see( 'insert' )
return 'break'
t = svar.get()
if event.char == '\b':
if len( t ) == 1:
t = ''
else:
t = t[ 0 : -1 ]
svar.set( t )
else:
t = t + event.char
svar.set( t )
return 'break'
#@-node:mork.20041030164547.155:Goto
#@-others
#@nonl
#@-node:mork.20041031160002:goto methods
#@+node:mork.20041122110739:directory methods
#@+others
#@+node:mork.20041122110739.1:makeDirectory
def makeDirectory( self, event ):
svar,label = self.getSvarLabel( event )
state = self.mcStateManager.getState( 'make_directory' )
if not state:
self.mcStateManager.setState( 'make_directory', True )
self.setLabelBlue( label )
directory = os.getcwd()
svar.set( '%s%s' %( directory, os.sep ) )
return 'break'
if event.keysym == 'Return':
ndirectory = svar.get()
self.keyboardQuit( event )
try:
os.mkdir( ndirectory )
except:
svar.set( "Could not make %s%" % ndirectory )
return 'break'
else:
self.setSvar( event, svar )
return 'break'
#@nonl
#@-node:mork.20041122110739.1:makeDirectory
#@+node:mork.20041122111431:removeDirectory
def removeDirectory( self, event ):
svar,label = self.getSvarLabel( event )
state = self.mcStateManager.getState( 'remove_directory' )
if not state:
self.mcStateManager.setState( 'remove_directory', True )
self.setLabelBlue( label )
directory = os.getcwd()
svar.set( '%s%s' %( directory, os.sep ) )
return 'break'
if event.keysym == 'Return':
ndirectory = svar.get()
self.keyboardQuit( event )
try:
os.rmdir( ndirectory )
except:
svar.set( "Could not remove %s%" % ndirectory )
return 'break'
else:
self.setSvar( event, svar )
return 'break'
#@nonl
#@-node:mork.20041122111431:removeDirectory
#@-others
#@nonl
#@-node:mork.20041122110739:directory methods
#@+node:mork.20041031182449:file methods
#@+at
# These methods load files into buffers and save buffers to files
#
#@-at
#@@c
#@+others
#@+node:mork.20041122112210:deleteFile
def deleteFile( self, event ):
svar,label = self.getSvarLabel( event )
state = self.mcStateManager.getState( 'delete_file' )
if not state:
self.mcStateManager.setState( 'delete_file', True )
self.setLabelBlue( label )
directory = os.getcwd()
svar.set( '%s%s' %( directory, os.sep ) )
return 'break'
if event.keysym == 'Return':
dfile = svar.get()
self.keyboardQuit( event )
try:
os.remove( dfile )
except:
svar.set( "Could not delete %s%" % dfile )
return 'break'
else:
self.setSvar( event, svar )
return 'break'
#@-node:mork.20041122112210:deleteFile
#@+node:mork.20041030164547.151:insertFile
def insertFile( self, event ):
tbuffer = event.widget
f, name = self.getReadableTextFile()
if not f: return None
txt = f.read()
f.close()
tbuffer.insert( 'insert', txt )
return self._tailEnd( tbuffer )
#@-node:mork.20041030164547.151:insertFile
#@+node:mork.20041030164547.152:saveFile
def saveFile( self, event ):
tbuffer = event.widget
import tkFileDialog
txt = tbuffer.get( '1.0', 'end' )
f = tkFileDialog.asksaveasfile()
if f == None : return None
f.write( txt )
f.close()
#@-node:mork.20041030164547.152:saveFile
#@+node:mork.20041121140620.2:getReadableFile
def getReadableTextFile( self ):
import tkFileDialog
fname = tkFileDialog.askopenfilename()
if fname == None: return None, None
f = open( fname, 'rt' )
return f, fname
#@-node:mork.20041121140620.2:getReadableFile
#@-others
#@nonl
#@-node:mork.20041031182449:file methods
#@+node:mork.20041123192555:Esc methods for Python evaluation
#@+others
#@+node:mork.20041123192555.1:watchEscape
def watchEscape( self, event ):
svar, label = self.getSvarLabel( event )
if not self.mcStateManager.hasState():
self.mcStateManager.setState( 'escape' , 'start' )
self.setLabelBlue( label )
svar.set( 'Esc' )
return 'break'
if self.mcStateManager.whichState() == 'escape':
state = self.mcStateManager.getState( 'escape' )
hi1 = self.keysymhistory[ 0 ]
hi2 = self.keysymhistory[ 1 ]
if state == 'esc esc' and event.keysym == 'colon':
return self.startEvaluate( event )
elif state == 'evaluate':
return self.escEvaluate( event )
elif hi1 == hi2 == 'Escape':
self.mcStateManager.setState( 'escape', 'esc esc' )
svar.set( 'Esc Esc -' )
return 'break'
elif event.keysym in ( 'Shift_L', 'Shift_R' ):
return
else:
return self.keyboardQuit( event )
#@-node:mork.20041123192555.1:watchEscape
#@+node:mork.20041124095452:escEvaluate
def escEvaluate( self, event ):
svar, label = self.getSvarLabel( event )
if svar.get() == 'Eval:':
svar.set( '' )
if event.keysym =='Return':
expression = svar.get()
try:
ok = False
tbuffer = event.widget
result = eval( expression, {}, {} )
result = str( result )
tbuffer.insert( 'insert', result )
ok = True
finally:
self.keyboardQuit( event )
if not ok:
svar.set( 'Error: Invalid Expression' )
return self._tailEnd( tbuffer )
else:
self.setSvar( event, svar )
return 'break'
#@-node:mork.20041124095452:escEvaluate
#@+node:mork.20041124102729:startEvaluate
def startEvaluate( self, event ):
svar, label = self.getSvarLabel( event )
self.setLabelBlue( label )
svar.set( 'Eval:' )
self.mcStateManager.setState( 'escape', 'evaluate' )
return 'break'
#@-node:mork.20041124102729:startEvaluate
#@-others
#@nonl
#@-node:mork.20041123192555:Esc methods for Python evaluation
#@+node:mork.20041124123825:tabify/untabify
#@+at
# For the tabify and untabify Alt-x commands. Turns tabs to spaces and
# spaces to tabs in the selection
#
#@-at
#@@c
#@+others
#@+node:mork.20041124123825.1:tabify
def tabify( self, event, which='tabify' ):
tbuffer = event.widget
if tbuffer.tag_ranges( 'sel' ):
i = tbuffer.index( 'sel.first' )
end = tbuffer.index( 'sel.last' )
txt = tbuffer.get( i, end )
if which == 'tabify':
pattern = re.compile( ' {4,4}' )
ntxt = pattern.sub( '\t', txt )
else:
pattern = re.compile( '\t' )
ntxt = pattern.sub( ' ', txt )
tbuffer.delete( i, end )
tbuffer.insert( i , ntxt )
self.keyboardQuit( event )
return self._tailEnd( tbuffer )
self.keyboardQuit( event )
#@-node:mork.20041124123825.1:tabify
#@-others
#@nonl
#@-node:mork.20041124123825:tabify/untabify
#@+node:mork.20041208120232:shell and subprocess
#@+others
#@+node:mork.20041208120232.1:def startSubprocess
def startSubprocess( self, event, which = 0 ):
svar, label = self.getSvarLabel( event )
statecontents = { 'state':'start', 'payload': None }
self.mcStateManager.setState( 'subprocess', statecontents )
if which:
tbuffer = event.widget
svar.set( "Shell command on region:" )
is1 = is2 = None
try:
is1 = tbuffer.index( 'sel.first' )
is2 = tbuffer.index( 'sel.last' )
finally:
if is1:
statecontents[ 'payload' ] = tbuffer.get( is1, is2 )
else:
return self.keyboardQuit( event )
else:
svar.set( "Alt - !:" )
self.setLabelBlue( label )
return 'break'
#@-node:mork.20041208120232.1:def startSubprocess
#@+node:mork.20041208120232.2:subprocess
def subprocesser( self, event ):
state = self.mcStateManager.getState( 'subprocess' )
svar, label = self.getSvarLabel( event )
if state[ 'state' ] == 'start':
state[ 'state' ] = 'watching'
svar.set( "" )
if event.keysym == "Return":
#cmdline = svar.get().split()
cmdline = svar.get()
return self.executeSubprocess( event, cmdline, input=state[ 'payload' ] )
else:
self.setSvar( event, svar )
return 'break'
#@-node:mork.20041208120232.2:subprocess
#@+node:mork.20041208121502:executeSubprocess
def executeSubprocess( self, event, command ,input = None ):
import subprocess
try:
try:
out ,err = os.tmpnam(), os.tmpnam()
ofile = open( out, 'wt+' )
efile = open( err, 'wt+' )
process = subprocess.Popen( command, bufsize=-1,
stdout = ofile.fileno(),
stderr= ofile.fileno(),
stdin=subprocess.PIPE,
shell=True )
if input:
process.communicate( input )
process.wait()
tbuffer = event.widget
efile.seek( 0 )
errinfo = efile.read()
if errinfo:
tbuffer.insert( 'insert', errinfo )
ofile.seek( 0 )
okout = ofile.read()
if okout:
tbuffer.insert( 'insert', okout )
except Exception, x:
tbuffer = event.widget
tbuffer.insert( 'insert', x )
finally:
os.remove( out )
os.remove( err )
self.keyboardQuit( event )
return self._tailEnd( tbuffer )
#@-node:mork.20041208121502:executeSubprocess
#@-others
#@nonl
#@-node:mork.20041208120232:shell and subprocess
#@-others
#@nonl
#@-node:mork.20041030165020:class Emacs
#@-others
if __name__ == '__main__':
#@ << run standalone tests >>
#@+node:ekr.20041106100834:<< run standalone tests >>
#@+at
# This part runs Temacs with a Text widget.
# It should be accessible by typing python temacs.py at the command prompt
# Note: There is no configuration as to buffers and such, so dont access
# that functionality. Just a proof of concept.
#
#@-at
#@@c
Tl = Tkinter.Tk()
Tl.title( 'temacs Emacs test' )
Tx = Tkinter.Text( background = 'white', foreground = 'blue' )
f2 = Tkinter.Frame()
f2.pack( side = 'bottom' )
def onQuit():
import sys
sys.exit( 0 )
minibuffer = Tkinter.Label( f2 )
minibuffer.pack( side = 'right', expand = 1, fill = 'both' )
quitb = Tkinter.Button( f2, text = 'Quit' , command = onQuit )
quitb.pack( side = 'left' )
Tx.pack( side = 'top' )
emacs = Emacs( Tx, minibuffer, True, True )
Tl.mainloop()
#@nonl
#@-node:ekr.20041106100834:<< run standalone tests >>
#@nl
#@nonl
#@-node:mork.20041030164547:@thin temacs.py
#@-leo
|