replace.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /* replace.c, Ait Emacs, Kevin Bloom, BSD 3-Clause, 2023-2024 */
  2. #include <string.h>
  3. #include "header.h"
  4. #include "termbox.h"
  5. #include "util.h"
  6. /* These aren't used anywhere else, so I'm fine with leaving them out of
  7. the header.
  8. */
  9. char pquery[STRBUF_M];
  10. char pwith[STRBUF_M];
  11. /*search for a string and replace it with another string */
  12. void query_replace(void)
  13. {
  14. point_t o_point = curbp->b_point;
  15. point_t l_point = -1;
  16. point_t found, mark;
  17. char question[STRBUF_L];
  18. int slen, rlen; /* length of search and replace strings */
  19. int numsub = 0; /* number of substitutions */
  20. int ask = TRUE, last = FALSE, c;
  21. struct tb_event ev;
  22. const char *qmsg = "Query replace";
  23. char *querymsg;
  24. if(pquery[0] != '\0' && pwith[0] != '\0') {
  25. asprintf(&querymsg, "%s (default %s -> %s): ", qmsg, pquery, pwith);
  26. } else {
  27. asprintf(&querymsg, "%s: ", qmsg);
  28. }
  29. memset(searchtext, 0, STRBUF_M);
  30. memset(replace, 0, STRBUF_M);
  31. if (!getinput(querymsg, (char*)searchtext, STRBUF_M, F_CLEAR, TRUE))
  32. return;
  33. if(searchtext[0] == '\0') {
  34. strncpy(searchtext, pquery, STRBUF_M);
  35. strncpy(replace, pwith, STRBUF_M);
  36. } else if (!getinput("With: ", (char*)replace, STRBUF_M, F_CLEAR, TRUE))
  37. return;
  38. memcpy(pquery, searchtext, STRBUF_M);
  39. memcpy(pwith, replace, STRBUF_M);
  40. slen = strlen(searchtext);
  41. rlen = strlen(replace);
  42. /* build query replace question string */
  43. sprintf(question, "Replace '%s' with '%s' ? ", searchtext, replace);
  44. /* scan through the file, from point */
  45. numsub = 0;
  46. while(TRUE) {
  47. found = search_forward(curbp, curbp->b_point, searchtext);
  48. /* if not found set the point to the last point of replacement, or where we started */
  49. if (found == -1) {
  50. curbp->b_point = (l_point == -1 ? o_point : l_point);
  51. break;
  52. }
  53. curbp->b_point = found;
  54. /* search_forward places point at end of search, move to start of search */
  55. curbp->b_point -= slen;
  56. search_dir = 1;
  57. found_point = found;
  58. if (ask == TRUE) {
  59. msg(question);
  60. clrtoeol(question, MSGLINE);
  61. qprompt:
  62. update_display();
  63. if(execute_kbd_macro) {
  64. use_kbd_macro(&ev);
  65. } else if(tb_poll_event(&ev) != TB_OK)
  66. return;
  67. if(!ev.mod)
  68. c = ev.ch;
  69. else
  70. c = ev.key;
  71. if(record_input) {
  72. record_buffer[record_buffer_index] = ev;
  73. record_buffer_index++;
  74. }
  75. switch (c) {
  76. case 'y': /* yes, substitute */
  77. break;
  78. case 'n': /* no, find next */
  79. curbp->b_point = found; /* set to end of search string */
  80. continue;
  81. case '!': /* yes/stop asking, do the lot */
  82. ask = FALSE;
  83. found_point = -1;
  84. break;
  85. case 'l': /* last replacement */
  86. last = TRUE;
  87. break;
  88. case TB_KEY_CTRL_G:
  89. case TB_KEY_ESC: /* esc */
  90. case TB_KEY_ENTER:
  91. case 'q': /* controlled exit */
  92. found_point = -1;
  93. shift_pmark(TRUE, o_point);
  94. shift_pmark(TRUE, curbp->b_point);
  95. msg("%d substitutions", numsub);
  96. return;
  97. default: /* help me */
  98. msg("(y)es, (n)o, (!)do the rest, (l)last, (q)uit");
  99. goto qprompt;
  100. }
  101. }
  102. mark = curbp->b_mark;
  103. curbp->b_mark = curbp->b_point + slen;
  104. undoset(REPLACE, rlen);
  105. curbp->b_mark = mark;
  106. if (rlen > slen) {
  107. movegap(curbp, found);
  108. /*check enough space in gap left */
  109. if (rlen - slen < curbp->b_egap - curbp->b_gap)
  110. growgap(curbp, rlen - slen);
  111. /* shrink gap right by r - s */
  112. curbp->b_gap = curbp->b_gap + (rlen - slen);
  113. } else if (slen > rlen) {
  114. movegap(curbp, found);
  115. /* stretch gap left by s - r, no need to worry about space */
  116. curbp->b_gap = curbp->b_gap - (slen - rlen);
  117. } else {
  118. /* if rlen = slen, we just overwrite the chars, no need to move gap */
  119. }
  120. /* now just overwrite the chars at point in the buffer */
  121. l_point = curbp->b_point;
  122. memcpy(ptr(curbp, curbp->b_point), replace, rlen * sizeof (char_t));
  123. curbp->b_flags |= B_MODIFIED;
  124. curbp->b_point = found - (slen - rlen); /* end of replcement */
  125. numsub++;
  126. if(last)
  127. break;
  128. }
  129. found_point = -1;
  130. shift_pmark(TRUE, o_point);
  131. shift_pmark(TRUE, curbp->b_point);
  132. if(curbp->b_point > curbp->b_epage && !ask) {
  133. curbp->b_reframe = TRUE;
  134. }
  135. msg("%d substitutions", numsub);
  136. }