⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tag.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (STRNCMP(p, "kind:", 5) == 0)
		{
		    tagp->tagkind = p + 5;
		    break;
		}
		pc = vim_strchr(p, ':');
		pt = vim_strchr(p, '\t');
		if (pc == NULL || (pt != NULL && pc > pt))
		{
		    tagp->tagkind = p;
		    break;
		}
		if (pt == NULL)
		    break;
		p = pt + 1;
	    }
	}
	if (tagp->tagkind != NULL)
	{
	    for (p = tagp->tagkind;
			    *p && *p != '\t' && *p != '\r' && *p != '\n'; ++p)
		;
	    tagp->tagkind_end = p;
	}
    }
    return retval;
}

/*
 * Jump to a tag that has been found in one of the tag files
 *
 * returns OK for success, NOTAGFILE when file not found, FAIL otherwise.
 */
    static int
jumpto_tag(lbuf, forceit)
    char_u	*lbuf;		/* line from the tags file for this tag */
    int		forceit;	/* :ta with ! */
{
    int		save_secure;
    int		save_magic;
    int		save_p_ws, save_p_scs, save_p_ic;
    int		csave = 0;
    char_u	*str;
    char_u	*pbuf;			/* search pattern buffer */
    char_u	*pbuf_end;
    char_u	*expanded_fname = NULL;
    char_u	*tofree_fname = NULL;
    char_u	*fname;
    struct tag_pointers tagp;
    int		retval = FAIL;
    int		getfile_result;
    int		search_options;

    pbuf = alloc(LSIZE);

    /* parse the match line into the tagp structure */
    if (pbuf == NULL || parse_match(lbuf, &tagp) == FAIL)
    {
	tagp.fname_end = NULL;
	goto erret;
    }

    /* truncate the file name, so it can be used as a string */
    csave = *tagp.fname_end;
    *tagp.fname_end = NUL;
    fname = tagp.fname;

    /* copy the command to pbuf[], remove trailing CR/NL */
    str = tagp.command;
    for (pbuf_end = pbuf; *str && *str != '\n' && *str != '\r'; )
    {
#ifdef EMACS_TAGS
	if (tagp.is_etag && *str == ',')/* stop at ',' after line number */
	    break;
#endif
	*pbuf_end++ = *str++;
    }
    *pbuf_end = NUL;

#ifdef EMACS_TAGS
    if (!tagp.is_etag)
#endif
    {
	/*
	 * Remove the "<Tab>fieldname:value" stuff; we don't need it here.
	 */
	str = pbuf;
	if (find_extra(&str) == OK)
	{
	    pbuf_end = str;
	    *pbuf_end = NUL;
	}
    }

    /*
     * expand file name (for environment variables)
     */
    expanded_fname = ExpandOne((char_u *)fname, NULL, WILD_LIST_NOTFOUND,
							    WILD_EXPAND_FREE);
    if (expanded_fname != NULL)
	fname = expanded_fname;

    /*
     * if 'tagrelative' option set, may change file name
     */
    fname = expand_rel_name(fname, tagp.tag_fname);
    if (fname == NULL)
	goto erret;
    tofree_fname = fname;	/* free() it later */

    /*
     * check if file for tag exists before abandoning current file
     */
    if (mch_getperm(fname) < 0)
    {
	retval = NOTAGFILE;
	vim_free(nofile_fname);
	nofile_fname = vim_strsave(fname);
	if (nofile_fname == NULL)
	    nofile_fname = (char_u *)"";
	goto erret;
    }

    ++RedrawingDisabled;

#ifdef USE_GUI
    need_mouse_correct = TRUE;
#endif

    /* if it was a CTRL-W CTRL-] command split window now */
    if (postponed_split)
	win_split(postponed_split > 0 ? postponed_split : 0, FALSE, FALSE);

    /* A :ta from a help file will keep the b_help flag set. */
    keep_help_flag = curbuf->b_help;
    getfile_result = getfile(0, fname, NULL, TRUE, (linenr_t)0, forceit);
    keep_help_flag = FALSE;

    if (getfile_result <= 0)		/* got to the right file */
    {
	curwin->w_set_curswant = TRUE;
	postponed_split = 0;

	save_secure = secure;
	secure = 1;
	save_magic = p_magic;
	p_magic = FALSE;	/* always execute with 'nomagic' */
	tag_modified = FALSE;

	/*
	 * If 'cpoptions' contains 't', store the search pattern for the "n"
	 * command.  If 'cpoptions' does not contain 't', the search pattern
	 * is not stored.
	 */
	if (vim_strchr(p_cpo, CPO_TAGPAT) != NULL)
	    search_options = 0;
	else
	    search_options = SEARCH_KEEP;

	/*
	 * If the command is a search, try here.
	 *
	 * Reset 'smartcase' for the search, since the search pattern was not
	 * typed by the user.
	 * Only use do_search() when there is a full search command, without
	 * anything following.
	 */
	str = pbuf;
	if (pbuf[0] == '/' || pbuf[0] == '?')
	    str = skip_regexp(pbuf + 1, pbuf[0], FALSE) + 1;
	if (str > pbuf_end - 1)	/* search command with nothing following */
	{
	    save_p_ws = p_ws;
	    save_p_ic = p_ic;
	    save_p_scs = p_scs;
	    p_ws = TRUE;	/* Switch wrap-scan on temporarily */
	    p_ic = FALSE;	/* don't ignore case now */
	    p_scs = FALSE;

	    /* put pattern in search history */
	    add_to_history(HIST_SEARCH, pbuf + 1);

	    curwin->w_cursor.lnum = 0;	/* start search before first line */
	    if (do_search(NULL, pbuf[0], pbuf + 1, (long)1, search_options))
		retval = OK;
	    else
	    {
		int	found = 1;
		int	cc;

		/*
		 * try again, ignore case now
		 */
		p_ic = TRUE;
		if (!do_search(NULL, pbuf[0], pbuf + 1, (long)1,
							      search_options))
		{
		    /*
		     * Failed to find pattern, take a guess: "^func  ("
		     */
		    found = 2;
		    (void)test_for_static(&tagp);
		    cc = *tagp.tagname_end;
		    *tagp.tagname_end = NUL;
		    sprintf((char *)pbuf, "^%s\\s\\*(", tagp.tagname);
		    if (!do_search(NULL, '/', pbuf, (long)1, search_options))
		    {
			/* Guess again: "^char * \<func  (" */
			sprintf((char *)pbuf, "^\\[#a-zA-Z_]\\.\\*\\<%s\\s\\*(",
								tagp.tagname);
			if (!do_search(NULL, '/', pbuf, (long)1,
							      search_options))
			    found = 0;
		    }
		    *tagp.tagname_end = cc;
		}
		if (found == 0)
		    EMSG("Can't find tag pattern");
		else
		{
		    /*
		     * Only give a message when really guessed, not when 'ic'
		     * is set and match found while ignoring case.
		     */
		    if (found == 2 || !save_p_ic)
		    {
			MSG("Couldn't find tag, just guessing!");
			if (!msg_scrolled)
			{
			    out_flush();
			    ui_delay(1000L, TRUE);
			}
		    }
		    retval = OK;
		}
	    }
	    p_ws = save_p_ws;
	    p_ic = save_p_ic;
	    p_scs = save_p_scs;

	    /* A search command may have positioned the cursor beyond the end
	     * of the line.  May need to correct that here. */
	    adjust_cursor();
	}
	else
	{
	    curwin->w_cursor.lnum = 1;		/* start command in line 1 */
	    do_cmdline(pbuf, NULL, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE);
	    retval = OK;
	}

	/*
	 * When the command has set the b_changed flag, give a warning to the
	 * user about this.
	 */
	if (tag_modified)
	{
	    secure = 2;
	    EMSG("WARNING: tag command changed a buffer!!!");
	}
	if (secure == 2)	    /* done something that is not allowed */
	    wait_return(TRUE);
	secure = save_secure;
	p_magic = save_magic;

	/* Return OK if jumped to another file (at least we found the file!). */
	if (getfile_result == -1)
	    retval = OK;

	/*
	 * For a help buffer: Put the cursor line at the top of the window,
	 * the help subject will be below it.
	 */
	if (curbuf->b_help)
	{
	    set_topline(curwin, curwin->w_cursor.lnum);
	    update_topline();		/* correct for 'so' */
	    update_screen(NOT_VALID);
	}
	--RedrawingDisabled;
    }
    else
    {
	--RedrawingDisabled;
	if (postponed_split)		/* close the window */
	{
	    close_window(curwin, FALSE);
	    postponed_split = 0;
	}
    }

erret:
    if (tagp.fname_end != NULL)
	*tagp.fname_end = csave;
    vim_free(pbuf);
    vim_free(tofree_fname);
    vim_free(expanded_fname);

    return retval;
}

/*
 * If 'tagrelative' option set, change fname (name of file containing tag)
 * according to tag_fname (name of tag file containing fname).
 * Returns a pointer to allocated memory (or NULL when out of memory).
 */
    static char_u *
expand_rel_name(fname, tag_fname)
    char_u	*fname;
    char_u	*tag_fname;
{
    char_u	*p;
    char_u	*retval;

    if ((p_tr || curbuf->b_help) && !mch_isFullName(fname) &&
				       (p = gettail(tag_fname)) != tag_fname)
    {
	retval = alloc(MAXPATHL);
	if (retval == NULL)
	    return NULL;

	STRCPY(retval, tag_fname);
	STRNCPY(retval + (p - tag_fname), fname, MAXPATHL - (p - tag_fname));
	/*
	 * Translate names like "src/a/../b/file.c" into "src/b/file.c".
	 */
	simplify_filename(retval);
    }
    else
	retval = vim_strsave(fname);

    return retval;
}

/*
 * Moves the tail part of the path (including the terminating NUL) pointed to
 * by "tail" to the new location pointed to by "here". This should accomodate
 * an overlapping move.
 */
#define movetail(here, tail)  mch_memmove(here, tail, STRLEN(tail) + (size_t)1)

/*
 * Converts a file name into a canonical form. It simplifies a file name into
 * its simplest form by stripping out unneeded components, if any.  The
 * resulting file name is simplified in place and will either be the same
 * length as that supplied, or shorter.
 */
    void
simplify_filename(filename)
    char_u *filename;
{
#ifndef AMIGA	    /* Amiga doesn't have "..", it uses "/" */
    int	    components = 0;
    char_u  *p, *tail, *start;
#ifdef UNIX
    char_u  *orig = vim_strsave(filename);

    if (orig == NULL)
	return;
#endif

    p = filename;
#ifdef BACKSLASH_IN_FILENAME
    if (p[1] == ':')	    /* skip "x:" */
	p += 2;
#endif

    while (vim_ispathsep(*p))
	++p;
    start = p;	    /* remember start after "c:/" or "/" or "//" */

    do
    {
	/* At this point "p" is pointing to the char following a "/". */
	if (vim_ispathsep(*p))
	    movetail(p, p + 1);		/* remove duplicate "/" */
	else if (p[0] == '.' && vim_ispathsep(p[1]))
	    movetail(p, p + 2);		/* strip "./" */
	else if (p[0] == '.' && p[1] == '.' && vim_ispathsep(p[2]))
	{
	    if (components > 0)		/* strip one preceding component */
	    {
		tail = p + 3;		/* skip to after "../" or "..///" */
		while (vim_ispathsep(*tail))
		    ++tail;
		--p;
		/* skip back to after previous '/' */
		while (p > start && !vim_ispathsep(p[-1]))
		    --p;
		/* skip back to after first '/' in a row */
		while (p - 1 > start && vim_ispathsep(p[-2]))
		    --p;
		movetail(p, tail);	/* strip previous component */
		--components;
	    }
	    else			/* leading "../" */
		p += 3;			/* skip to char after "/" */
	}
	else
	{
	    ++components;		/* simple path component */
	    p = getnextcomp(p);
	}
    } while (p != NULL && *p != NUL);

#ifdef UNIX
    /* Check that the new file name is really the same file.  This will not be
     * the case when using symbolic links: "dir/link/../name" != "dir/name". */
    {
	struct stat	orig_st, new_st;

	if (	   stat((char *)orig, &orig_st) < 0
		|| stat((char *)filename, &new_st) < 0
		|| orig_st.st_ino != new_st.st_ino
		|| orig_st.st_dev != new_st.st_dev)
	    STRCPY(filename, orig);
	vim_free(orig);
    }
#endif
#endif /* !AMIGA */
}

/*
 * Check if we have a tag for the current file.
 * This is a bit slow, because of the full path compare in fullpathcmp().
 * Return TRUE if tag for file "fname" if tag file "tag_fname" is for current
 * file.
 */
    static int
#ifdef EMACS_TAGS
test_for_current(is_etag, fname, fname_end, tag_fname)
    int	    is_etag;
#else
test_for_current(fname, fname_end, tag_fname)
#endif
    char_u  *fname;
    char_u  *fname_end;
    char_u  *tag_fname;
{
    int	    c;
    int	    retval = FALSE;
    char_u  *relname;

    if (curbuf->b_ffname != NULL)	/* if the current buffer has a name */
    {
#ifdef EMACS_TAGS
	if (is_etag)
	    c = 0;	    /* to shut up GCC */
	else
#endif
	{
	    c = *fname_end;
	    *fname_end = NUL;
	}
	relname = expand_rel_name(fname, tag_fname);
	if (relname != NULL)
	{
	    retval = (fullpathcmp(relname, curbuf->b_ffname, TRUE) & FPC_SAME);
	    vim_free(relname);
	}
#ifdef EMACS_TAGS
	if (!is_etag)
#endif
	    *fname_end = c;
    }

    return retval;
}

/*
 * Find the end of the tagaddress.
 * Return OK if ";\"\t" is following, FAIL otherwise.
 */
    static int
find_extra(pp)
    char_u	**pp;
{
    char_u	*str = *pp;

    /* Repeat for addresses separated with ';' */
    for (;;)
    {
	if (isdigit(*str))
	    str = skipdigits(str);
	else if (*str == '/' || *str == '?')
	{
	    str = skip_regexp(str + 1, *str, FALSE);
	    if (*str != **pp)
		str = NULL;
	    else
		++str;
	}
	else
	    str = NULL;
	if (str == NULL || *str != ';'
		      || !(isdigit(str[1]) || str[1] == '/' || str[1] == '?'))
	    break;
	++str;	/* skip ';' */
    }

    if (str != NULL && STRNCMP(str, ";\"\t", 3) == 0)
    {
	*pp = str;
	return OK;
    }
    return FAIL;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -