/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * Code to handle tags and the tag stack */ #if defined MSDOS || defined WIN32 || defined(_WIN64)# include "vimio.h" /* for lseek(), must be before vim.h */#endif #include "vim.h" #ifdef HAVE_FCNTL_H# include <fcntl.h> /* for lseek() */#endif /* * Structure to hold pointers to various items in a tag line. */typedef struct tag_pointers{ /* filled in by parse_tag_line(): */ char_u *tagname; /* start of tag name (skip "file:") */ char_u *tagname_end; /* char after tag name */ char_u *fname; /* first char of file name */ char_u *fname_end; /* char after file name */ char_u *command; /* first char of command */ /* filled in by parse_match(): */ char_u *command_end; /* first char after command */ char_u *tag_fname; /* file name of the tags file */#ifdef FEAT_EMACS_TAGS int is_etag; /* TRUE for emacs tag */#endif char_u *tagkind; /* "kind:" value */ char_u *tagkind_end; /* end of tagkind */} tagptrs_T; /* * The matching tags are first stored in ga_match[]. In which one depends on * the priority of the match. * At the end, the matches from ga_match[] are concatenated, to make a list * sorted on priority. */#define MT_ST_CUR 0 /* static match in current file */#define MT_GL_CUR 1 /* global match in current file */#define MT_GL_OTH 2 /* global match in other file */#define MT_ST_OTH 3 /* static match in other file */#define MT_IC_ST_CUR 4 /* icase static match in current file */#define MT_IC_GL_CUR 5 /* icase global match in current file */#define MT_IC_GL_OTH 6 /* icase global match in other file */#define MT_IC_ST_OTH 7 /* icase static match in other file */#define MT_IC_OFF 4 /* add for icase match */#define MT_RE_OFF 8 /* add for regexp match */#define MT_MASK 7 /* mask for printing priority */#define MT_COUNT 16 static char *mt_names[MT_COUNT/2] = {"FSC", "F C", "F ", "FS ", " SC", " C", " ", " S "}; #define NOTAGFILE 99 /* return value for jumpto_tag */static char_u *nofile_fname = NULL; /* fname for NOTAGFILE error */ static void taglen_advance __ARGS((int l)); static int jumpto_tag __ARGS((char_u *lbuf, int forceit, int keep_help));#ifdef FEAT_EMACS_TAGSstatic int parse_tag_line __ARGS((char_u *lbuf, int is_etag, tagptrs_T *tagp));#elsestatic int parse_tag_line __ARGS((char_u *lbuf, tagptrs_T *tagp));#endifstatic int test_for_static __ARGS((tagptrs_T *));static int parse_match __ARGS((char_u *lbuf, tagptrs_T *tagp));static char_u *tag_full_fname __ARGS((tagptrs_T *tagp));static char_u *expand_tag_fname __ARGS((char_u *fname, char_u *tag_fname, int expand));#ifdef FEAT_EMACS_TAGSstatic int test_for_current __ARGS((int, char_u *, char_u *, char_u *, char_u *));#elsestatic int test_for_current __ARGS((char_u *, char_u *, char_u *, char_u *));#endifstatic int find_extra __ARGS((char_u **pp)); static char_u *bottommsg = (char_u *)N_("E555: at bottom of tag stack");static char_u *topmsg = (char_u *)N_("E556: at top of tag stack"); static char_u *tagmatchname = NULL; /* name of last used tag */ /* * We use ftello() here, if available. It returns off_t instead of long, * which helps if long is 32 bit and off_t is 64 bit. */#ifdef HAVE_FTELLO# define ftell ftello#endif #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)/* * Tag for preview window is remembered separately, to avoid messing up the * normal tagstack. */static taggy_T ptag_entry = {NULL};#endif /* * Jump to tag; handling of tag commands and tag stack * * *tag != NUL: ":tag {tag}", jump to new tag, add to tag stack * * type == DT_TAG: ":tag [tag]", jump to newer position or same tag again * type == DT_HELP: like DT_TAG, but don't use regexp. * type == DT_POP: ":pop" or CTRL-T, jump to old position * type == DT_NEXT: jump to next match of same tag * type == DT_PREV: jump to previous match of same tag * type == DT_FIRST: jump to first match of same tag * type == DT_LAST: jump to last match of same tag * type == DT_SELECT: ":tselect [tag]", select tag from a list of all matches * type == DT_JUMP: ":tjump [tag]", jump to tag or select tag from a list * type == DT_CSCOPE: use cscope to find the tag * type == DT_LTAG: use location list for displaying tag matches * type == DT_FREE: free cached matches * * for cscope, returns TRUE if we jumped to tag or aborted, FALSE otherwise */ intdo_tag(tag, type, count, forceit, verbose) char_u *tag; /* tag (pattern) to jump to */ int type; int count; int forceit; /* :ta with ! */ int verbose; /* print "tag not found" message */{ taggy_T *tagstack = curwin->w_tagstack; int tagstackidx = curwin->w_tagstackidx; int tagstacklen = curwin->w_tagstacklen; int cur_match = 0; int cur_fnum = curbuf->b_fnum; int oldtagstackidx = tagstackidx; int prevtagstackidx = tagstackidx; int prev_num_matches; int new_tag = FALSE; int other_name; int i, j, k; int idx; int ic; char_u *p; char_u *name; int no_regexp = FALSE; int error_cur_match = 0; char_u *command_end; int save_pos = FALSE; fmark_T saved_fmark; int taglen;#ifdef FEAT_CSCOPE int jumped_to_tag = FALSE;#endif tagptrs_T tagp, tagp2; int new_num_matches; char_u **new_matches; int attr; int use_tagstack; int skip_msg = FALSE; char_u *buf_ffname = curbuf->b_ffname; /* name to use for priority computation */ /* remember the matches for the last used tag */ static int num_matches = 0; static int max_num_matches = 0; /* limit used for match search */ static char_u **matches = NULL; static int flags; #ifdef EXITFREE if (type == DT_FREE) { /* remove the list of matches */ FreeWild(num_matches, matches);# ifdef FEAT_CSCOPE cs_free_tags();# endif num_matches = 0; return FALSE; }#endif if (type == DT_HELP) { type = DT_TAG; no_regexp = TRUE; } prev_num_matches = num_matches; free_string_option(nofile_fname); nofile_fname = NULL; clearpos(&saved_fmark.mark); /* shutup gcc 4.0 */ saved_fmark.fnum = 0; /* * Don't add a tag to the tagstack if 'tagstack' has been reset. */ if ((!p_tgst && *tag != NUL)) { use_tagstack = FALSE; new_tag = TRUE; } else {#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) if (g_do_tagpreview) use_tagstack = FALSE; else#endif use_tagstack = TRUE; /* new pattern, add to the tag stack */ if (*tag != NUL && (type == DT_TAG || type == DT_SELECT || type == DT_JUMP#ifdef FEAT_QUICKFIX || type == DT_LTAG#endif#ifdef FEAT_CSCOPE || type == DT_CSCOPE#endif )) {#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) if (g_do_tagpreview) { if (ptag_entry.tagname != NULL && STRCMP(ptag_entry.tagname, tag) == 0) { /* Jumping to same tag: keep the current match, so that * the CursorHold autocommand example works. */ cur_match = ptag_entry.cur_match; cur_fnum = ptag_entry.cur_fnum; } else { vim_free(ptag_entry.tagname); if ((ptag_entry.tagname = vim_strsave(tag)) == NULL) goto end_do_tag; } } else#endif { /* * If the last used entry is not at the top, delete all tag * stack entries above it. */ while (tagstackidx < tagstacklen) vim_free(tagstack[--tagstacklen].tagname); /* if the tagstack is full: remove oldest entry */ if (++tagstacklen > TAGSTACKSIZE) { tagstacklen = TAGSTACKSIZE; vim_free(tagstack[0].tagname); for (i = 1; i < tagstacklen; ++i) tagstack[i - 1] = tagstack[i]; --tagstackidx; } /* * put the tag name in the tag stack */ if ((tagstack[tagstackidx].tagname = vim_strsave(tag)) == NULL) { curwin->w_tagstacklen = tagstacklen - 1; goto end_do_tag; } curwin->w_tagstacklen = tagstacklen; save_pos = TRUE; /* save the cursor position below */ } new_tag = TRUE; } else { if (#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) g_do_tagpreview ? ptag_entry.tagname == NULL :#endif tagstacklen == 0) { /* empty stack */ EMSG(_(e_tagstack)); goto end_do_tag; } if (type == DT_POP) /* go to older position */ {#ifdef FEAT_FOLDING int old_KeyTyped = KeyTyped;#endif if ((tagstackidx -= count) < 0) { EMSG(_(bottommsg)); if (tagstackidx + count == 0) { /* We did [num]^T from the bottom of the stack */ tagstackidx = 0; goto end_do_tag; } /* We weren't at the bottom of the stack, so jump all the * way to the bottom now. */ tagstackidx = 0; } else if (tagstackidx >= tagstacklen) /* count == 0? */ { EMSG(_(topmsg)); goto end_do_tag; } /* Make a copy of the fmark, autocommands may invalidate the * tagstack before it's used. */ saved_fmark = tagstack[tagstackidx].fmark; if (saved_fmark.fnum != curbuf->b_fnum) { /* * Jump to other file. If this fails (e.g. because the * file was changed) keep original position in tag stack. */ if (buflist_getfile(saved_fmark.fnum, saved_fmark.mark.lnum, GETF_SETMARK, forceit) == FAIL) { tagstackidx = oldtagstackidx; /* back to old posn */ goto end_do_tag; } /* An BufReadPost autocommand may jump to the '" mark, but * we don't what that here. */ curwin->w_cursor.lnum = saved_fmark.mark.lnum; } else { setpcmark(); curwin->w_cursor.lnum = saved_fmark.mark.lnum; } curwin->w_cursor.col = saved_fmark.mark.col; curwin->w_set_curswant = TRUE; check_cursor();#ifdef FEAT_FOLDING if ((fdo_flags & FDO_TAG) && old_KeyTyped) foldOpenCursor();#endif /* remove the old list of matches */ FreeWild(num_matches, matches);#ifdef FEAT_CSCOPE cs_free_tags();#endif num_matches = 0; tag_freematch(); goto end_do_tag; } if (type == DT_TAG#if defined(FEAT_QUICKFIX) || type == DT_LTAG#endif ) {#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) if (g_do_tagpreview) { cur_match = ptag_entry.cur_match; cur_fnum = ptag_entry.cur_fnum; } else#endif { /* ":tag" (no argument): go to newer pattern */ save_pos = TRUE; /* save the cursor position below */ if ((tagstackidx += count - 1) >= tagstacklen) { /* * Beyond the last one, just give an error message and * go to the last one. Don't store the cursor * position. */ tagstackidx = tagstacklen - 1; EMSG(_(topmsg)); save_pos = FALSE; } else if (tagstackidx < 0) /* must have been count == 0 */ { EMSG(_(bottommsg)); tagstackidx = 0; goto end_do_tag; } cur_match = tagstack[tagstackidx].cur_match; cur_fnum = tagstack[tagstackidx].cur_fnum; } new_tag = TRUE; } else /* go to other matching tag */ { /* Save index for when selection is cancelled. */ prevtagstackidx = tagstackidx; #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) if (g_do_tagpreview) { cur_match = ptag_entry.cur_match; cur_fnum = ptag_entry.cur_fnum; } else#endif { if (--tagstackidx < 0) tagstackidx = 0; cur_match = tagstack[tagstackidx].cur_match; cur_fnum = tagstack[tagstackidx].cur_fnum; } switch (type) { case DT_FIRST: cur_match = count - 1; break; case DT_SELECT: case DT_JUMP:#ifdef FEAT_CSCOPE case DT_CSCOPE:#endif case DT_LAST: cur_match = MAXCOL - 1; break; case DT_NEXT: cur_match += count; break; case DT_PREV: cur_match -= count; break; } if (cur_match >= MAXCOL) cur_match = MAXCOL - 1; else if (cur_match < 0) { EMSG(_("E425: Cannot go before first matching tag")); skip_msg = TRUE; cur_match = 0; cur_fnum = curbuf->b_fnum; } } } #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) if (g_do_tagpreview) { if (type != DT_SELECT && type != DT_JUMP) { ptag_entry.cur_match = cur_match; ptag_entry.cur_fnum = cur_fnum; } } else#endif { /* * For ":tag [arg]" or ":tselect" remember position before the jump. */ saved_fmark = tagstack[tagstackidx].fmark; if (save_pos) { tagstack[tagstackidx].fmark.mark = curwin->w_cursor; tagstack[tagstackidx].fmark.fnum = curbuf->b_fnum; } /* Curwin will change in the call to jumpto_tag() if ":stag" was * used or an autocommand jumps to another window; store value of * tagstackidx now. */ curwin->w_tagstackidx = tagstackidx; if (type != DT_SELECT && type != DT_JUMP) { curwin->w_tagstack[tagstackidx].cur_match = cur_match; curwin->w_tagstack[tagstackidx].cur_fnum = cur_fnum; } } } /* When not using the current buffer get the name of buffer "cur_fnum". * Makes sure that the tag order doesn't change when using a remembered * position for "cur_match". */ if (cur_fnum != curbuf->b_fnum) { buf_T *buf = buflist_findnr(cur_fnum); if (buf != NULL) buf_ffname = buf->b_ffname; } /* * Repeat searching for tags, when a file has not been found. */ for (;;) { /* * When desired match not found yet, try to find it (and others). */ if (use_tagstack) name = tagstack[tagstackidx].tagname;Lines 1–500 of 3875. Load more
/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * Code to handle tags and the tag stack */ #if defined MSDOS || defined WIN32 || defined(_WIN64) # include "vimio.h" /* for lseek(), must be before vim.h */ #endif #include "vim.h" #ifdef HAVE_FCNTL_H # include <fcntl.h> /* for lseek() */ #endif /* * Structure to hold pointers to various items in a tag line. */ typedef struct tag_pointers { /* filled in by parse_tag_line(): */ char_u *tagname; /* start of tag name (skip "file:") */ char_u *tagname_end; /* char after tag name */ char_u *fname; /* first char of file name */ char_u *fname_end; /* char after file name */ char_u *command; /* first char of command */ /* filled in by parse_match(): */ char_u *command_end; /* first char after command */ char_u *tag_fname; /* file name of the tags file */ #ifdef FEAT_EMACS_TAGS int is_etag; /* TRUE for emacs tag */ #endif char_u *tagkind; /* "kind:" value */ char_u *tagkind_end; /* end of tagkind */ } tagptrs_T; /* * The matching tags are first stored in ga_match[]. In which one depends on * the priority of the match. * At the end, the matches from ga_match[] are concatenated, to make a list * sorted on priority. */ #define MT_ST_CUR 0 /* static match in current file */ #define MT_GL_CUR 1 /* global match in current file */ #define MT_GL_OTH 2 /* global match in other file */ #define MT_ST_OTH 3 /* static match in other file */ #define MT_IC_ST_CUR 4 /* icase static match in current file */ #define MT_IC_GL_CUR 5 /* icase global match in current file */ #define MT_IC_GL_OTH 6 /* icase global match in other file */ #define MT_IC_ST_OTH 7 /* icase static match in other file */ #define MT_IC_OFF 4 /* add for icase match */ #define MT_RE_OFF 8 /* add for regexp match */ #define MT_MASK 7 /* mask for printing priority */ #define MT_COUNT 16 static char *mt_names[MT_COUNT/2] = {"FSC", "F C", "F ", "FS ", " SC", " C", " ", " S "}; #define NOTAGFILE 99 /* return value for jumpto_tag */ static char_u *nofile_fname = NULL; /* fname for NOTAGFILE error */ static void taglen_advance __ARGS((int l)); static int jumpto_tag __ARGS((char_u *lbuf, int forceit, int keep_help)); #ifdef FEAT_EMACS_TAGS static int parse_tag_line __ARGS((char_u *lbuf, int is_etag, tagptrs_T *tagp)); #else static int parse_tag_line __ARGS((char_u *lbuf, tagptrs_T *tagp)); #endif static int test_for_static __ARGS((tagptrs_T *)); static int parse_match __ARGS((char_u *lbuf, tagptrs_T *tagp)); static char_u *tag_full_fname __ARGS((tagptrs_T *tagp)); static char_u *expand_tag_fname __ARGS((char_u *fname, char_u *tag_fname, int expand)); #ifdef FEAT_EMACS_TAGS static int test_for_current __ARGS((int, char_u *, char_u *, char_u *, char_u *)); #else static int test_for_current __ARGS((char_u *, char_u *, char_u *, char_u *)); #endif static int find_extra __ARGS((char_u **pp)); static char_u *bottommsg = (char_u *)N_("E555: at bottom of tag stack"); static char_u *topmsg = (char_u *)N_("E556: at top of tag stack"); static char_u *tagmatchname = NULL; /* name of last used tag */ /* * We use ftello() here, if available. It returns off_t instead of long, * which helps if long is 32 bit and off_t is 64 bit. */ #ifdef HAVE_FTELLO # define ftell ftello #endif #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) /* * Tag for preview window is remembered separately, to avoid messing up the * normal tagstack. */ static taggy_T ptag_entry = {NULL}; #endif /* * Jump to tag; handling of tag commands and tag stack * * *tag != NUL: ":tag {tag}", jump to new tag, add to tag stack * * type == DT_TAG: ":tag [tag]", jump to newer position or same tag again * type == DT_HELP: like DT_TAG, but don't use regexp. * type == DT_POP: ":pop" or CTRL-T, jump to old position * type == DT_NEXT: jump to next match of same tag * type == DT_PREV: jump to previous match of same tag * type == DT_FIRST: jump to first match of same tag * type == DT_LAST: jump to last match of same tag * type == DT_SELECT: ":tselect [tag]", select tag from a list of all matches * type == DT_JUMP: ":tjump [tag]", jump to tag or select tag from a list * type == DT_CSCOPE: use cscope to find the tag * type == DT_LTAG: use location list for displaying tag matches * type == DT_FREE: free cached matches * * for cscope, returns TRUE if we jumped to tag or aborted, FALSE otherwise */ int do_tag(tag, type, count, forceit, verbose) char_u *tag; /* tag (pattern) to jump to */ int type; int count; int forceit; /* :ta with ! */ int verbose; /* print "tag not found" message */ { taggy_T *tagstack = curwin->w_tagstack; int tagstackidx = curwin->w_tagstackidx; int tagstacklen = curwin->w_tagstacklen; int cur_match = 0; int cur_fnum = curbuf->b_fnum; int oldtagstackidx = tagstackidx; int prevtagstackidx = tagstackidx; int prev_num_matches; int new_tag = FALSE; int other_name; int i, j, k; int idx; int ic; char_u *p; char_u *name; int no_regexp = FALSE; int error_cur_match = 0; char_u *command_end; int save_pos = FALSE; fmark_T saved_fmark; int taglen; #ifdef FEAT_CSCOPE int jumped_to_tag = FALSE; #endif tagptrs_T tagp, tagp2; int new_num_matches; char_u **new_matches; int attr; int use_tagstack; int skip_msg = FALSE; char_u *buf_ffname = curbuf->b_ffname; /* name to use for priority computation */ /* remember the matches for the last used tag */ static int num_matches = 0; static int max_num_matches = 0; /* limit used for match search */ static char_u **matches = NULL; static int flags; #ifdef EXITFREE if (type == DT_FREE) { /* remove the list of matches */ FreeWild(num_matches, matches); # ifdef FEAT_CSCOPE cs_free_tags(); # endif num_matches = 0; return FALSE; } #endif if (type == DT_HELP) { type = DT_TAG; no_regexp = TRUE; } prev_num_matches = num_matches; free_string_option(nofile_fname); nofile_fname = NULL; clearpos(&saved_fmark.mark); /* shutup gcc 4.0 */ saved_fmark.fnum = 0; /* * Don't add a tag to the tagstack if 'tagstack' has been reset. */ if ((!p_tgst && *tag != NUL)) { use_tagstack = FALSE; new_tag = TRUE; } else { #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) if (g_do_tagpreview) use_tagstack = FALSE; else #endif use_tagstack = TRUE; /* new pattern, add to the tag stack */ if (*tag != NUL && (type == DT_TAG || type == DT_SELECT || type == DT_JUMP #ifdef FEAT_QUICKFIX || type == DT_LTAG #endif #ifdef FEAT_CSCOPE || type == DT_CSCOPE #endif )) { #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) if (g_do_tagpreview) { if (ptag_entry.tagname != NULL && STRCMP(ptag_entry.tagname, tag) == 0) { /* Jumping to same tag: keep the current match, so that * the CursorHold autocommand example works. */ cur_match = ptag_entry.cur_match; cur_fnum = ptag_entry.cur_fnum; } else { vim_free(ptag_entry.tagname); if ((ptag_entry.tagname = vim_strsave(tag)) == NULL) goto end_do_tag; } } else #endif { /* * If the last used entry is not at the top, delete all tag * stack entries above it. */ while (tagstackidx < tagstacklen) vim_free(tagstack[--tagstacklen].tagname); /* if the tagstack is full: remove oldest entry */ if (++tagstacklen > TAGSTACKSIZE) { tagstacklen = TAGSTACKSIZE; vim_free(tagstack[0].tagname); for (i = 1; i < tagstacklen; ++i) tagstack[i - 1] = tagstack[i]; --tagstackidx; } /* * put the tag name in the tag stack */ if ((tagstack[tagstackidx].tagname = vim_strsave(tag)) == NULL) { curwin->w_tagstacklen = tagstacklen - 1; goto end_do_tag; } curwin->w_tagstacklen = tagstacklen; save_pos = TRUE; /* save the cursor position below */ } new_tag = TRUE; } else { if ( #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) g_do_tagpreview ? ptag_entry.tagname == NULL : #endif tagstacklen == 0) { /* empty stack */ EMSG(_(e_tagstack)); goto end_do_tag; } if (type == DT_POP) /* go to older position */ { #ifdef FEAT_FOLDING int old_KeyTyped = KeyTyped; #endif if ((tagstackidx -= count) < 0) { EMSG(_(bottommsg)); if (tagstackidx + count == 0) { /* We did [num]^T from the bottom of the stack */ tagstackidx = 0; goto end_do_tag; } /* We weren't at the bottom of the stack, so jump all the * way to the bottom now. */ tagstackidx = 0; } else if (tagstackidx >= tagstacklen) /* count == 0? */ { EMSG(_(topmsg)); goto end_do_tag; } /* Make a copy of the fmark, autocommands may invalidate the * tagstack before it's used. */ saved_fmark = tagstack[tagstackidx].fmark; if (saved_fmark.fnum != curbuf->b_fnum) { /* * Jump to other file. If this fails (e.g. because the * file was changed) keep original position in tag stack. */ if (buflist_getfile(saved_fmark.fnum, saved_fmark.mark.lnum, GETF_SETMARK, forceit) == FAIL) { tagstackidx = oldtagstackidx; /* back to old posn */ goto end_do_tag; } /* An BufReadPost autocommand may jump to the '" mark, but * we don't what that here. */ curwin->w_cursor.lnum = saved_fmark.mark.lnum; } else { setpcmark(); curwin->w_cursor.lnum = saved_fmark.mark.lnum; } curwin->w_cursor.col = saved_fmark.mark.col; curwin->w_set_curswant = TRUE; check_cursor(); #ifdef FEAT_FOLDING if ((fdo_flags & FDO_TAG) && old_KeyTyped) foldOpenCursor(); #endif /* remove the old list of matches */ FreeWild(num_matches, matches); #ifdef FEAT_CSCOPE cs_free_tags(); #endif num_matches = 0; tag_freematch(); goto end_do_tag; } if (type == DT_TAG #if defined(FEAT_QUICKFIX) || type == DT_LTAG #endif ) { #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) if (g_do_tagpreview) { cur_match = ptag_entry.cur_match; cur_fnum = ptag_entry.cur_fnum; } else #endif { /* ":tag" (no argument): go to newer pattern */ save_pos = TRUE; /* save the cursor position below */ if ((tagstackidx += count - 1) >= tagstacklen) { /* * Beyond the last one, just give an error message and * go to the last one. Don't store the cursor * position. */ tagstackidx = tagstacklen - 1; EMSG(_(topmsg)); save_pos = FALSE; } else if (tagstackidx < 0) /* must have been count == 0 */ { EMSG(_(bottommsg)); tagstackidx = 0; goto end_do_tag; } cur_match = tagstack[tagstackidx].cur_match; cur_fnum = tagstack[tagstackidx].cur_fnum; } new_tag = TRUE; } else /* go to other matching tag */ { /* Save index for when selection is cancelled. */ prevtagstackidx = tagstackidx; #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) if (g_do_tagpreview) { cur_match = ptag_entry.cur_match; cur_fnum = ptag_entry.cur_fnum; } else #endif { if (--tagstackidx < 0) tagstackidx = 0; cur_match = tagstack[tagstackidx].cur_match; cur_fnum = tagstack[tagstackidx].cur_fnum; } switch (type) { case DT_FIRST: cur_match = count - 1; break; case DT_SELECT: case DT_JUMP: #ifdef FEAT_CSCOPE case DT_CSCOPE: #endif case DT_LAST: cur_match = MAXCOL - 1; break; case DT_NEXT: cur_match += count; break; case DT_PREV: cur_match -= count; break; } if (cur_match >= MAXCOL) cur_match = MAXCOL - 1; else if (cur_match < 0) { EMSG(_("E425: Cannot go before first matching tag")); skip_msg = TRUE; cur_match = 0; cur_fnum = curbuf->b_fnum; } } } #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) if (g_do_tagpreview) { if (type != DT_SELECT && type != DT_JUMP) { ptag_entry.cur_match = cur_match; ptag_entry.cur_fnum = cur_fnum; } } else #endif { /* * For ":tag [arg]" or ":tselect" remember position before the jump. */ saved_fmark = tagstack[tagstackidx].fmark; if (save_pos) { tagstack[tagstackidx].fmark.mark = curwin->w_cursor; tagstack[tagstackidx].fmark.fnum = curbuf->b_fnum; } /* Curwin will change in the call to jumpto_tag() if ":stag" was * used or an autocommand jumps to another window; store value of * tagstackidx now. */ curwin->w_tagstackidx = tagstackidx; if (type != DT_SELECT && type != DT_JUMP) { curwin->w_tagstack[tagstackidx].cur_match = cur_match; curwin->w_tagstack[tagstackidx].cur_fnum = cur_fnum; } } } /* When not using the current buffer get the name of buffer "cur_fnum". * Makes sure that the tag order doesn't change when using a remembered * position for "cur_match". */ if (cur_fnum != curbuf->b_fnum) { buf_T *buf = buflist_findnr(cur_fnum); if (buf != NULL) buf_ffname = buf->b_ffname; } /* * Repeat searching for tags, when a file has not been found. */ for (;;) { /* * When desired match not found yet, try to find it (and others). */ if (use_tagstack) name = tagstack[tagstackidx].tagname;