search.red 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. %
  2. % SEARCH.RED - Search utilities for EMODE
  3. %
  4. % Author: William F. Galway
  5. % Symbolic Computation Group
  6. % Computer Science Dept.
  7. % University of Utah
  8. % Date: 8 June 1982
  9. % Copyright (c) 1982 University of Utah
  10. %
  11. % These routines to implement minimal string searches for EMODE. Searches
  12. % are non-incremental, limited to single line patterns, and always ignore
  13. % case. This file also includes routines for moving over other patterns
  14. % (words, etc.).
  15. %%%%% Changes: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  16. % AS 7/15/82
  17. % - Fixed skip_backward_blanks to behave properly at the beginning
  18. % of the buffer (loop termination test was incorrect).
  19. % - Use sleep primitive for insert_matching_paren.
  20. FLUID '(
  21. last_search_string
  22. );
  23. Symbolic Procedure forward_string_search();
  24. % Invoked from keyboard, search forward from point for string, leave
  25. % "point" unchanged if not found.
  26. begin scalar strng;
  27. % Get search string, update default.
  28. strng :=
  29. last_search_string :=
  30. prompt_for_string("Forward search: ", last_search_string);
  31. if buffer_search(strng, 1) then % 1 for forward search, and if found
  32. for i := 0:size(strng) do % move to end of string.
  33. !$ForwardCharacter();
  34. end;
  35. Symbolic Procedure reverse_string_search();
  36. % Invoked from keyboard, search backwards from point for string, leave
  37. % "point unchanged if not found.
  38. begin scalar strng;
  39. strng :=
  40. last_search_string :=
  41. prompt_for_string("Reverse Search: ", last_search_string);
  42. !$Backwardcharacter(); % Back up before starting search.
  43. if not buffer_search(strng, -1) then % -1 for backward search
  44. !$ForwardCharacter(); % restore point if not found.
  45. end;
  46. Symbolic Procedure buffer_search(strng,dir);
  47. % Search in buffer for strng. "Ding" and leave point unchanged if
  48. % not found, return NIL if not found. dir is +1 for forward, -1
  49. % for backward.
  50. begin scalar search_point, search_lineindex, found, within_buffer;
  51. PutLine(); % Make sure line is "saved" in buffer
  52. % Start at current location in the buffer.
  53. search_lineindex := CurrentLineIndex;
  54. search_point := min(point, size GetBufferText(search_lineindex));
  55. within_buffer := not EndOfBufferP(search_lineindex);
  56. while within_buffer
  57. and not (found := subscript(strng,
  58. GetBufferText(search_lineindex),
  59. search_point,
  60. dir))
  61. do
  62. <<
  63. % Move to "beginning" of "next" line
  64. if dir > 0 then
  65. <<
  66. within_buffer := not EndOfBufferP(NextIndex search_lineindex);
  67. if within_buffer then
  68. <<
  69. search_lineindex := NextIndex(search_lineindex);
  70. search_point := 0;
  71. >>;
  72. >>
  73. else
  74. <<
  75. within_buffer := not BeginningOfBufferP(search_lineindex);
  76. if within_buffer then
  77. <<
  78. search_lineindex := PreviousIndex(search_lineindex);
  79. search_point := size GetBufferText(search_lineindex);
  80. >>;
  81. >>;
  82. >>;
  83. if found then
  84. <<
  85. SelectLine(search_lineindex);
  86. point := found;
  87. >>
  88. else
  89. Ding();
  90. return found;
  91. end;
  92. Symbolic Procedure subscript(pattern,strng,start,dir);
  93. % Locate pattern in strng, starting at "start", searching in direction
  94. % "dir" (+1 for forward search, -1 for backward search).
  95. % Return NIL if not found, otherwise return the subscript of the first
  96. % matching character.
  97. begin scalar found;
  98. while 0 <= start and start <= size strng
  99. and not (found := is_substring(pattern,strng,start))
  100. do
  101. start := start + dir;
  102. return
  103. if found then
  104. start
  105. else
  106. NIL;
  107. end;
  108. Symbolic Procedure RaiseChar(ch);
  109. % Return character code for upper case version of character.
  110. % (ch is a character code.)
  111. if ch < char lower 'a or ch > char lower 'z then
  112. ch
  113. else
  114. ch - char lower 'a + char 'A;
  115. Symbolic Procedure is_substring(substrng,strng,start);
  116. % Return T if substrng occurs as substring of strng, starting at "start".
  117. % Ignore case differences.
  118. begin scalar i;
  119. i := 0;
  120. while i <= size(substrng) and i+start <= size(strng)
  121. and RaiseChar substrng[i] = RaiseChar strng[i+start]
  122. do
  123. i := i + 1;
  124. return
  125. i > size(substrng); % T if all chars matched, false otherwise.
  126. end;
  127. FLUID '(paren_depth);
  128. Symbolic Procedure adjust_depth(ch);
  129. % Adjust paren_depth based on the character.
  130. if ch = char !( then
  131. paren_depth := paren_depth + 1
  132. else if ch = char !) then
  133. paren_depth := paren_depth - 1;
  134. Symbolic Procedure skip_forward_blanks();
  135. % Skip over "blanks", return the first non-blank character seen.
  136. begin scalar ch;
  137. while
  138. not (EndOfBufferP(NextIndex CurrentLineIndex)
  139. and point = length CurrentLine)
  140. AND
  141. % 17 means "ignore".
  142. CurrentScanTable!*[ch := CurrentCharacter()] = 17
  143. do
  144. !$ForwardCharacter();
  145. return ch;
  146. end;
  147. Symbolic Procedure skip_backward_blanks();
  148. % Skip backwards over "blanks", return the first non-blank character seen.
  149. begin scalar ch, flg;
  150. flg := T;
  151. while
  152. not (BeginningOfBufferP(CurrentLineIndex) and point = 0)
  153. AND
  154. flg
  155. do
  156. <<
  157. !$BackwardCharacter();
  158. % 17 means "ignore".
  159. flg := CurrentScanTable!*[ch := CurrentCharacter()] = 17
  160. >>;
  161. % Position "cursor" to the right of the terminating character.
  162. if not(BeginningOfBufferP(CurrentLineIndex) AND point = 0) then
  163. !$ForwardCharacter();
  164. return ch;
  165. end;
  166. Symbolic Procedure forward_word();
  167. % Move forward one "word", starting from point.
  168. begin scalar ch;
  169. while
  170. not (EndOfBufferP(NextIndex CurrentLineIndex)
  171. and point = length CurrentLine)
  172. AND
  173. % Scan for start of word.
  174. not(LetterP(ch := skip_forward_blanks()) OR DigitP(ch))
  175. do
  176. !$ForwardCharacter();
  177. % Now, scan for end of word.
  178. while
  179. not (EndOfBufferP(NextIndex CurrentLineIndex)
  180. and point = length CurrentLine)
  181. AND
  182. (LetterP(ch := CurrentCharacter()) OR DigitP(ch))
  183. do
  184. % Can't be a paren, so don't bother to count.
  185. !$ForwardCharacter();
  186. end;
  187. Symbolic Procedure backward_word();
  188. % Move backward one "word", starting from point.
  189. begin scalar ch,flg;
  190. flg := T;
  191. % Scan for the start of a word (a "letter" or digit).
  192. while flg
  193. AND
  194. not(BeginningOfBufferP(CurrentLineIndex) AND point = 0)
  195. do
  196. <<
  197. !$BackwardCharacter();
  198. flg := not (LetterP(ch := CurrentCharacter()) OR DigitP(ch));
  199. >>;
  200. % Now, scan for "end" of identifier.
  201. flg := T;
  202. while flg
  203. AND
  204. not(BeginningOfBufferP(CurrentLineIndex) AND point = 0)
  205. do
  206. <<
  207. !$BackwardCharacter();
  208. flg := (LetterP(ch := CurrentCharacter()) OR DigitP(ch));
  209. >>;
  210. % Position "cursor" to the right of the terminating character.
  211. if not(BeginningOfBufferP(CurrentLineIndex) AND point = 0) then
  212. !$ForwardCharacter();
  213. end;
  214. Symbolic Procedure LetterP(ch);
  215. % Note that we don't use
  216. ch < 128 and CurrentScanTable!*[ch] equal 10; % 10 means "a letter".
  217. Symbolic Procedure forward_sexpr();
  218. % Move forward over a set of balanced parenthesis (roughly speaking).
  219. begin scalar ch, cline, cpoint, paren_depth; % paren_depth is FLUID.
  220. % Remember our spot.
  221. cline := CurrentLineIndex;
  222. cpoint := point;
  223. paren_depth := 0;
  224. ch := skip_forward_blanks();
  225. adjust_depth(ch);
  226. if paren_depth > 0 then % Skip over balanced parens, if first thing was
  227. % a paren.
  228. <<
  229. while not (EndOfBufferP(NextIndex CurrentLineIndex)
  230. and point = length CurrentLine)
  231. AND
  232. paren_depth > 0
  233. do
  234. <<
  235. !$ForwardCharacter();
  236. adjust_depth CurrentCharacter();
  237. >>;
  238. % Complain, and avoid moving point, if match not found.
  239. if paren_depth > 0 then
  240. <<
  241. ding();
  242. PutLine();
  243. point := cpoint;
  244. GetLine(cline);
  245. >>
  246. else
  247. !$ForwardCharacter(); % Skip over trailing right paren.
  248. >>
  249. % Otherwise (paren not first character seen), just skip a word.
  250. else
  251. forward_word()
  252. end;
  253. Symbolic Procedure backward_sexpr();
  254. % Move backwards over a set of balanced parenthesis (roughly speaking).
  255. begin scalar ch, flg, cline, cpoint, paren_depth; % paren_depth is FLUID.
  256. % Remember our spot.
  257. cline := CurrentLineIndex;
  258. cpoint := point;
  259. paren_depth := 0;
  260. ch := skip_backward_blanks();
  261. flg := T;
  262. if ch = char !) then % Skip over balanced parens, if first thing was
  263. % a paren.
  264. <<
  265. while not(BeginningOfBufferP(CurrentLineIndex) AND point = 0)
  266. AND
  267. flg
  268. do
  269. <<
  270. !$BackwardCharacter();
  271. adjust_depth CurrentCharacter();
  272. flg := paren_depth < 0; % (< 0, since this is backwards search! )
  273. >>;
  274. % Complain, and avoid moving point, if match not found.
  275. if paren_depth < 0 then
  276. <<
  277. ding();
  278. PutLine();
  279. point := cpoint;
  280. GetLine(cline);
  281. >>;
  282. >>
  283. % if a left paren, just back up slightly (a bit of a KLUDGE).
  284. else if ch = char !( then
  285. !$BackwardCharacter()
  286. % Otherwise (paren not first character seen), just skip a word.
  287. else
  288. backward_word();
  289. end;
  290. Symbolic Procedure insert_matching_paren();
  291. % Insert a right parenthesis, back up to a matching left parenthesis, pause
  292. % there a "second" and then come back to current location.
  293. begin scalar cline, cpoint, flg, timer, paren_depth;
  294. InsertCharacter char !); % (Or, InsertSelfCharacter?)
  295. cline := CurrentLineIndex;
  296. cpoint := point;
  297. paren_depth := 0;
  298. flg := T;
  299. while
  300. not(BeginningOfBufferP(CurrentLineIndex) AND point = 0)
  301. AND
  302. flg
  303. do
  304. <<
  305. !$BackwardCharacter();
  306. adjust_depth CurrentCharacter();
  307. flg := paren_depth < 0;
  308. >>;
  309. if flg then % No match found
  310. ding()
  311. else
  312. <<
  313. optional_refresh(); % Show where we are, if no typeahead.
  314. % "pause" for 1/2 sec (30/60ths) or until character is typed.
  315. sleep!-until!-timeout!-or!-input(30);
  316. >>;
  317. % Go back to original spot.
  318. point := cpoint;
  319. SelectLine(cline);
  320. end;