home *** CD-ROM | disk | FTP | other *** search
/ Macwelt 1 / Macwelt DVD 1.toast / Web-Publishing / HTML-Editoren / Alpha ƒ / Tcl / Modes / pythonMode.tcl < prev    next >
Encoding:
Text File  |  2000-12-06  |  7.4 KB  |  205 lines

  1. # (auto-install)
  2. ############################################################################# 
  3. # pythonMode.tcl
  4. #  Howard Oakley, EHN & DIJ Oakley
  5. #  howard@quercus.demon.co.uk
  6. #
  7. # Description:
  8. # This auto-installing file implements a simple mode for editing 
  9. # Python using Alpha. It has been tested with Alpha version 7.2. 
  10. # The features of this mode include:
  11. # syntax colouring - comments in red, strings (some) in green,
  12. #  keywords in blue, and colons (a Python particular) in magenta 
  13. # easy production of comment boxes etc.
  14. # def and class marking - automatically generated marks (M popup) give 
  15. #  the function name first, and then the class (if any), whilst class 
  16. #  definitions give the class name twice; the {} popup takes
  17. #  you to class definitions
  18. # automatic indentation - given the importance of this in Python control 
  19. #  structures, this was an essential, and is accomplished
  20. #  using tabs in syntactic context.
  21. # The code below is a cobbling together of code stolen from other sources. 
  22. # Whilst the fine code of the original sources is reliable, there are 
  23. # all sorts of nasty kludges which I have used to get it to do what 
  24. # I needed. Tcl purists who can improve on it are invited to do so: 
  25. # please e-mail your corrections to me so that I can maintain this. 
  26. # My thanks and apologies to those from whom I have stolen code. 
  27. # Version: 1.0 dated 17 Sep 1999 [or if you prefer it, 1999-09-17]. 
  28. # (Vince fixed some stuff up for Alphatk, and removed some obsolete things)
  29. ############################################################################# 
  30.  
  31. alpha::mode Pyth 1.0.1 source {*.py} {
  32.     electricBraces electricTab electricReturn
  33. } {} help {
  34.     Python Mode provides syntax coloring - comments in red, strings (some) in
  35.     green, keywords in blue, and colons (a Python particular) in magenta; easy
  36.     production of comment boxes etc.; def and class marking - automatically
  37.     generated file marks (M popup) give the function name first, and then the
  38.     class (if any), whilst class definitions give the class name twice; the {}
  39.     popup (ParseFuncs) takes you to class definitions; automatic indentation -
  40.     given the importance of this in Python control structures, this is an
  41.     essential, and is accomplished using tabs in syntactic context.
  42. }
  43.  
  44. # We need at least this version
  45. alpha::package require AlphaTcl 7.4a7
  46.  
  47. newPref v leftFillColumn {1} Pyth
  48. newPref v wordBreak {\w+} Pyth
  49. newPref f wordWrap {0} Pyth
  50. newPref v funcExpr {^[ \t]*(def|class)[ \t]+([A-Za-z0-9_]+)} Pyth 
  51. newPref v parseExpr {^[ \t]*([A-Za-z0-9_]*)} Pyth
  52. newPref v wordBreakPreface {\W} Pyth
  53. newPref f autoMark 0 Pyth
  54.  
  55. # I extend the range of keywords a little, to include some type conversions # and other important items
  56.  
  57. set pythKeyWords {
  58.     access and break class continue def del elif else
  59.     except exec finally for from global if import in
  60.     is lambda not or pass print raise return self try while 
  61.     = < > <= >= + * - / != <> % | ^ &
  62.     len min max ~ abs int long float complex divmod pow
  63.     list map tuple eval string repr assert
  64. }
  65.  
  66. regModeKeywords -e {#} -s green -c red -i : -I magenta -k blue Pyth $pythKeyWords
  67. unset pythKeyWords
  68.  
  69. #================================================================================ 
  70. # for Tcl 8.0 compatibility, hopefully
  71. namespace eval Pyth {}
  72. #================================================================================ 
  73.  
  74. # for easy production of comment boxes etc.
  75.  
  76. set Pyth::commentCharacters(General) "\#"
  77. set Pyth::commentCharacters(Paragraph) [list "#----" "#----" "#"] 
  78. set Pyth::commentCharacters(Box) [list "#" 2 "#" 2 "#" 3] 
  79.  
  80. # the mark routine, which has to append the class name *if* the definition is
  81. # part of a class definition, but reset the empty class name if it is not, 
  82. # i.e. there is no leading whitespace before the 'def'
  83. # - this therefore builds the M popup menu.
  84.  
  85. proc Pyth::MarkFile {} {
  86.     global PythmodeVars
  87.     set pos [minPos]
  88.     set classnom ""
  89.     
  90.     while {![catch {search -s -f 1 -r 1 -m 0 -i 1 $PythmodeVars(funcExpr) $pos} res]} {
  91.     set start [lindex $res 0]
  92.     set end [pos::math [lindex $res 1] + 1]
  93.     set text [getText $start $end]
  94.     
  95.     if {[regexp -indices {(class)[ \t]+([a-zA-Z0-9_]+)} $text dummy dummy0 pname]} {
  96.         set i1 [pos::math $start + [lindex $pname 0]]
  97.         set i2 [pos::math $start + [lindex $pname 1] + 1]
  98.         # this is the start of a class definition, so save the class name       
  99.         set classnom  [getText $i1 $i2]
  100.     } else {
  101.         if {[pos::compare $pos > [minPos]]} {
  102.         set pp [pos::math $start - 1]
  103.         set pq [pos::math $start + 1]
  104.         set pr [getText $pp $pq]
  105.         if {![regexp {[ \t]+} $pr]} {
  106.             # this is a standalone def, therefore reset the class name to an empty string
  107.             set classnom ""
  108.         }
  109.         }
  110.     }
  111.     
  112.     if {[regexp -indices {(def|class)[ \t]+([a-zA-Z0-9_]+)} $text dummy dummy0 pname]} {
  113.         set i1 [pos::math $start + [lindex $pname 0]]
  114.         set i2 [pos::math $start + [lindex $pname 1] + 1]
  115.         set word  [getText $i1 $i2]
  116.         set tmp [concat $i1 $i2]
  117.         # assemble the marker name with the def element first, followed by any class name
  118.         set ol_word [join [concat $word " " $classnom ""]]   set inds($ol_word) $tmp
  119.     }
  120.     
  121.     set pos $end
  122.     }
  123.     if {[info exists inds]} {
  124.     foreach f [lsort -ignore [array names inds]] {
  125.         set res $inds($f)
  126.         setNamedMark $f [lineStart [lindex $res 0]] [lindex $res 0] [lindex $res 1]
  127.     }
  128.     }
  129. }
  130.  
  131. # this builds the {} menu along similar lines, but this time with just
  132. # class definitions
  133. proc Pyth::parseFuncs {} {
  134.     global PythmodeVars
  135.     set pos [minPos]
  136.     
  137.     while {![catch {search -s -f 1 -r 1 -m 0 -i 1 $PythmodeVars(funcExpr) $pos} res]} {
  138.     set start [lindex $res 0]
  139.     set end [pos::math [lindex $res 1] + 1]
  140.     set text [getText $start $end]
  141.     
  142.     if {[regexp -indices {(class)[ \t]+([a-zA-Z0-9_]+)} $text dummy dummy0 pname]} {
  143.         set i1 [pos::math $start + [lindex $pname 0]]
  144.         set i2 [pos::math $start + [lindex $pname 1] + 1]
  145.         set word  [getText $i1 $i2]
  146.         set tmp [concat $i1 $i2]
  147.         set inds($word) $tmp
  148.     }
  149.     set pos $end
  150.     }
  151.     set rtnRes {}
  152.     
  153.     if {[info exists inds]} {
  154.     foreach f [lsort -ignore [array names inds]] {
  155.         set next [nextLineStart $inds($f)]
  156.         lappend rtnRes $f $next
  157.     }
  158.     }
  159.     return $rtnRes 
  160. }
  161.  
  162. proc Pyth::indentLine {} {
  163.     # get details of current line
  164.     set beg [lineStart [getPos]]
  165.     set text [getText $beg [nextLineStart $beg]]
  166.     regexp "^\[ \t\]*" $text white
  167.     set len [string length $white]
  168.     set epos [pos::math $beg + $len]
  169.     
  170.     # Find last previous non-comment line and get its leading
  171.     # whitespace 
  172.     set pos $beg
  173.     while 1 {
  174.     if {[catch {search -s -f 0 -r 1 -i 0 -m 0 "^\[ \t\]*\[^ \t\r\n\]" [pos::math $pos - 1]} lst]} {
  175.         # search failed at top of file
  176.         set line "#"
  177.         set lwhite 0
  178.         break
  179.     }
  180.     if {![catch {text::inCommentBlock [lindex $lst 0]} res]} {
  181.         set pos [lindex $res 0]
  182.     } else {
  183.         set line [getText [lindex $lst 0] [pos::math [nextLineStart [lindex $lst 0]] - 1]]
  184.         set lwhite [posX [pos::math [lindex $lst 1] - 1]] 
  185.         break
  186.     }
  187.     }
  188.     # we need (syntactically) to increase the tabs by 1, so first do
  189.     # this using spaces, and then convert the spaces to a tab.  This is
  190.     # not elegant, but it works!
  191.     if {[regexp ":\[ \t\]*$" $line]} {
  192.     getWinInfo a
  193.     set ps $a(tabsize)
  194.     incr lwhite $ps
  195.     }
  196.     set lwhite [text::indentOf $lwhite]
  197.     if {$white != $lwhite} {
  198.     replaceText $beg $epos $lwhite
  199.     select $beg [pos::math $beg + [string length $lwhite]]
  200.     spacesToTabs
  201.     }
  202.     goto [pos::math $beg + [string length $lwhite]]
  203. }
  204.