command.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. /* command.c, Ait, BSD 3-Clause, Kevin Bloom, 2023,
  2. Derived from: Atto January 2017
  3. Derived from: AnthonyEditor January 93
  4. */
  5. #include "header.h"
  6. #include "termbox.h"
  7. #include "util.h"
  8. void quit() { done = 1; }
  9. void up()
  10. {
  11. curbp->b_point = lncolumn(curbp, upup(curbp, curwp, curbp->b_point),curbp->b_pcol - curwp->w_left);
  12. }
  13. void down()
  14. {
  15. curbp->b_point = lncolumn(curbp, dndn(curbp, curwp, curbp->b_point),curbp->b_pcol - curwp->w_left);
  16. }
  17. void lnbegin()
  18. {
  19. curbp->b_point = segstart(curbp, curwp, lnstart(curbp, curbp->b_point), curbp->b_point);
  20. }
  21. void version() { msg(VERSION); }
  22. void top() { curbp->b_point = 0; }
  23. void bottom()
  24. {
  25. curbp->b_point = pos(curbp, curbp->b_ebuf);
  26. if (curbp->b_epage < pos(curbp, curbp->b_ebuf))
  27. curbp->b_reframe = 1;
  28. }
  29. void block() { curbp->b_mark = curbp->b_point; }
  30. void copy() { copy_cut(FALSE, TRUE, FALSE); }
  31. void cut() { copy_cut(TRUE, TRUE, FALSE); }
  32. void resize_terminal()
  33. {
  34. LINES = tb_height();
  35. COLS = tb_width();
  36. MSGLINE = LINES-1;
  37. one_window(curwp);
  38. }
  39. void print_to_msgline(const char *msg)
  40. {
  41. printf_tb(0, MSGLINE, TB_DEFAULT, TB_DEFAULT, msg);
  42. tb_set_cursor(strlen(msg), MSGLINE);
  43. }
  44. void quit_ask()
  45. {
  46. if (modified_buffers() > 0) {
  47. const char *msg = "Modified buffers exist; really exit (y/N) ?";
  48. print_to_msgline(msg);
  49. clrtoeol(msg, MSGLINE);
  50. if (!yesno(FALSE)) {
  51. clrtoeol("", MSGLINE);
  52. return;
  53. }
  54. }
  55. quit();
  56. }
  57. void redraw()
  58. {
  59. window_t *wp;
  60. int i;
  61. for (i = 0, wp=windows[i]; wp != NULL && i < number_of_windows; i++, wp=windows[i])
  62. wp->w_update = TRUE;
  63. update_display(TRUE);
  64. }
  65. void left()
  66. {
  67. int n = prev_utf8_char_size();
  68. while (0 < curbp->b_point && n-- > 0)
  69. --curbp->b_point;
  70. }
  71. void right()
  72. {
  73. int n = utf8_size(*ptr(curbp,curbp->b_point));
  74. while ((curbp->b_point < pos(curbp, curbp->b_ebuf)) && n-- > 0)
  75. ++curbp->b_point;
  76. }
  77. /* work out number of bytes based on first byte */
  78. int utf8_size(char_t c)
  79. {
  80. if (c >= 192 && c < 224) return 2;
  81. if (c >= 224 && c < 240) return 3;
  82. if (c >= 240 && c < 248) return 4;
  83. return 1; /* if in doubt it is 1 */
  84. }
  85. int prev_utf8_char_size()
  86. {
  87. int n;
  88. for (n=2;n<5;n++)
  89. if (-1 < curbp->b_point - n && (utf8_size(*(ptr(curbp, curbp->b_point - n))) == n))
  90. return n;
  91. return 1;
  92. }
  93. void lnend()
  94. {
  95. if (curbp->b_point == pos(curbp, curbp->b_ebuf)) return; /* do nothing if EOF */
  96. curbp->b_point = dndn(curbp, curwp, curbp->b_point);
  97. point_t p = curbp->b_point;
  98. left();
  99. curbp->b_point = (*ptr(curbp, curbp->b_point) == '\n') ? curbp->b_point : p;
  100. }
  101. void wleft()
  102. {
  103. char_t *p;
  104. if ((!isspace(*(p = ptr(curbp, curbp->b_point))) || !is_symbol(*p)) && curbp->b_buf < p)
  105. --curbp->b_point;
  106. while ((isspace(*(p = ptr(curbp, curbp->b_point))) || is_symbol(*p)) && curbp->b_buf < p)
  107. --curbp->b_point;
  108. while (!isspace(*(p = ptr(curbp, curbp->b_point))) && !is_symbol(*p) && curbp->b_buf < p)
  109. --curbp->b_point;
  110. if(isspace(*(p = ptr(curbp, curbp->b_point))) || is_symbol(*p))
  111. ++curbp->b_point;
  112. }
  113. void wleftdelete()
  114. {
  115. // undoset();
  116. iblock();
  117. wleft();
  118. copy_cut(TRUE, TRUE, FALSE);
  119. }
  120. void pgdown()
  121. {
  122. curbp->b_page = curbp->b_point = upup(curbp, curwp, curbp->b_epage);
  123. while (0 < curbp->b_row--)
  124. down();
  125. curbp->b_epage = pos(curbp, curbp->b_ebuf);
  126. curbp->b_pcol = 0;
  127. }
  128. void pgup()
  129. {
  130. int i = curwp->w_rows;
  131. while (0 < --i) {
  132. curbp->b_page = upup(curbp, curwp, curbp->b_page);
  133. up();
  134. }
  135. curbp->b_pcol = 0;
  136. }
  137. void wright()
  138. {
  139. char_t *p;
  140. if ((!isspace(*(p = ptr(curbp, curbp->b_point))) || !is_symbol(*p)) && p < curbp->b_ebuf)
  141. ++curbp->b_point;
  142. while ((isspace(*(p = ptr(curbp, curbp->b_point))) || is_symbol(*p)) && p < curbp->b_ebuf)
  143. ++curbp->b_point;
  144. while (!isspace(*(p = ptr(curbp, curbp->b_point))) && !is_symbol(*p) && p < curbp->b_ebuf)
  145. ++curbp->b_point;
  146. }
  147. void wrightdelete()
  148. {
  149. // undoset();
  150. iblock();
  151. wright();
  152. copy_cut(TRUE, TRUE, FALSE);
  153. }
  154. void insert()
  155. {
  156. assert(curbp->b_gap <= curbp->b_egap);
  157. if(lastcommand != KBD_INSERT)
  158. undoset();
  159. if (curbp->b_gap == curbp->b_egap && !growgap(curbp, CHUNK))
  160. return;
  161. curbp->b_point = movegap(curbp, curbp->b_point);
  162. if(!undoset_flag)
  163. undoset();
  164. /* overwrite if mid line, not EOL or EOF, CR will insert as normal */
  165. if ((curbp->b_flags & B_OVERWRITE) && *input != '\r' && *(ptr(curbp, curbp->b_point)) != '\n' && curbp->b_point < pos(curbp,curbp->b_ebuf) ) {
  166. *(ptr(curbp, curbp->b_point)) = *input;
  167. if (curbp->b_point < pos(curbp, curbp->b_ebuf))
  168. ++curbp->b_point;
  169. } else {
  170. *curbp->b_gap++ = *input == '\r' ? '\n' : *input;
  171. curbp->b_point = pos(curbp, curbp->b_egap);
  172. // force reframe if scrolled off bottom of screen and at EOF
  173. if (curbp->b_point == pos(curbp, curbp->b_ebuf) && curbp->b_point >= curbp->b_epage) curbp->b_reframe = 1;
  174. }
  175. curbp->b_flags |= B_MODIFIED;
  176. undoset_flag = TRUE;
  177. lastcommand = KBD_INSERT;
  178. }
  179. void insert_str()
  180. {
  181. int len = strlen((const char *)input);
  182. assert(curbp->b_gap <= curbp->b_egap);
  183. undoset();
  184. if (curbp->b_gap == curbp->b_egap && !growgap(curbp, CHUNK))
  185. return;
  186. curbp->b_point = movegap(curbp, curbp->b_point);
  187. if(!undoset_flag)
  188. undoset();
  189. /* overwrite if mid line, not EOL or EOF, CR will insert as normal */
  190. if ((curbp->b_flags & B_OVERWRITE) && input[0] != '\r' && *(ptr(curbp, curbp->b_point)) != '\n' && curbp->b_point < pos(curbp,curbp->b_ebuf) ) {
  191. *(ptr(curbp, curbp->b_point)) = *input;
  192. if (curbp->b_point < pos(curbp, curbp->b_ebuf))
  193. ++curbp->b_point;
  194. } else {
  195. for(int i = 0; i < len; i++) {
  196. *curbp->b_gap++ = input[i] == '\r' ? '\n' : input[i];
  197. }
  198. curbp->b_point = pos(curbp, curbp->b_egap);
  199. // force reframe if scrolled off bottom of screen and at EOF
  200. if (curbp->b_point == pos(curbp, curbp->b_ebuf) && curbp->b_point >= curbp->b_epage) curbp->b_reframe = 1;
  201. }
  202. curbp->b_flags |= B_MODIFIED;
  203. undoset_flag = TRUE;
  204. }
  205. void insert_unicode()
  206. {
  207. int len = strlen((const char *)unicode_buf);
  208. assert(curbp->b_gap <= curbp->b_egap);
  209. if(lastcommand != KBD_INSERT)
  210. undoset();
  211. if (curbp->b_gap == curbp->b_egap && !growgap(curbp, CHUNK))
  212. return;
  213. curbp->b_point = movegap(curbp, curbp->b_point);
  214. if(!undoset_flag)
  215. undoset();
  216. /* overwrite if mid line, not EOL or EOF, CR will insert as normal */
  217. for(int i = 0; i < len; i++) {
  218. *curbp->b_gap++ = unicode_buf[i];
  219. }
  220. curbp->b_point = pos(curbp, curbp->b_egap);
  221. // force reframe if scrolled off bottom of screen and at EOF
  222. if (curbp->b_point == pos(curbp, curbp->b_ebuf) && curbp->b_point >= curbp->b_epage) curbp->b_reframe = 1;
  223. curbp->b_flags |= B_MODIFIED;
  224. undoset_flag = TRUE;
  225. unicode_buf[0] = '\0';
  226. lastcommand = KBD_INSERT;
  227. }
  228. void backsp()
  229. {
  230. if(lastcommand != KBD_DELETE_CHAR)
  231. undoset();
  232. curbp->b_point = movegap(curbp, curbp->b_point);
  233. if (curbp->b_buf < curbp->b_gap) {
  234. curbp->b_gap -= prev_utf8_char_size();
  235. curbp->b_flags |= B_MODIFIED;
  236. }
  237. curbp->b_point = pos(curbp, curbp->b_egap);
  238. lastcommand = KBD_DELETE_CHAR;
  239. }
  240. void delete()
  241. {
  242. if(lastcommand != KBD_DELETE_CHAR)
  243. undoset();
  244. curbp->b_point = movegap(curbp, curbp->b_point);
  245. if (curbp->b_egap < curbp->b_ebuf) {
  246. curbp->b_egap += utf8_size(*curbp->b_egap);
  247. curbp->b_point = pos(curbp, curbp->b_egap);
  248. curbp->b_flags |= B_MODIFIED;
  249. }
  250. lastcommand = KBD_DELETE_CHAR;
  251. }
  252. void gotoline()
  253. {
  254. int line;
  255. point_t p;
  256. if (getinput("Goto line: ", temp, STRBUF_S, F_CLEAR, FALSE)) {
  257. line = atoi(temp);
  258. p = line_to_point(line);
  259. if (p != -1) {
  260. curbp->b_point = p;
  261. curbp->b_pcol = 0;
  262. if (curbp->b_epage < pos(curbp, curbp->b_ebuf)) curbp->b_reframe = 1;
  263. msg("Line %d", line);
  264. } else {
  265. msg("Line %d, not found", line);
  266. }
  267. }
  268. }
  269. void get_current_path(char *cur_path)
  270. {
  271. int cutoff = 0;
  272. for(int i = strlen(curbp->b_fname) - 1; i > -1; i--) {
  273. if(curbp->b_fname[i] == '/') {
  274. cutoff = i;
  275. break;
  276. }
  277. }
  278. for(int i = 0; i <= cutoff; i++)
  279. cur_path[i] = curbp->b_fname[i];
  280. cur_path[cutoff+1] = '\0';
  281. }
  282. void insertfile()
  283. {
  284. char cur_path[NAME_MAX] = "\0";
  285. if(curbp->b_path) {
  286. get_current_path(cur_path);
  287. strcpy(temp, cur_path);
  288. }
  289. else
  290. strcpy(temp, editor_dir);
  291. if (getfilename("Insert file: ", temp, NAME_MAX))
  292. (void)insert_file(temp, TRUE);
  293. }
  294. void readfile()
  295. {
  296. buffer_t *bp;
  297. char cur_path[NAME_MAX];
  298. if(curbp->b_path) {
  299. get_current_path(cur_path);
  300. strcpy(temp, cur_path);
  301. }
  302. else
  303. strcpy(temp, editor_dir);
  304. int result = getfilename("Find file: ", (char*)temp, NAME_MAX);
  305. if (result) {
  306. bp = find_buffer(temp, TRUE);
  307. disassociate_b(curwp);
  308. curbp = bp;
  309. associate_b2w(curbp, curwp);
  310. /* load the file if not already loaded */
  311. if (bp != NULL && bp->b_fname[0] == '\0') {
  312. if (!load_file(temp)) {
  313. msg("New file %s", temp);
  314. }
  315. strncpy(curbp->b_fname, temp, NAME_MAX);
  316. curbp->b_fname[NAME_MAX] = '\0'; /* truncate if required */
  317. }
  318. }
  319. }
  320. void savebuffer()
  321. {
  322. if(curbp->b_flags & B_MODIFIED) {
  323. if (curbp->b_fname[0] != '\0') {
  324. save(curbp->b_fname);
  325. return;
  326. } else {
  327. writefile();
  328. }
  329. } else {
  330. msg("(No changes need to be saved.)");
  331. }
  332. }
  333. void writefile()
  334. {
  335. strncpy(temp, curbp->b_fname, NAME_MAX);
  336. if (getinput("Write file: ", temp, NAME_MAX, F_NONE, FALSE))
  337. if (save(temp) == TRUE)
  338. strncpy(curbp->b_fname, temp, NAME_MAX);
  339. }
  340. void killbuffer()
  341. {
  342. buffer_t *kill_bp = curbp;
  343. buffer_t *bp;
  344. int bcount = count_buffers();
  345. const char *message = "Discard changes (y/N) ?";
  346. /* do nothing if only buffer left is the scratch buffer */
  347. if (bcount == 1 && 0 == strcmp(get_buffer_name(curbp), "*scratch*"))
  348. return;
  349. if (curbp->b_flags & B_MODIFIED) {
  350. print_to_msgline(message);
  351. clrtoeol(message, MSGLINE);
  352. if (!yesno(FALSE))
  353. return;
  354. }
  355. if (bcount == 1) {
  356. /* create a scratch buffer */
  357. bp = find_buffer("*scratch*", TRUE);
  358. strncpy(bp->b_bname, "*scratch*", STRBUF_S);
  359. bp->b_path = FALSE;
  360. }
  361. next_buffer();
  362. assert(kill_bp != curbp);
  363. delete_buffer(kill_bp);
  364. }
  365. void iblock()
  366. {
  367. block();
  368. msg("Mark set");
  369. }
  370. void unmark()
  371. {
  372. curbp->b_pmark = curbp->b_mark;
  373. curbp->b_mark = NOMARK;
  374. msg("Mark removed");
  375. }
  376. void toggle_overwrite_mode() {
  377. if (curbp->b_flags & B_OVERWRITE)
  378. curbp->b_flags &= ~B_OVERWRITE;
  379. else
  380. curbp->b_flags |= B_OVERWRITE;
  381. }
  382. void killtoeol()
  383. {
  384. if (curbp->b_point == pos(curbp, curbp->b_ebuf))
  385. return; /* do nothing if at end of file */
  386. if (*(ptr(curbp, curbp->b_point)) == 0xa) {
  387. delete(); /* delete CR if at start of empty line */
  388. } else {
  389. undoset();
  390. curbp->b_mark = curbp->b_point;
  391. lnend();
  392. if (curbp->b_mark != curbp->b_point) copy_cut(TRUE, TRUE, TRUE);
  393. }
  394. }
  395. void copy_cut(int cut, int displaymsg, int internal)
  396. {
  397. char_t *p;
  398. /* if no mark or point == marker, nothing doing */
  399. if (curbp->b_mark == NOMARK || curbp->b_point == curbp->b_mark)
  400. return;
  401. if (scrap != NULL) {
  402. free(scrap);
  403. scrap = NULL;
  404. }
  405. if(cut && !internal)
  406. undoset();
  407. if (curbp->b_point < curbp->b_mark) {
  408. /* point above marker: move gap under point, region = marker - point */
  409. (void) movegap(curbp, curbp->b_point);
  410. p = ptr(curbp, curbp->b_point);
  411. nscrap = curbp->b_mark - curbp->b_point;
  412. } else {
  413. /* if point below marker: move gap under marker, region = point - marker */
  414. (void) movegap(curbp, curbp->b_mark);
  415. p = ptr(curbp, curbp->b_mark);
  416. nscrap = curbp->b_point - curbp->b_mark;
  417. }
  418. if ((scrap = (char_t*) malloc(nscrap)) == NULL && displaymsg) {
  419. msg("No more memory available.");
  420. } else {
  421. (void) memcpy(scrap, p, nscrap * sizeof (char_t));
  422. if (cut) {
  423. curbp->b_egap += nscrap; /* if cut expand gap down */
  424. curbp->b_point = pos(curbp, curbp->b_egap); /* set point to after region */
  425. curbp->b_flags |= B_MODIFIED;
  426. if(displaymsg)
  427. msg("%ld bytes cut.", nscrap);
  428. } else {
  429. if(displaymsg)
  430. msg("%ld bytes copied.", nscrap);
  431. }
  432. curbp->b_mark = NOMARK; /* unmark */
  433. }
  434. }
  435. void paste_internal(int internal)
  436. {
  437. if(curbp->b_flags & B_OVERWRITE)
  438. return;
  439. if (nscrap <= 0) {
  440. msg("Scrap is empty. Nothing to paste.");
  441. } else if (nscrap < curbp->b_egap - curbp->b_gap || growgap(curbp, nscrap)) {
  442. if(!internal)
  443. undoset();
  444. curbp->b_point = movegap(curbp, curbp->b_point);
  445. memcpy(curbp->b_gap, scrap, nscrap * sizeof (char_t));
  446. curbp->b_gap += nscrap;
  447. curbp->b_point = pos(curbp, curbp->b_egap);
  448. curbp->b_flags |= B_MODIFIED;
  449. }
  450. }
  451. void paste()
  452. {
  453. paste_internal(FALSE);
  454. }
  455. void showpos()
  456. {
  457. int current, lastln;
  458. point_t end_p = pos(curbp, curbp->b_ebuf);
  459. get_line_stats(&current, &lastln, curbp);
  460. if (curbp->b_point == end_p) {
  461. msg("[EOB] Line = %d/%d Point = %d/%d", current, lastln,
  462. curbp->b_point, ((curbp->b_ebuf - curbp->b_buf) - (curbp->b_egap - curbp->b_gap)));
  463. } else {
  464. /* TODO: unctrl(*(ptr(curbp, curbp->b_point)))*/
  465. msg("Char = %s 0x%x Line = %d/%d Point = %d/%d", "N/A", *(ptr(curbp, curbp->b_point)),
  466. current, lastln,
  467. curbp->b_point, ((curbp->b_ebuf - curbp->b_buf) - (curbp->b_egap - curbp->b_gap)));
  468. }
  469. }
  470. /* Delete whitespace between non-whitespace */
  471. void deletewhitespacebetween()
  472. {
  473. char_t *p;
  474. while (isspace(*(p = ptr(curbp, curbp->b_point - 1))) && curbp->b_buf < p && *p != '\n')
  475. backsp();
  476. while (isspace(*(p = ptr(curbp, curbp->b_point))) && curbp->b_buf < p && *p != '\n')
  477. delete();
  478. }
  479. void insertnewlinebelow()
  480. {
  481. input = (char_t *)"\n";
  482. insert();
  483. up();
  484. }
  485. void insertnewline()
  486. {
  487. point_t point;
  488. char_t *p, *space = NULL;
  489. int spaces = 0, i;
  490. point = segstart(curbp, curwp, lnstart(curbp, curbp->b_point), curbp->b_point);
  491. while(isspace(*(p = ptr(curbp, point))) && *p != '\n' && curwp->w_col != 0) {
  492. if(spaces == 0) {
  493. space = p;
  494. }
  495. if(*p != '\n') {
  496. spaces++;
  497. point++;
  498. }
  499. }
  500. input = (char_t *)"\n";
  501. insert();
  502. input = (char_t *)space;
  503. for(i = 0; i < spaces; i++) {
  504. insert();
  505. }
  506. }
  507. void inserttab()
  508. {
  509. input = (char_t *)"\t";
  510. insert();
  511. }
  512. void inserttabasspace()
  513. {
  514. input = (char_t *)" ";
  515. insert_str();
  516. }
  517. void suspend()
  518. {
  519. tb_shutdown();
  520. raise(SIGTSTP);
  521. }
  522. void transpose()
  523. {
  524. char_t cur = *ptr(curbp, curbp->b_point);
  525. delete();
  526. left();
  527. input = &cur;
  528. insert();
  529. }
  530. /* Delete a word but don't display any messages. */
  531. void deleteword(int dir) {
  532. block();
  533. if(dir)
  534. wright();
  535. else
  536. wleft();
  537. copy_cut(TRUE, FALSE, TRUE);
  538. }
  539. /* Transpose words and put scrap back to how it was. */
  540. /* TODO: Fix the undo for this. */
  541. void transposeword()
  542. {
  543. char_t *current_scrap;
  544. int n_scrap = nscrap;
  545. undoset();
  546. current_scrap = (char_t*) malloc(nscrap);
  547. (void) memcpy(current_scrap, scrap, nscrap * sizeof (char_t));
  548. wright();
  549. deleteword(0);
  550. wleft();
  551. paste_internal(TRUE);
  552. deleteword(1);
  553. right();
  554. paste_internal(TRUE);
  555. if (scrap != NULL) {
  556. free(scrap);
  557. scrap = NULL;
  558. }
  559. nscrap = n_scrap;
  560. scrap = (char_t*) malloc(nscrap);
  561. (void) memcpy(scrap, current_scrap, nscrap * sizeof (char_t));
  562. }
  563. void lowercaseword()
  564. {
  565. char_t *p;
  566. char_t c[1];
  567. while (isspace(*(p = ptr(curbp, curbp->b_point))) && p < curbp->b_ebuf)
  568. ++curbp->b_point;
  569. while (!isspace(*(p = ptr(curbp, curbp->b_point))) && p < curbp->b_ebuf) {
  570. c[0] = tolower(*p);
  571. input = c;
  572. delete();
  573. insert();
  574. }
  575. }
  576. void capitalizeword()
  577. {
  578. char_t *p;
  579. while (isspace(*(p = ptr(curbp, curbp->b_point))) && p < curbp->b_ebuf)
  580. ++curbp->b_point;
  581. p = ptr(curbp, curbp->b_point);
  582. char_t c[1];
  583. c[0] = toupper(*p);
  584. input = c;
  585. delete();
  586. insert();
  587. while (!isspace(*(p = ptr(curbp, curbp->b_point))) && p < curbp->b_ebuf)
  588. ++curbp->b_point;
  589. }
  590. void uppercaseword()
  591. {
  592. char_t *p;
  593. char_t c[1];
  594. while (isspace(*(p = ptr(curbp, curbp->b_point))) && p < curbp->b_ebuf)
  595. ++curbp->b_point;
  596. while (!isspace(*(p = ptr(curbp, curbp->b_point))) && p < curbp->b_ebuf) {
  597. c[0] = toupper(*p);
  598. input = c;
  599. delete();
  600. insert();
  601. }
  602. }
  603. /* type = 0, zap
  604. type = 1, jump
  605. */
  606. /* TODO: Throw error when putting non-char in. */
  607. void gotochar(int type)
  608. {
  609. char_t *p;
  610. int c;
  611. struct tb_event ev;
  612. char *prompt = type == 0 ? "Zap to Char: " : "Jump to Char: ";
  613. if(character[0] == '\0') {
  614. display_prompt_and_response(prompt, character);
  615. tb_present();
  616. if(tb_poll_event(&ev) != TB_OK) return;
  617. if(!ev.mod)
  618. c = ev.ch;
  619. else
  620. c = ev.key;
  621. /* Ignore all control keys other than C-g and ESC*/
  622. if (c < 32 && c != TB_KEY_CTRL_G && c != TB_KEY_ESC)
  623. return;
  624. if(c == TB_KEY_CTRL_G || c == TB_KEY_ESC)
  625. return;
  626. else
  627. character[0] = c;
  628. display_prompt_and_response(prompt, character);
  629. tb_present();
  630. }
  631. if(negated)
  632. left();
  633. if(*ptr(curbp, curbp->b_point) == character[0]) {
  634. if(type == 0) {
  635. delete();
  636. if(negated)
  637. left();
  638. } else {
  639. if(negated)
  640. left();
  641. else
  642. right();
  643. }
  644. }
  645. while (*(p = ptr(curbp, curbp->b_point)) != character[0] && p < curbp->b_ebuf && p > curbp->b_buf) {
  646. if(type == 0) {
  647. delete();
  648. if(negated)
  649. left();
  650. } else {
  651. if(negated)
  652. left();
  653. else
  654. right();
  655. }
  656. }
  657. if(type == 0)
  658. delete(); // delete the character itself
  659. negated = FALSE;
  660. tb_set_cursor(0, MSGLINE);
  661. clrtoeol("", MSGLINE);
  662. }
  663. void zaptochar()
  664. {
  665. gotochar(0);
  666. }
  667. void negated_zaptochar()
  668. {
  669. negated = TRUE;
  670. gotochar(0);
  671. }
  672. void jumptochar()
  673. {
  674. gotochar(1);
  675. }
  676. void negated_jumptochar()
  677. {
  678. negated = TRUE;
  679. gotochar(1);
  680. }
  681. void poptomark()
  682. {
  683. if(curbp->b_mark > -1)
  684. curbp->b_point = curbp->b_mark;
  685. else
  686. curbp->b_point = curbp->b_pmark;
  687. }
  688. void universal_argument_load()
  689. {
  690. universal_argument++;
  691. msg("C-u %d", universal_argument);
  692. }
  693. void numeric_argument_load()
  694. {
  695. numeric_argument = (numeric_argument * 10) + atoi((const char *)&input_char);
  696. msg("C-u %d", numeric_argument);
  697. }
  698. void back_to_indentation()
  699. {
  700. char_t *p;
  701. while (isspace(*(p = ptr(curbp, curbp->b_point))) && p < curbp->b_ebuf)
  702. ++curbp->b_point;
  703. }
  704. void negate()
  705. {
  706. negated = !negated;
  707. msg("C-u -");
  708. }
  709. void forward_bracket()
  710. {
  711. point_t p;
  712. if((p = find_matching_bracket(curbp, 1)) >= 0)
  713. curbp->b_point = curbp->b_mark == NOMARK ? p : p + 1;
  714. }
  715. void backward_bracket()
  716. {
  717. point_t p;
  718. if((p = find_matching_bracket(curbp, -1)) >= 0)
  719. curbp->b_point = p;
  720. }
  721. void start_kbd_macro()
  722. {
  723. record_input = TRUE;
  724. for(int i = 0; i < record_buffer_index; i++) {
  725. memset(&record_buffer[i], 0, sizeof(record_buffer[i]));
  726. }
  727. record_buffer_index = 0;
  728. msg("Started keyboard macro...");
  729. }
  730. void end_kbd_macro()
  731. {
  732. record_input = FALSE;
  733. msg("Ended keyboard macro.");
  734. }
  735. void run_kbd_macro()
  736. {
  737. if(numeric_argument > 0)
  738. numeric_argument--;
  739. execute_kbd_macro = TRUE;
  740. }
  741. void open_file_from_shell()
  742. {
  743. get_popen_data(1);
  744. }
  745. void insert_from_shell()
  746. {
  747. get_popen_data(0);
  748. }