unstack, sort: cleanup and improvement
[minix.git] / commands / elvis / move1.c
blobf57ab9a0a7ce81e3d805d4c8e2028b4fe5ed3725
1 /* move1.c */
3 /* Author:
4 * Steve Kirkendall
5 * 14407 SW Teal Blvd. #C
6 * Beaverton, OR 97005
7 * kirkenda@cs.pdx.edu
8 */
11 /* This file contains most movement functions */
13 #include "config.h"
14 #include "vi.h"
15 #include "ctype.h"
17 MARK m_updnto(m, cnt, cmd)
18 MARK m; /* movement is relative to this mark */
19 long cnt; /* a numeric argument */
20 char cmd; /* the command character */
22 DEFAULT(cmd == 'G' ? nlines : 1L);
24 /* move up or down 'cnt' lines */
25 switch (cmd)
27 case ctrl('P'):
28 case '-':
29 case 'k':
30 m -= MARK_AT_LINE(cnt);
31 break;
33 case 'G':
34 if (cnt < 1L || cnt > nlines)
36 msg("Only %ld lines", nlines);
37 return MARK_UNSET;
39 m = MARK_AT_LINE(cnt);
40 break;
42 case '_':
43 cnt--;
44 /* fall through... */
46 default:
47 m += MARK_AT_LINE(cnt);
50 /* if that left us screwed up, then fail */
51 if (m < MARK_FIRST || markline(m) > nlines)
53 return MARK_UNSET;
56 return m;
59 /*ARGSUSED*/
60 MARK m_right(m, cnt, key, prevkey)
61 MARK m; /* movement is relative to this mark */
62 long cnt; /* a numeric argument */
63 int key; /* movement keystroke */
64 int prevkey;/* operator keystroke, or 0 if none */
66 int idx; /* index of the new cursor position */
68 DEFAULT(1);
70 /* If used with an operator, then move 1 less character, since the 'l'
71 * command includes the character that it moves onto.
73 if (prevkey != '\0')
75 cnt--;
78 /* move to right, if that's OK */
79 pfetch(markline(m));
80 idx = markidx(m) + cnt;
81 if (idx < plen)
83 m += cnt;
85 else
87 return MARK_UNSET;
90 return m;
93 /*ARGSUSED*/
94 MARK m_left(m, cnt)
95 MARK m; /* movement is relative to this mark */
96 long cnt; /* a numeric argument */
98 DEFAULT(1);
100 /* move to the left, if that's OK */
101 if (markidx(m) >= cnt)
103 m -= cnt;
105 else
107 return MARK_UNSET;
110 return m;
113 /*ARGSUSED*/
114 MARK m_tocol(m, cnt, cmd)
115 MARK m; /* movement is relative to this mark */
116 long cnt; /* a numeric argument */
117 int cmd; /* either ctrl('X') or '|' */
119 char *text; /* text of the line */
120 int col; /* column number */
121 int idx; /* index into the line */
124 /* if doing ^X, then adjust for sideways scrolling */
125 if (cmd == ctrl('X'))
127 DEFAULT(*o_columns & 0xff);
128 cnt += leftcol;
130 else
132 DEFAULT(1);
135 /* internally, columns are numbered 0..COLS-1, not 1..COLS */
136 cnt--;
138 /* if 0, that's easy */
139 if (cnt == 0)
141 m &= ~(BLKSIZE - 1);
142 return m;
145 /* find that column within the line */
146 pfetch(markline(m));
147 text = ptext;
148 for (col = idx = 0; col < cnt && *text; text++, idx++)
150 if (*text == '\t' && !*o_list)
152 col += *o_tabstop;
153 col -= col % *o_tabstop;
155 else if (UCHAR(*text) < ' ' || *text == '\177')
157 col += 2;
159 #ifndef NO_CHARATTR
160 else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr)
162 text += 2; /* plus one more as part of for loop */
164 #endif
165 else
167 col++;
170 if (!*text)
172 /* the desired column was past the end of the line, so
173 * act like the user pressed "$" instead.
175 return m | (BLKSIZE - 1);
177 else
179 m = (m & ~(BLKSIZE - 1)) + idx;
181 return m;
184 /*ARGSUSED*/
185 MARK m_front(m, cnt)
186 MARK m; /* movement is relative to this mark */
187 long cnt; /* a numeric argument (ignored) */
189 char *scan;
191 /* move to the first non-whitespace character */
192 pfetch(markline(m));
193 scan = ptext;
194 m &= ~(BLKSIZE - 1);
195 while (*scan == ' ' || *scan == '\t')
197 scan++;
198 m++;
201 return m;
204 /*ARGSUSED*/
205 MARK m_rear(m, cnt)
206 MARK m; /* movement is relative to this mark */
207 long cnt; /* a numeric argument (ignored) */
209 /* Try to move *EXTREMELY* far to the right. It is fervently hoped
210 * that other code will convert this to a more reasonable MARK before
211 * anything tries to actually use it. (See adjmove() in vi.c)
213 return m | (BLKSIZE - 1);
216 #ifndef NO_SENTENCE
217 static int isperiod(ptr)
218 char *ptr; /* pointer to possible sentence-ender */
220 /* if not '.', '?', or '!', then it isn't a sentence ender */
221 if (*ptr != '.' && *ptr != '?' && *ptr != '!')
223 return FALSE;
226 /* skip any intervening ')', ']', or '"' characters */
229 ptr++;
230 } while (*ptr == ')' || *ptr == ']' || *ptr == '"');
232 /* do we have two spaces or EOL? */
233 if (!*ptr || ptr[0] == ' ' && ptr[1] == ' ')
235 return TRUE;
237 return FALSE;
240 /*ARGSUSED*/
241 MARK m_sentence(m, cnt, cmd)
242 MARK m; /* movement is relative to this mark */
243 long cnt; /* a numeric argument */
244 int cmd; /* either '(' or ')' */
246 REG char *text;
247 REG long l;
249 DEFAULT(1);
251 /* If '(' command, then move back one word, so that if we hit '(' at
252 * the start of a sentence we don't simply stop at the end of the
253 * previous sentence and bounce back to the start of this one again.
255 if (cmd == '(')
257 m = m_bword(m, 1L, 'b');
258 if (!m)
260 return m;
264 /* get the current line */
265 l = markline(m);
266 pfetch(l);
267 text = ptext + markidx(m);
269 /* for each requested sentence... */
270 while (cnt-- > 0)
272 /* search forward for one of [.?!] followed by spaces or EOL */
275 if (cmd == ')')
277 /* move forward, wrap at end of line */
278 if (!text[0])
280 if (l >= nlines)
282 return MARK_UNSET;
284 l++;
285 pfetch(l);
286 text = ptext;
288 else
290 text++;
293 else
295 /* move backward, wrap at beginning of line */
296 if (text == ptext)
300 if (l <= 1)
302 return MARK_FIRST;
304 l--;
305 pfetch(l);
306 } while (!*ptext);
307 text = ptext + plen - 1;
309 else
311 text--;
314 } while (!isperiod(text));
317 /* construct a mark for this location */
318 m = buildmark(text);
320 /* move forward to the first word of the next sentence */
321 m = m_fword(m, 1L, 'w', '\0');
323 return m;
325 #endif
327 MARK m_paragraph(m, cnt, cmd)
328 MARK m; /* movement is relative to this mark */
329 long cnt; /* a numeric argument */
330 int cmd; /* either '{' or '}' */
332 char *text; /* text of the current line */
333 char *pscn; /* used to scan thru value of "paragraphs" option */
334 long l, ol; /* current line number, original line number */
335 int dir; /* -1 if we're moving up, or 1 if down */
336 char col0; /* character to expect in column 0 */
337 #ifndef NO_SENTENCE
338 # define SENTENCE(x) (x)
339 char *list; /* either o_sections or o_paragraph */
340 #else
341 # define SENTENCE(x)
342 #endif
344 DEFAULT(1);
346 /* set the direction, based on the command */
347 switch (cmd)
349 case '{':
350 dir = -1;
351 col0 = '\0';
352 SENTENCE(list = o_paragraphs);
353 break;
355 case '}':
356 dir = 1;
357 col0 = '\0';
358 SENTENCE(list = o_paragraphs);
359 break;
361 case '[':
362 if (getkey(0) != '[')
364 return MARK_UNSET;
366 dir = -1;
367 col0 = '{';
368 SENTENCE(list = o_sections);
369 break;
371 case ']':
372 if (getkey(0) != ']')
374 return MARK_UNSET;
376 dir = 1;
377 col0 = '{';
378 SENTENCE(list = o_sections);
379 break;
381 ol = l = markline(m);
383 /* for each paragraph that we want to travel through... */
384 while (l > 0 && l <= nlines && cnt-- > 0)
386 /* skip blank lines between paragraphs */
387 while (l > 0 && l <= nlines && col0 == *(text = fetchline(l)))
389 l += dir;
392 /* skip non-blank lines that aren't paragraph separators
396 #ifndef NO_SENTENCE
397 if (*text == '.' && l != ol)
399 for (pscn = list; pscn[0] && pscn[1]; pscn += 2)
401 if (pscn[0] == text[1] && pscn[1] == text[2])
403 pscn = (char *)0;
404 goto BreakBreak;
408 #endif
409 l += dir;
410 } while (l > 0 && l <= nlines && col0 != *(text = fetchline(l)));
411 BreakBreak: ;
414 if (l > nlines)
416 m = MARK_LAST;
418 else if (l <= 0)
420 m = MARK_FIRST;
422 else
424 m = MARK_AT_LINE(l);
426 return m;
430 /*ARGSUSED*/
431 MARK m_match(m, cnt)
432 MARK m; /* movement is relative to this mark */
433 long cnt; /* a numeric argument (normally 0) */
435 long l;
436 REG char *text;
437 REG char match;
438 REG char nest;
439 REG int count;
441 #ifndef NO_EXTENSIONS
442 /* if we're given a number, then treat it as a percentage of the file */
443 if (cnt > 0)
445 /* make sure it is a reasonable number */
446 if (cnt > 100)
448 msg("can only be from 1%% to 100%%");
449 return MARK_UNSET;
452 /* return the appropriate line number */
453 l = (nlines - 1L) * cnt / 100L + 1L;
454 return MARK_AT_LINE(l);
456 #endif /* undef NO_EXTENSIONS */
458 /* get the current line */
459 l = markline(m);
460 pfetch(l);
461 text = ptext + markidx(m);
463 /* search forward within line for one of "[](){}" */
464 for (match = '\0'; !match && *text; text++)
466 /* tricky way to recognize 'em in ASCII */
467 nest = *text;
468 if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[')
470 match = nest ^ ('[' ^ ']');
472 else if ((nest & 0xfe) == '(')
474 match = nest ^ ('(' ^ ')');
476 else
478 match = 0;
481 if (!match)
483 return MARK_UNSET;
485 text--;
487 /* search forward or backward for match */
488 if (match == '(' || match == '[' || match == '{')
490 /* search backward */
491 for (count = 1; count > 0; )
493 /* wrap at beginning of line */
494 if (text == ptext)
498 if (l <= 1L)
500 return MARK_UNSET;
502 l--;
503 pfetch(l);
504 } while (!*ptext);
505 text = ptext + plen - 1;
507 else
509 text--;
512 /* check the char */
513 if (*text == match)
514 count--;
515 else if (*text == nest)
516 count++;
519 else
521 /* search forward */
522 for (count = 1; count > 0; )
524 /* wrap at end of line */
525 if (!*text)
527 if (l >= nlines)
529 return MARK_UNSET;
531 l++;
532 pfetch(l);
533 text = ptext;
535 else
537 text++;
540 /* check the char */
541 if (*text == match)
542 count--;
543 else if (*text == nest)
544 count++;
548 /* construct a mark for this place */
549 m = buildmark(text);
550 return m;
553 /*ARGSUSED*/
554 MARK m_tomark(m, cnt, key)
555 MARK m; /* movement is relative to this mark */
556 long cnt; /* (ignored) */
557 int key; /* keystroke - the mark to move to */
559 /* mark '' is a special case */
560 if (key == '\'' || key == '`')
562 if (mark[26] == MARK_UNSET)
564 return MARK_FIRST;
566 else
568 return mark[26];
572 /* if not a valid mark number, don't move */
573 if (key < 'a' || key > 'z')
575 return MARK_UNSET;
578 /* return the selected mark -- may be MARK_UNSET */
579 if (!mark[key - 'a'])
581 msg("mark '%c is unset", key);
583 return mark[key - 'a'];