incr.sl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2. %
  3. % Incremental-Search.SL - Incremental Search Routines for NMODE
  4. %
  5. % Author: Jeffrey Soreff
  6. % Hewlett-Packard/CRC
  7. % Date: 21 December 1982
  8. % Revised: 17 February 1982
  9. %
  10. % 17-Feb-83 Alan Snyder
  11. % Fixed to allow pushback of bit-prefix characters.
  12. % 7-Feb-83 Alan Snyder
  13. % Revised to refresh all windows when writing message (write-message no
  14. % longer does this).
  15. % 18 January 1982 Jeffrey Soreff
  16. % This was revised to preserve the message existing before a search.
  17. %
  18. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  19. (CompileTime (load fast-strings fast-vectors fast-int extended-char))
  20. (BothTimes (load objects))
  21. % Global Variables
  22. (fluid '(text-last-searched-for))
  23. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  24. %
  25. % Actual Command Functions
  26. %
  27. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  28. (de incremental-search-command () (incr-search 1))
  29. (de reverse-search-command () (incr-search -1))
  30. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  31. %
  32. % Support Objects and Methods
  33. %
  34. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  35. (defflavor search-state
  36. ((state-list nil)
  37. (halt nil) % Halt means that the search should halt on this iteration.
  38. direct % This is the direction of the search: +1 for forward, -1 for back.
  39. (repeat-flag nil) % When repeating a search for the same text as before.
  40. (found-flag t) % This flag indicates that the current text was found.
  41. (place (buffer-get-position)) % This is set to the start of text found.
  42. (apparent-place (buffer-get-position))
  43. % Apparent-place is put where the user should see the cursor: after the
  44. % text for forward searching, and before it for backward searching.
  45. (text [""])) % The text being searched for.
  46. ()
  47. (gettable-instance-variables halt)
  48. (initable-instance-variables direct)
  49. )
  50. (defmethod (search-state push) ()
  51. % This method stores the information needed when one deletes a
  52. % character from the search string. It affects only state-list.
  53. (setf state-list
  54. (cons
  55. (vector direct repeat-flag found-flag place apparent-place)
  56. state-list)))
  57. (defmethod (search-state pop) ()
  58. % This method restores the last state of the search. The text is
  59. % recomputed on the fly, while most of the other elements of the
  60. % state are explicitly retrieved from the list. "Halt" is not
  61. % retrieved, since the search should never pass a state where halt
  62. % is true. In addition to altering local variables,
  63. % text-last-searched-for is set equal to the truncated text, and
  64. % point is moved to its last location.
  65. (unless repeat-flag (setf text (trim-text text)))
  66. (when (cdr state-list)
  67. (setf state-list (cdr state-list))
  68. (setf text-last-searched-for text)) % see next line.
  69. % Don't destroy information from previous search if one is in the
  70. % first state of a search and a deletion is attempted.
  71. (let ((state (car state-list)))
  72. (setf direct (vector-fetch state 0))
  73. (setf repeat-flag (vector-fetch state 1))
  74. (setf found-flag (vector-fetch state 2))
  75. (setf place (vector-fetch state 3))
  76. (setf apparent-place (vector-fetch state 4)))
  77. (buffer-set-position apparent-place))
  78. (defmethod (search-state do-search) (next-command)
  79. % This method sets up searches. It analyses the current command to
  80. % determine if a search for old text is being repeated, or if a new
  81. % character is being added on to the existing text. It updates the
  82. % text being searched for, the record of the last text searched for,
  83. % the direction of the search, and it sets up point before searches.
  84. (let ((char-add-list nil))
  85. (cond ((setf repeat-flag (=> next-command repeat-flag))
  86. (setf direct (=> next-command direct))
  87. (when (and (= direct (vector-fetch (car state-list) 0))
  88. % The direction hasn't changed since the last search.
  89. (equal text [""]))
  90. (setf repeat-flag nil) % This is not a search for the text last searched for.
  91. (setf char-add-list (text2list text-last-searched-for))))
  92. (t (setf char-add-list (list (=> next-command char)))))
  93. (if repeat-flag
  94. (=> self actual-search)
  95. % else
  96. (for (in current-char char-add-list)
  97. (do (setf text (new-text text current-char))
  98. (buffer-set-position place)
  99. (=> self actual-search)))))
  100. (unless (equal text [""]) (setf text-last-searched-for text)))
  101. (defmethod (search-state actual-search) ()
  102. % This method does the actual searching for text. It first checks to
  103. % see if the search could possibly succeed, which it couldn't if the
  104. % search just extends a previously unsuccessful search in the old
  105. % direction. This method also stores the location of the start of
  106. % the new text and the location at which the user should see the
  107. % cursor after the search.
  108. (when (or found-flag (~= direct (vector-fetch (car state-list) 0)))
  109. % One should search if the last text was found or the direction has changed.
  110. (let ((backed-up (when (and repeat-flag (< direct 0))
  111. (move-backward-character))))
  112. % Avoid jamming at the current string in repeated backward search.
  113. (setf found-flag (buffer-text-search? text direct))
  114. (when (not found-flag) (ding))
  115. (when (and backed-up (not found-flag)) (move-forward-character))))
  116. (when found-flag
  117. (setf place (buffer-get-position))
  118. (if (> direct 0) (move-over-text text))
  119. (setf apparent-place (buffer-get-position))) % end of text if forward
  120. (buffer-set-position apparent-place)
  121. (=> self push))
  122. (defmethod (search-state super-pop) ()
  123. % This method pops off all unsuccessful searches or, if the last
  124. % search was successful, undoes all the searching.
  125. (cond (found-flag (setf state-list (lastpair state-list)) % first state
  126. (setf text [""])
  127. (setf halt t)
  128. (=> self pop))
  129. (t (while (not found-flag)
  130. (=> self pop))
  131. (ding))))
  132. (defmethod (search-state init) ()
  133. (=> self prompt)
  134. (=> self push))
  135. (defmethod (search-state prompt) ()
  136. (update-message text found-flag direct))
  137. (defflavor parsed-char
  138. (char halt pop-flag repeat-flag direct)
  139. % Char is the next character returned after processing. Halt is a
  140. % flag indicating if the searching should halt unconditionally.
  141. % Pop-flag indicates whether a delete is being done. Repeat-flag
  142. % indicates whether one of the commands (^R and ^S) which trigger
  143. % searching for the same text as before (but possibly in a new
  144. % direction) has occured. Direct indicates the direction that the
  145. % search should take.
  146. ()
  147. gettable-instance-variables)
  148. (defmethod (parsed-char parse-next-character) ()
  149. % This function inputs and parses new characters or commands.
  150. (setf char (input-terminal-character))
  151. (setf halt nil)
  152. (setf pop-flag nil)
  153. (setf repeat-flag nil)
  154. (let ((up-char (X-Char-Upcase char)))
  155. (cond ((= up-char (x-char C-Q))
  156. (setf char (input-direct-terminal-character)))
  157. ((or (= up-char (x-char Rubout))(= up-char (x-char Backspace)))
  158. (setf repeat-flag nil)
  159. (setf pop-flag t))
  160. ((= up-char (x-char C-G))
  161. (setf repeat-flag t)
  162. (setf pop-flag t))
  163. ((or (= up-char (x-char C-S))(= up-char (x-char C-R)))
  164. (setf repeat-flag t)
  165. (if (= up-char (x-char C-S))
  166. (setf direct +1)
  167. (setf direct -1)))
  168. ((= up-char (x-char Escape))
  169. (setf halt t))
  170. ((or (= up-char (x-char Return))(not (X-Control? up-char))))
  171. % The last line detects normal characters.
  172. (t % normal control character
  173. (push-back-input-character char)
  174. (setf halt t)))))
  175. (de incr-search (direct)
  176. % The main function for the search
  177. (let* ((old-msg (write-message ""))
  178. (search-at (make-instance 'search-state 'direct direct))
  179. (next-command (make-instance 'parsed-char)))
  180. (while (continue search-at next-command) % gets and parses next char
  181. % The main loop for the search
  182. (if (=> next-command pop-flag)
  183. (if (=> next-command repeat-flag)
  184. (=> search-at super-pop)
  185. (=> search-at pop))
  186. (=> search-at do-search next-command))
  187. (=> search-at prompt))
  188. (write-message old-msg))) % This restores the message after the search.
  189. (de continue (search-state parsed-char)
  190. % This function parses the next input character, if that is called
  191. % for, and determines if the search should continue or be halted. It
  192. % returns a boolean value which is true if the search should
  193. % continue.
  194. (unless
  195. (=> search-state halt)
  196. (=> parsed-char parse-next-character)
  197. (not (=> parsed-char halt))))
  198. (de update-message (text found direct)
  199. % This function displays the last line of the search string, whether
  200. % it was found, and in what direction the search proceeded.
  201. (let* ((line-count (vector-upper-bound text))
  202. (last-line (vector-fetch text line-count)))
  203. (write-message
  204. (string-concat
  205. (if found "" "Failing ")
  206. (if (> direct 0) "" "Reverse ")
  207. "I-search: "
  208. last-line))
  209. (nmode-refresh)
  210. ))
  211. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  212. %
  213. % Start of text handling functions
  214. %
  215. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  216. (de move-over-text (text)
  217. % This function moves point to the end of a chunk of text, assuming
  218. % that point is started at the beginning of the text.
  219. (let ((line-count (vector-upper-bound text)))
  220. (set-line-pos (+ (current-line-pos) line-count))
  221. (if (> line-count 0)(move-to-start-of-line))
  222. (move-over-characters (string-length (vector-fetch text line-count)))))
  223. (de trim-text (old-text)
  224. % This is a pure function, without side effects. It trims one
  225. % character or empty line return off the old text. It will not,
  226. % however, delete the last null string from a text vector. In that
  227. % case it dings and returns the old text.
  228. (let* ((line-count (vector-upper-bound old-text))
  229. (short-text (sub old-text 0 (- line-count 1)))
  230. (last-line (vector-fetch old-text line-count))
  231. (last-count (string-length last-line)))
  232. (if (> last-count 0)
  233. (concat short-text (vector (sub last-line 0 (- last-count 2))))
  234. (if (> line-count 0) short-text (Ding) old-text))))
  235. (de new-text (old-text char)
  236. % This is a pure function, without side effects. It returns an
  237. % updated version of the text vector. It updates the text vector by
  238. % adding a new character or a new line.
  239. (let* ((line-count (vector-upper-bound old-text))
  240. (short-text (sub old-text 0 (- line-count 1)))
  241. (last-line (vector-fetch old-text line-count)))
  242. (if (= char (x-char Return))
  243. (concat old-text [""])
  244. (concat short-text
  245. (vector (string-concat last-line (string char)))))))
  246. (de text2list (text)
  247. % This function converts text into a list of characters, with cursor
  248. % returns where the breaks between strings used to be.
  249. (append (string2list (vector-fetch text 0))
  250. (for (from indx 1 (vector-upper-bound text) 1)
  251. (join (cons (x-char return)
  252. (string2list (vector-fetch text indx)))))))
  253. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  254. %
  255. % Start of text searching functions
  256. %
  257. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  258. (de buffer-text-search? (text direct)
  259. % This function searches in the buffer for the specified text. The
  260. % direct is +1 for forward searching and -1 for backward
  261. % searching. This function leaves point at the start of the text,
  262. % if it is found, and at the old point if the text is not found.
  263. % This function returns a boolean, true if it found the text.
  264. (let ((current-place (buffer-get-position))
  265. (match-rest nil))
  266. (while (and (not match-rest)
  267. (buffer-search (vector-fetch text 0) direct))
  268. (setf match-rest (match-rest-of-text? text))
  269. (unless match-rest
  270. (if (> direct 0)(move-forward)(move-backward))))
  271. (unless match-rest (buffer-set-position current-place))
  272. match-rest))
  273. (de match-rest-of-text? (text)
  274. % This function determines if two conditions are satified: First,
  275. % that all lines in text except the last fill out their respective
  276. % lines. Second, that all lines except the first match their
  277. % respective lines. This function assumes that point is initially
  278. % at the start of a string which matches the first string in text.
  279. % It also assumes that text is in upper case. This function returns
  280. % a boolean value. It does not move point.
  281. (let ((temp nil) % This avoids a compiler bug.
  282. (indx 0)
  283. (match-rest t)
  284. (line (current-line-pos))
  285. (char-pos (current-char-pos)))
  286. (while (and match-rest (< indx (vector-upper-bound text)))
  287. (setf temp (+ char-pos (string-length (vector-fetch text indx))))
  288. (setf match-rest
  289. (and match-rest % Check filling out of lines.
  290. (= temp
  291. (string-length (current-buffer-fetch (+ line indx))))))
  292. (setf char-pos 0) % Only the first string is set back on its line.
  293. (incr indx)
  294. (setf match-rest
  295. (and match-rest % Check matching of lines.
  296. (pattern-matches-in-line
  297. (string-upcase (vector-fetch text indx))
  298. (current-buffer-fetch (+ line indx)) 0))))
  299. (and match-rest (= indx (vector-upper-bound text)))))