# # Various helper funcs/classes for TF Python that are more suited to writing # in python than in C (so aren't in the base tf module) # # Copyright 2008 Ron Dippold import tf # --------------------------------------------------------------------------- # Misc helper functions # --------------------------------------------------------------------------- def screensize(): """ Returns ( rows, columns ) """ return ( tf.eval( "/test columns()" ), tf.eval( "/test lines()" ) ) def visual(): """ if visual is off, returns 0, otherwise returns number of input lines """ if tf.getvar( "visual", "off" ) == "on": return tf.getvar( "isize", 3 ) else: return 0 def eval_escape( text ): """ returns text with %, \, and $ doubled """ return text.replace('%','%%').replace( '\\','\\\\').replace("$","$$") def cmd_parse( argstr, opts ): """ Parse tf-style command lines into args and opts- like getopt, but for TinyFugue style where -w may have or not, and must be next to -w, not separated by a space. argstr is the command line, opts is a list of 'w:ligvt:a:m:A:B:C:#' where : means an argument - we don't care if it's optional or not. # is a number option like '-42' such as in the /quote command. The arguments are considered over when we hit any non-flag or '--' or '-' Returns ( cmd, optdict, rest ) where cmd is '/recall' (or blank if there wasn't a command present), optdict is { 'w':'foo', 'l':'', ... } and rest is a string with the rest of the line (unlike getopt, we need to preserve the spacing in the rest of the line). See also cmd_unparse - you can put the command back together after changing the args. """ # parts opts into an flagsdict - guess we could cache these flagsdict = {} i, olen = 0, len(opts) while i, ) set TF variable to , returns the old value. Saves the old value for when reverting State. """ old = tf.getvar( var ) tf.eval( "/set %s=%s" % ( var, value ) ) if not var in self.oldvar: self.oldvar[ var ] = old return old def define( self, name="", body="", flags="" ): """ n = State.define( name='', body='', flags='' ) Adds a new /def, returns the number of the new /def. All args optional. Saves the old value of named /def if it exists, for reverting State. Not named def() because that's a Python keyword. """ if name and not name in self.olddef: x = screenscrape( "/list -i -msimple %s" % name ) if x: self.olddef[name] = x[0] if flags and not flags.startswith("-"): flags = "-"+flags n = tf.eval( "/def %s %s = %s" % ( flags, name, eval_escape(body) ) ) self.newdef.append( n ) return n def bind( self, key, body="", flags="" ): """ n = State.bind( key='', body='', flags='' ) Create a new key binding for . Returns the number of the new /def. Body and flags are optional. Saves old binding for reverting State. """ if not key: raise Exception( "tfutil.bind: empty key name" ) if not key in self.oldkey: x = screenscrape( "/list -i -msimple -b'%s'" % key ) if x: self.oldkey[key] = x[0] if flags and not flags.startswith("-"): flags = "-"+flags key = "-b'%s'" % key.strip("'") n = tf.eval( "/def %s %s = %s" % ( flags, key, eval_escape(body) ) ) self.newkey.append( n ) return n def status( self, argstr ): # save current fields if not self.status_saved: tf.eval( "/status_save _tf4status" ) self.status_saved = True if not argstr.startswith("/"): argstr = "/status_"+argstr tf.eval( argstr ) def lose_changes( self ): """ Lose track of all the changes you've made since creating this object. """ self.oldvar = {} # { : } self.olddef = {} # { : } self.newdef = [] # [ ] self.oldkey = {} # { : } self.newkey = [] # [ ] self.status_saved = False def revert( self ): """ Revert to previous state - this will undo all the setvar(), define(), and bind()s you've done. """ # variables are easy for var, value in self.oldvar.items(): tf.eval( "/set %s=%s" % ( var, value ) ) # get rid of our new definitions if self.newdef: tf.eval( "/undefn %s" % " ".join( [ str(n) for n in self.newdef ] ) ) # restore the old ones for name, olddef in self.olddef.items(): # '% 829: /def -p2 blah= blah' tf.eval( eval_escape( olddef.split( ":", 1 )[1].lstrip() ) ) # get rid of our new bindings if self.newkey: tf.eval( "/undefn %s" % " ".join( [ str(n) for n in self.newkey ] ) ) # restore the old ones for name, oldkey in self.oldkey.items(): tf.eval( eval_escape( olddef.split( ":", 1 )[1].lstrip() ) ) # revert status line if self.status_saved: tf.eval( "/status_restore _tf4status" ) # now forget all our changes self.lose_changes() # We need this for the screenscrape hook tf.eval( "/python_load tfutil" )