Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

382 lines
11 KiB

  1. /*
  2. * The main edit loop as well as some other simple cursor movement routines.
  3. */
  4. #include "stevie.h"
  5. /*
  6. * This flag is used to make auto-indent work right on lines where only
  7. * a <RETURN> or <ESC> is typed. It is set when an auto-indent is done,
  8. * and reset when any other editting is done on the line. If an <ESC>
  9. * or <RETURN> is received, and did_ai is TRUE, the line is truncated.
  10. */
  11. bool_t did_ai = FALSE;
  12. void
  13. edit()
  14. {
  15. extern bool_t need_redraw;
  16. int c;
  17. register char *p, *q;
  18. Prenum = 0;
  19. /* position the display and the cursor at the top of the file. */
  20. *Topchar = *Filemem;
  21. *Curschar = *Filemem;
  22. Cursrow = Curscol = 0;
  23. do_mlines(); /* check for mode lines before starting */
  24. updatescreen();
  25. for ( ;; ) {
  26. /* Figure out where the cursor is based on Curschar. */
  27. cursupdate();
  28. if (need_redraw && !anyinput()) {
  29. updatescreen();
  30. need_redraw = FALSE;
  31. }
  32. if (!anyinput())
  33. windgoto(Cursrow,Curscol);
  34. c = vgetc();
  35. if (State == NORMAL) {
  36. /* We're in the normal (non-insert) mode. */
  37. /* Pick up any leading digits and compute 'Prenum' */
  38. if ( (Prenum>0 && isdigit(c)) || (isdigit(c) && c!='0') ){
  39. Prenum = Prenum*10 + (c-'0');
  40. continue;
  41. }
  42. /* execute the command */
  43. normal(c);
  44. Prenum = 0;
  45. } else {
  46. /*
  47. * Insert or Replace mode.
  48. */
  49. switch (c) {
  50. case ESC: /* an escape ends input mode */
  51. /*
  52. * If we just did an auto-indent, truncate the
  53. * line, and put the cursor back.
  54. */
  55. if (did_ai) {
  56. Curschar->linep->s[0] = NUL;
  57. Curschar->index = 0;
  58. did_ai = FALSE;
  59. }
  60. set_want_col = TRUE;
  61. /* Don't end up on a '\n' if you can help it. */
  62. if (gchar(Curschar) == NUL && Curschar->index != 0)
  63. dec(Curschar);
  64. /*
  65. * The cursor should end up on the last inserted
  66. * character. This is an attempt to match the real
  67. * 'vi', but it may not be quite right yet.
  68. */
  69. if (Curschar->index != 0 && !endofline(Curschar))
  70. dec(Curschar);
  71. State = NORMAL;
  72. msg("");
  73. /* construct the Redo buffer */
  74. p = ralloc(Redobuff,
  75. Ninsert+2 < REDOBUFFMIN
  76. ? REDOBUFFMIN : Ninsert+2);
  77. if(p == NULL) {
  78. msg("Insufficient memory -- command not saved for redo");
  79. } else {
  80. Redobuff=p;
  81. q=Insbuff;
  82. while ( q < Insptr )
  83. *p++ = *q++;
  84. *p++ = ESC;
  85. *p = NUL;
  86. }
  87. updatescreen();
  88. break;
  89. case CTRL('D'):
  90. /*
  91. * Control-D is treated as a backspace in insert
  92. * mode to make auto-indent easier. This isn't
  93. * completely compatible with vi, but it's a lot
  94. * easier than doing it exactly right, and the
  95. * difference isn't very noticeable.
  96. */
  97. case BS:
  98. /* can't backup past starting point */
  99. if (Curschar->linep == Insstart->linep &&
  100. Curschar->index <= Insstart->index) {
  101. beep();
  102. break;
  103. }
  104. /* can't backup to a previous line */
  105. if (Curschar->linep != Insstart->linep &&
  106. Curschar->index <= 0) {
  107. beep();
  108. break;
  109. }
  110. did_ai = FALSE;
  111. dec(Curschar);
  112. if (State == INSERT)
  113. delchar(TRUE);
  114. /*
  115. * It's a little strange to put backspaces into
  116. * the redo buffer, but it makes auto-indent a
  117. * lot easier to deal with.
  118. */
  119. insertchar(BS);
  120. cursupdate();
  121. updateline();
  122. break;
  123. case CR:
  124. case NL:
  125. insertchar(NL);
  126. opencmd(FORWARD, TRUE); /* open a new line */
  127. break;
  128. case TAB:
  129. if (!P(P_HT)) {
  130. /* fake TAB with spaces */
  131. int i = P(P_TS) - (Curscol % P(P_TS));
  132. did_ai = FALSE;
  133. while (i--) {
  134. inschar(' ');
  135. insertchar(' ');
  136. }
  137. updateline();
  138. break;
  139. }
  140. /* else fall through to normal case */
  141. default:
  142. did_ai = FALSE;
  143. inschar(c);
  144. insertchar(c);
  145. updateline();
  146. break;
  147. }
  148. }
  149. }
  150. }
  151. void
  152. insertchar(c)
  153. int c;
  154. {
  155. char *p;
  156. *Insptr++ = (char)c;
  157. Ninsert++;
  158. if(Ninsert == InsbuffSize) { // buffer is full -- enlarge it
  159. if((p = ralloc(Insbuff,InsbuffSize+INSERTSLOP)) != NULL) {
  160. Insptr += p - Insbuff;
  161. Insbuff = p;
  162. InsbuffSize += INSERTSLOP;
  163. } else { // could not get bigger buffer
  164. stuffin(mkstr(ESC)); // just end insert mode
  165. }
  166. }
  167. }
  168. void
  169. getout()
  170. {
  171. windgoto(Rows-1,0);
  172. //putchar('\r');
  173. putchar('\n');
  174. windexit(0);
  175. }
  176. void
  177. scrolldown(nlines)
  178. int nlines;
  179. {
  180. register LNPTR *p;
  181. register int done = 0; /* total # of physical lines done */
  182. /* Scroll up 'nlines' lines. */
  183. while (nlines--) {
  184. if ((p = prevline(Topchar)) == NULL)
  185. break;
  186. done += plines(p);
  187. *Topchar = *p;
  188. /*
  189. * If the cursor is on the bottom line, we need to
  190. * make sure it gets moved up the appropriate number
  191. * of lines so it stays on the screen.
  192. */
  193. if (Curschar->linep == Botchar->linep->prev) {
  194. int i = 0;
  195. while (i < done) {
  196. i += plines(Curschar);
  197. *Curschar = *prevline(Curschar);
  198. }
  199. }
  200. }
  201. s_ins(0, done);
  202. }
  203. void
  204. scrollup(nlines)
  205. int nlines;
  206. {
  207. register LNPTR *p;
  208. register int done = 0; /* total # of physical lines done */
  209. register int pl; /* # of plines for the current line */
  210. /* Scroll down 'nlines' lines. */
  211. while (nlines--) {
  212. pl = plines(Topchar);
  213. if ((p = nextline(Topchar)) == NULL)
  214. break;
  215. done += pl;
  216. if (Curschar->linep == Topchar->linep)
  217. *Curschar = *p;
  218. *Topchar = *p;
  219. }
  220. s_del(0, done);
  221. }
  222. /*
  223. * oneright
  224. * oneleft
  225. * onedown
  226. * oneup
  227. *
  228. * Move one char {right,left,down,up}. Return TRUE when
  229. * sucessful, FALSE when we hit a boundary (of a line, or the file).
  230. */
  231. bool_t
  232. oneright()
  233. {
  234. set_want_col = TRUE;
  235. switch (inc(Curschar)) {
  236. case 0:
  237. return TRUE;
  238. case 1:
  239. dec(Curschar); /* crossed a line, so back up */
  240. /* fall through */
  241. case -1:
  242. return FALSE;
  243. DEFAULT_UNREACHABLE;
  244. }
  245. /*NOTREACHED*/
  246. }
  247. bool_t
  248. oneleft()
  249. {
  250. set_want_col = TRUE;
  251. switch (dec(Curschar)) {
  252. case 0:
  253. return TRUE;
  254. case 1:
  255. inc(Curschar); /* crossed a line, so back up */
  256. /* fall through */
  257. case -1:
  258. return FALSE;
  259. DEFAULT_UNREACHABLE;
  260. }
  261. /*NOTREACHED*/
  262. }
  263. void
  264. beginline(flag)
  265. bool_t flag;
  266. {
  267. while ( oneleft() )
  268. ;
  269. if (flag) {
  270. while (isspace(gchar(Curschar)) && oneright())
  271. ;
  272. }
  273. set_want_col = TRUE;
  274. }
  275. bool_t
  276. oneup(n)
  277. int n;
  278. {
  279. LNPTR p, *np;
  280. register int k;
  281. p = *Curschar;
  282. for ( k=0; k<n; k++ ) {
  283. /* Look for the previous line */
  284. if ( (np=prevline(&p)) == NULL ) {
  285. /* If we've at least backed up a little .. */
  286. if ( k > 0 )
  287. break; /* to update the cursor, etc. */
  288. else
  289. return FALSE;
  290. }
  291. p = *np;
  292. }
  293. *Curschar = p;
  294. /* This makes sure Topchar gets updated so the complete line */
  295. /* is one the screen. */
  296. cursupdate();
  297. /* try to advance to the column we want to be at */
  298. *Curschar = *coladvance(&p, Curswant);
  299. return TRUE;
  300. }
  301. bool_t
  302. onedown(n)
  303. int n;
  304. {
  305. LNPTR p, *np;
  306. register int k;
  307. p = *Curschar;
  308. for ( k=0; k<n; k++ ) {
  309. /* Look for the next line */
  310. if ( (np=nextline(&p)) == NULL ) {
  311. if ( k > 0 )
  312. break;
  313. else
  314. return FALSE;
  315. }
  316. p = *np;
  317. }
  318. /* try to advance to the column we want to be at */
  319. *Curschar = *coladvance(&p, Curswant);
  320. return TRUE;
  321. }