command.c 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490
  1. /* command.c, Ait, BSD 3-Clause, Kevin Bloom, 2023-2024,
  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. char_t *p;
  20. if(curbp->b_point == 0)
  21. return;
  22. p = ptr(curbp, curbp->b_point);
  23. while(*(p = ptr(curbp, curbp->b_point-1)) != '\n' && p > curbp->b_buf)
  24. --curbp->b_point;
  25. if(curbp->b_point != 0 && p == curbp->b_buf)
  26. --curbp->b_point;
  27. curbp->b_pcol = 0 + curwp->w_left;
  28. }
  29. void version() { msg(VERSION); }
  30. void top()
  31. {
  32. shift_pmark(TRUE, NOMARK);
  33. curbp->b_point = 0;
  34. curbp->b_pcol = 0 + curwp->w_left;
  35. }
  36. void bottom()
  37. {
  38. shift_pmark(TRUE, NOMARK);
  39. curbp->b_point = pos(curbp, curbp->b_ebuf);
  40. if (curbp->b_epage < pos(curbp, curbp->b_ebuf))
  41. curbp->b_reframe = 1;
  42. curbp->b_pcol = 0 + curwp->w_left;
  43. }
  44. void block() { curbp->b_mark = curbp->b_point; }
  45. void copy() { copy_cut(FALSE, TRUE, FALSE); }
  46. void cut() { copy_cut(TRUE, TRUE, FALSE); }
  47. void resize_terminal()
  48. {
  49. LINES = tb_height();
  50. COLS = tb_width();
  51. MSGLINE = LINES-1;
  52. one_window(curwp);
  53. }
  54. void print_to_msgline(const char *msg)
  55. {
  56. printf_tb(0, MSGLINE, TB_DEFAULT, TB_DEFAULT, msg);
  57. tb_set_cursor(strlen(msg), MSGLINE);
  58. }
  59. void quit_ask()
  60. {
  61. if (modified_buffers() > 0) {
  62. const char *msg = "Modified buffers exist; really exit (y/N) ?";
  63. print_to_msgline(msg);
  64. clrtoeol(msg, MSGLINE);
  65. if (!yesno(FALSE)) {
  66. clrtoeol("", MSGLINE);
  67. return;
  68. }
  69. }
  70. quit();
  71. }
  72. void redraw()
  73. {
  74. window_t *wp;
  75. for (wp=wheadp; wp != NULL; wp = wp->w_next)
  76. wp->w_update = TRUE;
  77. update_display();
  78. }
  79. void left()
  80. {
  81. int n = prev_utf8_char_size();
  82. if(curbp->b_point == 0)
  83. return;
  84. while (0 < curbp->b_point && n-- > 0)
  85. --curbp->b_point;
  86. }
  87. void right()
  88. {
  89. if(curbp->b_point == pos(curbp, curbp->b_ebuf))
  90. return;
  91. int n = utf8_size(*ptr(curbp,curbp->b_point));
  92. while ((curbp->b_point < pos(curbp, curbp->b_ebuf)) && n-- > 0)
  93. ++curbp->b_point;
  94. }
  95. /* work out number of bytes based on first byte */
  96. int utf8_size(char_t c)
  97. {
  98. return tb_utf8_char_length(c);
  99. }
  100. int prev_utf8_char_size()
  101. {
  102. int n;
  103. for (n=2;n<5;n++)
  104. if (-1 < curbp->b_point - n && (utf8_size(*(ptr(curbp, curbp->b_point - n))) == n))
  105. return n;
  106. return 1;
  107. }
  108. void lnend()
  109. {
  110. char_t *p;
  111. int cols = 0;
  112. lnbegin(); // reset the line so we get the right number for `cols`
  113. while(*(p = ptr(curbp, curbp->b_point)) != '\n' && curbp->b_ebuf > p) {
  114. ++curbp->b_point;
  115. }
  116. /* loop until we get to the correct column */
  117. while(cols > curwp->w_cols) {
  118. cols -= curwp->w_cols;
  119. }
  120. curbp->b_pcol = cols + curwp->w_left; // set it for column-memory
  121. }
  122. void wleft()
  123. {
  124. char_t *p;
  125. if ((!isspace(*(p = ptr(curbp, curbp->b_point))) || !is_symbol(*p)) && curbp->b_buf < p)
  126. --curbp->b_point;
  127. while ((isspace(*(p = ptr(curbp, curbp->b_point))) || is_symbol(*p)) && curbp->b_buf < p)
  128. --curbp->b_point;
  129. while (!isspace(*(p = ptr(curbp, curbp->b_point))) && !is_symbol(*p) && curbp->b_buf < p)
  130. --curbp->b_point;
  131. if(isspace(*(p = ptr(curbp, curbp->b_point))) || is_symbol(*p))
  132. ++curbp->b_point;
  133. }
  134. void wleftdelete()
  135. {
  136. currentcommand = KBD_DELETE_CHAR;
  137. iblock();
  138. wleft();
  139. copy_cut(TRUE, TRUE, FALSE);
  140. }
  141. void pgdown()
  142. {
  143. curbp->b_page = curbp->b_point = upup(curbp, curwp, curbp->b_epage);
  144. while (0 < curwp->w_top - curbp->b_row) {
  145. down();
  146. curbp->b_row--;
  147. }
  148. curbp->b_epage = pos(curbp, curbp->b_ebuf);
  149. curbp->b_pcol = 0 + curwp->w_left;
  150. }
  151. void pgup()
  152. {
  153. int i = curwp->w_rows;
  154. while (0 < --i) {
  155. curbp->b_page = upup(curbp, curwp, curbp->b_page);
  156. up();
  157. }
  158. curbp->b_pcol = 0 + curwp->w_left;
  159. }
  160. void wright()
  161. {
  162. char_t *p;
  163. if ((!isspace(*(p = ptr(curbp, curbp->b_point))) || !is_symbol(*p)) && p < curbp->b_ebuf)
  164. ++curbp->b_point;
  165. while ((isspace(*(p = ptr(curbp, curbp->b_point))) || is_symbol(*p)) && p < curbp->b_ebuf)
  166. ++curbp->b_point;
  167. while (!isspace(*(p = ptr(curbp, curbp->b_point))) && !is_symbol(*p) && p < curbp->b_ebuf)
  168. ++curbp->b_point;
  169. }
  170. void wrightdelete()
  171. {
  172. currentcommand = KBD_DELETE_CHAR;
  173. iblock();
  174. wright();
  175. copy_cut(TRUE, TRUE, FALSE);
  176. }
  177. void insert()
  178. {
  179. assert(curbp->b_gap <= curbp->b_egap);
  180. if (curbp->b_gap == curbp->b_egap && !growgap(curbp, CHUNK))
  181. return;
  182. curbp->b_point = movegap(curbp, curbp->b_point);
  183. /* overwrite if mid line, not EOL or EOF, CR will insert as normal */
  184. if ((curbp->b_flags & B_OVERWRITE) && *input != '\r' && *(ptr(curbp, curbp->b_point)) != '\n' && curbp->b_point < pos(curbp,curbp->b_ebuf) ) {
  185. *(ptr(curbp, curbp->b_point)) = *input;
  186. if (curbp->b_point < pos(curbp, curbp->b_ebuf))
  187. ++curbp->b_point;
  188. } else {
  189. *curbp->b_gap++ = *input == '\r' ? '\n' : *input;
  190. curbp->b_point = pos(curbp, curbp->b_egap);
  191. // force reframe if scrolled off bottom of screen and at EOF
  192. if (curbp->b_point == pos(curbp, curbp->b_ebuf) && curbp->b_point >= curbp->b_epage &&
  193. curwp->w_rows == (curwp->w_row - curwp->w_top))
  194. curbp->b_reframe = 1;
  195. }
  196. curbp->b_flags |= B_MODIFIED;
  197. undoset_flag = TRUE;
  198. currentcommand = KBD_INSERT;
  199. }
  200. void insert_str()
  201. {
  202. int len = strlen((const char *)input);
  203. assert(curbp->b_gap <= curbp->b_egap);
  204. undoset(1, FALSE);
  205. if (curbp->b_gap == curbp->b_egap && !growgap(curbp, CHUNK))
  206. return;
  207. curbp->b_point = movegap(curbp, curbp->b_point);
  208. /* overwrite if mid line, not EOL or EOF, CR will insert as normal */
  209. if ((curbp->b_flags & B_OVERWRITE) && input[0] != '\r' && *(ptr(curbp, curbp->b_point)) != '\n' && curbp->b_point < pos(curbp,curbp->b_ebuf) ) {
  210. *(ptr(curbp, curbp->b_point)) = *input;
  211. if (curbp->b_point < pos(curbp, curbp->b_ebuf))
  212. ++curbp->b_point;
  213. } else {
  214. for(int i = 0; i < len; i++) {
  215. *curbp->b_gap++ = input[i] == '\r' ? '\n' : input[i];
  216. // if(input[i] == '\n' || input[i] == '\r')
  217. // curbp->b_line++;
  218. }
  219. curbp->b_point = pos(curbp, curbp->b_egap);
  220. // force reframe if scrolled off bottom of screen and at EOF
  221. if (curbp->b_point == pos(curbp, curbp->b_ebuf) && curbp->b_point >= curbp->b_epage &&
  222. curwp->w_rows == (curwp->w_row - curwp->w_top))
  223. curbp->b_reframe = 1;
  224. }
  225. curbp->b_flags |= B_MODIFIED;
  226. undoset_flag = TRUE;
  227. }
  228. void insert_unicode()
  229. {
  230. int len = strlen((const char *)unicode_buf);
  231. assert(curbp->b_gap <= curbp->b_egap);
  232. undoset(INSERT, lastcommand == KBD_INSERT);
  233. if (curbp->b_gap == curbp->b_egap && !growgap(curbp, CHUNK))
  234. return;
  235. curbp->b_point = movegap(curbp, curbp->b_point);
  236. /* overwrite if mid line, not EOL or EOF, CR will insert as normal */
  237. for(int i = 0; i < len; i++) {
  238. *curbp->b_gap++ = unicode_buf[i];
  239. }
  240. curbp->b_point = pos(curbp, curbp->b_egap);
  241. // force reframe if scrolled off bottom of screen and at EOF
  242. if (curbp->b_point == pos(curbp, curbp->b_ebuf) && curbp->b_point >= curbp->b_epage &&
  243. curwp->w_rows == (curwp->w_row - curwp->w_top))
  244. curbp->b_reframe = 1;
  245. curbp->b_flags |= B_MODIFIED;
  246. undoset_flag = TRUE;
  247. unicode_buf[0] = '\0';
  248. currentcommand = KBD_INSERT;
  249. }
  250. void backsp()
  251. {
  252. undoset(3, lastcommand == KBD_DELETE_CHAR);
  253. if(curbp->b_point != 0 && *ptr(curbp, curbp->b_point - 1) == '\n')
  254. curbp->b_line--;
  255. curbp->b_point = movegap(curbp, curbp->b_point);
  256. if (curbp->b_buf < curbp->b_gap) {
  257. curbp->b_gap -= prev_utf8_char_size();
  258. curbp->b_flags |= B_MODIFIED;
  259. }
  260. curbp->b_point = pos(curbp, curbp->b_egap);
  261. currentcommand = KBD_DELETE_CHAR;
  262. }
  263. void delete()
  264. {
  265. undoset(2, lastcommand == KBD_DELETE_CHAR);
  266. curbp->b_point = movegap(curbp, curbp->b_point);
  267. if (curbp->b_egap < curbp->b_ebuf) {
  268. curbp->b_egap += utf8_size(*curbp->b_egap);
  269. curbp->b_point = pos(curbp, curbp->b_egap);
  270. curbp->b_flags |= B_MODIFIED;
  271. }
  272. currentcommand = KBD_DELETE_CHAR;
  273. }
  274. void gotoline()
  275. {
  276. int line;
  277. point_t p;
  278. if (getinput("Goto line: ", temp, STRBUF_S, F_CLEAR, FALSE)) {
  279. line = atoi(temp);
  280. p = line_to_point(line);
  281. if (p != -1) {
  282. shift_pmark(TRUE, NOMARK);
  283. curbp->b_point = p;
  284. curbp->b_pcol = 0 + curwp->w_left;
  285. if (curbp->b_epage < pos(curbp, curbp->b_ebuf)) curbp->b_reframe = 1;
  286. curwp->w_update = TRUE;
  287. curwp->w_recenter = TRUE;
  288. msg("Line %d", line);
  289. } else {
  290. msg("Line %d, not found", line);
  291. }
  292. }
  293. clrtoeol("", MSGLINE);
  294. }
  295. void gotocolumn()
  296. {
  297. int col, remainder = 0;
  298. point_t opoint = curbp->b_point, end = pos(curbp, curbp->b_ebuf);
  299. if (getinput("Goto column: ", temp, STRBUF_S, F_CLEAR, FALSE)) {
  300. col = atoi(temp);
  301. remainder = col - curbp->b_col - 1;
  302. if(remainder > 0) {
  303. shift_pmark(TRUE, NOMARK);
  304. if(*ptr(curbp, curbp->b_point) == '\n') {
  305. msg("Column %d, not found.", col);
  306. return;
  307. }
  308. for(; remainder > 0; remainder--) {
  309. right();
  310. printf("%d,",remainder);
  311. if((*ptr(curbp, curbp->b_point) == '\n' ||
  312. curbp->b_point == end) &&
  313. remainder != 1) {
  314. curbp->b_point = opoint;
  315. msg("Column %d, not found.", col);
  316. return;
  317. }
  318. }
  319. } else if(remainder < 0) {
  320. shift_pmark(TRUE, NOMARK);
  321. remainder *= -1;
  322. if(curbp->b_point == 0 ||
  323. *ptr(curbp, curbp->b_point - 1) == '\n') {
  324. msg("Column %d, not found.", col);
  325. return;
  326. }
  327. for(; remainder > 0; remainder--) {
  328. left();
  329. if((*ptr(curbp, curbp->b_point - 1) == '\n' ||
  330. curbp->b_point == 0) &&
  331. remainder != 1) {
  332. curbp->b_point = opoint;
  333. msg("Column %d, not found.", col);
  334. return;
  335. }
  336. }
  337. }
  338. }
  339. clrtoeol("", MSGLINE);
  340. }
  341. void jumptorow()
  342. {
  343. int line = -1, j = 0, i = 0, current, lastln, pageln;
  344. char num[3] = { 0, 0, 0 };
  345. struct tb_event ev;
  346. char *prompt = "Jump to line reference: ";
  347. int start_col = strlen(prompt), match = FALSE;
  348. char opts[10] = {'f','j','d','k','s','l','g','h', 'a', ';'};
  349. char chars[curwp->w_rows][2];
  350. point_t point;
  351. char_t *p;
  352. char f, s;
  353. int count = 0, fp = 0, sp = 0;
  354. int w_row = curwp->w_row - curwp->w_top;
  355. get_line_stats(&current, &lastln, curbp);
  356. pageln = current - w_row;
  357. point = curbp->b_page;
  358. p = ptr(curbp, point);
  359. for(int i = 0; i < curwp->w_rows && pageln <= lastln; i++) {
  360. f = opts[fp];
  361. s = opts[sp];
  362. chars[i][0] = f;
  363. chars[i][1] = s;
  364. printf_tb(curwp->w_left, curwp->w_top+i, TB_RED, TB_CYAN, "%c%c", f,s);
  365. sp++;
  366. count++;
  367. if(count > 7) {
  368. fp++;
  369. sp = 0;
  370. count = 0;
  371. }
  372. int c = 1;
  373. while(*(p = ptr(curbp, point)) != '\n' &&
  374. curbp->b_ebuf > p && c < curwp->w_cols) {
  375. ++point;
  376. c++;
  377. }
  378. if(*p == '\n' || pageln == lastln)
  379. pageln++;
  380. ++point;
  381. p = ptr(curbp, point);
  382. }
  383. display_prompt_and_response(prompt, num);
  384. tb_present();
  385. while(j < 2) {
  386. display_prompt_and_response(prompt, num);
  387. tb_present();
  388. if(tb_poll_event(&ev) != TB_OK) break;
  389. if(ev.key == TB_KEY_CTRL_G) {
  390. clrtoeol("", MSGLINE);
  391. return;
  392. }
  393. if(j < 2) {
  394. num[j] = ev.ch;
  395. tb_set_cursor(start_col, MSGLINE);
  396. addstr(num);
  397. point = curbp->b_page;
  398. p = ptr(curbp, point);
  399. if(j == 0) {
  400. pageln = current - w_row;
  401. for(int i = 0; i < curwp->w_rows && pageln <= lastln; i++) {
  402. if(chars[i][0] == ev.ch) {
  403. match = TRUE;
  404. if(*p != '\n')
  405. p = ptr(curbp, point+1);
  406. if(*p == '\0')
  407. *p = ' ';
  408. printf_tb(curwp->w_left, curwp->w_top+i, TB_RED, TB_CYAN, "%c", chars[i][1]);
  409. printf_tb(curwp->w_left+1, curwp->w_top+i, TB_DEFAULT, TB_DEFAULT, "%c", *p == '\n' ? ' ' : *p);
  410. } else {
  411. printf_tb(curwp->w_left, curwp->w_top+i, TB_DEFAULT, TB_DEFAULT, "%c", *p == '\n' ? ' ' : *p);
  412. if(*p != '\n')
  413. p = ptr(curbp, point+1);
  414. if(*p == '\0')
  415. *p = ' ';
  416. printf_tb(curwp->w_left+1, curwp->w_top+i, TB_DEFAULT, TB_DEFAULT, "%c", *p == '\n' ? ' ' : *p);
  417. }
  418. int c = 1;
  419. while(*(p = ptr(curbp, point)) != '\n' &&
  420. curbp->b_ebuf > p && c < curwp->w_cols) {
  421. ++point;
  422. c++;
  423. }
  424. if(*p == '\n' || pageln == lastln)
  425. pageln++;
  426. ++point;
  427. p = ptr(curbp, point);
  428. }
  429. }
  430. j++;
  431. }
  432. if(!match) {
  433. clrtoeol("", MSGLINE);
  434. return;
  435. }
  436. }
  437. for(; i < curwp->w_rows; i++) {
  438. if(chars[i][0] == num[0] && chars[i][1] == num[1]) {
  439. line = w_row - i;
  440. break;
  441. }
  442. }
  443. if(i == curwp->w_rows) {
  444. msg("Out of bounds");
  445. return;
  446. }
  447. shift_pmark(TRUE, NOMARK);
  448. if(line > 0) {
  449. for(; line > 0; line--) {
  450. up();
  451. }
  452. } else {
  453. for(; line < 0; line++) {
  454. down();
  455. }
  456. }
  457. clrtoeol("", MSGLINE);
  458. }
  459. void jumpword()
  460. {
  461. point_t current = curbp->b_page;
  462. char num[3] = { 'f', 'f', 0 };
  463. int j = 0, match = FALSE;
  464. char starting[1];
  465. struct tb_event ev;
  466. char *prompt = "Jump to word starting with: ";
  467. int start_col = strlen(prompt);
  468. char opts[10] = {'f','j','d','k','s','l','g','h', 'a', ';'};
  469. int diff = curbp->b_epage - curbp->b_page;
  470. char chars[diff][2];
  471. point_t point = -1;
  472. int begin = TRUE, is_white = FALSE, is_symb = FALSE, charlen = 0;
  473. char_t *p, *tp;
  474. char f, s;
  475. int count = 0, fp = 0, sp = 0, x = 0, y = 0;
  476. display_prompt_and_response(prompt, starting);
  477. tb_present();
  478. if(tb_poll_event(&ev) != TB_OK) return;
  479. if(ev.key == TB_KEY_CTRL_G) {
  480. clrtoeol("", MSGLINE);
  481. return;
  482. }
  483. starting[0] = (unsigned)ev.ch;
  484. for(; current < curbp->b_epage; current++) {
  485. p = ptr(curbp, current);
  486. is_white = isspace(*p);
  487. is_symb = is_symbol(*p);
  488. if(is_white || is_symb || current == 0)
  489. begin = TRUE;
  490. if(*p == (char_t)starting[0] && begin) {
  491. f = opts[fp];
  492. s = opts[sp];
  493. chars[current-curbp->b_page][0] = f;
  494. chars[current-curbp->b_page][1] = s;
  495. charlen++;
  496. printf_tb(curwp->w_left+x, curwp->w_top+y, TB_RED, TB_CYAN, "%c%c", f,s);
  497. sp++;
  498. count++;
  499. if(count > 7) {
  500. fp++;
  501. sp = 0;
  502. count = 0;
  503. }
  504. begin = FALSE;
  505. }
  506. if(!is_white && !is_symb)
  507. begin = FALSE;
  508. x++;
  509. if(*p == '\t')
  510. x += (TAB_SIZE - 2);
  511. if(*p < 31)
  512. x++;
  513. if(*p == '\n' || x >= curwp->w_cols) {
  514. x = 0;
  515. y++;
  516. }
  517. }
  518. tb_present();
  519. if(charlen > 1) {
  520. display_prompt_and_response(prompt, num);
  521. tb_present();
  522. while(j < 2) {
  523. display_prompt_and_response(prompt, num);
  524. tb_present();
  525. if(tb_poll_event(&ev) != TB_OK) break;
  526. if(ev.key == TB_KEY_CTRL_G) {
  527. clrtoeol("", MSGLINE);
  528. return;
  529. }
  530. if(j < 2) {
  531. num[j] = ev.ch;
  532. tb_set_cursor(start_col, MSGLINE);
  533. addstr(num);
  534. x = 0;
  535. y = 0;
  536. if(j == 0) {
  537. for(current = curbp->b_page; current < curbp->b_epage; current++) {
  538. p = ptr(curbp, current);
  539. tp = ptr(curbp, current);
  540. is_white = isspace(*p);
  541. is_symb = is_symbol(*p);
  542. if(is_white || is_symb || current == 0)
  543. begin = TRUE;
  544. if(*p == (char_t)starting[0] && begin) {
  545. point_t i = current-curbp->b_page;
  546. if(chars[i][0] == ev.ch) {
  547. match = TRUE;
  548. tp = ptr(curbp, current+1);
  549. printf_tb(curwp->w_left+x, curwp->w_top+y, TB_RED, TB_CYAN, "%c", chars[i][1]);
  550. printf_tb(curwp->w_left+x+1, curwp->w_top+y, TB_DEFAULT, TB_DEFAULT, "%c", *tp == '\n' ? ' ' : *tp);
  551. } else {
  552. printf_tb(curwp->w_left+x, curwp->w_top+y, TB_DEFAULT, TB_DEFAULT, "%c", *tp == '\n' ? ' ' : *tp);
  553. tp = ptr(curbp, current+1);
  554. printf_tb(curwp->w_left+x+1, curwp->w_top+y, TB_DEFAULT, TB_DEFAULT, "%c", *tp == '\n' ? ' ' : *tp);
  555. }
  556. begin = FALSE;
  557. }
  558. if(!is_white && !is_symb)
  559. begin = FALSE;
  560. x++;
  561. if(*p == '\t')
  562. x += (TAB_SIZE - 2);
  563. if(*p < 31)
  564. x++;
  565. if(*p == '\n' || x >= curwp->w_cols) {
  566. x = 0;
  567. y++;
  568. }
  569. }
  570. }
  571. j++;
  572. if(!match) {
  573. clrtoeol("", MSGLINE);
  574. return;
  575. }
  576. }
  577. }
  578. }
  579. for(point_t cur = 0; cur < diff; cur++) {
  580. if(chars[cur][0] == num[0] && chars[cur][1] == num[1]) {
  581. point = cur + curbp->b_page;
  582. break;
  583. }
  584. }
  585. if(point == -1) {
  586. msg("Out of bounds.");
  587. } else {
  588. shift_pmark(TRUE, NOMARK);
  589. curbp->b_point = point;
  590. int cols = 0;
  591. /* Calculate the pcol value */
  592. lnbegin(); // reset the line so we get the right number for `cols`
  593. while(curbp->b_point != point) {
  594. ++curbp->b_point;
  595. cols++;
  596. }
  597. /* loop until we get to the correct column */
  598. while(cols > curwp->w_cols) {
  599. cols -= curwp->w_cols;
  600. }
  601. curbp->b_pcol = cols + curwp->w_left; // set it for column-memory
  602. clrtoeol("", MSGLINE);
  603. }
  604. /* Clear out the chars array */
  605. for(int i = 0; i < diff; i++) {
  606. chars[i][0] = 0;
  607. chars[i][1] = 0;
  608. }
  609. /* TODO: figure out why this has to be here
  610. Without this printf, the chars array doesn't appear to get
  611. cleared entirely and you end up jumping to the wrong points.
  612. */
  613. printf("%s", chars[0]);
  614. }
  615. void get_current_path(char *cur_path)
  616. {
  617. int cutoff = 0;
  618. for(int i = strlen(curbp->b_fname) - 1; i > -1; i--) {
  619. if(curbp->b_fname[i] == '/') {
  620. cutoff = i;
  621. break;
  622. }
  623. }
  624. for(int i = 0; i <= cutoff; i++)
  625. cur_path[i] = curbp->b_fname[i];
  626. cur_path[cutoff+1] = '\0';
  627. }
  628. void insertfile()
  629. {
  630. char cur_path[PATH_MAX] = "\0";
  631. if(curbp->b_path) {
  632. get_current_path(cur_path);
  633. strcpy(temp, cur_path);
  634. }
  635. else
  636. strcpy(temp, editor_dir);
  637. if (getfilename("Insert file: ", temp, PATH_MAX))
  638. (void)insert_file(temp, TRUE);
  639. }
  640. void readfile()
  641. {
  642. buffer_t *bp;
  643. char cur_path[PATH_MAX];
  644. if(curbp->b_path) {
  645. get_current_path(cur_path);
  646. strcpy(temp, cur_path);
  647. }
  648. else
  649. strcpy(temp, editor_dir);
  650. int result = getfilename("Find file: ", (char*)temp, PATH_MAX);
  651. if (result) {
  652. bp = find_buffer(temp, TRUE);
  653. disassociate_b(curwp);
  654. curbp = bp;
  655. associate_b2w(curbp, curwp);
  656. if (!growgap(curbp, CHUNK))
  657. fatal("%s: Failed to allocate required memory.\n");
  658. movegap(curbp, 0);
  659. /* load the file if not already loaded */
  660. if (bp != NULL && bp->b_fname[0] == '\0') {
  661. if (!load_file(temp)) {
  662. msg("New file %s", temp);
  663. }
  664. strncpy(curbp->b_fname, temp, PATH_MAX);
  665. curbp->b_fname[PATH_MAX] = '\0'; /* truncate if required */
  666. }
  667. }
  668. }
  669. void savebuffer()
  670. {
  671. const char *message = "No newline at the end of file, add one (Y/n) ?";
  672. if(curbp->b_flags & B_MODIFIED) {
  673. /* move the gap to point 0 so that the ebuf is updated. */
  674. (void) movegap(curbp, 0);
  675. if(*(curbp->b_ebuf - 1) != '\n') {
  676. print_to_msgline(message);
  677. clrtoeol(message, MSGLINE);
  678. if (yesno(TRUE)) {
  679. clrtoeol("", MSGLINE);
  680. *curbp->b_ebuf++ = '\n';
  681. }
  682. }
  683. if (curbp->b_fname[0] != '\0') {
  684. save(curbp->b_fname);
  685. return;
  686. } else {
  687. writefile();
  688. }
  689. } else {
  690. msg("(No changes need to be saved.)");
  691. }
  692. }
  693. void writefile()
  694. {
  695. const char *message = "Write file: ";
  696. strncpy(temp, curbp->b_fname, PATH_MAX);
  697. if (getinput((char *)message, temp, PATH_MAX, F_NONE, FALSE))
  698. if (save(temp) == TRUE)
  699. strncpy(curbp->b_fname, temp, PATH_MAX);
  700. clrtoeol(message, MSGLINE);
  701. }
  702. void killbuffer()
  703. {
  704. buffer_t *kill_bp = curbp;
  705. buffer_t *bp;
  706. int bcount = count_buffers();
  707. const char *message = "Discard changes (y/N) ?";
  708. /* do nothing if only buffer left is the scratch buffer */
  709. if (bcount == 1 && 0 == strcmp(get_buffer_name(curbp), "*scratch*"))
  710. return;
  711. if (curbp->b_flags & B_MODIFIED) {
  712. print_to_msgline(message);
  713. clrtoeol(message, MSGLINE);
  714. if (!yesno(FALSE))
  715. return;
  716. }
  717. if (bcount == 1) {
  718. /* create a scratch buffer */
  719. bp = find_buffer("*scratch*", TRUE);
  720. strncpy(bp->b_bname, "*scratch*", STRBUF_S);
  721. bp->b_path = FALSE;
  722. }
  723. next_buffer();
  724. assert(kill_bp != curbp);
  725. delete_buffer(kill_bp);
  726. for(window_t *wp = wheadp; wp != NULL; wp = wp->w_next) {
  727. if(kill_bp == wp->w_bufp) {
  728. wp->w_bufp = curbp;
  729. }
  730. }
  731. }
  732. void iblock()
  733. {
  734. block();
  735. msg("Mark set");
  736. }
  737. void unmark()
  738. {
  739. shift_pmark(TRUE, NOMARK);
  740. curbp->b_mark = NOMARK;
  741. msg("Mark removed");
  742. }
  743. void toggle_overwrite_mode() {
  744. if (curbp->b_flags & B_OVERWRITE)
  745. curbp->b_flags &= ~B_OVERWRITE;
  746. else
  747. curbp->b_flags |= B_OVERWRITE;
  748. }
  749. void killtoeol()
  750. {
  751. if (curbp->b_point == pos(curbp, curbp->b_ebuf))
  752. return; /* do nothing if at end of file */
  753. if (*(ptr(curbp, curbp->b_point)) == 0xa) {
  754. delete(); /* delete CR if at start of empty line */
  755. } else {
  756. curbp->b_mark = curbp->b_point;
  757. lnend();
  758. if (curbp->b_mark != curbp->b_point) copy_cut(TRUE, TRUE, FALSE);
  759. }
  760. }
  761. void copy_cut(int cut, int displaymsg, int internal)
  762. {
  763. char_t *p;
  764. /* if no mark or point == marker, nothing doing */
  765. if (curbp->b_mark == NOMARK || curbp->b_point == curbp->b_mark)
  766. return;
  767. if (scrap != NULL) {
  768. free(scrap);
  769. scrap = NULL;
  770. }
  771. if(cut && !internal)
  772. undoset(4, FALSE);
  773. if (curbp->b_point < curbp->b_mark) {
  774. /* point above marker: move gap under point, region = marker - point */
  775. (void) movegap(curbp, curbp->b_point);
  776. p = ptr(curbp, curbp->b_point);
  777. nscrap = curbp->b_mark - curbp->b_point;
  778. if(cut && currentcommand == KBD_DELETE_CHAR)
  779. for(point_t pt = curbp->b_mark-1; pt > curbp->b_point; pt--) {
  780. if(*ptr(curbp, pt) == '\n')
  781. curbp->b_line--;
  782. }
  783. } else {
  784. /* if point below marker: move gap under marker, region = point - marker */
  785. (void) movegap(curbp, curbp->b_mark);
  786. p = ptr(curbp, curbp->b_mark);
  787. nscrap = curbp->b_point - curbp->b_mark;
  788. if (cut && currentcommand != KBD_DELETE_CHAR)
  789. for(point_t pt = curbp->b_mark; pt < curbp->b_point; pt++) {
  790. if(*ptr(curbp, pt) == '\n')
  791. curbp->b_line--;
  792. }
  793. }
  794. if ((scrap = (char_t*) malloc(nscrap)) == NULL && displaymsg) {
  795. msg("No more memory available.");
  796. } else {
  797. (void) memcpy(scrap, p, nscrap * sizeof (char_t));
  798. if (cut) {
  799. curbp->b_egap += nscrap; /* if cut expand gap down */
  800. curbp->b_point = pos(curbp, curbp->b_egap); /* set point to after region */
  801. curbp->b_flags |= B_MODIFIED;
  802. if(displaymsg)
  803. msg("%ld bytes cut.", nscrap);
  804. currentcommand = KBD_CUT;
  805. } else {
  806. if(displaymsg)
  807. msg("%ld bytes copied.", nscrap);
  808. }
  809. curbp->b_mark = NOMARK; /* unmark */
  810. }
  811. }
  812. void paste_internal(int internal)
  813. {
  814. int new_rows = 0;
  815. int col = curwp->w_col - curwp->w_left + 1;
  816. point_t opoint = curbp->b_point;
  817. if(curbp->b_flags & B_OVERWRITE)
  818. return;
  819. if (nscrap <= 0) {
  820. msg("Scrap is empty. Nothing to paste.");
  821. } else if (nscrap < curbp->b_egap - curbp->b_gap || growgap(curbp, nscrap)) {
  822. if(!internal)
  823. undoset(5, FALSE);
  824. curbp->b_point = movegap(curbp, curbp->b_point);
  825. memcpy(curbp->b_gap, scrap, nscrap * sizeof (char_t));
  826. curbp->b_gap += nscrap;
  827. curbp->b_point = pos(curbp, curbp->b_egap);
  828. curbp->b_flags |= B_MODIFIED;
  829. /* TODO: this assumes 1 char = 1 point (not always true) */
  830. col += curbp->b_point - opoint;
  831. for(int i = 0, cc = col; scrap[i] != '\0'; i++) {
  832. cc++;
  833. if(scrap[i] == '\n' || cc >= curwp->w_cols) {
  834. new_rows++;
  835. cc = 0;
  836. }
  837. curbp->b_pcol = cc + curwp->w_left;
  838. }
  839. if ((curbp->b_row - curwp->w_top) + new_rows >= curwp->w_rows)
  840. curbp->b_reframe = 1;
  841. }
  842. }
  843. void paste()
  844. {
  845. paste_internal(FALSE);
  846. }
  847. void clipboard()
  848. {
  849. int new_rows = 0;
  850. int ntemp = strlen(gtemp);
  851. if(curbp->b_flags & B_OVERWRITE)
  852. return;
  853. if (ntemp <= 0) {
  854. msg("Temp buffer is empty. Nothing to paste.");
  855. } else if (ntemp < curbp->b_egap - curbp->b_gap || growgap(curbp, ntemp)) {
  856. undoset(CLIPBOARD, FALSE);
  857. curbp->b_point = movegap(curbp, curbp->b_point);
  858. memcpy(curbp->b_gap, gtemp, ntemp * sizeof (char_t));
  859. curbp->b_gap += ntemp;
  860. curbp->b_point = pos(curbp, curbp->b_egap);
  861. curbp->b_flags |= B_MODIFIED;
  862. for(int i = 0; gtemp[i] != '\0'; i++) {
  863. if(gtemp[i] == '\n')
  864. new_rows++;
  865. }
  866. if ((curbp->b_row - curwp->w_top) + new_rows > curwp->w_rows &&
  867. curbp->b_point >= curbp->b_epage)
  868. curbp->b_reframe = 1;
  869. free(gtemp);
  870. gtemp = malloc(sizeof(char) * TEMPBUF);
  871. }
  872. }
  873. void showpos()
  874. {
  875. int current, lastln;
  876. point_t end_p = pos(curbp, curbp->b_ebuf);
  877. get_line_stats(&current, &lastln, curbp);
  878. if (curbp->b_point == end_p) {
  879. msg("[EOB] Line = %d/%d Point = %d/%d", current, lastln,
  880. curbp->b_point, ((curbp->b_ebuf - curbp->b_buf) - (curbp->b_egap - curbp->b_gap)));
  881. } else {
  882. char c = unctrl(*(ptr(curbp, curbp->b_point)));
  883. msg("Char = %c 0x%x Line = %d/%d Point = %d/%d", c, *(ptr(curbp, curbp->b_point)),
  884. current, lastln,
  885. curbp->b_point, ((curbp->b_ebuf - curbp->b_buf) - (curbp->b_egap - curbp->b_gap)));
  886. }
  887. }
  888. /* Delete whitespace between non-whitespace */
  889. void delete_between()
  890. {
  891. char_t *p, other;
  892. struct tb_event ev;
  893. char *prompt = "Bracket to Zap Between: ";
  894. int c, is_start = FALSE;
  895. /* Delete everything between brackets. */
  896. if(universal_argument > 0) {
  897. if(character[0] == '\0') {
  898. display_prompt_and_response(prompt, character);
  899. tb_present();
  900. if(tb_poll_event(&ev) != TB_OK) return;
  901. if(!ev.mod)
  902. c = ev.ch;
  903. else
  904. c = ev.key;
  905. /* Ignore all control keys other than C-g and ESC*/
  906. if (c < 32 && c != TB_KEY_CTRL_G && c != TB_KEY_ESC)
  907. return;
  908. if(c == TB_KEY_CTRL_G || c == TB_KEY_ESC)
  909. return;
  910. else
  911. character[0] = c;
  912. display_prompt_and_response(prompt, character);
  913. tb_present();
  914. }
  915. if(!(other = is_bracket(character[0], TRUE, &is_start))) {
  916. return;
  917. }
  918. for(;universal_argument > 0; universal_argument--)
  919. jumptochar();
  920. adjust_bline();
  921. universal_argument = 0;
  922. lastcommand = KBD_DELETE_CHAR;
  923. if(is_start) {
  924. curbp->b_point++;
  925. while (*(p = ptr(curbp, curbp->b_point)) != other && curbp->b_buf < p)
  926. delete();
  927. } else {
  928. while (*(p = ptr(curbp, curbp->b_point - 1)) != other && curbp->b_buf < p)
  929. backsp();
  930. }
  931. character[0] = '\0';
  932. return;
  933. }
  934. /* If in a word delete the word both directions.
  935. This is the same as doing a `esc f` then `esc backsp`.
  936. This does not delete the symbols, just the words.
  937. */
  938. if(!isspace(*ptr(curbp, curbp->b_point - 1)) &&
  939. !isspace(*ptr(curbp, curbp->b_point)) &&
  940. !isspace(*ptr(curbp, curbp->b_point + 1))) {
  941. wright();
  942. wleftdelete();
  943. return;
  944. }
  945. lastcommand = KBD_DELETE_CHAR;
  946. /* Otherwise just delete whitespace */
  947. while (isspace(*(p = ptr(curbp, curbp->b_point - 1))) && curbp->b_buf < p && *p != '\n')
  948. backsp();
  949. while (isspace(*(p = ptr(curbp, curbp->b_point))) && curbp->b_buf < p && *p != '\n')
  950. delete();
  951. }
  952. void insertnewlinebelow()
  953. {
  954. char_t newline[2];
  955. newline[0] = '\n';
  956. newline[1] = '\0';
  957. input = newline;
  958. undoset(1, lastcommand == KBD_INSERT);
  959. insert();
  960. up();
  961. currentcommand = KBD_INSERT;
  962. }
  963. void insertnewline()
  964. {
  965. point_t point;
  966. char_t *p, *space = NULL, *str;
  967. int spaces = 0, i;
  968. point = segstart(curbp, curwp, lnstart(curbp, curbp->b_point), curbp->b_point);
  969. while(point < pos(curbp, curbp->b_ebuf) &&
  970. isspace(*(p = ptr(curbp, point))) &&
  971. *p != '\n' &&
  972. curwp->w_col != 0) {
  973. if(spaces == 0) {
  974. space = p;
  975. }
  976. if(*p != '\n') {
  977. spaces++;
  978. point++;
  979. }
  980. }
  981. str = (char_t *) malloc(sizeof(char_t)*spaces+2);
  982. str[0] = '\n';
  983. for(i = 0; i < spaces; i++) {
  984. str[i+1] = *space;
  985. }
  986. str[i+1] = '\0';
  987. input = str;
  988. insert_str();
  989. curbp->b_pcol = spaces + curwp->w_left;
  990. currentcommand = KBD_INSERT;
  991. free(str);
  992. if((curwp->w_row - curwp->w_top) == curwp->w_rows-1) {
  993. curbp->b_reframe = TRUE;
  994. }
  995. }
  996. void inserttab()
  997. {
  998. input = (char_t *)"\t";
  999. undoset(1, FALSE);
  1000. insert();
  1001. }
  1002. void inserttabasspace()
  1003. {
  1004. char_t spaces[TAB_SPACE_SIZE+1];
  1005. memset(spaces, ' ', sizeof(spaces));
  1006. spaces[TAB_SPACE_SIZE] = '\0';
  1007. input = spaces;
  1008. insert_str();
  1009. }
  1010. void suspend()
  1011. {
  1012. tb_shutdown();
  1013. raise(SIGTSTP);
  1014. }
  1015. void transpose()
  1016. {
  1017. char_t *cur = ptr(curbp, curbp->b_point);
  1018. char_t *prev = ptr(curbp, curbp->b_point-1);
  1019. char_t replace[3];
  1020. if(cur == curbp->b_ebuf) {
  1021. return;
  1022. }
  1023. point_t mark = curbp->b_mark;
  1024. replace[0] = *cur;
  1025. replace[1] = *prev;
  1026. replace[2] = '\0';
  1027. curbp->b_point--;
  1028. curbp->b_mark = curbp->b_point + 2;
  1029. undoset(REPLACE, 2);
  1030. curbp->b_mark = mark;
  1031. curbp->b_point++;
  1032. memcpy(ptr(curbp, curbp->b_point-1), replace, 2 * sizeof (char_t));
  1033. curbp->b_flags |= B_MODIFIED;
  1034. }
  1035. /* Delete a word but don't display any messages. */
  1036. void deleteword(int dir) {
  1037. block();
  1038. if(dir)
  1039. wright();
  1040. else
  1041. wleft();
  1042. copy_cut(TRUE, FALSE, TRUE);
  1043. }
  1044. /* Transpose words and put scrap back to how it was. */
  1045. void transposeword()
  1046. {
  1047. char_t *current_scrap, *p;
  1048. int n_scrap = nscrap, newlines = 0;
  1049. point_t mark = curbp->b_mark, epoint, point, npoint;
  1050. /* copy the current scrap */
  1051. current_scrap = (char_t*) malloc(nscrap);
  1052. (void) memcpy(current_scrap, scrap, nscrap * sizeof (char_t));
  1053. /* Find all the key points for the undo */
  1054. wright();
  1055. epoint = curbp->b_point;
  1056. wleft();
  1057. wleft();
  1058. curbp->b_mark = epoint;
  1059. point = curbp->b_point;
  1060. /* Adjust `b_line` to match the line you'll eventually
  1061. be on. This has to happen before the undo so that the
  1062. undo's line tracker keeps it right.
  1063. */
  1064. npoint = point;
  1065. while(npoint < epoint) {
  1066. p = ptr(curbp, npoint);
  1067. if(*p == '\n')
  1068. newlines++;
  1069. npoint++;
  1070. }
  1071. curbp->b_line -= newlines;
  1072. undoset(REPLACE, curbp->b_mark - point);
  1073. /* Cut the word to the left*/
  1074. curbp->b_mark = point;
  1075. curbp->b_point = point;
  1076. wright();
  1077. copy_cut(TRUE, FALSE, TRUE);
  1078. /* paste the left word */
  1079. right();
  1080. paste_internal(TRUE);
  1081. /* cut the right word */
  1082. curbp->b_mark = curbp->b_point;
  1083. wright();
  1084. copy_cut(TRUE, FALSE, TRUE);
  1085. wleft();
  1086. /* paste the right word */
  1087. left();
  1088. paste_internal(TRUE);
  1089. /* Put it all back together */
  1090. if (scrap != NULL) {
  1091. free(scrap);
  1092. scrap = NULL;
  1093. }
  1094. nscrap = n_scrap;
  1095. scrap = (char_t*) malloc(nscrap);
  1096. (void) memcpy(scrap, current_scrap, nscrap * sizeof (char_t));
  1097. curbp->b_mark = mark;
  1098. }
  1099. void lowercaseword()
  1100. {
  1101. char_t *p, *word;
  1102. char_t c[2];
  1103. point_t sword, eword;
  1104. int olast = lastcommand;
  1105. while ((isspace(*(p = ptr(curbp, curbp->b_point))) || is_symbol(*p)) && p < curbp->b_ebuf)
  1106. ++curbp->b_point;
  1107. sword = curbp->b_point;
  1108. wright();
  1109. eword = curbp->b_point;
  1110. word = (char_t *) malloc(sizeof(char_t)*(eword - sword));
  1111. curbp->b_point = sword;
  1112. lastcommand = KBD_DELETE_CHAR;
  1113. for(int i = sword, k = 0; i < eword; i++, k++) {
  1114. word[k] = *ptr(curbp, curbp->b_point);
  1115. delete();
  1116. }
  1117. lastcommand = olast;
  1118. for(int i = sword, k = 0; i < eword; i++, k++) {
  1119. c[0] = tolower(word[k]);
  1120. c[1] = '\0';
  1121. input = c;
  1122. undoset(INSERT, i != 0);
  1123. insert();
  1124. }
  1125. free(word);
  1126. }
  1127. void capitalizeword()
  1128. {
  1129. char_t *p;
  1130. while (isspace(*(p = ptr(curbp, curbp->b_point))) && p < curbp->b_ebuf)
  1131. ++curbp->b_point;
  1132. p = ptr(curbp, curbp->b_point);
  1133. char_t c[1];
  1134. c[0] = toupper(*p);
  1135. input = c;
  1136. delete();
  1137. undoset(INSERT, FALSE);
  1138. insert();
  1139. if(isspace(*(p = ptr(curbp, curbp->b_point+1))) || is_symbol(*p))
  1140. curbp->b_point++;
  1141. else
  1142. wright();
  1143. }
  1144. void uppercaseword()
  1145. {
  1146. char_t *p, *word;
  1147. char_t c[2];
  1148. point_t sword, eword;
  1149. int olast = lastcommand;
  1150. while ((isspace(*(p = ptr(curbp, curbp->b_point))) || is_symbol(*p)) && p < curbp->b_ebuf)
  1151. ++curbp->b_point;
  1152. sword = curbp->b_point;
  1153. wright();
  1154. eword = curbp->b_point;
  1155. word = (char_t *) malloc(sizeof(char_t)*(eword - sword));
  1156. curbp->b_point = sword;
  1157. lastcommand = KBD_DELETE_CHAR;
  1158. for(int i = sword, k = 0; i < eword; i++, k++) {
  1159. word[k] = *ptr(curbp, curbp->b_point);
  1160. delete();
  1161. }
  1162. lastcommand = olast;
  1163. for(int i = sword, k = 0; i < eword; i++, k++) {
  1164. c[0] = toupper(word[k]);
  1165. c[1] = '\0';
  1166. input = c;
  1167. undoset(INSERT, i != 0);
  1168. insert();
  1169. }
  1170. free(word);
  1171. }
  1172. /* type = 0, zap
  1173. type = 1, jump
  1174. */
  1175. /* TODO: Throw error when putting non-char in.
  1176. */
  1177. void gotochar(int type, int include_char)
  1178. {
  1179. char_t *p;
  1180. point_t opoint = curbp->b_point, eol;
  1181. int c, col = 0;
  1182. struct tb_event ev;
  1183. char *prompt = type == 0 ? "Zap to Char: " : "Jump to Char: ";
  1184. if(character[0] == '\0') {
  1185. display_prompt_and_response(prompt, character);
  1186. tb_present();
  1187. if(tb_poll_event(&ev) != TB_OK) return;
  1188. if(!ev.mod)
  1189. c = ev.ch;
  1190. else
  1191. c = ev.key;
  1192. /* Ignore all control keys other than C-g and ESC*/
  1193. if (c < 32 && c != TB_KEY_CTRL_G && c != TB_KEY_ESC)
  1194. return;
  1195. if(c == TB_KEY_CTRL_G || c == TB_KEY_ESC)
  1196. return;
  1197. else
  1198. character[0] = c;
  1199. display_prompt_and_response(prompt, character);
  1200. tb_present();
  1201. }
  1202. if(type == 0) {
  1203. block();
  1204. }
  1205. if(*ptr(curbp, curbp->b_point) == character[0] || curbp->b_point == 0) {
  1206. if(negated)
  1207. left();
  1208. else
  1209. right();
  1210. }
  1211. while (*(p = ptr(curbp, curbp->b_point + (include_char ? 0 : (negated ? -1 : 1)))) != character[0] &&
  1212. p < curbp->b_ebuf && curbp->b_point > 0) {
  1213. if(negated)
  1214. left();
  1215. else
  1216. right();
  1217. }
  1218. if(type == 0 && !negated)
  1219. right();
  1220. if(type == 0)
  1221. copy_cut(TRUE, FALSE, FALSE);
  1222. tb_set_cursor(0, MSGLINE);
  1223. clrtoeol("", MSGLINE);
  1224. eol = lnstart(curbp, curbp->b_point);
  1225. for(point_t poi = curbp->b_point; poi > eol; poi -= utf8_size(*ptr(curbp,poi)))
  1226. col++;
  1227. curbp->b_pcol = col + curwp->w_left;
  1228. if(p >= ptr(curbp, curbp->b_epage)) {
  1229. curbp->b_reframe = TRUE;
  1230. }
  1231. if((!negated && p >= curbp->b_ebuf) || (negated && curbp->b_point <= 0)) {
  1232. msg("No match found.");
  1233. curbp->b_point = opoint;
  1234. }
  1235. negated = FALSE;
  1236. }
  1237. void zaptochar()
  1238. {
  1239. gotochar(0, universal_argument == 0);
  1240. universal_argument = 0;
  1241. }
  1242. void negated_zaptochar()
  1243. {
  1244. negated = TRUE;
  1245. gotochar(0, universal_argument == 0);
  1246. universal_argument = 0;
  1247. }
  1248. void jumptochar()
  1249. {
  1250. shift_pmark(TRUE, NOMARK);
  1251. gotochar(1, TRUE);
  1252. }
  1253. void negated_jumptochar()
  1254. {
  1255. shift_pmark(TRUE, NOMARK);
  1256. negated = TRUE;
  1257. gotochar(1, TRUE);
  1258. }
  1259. void poptomark()
  1260. {
  1261. if(curbp->b_mark != NOMARK)
  1262. curbp->b_point = curbp->b_mark;
  1263. else if(curbp->b_pmark[0] != NOMARK)
  1264. curbp->b_point = shift_pmark(FALSE, NOMARK);
  1265. else {
  1266. msg("No valid mark to pop to.");
  1267. return;
  1268. }
  1269. if(curbp->b_point < curbp->b_page || curbp->b_point > curbp->b_epage) {
  1270. curbp->b_reframe = TRUE;
  1271. curwp->w_recenter = TRUE;
  1272. }
  1273. }
  1274. void universal_argument_load()
  1275. {
  1276. universal_argument++;
  1277. msg("C-u %d", universal_argument);
  1278. }
  1279. void numeric_argument_load()
  1280. {
  1281. numeric_argument = (numeric_argument * 10) + atoi((const char *)&input_char);
  1282. msg("C-u %d", numeric_argument);
  1283. }
  1284. void back_to_indentation()
  1285. {
  1286. char_t *p;
  1287. while (isspace(*(p = ptr(curbp, curbp->b_point))) && p < curbp->b_ebuf)
  1288. ++curbp->b_point;
  1289. }
  1290. void negate()
  1291. {
  1292. negated = !negated;
  1293. msg("C-u -");
  1294. }
  1295. void forward_bracket()
  1296. {
  1297. point_t p, eol;
  1298. int col = 0;
  1299. if((p = find_matching_bracket(curbp, curwp, 1, FALSE)) >= 0)
  1300. curbp->b_point = curbp->b_mark == NOMARK ? p : p + 1;
  1301. /* Make sure the column memory updates to the new column */
  1302. eol = lnstart(curbp, curbp->b_point);
  1303. for(p = curbp->b_point; p > eol; p -= utf8_size(*ptr(curbp,p)))
  1304. col++;
  1305. curbp->b_pcol = col + curwp->w_left;
  1306. }
  1307. void backward_bracket()
  1308. {
  1309. point_t p, eol;
  1310. int col = 0;
  1311. if((p = find_matching_bracket(curbp, curwp, -1, FALSE)) >= 0) {
  1312. curbp->b_point = p;
  1313. if(curbp->b_mark != NOMARK)
  1314. curbp->b_mark++;
  1315. }
  1316. /* Make sure the column memory updates to the new column */
  1317. eol = lnstart(curbp, curbp->b_point);
  1318. for(p = curbp->b_point; p > eol; p -= utf8_size(*ptr(curbp,p)))
  1319. col++;
  1320. curbp->b_pcol = col + curwp->w_left;
  1321. }
  1322. void start_kbd_macro()
  1323. {
  1324. record_input = TRUE;
  1325. for(int i = 0; i < record_buffer_index; i++) {
  1326. memset(&record_buffer[i], 0, sizeof(record_buffer[i]));
  1327. }
  1328. record_buffer_index = 0;
  1329. msg("Started keyboard macro...");
  1330. }
  1331. void end_kbd_macro()
  1332. {
  1333. record_input = FALSE;
  1334. msg("Ended keyboard macro.");
  1335. }
  1336. void run_kbd_macro()
  1337. {
  1338. if(numeric_argument > 0)
  1339. numeric_argument--;
  1340. execute_kbd_macro = TRUE;
  1341. }
  1342. void open_file_from_shell()
  1343. {
  1344. get_popen_data(1);
  1345. }
  1346. void insert_from_shell()
  1347. {
  1348. get_popen_data(0);
  1349. }
  1350. void insert_control_char()
  1351. {
  1352. struct tb_event ev;
  1353. char *prompt = "Insert Control Char: ";
  1354. display_prompt_and_response(prompt, character);
  1355. tb_present();
  1356. if(tb_poll_event(&ev) != TB_OK) return;
  1357. tb_set_cursor(0, MSGLINE);
  1358. clrtoeol("", MSGLINE);
  1359. if(ev.key > 0x1a) {
  1360. return;
  1361. }
  1362. input[0] = (char)ev.key;
  1363. input[1] = '\0';
  1364. undoset(1, lastcommand == KBD_INSERT);
  1365. insert();
  1366. currentcommand = KBD_INSERT;
  1367. ignorenotbound = TRUE;
  1368. }