ex_cmds.c
资源名称:vim53src.zip [点击查看]
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:76k
源码类别:
编辑器/阅读器
开发平台:
DOS
- /* 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.
- */
- /*
- * ex_cmds.c: functions for command line commands
- */
- #include "vim.h"
- #ifdef EX_EXTRA
- static int linelen __ARGS((int *has_tab));
- #endif
- static void do_filter __ARGS((linenr_t line1, linenr_t line2,
- char_u *buff, int do_in, int do_out));
- #ifdef VIMINFO
- static char_u *viminfo_filename __ARGS((char_u *));
- static void do_viminfo __ARGS((FILE *fp_in, FILE *fp_out, int want_info,
- int want_marks, int force_read));
- static int read_viminfo_up_to_marks __ARGS((char_u *line, FILE *fp,
- int forceit, int writing));
- #endif
- static int do_sub_msg __ARGS((void));
- static int
- #ifdef __BORLANDC__
- _RTLENTRYF
- #endif
- help_compare __ARGS((const void *s1, const void *s2));
- void
- do_ascii()
- {
- int c;
- char buf1[20];
- char buf2[20];
- char_u buf3[3];
- #ifdef MULTI_BYTE
- int c2 = NUL;
- #endif
- c = gchar_cursor();
- if (c == NUL)
- {
- MSG("empty line");
- return;
- }
- #ifdef MULTI_BYTE
- /* split lead from trail */
- c2 = (((unsigned)c >> 8) & 0xff);
- c = (c & 0xff);
- if (c2)
- {
- buf2[0] = c;
- buf2[1] = c2;
- buf2[2] = NUL;
- sprintf((char *)IObuff, "%s %d %d, Hex %02x %02x, Octal %03o %03o",
- buf2, c,c2, c,c2, c,c2);
- }
- else
- #endif
- {
- if (c == NL) /* NUL is stored as NL */
- c = NUL;
- if (vim_isprintc(c) && (c < ' ' || c > '~'))
- {
- transchar_nonprint(buf3, c);
- sprintf(buf1, " <%s>", (char *)buf3);
- }
- else
- buf1[0] = NUL;
- if (c >= 0x80)
- sprintf(buf2, " <M-%s>", transchar(c & 0x7f));
- else
- buf2[0] = NUL;
- sprintf((char *)IObuff, "<%s>%s%s %d, Hex %02x, Octal %03o",
- transchar(c), buf1, buf2, c, c, c);
- }
- msg(IObuff);
- }
- #ifdef EX_EXTRA
- /*
- * Handle ":left", ":center" and ":right" commands: align text.
- */
- void
- do_align(eap)
- EXARG *eap;
- {
- FPOS save_curpos;
- int len;
- int indent = 0;
- int new_indent;
- int has_tab;
- int width;
- #ifdef RIGHTLEFT
- if (curwin->w_p_rl)
- {
- /* switch left and right aligning */
- if (eap->cmdidx == CMD_right)
- eap->cmdidx = CMD_left;
- else if (eap->cmdidx == CMD_left)
- eap->cmdidx = CMD_right;
- }
- #endif
- width = atoi((char *)eap->arg);
- save_curpos = curwin->w_cursor;
- if (eap->cmdidx == CMD_left) /* width is used for new indent */
- {
- if (width >= 0)
- indent = width;
- }
- else
- {
- /*
- * if 'textwidth' set, use it
- * else if 'wrapmargin' set, use it
- * if invalid value, use 80
- */
- if (width <= 0)
- width = curbuf->b_p_tw;
- if (width == 0 && curbuf->b_p_wm > 0)
- width = Columns - curbuf->b_p_wm;
- if (width <= 0)
- width = 80;
- }
- if (u_save((linenr_t)(eap->line1 - 1), (linenr_t)(eap->line2 + 1)) == FAIL)
- return;
- #ifdef SYNTAX_HL
- /* recompute syntax hl., starting with first line */
- syn_changed(eap->line1);
- #endif
- for (curwin->w_cursor.lnum = eap->line1;
- curwin->w_cursor.lnum <= eap->line2; ++curwin->w_cursor.lnum)
- {
- if (eap->cmdidx == CMD_left) /* left align */
- new_indent = indent;
- else
- {
- len = linelen(eap->cmdidx == CMD_right ? &has_tab
- : NULL) - get_indent();
- if (len <= 0) /* skip blank lines */
- continue;
- if (eap->cmdidx == CMD_center)
- new_indent = (width - len) / 2;
- else
- {
- new_indent = width - len; /* right align */
- /*
- * Make sure that embedded TABs don't make the text go too far
- * to the right.
- */
- if (has_tab)
- while (new_indent > 0)
- {
- set_indent(new_indent, TRUE); /* set indent */
- if (linelen(NULL) <= width)
- {
- /*
- * Now try to move the line as much as possible to
- * the right. Stop when it moves too far.
- */
- do
- set_indent(++new_indent, TRUE); /* set indent */
- while (linelen(NULL) <= width);
- --new_indent;
- break;
- }
- --new_indent;
- }
- }
- }
- if (new_indent < 0)
- new_indent = 0;
- set_indent(new_indent, TRUE); /* set indent */
- }
- curwin->w_cursor = save_curpos;
- beginline(BL_WHITE | BL_FIX);
- /*
- * If the cursor is after the first changed line, its position needs to be
- * updated.
- */
- if (curwin->w_cursor.lnum > eap->line1)
- {
- changed_line_abv_curs();
- invalidate_botline();
- }
- else if (curwin->w_cursor.lnum == eap->line1)
- changed_cline_bef_curs();
- /*
- * If the start of the aligned lines is before botline, it may have become
- * approximated (lines got longer or shorter).
- */
- if (botline_approximated() && eap->line1 < curwin->w_botline)
- approximate_botline();
- update_screen(NOT_VALID);
- }
- /*
- * Get the length of the current line, excluding trailing white space.
- */
- static int
- linelen(has_tab)
- int *has_tab;
- {
- char_u *line;
- char_u *first;
- char_u *last;
- int save;
- int len;
- /* find the first non-blank character */
- line = ml_get_curline();
- first = skipwhite(line);
- /* find the character after the last non-blank character */
- for (last = first + STRLEN(first);
- last > first && vim_iswhite(last[-1]); --last)
- ;
- save = *last;
- *last = NUL;
- len = linetabsize(line); /* get line length */
- if (has_tab != NULL) /* check for embedded TAB */
- *has_tab = (vim_strrchr(first, TAB) != NULL);
- *last = save;
- return len;
- }
- /*
- * Handle ":retab" command.
- */
- void
- do_retab(eap)
- EXARG *eap;
- {
- linenr_t lnum;
- int got_tab = FALSE;
- long num_spaces = 0;
- long num_tabs;
- long len;
- long col;
- long vcol;
- long start_col = 0; /* For start of white-space string */
- long start_vcol = 0; /* For start of white-space string */
- int temp;
- long old_len;
- char_u *ptr;
- char_u *new_line = (char_u *)1; /* init to non-NULL */
- int did_something = FALSE;
- int did_undo; /* called u_save for current line */
- int new_ts;
- int save_list;
- save_list = curwin->w_p_list;
- curwin->w_p_list = 0; /* don't want list mode here */
- #ifdef SYNTAX_HL
- /* recompute syntax hl. starting with line1 */
- syn_changed(eap->line1);
- #endif
- new_ts = getdigits(&(eap->arg));
- if (new_ts == 0)
- new_ts = curbuf->b_p_ts;
- for (lnum = eap->line1; !got_int && lnum <= eap->line2; ++lnum)
- {
- ptr = ml_get(lnum);
- col = 0;
- vcol = 0;
- did_undo = FALSE;
- for (;;)
- {
- if (vim_iswhite(ptr[col]))
- {
- if (!got_tab && num_spaces == 0)
- {
- /* First consecutive white-space */
- start_vcol = vcol;
- start_col = col;
- }
- if (ptr[col] == ' ')
- num_spaces++;
- else
- got_tab = TRUE;
- }
- else
- {
- if (got_tab || (eap->forceit && num_spaces > 1))
- {
- /* Retabulate this string of white-space */
- /* len is virtual length of white string */
- len = num_spaces = vcol - start_vcol;
- num_tabs = 0;
- if (!curbuf->b_p_et)
- {
- temp = new_ts - (start_vcol % new_ts);
- if (num_spaces >= temp)
- {
- num_spaces -= temp;
- num_tabs++;
- }
- num_tabs += num_spaces / new_ts;
- num_spaces -= (num_spaces / new_ts) * new_ts;
- }
- if (curbuf->b_p_et || got_tab ||
- (num_spaces + num_tabs < len))
- {
- if (did_undo == FALSE)
- {
- did_undo = TRUE;
- if (u_save((linenr_t)(lnum - 1),
- (linenr_t)(lnum + 1)) == FAIL)
- {
- new_line = NULL; /* flag out-of-memory */
- break;
- }
- }
- /* len is actual number of white characters used */
- len = num_spaces + num_tabs;
- old_len = STRLEN(ptr);
- new_line = lalloc(old_len - col + start_col + len + 1,
- TRUE);
- if (new_line == NULL)
- break;
- if (start_col > 0)
- mch_memmove(new_line, ptr, (size_t)start_col);
- mch_memmove(new_line + start_col + len,
- ptr + col, (size_t)(old_len - col + 1));
- ptr = new_line + start_col;
- for (col = 0; col < len; col++)
- ptr[col] = (col < num_tabs) ? 't' : ' ';
- ml_replace(lnum, new_line, FALSE);
- did_something = TRUE;
- ptr = new_line;
- col = start_col + len;
- }
- }
- got_tab = FALSE;
- num_spaces = 0;
- }
- if (ptr[col] == NUL)
- break;
- vcol += chartabsize(ptr[col++], (colnr_t)vcol);
- }
- if (new_line == NULL) /* out of memory */
- break;
- line_breakcheck();
- }
- if (got_int)
- emsg(e_interr);
- if (did_something)
- changed();
- curwin->w_p_list = save_list; /* restore 'list' */
- if (curbuf->b_p_ts != new_ts || did_something)
- {
- /*
- * Cursor may need updating when change is before or at the cursor
- * line. w_botline may be wrong a bit now.
- */
- if (curbuf->b_p_ts != new_ts || eap->line1 < curwin->w_cursor.lnum)
- changed_line_abv_curs(); /* recompute cursor pos compl. */
- else if (eap->line1 == curwin->w_cursor.lnum)
- changed_cline_bef_curs(); /* recompute curosr pos partly */
- approximate_botline();
- }
- curbuf->b_p_ts = new_ts;
- coladvance(curwin->w_curswant);
- u_clearline();
- update_screen(NOT_VALID);
- }
- #endif
- /*
- * :move command - move lines line1-line2 to line dest
- *
- * return FAIL for failure, OK otherwise
- */
- int
- do_move(line1, line2, dest)
- linenr_t line1;
- linenr_t line2;
- linenr_t dest;
- {
- char_u *str;
- linenr_t l;
- linenr_t extra; /* Num lines added before line1 */
- linenr_t num_lines; /* Num lines moved */
- linenr_t last_line; /* Last line in file after adding new text */
- if (dest >= line1 && dest < line2)
- {
- EMSG("Move lines into themselves");
- return FAIL;
- }
- num_lines = line2 - line1 + 1;
- /*
- * First we copy the old text to its new location -- webb
- * Also copy the flag that ":global" command uses.
- */
- if (u_save(dest, dest + 1) == FAIL)
- return FAIL;
- for (extra = 0, l = line1; l <= line2; l++)
- {
- str = vim_strsave(ml_get(l + extra));
- if (str != NULL)
- {
- ml_append(dest + l - line1, str, (colnr_t)0, FALSE);
- vim_free(str);
- if (dest < line1)
- extra++;
- }
- }
- /*
- * Now we must be careful adjusting our marks so that we don't overlap our
- * mark_adjust() calls.
- *
- * We adjust the marks within the old text so that they refer to the
- * last lines of the file (temporarily), because we know no other marks
- * will be set there since these line numbers did not exist until we added
- * our new lines.
- *
- * Then we adjust the marks on lines between the old and new text positions
- * (either forwards or backwards).
- *
- * And Finally we adjust the marks we put at the end of the file back to
- * their final destination at the new text position -- webb
- */
- last_line = curbuf->b_ml.ml_line_count;
- mark_adjust(line1, line2, last_line - line2, 0L);
- if (dest >= line2)
- {
- mark_adjust(line2 + 1, dest, -num_lines, 0L);
- curbuf->b_op_start.lnum = dest - num_lines + 1;
- curbuf->b_op_end.lnum = dest;
- }
- else
- {
- mark_adjust(dest + 1, line1 - 1, num_lines, 0L);
- curbuf->b_op_start.lnum = dest + 1;
- curbuf->b_op_end.lnum = dest + num_lines;
- }
- curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
- mark_adjust(last_line - num_lines + 1, last_line,
- -(last_line - dest - extra), 0L);
- /*
- * Now we delete the original text -- webb
- */
- if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL)
- return FAIL;
- for (l = line1; l <= line2; l++)
- ml_delete(line1 + extra, TRUE);
- changed();
- if (!global_busy && num_lines > p_report)
- smsg((char_u *)"%ld line%s moved", num_lines, plural(num_lines));
- /*
- * Leave the cursor on the last of the moved lines.
- */
- if (dest >= line1)
- curwin->w_cursor.lnum = dest;
- else
- curwin->w_cursor.lnum = dest + (line2 - line1) + 1;
- changed_line_abv_curs();
- /*
- * TODO: should recompute w_botline for simple situations.
- */
- invalidate_botline();
- return OK;
- }
- /*
- * :copy command - copy lines line1-line2 to line n
- */
- void
- do_copy(line1, line2, n)
- linenr_t line1;
- linenr_t line2;
- linenr_t n;
- {
- linenr_t lnum;
- char_u *p;
- lnum = line2 - line1 + 1;
- mark_adjust(n + 1, (linenr_t)MAXLNUM, lnum, 0L);
- curbuf->b_op_start.lnum = n + 1;
- curbuf->b_op_end.lnum = n + lnum;
- curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
- /*
- * there are three situations:
- * 1. destination is above line1
- * 2. destination is between line1 and line2
- * 3. destination is below line2
- *
- * n = destination (when starting)
- * 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("