📄 ex_cmds.c
字号:
* 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 + -