command.c 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072
  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 && curbp->b_line == 1)
  26. --curbp->b_point;
  27. curbp->b_col = 0 + curwp->w_left;
  28. }
  29. void version() { msg(VERSION); }
  30. void top()
  31. {
  32. shift_pmark(TRUE, curbp->b_point);
  33. curbp->b_point = 0;
  34. curbp->b_pcol = 0 + curwp->w_left;
  35. shift_pmark(TRUE, curbp->b_point);
  36. }
  37. void bottom()
  38. {
  39. shift_pmark(TRUE, curbp->b_point);
  40. curbp->b_point = pos(curbp, curbp->b_ebuf);
  41. if (curbp->b_epage < pos(curbp, curbp->b_ebuf))
  42. curbp->b_reframe = 1;
  43. curbp->b_pcol = 0 + curwp->w_left;
  44. shift_pmark(TRUE, curbp->b_point);
  45. }
  46. void block() { curbp->b_mark = curbp->b_point; }
  47. void copy() { copy_cut(FALSE, TRUE, FALSE); }
  48. void cut() {
  49. currentcommand = KBD_CUT;
  50. copy_cut(TRUE, TRUE, FALSE);
  51. }
  52. void resize_terminal()
  53. {
  54. LINES = tb_height();
  55. COLS = tb_width();
  56. MSGLINE = LINES-1;
  57. resize();
  58. }
  59. void print_to_msgline(const char *msg)
  60. {
  61. printf_tb(0, MSGLINE, TB_DEFAULT, TB_DEFAULT, msg);
  62. tb_set_cursor(strlen(msg), MSGLINE);
  63. }
  64. void quit_ask()
  65. {
  66. if (modified_buffers() > 0) {
  67. const char *msg = "Modified buffers exist; really exit (y/N) ?";
  68. print_to_msgline(msg);
  69. clrtoeol(msg, MSGLINE);
  70. if (!yesno(FALSE)) {
  71. clrtoeol("", MSGLINE);
  72. return;
  73. }
  74. }
  75. quit();
  76. }
  77. void redraw()
  78. {
  79. window_t *wp;
  80. for (wp=wheadp; wp != NULL; wp = wp->w_next)
  81. wp->w_update = TRUE;
  82. update_display();
  83. }
  84. void left()
  85. {
  86. int n = prev_utf8_char_size();
  87. if(curbp->b_point == 0)
  88. return;
  89. while (0 < curbp->b_point && n-- > 0)
  90. --curbp->b_point;
  91. }
  92. void right()
  93. {
  94. if(curbp->b_point == pos(curbp, curbp->b_ebuf))
  95. return;
  96. int n = utf8_size(*ptr(curbp,curbp->b_point));
  97. while ((curbp->b_point < pos(curbp, curbp->b_ebuf)) && n-- > 0)
  98. ++curbp->b_point;
  99. }
  100. /* work out number of bytes based on first byte */
  101. int utf8_size(char_t c)
  102. {
  103. return tb_utf8_char_length(c);
  104. }
  105. int prev_utf8_char_size()
  106. {
  107. int n;
  108. for (n=2;n<5;n++)
  109. if (-1 < curbp->b_point - n && (utf8_size(*(ptr(curbp, curbp->b_point - n))) == n))
  110. return n;
  111. return 1;
  112. }
  113. void lnend()
  114. {
  115. char_t *p;
  116. int cols = 0;
  117. lnbegin(); // reset the line so we get the right number for `cols`
  118. while(*(p = ptr(curbp, curbp->b_point)) != '\n' && curbp->b_ebuf > p) {
  119. ++curbp->b_point;
  120. }
  121. /* loop until we get to the correct column */
  122. while(cols > curwp->w_cols) {
  123. cols -= curwp->w_cols;
  124. }
  125. curbp->b_pcol = cols + curwp->w_left; // set it for column-memory
  126. }
  127. void wleft()
  128. {
  129. char_t *p = NULL;
  130. if ((curbp->b_buf < p || p == NULL) && (!isspace(*(p = ptr(curbp, curbp->b_point))) || !is_symbol(*p)))
  131. --curbp->b_point;
  132. while (curbp->b_buf < p && (isspace(*(p = ptr(curbp, curbp->b_point))) || is_symbol(*p)) && curbp->b_buf < p)
  133. --curbp->b_point;
  134. while (curbp->b_buf < p && !isspace(*(p = ptr(curbp, curbp->b_point))) && !is_symbol(*p) && curbp->b_buf < p)
  135. --curbp->b_point;
  136. if(curbp->b_buf < p && (isspace(*(p = ptr(curbp, curbp->b_point))) || is_symbol(*p)))
  137. ++curbp->b_point;
  138. }
  139. void wleftdelete()
  140. {
  141. currentcommand = KBD_DELETE_WORD;
  142. iblock();
  143. wleft();
  144. copy_cut(TRUE, TRUE, FALSE);
  145. }
  146. void pgdown()
  147. {
  148. shift_pmark(TRUE, curbp->b_point);
  149. curbp->b_page = curbp->b_point = upup(curbp, curwp, curbp->b_epage);
  150. while (0 < curwp->w_top - curbp->b_row) {
  151. down();
  152. curbp->b_row--;
  153. }
  154. curbp->b_epage = pos(curbp, curbp->b_ebuf);
  155. curbp->b_pcol = 0 + curwp->w_left;
  156. shift_pmark(TRUE, curbp->b_point);
  157. }
  158. void pgup()
  159. {
  160. int i = curwp->w_rows;
  161. shift_pmark(TRUE, curbp->b_point);
  162. while (0 < --i) {
  163. curbp->b_page = upup(curbp, curwp, curbp->b_page);
  164. up();
  165. }
  166. curbp->b_pcol = 0 + curwp->w_left;
  167. shift_pmark(TRUE, curbp->b_point);
  168. }
  169. void wright()
  170. {
  171. char_t *p = NULL;
  172. if (p < curbp->b_ebuf && (!isspace(*(p = ptr(curbp, curbp->b_point))) || !is_symbol(*p)))
  173. ++curbp->b_point;
  174. while (p < curbp->b_ebuf && (isspace(*(p = ptr(curbp, curbp->b_point))) || is_symbol(*p)))
  175. ++curbp->b_point;
  176. while (p < curbp->b_ebuf && !isspace(*(p = ptr(curbp, curbp->b_point))) && !is_symbol(*p))
  177. ++curbp->b_point;
  178. }
  179. void wrightdelete()
  180. {
  181. currentcommand = KBD_DELETE_WORD;
  182. iblock();
  183. wright();
  184. copy_cut(TRUE, TRUE, FALSE);
  185. }
  186. void insert()
  187. {
  188. assert(curbp->b_gap <= curbp->b_egap);
  189. if (curbp->b_gap == curbp->b_egap && !growgap(curbp, CHUNK))
  190. return;
  191. curbp->b_point = movegap(curbp, curbp->b_point);
  192. /* overwrite if mid line, not EOL or EOF, CR will insert as normal */
  193. if ((curbp->b_flags & B_OVERWRITE) && *input != '\r' && *(ptr(curbp, curbp->b_point)) != '\n' && curbp->b_point < pos(curbp,curbp->b_ebuf) ) {
  194. *(ptr(curbp, curbp->b_point)) = *input;
  195. if (curbp->b_point < pos(curbp, curbp->b_ebuf))
  196. ++curbp->b_point;
  197. } else {
  198. *curbp->b_gap++ = *input == '\r' ? '\n' : *input;
  199. curbp->b_point = pos(curbp, curbp->b_egap);
  200. // force reframe if scrolled off bottom of screen and at EOF
  201. if (curbp->b_point == pos(curbp, curbp->b_ebuf) && curbp->b_point >= curbp->b_epage &&
  202. curwp->w_rows == (curwp->w_row - curwp->w_top))
  203. curbp->b_reframe = 1;
  204. }
  205. curbp->b_flags |= B_MODIFIED;
  206. undoset_flag = TRUE;
  207. currentcommand = KBD_INSERT;
  208. }
  209. void insert_str()
  210. {
  211. int len = strlen((const char *)input);
  212. assert(curbp->b_gap <= curbp->b_egap);
  213. undoset(INSERT, FALSE);
  214. if (curbp->b_gap == curbp->b_egap && !growgap(curbp, CHUNK))
  215. return;
  216. curbp->b_point = movegap(curbp, curbp->b_point);
  217. /* overwrite if mid line, not EOL or EOF, CR will insert as normal */
  218. if ((curbp->b_flags & B_OVERWRITE) && input[0] != '\r' && *(ptr(curbp, curbp->b_point)) != '\n' && curbp->b_point < pos(curbp,curbp->b_ebuf) ) {
  219. *(ptr(curbp, curbp->b_point)) = *input;
  220. if (curbp->b_point < pos(curbp, curbp->b_ebuf))
  221. ++curbp->b_point;
  222. } else {
  223. for(int i = 0; i < len; i++) {
  224. *curbp->b_gap++ = input[i] == '\r' ? '\n' : input[i];
  225. // if(input[i] == '\n' || input[i] == '\r')
  226. // curbp->b_line++;
  227. }
  228. curbp->b_point = pos(curbp, curbp->b_egap);
  229. // force reframe if scrolled off bottom of screen and at EOF
  230. if (curbp->b_point == pos(curbp, curbp->b_ebuf) && curbp->b_point >= curbp->b_epage &&
  231. curwp->w_rows == (curwp->w_row - curwp->w_top))
  232. curbp->b_reframe = 1;
  233. }
  234. curbp->b_flags |= B_MODIFIED;
  235. undoset_flag = TRUE;
  236. }
  237. void insert_unicode()
  238. {
  239. int len = strlen((const char *)unicode_buf);
  240. assert(curbp->b_gap <= curbp->b_egap);
  241. undoset(INSERT, lastcommand == KBD_INSERT);
  242. if (curbp->b_gap == curbp->b_egap && !growgap(curbp, CHUNK))
  243. return;
  244. curbp->b_point = movegap(curbp, curbp->b_point);
  245. /* overwrite if mid line, not EOL or EOF, CR will insert as normal */
  246. for(int i = 0; i < len; i++) {
  247. *curbp->b_gap++ = unicode_buf[i];
  248. }
  249. curbp->b_point = pos(curbp, curbp->b_egap);
  250. // force reframe if scrolled off bottom of screen and at EOF
  251. if (curbp->b_point == pos(curbp, curbp->b_ebuf) && curbp->b_point >= curbp->b_epage &&
  252. curwp->w_rows == (curwp->w_row - curwp->w_top))
  253. curbp->b_reframe = 1;
  254. curbp->b_flags |= B_MODIFIED;
  255. undoset_flag = TRUE;
  256. unicode_buf[0] = '\0';
  257. currentcommand = KBD_INSERT;
  258. }
  259. void backsp()
  260. {
  261. undoset(BACKSP, lastcommand == KBD_DELETE_CHAR);
  262. if(curbp->b_point != 0 && *ptr(curbp, curbp->b_point - 1) == '\n')
  263. curbp->b_line--;
  264. curbp->b_point = movegap(curbp, curbp->b_point);
  265. if (curbp->b_buf < curbp->b_gap) {
  266. curbp->b_gap -= prev_utf8_char_size();
  267. curbp->b_flags |= B_MODIFIED;
  268. }
  269. curbp->b_point = pos(curbp, curbp->b_egap);
  270. currentcommand = KBD_DELETE_CHAR;
  271. }
  272. void delete()
  273. {
  274. undoset(DELETE, lastcommand == KBD_DELETE_CHAR);
  275. curbp->b_point = movegap(curbp, curbp->b_point);
  276. if (curbp->b_egap < curbp->b_ebuf) {
  277. curbp->b_egap += utf8_size(*curbp->b_egap);
  278. curbp->b_point = pos(curbp, curbp->b_egap);
  279. curbp->b_flags |= B_MODIFIED;
  280. }
  281. currentcommand = KBD_DELETE_CHAR;
  282. }
  283. void gotoline()
  284. {
  285. int line, showdefault = lastline > 0;
  286. point_t p;
  287. char *prompt;
  288. if(showdefault)
  289. asprintf(&prompt, "Goto line (default %d): ", lastline);
  290. else
  291. asprintf(&prompt, "Goto line: ");
  292. if (getinput(prompt, temp, STRBUF_S, F_CLEAR, showdefault)) {
  293. line = temp[0] == 0 && showdefault ? lastline : atoi(temp);
  294. p = line_to_point(line);
  295. if (p != -1) {
  296. shift_pmark(TRUE, curbp->b_point);
  297. curbp->b_point = p;
  298. curbp->b_pcol = 0 + curwp->w_left;
  299. if (curbp->b_epage < pos(curbp, curbp->b_ebuf)) curbp->b_reframe = 1;
  300. curwp->w_update = TRUE;
  301. curwp->w_recenter = TRUE;
  302. lastline = line;
  303. msg("Line %d", line);
  304. shift_pmark(TRUE, curbp->b_point);
  305. } else {
  306. msg("Line %d, not found", line);
  307. }
  308. }
  309. clrtoeol("", MSGLINE);
  310. free(prompt);
  311. prompt = NULL;
  312. }
  313. void gotocolumn()
  314. {
  315. int col, remainder = 0, showdefault = lastcol > 0;
  316. point_t opoint = curbp->b_point, end = pos(curbp, curbp->b_ebuf);
  317. char *prompt;
  318. shift_pmark(TRUE, curbp->b_point);
  319. if(showdefault)
  320. asprintf(&prompt, "Goto column (default %d): ", lastcol);
  321. else
  322. asprintf(&prompt, "Goto column: ");
  323. if (getinput(prompt, temp, STRBUF_S, F_CLEAR, showdefault)) {
  324. col = temp[0] == 0 && showdefault ? lastcol : atoi(temp);
  325. remainder = col - curbp->b_col - 1;
  326. if(remainder > 0) {
  327. if(*ptr(curbp, curbp->b_point) == '\n') {
  328. msg("Column %d, not found.", col);
  329. return;
  330. }
  331. for(; remainder > 0; remainder--) {
  332. right();
  333. if((*ptr(curbp, curbp->b_point) == '\n' ||
  334. curbp->b_point == end) &&
  335. remainder != 1) {
  336. curbp->b_point = opoint;
  337. msg("Column %d, not found.", col);
  338. return;
  339. }
  340. }
  341. } else if(remainder < 0) {
  342. remainder *= -1;
  343. if(curbp->b_point == 0 ||
  344. *ptr(curbp, curbp->b_point - 1) == '\n') {
  345. msg("Column %d, not found.", col);
  346. return;
  347. }
  348. for(; remainder > 0; remainder--) {
  349. left();
  350. if((*ptr(curbp, curbp->b_point - 1) == '\n' ||
  351. curbp->b_point == 0) &&
  352. remainder != 1) {
  353. curbp->b_point = opoint;
  354. msg("Column %d, not found.", col);
  355. return;
  356. }
  357. }
  358. }
  359. lastcol = col;
  360. }
  361. shift_pmark(TRUE, curbp->b_point);
  362. clrtoeol("", MSGLINE);
  363. free(prompt);
  364. prompt = NULL;
  365. }
  366. void jumptorow()
  367. {
  368. int line = -1, j = 0, i = 0, current, lastln, pageln;
  369. char num[3] = { 0, 0, 0 };
  370. struct tb_event ev;
  371. char *prompt = "Jump to line reference: ";
  372. int start_col = strlen(prompt), match = FALSE;
  373. char opts[10] = {'f','j','d','k','s','l','g','h', 'a', ';'};
  374. char chars[curwp->w_rows][2];
  375. point_t point;
  376. char_t *p;
  377. char f, s;
  378. int count = 0, fp = 0, sp = 0;
  379. int w_row = curwp->w_row - curwp->w_top;
  380. get_line_stats(&current, &lastln, curbp);
  381. pageln = current - w_row;
  382. point = curbp->b_page;
  383. p = ptr(curbp, point);
  384. for(int i = 0; i < curwp->w_rows && pageln <= lastln; i++) {
  385. f = opts[fp];
  386. s = opts[sp];
  387. chars[i][0] = f;
  388. chars[i][1] = s;
  389. printf_tb(curwp->w_left, curwp->w_top+i, TB_RED, TB_CYAN, "%c%c", f,s);
  390. sp++;
  391. count++;
  392. if(count > 7) {
  393. fp++;
  394. sp = 0;
  395. count = 0;
  396. }
  397. int c = 1;
  398. while(*(p = ptr(curbp, point)) != '\n' &&
  399. curbp->b_ebuf > p && c < curwp->w_cols) {
  400. ++point;
  401. c++;
  402. }
  403. if(*p == '\n' || pageln == lastln)
  404. pageln++;
  405. ++point;
  406. p = ptr(curbp, point);
  407. }
  408. display_prompt_and_response(prompt, num);
  409. tb_present();
  410. while(j < 2) {
  411. display_prompt_and_response(prompt, num);
  412. tb_present();
  413. if(execute_kbd_macro) {
  414. use_kbd_macro(&ev);
  415. } else if(tb_poll_event(&ev) != TB_OK)
  416. break;
  417. if(record_input) {
  418. record_buffer[record_buffer_index] = ev;
  419. record_buffer_index++;
  420. }
  421. if(ev.key == TB_KEY_CTRL_G) {
  422. clrtoeol("", MSGLINE);
  423. return;
  424. }
  425. if(j < 2) {
  426. num[j] = ev.ch;
  427. tb_set_cursor(start_col, MSGLINE);
  428. addstr(num);
  429. point = curbp->b_page;
  430. p = ptr(curbp, point);
  431. int i = 0;
  432. if(j == 0) {
  433. pageln = current - w_row;
  434. for(i = 0; i < curwp->w_rows && pageln <= lastln; i++) {
  435. if(chars[i][0] == ev.ch) {
  436. match = TRUE;
  437. if(*p != '\n')
  438. p = ptr(curbp, point+1);
  439. if(*p == '\0')
  440. *p = ' ';
  441. printf_tb(curwp->w_left, curwp->w_top+i, TB_RED, TB_CYAN, "%c", chars[i][1]);
  442. printf_tb(curwp->w_left+1, curwp->w_top+i, TB_DEFAULT, TB_DEFAULT, "%c", *p == '\n' ? ' ' : *p);
  443. } else {
  444. printf_tb(curwp->w_left, curwp->w_top+i, TB_DEFAULT, TB_DEFAULT, "%c", *p == '\n' ? ' ' : *p);
  445. if(*p != '\n')
  446. p = ptr(curbp, point+1);
  447. if(*p == '\0')
  448. *p = ' ';
  449. printf_tb(curwp->w_left+1, curwp->w_top+i, TB_DEFAULT, TB_DEFAULT, "%c", *p == '\n' ? ' ' : *p);
  450. }
  451. int c = 1;
  452. while(*(p = ptr(curbp, point)) != '\n' &&
  453. curbp->b_ebuf > p && c < curwp->w_cols) {
  454. ++point;
  455. c++;
  456. }
  457. if(curbp->b_ebuf == p && chars[i][0] != ev.ch) {
  458. printf_tb(curwp->w_left, curwp->w_top+i, TB_DEFAULT, TB_DEFAULT, "%c", ' ');
  459. }
  460. if(*p == '\n' || pageln == lastln)
  461. pageln++;
  462. ++point;
  463. p = ptr(curbp, point);
  464. }
  465. }
  466. j++;
  467. }
  468. if(!match) {
  469. clrtoeol("", MSGLINE);
  470. return;
  471. }
  472. }
  473. for(; i < curwp->w_rows; i++) {
  474. if(chars[i][0] == num[0] && chars[i][1] == num[1]) {
  475. line = w_row - i;
  476. break;
  477. }
  478. }
  479. if(i == curwp->w_rows) {
  480. msg("Out of bounds");
  481. return;
  482. }
  483. shift_pmark(TRUE, curbp->b_point);
  484. if(line > 0) {
  485. for(; line > 0; line--) {
  486. up();
  487. }
  488. } else {
  489. for(; line < 0; line++) {
  490. down();
  491. }
  492. }
  493. shift_pmark(TRUE, curbp->b_point);
  494. clrtoeol("", MSGLINE);
  495. }
  496. void jumpword()
  497. {
  498. point_t current = curbp->b_page;
  499. char num[3] = { 0, 0, 0 };
  500. int j = 0, match = FALSE;
  501. char starting[1];
  502. struct tb_event ev;
  503. char *prompt = "Jump to word starting with: ";
  504. int start_col = strlen(prompt);
  505. char opts[10] = {'f','j','d','k','s','l','g','h', 'a', ';'};
  506. int diff = curbp->b_epage - curbp->b_page;
  507. char chars[diff][2];
  508. point_t point = -1;
  509. int begin = TRUE, is_white = FALSE, is_symb = FALSE, charlen = 0;
  510. char_t *p, *tp;
  511. char f, s;
  512. int count = 0, fp = 0, sp = 0, x = 0, y = 0;
  513. display_prompt_and_response(prompt, starting);
  514. tb_present();
  515. if(execute_kbd_macro) {
  516. use_kbd_macro(&ev);
  517. } else if(tb_poll_event(&ev) != TB_OK)
  518. return;
  519. if(record_input) {
  520. record_buffer[record_buffer_index] = ev;
  521. record_buffer_index++;
  522. }
  523. if(ev.key == TB_KEY_CTRL_G) {
  524. clrtoeol("", MSGLINE);
  525. return;
  526. }
  527. starting[0] = (unsigned)ev.ch;
  528. for(; current < curbp->b_epage; current++) {
  529. p = ptr(curbp, current);
  530. is_white = isspace(*p);
  531. is_symb = is_symbol(*p);
  532. if(is_white || is_symb || current == 0)
  533. begin = TRUE;
  534. if(*p == (char_t)starting[0] && begin) {
  535. f = opts[fp];
  536. s = opts[sp];
  537. chars[current-curbp->b_page][0] = f;
  538. chars[current-curbp->b_page][1] = s;
  539. charlen++;
  540. printf_tb(curwp->w_left+x, curwp->w_top+y, TB_RED, TB_CYAN, "%c%c", f,s);
  541. sp++;
  542. count++;
  543. if(count > 7) {
  544. fp++;
  545. sp = 0;
  546. count = 0;
  547. }
  548. begin = FALSE;
  549. }
  550. if(!is_white && !is_symb)
  551. begin = FALSE;
  552. x++;
  553. if(*p == '\t')
  554. x += (TAB_SIZE - 2);
  555. if(*p < 31)
  556. x++;
  557. if(*p == '\n' || x >= curwp->w_cols) {
  558. x = 0;
  559. y++;
  560. }
  561. }
  562. tb_present();
  563. if(charlen > 1) {
  564. display_prompt_and_response(prompt, num);
  565. tb_present();
  566. while(j < 2) {
  567. display_prompt_and_response(prompt, num);
  568. tb_present();
  569. if(tb_poll_event(&ev) != TB_OK) break;
  570. if(ev.key == TB_KEY_CTRL_G) {
  571. clrtoeol("", MSGLINE);
  572. return;
  573. }
  574. if(j < 2) {
  575. num[j] = ev.ch;
  576. tb_set_cursor(start_col, MSGLINE);
  577. addstr(num);
  578. x = 0;
  579. y = 0;
  580. if(j == 0) {
  581. for(current = curbp->b_page; current < curbp->b_epage; current++) {
  582. p = ptr(curbp, current);
  583. tp = ptr(curbp, current);
  584. is_white = isspace(*p);
  585. is_symb = is_symbol(*p);
  586. if(is_white || is_symb || current == 0)
  587. begin = TRUE;
  588. if(*p == (char_t)starting[0] && begin) {
  589. point_t i = current-curbp->b_page;
  590. if(chars[i][0] == ev.ch) {
  591. match = TRUE;
  592. tp = ptr(curbp, current+1);
  593. printf_tb(curwp->w_left+x, curwp->w_top+y, TB_RED, TB_CYAN, "%c", chars[i][1]);
  594. printf_tb(curwp->w_left+x+1, curwp->w_top+y, TB_DEFAULT, TB_DEFAULT, "%c", *tp == '\n' ? ' ' : *tp);
  595. } else {
  596. printf_tb(curwp->w_left+x, curwp->w_top+y, TB_DEFAULT, TB_DEFAULT, "%c", *tp == '\n' ? ' ' : *tp);
  597. tp = ptr(curbp, current+1);
  598. printf_tb(curwp->w_left+x+1, curwp->w_top+y, TB_DEFAULT, TB_DEFAULT, "%c", *tp == '\n' ? ' ' : *tp);
  599. }
  600. begin = FALSE;
  601. }
  602. if(!is_white && !is_symb)
  603. begin = FALSE;
  604. x++;
  605. if(*p == '\t')
  606. x += (TAB_SIZE - 2);
  607. if(*p < 31)
  608. x++;
  609. if(*p == '\n' || x >= curwp->w_cols) {
  610. x = 0;
  611. y++;
  612. }
  613. }
  614. }
  615. j++;
  616. if(!match) {
  617. clrtoeol("", MSGLINE);
  618. return;
  619. }
  620. }
  621. }
  622. } else {
  623. num[0] = 'f';
  624. num[1] = 'f';
  625. }
  626. for(point_t cur = 0; cur < diff; cur++) {
  627. if(chars[cur][0] == num[0] && chars[cur][1] == num[1]) {
  628. point = cur + curbp->b_page;
  629. break;
  630. }
  631. }
  632. if(point == -1) {
  633. msg("Out of bounds.");
  634. } else {
  635. shift_pmark(TRUE, curbp->b_point);
  636. curbp->b_point = point;
  637. int cols = 0;
  638. /* Calculate the pcol value */
  639. lnbegin(); // reset the line so we get the right number for `cols`
  640. while(curbp->b_point != point) {
  641. ++curbp->b_point;
  642. cols++;
  643. }
  644. /* loop until we get to the correct column */
  645. while(cols > curwp->w_cols) {
  646. cols -= curwp->w_cols;
  647. }
  648. curbp->b_pcol = cols + curwp->w_left; // set it for column-memory
  649. clrtoeol("", MSGLINE);
  650. }
  651. /* Clear out the chars array */
  652. for(int i = 0; i < diff; i++) {
  653. chars[i][0] = 0;
  654. chars[i][1] = 0;
  655. }
  656. shift_pmark(TRUE, curbp->b_point);
  657. /* TODO: figure out why this has to be here
  658. Without this printf, the chars array doesn't appear to get
  659. cleared entirely and you end up jumping to the wrong points.
  660. */
  661. printf("%s", chars[0]);
  662. }
  663. void get_current_path(char *cur_path)
  664. {
  665. int cutoff = 0;
  666. for(int i = strlen(curbp->b_fname) - 1; i > -1; i--) {
  667. if(curbp->b_fname[i] == '/') {
  668. cutoff = i;
  669. break;
  670. }
  671. }
  672. for(int i = 0; i <= cutoff; i++)
  673. cur_path[i] = curbp->b_fname[i];
  674. cur_path[cutoff+1] = '\0';
  675. }
  676. void insertfile()
  677. {
  678. char cur_path[PATH_MAX] = "\0";
  679. if(curbp->b_path) {
  680. get_current_path(cur_path);
  681. strcpy(temp, cur_path);
  682. }
  683. else
  684. strcpy(temp, editor_dir);
  685. if (getfilename("Insert file: ", temp, PATH_MAX))
  686. (void)insert_file(temp, TRUE);
  687. }
  688. void readfile()
  689. {
  690. buffer_t *bp;
  691. char cur_path[PATH_MAX];
  692. if(curbp->b_path) {
  693. get_current_path(cur_path);
  694. strcpy(temp, cur_path);
  695. }
  696. else
  697. strcpy(temp, editor_dir);
  698. int result = getfilename("Find file: ", (char*)temp, PATH_MAX);
  699. if (result) {
  700. bp = find_buffer(temp, TRUE, FALSE);
  701. disassociate_b(curwp);
  702. curbp = bp;
  703. associate_b2w(curbp, curwp);
  704. if (!growgap(curbp, CHUNK))
  705. fatal("%s: Failed to allocate required memory.\n");
  706. movegap(curbp, 0);
  707. /* load the file if not already loaded */
  708. if (bp != NULL && bp->b_fname[0] == '\0') {
  709. if (!load_file(temp)) {
  710. msg("New file %s", temp);
  711. }
  712. strncpy(curbp->b_fname, temp, PATH_MAX);
  713. curbp->b_fname[PATH_MAX] = '\0'; /* truncate if required */
  714. }
  715. }
  716. }
  717. void savebuffer()
  718. {
  719. const char *message = "No newline at the end of file, add one (Y/n) ?";
  720. if(curbp->b_flags & B_MODIFIED) {
  721. /* move the gap to point 0 so that the ebuf is updated. */
  722. (void) movegap(curbp, 0);
  723. if(*(curbp->b_ebuf - 1) != '\n') {
  724. print_to_msgline(message);
  725. clrtoeol(message, MSGLINE);
  726. if (yesno(TRUE)) {
  727. clrtoeol("", MSGLINE);
  728. *curbp->b_ebuf++ = '\n';
  729. }
  730. }
  731. if (curbp->b_fname[0] != '\0') {
  732. save(curbp->b_fname);
  733. return;
  734. } else {
  735. writefile();
  736. }
  737. } else {
  738. msg("(No changes need to be saved.)");
  739. }
  740. }
  741. void writefile()
  742. {
  743. const char *message = "Write file: ";
  744. strncpy(temp, curbp->b_fname, PATH_MAX);
  745. if (getinput((char *)message, temp, PATH_MAX, F_NONE, FALSE))
  746. if (save(temp) == TRUE)
  747. strncpy(curbp->b_fname, temp, PATH_MAX);
  748. clrtoeol(message, MSGLINE);
  749. }
  750. void killbuffer()
  751. {
  752. buffer_t *kill_bp = curbp;
  753. buffer_t *bp;
  754. int bcount = count_buffers();
  755. const char *message = "Discard changes (y/N) ?";
  756. /* do nothing if only buffer left is the scratch buffer */
  757. if (bcount == 1 && 0 == strcmp(get_buffer_name(curbp), "*scratch*"))
  758. return;
  759. if (curbp->b_flags & B_MODIFIED) {
  760. print_to_msgline(message);
  761. clrtoeol(message, MSGLINE);
  762. if (!yesno(FALSE))
  763. return;
  764. }
  765. if (bcount == 1) {
  766. /* create a scratch buffer */
  767. bp = find_buffer("*scratch*", TRUE, FALSE);
  768. strncpy(bp->b_bname, "*scratch*", STRBUF_S);
  769. bp->b_path = FALSE;
  770. }
  771. next_buffer();
  772. assert(kill_bp != curbp);
  773. delete_buffer(kill_bp);
  774. for(window_t *wp = wheadp; wp != NULL; wp = wp->w_next) {
  775. if(kill_bp == wp->w_bufp) {
  776. wp->w_bufp = curbp;
  777. }
  778. }
  779. clrtoeol("", MSGLINE);
  780. }
  781. void iblock()
  782. {
  783. block();
  784. msg("Mark set");
  785. }
  786. void unmark()
  787. {
  788. shift_pmark(TRUE, NOMARK);
  789. curbp->b_mark = NOMARK;
  790. universal_argument = 0;
  791. msg("Mark removed");
  792. }
  793. void toggle_overwrite_mode() {
  794. if (curbp->b_flags & B_OVERWRITE)
  795. curbp->b_flags &= ~B_OVERWRITE;
  796. else
  797. curbp->b_flags |= B_OVERWRITE;
  798. }
  799. void killtoeol()
  800. {
  801. if (curbp->b_point == pos(curbp, curbp->b_ebuf))
  802. return; /* do nothing if at end of file */
  803. if (*(ptr(curbp, curbp->b_point)) == 0xa) {
  804. delete(); /* delete CR if at start of empty line */
  805. } else {
  806. curbp->b_mark = curbp->b_point;
  807. lnend();
  808. if (curbp->b_mark != curbp->b_point) {
  809. currentcommand = KBD_CUT;
  810. copy_cut(TRUE, TRUE, FALSE);
  811. }
  812. }
  813. }
  814. /* Since version 1.9, you can use back-word-delete and
  815. fwd-word-delete to delete (and cut) a string of text so long that
  816. you don't interrupt the use of that direction of deletion. In
  817. other words, if you had the follow text and performed two `M-d`,
  818. you'd get both words in the scrap:
  819. hello there
  820. ^
  821. |
  822. point is here
  823. This means I have to concat, in the correct order, what you've cut
  824. in the scrap. To do this, I need the original scrap size and value
  825. then do some stuff to merge them together.
  826. */
  827. void copy_cut(int cut, int displaymsg, int internal)
  828. {
  829. char_t *p, *os, *ns = NULL;
  830. int shouldconcat = FALSE, onscrap = scrap.len, hasscrap = TRUE;
  831. /* if no mark or point == marker, nothing doing */
  832. if (curbp->b_mark == NOMARK || curbp->b_point == curbp->b_mark)
  833. return;
  834. if(cut && !internal) {
  835. /* We only concat if it's a word delete */
  836. shouldconcat = lastcommand == KBD_DELETE_WORD &&
  837. currentcommand == KBD_DELETE_WORD ?
  838. curbp->b_point - curbp->b_mark : FALSE;
  839. undoset(CUT, shouldconcat);
  840. }
  841. if(!shouldconcat || scrap.data == NULL) {
  842. hasscrap = FALSE;
  843. onscrap = 0;
  844. for(int i = KILLRING_SIZE-1; i > 0; i--) {
  845. if(kill_ring[i].data != NULL) {
  846. free(kill_ring[i].data);
  847. kill_ring[i].data = NULL;
  848. }
  849. if(kill_ring[i-1].data != NULL) {
  850. if ((kill_ring[i].data = (char_t *)malloc(kill_ring[i-1].len*sizeof(char_t))) == NULL) {
  851. msg("No more memory available.");
  852. return;
  853. } else {
  854. (void) memcpy(kill_ring[i].data, kill_ring[i-1].data, kill_ring[i-1].len*sizeof(char_t));
  855. kill_ring[i].len = kill_ring[i-1].len;
  856. }
  857. }
  858. }
  859. if(kill_ring[0].data != NULL) {
  860. free(kill_ring[0].data);
  861. kill_ring[0].data = NULL;
  862. }
  863. if ((kill_ring[0].data = (char_t *)malloc(scrap.len*sizeof(char_t))) == NULL) {
  864. msg("No more memory available.");
  865. return;
  866. } else {
  867. (void) memcpy(kill_ring[0].data, scrap.data, scrap.len*sizeof(char_t));
  868. kill_ring[0].len = scrap.len;
  869. }
  870. }
  871. if (curbp->b_point < curbp->b_mark) {
  872. /* point above marker: move gap under point, region = marker - point */
  873. (void) movegap(curbp, curbp->b_point);
  874. p = ptr(curbp, curbp->b_point);
  875. scrap.len = curbp->b_mark - curbp->b_point;
  876. if(cut && currentcommand == KBD_DELETE_WORD)
  877. for(point_t pt = curbp->b_mark-1; pt > curbp->b_point; pt--) {
  878. if(*ptr(curbp, pt) == '\n')
  879. curbp->b_line--;
  880. }
  881. } else {
  882. /* if point below marker: move gap under marker, region = point - marker */
  883. (void) movegap(curbp, curbp->b_mark);
  884. p = ptr(curbp, curbp->b_mark);
  885. scrap.len = curbp->b_point - curbp->b_mark;
  886. if (cut && currentcommand != KBD_DELETE_WORD)
  887. for(point_t pt = curbp->b_mark; pt < curbp->b_point; pt++) {
  888. if(*ptr(curbp, pt) == '\n')
  889. curbp->b_line--;
  890. }
  891. }
  892. if (shouldconcat) {
  893. ns = (char_t *) strndup((const char *)p, scrap.len);
  894. ns[scrap.len] = '\0';
  895. if(shouldconcat < 0 && hasscrap) { /* deleting with M-<backsp> */
  896. asprintf((char **)&os, "%s%s", ns, scrap.data);
  897. os[onscrap + scrap.len] = '\0';
  898. if(scrap.data != NULL)
  899. free(scrap.data);
  900. scrap.data = os;
  901. free(ns);
  902. ns = NULL;
  903. } else if(shouldconcat > 0 && hasscrap) { /* deleting with M-d */
  904. asprintf((char **)&os, "%s%s", scrap.data, ns);
  905. os[onscrap + scrap.len] = '\0';
  906. if(scrap.data != NULL)
  907. free(scrap.data);
  908. scrap.data = os;
  909. free(ns);
  910. ns = NULL;
  911. } else /* first time deleting */
  912. scrap.data = ns;
  913. scrap.len = onscrap + scrap.len;
  914. // os = NULL;
  915. } else {
  916. if (scrap.data != NULL) {
  917. free(scrap.data);
  918. scrap.data = NULL;
  919. }
  920. if ((scrap.data = (char_t*) malloc(scrap.len)) == NULL) {
  921. msg("No more memory available.");
  922. return;
  923. } else {
  924. (void) memcpy(scrap.data, p, scrap.len * sizeof (char_t));
  925. }
  926. }
  927. if (cut) {
  928. /* note that we only need to expand the gap by the amount being
  929. concated
  930. */
  931. curbp->b_egap += scrap.len - onscrap; /* if cut expand gap down */
  932. curbp->b_point = pos(curbp, curbp->b_egap); /* set point to after region */
  933. curbp->b_flags |= B_MODIFIED;
  934. if(displaymsg)
  935. msg("%ld bytes cut.", scrap.len);
  936. // currentcommand = KBD_CUT;
  937. } else {
  938. if(displaymsg)
  939. msg("%ld bytes copied.", scrap.len);
  940. }
  941. curbp->b_mark = NOMARK; /* unmark */
  942. }
  943. void paste_internal(int internal)
  944. {
  945. int new_rows = 0;
  946. int col = curwp->w_col - curwp->w_left + 1;
  947. point_t opoint = curbp->b_point;
  948. if(curbp->b_flags & B_OVERWRITE)
  949. return;
  950. if (scrap.len <= 0) {
  951. msg("Scrap is empty. Nothing to yank.");
  952. } else if (scrap.len < curbp->b_egap - curbp->b_gap || growgap(curbp, scrap.len)) {
  953. if(!internal)
  954. undoset(YANK, FALSE);
  955. curbp->b_point = movegap(curbp, curbp->b_point);
  956. memcpy(curbp->b_gap, scrap.data, scrap.len * sizeof (char_t));
  957. curbp->b_gap += scrap.len;
  958. curbp->b_point = pos(curbp, curbp->b_egap);
  959. curbp->b_flags |= B_MODIFIED;
  960. /* TODO: this assumes 1 char = 1 point (not always true) */
  961. col += curbp->b_point - opoint;
  962. for(int i = 0, cc = col; scrap.data[i] != '\0'; i++) {
  963. cc++;
  964. if(scrap.data[i] == '\n' || cc >= curwp->w_cols) {
  965. new_rows++;
  966. cc = 0;
  967. }
  968. curbp->b_pcol = cc + curwp->w_left;
  969. }
  970. if ((curbp->b_row - curwp->w_top) + new_rows >= curwp->w_rows)
  971. curbp->b_reframe = 1;
  972. }
  973. }
  974. void paste()
  975. {
  976. char_t *oscrap;
  977. int onscrap;
  978. currentcommand = KBD_YANK;
  979. if(universal_argument > 0 && universal_argument-1 < KILLRING_SIZE) {
  980. oscrap = (char_t *)strndup((char *)scrap.data, scrap.len);
  981. onscrap = scrap.len;
  982. free(scrap.data);
  983. scrap.len = kill_ring[universal_argument-1].len;
  984. scrap.data = (char_t*) malloc(scrap.len);
  985. memccpy(scrap.data, kill_ring[universal_argument-1].data, '\0', scrap.len);
  986. paste_internal(FALSE);
  987. free(scrap.data);
  988. scrap.len = onscrap;
  989. scrap.data = (char_t*) malloc(scrap.len);
  990. memcpy(scrap.data, oscrap, scrap.len);
  991. free(oscrap);
  992. return;
  993. }
  994. paste_internal(FALSE);
  995. }
  996. void clipboard()
  997. {
  998. int new_rows = 0;
  999. int len = strlen((const char *)gtemp);
  1000. if(curbp->b_flags & B_OVERWRITE)
  1001. return;
  1002. if (len <= 0) {
  1003. msg("Temp buffer is empty. Nothing to paste.");
  1004. return;
  1005. }
  1006. undoset(CLIPBOARD, FALSE);
  1007. if (curbp->b_egap == curbp->b_gap && !growgap(curbp, CHUNK))
  1008. return;
  1009. curbp->b_point = movegap(curbp, curbp->b_point);
  1010. for(int i = 0; i < len; i++) {
  1011. *curbp->b_gap++ = gtemp[i];
  1012. }
  1013. curbp->b_point = pos(curbp, curbp->b_egap);
  1014. curbp->b_flags |= B_MODIFIED;
  1015. for(int i = 0; gtemp[i] != '\0'; i++) {
  1016. if(gtemp[i] == '\n')
  1017. new_rows++;
  1018. }
  1019. if ((curbp->b_row - curwp->w_top) + new_rows > curwp->w_rows &&
  1020. curbp->b_point >= curbp->b_epage)
  1021. curbp->b_reframe = 1;
  1022. free(gtemp);
  1023. gtemp = NULL;
  1024. }
  1025. void showpos()
  1026. {
  1027. int current, lastln;
  1028. point_t end_p = pos(curbp, curbp->b_ebuf);
  1029. get_line_stats(&current, &lastln, curbp);
  1030. if (curbp->b_point == end_p) {
  1031. msg("[EOB] Line = %d/%d Point = %d/%d", current, lastln,
  1032. curbp->b_point, ((curbp->b_ebuf - curbp->b_buf) - (curbp->b_egap - curbp->b_gap)));
  1033. } else {
  1034. char c = unctrl(*(ptr(curbp, curbp->b_point)));
  1035. msg("Char = %c 0x%x Line = %d/%d Point = %d/%d", c, *(ptr(curbp, curbp->b_point)),
  1036. current, lastln,
  1037. curbp->b_point, ((curbp->b_ebuf - curbp->b_buf) - (curbp->b_egap - curbp->b_gap)));
  1038. }
  1039. }
  1040. /* Delete whitespace between non-whitespace */
  1041. void delete_between()
  1042. {
  1043. char_t *p, other;
  1044. struct tb_event ev;
  1045. char *prompt;
  1046. int c, is_start = FALSE;
  1047. /* Delete everything between brackets. */
  1048. if(universal_argument > 0) {
  1049. if(character[0] == '\0') {
  1050. if(lastsymb == 0)
  1051. asprintf(&prompt, "Bracket to Zap Between: ");
  1052. else
  1053. asprintf(&prompt, "Bracket to Zap Between (default %c): ", lastsymb);
  1054. display_prompt_and_response(prompt, character);
  1055. tb_present();
  1056. if(execute_kbd_macro) {
  1057. use_kbd_macro(&ev);
  1058. } else if(tb_poll_event(&ev) != TB_OK)
  1059. return;
  1060. if(!ev.mod)
  1061. c = ev.ch;
  1062. else
  1063. c = ev.key;
  1064. if(record_input) {
  1065. record_buffer[record_buffer_index] = ev;
  1066. record_buffer_index++;
  1067. }
  1068. /* Ignore all control keys other than C-g, ESC, and return */
  1069. if (c < 32 && c != TB_KEY_CTRL_G && c != TB_KEY_ESC && c != TB_KEY_ENTER)
  1070. return;
  1071. if(c == TB_KEY_CTRL_G || c == TB_KEY_ESC)
  1072. return;
  1073. else if(c == TB_KEY_ENTER)
  1074. character[0] = lastsymb;
  1075. else
  1076. character[0] = c;
  1077. display_prompt_and_response(prompt, character);
  1078. tb_present();
  1079. }
  1080. if(!(other = is_bracket(character[0], TRUE, &is_start))) {
  1081. return;
  1082. }
  1083. for(;universal_argument > 0; universal_argument--)
  1084. jumptochar();
  1085. adjust_bline();
  1086. universal_argument = 0;
  1087. lastcommand = KBD_DELETE_CHAR;
  1088. if(is_start) {
  1089. curbp->b_point++;
  1090. while (*(p = ptr(curbp, curbp->b_point)) != other && curbp->b_buf < p)
  1091. delete();
  1092. } else {
  1093. while (*(p = ptr(curbp, curbp->b_point - 1)) != other && curbp->b_buf < p)
  1094. backsp();
  1095. }
  1096. lastsymb = character[0];
  1097. character[0] = '\0';
  1098. return;
  1099. }
  1100. /* If in a word delete the word both directions.
  1101. This is the same as doing a `esc f` then `esc backsp`.
  1102. This does not delete the symbols, just the words.
  1103. */
  1104. if(!isspace(*ptr(curbp, curbp->b_point - 1)) &&
  1105. !isspace(*ptr(curbp, curbp->b_point)) &&
  1106. !isspace(*ptr(curbp, curbp->b_point + 1))) {
  1107. wright();
  1108. wleftdelete();
  1109. return;
  1110. }
  1111. lastcommand = KBD_DELETE_CHAR;
  1112. /* Otherwise just delete whitespace */
  1113. while (isspace(*(p = ptr(curbp, curbp->b_point - 1))) && curbp->b_buf < p && *p != '\n')
  1114. backsp();
  1115. if(isspace(*(p = ptr(curbp, curbp->b_point - 1))) && *p != '\n')
  1116. backsp();
  1117. while (isspace(*(p = ptr(curbp, curbp->b_point))) && curbp->b_buf <= p && *p != '\n')
  1118. delete();
  1119. }
  1120. void insertnewlinebelow()
  1121. {
  1122. input[0] = '\n';
  1123. input[1] = '\0';
  1124. undoset(INSERT, FALSE);
  1125. insert();
  1126. curbp->b_point--;
  1127. currentcommand = KBD_DEFAULT;
  1128. }
  1129. void insertnewline()
  1130. {
  1131. point_t point;
  1132. char_t *p, *space = NULL;
  1133. int spaces = 0, i;
  1134. point = segstart(curbp, curwp, lnstart(curbp, curbp->b_point), curbp->b_point);
  1135. while(point < pos(curbp, curbp->b_ebuf) &&
  1136. isspace(*(p = ptr(curbp, point))) &&
  1137. *p != '\n' &&
  1138. curwp->w_col != 0) {
  1139. if(spaces == 0) {
  1140. space = p;
  1141. }
  1142. if(*p != '\n') {
  1143. spaces++;
  1144. point++;
  1145. }
  1146. }
  1147. input[0] = '\n';
  1148. for(i = 0; i < spaces; i++) {
  1149. input[i+1] = *space;
  1150. }
  1151. i++;
  1152. input[i] = '\0';
  1153. insert_str();
  1154. curbp->b_pcol = spaces + curwp->w_left;
  1155. /* this stops the annoying reframing */
  1156. curbp->b_epage += spaces ? spaces : 1;
  1157. currentcommand = KBD_INSERT;
  1158. if((curwp->w_row - curwp->w_top) == curwp->w_rows-1) {
  1159. curbp->b_reframe = TRUE;
  1160. }
  1161. }
  1162. void inserttab()
  1163. {
  1164. input[0] = '\t';
  1165. input[1] = '\0';
  1166. undoset(INSERT, FALSE);
  1167. insert();
  1168. }
  1169. void inserttabasspace()
  1170. {
  1171. memset(input, ' ', TAB_SPACE_SIZE+1);
  1172. input[TAB_SPACE_SIZE] = '\0';
  1173. curbp->b_epage += TAB_SPACE_SIZE;
  1174. insert_str();
  1175. }
  1176. void suspend()
  1177. {
  1178. tb_shutdown();
  1179. raise(SIGTSTP);
  1180. }
  1181. void transpose()
  1182. {
  1183. char_t *cur = ptr(curbp, curbp->b_point);
  1184. char_t *prev = ptr(curbp, curbp->b_point-1);
  1185. char_t replace[3];
  1186. if(cur == curbp->b_ebuf) {
  1187. return;
  1188. }
  1189. point_t mark = curbp->b_mark;
  1190. replace[0] = *cur;
  1191. replace[1] = *prev;
  1192. replace[2] = '\0';
  1193. curbp->b_point--;
  1194. curbp->b_mark = curbp->b_point + 2;
  1195. undoset(REPLACE, 2);
  1196. curbp->b_mark = mark;
  1197. curbp->b_point++;
  1198. memcpy(ptr(curbp, curbp->b_point-1), replace, 2 * sizeof (char_t));
  1199. curbp->b_flags |= B_MODIFIED;
  1200. }
  1201. /* Transpose words and put scrap back to how it was. */
  1202. void transposeword()
  1203. {
  1204. char_t *current_scrap, *p;
  1205. int n_scrap = scrap.len, newlines = 0;
  1206. point_t mark = curbp->b_mark, epoint, point, npoint;
  1207. /* copy the current scrap */
  1208. // current_scrap = (char_t*) malloc(scrap.len);
  1209. // (void) memcpy(current_scrap, scrap.data, scrap.len * sizeof (char_t));
  1210. current_scrap = (char_t *)strndup((const char*)scrap.data, scrap.len);
  1211. /* Find all the key points for the undo */
  1212. wright();
  1213. epoint = curbp->b_point;
  1214. wleft();
  1215. wleft();
  1216. curbp->b_mark = epoint;
  1217. point = curbp->b_point;
  1218. /* Adjust `b_line` to match the line you'll eventually
  1219. be on. This has to happen before the undo so that the
  1220. undo's line tracker keeps it right.
  1221. */
  1222. npoint = point;
  1223. while(npoint < epoint) {
  1224. p = ptr(curbp, npoint);
  1225. if(*p == '\n')
  1226. newlines++;
  1227. npoint++;
  1228. }
  1229. curbp->b_line -= newlines;
  1230. undoset(REPLACE, curbp->b_mark - point);
  1231. /* Cut the word to the left*/
  1232. curbp->b_mark = point;
  1233. curbp->b_point = point;
  1234. wright();
  1235. currentcommand = KBD_CUT;
  1236. copy_cut(TRUE, FALSE, TRUE);
  1237. /* paste the left word */
  1238. right();
  1239. paste_internal(TRUE);
  1240. /* cut the right word */
  1241. curbp->b_mark = curbp->b_point;
  1242. wright();
  1243. currentcommand = KBD_CUT;
  1244. copy_cut(TRUE, FALSE, TRUE);
  1245. wleft();
  1246. /* paste the right word */
  1247. left();
  1248. paste_internal(TRUE);
  1249. /* Put it all back together */
  1250. if (scrap.data != NULL) {
  1251. free(scrap.data);
  1252. scrap.data = NULL;
  1253. }
  1254. scrap.len = n_scrap;
  1255. free(scrap.data);
  1256. scrap.data = NULL;
  1257. // scrap.data = (char_t*) malloc(scrap.len);
  1258. // (void) memcpy(scrap.data, current_scrap, scrap.len * sizeof (char_t));
  1259. scrap.data = (char_t *)strndup((const char*)current_scrap, scrap.len);
  1260. curbp->b_mark = mark;
  1261. }
  1262. void lowercaseword()
  1263. {
  1264. char_t *p, *word;
  1265. point_t sword, eword;
  1266. int olast = lastcommand;
  1267. while ((isspace(*(p = ptr(curbp, curbp->b_point))) || is_symbol(*p)) && p < curbp->b_ebuf)
  1268. ++curbp->b_point;
  1269. sword = curbp->b_point;
  1270. wright();
  1271. eword = curbp->b_point;
  1272. word = (char_t *) malloc(sizeof(char_t)*(eword - sword));
  1273. curbp->b_point = sword;
  1274. lastcommand = KBD_DELETE_CHAR;
  1275. for(int i = sword, k = 0; i < eword; i++, k++) {
  1276. word[k] = *ptr(curbp, curbp->b_point);
  1277. delete();
  1278. }
  1279. lastcommand = olast;
  1280. for(int i = sword, k = 0; i < eword; i++, k++) {
  1281. input[0] = tolower(word[k]);
  1282. input[1] = '\0';
  1283. undoset(INSERT, i != 0);
  1284. insert();
  1285. }
  1286. free(word);
  1287. }
  1288. void capitalizeword()
  1289. {
  1290. char_t *p;
  1291. while (isspace(*(p = ptr(curbp, curbp->b_point))) && p < curbp->b_ebuf)
  1292. ++curbp->b_point;
  1293. p = ptr(curbp, curbp->b_point);
  1294. input[0] = toupper(*p);
  1295. input[1] = '\0';
  1296. delete();
  1297. undoset(INSERT, FALSE);
  1298. insert();
  1299. if(isspace(*(p = ptr(curbp, curbp->b_point+1))) || is_symbol(*p))
  1300. curbp->b_point++;
  1301. else
  1302. wright();
  1303. }
  1304. void uppercaseword()
  1305. {
  1306. char_t *p, *word;
  1307. point_t sword, eword;
  1308. int olast = lastcommand;
  1309. while ((isspace(*(p = ptr(curbp, curbp->b_point))) || is_symbol(*p)) && p < curbp->b_ebuf)
  1310. ++curbp->b_point;
  1311. sword = curbp->b_point;
  1312. wright();
  1313. eword = curbp->b_point;
  1314. word = (char_t *) malloc(sizeof(char_t)*(eword - sword));
  1315. curbp->b_point = sword;
  1316. lastcommand = KBD_DELETE_CHAR;
  1317. for(int i = sword, k = 0; i < eword; i++, k++) {
  1318. word[k] = *ptr(curbp, curbp->b_point);
  1319. delete();
  1320. }
  1321. lastcommand = olast;
  1322. for(int i = sword, k = 0; i < eword; i++, k++) {
  1323. input[0] = toupper(word[k]);
  1324. input[1] = '\0';
  1325. undoset(INSERT, i != 0);
  1326. insert();
  1327. }
  1328. free(word);
  1329. }
  1330. /* type = 0, zap
  1331. type = 1, jump
  1332. */
  1333. /* TODO: Throw error when putting non-char in.
  1334. */
  1335. void gotochar(int type, int include_char)
  1336. {
  1337. char_t *p;
  1338. point_t opoint = curbp->b_point, eol;
  1339. int c, col = 0;
  1340. struct tb_event ev;
  1341. char *promptBeg = type == 0 ? "Zap to Char" : "Jump to Char";
  1342. char *prompt;
  1343. if(lastchar == 0)
  1344. asprintf(&prompt, "%s: ", promptBeg);
  1345. else
  1346. asprintf(&prompt, "%s (default %c): ", promptBeg, lastchar);
  1347. if(character[0] == '\0') {
  1348. display_prompt_and_response(prompt, character);
  1349. tb_present();
  1350. if(execute_kbd_macro) {
  1351. use_kbd_macro(&ev);
  1352. } else if(tb_poll_event(&ev) != TB_OK)
  1353. return;
  1354. if(!ev.mod)
  1355. c = ev.ch;
  1356. else
  1357. c = ev.key;
  1358. if(record_input) {
  1359. record_buffer[record_buffer_index] = ev;
  1360. record_buffer_index++;
  1361. }
  1362. /* Ignore all control keys other than C-g, ESC, and return */
  1363. if (c < 32 &&
  1364. c != TB_KEY_CTRL_G &&
  1365. c != TB_KEY_ESC &&
  1366. c != TB_KEY_CTRL_I &&
  1367. c != TB_KEY_TAB &&
  1368. c != TB_KEY_ENTER)
  1369. return;
  1370. if(c == TB_KEY_CTRL_G || c == TB_KEY_ESC)
  1371. return;
  1372. else if (c == TB_KEY_ENTER)
  1373. character[0] = lastchar;
  1374. else
  1375. character[0] = c;
  1376. display_prompt_and_response(prompt, character);
  1377. tb_present();
  1378. }
  1379. if(type == 0) {
  1380. block();
  1381. }
  1382. if(*ptr(curbp, curbp->b_point) == character[0] || curbp->b_point == 0) {
  1383. if(negated)
  1384. left();
  1385. else
  1386. right();
  1387. }
  1388. while (*(p = ptr(curbp, curbp->b_point + (include_char ? 0 : (negated ? -1 : 1)))) != character[0]) {
  1389. if(negated) {
  1390. if(curbp->b_point == 0)
  1391. break;
  1392. left();
  1393. } else {
  1394. if(p == curbp->b_ebuf)
  1395. break;
  1396. right();
  1397. }
  1398. }
  1399. if(type == 0 && !negated)
  1400. right();
  1401. if(type == 0) {
  1402. currentcommand = KBD_CUT;
  1403. copy_cut(TRUE, FALSE, FALSE);
  1404. }
  1405. tb_set_cursor(0, MSGLINE);
  1406. clrtoeol("", MSGLINE);
  1407. eol = lnstart(curbp, curbp->b_point);
  1408. for(point_t poi = curbp->b_point; poi > eol; poi -= utf8_size(*ptr(curbp,poi)))
  1409. col++;
  1410. curbp->b_pcol = col + curwp->w_left;
  1411. if(p >= ptr(curbp, curbp->b_epage)) {
  1412. curbp->b_reframe = TRUE;
  1413. }
  1414. if((!negated && p >= curbp->b_ebuf) || (negated && curbp->b_point <= 0)) {
  1415. msg("No match found.");
  1416. curbp->b_point = opoint;
  1417. }
  1418. negated = FALSE;
  1419. lastchar = character[0];
  1420. }
  1421. void zaptochar()
  1422. {
  1423. gotochar(0, universal_argument == 0);
  1424. universal_argument = 0;
  1425. }
  1426. void negated_zaptochar()
  1427. {
  1428. negated = TRUE;
  1429. gotochar(0, universal_argument == 0);
  1430. universal_argument = 0;
  1431. }
  1432. void jumptochar()
  1433. {
  1434. shift_pmark(TRUE, curbp->b_point);
  1435. gotochar(1, TRUE);
  1436. shift_pmark(TRUE, curbp->b_point);
  1437. }
  1438. void negated_jumptochar()
  1439. {
  1440. shift_pmark(TRUE, curbp->b_point);
  1441. negated = TRUE;
  1442. gotochar(1, TRUE);
  1443. shift_pmark(TRUE, curbp->b_point);
  1444. }
  1445. void poptomark()
  1446. {
  1447. point_t p;
  1448. if(curbp->b_mark != NOMARK)
  1449. curbp->b_point = curbp->b_mark;
  1450. else if(curbp->b_pmark[0] != NOMARK) {
  1451. p = shift_pmark(FALSE, NOMARK);
  1452. if(p == curbp->b_point) {
  1453. p = shift_pmark(FALSE, NOMARK);
  1454. }
  1455. curbp->b_point = p;
  1456. } else {
  1457. msg("No valid mark to pop to.");
  1458. return;
  1459. }
  1460. if(curbp->b_point < curbp->b_page || curbp->b_point > curbp->b_epage) {
  1461. curbp->b_reframe = TRUE;
  1462. curwp->w_recenter = TRUE;
  1463. }
  1464. }
  1465. void universal_argument_load()
  1466. {
  1467. universal_argument++;
  1468. msg("C-u %d", universal_argument);
  1469. }
  1470. void numeric_argument_load()
  1471. {
  1472. numeric_argument = (numeric_argument * 10) + atoi((const char *)&input_char);
  1473. msg("C-u %d", numeric_argument);
  1474. }
  1475. void back_to_indentation()
  1476. {
  1477. char_t *p;
  1478. while (isspace(*(p = ptr(curbp, curbp->b_point))) && p < curbp->b_ebuf)
  1479. ++curbp->b_point;
  1480. }
  1481. void negate()
  1482. {
  1483. negated = !negated;
  1484. msg("C-u -");
  1485. }
  1486. void forward_bracket()
  1487. {
  1488. point_t p, eol;
  1489. int col = 0;
  1490. if((p = find_matching_bracket(curbp, curwp, 1, FALSE)) >= 0)
  1491. curbp->b_point = curbp->b_mark == NOMARK ? p : p + 1;
  1492. /* Make sure the column memory updates to the new column */
  1493. eol = lnstart(curbp, curbp->b_point);
  1494. for(p = curbp->b_point; p > eol; p -= utf8_size(*ptr(curbp,p)))
  1495. col++;
  1496. curbp->b_pcol = col + curwp->w_left;
  1497. }
  1498. void backward_bracket()
  1499. {
  1500. point_t p, eol;
  1501. int col = 0;
  1502. if((p = find_matching_bracket(curbp, curwp, -1, FALSE)) >= 0) {
  1503. curbp->b_point = p;
  1504. if(curbp->b_mark != NOMARK)
  1505. curbp->b_mark++;
  1506. }
  1507. /* Make sure the column memory updates to the new column */
  1508. eol = lnstart(curbp, curbp->b_point);
  1509. for(p = curbp->b_point; p > eol; p -= utf8_size(*ptr(curbp,p)))
  1510. col++;
  1511. curbp->b_pcol = col + curwp->w_left;
  1512. }
  1513. void start_kbd_macro()
  1514. {
  1515. record_input = TRUE;
  1516. for(int i = 0; i < record_buffer_index; i++) {
  1517. memset(&record_buffer[i], 0, sizeof(record_buffer[i]));
  1518. }
  1519. record_buffer_index = 0;
  1520. msg("Started keyboard macro...");
  1521. }
  1522. void end_kbd_macro()
  1523. {
  1524. record_input = FALSE;
  1525. msg("Ended keyboard macro.");
  1526. }
  1527. void run_kbd_macro()
  1528. {
  1529. if(numeric_argument > 0)
  1530. numeric_argument--;
  1531. /* If you start_kbd_macro and immediately close it, you haven't
  1532. really recorded anything. This shows up as the second value
  1533. being C-x and then 0 in the 3rd.
  1534. */
  1535. if(record_buffer_index == 0 ||
  1536. (record_buffer[1].key == TB_KEY_CTRL_X && record_buffer[2].key == 0)) {
  1537. msg("No recorded keyboard macro.");
  1538. return;
  1539. }
  1540. if(record_input) {
  1541. msg("Currently recording keyboard macro.");
  1542. return;
  1543. }
  1544. execute_kbd_macro = TRUE;
  1545. }
  1546. void open_file_from_shell()
  1547. {
  1548. get_popen_data(1);
  1549. }
  1550. void insert_from_shell()
  1551. {
  1552. get_popen_data(0);
  1553. }
  1554. void control_from_shell()
  1555. {
  1556. get_popen_data(2);
  1557. }
  1558. void insert_control_char()
  1559. {
  1560. struct tb_event ev;
  1561. char *prompt = "Insert Control Char: ";
  1562. display_prompt_and_response(prompt, character);
  1563. tb_present();
  1564. if(execute_kbd_macro) {
  1565. use_kbd_macro(&ev);
  1566. } else if(tb_poll_event(&ev) != TB_OK)
  1567. return;
  1568. if(record_input) {
  1569. record_buffer[record_buffer_index] = ev;
  1570. record_buffer_index++;
  1571. }
  1572. tb_set_cursor(0, MSGLINE);
  1573. clrtoeol("", MSGLINE);
  1574. if(ev.key > 0x1a) {
  1575. return;
  1576. }
  1577. input[0] = (char)ev.key;
  1578. input[1] = '\0';
  1579. undoset(INSERT, lastcommand == KBD_INSERT);
  1580. insert();
  1581. currentcommand = KBD_INSERT;
  1582. ignorenotbound = TRUE;
  1583. }
  1584. void comment_at_eol()
  1585. {
  1586. if(curbp->b_keywords == NULL || curbp->b_keywords->slc == NULL) {
  1587. return;
  1588. }
  1589. lnend();
  1590. inserttabasspace();
  1591. for(int c = 0; curbp->b_keywords->slc[c] != '\0'; c++)
  1592. input[c] = curbp->b_keywords->slc[c];
  1593. input[strlen(curbp->b_keywords->slc)] = ' ';
  1594. input[strlen(curbp->b_keywords->slc)+1] = '\0';
  1595. insert_str();
  1596. }
  1597. int single_line_comment()
  1598. {
  1599. point_t p = curbp->b_point, op = -1;
  1600. int nslc = strlen(curbp->b_keywords->slc);
  1601. int match = FALSE, i = 0;
  1602. char_t* c;
  1603. if(op != -1)
  1604. p = op;
  1605. lnbegin();
  1606. for(i = 0; curbp->b_keywords->slc[i] != '\0'; i++) {
  1607. if(*(c = ptr(curbp, curbp->b_point)) == curbp->b_keywords->slc[i]) {
  1608. match = TRUE;
  1609. } else {
  1610. match = FALSE;
  1611. }
  1612. }
  1613. if(match) {
  1614. for(; i > 0; i--)
  1615. delete();
  1616. delete(); // don't forget the extra space
  1617. return -1 * (nslc + 1);
  1618. }
  1619. for(int c = 0; curbp->b_keywords->slc[c] != '\0'; c++)
  1620. input[c] = curbp->b_keywords->slc[c];
  1621. input[nslc] = ' ';
  1622. input[nslc+1] = '\0';
  1623. insert_str();
  1624. curbp->b_point = p + nslc + 1;
  1625. return nslc + 1;
  1626. }
  1627. void comment()
  1628. {
  1629. point_t p = curbp->b_point, op = -1, mark = curbp->b_mark;
  1630. char_t *c;
  1631. int match = FALSE, i = 0, e = 0, j = 0;
  1632. int oline = curbp->b_line;
  1633. int newline = curbp->b_line, extra = 0;
  1634. if(curbp->b_keywords == NULL || curbp->b_keywords->slc == NULL) {
  1635. return;
  1636. }
  1637. /* multi-line */
  1638. if(mark != NOMARK) {
  1639. if(curbp->b_keywords->mlc != NULL &&
  1640. curbp->b_keywords->emlc != NULL &&
  1641. universal_argument == 0) {
  1642. copy_cut(TRUE, FALSE, FALSE);
  1643. for(j = 0; curbp->b_keywords->mlc[j] != '\0'; j++)
  1644. input[j] = curbp->b_keywords->mlc[j];
  1645. input[j+1] = '\0';
  1646. insert_str();
  1647. extra = j;
  1648. for(j = 0; curbp->b_keywords->emlc[j] != '\0'; j++)
  1649. input[j] = curbp->b_keywords->emlc[j];
  1650. input[j] = '\0';
  1651. insert_str();
  1652. extra += j;
  1653. for(; j > 0; j--)
  1654. left();
  1655. paste_internal(FALSE);
  1656. curbp->b_point = p + extra;
  1657. return;
  1658. } else { // end of multi-line
  1659. /* comment out multiple lines with a single line comment */
  1660. if(mark > curbp->b_point) {
  1661. while(curbp->b_point < mark) {
  1662. int len = single_line_comment();
  1663. extra += len;
  1664. /* the mark point changes as you remove comment symbols */
  1665. mark += len;
  1666. down();
  1667. lnbegin();
  1668. }
  1669. curbp->b_mark = NOMARK;
  1670. return;
  1671. } else {
  1672. curbp->b_point = mark;
  1673. lnbegin();
  1674. mark = curbp->b_point;
  1675. curbp->b_point = p;
  1676. while(curbp->b_point >= mark && curbp->b_point > 0) {
  1677. extra += single_line_comment();
  1678. up();
  1679. lnbegin();
  1680. }
  1681. if(mark == 0) {
  1682. extra += single_line_comment();
  1683. }
  1684. curbp->b_mark = NOMARK;
  1685. curbp->b_point = p + extra;
  1686. return;
  1687. }
  1688. }
  1689. }
  1690. /* Check to see if you're in a multi-line comment.
  1691. If you see the end of a multi-line comment, you know immediately
  1692. that you aren't in one.
  1693. */
  1694. if(curbp->b_keywords->mlc != NULL &&
  1695. curbp->b_keywords->emlc != NULL) {
  1696. op = p;
  1697. for(e = strlen(curbp->b_keywords->emlc) - 1, i = strlen(curbp->b_keywords->mlc) - 1;
  1698. p > 0 && i >= 0 && e >= 0;
  1699. p--) {
  1700. int smatch = *(c = ptr(curbp, p)) == curbp->b_keywords->mlc[i];
  1701. int ematch = *c == curbp->b_keywords->emlc[e];
  1702. if(*c == '\n')
  1703. newline--;
  1704. if(smatch) {
  1705. if(i == 0)
  1706. break;
  1707. i--;
  1708. }
  1709. if(ematch) {
  1710. if(e == 0)
  1711. break;
  1712. e--;
  1713. }
  1714. if(!smatch) {
  1715. i = strlen(curbp->b_keywords->mlc) - 1;
  1716. }
  1717. if(!ematch) {
  1718. e = strlen(curbp->b_keywords->emlc) - 1;
  1719. }
  1720. }
  1721. }
  1722. /* If you're in a multi-line comment, remove it. */
  1723. if(i <= 0 && e > 0) {
  1724. curbp->b_point = p;
  1725. curbp->b_line = newline;
  1726. for(i = strlen(curbp->b_keywords->mlc); i > 0; i--)
  1727. delete();
  1728. match = FALSE;
  1729. for(i = 0; p < pos(curbp, curbp->b_ebuf) && i < strlen(curbp->b_keywords->emlc); p++) {
  1730. if(*(c = ptr(curbp, p)) == curbp->b_keywords->emlc[i]) {
  1731. match = TRUE;
  1732. i++;
  1733. } else {
  1734. match = FALSE;
  1735. }
  1736. if(*c == '\n')
  1737. curbp->b_line++;
  1738. }
  1739. if(match) {
  1740. p -= i;
  1741. curbp->b_point = p;
  1742. for(; i > 0; i--)
  1743. delete();
  1744. }
  1745. curbp->b_point = op - strlen(curbp->b_keywords->mlc);
  1746. curbp->b_line = oline;
  1747. return;
  1748. }
  1749. /* single line */
  1750. if(universal_argument > 0 &&
  1751. curbp->b_keywords->mlc != NULL &&
  1752. curbp->b_keywords->emlc != NULL) {
  1753. j = 0;
  1754. for(; curbp->b_keywords->mlc[j] != '\0'; j++)
  1755. input[j] = curbp->b_keywords->mlc[j];
  1756. input[j+1] = '\0';
  1757. insert_str();
  1758. op = curbp->b_point;
  1759. j = 0;
  1760. for(; curbp->b_keywords->emlc[j] != '\0'; j++)
  1761. input[j] = curbp->b_keywords->emlc[j];
  1762. input[j+1] = '\0';
  1763. insert_str();
  1764. curbp->b_point = op;
  1765. input[0] = ' ';
  1766. input[1] = '\0';
  1767. insert();
  1768. insert();
  1769. left();
  1770. } else
  1771. single_line_comment();
  1772. }
  1773. void dynamically_expand()
  1774. {
  1775. point_t endpoint = pos(curbp, curbp->b_ebuf);
  1776. int i = 0, j = 0;
  1777. char_t *p, result[TEMPBUF];
  1778. dynars_t *dyrs, *dr;
  1779. if ((dyrs = (dynars_t *) malloc (sizeof(dynars_t))) == NULL)
  1780. return;
  1781. p = ptr(curbp, curbp->b_point);
  1782. if(isalpha(*p) || isdigit(*p))
  1783. return;
  1784. if(dynaex.query == NULL) {
  1785. dynaex.end = curbp->b_point;
  1786. dynaex.start = curbp->b_point-1;
  1787. while(isalpha(*(p = ptr(curbp, --dynaex.start))) || isdigit(*p) || *p == '_')
  1788. ;;
  1789. dynaex.sp = dynaex.start;
  1790. dynaex.start++;
  1791. dynaex.nquery = dynaex.end - dynaex.start;
  1792. dynaex.nresult = dynaex.nquery;
  1793. dynaex.query = (char_t *) malloc(dynaex.nquery*sizeof(char_t));
  1794. p = ptr(curbp, dynaex.start);
  1795. memccpy(dynaex.query, p, '\0', dynaex.nquery);
  1796. }
  1797. if(dynaex.results == NULL) {
  1798. dynaex.results = dyrs;
  1799. dynaex.results->result = NULL;
  1800. dynaex.results->d_next = NULL;
  1801. }
  1802. restart:
  1803. i = dynaex.nquery-1;
  1804. j = i;
  1805. int dir = -1;
  1806. point_t match = 0;
  1807. while (!(dynaex.sp >= dynaex.start && dynaex.sp <= dynaex.end)) {
  1808. if(dynaex.sp == -1) {
  1809. dynaex.sp = endpoint;
  1810. }
  1811. p = ptr(curbp, dynaex.sp);
  1812. if(i == -1) {
  1813. if(!isalpha(*p) && !isdigit(*p) && *p != '_') {
  1814. dynaex.sp = match;
  1815. break;
  1816. }
  1817. result[j] = *p;
  1818. result[++j] = '\0';
  1819. } else if(*p == dynaex.query[i]) {
  1820. result[j] = dynaex.query[i];
  1821. i--;
  1822. j--;
  1823. if(i == -1) {
  1824. if(dynaex.sp == 0 || (!isalpha(*ptr(curbp, dynaex.sp-1)) &&
  1825. !isdigit(*ptr(curbp, dynaex.sp-1)))) {
  1826. j = dynaex.nquery;
  1827. dir = 1;
  1828. match = dynaex.sp;
  1829. dynaex.sp += dynaex.nquery - 1;
  1830. } else {
  1831. i = dynaex.nquery-1;
  1832. j = i;
  1833. dir = -1;
  1834. }
  1835. }
  1836. } else if(i >= 0) {
  1837. i = dynaex.nquery-1;
  1838. j = i;
  1839. dir = -1;
  1840. }
  1841. dynaex.sp += dir;
  1842. }
  1843. currentcommand = KBD_EXPAND;
  1844. if(dynaex.sp >= dynaex.start && dynaex.sp <= dynaex.end) {
  1845. msg("No dynamic expansion for \"%s\" found.", dynaex.query);
  1846. /* Free the struct so we can loop again */
  1847. dynaex.sp = dynaex.start - 1;
  1848. dr = dynaex.results;
  1849. while(dynaex.results != NULL) {
  1850. dr = dynaex.results;
  1851. dynaex.results = dynaex.results->d_next;
  1852. if(dr->result != NULL) {
  1853. free(dr->result);
  1854. dr->result = NULL;
  1855. }
  1856. if(dr != NULL) {
  1857. free(dr);
  1858. dr = NULL;
  1859. }
  1860. }
  1861. return;
  1862. }
  1863. /* Check if the match has been used before, if so, skip it. */
  1864. for(dr = dynaex.results; dr != NULL && dr->result != NULL; dr = dr->d_next) {
  1865. int k = 0;
  1866. for(; dr->result[k] != '\0'; k++) {
  1867. if(dr->result[k] != result[k])
  1868. break;
  1869. }
  1870. if(dr->result[k] == '\0' && result[k] == '\0') {
  1871. i = 0;
  1872. j = 0;
  1873. goto restart;
  1874. }
  1875. }
  1876. curbp->b_point = dynaex.start;
  1877. point_t end = dynaex.start + dynaex.nresult;
  1878. curbp->b_mark = end;
  1879. undoset(REPLACE, j);
  1880. curbp->b_mark = NOMARK;
  1881. if (j > dynaex.nresult) {
  1882. movegap(curbp, end);
  1883. /*check enough space in gap left */
  1884. if (j - dynaex.nresult < curbp->b_egap - curbp->b_gap)
  1885. growgap(curbp, j - dynaex.nresult);
  1886. /* shrink gap right by r - s */
  1887. curbp->b_gap = curbp->b_gap + (j - dynaex.nresult);
  1888. } else if (dynaex.nresult > j) {
  1889. movegap(curbp, end);
  1890. /* stretch gap left by s - r, no need to worry about space */
  1891. curbp->b_gap = curbp->b_gap - (dynaex.nresult - j);
  1892. } else {
  1893. /* if rlen = slen, we just overwrite the chars, no need to move gap */
  1894. }
  1895. /* now just overwrite the chars at point in the buffer */
  1896. memcpy(ptr(curbp, curbp->b_point), result, j * sizeof (char_t));
  1897. curbp->b_flags |= B_MODIFIED;
  1898. curbp->b_point = end + (j - dynaex.nresult);
  1899. dynaex.nresult = j;
  1900. /* Add the match to the matched list */
  1901. if(dynaex.results->result == NULL) {
  1902. dynaex.results->result = malloc(j*sizeof(char_t));
  1903. memccpy(dynaex.results->result, result, '\0', j);
  1904. } else {
  1905. dyrs->result = malloc(j*sizeof(char_t));
  1906. memccpy(dyrs->result, result, '\0', j);
  1907. dyrs->d_next = NULL;
  1908. for(dr = dynaex.results; dr->d_next != NULL; dr = dr->d_next)
  1909. ;;
  1910. dr->d_next = dyrs;
  1911. }
  1912. }