home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 September (IDG) / Sep99.iso / Shareware World / Utilities / Text Processing / Alpha / Tcl / SystemCode / templates.tcl < prev    next >
Encoding:
Text File  |  1999-04-20  |  8.4 KB  |  274 lines  |  [TEXT/ALFA]

  1. ## -*-Tcl-*-
  2.  # ###################################################################
  3.  #  Vince's Additions - an extension package for Alpha
  4.  # 
  5.  #  FILE: "templates.tcl"
  6.  #                                    created: 27/7/97 {9:29:20 pm} 
  7.  #                                last update: 20/4/1999 {12:39:41 am} 
  8.  #  Author: Vince Darley
  9.  #  E-mail: <darley@fas.harvard.edu>
  10.  #    mail: Division of Engineering and Applied Sciences, Harvard University
  11.  #          Oxford Street, Cambridge MA 02138, USA
  12.  #     www: <http://www.fas.harvard.edu/~darley/>
  13.  #  
  14.  # Copyright (c) 1997-1999  Vince Darley, all rights reserved
  15.  # 
  16.  # Simple template insertion mechanism.  Can be easily overridden
  17.  # by a more sophisticated scheme providing more features, whilst
  18.  # still working simply if desired.  Call any of these 
  19.  # procs from the outside:
  20.  # 
  21.  #  elec::Insertion args  -- insert the given args
  22.  #  elec::CenterInsertion args -- insert, then center redraw
  23.  #  elec::Wrap left right -- wrap left and right about the selection
  24.  #  
  25.  #  ring::+ -- move to the next template stop
  26.  #  ring::- -- move to the previous template stop
  27.  #  
  28.  # Any piece of text given to the three 'elec::' procs has a template
  29.  # conversion done.  Text of the form '•blah•' is converted to a single
  30.  # bullet '•', with 'blah' attached to it internally.  
  31.  # 
  32.  # A more sophisticated template package, available separately, can
  33.  # prompt the user with 'blah' in useful ways, and creates a proper
  34.  # template ring.
  35.  # 
  36.  #  modified by  rev reason
  37.  #  -------- --- --- -----------
  38.  #  27/7/97  VMD 1.0 original
  39.  # ###################################################################
  40.  ##
  41.  
  42. alpha::flag electricTab 0.1.1 global help {
  43.     Enabling the 'Electric Tab' feature allows Alpha you to use
  44.     the procedures 'Indent or Next Stop' and 'Tab or Complete' as
  45.     any of your 'Special Keys' bindings.
  46.     
  47.     What these procedures do is change the behaviour of the Tab
  48.     key to depend upon the context.  In other words, hitting Tab
  49.     will not usually insert a Tab, rather it may indent the
  50.     current line, or move to the next Stop mark or complete the
  51.     current text,...
  52.     
  53.     Note that 'cmd-Tab' is one of the possible key-bindings
  54.     used to complete whatever you type.  If you use cmd-Tab as
  55.     a 'program switcher' in MacOS or other software, then you
  56.     obviously cannot use that keybinding in Alpha, since it
  57.     will be intercepted by the operating system.
  58. }
  59.  
  60. namespace eval elec {}
  61. namespace eval bind {}
  62. namespace eval ring {}
  63.  
  64. proc alpha::useElectricTemplates {} {}
  65.  
  66. # The character inserted into the text to indicate 'stop marks': useful
  67. # positions which you can jump between very quickly
  68. newPref variable elecStopMarker "•"
  69.  
  70. ## 
  71.  # -------------------------------------------------------------------------
  72.  #     
  73.  #    "elec::_Insertion" --
  74.  #    
  75.  #  Insert a piece of text, padding on the left appropriately.  The text
  76.  #  should already be correctly indented within itself.
  77.  #     
  78.  #  Any piece of the text of the form '•blah•' is converted into a single
  79.  #  bullet.  A more advanced version of this procedure, available
  80.  #  separately, allows the use of '•blah•' to prompt the user either in the
  81.  #  window, or status line, and makes the template stops permanent entities
  82.  #  so you can cycle back and forth through a template 'ring'. 
  83.  # -------------------------------------------------------------------------
  84.  ##
  85. proc elec::_Insertion { center args } {
  86.     set text [join $args ""]
  87.     set pos [getPos]
  88.     regsub -all "\t" $text [text::Tab] text
  89.     if {[regexp "\[\n\r\]" $text]} {
  90.     regsub -all "\[\n\r\]" $text "\r[text::indentTo $pos]" text
  91.     }
  92.     if {[regexp "…" $text]} {
  93.     regsub -all "…" $text [text::halfTab] text
  94.     }
  95.     setMark
  96.     global elecStopMarker
  97.     if {![regexp "•" $text] || ([regexp {^([^•]*)••$} $text "" text])} {
  98.     insertText $text
  99.     if {$center} { centerRedraw }
  100.     } else {
  101.     regsub -all {•[^•]*•} $text $elecStopMarker text
  102.     insertText $text
  103.     goto $pos
  104.     if {$center} { centerRedraw }
  105.     # need to go to the first tab stop
  106.     ring::+
  107.     }
  108. }
  109.  
  110.  
  111. # ◊◊◊◊ possible tab key bindings ◊◊◊◊ #
  112. # note: Also provided by the base Alpha system, these overide when 
  113. # Univs Completions package is in use (these may be more intricate).
  114.  
  115. ## 
  116.  # -------------------------------------------------------------------------
  117.  #     
  118.  #    "bind::IndentOrNextstop" --
  119.  #    
  120.  #  Either insert a real tab if your mode hasn't defined its electricTab
  121.  #  variable, or jump to the next template stop (if we're mid-template), or
  122.  #  indent the current line correctly.
  123.  #     
  124.  #  If this proc doesn't seem to do the right thing.  Make sure you've got
  125.  #  'electricTab' set correctly in your preferences! 
  126.  # -------------------------------------------------------------------------
  127.  ##
  128. proc bind::IndentOrNextstop {{hard 0}} {
  129.     global electricTab
  130.     if {$hard || !$electricTab} {
  131.     insertActualTab 
  132.     } else {
  133.     if {![ring::+]} {bind::IndentLine}
  134.     }
  135. }
  136.  
  137. ## 
  138.  # -------------------------------------------------------------------------
  139.  #     
  140.  #    "bind::TabOrComplete" --
  141.  #    
  142.  #  Either insert a real tab if your mode hasn't defined its electricTab
  143.  #  variable, or invoke the completion mechanism, or indent the current
  144.  #  line correctly.
  145.  #     
  146.  #  If this proc doesn't seem to do the right thing.  Make sure you've got
  147.  #  'electricTab' set correctly in your preferences! 
  148.  # -------------------------------------------------------------------------
  149.  ##
  150. proc bind::TabOrComplete {{hard 0}} {
  151.     global electricTab
  152.     if {$hard || !$electricTab} {
  153.     insertActualTab 
  154.     } else {
  155.     bind::Completion
  156.     }
  157. }
  158.  
  159. proc ring::+ {} {
  160.     global elecStopMarker
  161.     set pos [getPos]
  162.     if {[pos::compare $pos == [maxPos]]} { return 0 }
  163.     set searchResult [lindex [search -s -n -f 1 -m 0 -i 1 -r 0 $elecStopMarker $pos] 0]
  164.     if {[string length $searchResult]} {
  165.     goto $searchResult
  166.     deleteChar
  167.     return 1
  168.     } else {
  169.     return 0
  170.     }
  171. }
  172.  
  173. proc ring::- {} {
  174.     global elecStopMarker
  175.     set pos [getPos]
  176.     if {[pos::compare $pos == [minPos]]} { return 0 }
  177.     set searchResult [lindex [search -s -n -f 0 -m 0 -i 1 -r 0 $elecStopMarker $pos] 0]
  178.     if {[string length $searchResult]} {
  179.     goto $searchResult
  180.     deleteChar
  181.     return 1
  182.     } else {
  183.     return 0
  184.     }
  185. }
  186.  
  187. # Removes all tab stops from the current selection (if there is one) 
  188. # or the current document, maintaining the cursor position in the 
  189. # latter case.
  190. proc ring::clear {} {
  191.     watchCursor
  192.     set pos [getPos]
  193.     global elecStopMarker
  194.     if {[pos::compare [set start $pos] == [set end [selEnd]]]} {
  195.     set start [minPos]
  196.     set end [maxPos]
  197.     set text1 [getText $start $pos]
  198.     set subs1 [regsub -all -- $elecStopMarker $text1 {} text1]
  199.     set text2 [getText $pos $end]
  200.     set subs2 [regsub -all -- $elecStopMarker $text2 {} text2]
  201.     append text $text1 $text2
  202.     replaceText $start $end $text
  203.     goto [pos::math $pos - $subs1]
  204.     message "[expr {$subs1 + $subs2}] stops cleared"
  205.     } else {
  206.     set text [getText $start $end]
  207.     set subs3 [regsub -all -- $elecStopMarker $text {} text]
  208.     replaceText $start $end $text
  209.     set end [getPos]
  210.     select $start $end
  211.     message "$subs3 stops cleared"
  212.     }
  213. }
  214. # indicates we're a very basic ring
  215. proc ring::type {} { return 0 }
  216. ## 
  217.  # -------------------------------------------------------------------------
  218.  # 
  219.  # "elec::CenterInsertion" --
  220.  # 
  221.  #  Insert and then do a refresh.  Useful for large electric insertions.
  222.  # -------------------------------------------------------------------------
  223.  ##
  224. proc elec::CenterInsertion {args} {
  225.     eval elec::_Insertion 1 $args
  226. }
  227.  
  228. ## 
  229.  # -------------------------------------------------------------------------
  230.  # 
  231.  # "elec::Insertion" --
  232.  # 
  233.  #  Just insert the electric item
  234.  # -------------------------------------------------------------------------
  235.  ##
  236. proc elec::Insertion { args } {
  237.     eval elec::_Insertion 0 $args
  238. }
  239. proc elec::ReplaceText { start end args } {
  240.     deleteText $start $end 
  241.     eval elec::_Insertion 0 $args
  242. }
  243.  
  244. ## 
  245.  # -------------------------------------------------------------------------
  246.  #     
  247.  #    "elec::Wrap" --
  248.  #    
  249.  #  Currently doesn't deal with indentation -- the wrapper is supposed to
  250.  #  handle that.
  251.  #     
  252.  #  Returns 0/1 to indicate if there was a selection which this proc
  253.  #  wrapped. 
  254.  # -------------------------------------------------------------------------
  255.  ##
  256. proc elec::Wrap { left right {complete 0}} {
  257.     set pos [getPos]
  258.     set s [getSelect]
  259.     if {[string length $s]} {
  260.     deleteText $pos [selEnd]
  261.     elec::Insertion $left $s $right
  262.     return 1
  263.     } else {
  264.     elec::Insertion $left "••" $right
  265.     if {$complete} {
  266.         bind::Completion
  267.     }
  268.     return 0
  269.     }
  270. }
  271.  
  272.  
  273.  
  274.