search.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /* search.c, Ait, BSD 3-Clause, Kevin Bloom, 2023-2024,
  2. Derived from: Atto January 2017
  3. Derived from: Anthony's Editor January 93
  4. */
  5. #include "header.h"
  6. #include "termbox.h"
  7. #include "util.h"
  8. #define FWD_SEARCH 1
  9. #define REV_SEARCH 2
  10. void search_fwd()
  11. {
  12. search(FWD_SEARCH);
  13. }
  14. void search_rev()
  15. {
  16. search(REV_SEARCH);
  17. }
  18. void search(int initdir)
  19. {
  20. char *prompt = "Search: ";
  21. char *failing_prompt = "Failing Search: ";
  22. int cpos = 0;
  23. int c, dir = initdir, failed_search = FALSE;
  24. point_t o_point = curbp->b_point, o_page = curbp->b_page;
  25. point_t found = o_point;
  26. int start_col = strlen(prompt);
  27. struct tb_event ev;
  28. char prev_search[STRBUF_L];
  29. strcpy(prev_search, searchtext);
  30. memset(searchtext, 0, STRBUF_L);
  31. display_prompt_and_response(prompt, searchtext);
  32. cpos = strlen(searchtext);
  33. for (;;) {
  34. tb_present();
  35. if(execute_kbd_macro) {
  36. use_kbd_macro(&ev);
  37. } else if(tb_poll_event(&ev) != TB_OK) return;
  38. if(record_input) {
  39. record_buffer[record_buffer_index] = ev;
  40. record_buffer_index++;
  41. }
  42. start_col = found == -1 ? strlen(failing_prompt) : strlen(prompt);
  43. if(msgline_editor(ev, found == -1 ? failing_prompt : prompt, searchtext, STRBUF_L, &cpos)) {
  44. if(ev.key == TB_KEY_CTRL_Y) {
  45. if(dir == FWD_SEARCH)
  46. found = search_forward(curbp, o_point, searchtext);
  47. else
  48. found = search_backwards(curbp, o_point, searchtext);
  49. display_search_result(found, dir, prompt, searchtext, &failed_search);
  50. }
  51. continue;
  52. }
  53. if(!ev.mod)
  54. c = ev.ch;
  55. else
  56. c = ev.key;
  57. /* ignore control keys other than return, C-g, CR, C-s, C-R, ESC */
  58. if (c < 32 &&
  59. c != TB_KEY_CTRL_G &&
  60. c != TB_KEY_ENTER &&
  61. c != TB_KEY_CTRL_R &&
  62. c != TB_KEY_CTRL_S &&
  63. c != TB_KEY_CTRL_I &&
  64. c != TB_KEY_TAB &&
  65. c != TB_KEY_ESC)
  66. continue;
  67. switch(c) {
  68. case TB_KEY_ENTER: /* return */
  69. if(found != o_point) {
  70. shift_pmark(TRUE, o_point);
  71. shift_pmark(TRUE, curbp->b_point);
  72. found_point = -1;
  73. return;
  74. }
  75. found = search_forward(curbp, curbp->b_point, searchtext);
  76. display_search_result(found, FWD_SEARCH, prompt, searchtext, &failed_search);
  77. curbp->b_pcol = curbp->b_col;
  78. break;
  79. case TB_KEY_ESC: /* esc */
  80. case TB_KEY_CTRL_G: /* ctrl-g */
  81. found_point = -1;
  82. curbp->b_point = o_point;
  83. curbp->b_page = o_page;
  84. return;
  85. case TB_KEY_CTRL_S: /* ctrl-s, do the search */
  86. if(searchtext[0] == '\0') {
  87. strcpy(searchtext, prev_search);
  88. }
  89. cpos = strlen(searchtext);
  90. found = search_forward(curbp, curbp->b_point, searchtext);
  91. if(found == -1 && failed_search)
  92. found = search_forward(curbp, 0, searchtext);
  93. display_search_result(found, FWD_SEARCH, prompt, searchtext, &failed_search);
  94. dir = FWD_SEARCH;
  95. break;
  96. case TB_KEY_CTRL_R: /* ctrl-r, do the search */
  97. if(searchtext[0] == '\0') {
  98. strcpy(searchtext, prev_search);
  99. }
  100. cpos = strlen(searchtext);
  101. found = search_backwards(curbp, curbp->b_point-1, searchtext);
  102. if(found == -1 && failed_search)
  103. found = search_backwards(curbp, pos(curbp, curbp->b_ebuf), searchtext);
  104. display_search_result(found, REV_SEARCH, prompt, searchtext, &failed_search);
  105. dir = REV_SEARCH;
  106. break;
  107. case TB_KEY_BACKSPACE2: /* del, erase */
  108. case TB_KEY_BACKSPACE: /* backspace */
  109. if (cpos == 0)
  110. continue;
  111. searchtext[--cpos] = '\0';
  112. tb_set_cursor(start_col + cpos, MSGLINE);
  113. display_prompt_and_response(prompt, searchtext);
  114. break;
  115. default:
  116. if (cpos < STRBUF_L - 1) {
  117. for(int i = strlen(searchtext); i > cpos; i--) {
  118. searchtext[i] = searchtext[i - 1];
  119. }
  120. searchtext[cpos] = c;
  121. tb_set_cursor(start_col, MSGLINE);
  122. addstr(searchtext);
  123. cpos++;
  124. tb_set_cursor(start_col + cpos, MSGLINE);
  125. if(cpos == strlen(searchtext)) {
  126. if(dir == FWD_SEARCH)
  127. found = search_forward(curbp, o_point, searchtext);
  128. else
  129. found = search_backwards(curbp, o_point, searchtext);
  130. display_search_result(found, dir, prompt, searchtext, &failed_search);
  131. }
  132. }
  133. break;
  134. }
  135. }
  136. }
  137. void display_search_result(point_t found, int dir, char *prompt, char *search, int *failed_search)
  138. {
  139. int i = curwp->w_rows / 2, found_end = FALSE, shift = 0;
  140. point_t new_page = 0;
  141. if (found != -1 ) {
  142. search_dir = dir;
  143. // tb_clear();
  144. found_point = found;
  145. curbp->b_point = dir == 2 ? found + 1 : found;
  146. update_display();
  147. msg("%s%s",prompt, search);
  148. new_page = curbp->b_page;
  149. shift = curwp->w_row - i;
  150. if(dir == FWD_SEARCH) {
  151. for(int k = shift; k > 0; k--) {
  152. found_end = FALSE;
  153. while(found_end == FALSE) {
  154. if(*ptr(curbp, new_page) == '\n')
  155. found_end = TRUE;
  156. new_page++;
  157. }
  158. }
  159. } else {
  160. for(int k = shift; k < 0; k++) {
  161. new_page = lnstart(curbp,new_page - 1);
  162. }
  163. }
  164. curbp->b_page = lnstart(curbp, new_page);
  165. update_display();
  166. *failed_search = FALSE;
  167. } else {
  168. found_point = -1;
  169. msg("Failing %s%s",prompt, search);
  170. dispmsg();
  171. *failed_search = TRUE;
  172. }
  173. }
  174. point_t search_forward(buffer_t *bp, point_t start_p, char *stext)
  175. {
  176. point_t end_p = pos(bp, bp->b_ebuf);
  177. point_t p,pp;
  178. char* s;
  179. char_t * cur;
  180. int case_sense = FALSE;
  181. if (0 == strlen(stext))
  182. return start_p;
  183. for (p=start_p; p < end_p; p++) {
  184. for (s=stext, pp=p; *s !='\0' && pp < end_p; s++, pp++) {
  185. cur = ptr(bp, pp);
  186. if(isupper(*s)) {
  187. case_sense = TRUE;
  188. if(*s != *cur)
  189. break;
  190. }
  191. else if (*s != *cur && case_sense)
  192. break;
  193. else if(*s != tolower(*cur))
  194. break;
  195. }
  196. if (*s == '\0')
  197. return pp;
  198. }
  199. return -1;
  200. }
  201. point_t search_backwards(buffer_t *bp, point_t start_p, char *stext)
  202. {
  203. point_t p,pp;
  204. char* s;
  205. char_t * cur;
  206. int case_sense = FALSE;
  207. if (0 == strlen(stext))
  208. return start_p;
  209. for (p=start_p; p >= 0; p--) {
  210. for (s=stext, pp=p; *s != '\0' && pp > -1; s++, pp++) {
  211. cur = ptr(bp, pp);
  212. if(isupper(*s)) {
  213. case_sense = TRUE;
  214. if(*s != *cur)
  215. break;
  216. }
  217. else if (*s != *cur && case_sense)
  218. break;
  219. else if(*s != tolower(*cur))
  220. break;
  221. }
  222. if (*s == '\0') {
  223. if (p > 0)
  224. p--;
  225. return p;
  226. }
  227. }
  228. return -1;
  229. }