home *** CD-ROM | disk | FTP | other *** search
- /* vi:ts=4:sw=4
- *
- * VIM - Vi IMproved by Bram Moolenaar
- *
- * Read the file "credits.txt" for a list of people who contributed.
- * Read the file "uganda.txt" for copying and usage conditions.
- */
-
- /*
- * mark.c: functions for setting marks and jumping to them
- */
-
- #include "vim.h"
- #include "globals.h"
- #include "proto.h"
-
- /*
- * This file contains routines to maintain and manipulate marks.
- */
-
- static struct filemark namedfm[NMARKS]; /* new marks with file nr */
-
- /*
- * setmark(c) - set named mark 'c' at current cursor position
- *
- * Returns OK on success, FAIL if no room for mark or bad name given.
- */
- int
- setmark(c)
- int c;
- {
- int i;
-
- if (islower(c))
- {
- i = c - 'a';
- curbuf->b_namedm[i] = curwin->w_cursor;
- return OK;
- }
- if (isupper(c))
- {
- i = c - 'A';
- namedfm[i].mark = curwin->w_cursor;
- namedfm[i].fnum = curbuf->b_fnum;
- return OK;
- }
- return FAIL;
- }
-
- /*
- * setpcmark() - set the previous context mark to the current position
- * and insert it into the jump list
- */
- void
- setpcmark()
- {
- int i;
- #ifdef ROTATE
- struct filemark tempmark;
- #endif
-
- curwin->w_prev_pcmark = curwin->w_pcmark;
- curwin->w_pcmark = curwin->w_cursor;
-
- #ifndef ROTATE
- /*
- * simply add the new entry at the end of the list
- */
- curwin->w_jumplistidx = curwin->w_jumplistlen;
- #else
- /*
- * If last used entry is not at the top, put it at the top by rotating
- * the stack until it is (the newer entries will be at the bottom).
- * Keep one entry (the last used one) at the top.
- */
- if (curwin->w_jumplistidx < curwin->w_jumplistlen)
- ++curwin->w_jumplistidx;
- while (curwin->w_jumplistidx < curwin->w_jumplistlen)
- {
- tempmark = curwin->w_jumplist[curwin->w_jumplistlen - 1];
- for (i = curwin->w_jumplistlen - 1; i > 0; --i)
- curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
- curwin->w_jumplist[0] = tempmark;
- ++curwin->w_jumplistidx;
- }
- #endif
-
- /* only add new entry if it differs from the last one */
- if (curwin->w_jumplistlen == 0 ||
- curwin->w_jumplist[curwin->w_jumplistidx - 1].mark.lnum !=
- curwin->w_pcmark.lnum ||
- curwin->w_jumplist[curwin->w_jumplistidx - 1].fnum !=
- curbuf->b_fnum)
- {
- /* if jumplist is full: remove oldest entry */
- if (++curwin->w_jumplistlen > JUMPLISTSIZE)
- {
- curwin->w_jumplistlen = JUMPLISTSIZE;
- for (i = 1; i < curwin->w_jumplistlen; ++i)
- curwin->w_jumplist[i - 1] = curwin->w_jumplist[i];
- --curwin->w_jumplistidx;
- }
-
- #ifdef ARCHIE
- /* Workaround for a bug in gcc 2.4.5 R2 on the Archimedes
- * Should be fixed in 2.5.x.
- */
- curwin->w_jumplist[curwin->w_jumplistidx].mark.ptr = curwin->w_pcmark.ptr;
- curwin->w_jumplist[curwin->w_jumplistidx].mark.col = curwin->w_pcmark.col;
- #else
- curwin->w_jumplist[curwin->w_jumplistidx].mark = curwin->w_pcmark;
- #endif
- curwin->w_jumplist[curwin->w_jumplistidx].fnum = curbuf->b_fnum;
- ++curwin->w_jumplistidx;
- }
- }
-
- /*
- * checkpcmark() - To change context, call setpcmark(), then move the current
- * position to where ever, then call checkpcmark(). This
- * ensures that the previous context will only be changed if
- * the cursor moved to a different line. -- webb.
- * If pcmark was deleted (with "dG") the previous mark is restored.
- */
- void
- checkpcmark()
- {
- if (curwin->w_prev_pcmark.lnum != 0 &&
- (curwin->w_pcmark.lnum == curwin->w_cursor.lnum ||
- curwin->w_pcmark.lnum == 0))
- {
- curwin->w_pcmark = curwin->w_prev_pcmark;
- curwin->w_prev_pcmark.lnum = 0; /* Show it has been checked */
- }
- }
-
- /*
- * move "count" positions in the jump list (count may be negative)
- */
- FPOS *
- movemark(count)
- int count;
- {
- FPOS *pos;
-
- if (curwin->w_jumplistlen == 0) /* nothing to jump to */
- return (FPOS *)NULL;
-
- if (curwin->w_jumplistidx + count < 0 ||
- curwin->w_jumplistidx + count >= curwin->w_jumplistlen)
- return (FPOS *)NULL;
-
- /*
- * if first CTRL-O or CTRL-I command after a jump, add cursor position to list
- */
- if (curwin->w_jumplistidx == curwin->w_jumplistlen)
- {
- setpcmark();
- --curwin->w_jumplistidx; /* skip the new entry */
- }
-
- curwin->w_jumplistidx += count;
- /* jump to other file */
- if (curwin->w_jumplist[curwin->w_jumplistidx].fnum != curbuf->b_fnum)
- {
- if (buflist_getfile(curwin->w_jumplist[curwin->w_jumplistidx].fnum,
- curwin->w_jumplist[curwin->w_jumplistidx].mark.lnum, FALSE) == FAIL)
- return (FPOS *)NULL;
- curwin->w_cursor.col = curwin->w_jumplist[curwin->w_jumplistidx].mark.col;
- pos = (FPOS *)-1;
- }
- else
- pos = &(curwin->w_jumplist[curwin->w_jumplistidx].mark);
- return pos;
- }
-
- /*
- * getmark(c) - find mark for char 'c'
- *
- * Return pointer to FPOS if found
- * NULL if no such mark.
- * -1 if mark is in other file (only if changefile is TRUE)
- */
- FPOS *
- getmark(c, changefile)
- int c;
- int changefile;
- {
- FPOS *posp;
- static FPOS pos_copy;
-
- posp = NULL;
- if (c == '\'' || c == '`') /* previous context mark */
- {
- pos_copy = curwin->w_pcmark; /* need to make a copy because b_pcmark */
- posp = &pos_copy; /* may be changed soon */
- }
- else if (c == '[') /* to start of previous operator */
- {
- if (curbuf->b_startop.lnum > 0 &&
- curbuf->b_startop.lnum <= curbuf->b_ml.ml_line_count)
- posp = &(curbuf->b_startop);
- }
- else if (c == ']') /* to end of previous operator */
- {
- if (curbuf->b_endop.lnum > 0 &&
- curbuf->b_endop.lnum <= curbuf->b_ml.ml_line_count)
- posp = &(curbuf->b_endop);
- }
- else if (islower(c)) /* normal named mark */
- posp = &(curbuf->b_namedm[c - 'a']);
- else if (isupper(c)) /* named file mark */
- {
- c -= 'A';
- posp = &(namedfm[c].mark);
- if (namedfm[c].fnum != curbuf->b_fnum &&
- namedfm[c].mark.lnum != 0 && changefile)
- {
- if (buflist_getfile(namedfm[c].fnum, namedfm[c].mark.lnum, TRUE) == OK)
- {
- curwin->w_cursor.col = namedfm[c].mark.col;
- posp = (FPOS *)-1;
- }
- }
- }
- return posp;
- }
-
- /*
- * clrallmarks() - clear all marks in the buffer 'buf'
- *
- * Used mainly when trashing the entire buffer during ":e" type commands
- */
- void
- clrallmarks(buf)
- BUF *buf;
- {
- static int i = -1;
-
- if (i == -1) /* first call ever: initialize */
- for (i = 0; i < NMARKS; i++)
- namedfm[i].mark.lnum = 0;
-
- for (i = 0; i < NMARKS; i++)
- buf->b_namedm[i].lnum = 0;
- buf->b_startop.lnum = 0; /* start/end op mark cleared */
- buf->b_endop.lnum = 0;
- }
-
- /*
- * get name of file from a filemark
- */
- char_u *
- fm_getname(fmark)
- struct filemark *fmark;
- {
- char_u *name;
-
- if (fmark->fnum != curbuf->b_fnum) /* not current file */
- {
- name = buflist_nr2name(fmark->fnum);
- if (name == NULL)
- return (char_u *)"-unknown-";
- return name;
- }
- return (char_u *)"-current-";
- }
-
- /*
- * print the marks (use the occasion to update the line numbers)
- */
- void
- domarks()
- {
- int i;
- char_u *name;
-
- gotocmdline(TRUE, NUL);
- msg_outstr((char_u *)"\nmark line file\n");
- for (i = 0; i < NMARKS; ++i)
- {
- if (curbuf->b_namedm[i].lnum != 0)
- {
- sprintf((char *)IObuff, " %c %5ld\n", i + 'a',
- curbuf->b_namedm[i].lnum);
- msg_outstr(IObuff);
- }
- flushbuf();
- }
- for (i = 0; i < NMARKS; ++i)
- {
- if (namedfm[i].mark.lnum != 0)
- {
- name = fm_getname(&namedfm[i]);
- if (name == NULL) /* file name not available */
- continue;
-
- sprintf((char *)IObuff, " %c %5ld %s\n",
- i + 'A',
- namedfm[i].mark.lnum,
- name);
- msg_outstr(IObuff);
- }
- flushbuf(); /* show one line at a time */
- }
- msg_end();
- }
-
- /*
- * print the jumplist
- */
- void
- dojumps()
- {
- int i;
- char_u *name;
-
- gotocmdline(TRUE, NUL);
- msg_outstr((char_u *)"\n jump line file\n");
- for (i = 0; i < curwin->w_jumplistlen; ++i)
- {
- if (curwin->w_jumplist[i].mark.lnum != 0)
- {
- name = fm_getname(&curwin->w_jumplist[i]);
- if (name == NULL) /* file name not available */
- continue;
-
- sprintf((char *)IObuff, "%c %2d %5ld %s\n",
- i == curwin->w_jumplistidx ? '>' : ' ',
- i + 1,
- curwin->w_jumplist[i].mark.lnum,
- name);
- msg_outstr(IObuff);
- }
- flushbuf();
- }
- if (curwin->w_jumplistidx == curwin->w_jumplistlen)
- msg_outstr((char_u *)">\n");
- msg_end();
- }
-
- /*
- * adjust marks between line1 and line2 (inclusive) to move 'inc' lines
- * If 'inc' is MAXLNUM the mark is made invalid.
- */
- void
- mark_adjust(line1, line2, inc)
- linenr_t line1;
- linenr_t line2;
- long inc;
- {
- int i;
- int fnum = curbuf->b_fnum;
- linenr_t *lp;
- WIN *win;
-
- /* named marks, lower case and upper case */
- for (i = 0; i < NMARKS; i++)
- {
- lp = &(curbuf->b_namedm[i].lnum);
- if (*lp >= line1 && *lp <= line2)
- {
- if (inc == MAXLNUM)
- *lp = 0;
- else
- *lp += inc;
- }
- if (namedfm[i].fnum == fnum)
- {
- lp = &(namedfm[i].mark.lnum);
- if (*lp >= line1 && *lp <= line2)
- {
- if (inc == MAXLNUM)
- *lp = 0;
- else
- *lp += inc;
- }
- }
- }
-
- /* previous context mark */
- lp = &(curwin->w_pcmark.lnum);
- if (*lp >= line1 && *lp <= line2)
- {
- if (inc == MAXLNUM)
- *lp = 0;
- else
- *lp += inc;
- }
-
- /* previous pcmark */
- lp = &(curwin->w_prev_pcmark.lnum);
- if (*lp >= line1 && *lp <= line2)
- {
- if (inc == MAXLNUM)
- *lp = 0;
- else
- *lp += inc;
- }
-
- /* quickfix marks */
- qf_mark_adjust(line1, line2, inc);
-
- /* jumplist marks */
- for (win = firstwin; win != NULL; win = win->w_next)
- {
- for (i = 0; i < win->w_jumplistlen; ++i)
- if (win->w_jumplist[i].fnum == fnum)
- {
- lp = &(win->w_jumplist[i].mark.lnum);
- if (*lp >= line1 && *lp <= line2)
- {
- if (inc == MAXLNUM)
- *lp = 0;
- else
- *lp += inc;
- }
- }
- /*
- * also adjust the line at the top of the window and the cursor position
- * for windows with the same buffer.
- */
- if (win != curwin && win->w_buffer == curbuf)
- {
- if (win->w_topline >= line1 && win->w_topline <= line2)
- {
- if (inc == MAXLNUM) /* topline is deleted */
- win->w_topline = line1;
- else /* keep topline on the same line */
- win->w_topline += inc;
- }
- if (win->w_cursor.lnum >= line1 && win->w_cursor.lnum <= line2)
- {
- if (inc == MAXLNUM) /* line with cursor is deleted */
- {
- win->w_cursor.lnum = line1;
- win->w_cursor.col = 0;
- }
- else /* keep cursor on the same line */
- win->w_cursor.lnum += inc;
- }
- }
- }
- }
-