home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyth_os2.zip / python-1.0.2 / Demo / lutz / psh.py next >
Text File  |  1994-02-04  |  10KB  |  385 lines

  1. #
  2. # Python command shell utility
  3. #
  4. # simplifies debugging, editing, etc;
  5. # augments normal Python commmand line;
  6. # cmd history: redundant if edline built;
  7. #
  8. # use:  python psh.py
  9. #       python; import psh; psh.go(); help
  10. #
  11. # TODO:
  12. # - cmd history scrolling via arrow keys
  13. # - arbitrary '$' aliases/replacements
  14. # - make it a class, so can use in other 
  15. #   apps (call self.handler, not python())
  16. # - see about using pdb's command class
  17. #   so shell cmds recognized while in pdb
  18. # - 'edit' (but not 'vi') runs out of 
  19. #   memory under windows (not under DOS)
  20. #############################################
  21.  
  22.  
  23.  
  24. from os import *
  25. from string import *
  26.  
  27.  
  28. editor   = 'vi'         # 'edit'
  29. memory   = 20           # settable: % shell.editor = 'vi'
  30. histnum  = 0            # retain all settings for next go()
  31. history  = []         
  32. prompter = '%'          
  33. aliases  = []
  34.  
  35.  
  36.  
  37.  
  38. def interact():
  39.     while 1:
  40.         cmd = raw_input(prompter + ' ')
  41.         cmd = prescan(cmd)
  42.         if cmd == 'quit':
  43.             break
  44.         execute(cmd)
  45.     
  46.  
  47.  
  48.  
  49. def execute(cmd):
  50.     global history, histnum
  51.     args = split(cmd)
  52.     if not args:                    # empty line or all blanks
  53.         return                      # else >= 1 word on line
  54.     
  55.     if shell_command(args[0]):
  56.         func = eval(args[0])              # get function for command
  57.         try: 
  58.             func(args[1:])                # null if no args[1:]
  59.         except:
  60.             print 'bad shell command'     # any errors come here
  61.  
  62.     else:
  63.         try:
  64.             python(cmd)                   # try as python command
  65.         except:
  66.             print 'bad command:', args[0]
  67.  
  68.     if args[0] != 're':
  69.         histnum = histnum+1
  70.         history = history[-(memory-1):] + [(histnum, cmd)]
  71.  
  72.  
  73.  
  74.  
  75. ##################################################                
  76. # see notes at bottom of file;
  77. ##################################################
  78.  
  79.  
  80.  
  81. def shell_command(name): 
  82.     return (name in help_dir.keys())
  83.  
  84.  
  85.  
  86. def python(cmd):
  87.     import __main__
  88.     exec(cmd, __main__.__dict__, __main__.__dict__)
  89.  
  90.  
  91.  
  92.  
  93. #####################################################
  94. # one function per keyword command; add to help too
  95. #####################################################
  96.  
  97.  
  98.  
  99. def quit(args):
  100.     raise NameError          # superfluous args
  101.  
  102.  
  103.  
  104. def prompt(args):        
  105.     global prompter
  106.     prompter = args[0]
  107.         
  108.  
  109.  
  110. def pwd(args):
  111.     print getcwd()
  112.  
  113.  
  114.  
  115. def cd(args): 
  116.     if not args:
  117.         chdir()
  118.     else:
  119.         chdir(args[0])
  120.     print getcwd()
  121.  
  122.  
  123.  
  124. def ls(args): 
  125.     if not args:
  126.         t = system('ls')                # listdir('.')
  127.     else:
  128.         t = system('ls ' + args[0])     # listdir(args[0])
  129.     
  130.  
  131.  
  132. def ed(args):
  133.     t = system(editor + ' ' + args[0])
  134.  
  135.  
  136.  
  137. def os(args):
  138.     t = system(join(args))                  # ex: os cp shell.py a:
  139.                                             # 'os' alone starts shell 
  140.  
  141.  
  142. def fix(args):                            
  143.     import sys                              # ex: fix holmes
  144.     module = args[0]
  145.     ed([module + '.py'])                    # assumes in cwd/'.'
  146.     if module in sys.modules.keys():
  147.         python('reload(' + module + ')')    # reload in __main__
  148.     else:
  149.         python('import ' + module)          # first load in __main__
  150.  
  151.  
  152.  
  153. def db(args):
  154.     import pdb
  155.     pdb.run(join(args))                     # ex: db shell.help(['ls'])
  156.                                             # pdb runs cmd in __main__
  157.  
  158.  
  159. def hi(args):
  160.     for (number, command) in history:
  161.         print number, '=>', command
  162.          
  163.  
  164.  
  165. def re(args):
  166.     if not args:
  167.         repeat = history[len(history)-1][1]
  168.     else:
  169.         try:
  170.             number = eval(args[0])                    # fail if non-num
  171.             for (num, cmd) in history: 
  172.                 if num == number: 
  173.                     repeat = cmd; 
  174.                     break
  175.             else: raise NameError                     # number not found
  176.         except:
  177.             prefix = join(args)
  178.             history.reverse()
  179.             for (num, cmd) in history:
  180.                 if cmd[:len(prefix)] == prefix:
  181.                     repeat = cmd
  182.                     history.reverse()
  183.                     break
  184.             else:
  185.                 history.reverse()
  186.                 print 'bad history command number'
  187.                 return
  188.     
  189.     print 'redo:', repeat
  190.     execute(repeat)                      # recursive call
  191.  
  192.  
  193.  
  194.  
  195. def src(args):
  196.     # import sys
  197.     # save = (sys.stdin, sys.stdout)
  198.     file = open(args[0], 'r')                    # open can fail
  199.     while 1:
  200.         cmd = file.readline()                    # read can fail
  201.         if not cmd: 
  202.             break
  203.         cmd = prescan(cmd)
  204.         if cmd == 'quit':
  205.             break
  206.         if cmd: print '[' + cmd + ']...'
  207.         execute(cmd)
  208.     file.close()
  209.  
  210.  
  211.  
  212.  
  213. def equ(args):
  214.     if not args:
  215.         for (patt, subst) in aliases:
  216.             print `patt`, '=>', `subst + ' '`
  217.     else:
  218.         global aliases                                     # (from, to)
  219.         aliases = [(args[0], join(args[1:]))] + aliases    # to can be a list 
  220.         
  221.  
  222.  
  223.  
  224. ##########################################################
  225. # currently only allows aliase name to be at the front
  226. # of the command line, not embedded in it (no '$' subst);
  227. # cmd pattern must be followed by a blank iff the patt
  228. # is not a special char, and the cmd contains args;
  229. # this stops 'quit' from becoming 'quit uit' when 'q'
  230. # has been aliased to 'quit';
  231. ##########################################################
  232.  
  233.  
  234.  
  235. def prefix(cmd, patt):
  236.     if cmd[:len(patt)] == patt:
  237.         if patt[0] not in letters:
  238.             return 1
  239.         if len(cmd) == len(patt): 
  240.             return 1
  241.         if cmd[len(patt)] in whitespace: 
  242.             return 1
  243.     return 0
  244.  
  245.  
  246.  
  247. def prescan(cmd):
  248.     cmd = strip(cmd)               # strip blanks for 'quit' test
  249.     if cmd and cmd[0] == '#':      # allow comments in src files
  250.         return ''
  251.     
  252.     for (patt, subst) in aliases:
  253.         if prefix(cmd, patt):
  254.             cmd = strip(subst + ' ' + cmd[len(patt):])     # allow '!' for 're '
  255.             print 'equ:', cmd                              # alloq 'q' for quit
  256.             break
  257.  
  258.     return cmd            
  259.  
  260.  
  261.  
  262.  
  263. ##################################################    
  264. # help_dir also serves to identify shell   
  265. # command names (distinct from python cmds);
  266. ##################################################
  267.  
  268.  
  269.  
  270.  
  271. help_dir = \
  272. {   'pwd':      ('',               'print current directory'),         \
  273.     'ls':       ('<dir>?',         'list contents of dir'),            \
  274.     'cd':       ('<dir>?',         'change current directory'),        \
  275.     'ed':       ('<file>?',        'edit a file (shell.editor)'),      \
  276.     'os':       ('<cmd>?',         'send command to system'),          \
  277.     'db':       ('<expr>?',        'run expr under pdb debugger'),     \
  278.     'fix':      ('<module>',       'edit and import|reload module'),   \
  279.     'prompt':   ('<str>',          'change the prompt string'),        \
  280.     'hi':       ('',               'prior command history list'),      \
  281.     're':       ('[<num>|<str>]?', 'repeat a prior command (see hi)'), \
  282.     'quit':     ('',               'exit the shell'),                  \
  283.     'help':     ('<cmd>?',         'describe one|all commands'),       \
  284.     'equ':      ('[<str> <val>]?', 'replace/aliase <str> with <val>'), \
  285.     'src':      ('<file>',         'read commands from a text file')   \
  286. }
  287.  
  288.  
  289.  
  290.  
  291. help_examples = \
  292. {   'ls':       'ls, ls ../benches/holmes',               \
  293.     'cd':       'cd ../benches',                          \
  294.     'ed':       'ed, ed shell.py',                        \
  295.     'os':       'os, os cp shell.py a:',                  \
  296.     'db':       'db shell.help([\'db\'])',                \
  297.     'fix':      'fix shell',                              \
  298.     'prompt':   'prompt psh>',                            \
  299.     're':       're 12, re x =, re db. [equ ! re, !fix]', \
  300.     'equ':      'equ, equ ! re, equ save os cp *.py a:',  \
  301.     'src':      'src script.txt'                          \
  302. }
  303.  
  304.  
  305.  
  306.  
  307. def help(args):
  308.     if args:
  309.         try:
  310.             desc = help_dir[args[0]]
  311.             print 'Command:    ', args[0]
  312.             print 'Arguments:  ', desc[0]
  313.             print 'Description:', desc[1]
  314.             if args[0] in help_examples.keys():
  315.                 print 'Examples:   ', help_examples[args[0]]
  316.         except:
  317.             print 'unknown help command'
  318.  
  319.     else:
  320.         print 'Available commands...\n'
  321.         keys = help_dir.keys()
  322.         keys.sort()
  323.         for x in keys:
  324.             print ljust(x + ' ' + help_dir[x][0], 18), help_dir[x][1]
  325.         print '\nOther commands are run by the Python interpreter in __main__'
  326.         print 'Type \'help <cmd>\' for more information on a specific command\n'
  327.  
  328.  
  329.  
  330.  
  331. ############################################
  332. # run shell; 'shell.go()' restarts is again
  333. # note: 'shell' is not available in __main__
  334. # yet, until this file is completely read,
  335. # so you can't 'db' shell stuff until you
  336. # 'quit' and call 'shell.xxx()' directly;
  337. #
  338. # load (src's) '.PshInit' if present in cwd;
  339. # should also ckeck home dir too;  useful
  340. # for canned 'equ' aliase commands, 'os' 
  341. # and 'prompt' commands, etc;
  342. ############################################
  343.  
  344.  
  345.  
  346.  
  347. def go():
  348.     print '-Python command shell-'
  349.     try:
  350.         src(['.PshInit'])
  351.         print 'loaded .PshInit'
  352.     except:
  353.         print '.PshInit file not found'
  354.     interact()
  355.     print 'command shell exit.'
  356.  
  357.  
  358. go()
  359.  
  360.  
  361.  
  362.  
  363.  
  364.  
  365. ##################################################
  366. # notes;
  367. # eval() succeeds for python cmds too
  368. # exec() runs with local=function in 'shell'
  369. # 'import *' adds os/string funcs to 'shell'
  370. #
  371. # def shell_command(name):
  372. #     import shell
  373. #     return (name in shell.__dict__.keys())
  374. ##################################################    
  375. # import sys
  376. # exec(join(args), \
  377. #         sys.modules['__main__'].__dict__, \
  378. #         sys.modules['__main__'].__dict__)
  379. #
  380. # 'x' = sys.modules['__main__'].x
  381. # 'x' = sys.modules['__main__'].__dict__['x']
  382. ##################################################
  383.  
  384.  
  385.