PageRenderTime 71ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/basic.c

https://github.com/snaewe/uemacs
C | 491 lines | 318 code | 49 blank | 124 comment | 107 complexity | 38d3a92082d24e7f4acb7ed48d8f4679 MD5 | raw file
  1. /* basic.c
  2. *
  3. * The routines in this file move the cursor around on the screen. They
  4. * compute a new value for the cursor, then adjust ".". The display code
  5. * always updates the cursor location, so only moves between lines, or
  6. * functions that adjust the top line in the window and invalidate the
  7. * framing, are hard.
  8. *
  9. * modified by Petri Kutvonen
  10. */
  11. #include <stdio.h>
  12. #include "estruct.h"
  13. #include "edef.h"
  14. #include "efunc.h"
  15. #include "line.h"
  16. #include "utf8.h"
  17. /*
  18. * This routine, given a pointer to a struct line, and the current cursor goal
  19. * column, return the best choice for the offset. The offset is returned.
  20. * Used by "C-N" and "C-P".
  21. */
  22. static int getgoal(struct line *dlp)
  23. {
  24. int col;
  25. int newcol;
  26. int dbo;
  27. int len = llength(dlp);
  28. col = 0;
  29. dbo = 0;
  30. while (dbo != len) {
  31. unicode_t c;
  32. int width = utf8_to_unicode(dlp->l_text, dbo, len, &c);
  33. newcol = col;
  34. /* Take tabs, ^X and \xx hex characters into account */
  35. if (c == '\t')
  36. newcol |= tabmask;
  37. else if (c < 0x20 || c == 0x7F)
  38. ++newcol;
  39. else if (c >= 0x80 && c <= 0xa0)
  40. newcol += 2;
  41. ++newcol;
  42. if (newcol > curgoal)
  43. break;
  44. col = newcol;
  45. dbo += width;
  46. }
  47. return dbo;
  48. }
  49. /*
  50. * Move the cursor to the beginning of the current line.
  51. */
  52. int gotobol(int f, int n)
  53. {
  54. curwp->w_doto = 0;
  55. return TRUE;
  56. }
  57. /*
  58. * Move the cursor backwards by "n" characters. If "n" is less than zero call
  59. * "forwchar" to actually do the move. Otherwise compute the new cursor
  60. * location. Error if you try and move out of the buffer. Set the flag if the
  61. * line pointer for dot changes.
  62. */
  63. int backchar(int f, int n)
  64. {
  65. struct line *lp;
  66. if (n < 0)
  67. return forwchar(f, -n);
  68. while (n--) {
  69. if (curwp->w_doto == 0) {
  70. if ((lp = lback(curwp->w_dotp)) == curbp->b_linep)
  71. return FALSE;
  72. curwp->w_dotp = lp;
  73. curwp->w_doto = llength(lp);
  74. curwp->w_flag |= WFMOVE;
  75. } else {
  76. do {
  77. unsigned char c;
  78. curwp->w_doto--;
  79. c = lgetc(curwp->w_dotp, curwp->w_doto);
  80. if (is_beginning_utf8(c))
  81. break;
  82. } while (curwp->w_doto);
  83. }
  84. }
  85. return TRUE;
  86. }
  87. /*
  88. * Move the cursor to the end of the current line. Trivial. No errors.
  89. */
  90. int gotoeol(int f, int n)
  91. {
  92. curwp->w_doto = llength(curwp->w_dotp);
  93. return TRUE;
  94. }
  95. /*
  96. * Move the cursor forwards by "n" characters. If "n" is less than zero call
  97. * "backchar" to actually do the move. Otherwise compute the new cursor
  98. * location, and move ".". Error if you try and move off the end of the
  99. * buffer. Set the flag if the line pointer for dot changes.
  100. */
  101. int forwchar(int f, int n)
  102. {
  103. if (n < 0)
  104. return backchar(f, -n);
  105. while (n--) {
  106. int len = llength(curwp->w_dotp);
  107. if (curwp->w_doto == len) {
  108. if (curwp->w_dotp == curbp->b_linep)
  109. return FALSE;
  110. curwp->w_dotp = lforw(curwp->w_dotp);
  111. curwp->w_doto = 0;
  112. curwp->w_flag |= WFMOVE;
  113. } else {
  114. do {
  115. unsigned char c;
  116. curwp->w_doto++;
  117. c = lgetc(curwp->w_dotp, curwp->w_doto);
  118. if (is_beginning_utf8(c))
  119. break;
  120. } while (curwp->w_doto < len);
  121. }
  122. }
  123. return TRUE;
  124. }
  125. /*
  126. * Move to a particular line.
  127. *
  128. * @n: The specified line position at the current buffer.
  129. */
  130. int gotoline(int f, int n)
  131. {
  132. int status;
  133. char arg[NSTRING]; /* Buffer to hold argument. */
  134. /* Get an argument if one doesnt exist. */
  135. if (f == FALSE) {
  136. if ((status =
  137. mlreply("Line to GOTO: ", arg, NSTRING)) != TRUE) {
  138. mlwrite("(Aborted)");
  139. return status;
  140. }
  141. n = atoi(arg);
  142. }
  143. /* Handle the case where the user may be passed something like this:
  144. * em filename +
  145. * In this case we just go to the end of the buffer.
  146. */
  147. if (n == 0)
  148. return gotoeob(f, n);
  149. /* If a bogus argument was passed, then returns false. */
  150. if (n < 0)
  151. return FALSE;
  152. /* First, we go to the begin of the buffer. */
  153. gotobob(f, n);
  154. return forwline(f, n - 1);
  155. }
  156. /*
  157. * Goto the beginning of the buffer. Massive adjustment of dot. This is
  158. * considered to be hard motion; it really isn't if the original value of dot
  159. * is the same as the new value of dot. Normally bound to "M-<".
  160. */
  161. int gotobob(int f, int n)
  162. {
  163. curwp->w_dotp = lforw(curbp->b_linep);
  164. curwp->w_doto = 0;
  165. curwp->w_flag |= WFHARD;
  166. return TRUE;
  167. }
  168. /*
  169. * Move to the end of the buffer. Dot is always put at the end of the file
  170. * (ZJ). The standard screen code does most of the hard parts of update.
  171. * Bound to "M->".
  172. */
  173. int gotoeob(int f, int n)
  174. {
  175. curwp->w_dotp = curbp->b_linep;
  176. curwp->w_doto = 0;
  177. curwp->w_flag |= WFHARD;
  178. return TRUE;
  179. }
  180. /*
  181. * Move forward by full lines. If the number of lines to move is less than
  182. * zero, call the backward line function to actually do it. The last command
  183. * controls how the goal column is set. Bound to "C-N". No errors are
  184. * possible.
  185. */
  186. int forwline(int f, int n)
  187. {
  188. struct line *dlp;
  189. if (n < 0)
  190. return backline(f, -n);
  191. /* if we are on the last line as we start....fail the command */
  192. if (curwp->w_dotp == curbp->b_linep)
  193. return FALSE;
  194. /* if the last command was not note a line move,
  195. reset the goal column */
  196. if ((lastflag & CFCPCN) == 0)
  197. curgoal = getccol(FALSE);
  198. /* flag this command as a line move */
  199. thisflag |= CFCPCN;
  200. /* and move the point down */
  201. dlp = curwp->w_dotp;
  202. while (n-- && dlp != curbp->b_linep)
  203. dlp = lforw(dlp);
  204. /* reseting the current position */
  205. curwp->w_dotp = dlp;
  206. curwp->w_doto = getgoal(dlp);
  207. curwp->w_flag |= WFMOVE;
  208. return TRUE;
  209. }
  210. /*
  211. * This function is like "forwline", but goes backwards. The scheme is exactly
  212. * the same. Check for arguments that are less than zero and call your
  213. * alternate. Figure out the new line and call "movedot" to perform the
  214. * motion. No errors are possible. Bound to "C-P".
  215. */
  216. int backline(int f, int n)
  217. {
  218. struct line *dlp;
  219. if (n < 0)
  220. return forwline(f, -n);
  221. /* if we are on the last line as we start....fail the command */
  222. if (lback(curwp->w_dotp) == curbp->b_linep)
  223. return FALSE;
  224. /* if the last command was not note a line move,
  225. reset the goal column */
  226. if ((lastflag & CFCPCN) == 0)
  227. curgoal = getccol(FALSE);
  228. /* flag this command as a line move */
  229. thisflag |= CFCPCN;
  230. /* and move the point up */
  231. dlp = curwp->w_dotp;
  232. while (n-- && lback(dlp) != curbp->b_linep)
  233. dlp = lback(dlp);
  234. /* reseting the current position */
  235. curwp->w_dotp = dlp;
  236. curwp->w_doto = getgoal(dlp);
  237. curwp->w_flag |= WFMOVE;
  238. return TRUE;
  239. }
  240. #if WORDPRO
  241. /*
  242. * go back to the beginning of the current paragraph
  243. * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
  244. * combination to delimit the beginning of a paragraph
  245. *
  246. * int f, n; default Flag & Numeric argument
  247. */
  248. int gotobop(int f, int n)
  249. {
  250. int suc; /* success of last backchar */
  251. if (n < 0) /* the other way... */
  252. return gotoeop(f, -n);
  253. while (n-- > 0) { /* for each one asked for */
  254. /* first scan back until we are in a word */
  255. suc = backchar(FALSE, 1);
  256. while (!inword() && suc)
  257. suc = backchar(FALSE, 1);
  258. curwp->w_doto = 0; /* and go to the B-O-Line */
  259. /* and scan back until we hit a <NL><NL> or <NL><TAB>
  260. or a <NL><SPACE> */
  261. while (lback(curwp->w_dotp) != curbp->b_linep)
  262. if (llength(curwp->w_dotp) != 0 &&
  263. #if PKCODE
  264. ((justflag == TRUE) ||
  265. #endif
  266. (lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
  267. lgetc(curwp->w_dotp, curwp->w_doto) != ' '))
  268. #if PKCODE
  269. )
  270. #endif
  271. curwp->w_dotp = lback(curwp->w_dotp);
  272. else
  273. break;
  274. /* and then forward until we are in a word */
  275. suc = forwchar(FALSE, 1);
  276. while (suc && !inword())
  277. suc = forwchar(FALSE, 1);
  278. }
  279. curwp->w_flag |= WFMOVE; /* force screen update */
  280. return TRUE;
  281. }
  282. /*
  283. * Go forword to the end of the current paragraph
  284. * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
  285. * combination to delimit the beginning of a paragraph
  286. *
  287. * int f, n; default Flag & Numeric argument
  288. */
  289. int gotoeop(int f, int n)
  290. {
  291. int suc; /* success of last backchar */
  292. if (n < 0) /* the other way... */
  293. return gotobop(f, -n);
  294. while (n-- > 0) { /* for each one asked for */
  295. /* first scan forward until we are in a word */
  296. suc = forwchar(FALSE, 1);
  297. while (!inword() && suc)
  298. suc = forwchar(FALSE, 1);
  299. curwp->w_doto = 0; /* and go to the B-O-Line */
  300. if (suc) /* of next line if not at EOF */
  301. curwp->w_dotp = lforw(curwp->w_dotp);
  302. /* and scan forword until we hit a <NL><NL> or <NL><TAB>
  303. or a <NL><SPACE> */
  304. while (curwp->w_dotp != curbp->b_linep) {
  305. if (llength(curwp->w_dotp) != 0 &&
  306. #if PKCODE
  307. ((justflag == TRUE) ||
  308. #endif
  309. (lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
  310. lgetc(curwp->w_dotp, curwp->w_doto) != ' '))
  311. #if PKCODE
  312. )
  313. #endif
  314. curwp->w_dotp = lforw(curwp->w_dotp);
  315. else
  316. break;
  317. }
  318. /* and then backward until we are in a word */
  319. suc = backchar(FALSE, 1);
  320. while (suc && !inword()) {
  321. suc = backchar(FALSE, 1);
  322. }
  323. curwp->w_doto = llength(curwp->w_dotp); /* and to the EOL */
  324. }
  325. curwp->w_flag |= WFMOVE; /* force screen update */
  326. return TRUE;
  327. }
  328. #endif
  329. /*
  330. * Scroll forward by a specified number of lines, or by a full page if no
  331. * argument. Bound to "C-V". The "2" in the arithmetic on the window size is
  332. * the overlap; this value is the default overlap value in ITS EMACS. Because
  333. * this zaps the top line in the display window, we have to do a hard update.
  334. */
  335. int forwpage(int f, int n)
  336. {
  337. struct line *lp;
  338. if (f == FALSE) {
  339. #if SCROLLCODE
  340. if (term.t_scroll != NULL)
  341. if (overlap == 0)
  342. n = curwp->w_ntrows / 3 * 2;
  343. else
  344. n = curwp->w_ntrows - overlap;
  345. else
  346. #endif
  347. n = curwp->w_ntrows - 2; /* Default scroll. */
  348. if (n <= 0) /* Forget the overlap. */
  349. n = 1; /* If tiny window. */
  350. } else if (n < 0)
  351. return backpage(f, -n);
  352. #if CVMVAS
  353. else /* Convert from pages. */
  354. n *= curwp->w_ntrows; /* To lines. */
  355. #endif
  356. lp = curwp->w_linep;
  357. while (n-- && lp != curbp->b_linep)
  358. lp = lforw(lp);
  359. curwp->w_linep = lp;
  360. curwp->w_dotp = lp;
  361. curwp->w_doto = 0;
  362. #if SCROLLCODE
  363. curwp->w_flag |= WFHARD | WFKILLS;
  364. #else
  365. curwp->w_flag |= WFHARD;
  366. #endif
  367. return TRUE;
  368. }
  369. /*
  370. * This command is like "forwpage", but it goes backwards. The "2", like
  371. * above, is the overlap between the two windows. The value is from the ITS
  372. * EMACS manual. Bound to "M-V". We do a hard update for exactly the same
  373. * reason.
  374. */
  375. int backpage(int f, int n)
  376. {
  377. struct line *lp;
  378. if (f == FALSE) {
  379. #if SCROLLCODE
  380. if (term.t_scroll != NULL)
  381. if (overlap == 0)
  382. n = curwp->w_ntrows / 3 * 2;
  383. else
  384. n = curwp->w_ntrows - overlap;
  385. else
  386. #endif
  387. n = curwp->w_ntrows - 2; /* Default scroll. */
  388. if (n <= 0) /* Don't blow up if the. */
  389. n = 1; /* Window is tiny. */
  390. } else if (n < 0)
  391. return forwpage(f, -n);
  392. #if CVMVAS
  393. else /* Convert from pages. */
  394. n *= curwp->w_ntrows; /* To lines. */
  395. #endif
  396. lp = curwp->w_linep;
  397. while (n-- && lback(lp) != curbp->b_linep)
  398. lp = lback(lp);
  399. curwp->w_linep = lp;
  400. curwp->w_dotp = lp;
  401. curwp->w_doto = 0;
  402. #if SCROLLCODE
  403. curwp->w_flag |= WFHARD | WFINS;
  404. #else
  405. curwp->w_flag |= WFHARD;
  406. #endif
  407. return TRUE;
  408. }
  409. /*
  410. * Set the mark in the current window to the value of "." in the window. No
  411. * errors are possible. Bound to "M-.".
  412. */
  413. int setmark(int f, int n)
  414. {
  415. curwp->w_markp = curwp->w_dotp;
  416. curwp->w_marko = curwp->w_doto;
  417. mlwrite("(Mark set)");
  418. return TRUE;
  419. }
  420. /*
  421. * Swap the values of "." and "mark" in the current window. This is pretty
  422. * easy, bacause all of the hard work gets done by the standard routine
  423. * that moves the mark about. The only possible error is "no mark". Bound to
  424. * "C-X C-X".
  425. */
  426. int swapmark(int f, int n)
  427. {
  428. struct line *odotp;
  429. int odoto;
  430. if (curwp->w_markp == NULL) {
  431. mlwrite("No mark in this window");
  432. return FALSE;
  433. }
  434. odotp = curwp->w_dotp;
  435. odoto = curwp->w_doto;
  436. curwp->w_dotp = curwp->w_markp;
  437. curwp->w_doto = curwp->w_marko;
  438. curwp->w_markp = odotp;
  439. curwp->w_marko = odoto;
  440. curwp->w_flag |= WFMOVE;
  441. return TRUE;
  442. }