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

📄 ex_cmds.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
     * curwin->w_cursor.lnum = destination (while copying)
     * line1 = start of source (while copying)
     * line2 = end of source (while copying)
     */
    if (u_save(n, n + 1) == FAIL)
	return;
    curwin->w_cursor.lnum = n;
    while (line1 <= line2)
    {
	/* need to use vim_strsave() because the line will be unlocked
	    within ml_append */
	p = vim_strsave(ml_get(line1));
	if (p != NULL)
	{
	    ml_append(curwin->w_cursor.lnum, p, (colnr_t)0, FALSE);
	    vim_free(p);
	}
		/* situation 2: skip already copied lines */
	if (line1 == n)
	    line1 = curwin->w_cursor.lnum;
	++line1;
	if (curwin->w_cursor.lnum < line1)
	    ++line1;
	if (curwin->w_cursor.lnum < line2)
	    ++line2;
	++curwin->w_cursor.lnum;
    }
    changed();
    changed_line_abv_curs();
    /*
     * TODO: should recompute w_botline for simple situations.
     */
    invalidate_botline();
    msgmore((long)lnum);
}

/*
 * Handle the ":!cmd" command.	Also for ":r !cmd" and ":w !cmd"
 * Bangs in the argument are replaced with the previously entered command.
 * Remember the argument.
 *
 * RISCOS: Bangs only replaced when followed by a space, since many
 * pathnames contain one.
 */
    void
do_bang(addr_count, line1, line2, forceit, arg, do_in, do_out)
    int		addr_count;
    linenr_t	line1, line2;
    int		forceit;
    char_u	*arg;
    int		do_in, do_out;
{
    static  char_u  *prevcmd = NULL;	    /* the previous command */
    char_u	    *newcmd = NULL;	    /* the new command */
    int		    free_newcmd = FALSE;    /* need to free() newcmd */
    int		    ins_prevcmd;
    char_u	    *t;
    char_u	    *p;
    char_u	    *trailarg;
    int		    len;
    int		    scroll_save = msg_scroll;

    /*
     * Disallow shell commands for "rvim".
     * Disallow shell commands from .exrc and .vimrc in current directory for
     * security reasons.
     */
    if (check_restricted() || check_secure())
	return;

    if (addr_count == 0)		/* :! */
    {
	msg_scroll = FALSE;	    /* don't scroll here */
	autowrite_all();
	msg_scroll = scroll_save;
    }

    /*
     * Try to find an embedded bang, like in :!<cmd> ! [args]
     * (:!! is indicated by the 'forceit' variable)
     */
    ins_prevcmd = forceit;
    trailarg = arg;
    do
    {
	len = STRLEN(trailarg) + 1;
	if (newcmd != NULL)
	    len += STRLEN(newcmd);
	if (ins_prevcmd)
	{
	    if (prevcmd == NULL)
	    {
		emsg(e_noprev);
		vim_free(newcmd);
		return;
	    }
	    len += STRLEN(prevcmd);
	}
	if ((t = alloc(len)) == NULL)
	{
	    vim_free(newcmd);
	    return;
	}
	*t = NUL;
	if (newcmd != NULL)
	    STRCAT(t, newcmd);
	if (ins_prevcmd)
	    STRCAT(t, prevcmd);
	p = t + STRLEN(t);
	STRCAT(t, trailarg);
	vim_free(newcmd);
	newcmd = t;

	/*
	 * Scan the rest of the argument for '!', which is replaced by the
	 * previous command.  "\!" is replaced by "!" (this is vi compatible).
	 */
	trailarg = NULL;
	while (*p)
	{
	    if (*p == '!'
#ifdef RISCOS
			&& (p[1] == ' ' || p[1] == NUL)
#endif
					)
	    {
		if (p > newcmd && p[-1] == '\\')
		    mch_memmove(p - 1, p, (size_t)(STRLEN(p) + 1));
		else
		{
		    trailarg = p;
		    *trailarg++ = NUL;
		    ins_prevcmd = TRUE;
		    break;
		}
	    }
	    ++p;
	}
    } while (trailarg != NULL);

    vim_free(prevcmd);
    prevcmd = newcmd;

    if (bangredo)	    /* put cmd in redo buffer for ! command */
    {
	AppendToRedobuff(prevcmd);
	AppendToRedobuff((char_u *)"\n");
	bangredo = FALSE;
    }
    /*
     * Add quotes around the command, for shells that need them.
     */
    if (*p_shq != NUL)
    {
	newcmd = alloc((unsigned)(STRLEN(prevcmd) + 2 * STRLEN(p_shq) + 1));
	if (newcmd == NULL)
	    return;
	STRCPY(newcmd, p_shq);
	STRCAT(newcmd, prevcmd);
	STRCAT(newcmd, p_shq);
	free_newcmd = TRUE;
    }
    if (addr_count == 0)		/* :! */
    {
	    /* echo the command */
	msg_start();
	msg_putchar(':');
	msg_putchar('!');
	msg_outtrans(newcmd);
	msg_clr_eos();
	windgoto(msg_row, msg_col);

	do_shell(newcmd, 0);
    }
    else				/* :range! */
	/* Careful: This may recursively call do_bang() again! (because of
	 * autocommands) */
	do_filter(line1, line2, newcmd, do_in, do_out);
    if (free_newcmd)
	vim_free(newcmd);
}

/*
 * call a shell to execute a command
 *
 * RISCOS GUI: If cmd starts with '~' then don't output anything, and don't
 * wait for <Return> afterwards.
  */
    void
do_shell(cmd, flags)
    char_u  *cmd;
    int	    flags;	/* may be SHELL_DOOUT when output is redirected */
{
    BUF	    *buf;
#ifndef USE_GUI_WIN32
    int	    save_nwr;
#endif
#ifdef WIN32
    int	    winstart;
#endif
#ifdef RISCOS
    int	    silent = FALSE;
#endif

    /*
     * Disallow shell commands for "rvim".
     * Disallow shell commands from .exrc and .vimrc in current directory for
     * security reasons.
     */
    if (check_restricted() || check_secure())
    {
	msg_end();
	return;
    }

#ifdef RISCOS
    while (*cmd == ' ')
	cmd++;
    if (*cmd == '~')
    {
	/* Useful for commands with no output, or those which open
	 * another window for their output.
	 */
	cmd++;
# ifdef USE_GUI
	if (gui.in_use)
	{
	    silent = TRUE;
	    flags |= SHELL_FILTER;	/* Makes call_shell() silent too */
	}
# endif
    }
#endif

#ifdef WIN32
    /*
     * Check if external commands are allowed now.
     */
    if (can_end_termcap_mode(TRUE) == FALSE)
	return;

    /*
     * Check if ":!start" is used.
     */
    if (cmd)
	winstart = (STRNICMP(cmd, "start ", 6) == 0);
#endif

    /*
     * For autocommands we want to get the output on the current screen, to
     * avoid having to type return below.
     */
    msg_putchar('\r');			/* put cursor at start of line */
#ifdef AUTOCMD
    if (!autocmd_busy)
#endif
    {
#ifdef WIN32
	if (!winstart)
#endif
	    stoptermcap();
    }
#ifdef RISCOS
    if (!silent)
#endif
	msg_putchar('\n');			/* may shift screen one line up */

    /* warning message before calling the shell */
    if (p_warn
#ifdef AUTOCMD
		&& !autocmd_busy
#endif
#ifdef RISCOS
		&& !silent
#endif
				   )
	for (buf = firstbuf; buf; buf = buf->b_next)
	    if (buf_changed(buf))
	    {
#ifdef USE_GUI_WIN32
		if (!winstart)
		    starttermcap();	    /* don't want a message box here */
#endif
		MSG_PUTS("[No write since last change]\n");
#ifdef USE_GUI_WIN32
		if (!winstart)
		    stoptermcap();
#endif
		break;
	    }

/* This windgoto is required for when the '\n' resulted in a "delete line 1"
 * command to the terminal. */

    if (!swapping_screen())
	windgoto(msg_row, msg_col);
    cursor_on();
    (void)call_shell(cmd, SHELL_COOKED | flags);
    need_check_timestamps = TRUE;

/*
 * put the message cursor at the end of the screen, avoids wait_return() to
 * overwrite the text that the external command showed
 */
    if (!swapping_screen())
    {
	msg_row = Rows - 1;
	msg_col = 0;
    }

#ifdef AUTOCMD
    if (autocmd_busy)
	must_redraw = CLEAR;
    else
#endif
    {
	/*
	 * For ":sh" there is no need to call wait_return(), just redraw.
	 * Also for the Win32 GUI (the output is in a console window).
	 * Otherwise there is probably text on the screen that the user wants
	 * to read before redrawing, so call wait_return().
	 */
#ifndef USE_GUI_WIN32
# ifdef WIN32
	if ((cmd == NULL) || (winstart && !need_wait_return))
	{
	    must_redraw = CLEAR;
# elif defined(RISCOS)
	if (cmd == NULL || silent)
	{
	    if (!silent)
		must_redraw = CLEAR;
# else
	if (cmd == NULL)
	{
	    must_redraw = CLEAR;
# endif
#endif
	    need_wait_return = FALSE;
	    dont_wait_return = TRUE;
#ifndef USE_GUI_WIN32
	}
	else
	{
	    /*
	     * If we switch screens when starttermcap() is called, we really
	     * want to wait for "hit return to continue".
	     */
	    save_nwr = no_wait_return;
	    if (swapping_screen())
		no_wait_return = FALSE;
#ifdef AMIGA
	    wait_return(term_console ? -1 : TRUE);	/* see below */
#else
	    wait_return(TRUE);
#endif
	    no_wait_return = save_nwr;
	}
#endif /* USE_GUI_WIN32 */

#ifdef WIN32
	if (!winstart) /*if winstart==TRUE, never stopped termcap!*/
#endif
	    starttermcap();	/* start termcap if not done by wait_return() */

	/*
	 * In an Amiga window redrawing is caused by asking the window size.
	 * If we got an interrupt this will not work. The chance that the
	 * window size is wrong is very small, but we need to redraw the
	 * screen.  Don't do this if ':' hit in wait_return().	THIS IS UGLY
	 * but it saves an extra redraw.
	 */
#ifdef AMIGA
	if (skip_redraw)		/* ':' hit in wait_return() */
	    must_redraw = CLEAR;
	else if (term_console)
	{
	    OUT_STR("\033[0 q");	/* get window size */
	    if (got_int)
		must_redraw = CLEAR;	/* if got_int is TRUE, redraw needed */
	    else
		must_redraw = 0;	/* no extra redraw needed */
	}
#endif /* AMIGA */
    }

    /* display any error messages now */
    mch_display_error();
}

/*
 * do_filter: filter lines through a command given by the user
 *
 * We use temp files and the call_shell() routine here. This would normally
 * be done using pipes on a UNIX machine, but this is more portable to
 * non-unix machines. The call_shell() routine needs to be able
 * to deal with redirection somehow, and should handle things like looking
 * at the PATH env. variable, and adding reasonable extensions to the
 * command name given by the user. All reasonable versions of call_shell()
 * do this.
 * We use input redirection if do_in is TRUE.
 * We use output redirection if do_out is TRUE.
 */
    static void
do_filter(line1, line2, buff, do_in, do_out)
    linenr_t	line1, line2;
    char_u	*buff;
    int		do_in, do_out;
{
    char_u	*itmp = NULL;
    char_u	*otmp = NULL;
    linenr_t	linecount;
    FPOS	cursor_save;
#ifdef AUTOCMD
    BUF		*old_curbuf = curbuf;
#endif

    if (*buff == NUL)	    /* no filter command */
	return;

#ifdef WIN32
    /*
     * Check if external commands are allowed now.
     */
    if (can_end_termcap_mode(TRUE) == FALSE)
	return;
#endif

    cursor_save = curwin->w_cursor;
    linecount = line2 - line1 + 1;
    curwin->w_cursor.lnum = line1;
    curwin->w_cursor.col = 0;
    changed_line_abv_curs();
    invalidate_botline();

    /*
     * 1. Form temp file names
     * 2. Write the lines to a temp file
     * 3. Run the filter command on the temp file
     * 4. Read the output of the command into the buffer
     * 5. Delete the original lines to be filtered
     * 6. Remove the temp files
     */

    if ((do_in && (itmp = vim_tempname('i')) == NULL) ||
			       (do_out && (otmp = vim_tempname('o')) == NULL))
    {
	emsg(e_notmp);
	goto filterend;
    }

/*
 * The writing and reading of temp files will not be shown.
 * Vi also doesn't do this and the messages are not very informative.
 */
    ++no_wait_return;		/* don't call wait_return() while busy */
    if (do_in && buf_write(curbuf, itmp, NULL, line1, line2,
					   FALSE, FALSE, FALSE, TRUE) == FAIL)
    {
	msg_putchar('\n');		    /* keep message from buf_write() */
	--no_wait_return;
	(void)emsg2(e_notcreate, itmp);	    /* will call wait_return */
	goto filterend;
    }
#ifdef AUTOCMD
    if (curbuf != old_curbuf)
	goto filterend;
#endif

    if (!do_out)
	msg_putchar('\n');

#if (defined(UNIX) && !defined(ARCHIE)) || defined(OS2)
/*
 * put braces around the command (for concatenated commands)
 */
    sprintf((char *)IObuff, "(%s)", (char *)buff);
    if (do_in)
    {
	STRCAT(IObuff, " < ");
	STRCAT(IObuff, itmp);
    }
#else
/*
 * for shells that don't understand braces around commands, at least allow
 * the use of commands in a pipe.
 */
    STRCPY(IObuff, buff);
    if (do_in)
    {
	char_u	    *p;

	/*
	 * If there is a pipe, we have to put the '<' in front of it.
	 * Don't do this when 'shellquote' is not empty, otherwise the
	 * redirection would be inside the quotes.
	 */
	p = vim_strchr(IObuff, '|');
	if (p && *p_shq == NUL)
	    *p = NUL;
#ifdef RISCOS
	STRCAT(IObuff, " { < ");    /* Use RISC OS notation for input. */
	STRCAT(IObuff, itmp);
	STRCAT(IObuff, " } ");
#else
	STRCAT(IObuff, " <");	    /* " < " causes problems on Amiga */
	STRCAT(IObuff, itmp);
#endif
	p = vim_strchr(buff, '|');
	if (p && *p_shq == NUL)
	    STRCAT(IObuff, p);
    }
#endif
    if (do_out)
    {
	char_u *p;

	if ((p = vim_strchr(p_srr, '%')) != NULL && p[1] == 's')
	{
	    p = IObuff + STRLEN(IObuff);

⌨️ 快捷键说明

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