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

📄 buffer.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 4 页
字号:
	    }
	    /* in non-help buffer, try to skip help buffers, and vv */
	    if (buf->b_ml.ml_mfp != NULL && buf->b_help == curbuf->b_help)
		break;
	    if (forward)
		buf = buf->b_next;
	    else
		buf = buf->b_prev;
	}
	if (buf == NULL)	/* No loaded buffers, just take one */
	{
	    if (curbuf->b_next != NULL)
		buf = curbuf->b_next;
	    else
		buf = curbuf->b_prev;
	}
    }

    /*
     * make buf current buffer
     */
    if (action == DOBUF_SPLIT)	    /* split window first */
    {
	if (win_split(0, FALSE, FALSE) == FAIL)
	    return FAIL;
    }

    /* go to current buffer - nothing to do */
    if (buf == curbuf)
	return OK;

    /*
     * Check if the current buffer may be abandoned.
     */
    if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit))
    {
	EMSG(e_nowrtmsg);
	return FAIL;
    }

    setpcmark();
    curwin->w_alt_fnum = curbuf->b_fnum; /* remember alternate file */
    buflist_altfpos();			 /* remember curpos */

    /* close_windows() or apply_autocmds() may change curbuf */
    delbuf = curbuf;

#ifdef AUTOCMD
    apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
    if (buf_valid(delbuf))
#endif
    {
	if (action == DOBUF_UNLOAD || action == DOBUF_DEL)
	    close_windows(delbuf);
	if (buf_valid(delbuf))
	    close_buffer(delbuf == curwin->w_buffer ? curwin : NULL, delbuf,
		    (action == DOBUF_GOTO && !p_hid && !buf_changed(delbuf))
			     || action == DOBUF_UNLOAD || action == DOBUF_DEL,
		      action == DOBUF_DEL);
    }
#ifdef AUTOCMD
    if (buf_valid(buf))	    /* an autocommand may have deleted buf! */
#endif
	enter_buffer(buf);
    return OK;
}

/*
 * enter a new current buffer.
 * (old curbuf must have been freed already)
 */
    static void
enter_buffer(buf)
    BUF	    *buf;
{
    buf_copy_options(curbuf, buf, BCO_ENTER | BCO_NOHELP);
    curwin->w_buffer = buf;
    curbuf = buf;
    ++curbuf->b_nwindows;
    if (curbuf->b_ml.ml_mfp == NULL)	/* need to load the file */
	open_buffer(FALSE);
    else
    {
	need_fileinfo = TRUE;		/* display file info after redraw */
	buf_check_timestamp(curbuf);	/* check if file has changed */
#ifdef AUTOCMD
	apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
#endif
    }
    buflist_getfpos();			/* restore curpos.lnum and possibly
					 * curpos.col */
    check_arg_idx();			/* check for valid arg_idx */
    maketitle();
    scroll_cursor_halfway(FALSE);	/* redisplay at correct position */
    update_screen(NOT_VALID);
}

/*
 * functions for dealing with the buffer list
 */

/*
 * Add a file name to the buffer list. Return a pointer to the buffer.
 * If the same file name already exists return a pointer to that buffer.
 * If it does not exist, or if fname == NULL, a new entry is created.
 * If use_curbuf is TRUE, may use current buffer.
 * This is the ONLY way to create a new buffer.
 */
static int  top_file_num = 1;		/* highest file number */

    BUF *
buflist_new(ffname, sfname, lnum, use_curbuf)
    char_u	*ffname;
    char_u	*sfname;
    linenr_t	lnum;
    int		use_curbuf;
{
    BUF		*buf;

    fname_expand(&ffname, &sfname);	/* will allocate ffname */

    /*
     * If file name already exists in the list, update the entry.
     */
    if (ffname != NULL && (buf = buflist_findname(ffname)) != NULL)
    {
	vim_free(ffname);
	if (lnum != 0)
	    buflist_setfpos(buf, lnum, (colnr_t)0);
	/* copy the options now, if 'cpo' doesn't have 's' and not done
	 * already */
	buf_copy_options(curbuf, buf, 0);
	return buf;
    }

    /*
     * If the current buffer has no name and no contents, use the current
     * buffer.	Otherwise: Need to allocate a new buffer structure.
     *
     * This is the ONLY place where a new buffer structure is allocated!
     */
    if (use_curbuf && curbuf != NULL && curbuf->b_ffname == NULL &&
		curbuf->b_nwindows <= 1 &&
		(curbuf->b_ml.ml_mfp == NULL || bufempty()))
    {
	buf = curbuf;
#ifdef AUTOCMD
	/* It's like this buffer is deleted. */
	apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
#endif
    }
    else
    {
	buf = (BUF *)alloc_clear((unsigned)sizeof(BUF));
	if (buf == NULL)
	{
	    vim_free(ffname);
	    return NULL;
	}
    }

    if (ffname != NULL)
    {
	buf->b_ffname = ffname;
	buf->b_sfname = vim_strsave(sfname);
    }
    if (buf->b_winfpos == NULL)
	buf->b_winfpos = (WINFPOS *)alloc((unsigned)sizeof(WINFPOS));
    if ((ffname != NULL && (buf->b_ffname == NULL ||
			 buf->b_sfname == NULL)) || buf->b_winfpos == NULL)
    {
	vim_free(buf->b_ffname);
	buf->b_ffname = NULL;
	vim_free(buf->b_sfname);
	buf->b_sfname = NULL;
	if (buf != curbuf)
	    free_buffer(buf);
	return NULL;
    }

    if (buf == curbuf)
    {
	buf_freeall(buf, FALSE); /* free all things allocated for this buffer */
	buf->b_nwindows = 0;
    }
    else
    {
	/*
	 * put new buffer at the end of the buffer list
	 */
	buf->b_next = NULL;
	if (firstbuf == NULL)		/* buffer list is empty */
	{
	    buf->b_prev = NULL;
	    firstbuf = buf;
	}
	else				/* append new buffer at end of list */
	{
	    lastbuf->b_next = buf;
	    buf->b_prev = lastbuf;
	}
	lastbuf = buf;

	buf->b_fnum = top_file_num++;
	if (top_file_num < 0)		/* wrap around (may cause duplicates) */
	{
	    EMSG("Warning: List of file names overflow");
	    ui_delay(3000L, TRUE);	/* make sure it is noticed */
	    top_file_num = 1;
	}

	buf->b_winfpos->wl_fpos.lnum = lnum;
	buf->b_winfpos->wl_fpos.col = 0;
	buf->b_winfpos->wl_next = NULL;
	buf->b_winfpos->wl_prev = NULL;
	buf->b_winfpos->wl_win = curwin;

#ifdef WANT_EVAL
	var_init(&buf->b_vars);	    /* init internal variables */
#endif
	/*
	 * Always copy the options from the current buffer.
	 */
	buf_copy_options(curbuf, buf, BCO_ALWAYS);
    }

    buf->b_fname = buf->b_sfname;
    buf->b_u_synced = TRUE;
    buf->b_flags |= BF_CHECK_RO | BF_NEVERLOADED;
    buf_clear(buf);
    clrallmarks(buf);		    /* clear marks */
    fmarks_check_names(buf);	    /* check file marks for this file */

    return buf;
}

/*
 * Get the highest buffer number.  Note that some buffers may have been
 * deleted.
 */
    int
buflist_maxbufnr()
{
    return (top_file_num - 1);
}

/*
 * Free the memory for the options of a buffer.
 */
    void
free_buf_options(buf, free_p_ff)
    BUF	    *buf;
    int	    free_p_ff;	    /* also free 'fileformat'? */
{
    if (free_p_ff)
    {
	free_string_option(buf->b_p_ff);
#ifdef MULTI_BYTE
	free_string_option(buf->b_p_fe);
#endif
    }
    free_string_option(buf->b_p_mps);
    free_string_option(buf->b_p_fo);
    free_string_option(buf->b_p_isk);
    free_string_option(buf->b_p_com);
    free_string_option(buf->b_p_nf);
#ifdef SYNTAX_HL
    free_string_option(buf->b_p_syn);
#endif
#ifdef CINDENT
    free_string_option(buf->b_p_cink);
    free_string_option(buf->b_p_cino);
#endif
#if defined(CINDENT) || defined(SMARTINDENT)
    free_string_option(buf->b_p_cinw);
#endif
#ifdef INSERT_EXPAND
    free_string_option(buf->b_p_cpt);
#endif
}

/*
 * get alternate file n
 * set linenr to lnum or altfpos.lnum if lnum == 0
 *	also set cursor column to altfpos.col if 'startofline' is not set.
 * if (options & GETF_SETMARK) call setpcmark()
 * if (options & GETF_ALT) we are jumping to an alternate file.
 *
 * return FAIL for failure, OK for success
 */
    int
buflist_getfile(n, lnum, options, forceit)
    int		n;
    linenr_t	lnum;
    int		options;
    int		forceit;
{
    BUF	    *buf;
    FPOS    *fpos;
    colnr_t col;

    buf = buflist_findnr(n);
    if (buf == NULL)
    {
	if ((options & GETF_ALT) && n == 0)
	    emsg(e_noalt);
	else
	    EMSGN("buffer %ld not found", n);
	return FAIL;
    }

    /* if alternate file is the current buffer, nothing to do */
    if (buf == curbuf)
	return OK;

    /* altfpos may be changed by getfile(), get it now */
    if (lnum == 0)
    {
	fpos = buflist_findfpos(buf);
	lnum = fpos->lnum;
	col = fpos->col;
    }
    else
	col = 0;

    ++RedrawingDisabled;
    if (getfile(buf->b_fnum, NULL, NULL, (options & GETF_SETMARK),
							  lnum, forceit) <= 0)
    {
	--RedrawingDisabled;

	/* cursor is at to BOL and w_cursor.lnum is checked due to getfile() */
	if (!p_sol && col != 0)
	{
	    curwin->w_cursor.col = col;
	    check_cursor_col();
	}
	return OK;
    }
    --RedrawingDisabled;
    return FAIL;
}

/*
 * go to the last know line number for the current buffer
 */
    void
buflist_getfpos()
{
    FPOS	*fpos;

    fpos = buflist_findfpos(curbuf);

    curwin->w_cursor.lnum = fpos->lnum;
    check_cursor_lnum();

    if (p_sol)
	curwin->w_cursor.col = 0;
    else
    {
	curwin->w_cursor.col = fpos->col;
	check_cursor_col();
    }
}

/*
 * find file in buffer list by name (it has to be for the current window)
 * 'ffname' must have a full path.
 */
    BUF *
buflist_findname(ffname)
    char_u	*ffname;
{
    BUF		*buf;

    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
	if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0)
	    return (buf);
    return NULL;
}

/*
 * Find file in buffer list by a regexppattern.
 * Return fnum of the found buffer, < 0 for error.
 */
    int
buflist_findpat(pattern, pattern_end)
    char_u	*pattern;
    char_u	*pattern_end;	    /* pointer to first char after pattern */
{
    BUF		*buf;
    vim_regexp	*prog;
    int		fnum = -1;
    char_u	*pat;
    char_u	*match;
    int		attempt;
    char_u	*p;

    if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#'))
    {
	if (*pattern == '%')
	    fnum = curbuf->b_fnum;
	else
	    fnum = curwin->w_alt_fnum;
    }

    /*
     * Try four ways of matching:
     * attempt == 0: without '^' or '$' (at any position)
     * attempt == 1: with '^' at start (only at postion 0)
     * attempt == 2: with '$' at end (only match at end)
     * attempt == 3: with '^' at start and '$' at end (only full match)
     */
    else for (attempt = 0; attempt <= 3; ++attempt)
    {
	/* may add '^' and '$' */
	pat = file_pat_to_reg_pat(pattern, pattern_end, NULL);
	if (pat == NULL)
	    return -1;
	if (attempt < 2)
	{
	    p = pat + STRLEN(pat) - 1;
	    if (p > pat && *p == '$')		    /* remove '$' */
		*p = NUL;
	}
	p = pat;
	if (*p == '^' && !(attempt & 1))	    /* remove '^' */
	    ++p;
	prog = vim_regcomp(p, (int)p_magic);
	vim_free(pat);
	if (prog == NULL)
	    return -1;

	for (buf = firstbuf; buf != NULL; buf = buf->b_next)
	{
	    match = buflist_match(prog, buf);
	    if (match != NULL)
	    {
		if (fnum >= 0)		/* already found a match */
		{
		    fnum = -2;
		    break;
		}
		fnum = buf->b_fnum;	/* remember first match */
	    }
	}
	vim_free(prog);
	if (fnum >= 0)			/* found one match */
	    break;
    }

    if (fnum == -2)
	EMSG2("More than one match for %s", pattern);
    else if (fnum < 1)
	EMSG2("No matching buffer for %s", pattern);
    return fnum;
}

/*
 * Find all buffer names that match.
 * For command line expansion of ":buf" and ":sbuf".
 * Return OK if matches found, FAIL otherwise.
 */
    int
ExpandBufnames(pat, num_file, file, options)
    char_u	*pat;
    int		*num_file;
    char_u	***file;
    int		options;
{
    int		count = 0;
    BUF		*buf;
    int		round;
    char_u	*p;
    int		attempt;
    vim_regexp	*prog;

    *num_file = 0;		    /* return values in case of FAIL */
    *file = NULL;

    /*
     * attempt == 1: try match with    '^', match at start
     * attempt == 2: try match without '^', match anywhere
     */
    for (attempt = 1; attempt <= 2; ++attempt)
    {
	if (attempt == 2)
	{
	    if (*pat != '^')	    /* there's no '^', no need to try again */
		break;
	    ++pat;		    /* skip the '^' */
	}
	prog = vim_regcomp(pat, (int)p_magic);
	if (prog == NULL)
	    return FAIL;

	/*
	 * round == 1: Count the matches.
	 * round == 2: Build the array to keep the matches.
	 */
	for (round = 1; round <= 2; ++round)
	{
	    count = 0;
	    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
	    {
		p = buflist_match(prog, buf);
		if (p != NULL)
		{
		    if (round == 1)
			++count;
		    else
		    {
			if (options & WILD_HOME_REPLACE)
			    p = home_replace_save(buf, p);
			else
			    p = vim_strsave(p);
			(*file)[count++] = p;
		    }
		}
	    }
	    if (count == 0)	/* no match found, break here */
		break;
	    if (round == 1)
	    {
		*file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
		if (*file == NULL)
		{
		    vim_free(prog);
		    return FAIL;
		}
	    }
	}
	vim_free(prog);
	if (count)		/* match(es) found, break here */
	    break;
    }

    *num_file = count;
    return (count == 0 ? FAIL : OK);
}

/*
 * Check for a match on the file name for buffer "buf" with regex prog "prog".
 */
    static char_u *
buflist_match(prog, buf)
    vim_regexp	*prog;
    BUF		*buf;
{
    char_u  *match;
#ifdef CASE_INSENSITIVE_FILENAME
    int	    save_reg_ic = reg_ic;

    reg_ic = TRUE;		/* Always ignore case */
#endif

    /* First try the short file name, then the long file name. */
    match = buflist_match_try(prog, buf->b_sfname);
    if (match == NULL)
	match = buflist_match_try(prog, buf->b_ffname);

#ifdef CASE_INSENSITIVE_FILENAME
    reg_ic = save_reg_ic;
#endif

    return match;
}

    static char_u *
buflist_match_try(prog, name)
    vim_regexp	*prog;
    char_u	*name;
{
    char_u  *match = NULL;
    char_u  *p;

    if (name != NULL)
    {
	if (vim_regexec(prog, name, TRUE) != 0)
	    match = name;
	else
	{
	    /* Replace $(HOME) with '~' and try matching again. */

⌨️ 快捷键说明

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