home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / epmsmp.zip / BALANCE.E < prev    next >
Text File  |  1992-08-26  |  9KB  |  237 lines

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;   Character Balancing Routine (for EOS2 and EPM)             ;;
  3. ;;   by Jonathan Kaye                                           ;;
  4. ;;                                                              ;;
  5. ;;   Upon entering a closing matching character, the balance    ;;
  6. ;;   routine shows the caller the matching opening character.   ;;
  7. ;;   If it is on the screen, it highlights the character in     ;;
  8. ;;   the color of the current commandline.  If it's not on      ;;
  9. ;;   the screen at the time, it reports in the message area     ;;
  10. ;;   the line of the opening character, giving line number      ;;
  11. ;;   and text that follows the character.                       ;;
  12. ;;                                                              ;;
  13. ;;   In EOS2, it keeps the opening character highlighted until  ;;
  14. ;;   the next key is pressed.  In EPM, it only flashes the      ;;
  15. ;;   opening character a few times.                             ;;
  16. ;;                                                              ;;
  17. ;;   Basically, it does what EMACS does.  But I don't think     ;;
  18. ;;   we can mention that word around here.                      ;;
  19. ;;                                                              ;;
  20. ;;   To use: Include BALANCE.E (include 'balance.e') in one     ;;
  21. ;;           of the MY*.E files, such as MYSTUFF.E.  Since      ;;
  22. ;;           I wanted the keys to be part of the base keyset,   ;;
  23. ;;           I moved the key definitions (the def ')', etc.) to ;;
  24. ;;           MYKEYS.E, leaving the procedure included in        ;;
  25. ;;           MYSTUFF.E.                                         ;;
  26. ;;                                                              ;;
  27. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  28.  
  29. ;; Define matching keys ----------------------
  30.  def ')'=
  31.    call balance("parenthesis",    "(", ")", 550)
  32.  
  33.  def ']'=
  34.    call balance("square bracket", "[", "]", 660)
  35.  
  36.  def '}'=
  37.    call balance("curly bracket",  "{", "}", 880)
  38.  
  39.  def '>'=
  40.    call balance("angle bracket",  "<", ">", 770)
  41. ;; -------------------------------------------
  42.  
  43. defproc balance (type, open_char, close_char, fail_beep_Hz)
  44.  
  45.   keyin close_char
  46.   refresh                     -- Get closing character on screen to start
  47.  
  48. compile if (NOT EPM)          -- No commandstate() function for EPM
  49.   if (commandstate() = 0) then
  50. compile endif
  51.     getsearch user_pattern    -- Hold user's pattern to restore when done
  52.  
  53.     display 0
  54.     compile if EPM
  55.       display -3              -- Don't show user cursor is jumping around
  56.                               -- Also turn off non-critical error messages
  57.     compile else
  58.       display 0               -- Don't show user cursor is jumping around
  59.     compile endif
  60.     call psave_pos(screenpos) -- Freeze our relative position on screen
  61.  
  62.     -- Set search keys we use to find opening and closing characters
  63.  
  64.     compile if EVERSION >= '4.12B'    -- Versions of E before 4.12B needs
  65.       loc_opts = 'R-'                 -- different grep locate options
  66.     compile else
  67.       loc_opts = 'R-G'
  68.     compile endif
  69.     open_pat = 'XCOM L /'open_char'/'loc_opts
  70.     clos_pat = 'XCOM L /'close_char'/'loc_opts
  71.  
  72.     -- Initialize for start of search right before closing character
  73.     close_col  = .COL - 1
  74.     close_line = .LINE
  75.     call minus_one(close_col, close_line)
  76.     open_col   = .COL    -- We can start here because we know there isn't
  77.     open_line  = .LINE   -- an opening character past what user just typed
  78.     found = 0
  79.  
  80.     loop
  81.       call minus_one(open_col, open_line) -- so we don't find last open again
  82.       call last_char(open_pat,  open_line,  open_col,  open_col,  open_line)
  83.       call last_char(clos_pat, close_line, close_col, close_col, close_line)
  84.  
  85.       if (open_line = -1) then leave      -- No opening character
  86.       else
  87.         if (more_recent(open_col, open_line, close_col, close_line)) then
  88.           -- Found our opening character
  89.           found = 1
  90.           leave
  91.         else
  92.           -- keep searching; the opening & closing we found (if we found any)
  93.           --            cancel each other (note that the opening & closing
  94.           --            chars don't necessarily match each other, but we
  95.           --            don't care for our purposes)
  96.           call minus_one(close_col, close_line)
  97.         endif
  98.       endif
  99.     endloop
  100.  
  101.     prestore_pos(screenpos)      -- Restore relative screen position
  102.     compile if EPM
  103.       -- Turn back on non-critical error messages and screen updates
  104.       display 3
  105.     compile else
  106.       sayerror 0                 -- Clear any pending error
  107.       -- Turn back on screen updates
  108.       display 1
  109.     compile endif
  110.     setsearch user_pattern       -- Restore user's search pattern
  111.  
  112.     if (found = 1) then
  113.       -- Calculate Screen Boundaries
  114.       top_line   = .LINE - .CURSORY + 1
  115.       left_col   = .COL  - .CURSORX + 1
  116.       rite_col   = left_col + .WINDOWWIDTH - 1
  117.  
  118.       if (on_screen(open_col, open_line, top_line, left_col, rite_col)) then
  119.         -- The open character is on the screen, so highlight it
  120.         call show_char(open_char, open_col, open_line, top_line, left_col)
  121.  
  122.         -- The open character is not on the screen, so display its position
  123.       else call show_at_bottom(open_col, open_line)
  124.       endif
  125.  
  126.     else
  127.       sayerror "No matching opening" type
  128.       call beep(fail_beep_Hz, 100)
  129.     endif
  130.  
  131. compile if (NOT EPM)         -- end of 'if commandstate()' (not for EPM)
  132.   endif
  133. compile endif
  134.  
  135. defproc minus_one (var col, var line)
  136. -- Subtracts one from the column position.  If we hit the left column in
  137. -- doing so, we go up to the line above us.
  138.   col = col - 1
  139.   if (col = 0) then
  140.     line = line - 1
  141.     getline x, line
  142.     col = length(x)
  143.   endif
  144.  
  145. defproc last_char (search_pat, line_no, col_no, var new_x, var new_y)
  146. -- Return the cursor position where the search ends, starting at given
  147. -- position.  '-1' means that the search was unsuccessful
  148.   if (col_no <> -1) then
  149.     .COL = col_no
  150.     .LINE = line_no
  151.     search_pat
  152.   endif
  153.   if (col_no = -1 OR rc = sayerror('String not found')) then
  154.     new_x = -1
  155.     new_y = -1
  156.   else
  157.     new_x = .COL
  158.     new_y = .LINE
  159.   endif
  160.  
  161. defproc more_recent (c1_x, c1_y, c2_x, c2_y)
  162. -- Says which set of coordinates (c1 or c2) is closer to the current pos
  163. -- in the backwards direction.  1 means c1 is closer, 0 means c2 is.
  164.   if (c2_y = -1)   then return 1; endif
  165.   if (c1_y = -1)   then return 0; endif
  166.   if (c1_y > c2_y) then return 1
  167.   else
  168.     if (c2_y > c1_y OR c2_x > c1_x) then return 0
  169.     else return 1
  170.     endif
  171.   endif
  172.  
  173. defproc show_char(open_char, x_pos, y_pos, top_line, left_col)
  174. compile if EPM
  175. ;; -------------------------------------------------------------------- ;;
  176. ;; For EPM: flash character on the screen for a moment.                 ;;
  177. ;; -------------------------------------------------------------------- ;;
  178. -- ***
  179. -- *** EPM function
  180. -- ***
  181. -- The opening character is on the screen, so we highlight it
  182.   y_coord = y_pos-top_line+1
  183.   x_coord = x_pos-left_col+1
  184.   display 0                          -- Turn off refreshing until we get a key
  185.   do j = 1 to 5
  186.       sayat open_char, y_coord, x_coord, .MARKCOLOR, 1
  187.       do i = 1 to 100
  188.       end
  189.       sayat open_char, y_coord, x_coord, .STATUSCOLOR, 1
  190.       do i = 1 to 100
  191.       end
  192.   end
  193.   display 1
  194.   refresh
  195.  
  196. compile else
  197. ;; -------------------------------------------------------------------- ;;
  198. ;; For EOS2: highlight character on the screen until user presses key.  ;;
  199. ;; -------------------------------------------------------------------- ;;
  200. -- ***
  201. -- *** EOS2 function
  202. -- ***
  203. -- The opening character is on the screen, so we highlight it
  204.   y_coord = y_pos-top_line+1+.BOXY
  205.   x_coord = x_pos-left_col+1+.BOXX
  206.   sayat open_char, y_coord, x_coord, .COMMANDCOLOR, 1
  207.   display 0                          -- Turn off refreshing until we get a key
  208.   k = mgetkey()                      -- Wait for keypress to unhighlight it
  209.   display 1
  210.   refresh                            -- Let screen refresh unhighlight it
  211.   executekey k
  212.   refresh                            -- Let screen refresh unhighlight it
  213.  
  214. compile endif
  215.  
  216. defproc on_screen(x_pos, y_pos, top_line, left_col, right_col)
  217.   if ((y_pos < top_line) OR (x_pos < left_col) OR (x_pos > right_col)) then
  218.     return (0)
  219.   else
  220.     return (1)
  221.   endif
  222.  
  223. defproc show_at_bottom (open_col, open_line)
  224.   -- Opening character not on screen, so tell user in message area where it is
  225.   getline line_str, open_line
  226.   if (.LINE = open_line) then
  227.     report_len = .COL - open_col - 1
  228.   else
  229.     report_len = length(line_str) - open_col + 1
  230.   endif
  231.   report_line = substr(line_str, open_col, report_len)
  232.   if (length(report_line) > 20) then
  233.     report_line = substr(report_line, 1, 20) "..."
  234.   endif
  235.   sayerror "Line" open_line":" report_line
  236.  
  237.