diff options
author | Sam Bingner <sam@bingner.com> | 2018-12-13 15:11:52 -1000 |
---|---|---|
committer | Sam Bingner <sam@bingner.com> | 2018-12-13 15:11:52 -1000 |
commit | 957aa75d05c00731d7112bed7b68ce4568667d0c (patch) | |
tree | 0445216818495a7864eaa3acde1a1570d34b958d /data/vim/patches/8.1.0281 | |
parent | c54a909c8b5a8519130803cf55f68603c0ad3682 (diff) |
Update vim
Diffstat (limited to 'data/vim/patches/8.1.0281')
-rw-r--r-- | data/vim/patches/8.1.0281 | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/data/vim/patches/8.1.0281 b/data/vim/patches/8.1.0281 new file mode 100644 index 000000000..9efb07608 --- /dev/null +++ b/data/vim/patches/8.1.0281 @@ -0,0 +1,738 @@ +To: vim_dev@googlegroups.com +Subject: Patch 8.1.0281 +Fcc: outbox +From: Bram Moolenaar <Bram@moolenaar.net> +Mime-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +------------ + +Patch 8.1.0281 +Problem: Parsing command modifiers is not separated. +Solution: Move command modifier parsing to a separate function. +Files: src/ex_docmd.c, src/proto/ex_docmd.pro, src/ex_cmds.h, + src/globals.h, src/feature.h + + +*** ../vim-8.1.0280/src/ex_docmd.c 2018-08-10 23:13:07.934024645 +0200 +--- src/ex_docmd.c 2018-08-13 23:27:03.980298529 +0200 +*************** +*** 1709,1721 **** + char_u *errormsg = NULL; /* error message */ + char_u *after_modifier = NULL; + exarg_T ea; /* Ex command arguments */ +- long verbose_save = -1; + int save_msg_scroll = msg_scroll; +- int save_msg_silent = -1; +- int did_esilent = 0; +- #ifdef HAVE_SANDBOX +- int did_sandbox = FALSE; +- #endif + cmdmod_T save_cmdmod; + int ni; /* set when Not Implemented */ + char_u *cmd; +--- 1709,1715 ---- +*************** +*** 1742,1748 **** + * recursive calls. + */ + save_cmdmod = cmdmod; +- vim_memset(&cmdmod, 0, sizeof(cmdmod)); + + /* "#!anything" is handled like a comment. */ + if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') +--- 1736,1741 ---- +*************** +*** 1750,1977 **** + + /* + * Repeat until no more command modifiers are found. + */ + ea.cmd = *cmdlinep; +! for (;;) +! { +! /* +! * 1. Skip comment lines and leading white space and colons. +! */ +! while (*ea.cmd == ' ' || *ea.cmd == '\t' || *ea.cmd == ':') +! ++ea.cmd; +! +! /* in ex mode, an empty line works like :+ */ +! if (*ea.cmd == NUL && exmode_active +! && (getline_equal(fgetline, cookie, getexmodeline) +! || getline_equal(fgetline, cookie, getexline)) +! && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) +! { +! ea.cmd = (char_u *)"+"; +! ex_pressedreturn = TRUE; +! } +! +! /* ignore comment and empty lines */ +! if (*ea.cmd == '"') +! goto doend; +! if (*ea.cmd == NUL) +! { +! ex_pressedreturn = TRUE; +! goto doend; +! } +! +! /* +! * 2. Handle command modifiers. +! */ +! p = skip_range(ea.cmd, NULL); +! switch (*p) +! { +! /* When adding an entry, also modify cmd_exists(). */ +! case 'a': if (!checkforcmd(&ea.cmd, "aboveleft", 3)) +! break; +! cmdmod.split |= WSP_ABOVE; +! continue; +! +! case 'b': if (checkforcmd(&ea.cmd, "belowright", 3)) +! { +! cmdmod.split |= WSP_BELOW; +! continue; +! } +! if (checkforcmd(&ea.cmd, "browse", 3)) +! { +! #ifdef FEAT_BROWSE_CMD +! cmdmod.browse = TRUE; +! #endif +! continue; +! } +! if (!checkforcmd(&ea.cmd, "botright", 2)) +! break; +! cmdmod.split |= WSP_BOT; +! continue; +! +! case 'c': if (!checkforcmd(&ea.cmd, "confirm", 4)) +! break; +! #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) +! cmdmod.confirm = TRUE; +! #endif +! continue; +! +! case 'k': if (checkforcmd(&ea.cmd, "keepmarks", 3)) +! { +! cmdmod.keepmarks = TRUE; +! continue; +! } +! if (checkforcmd(&ea.cmd, "keepalt", 5)) +! { +! cmdmod.keepalt = TRUE; +! continue; +! } +! if (checkforcmd(&ea.cmd, "keeppatterns", 5)) +! { +! cmdmod.keeppatterns = TRUE; +! continue; +! } +! if (!checkforcmd(&ea.cmd, "keepjumps", 5)) +! break; +! cmdmod.keepjumps = TRUE; +! continue; +! +! case 'f': /* only accept ":filter {pat} cmd" */ +! { +! char_u *reg_pat; +! +! if (!checkforcmd(&p, "filter", 4) +! || *p == NUL || ends_excmd(*p)) +! break; +! if (*p == '!') +! { +! cmdmod.filter_force = TRUE; +! p = skipwhite(p + 1); +! if (*p == NUL || ends_excmd(*p)) +! break; +! } +! p = skip_vimgrep_pat(p, ®_pat, NULL); +! if (p == NULL || *p == NUL) +! break; +! cmdmod.filter_regmatch.regprog = +! vim_regcomp(reg_pat, RE_MAGIC); +! if (cmdmod.filter_regmatch.regprog == NULL) +! break; +! ea.cmd = p; +! continue; +! } +! +! /* ":hide" and ":hide | cmd" are not modifiers */ +! case 'h': if (p != ea.cmd || !checkforcmd(&p, "hide", 3) +! || *p == NUL || ends_excmd(*p)) +! break; +! ea.cmd = p; +! cmdmod.hide = TRUE; +! continue; +! +! case 'l': if (checkforcmd(&ea.cmd, "lockmarks", 3)) +! { +! cmdmod.lockmarks = TRUE; +! continue; +! } +! +! if (!checkforcmd(&ea.cmd, "leftabove", 5)) +! break; +! cmdmod.split |= WSP_ABOVE; +! continue; +! +! case 'n': if (checkforcmd(&ea.cmd, "noautocmd", 3)) +! { +! if (cmdmod.save_ei == NULL) +! { +! /* Set 'eventignore' to "all". Restore the +! * existing option value later. */ +! cmdmod.save_ei = vim_strsave(p_ei); +! set_string_option_direct((char_u *)"ei", -1, +! (char_u *)"all", OPT_FREE, SID_NONE); +! } +! continue; +! } +! if (!checkforcmd(&ea.cmd, "noswapfile", 3)) +! break; +! cmdmod.noswapfile = TRUE; +! continue; +! +! case 'r': if (!checkforcmd(&ea.cmd, "rightbelow", 6)) +! break; +! cmdmod.split |= WSP_BELOW; +! continue; +! +! case 's': if (checkforcmd(&ea.cmd, "sandbox", 3)) +! { +! #ifdef HAVE_SANDBOX +! if (!did_sandbox) +! ++sandbox; +! did_sandbox = TRUE; + #endif +! continue; +! } +! if (!checkforcmd(&ea.cmd, "silent", 3)) +! break; +! if (save_msg_silent == -1) +! save_msg_silent = msg_silent; +! ++msg_silent; +! if (*ea.cmd == '!' && !VIM_ISWHITE(ea.cmd[-1])) +! { +! /* ":silent!", but not "silent !cmd" */ +! ea.cmd = skipwhite(ea.cmd + 1); +! ++emsg_silent; +! ++did_esilent; +! } +! continue; +! +! case 't': if (checkforcmd(&p, "tab", 3)) +! { +! long tabnr = get_address(&ea, &ea.cmd, ADDR_TABS, +! ea.skip, FALSE, 1); +! if (tabnr == MAXLNUM) +! cmdmod.tab = tabpage_index(curtab) + 1; +! else +! { +! if (tabnr < 0 || tabnr > LAST_TAB_NR) +! { +! errormsg = (char_u *)_(e_invrange); +! goto doend; +! } +! cmdmod.tab = tabnr + 1; +! } +! ea.cmd = p; +! continue; +! } +! if (!checkforcmd(&ea.cmd, "topleft", 2)) +! break; +! cmdmod.split |= WSP_TOP; +! continue; +! +! case 'u': if (!checkforcmd(&ea.cmd, "unsilent", 3)) +! break; +! if (save_msg_silent == -1) +! save_msg_silent = msg_silent; +! msg_silent = 0; +! continue; + +- case 'v': if (checkforcmd(&ea.cmd, "vertical", 4)) +- { +- cmdmod.split |= WSP_VERT; +- continue; +- } +- if (!checkforcmd(&p, "verbose", 4)) +- break; +- if (verbose_save < 0) +- verbose_save = p_verbose; +- if (vim_isdigit(*ea.cmd)) +- p_verbose = atoi((char *)ea.cmd); +- else +- p_verbose = 1; +- ea.cmd = p; +- continue; +- } +- break; +- } + after_modifier = ea.cmd; + + #ifdef FEAT_EVAL +--- 1743,1760 ---- + + /* + * Repeat until no more command modifiers are found. ++ * The "ea" structure holds the arguments that can be used. + */ + ea.cmd = *cmdlinep; +! ea.cmdlinep = cmdlinep; +! ea.getline = fgetline; +! ea.cookie = cookie; +! #ifdef FEAT_EVAL +! ea.cstack = cstack; + #endif +! if (parse_command_modifiers(&ea, &errormsg) == FAIL) +! goto doend; + + after_modifier = ea.cmd; + + #ifdef FEAT_EVAL +*************** +*** 2688,2712 **** + + /* The :try command saves the emsg_silent flag, reset it here when + * ":silent! try" was used, it should only apply to :try itself. */ +! if (ea.cmdidx == CMD_try && did_esilent > 0) + { +! emsg_silent -= did_esilent; + if (emsg_silent < 0) + emsg_silent = 0; +! did_esilent = 0; + } + + /* + * 7. Execute the command. +- * +- * The "ea" structure holds the arguments that can be used. + */ +- ea.cmdlinep = cmdlinep; +- ea.getline = fgetline; +- ea.cookie = cookie; +- #ifdef FEAT_EVAL +- ea.cstack = cstack; +- #endif + + #ifdef FEAT_USR_CMDS + if (IS_USER_CMDIDX(ea.cmdidx)) +--- 2471,2487 ---- + + /* The :try command saves the emsg_silent flag, reset it here when + * ":silent! try" was used, it should only apply to :try itself. */ +! if (ea.cmdidx == CMD_try && ea.did_esilent > 0) + { +! emsg_silent -= ea.did_esilent; + if (emsg_silent < 0) + emsg_silent = 0; +! ea.did_esilent = 0; + } + + /* + * 7. Execute the command. + */ + + #ifdef FEAT_USR_CMDS + if (IS_USER_CMDIDX(ea.cmdidx)) +*************** +*** 2775,2782 **** + ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL); + #endif + +! if (verbose_save >= 0) +! p_verbose = verbose_save; + + if (cmdmod.save_ei != NULL) + { +--- 2550,2557 ---- + ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL); + #endif + +! if (ea.verbose_save >= 0) +! p_verbose = ea.verbose_save; + + if (cmdmod.save_ei != NULL) + { +*************** +*** 2791,2803 **** + + cmdmod = save_cmdmod; + +! if (save_msg_silent != -1) + { + /* messages could be enabled for a serious error, need to check if the + * counters don't become negative */ +! if (!did_emsg || msg_silent > save_msg_silent) +! msg_silent = save_msg_silent; +! emsg_silent -= did_esilent; + if (emsg_silent < 0) + emsg_silent = 0; + /* Restore msg_scroll, it's set by file I/O commands, even when no +--- 2566,2578 ---- + + cmdmod = save_cmdmod; + +! if (ea.save_msg_silent != -1) + { + /* messages could be enabled for a serious error, need to check if the + * counters don't become negative */ +! if (!did_emsg || msg_silent > ea.save_msg_silent) +! msg_silent = ea.save_msg_silent; +! emsg_silent -= ea.did_esilent; + if (emsg_silent < 0) + emsg_silent = 0; + /* Restore msg_scroll, it's set by file I/O commands, even when no +*************** +*** 2811,2817 **** + } + + #ifdef HAVE_SANDBOX +! if (did_sandbox) + --sandbox; + #endif + +--- 2586,2592 ---- + } + + #ifdef HAVE_SANDBOX +! if (ea.did_sandbox) + --sandbox; + #endif + +*************** +*** 2829,2834 **** +--- 2604,2853 ---- + #endif + + /* ++ * Parse and skip over command modifiers: ++ * - update eap->cmd ++ * - store flags in "cmdmod". ++ * - Set ex_pressedreturn for an empty command line. ++ * - set msg_silent for ":silent" ++ * - set p_verbose for ":verbose" ++ * - Increment "sandbox" for ":sandbox" ++ * Return FAIL when the command is not to be executed. ++ * May set "errormsg" to an error message. ++ */ ++ int ++ parse_command_modifiers(exarg_T *eap, char_u **errormsg) ++ { ++ char_u *p; ++ ++ vim_memset(&cmdmod, 0, sizeof(cmdmod)); ++ eap->verbose_save = -1; ++ eap->save_msg_silent = -1; ++ ++ for (;;) ++ { ++ /* ++ * 1. Skip comment lines and leading white space and colons. ++ */ ++ while (*eap->cmd == ' ' || *eap->cmd == '\t' || *eap->cmd == ':') ++ ++eap->cmd; ++ ++ /* in ex mode, an empty line works like :+ */ ++ if (*eap->cmd == NUL && exmode_active ++ && (getline_equal(eap->getline, eap->cookie, getexmodeline) ++ || getline_equal(eap->getline, eap->cookie, getexline)) ++ && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) ++ { ++ eap->cmd = (char_u *)"+"; ++ ex_pressedreturn = TRUE; ++ } ++ ++ /* ignore comment and empty lines */ ++ if (*eap->cmd == '"') ++ return FAIL; ++ if (*eap->cmd == NUL) ++ { ++ ex_pressedreturn = TRUE; ++ return FAIL; ++ } ++ ++ /* ++ * 2. Handle command modifiers. ++ */ ++ p = skip_range(eap->cmd, NULL); ++ switch (*p) ++ { ++ /* When adding an entry, also modify cmd_exists(). */ ++ case 'a': if (!checkforcmd(&eap->cmd, "aboveleft", 3)) ++ break; ++ cmdmod.split |= WSP_ABOVE; ++ continue; ++ ++ case 'b': if (checkforcmd(&eap->cmd, "belowright", 3)) ++ { ++ cmdmod.split |= WSP_BELOW; ++ continue; ++ } ++ if (checkforcmd(&eap->cmd, "browse", 3)) ++ { ++ #ifdef FEAT_BROWSE_CMD ++ cmdmod.browse = TRUE; ++ #endif ++ continue; ++ } ++ if (!checkforcmd(&eap->cmd, "botright", 2)) ++ break; ++ cmdmod.split |= WSP_BOT; ++ continue; ++ ++ case 'c': if (!checkforcmd(&eap->cmd, "confirm", 4)) ++ break; ++ #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) ++ cmdmod.confirm = TRUE; ++ #endif ++ continue; ++ ++ case 'k': if (checkforcmd(&eap->cmd, "keepmarks", 3)) ++ { ++ cmdmod.keepmarks = TRUE; ++ continue; ++ } ++ if (checkforcmd(&eap->cmd, "keepalt", 5)) ++ { ++ cmdmod.keepalt = TRUE; ++ continue; ++ } ++ if (checkforcmd(&eap->cmd, "keeppatterns", 5)) ++ { ++ cmdmod.keeppatterns = TRUE; ++ continue; ++ } ++ if (!checkforcmd(&eap->cmd, "keepjumps", 5)) ++ break; ++ cmdmod.keepjumps = TRUE; ++ continue; ++ ++ case 'f': /* only accept ":filter {pat} cmd" */ ++ { ++ char_u *reg_pat; ++ ++ if (!checkforcmd(&p, "filter", 4) ++ || *p == NUL || ends_excmd(*p)) ++ break; ++ if (*p == '!') ++ { ++ cmdmod.filter_force = TRUE; ++ p = skipwhite(p + 1); ++ if (*p == NUL || ends_excmd(*p)) ++ break; ++ } ++ p = skip_vimgrep_pat(p, ®_pat, NULL); ++ if (p == NULL || *p == NUL) ++ break; ++ cmdmod.filter_regmatch.regprog = ++ vim_regcomp(reg_pat, RE_MAGIC); ++ if (cmdmod.filter_regmatch.regprog == NULL) ++ break; ++ eap->cmd = p; ++ continue; ++ } ++ ++ /* ":hide" and ":hide | cmd" are not modifiers */ ++ case 'h': if (p != eap->cmd || !checkforcmd(&p, "hide", 3) ++ || *p == NUL || ends_excmd(*p)) ++ break; ++ eap->cmd = p; ++ cmdmod.hide = TRUE; ++ continue; ++ ++ case 'l': if (checkforcmd(&eap->cmd, "lockmarks", 3)) ++ { ++ cmdmod.lockmarks = TRUE; ++ continue; ++ } ++ ++ if (!checkforcmd(&eap->cmd, "leftabove", 5)) ++ break; ++ cmdmod.split |= WSP_ABOVE; ++ continue; ++ ++ case 'n': if (checkforcmd(&eap->cmd, "noautocmd", 3)) ++ { ++ if (cmdmod.save_ei == NULL) ++ { ++ /* Set 'eventignore' to "all". Restore the ++ * existing option value later. */ ++ cmdmod.save_ei = vim_strsave(p_ei); ++ set_string_option_direct((char_u *)"ei", -1, ++ (char_u *)"all", OPT_FREE, SID_NONE); ++ } ++ continue; ++ } ++ if (!checkforcmd(&eap->cmd, "noswapfile", 3)) ++ break; ++ cmdmod.noswapfile = TRUE; ++ continue; ++ ++ case 'r': if (!checkforcmd(&eap->cmd, "rightbelow", 6)) ++ break; ++ cmdmod.split |= WSP_BELOW; ++ continue; ++ ++ case 's': if (checkforcmd(&eap->cmd, "sandbox", 3)) ++ { ++ #ifdef HAVE_SANDBOX ++ if (!eap->did_sandbox) ++ ++sandbox; ++ eap->did_sandbox = TRUE; ++ #endif ++ continue; ++ } ++ if (!checkforcmd(&eap->cmd, "silent", 3)) ++ break; ++ if (eap->save_msg_silent == -1) ++ eap->save_msg_silent = msg_silent; ++ ++msg_silent; ++ if (*eap->cmd == '!' && !VIM_ISWHITE(eap->cmd[-1])) ++ { ++ /* ":silent!", but not "silent !cmd" */ ++ eap->cmd = skipwhite(eap->cmd + 1); ++ ++emsg_silent; ++ ++eap->did_esilent; ++ } ++ continue; ++ ++ case 't': if (checkforcmd(&p, "tab", 3)) ++ { ++ long tabnr = get_address(eap, &eap->cmd, ADDR_TABS, ++ eap->skip, FALSE, 1); ++ if (tabnr == MAXLNUM) ++ cmdmod.tab = tabpage_index(curtab) + 1; ++ else ++ { ++ if (tabnr < 0 || tabnr > LAST_TAB_NR) ++ { ++ *errormsg = (char_u *)_(e_invrange); ++ return FAIL; ++ } ++ cmdmod.tab = tabnr + 1; ++ } ++ eap->cmd = p; ++ continue; ++ } ++ if (!checkforcmd(&eap->cmd, "topleft", 2)) ++ break; ++ cmdmod.split |= WSP_TOP; ++ continue; ++ ++ case 'u': if (!checkforcmd(&eap->cmd, "unsilent", 3)) ++ break; ++ if (eap->save_msg_silent == -1) ++ eap->save_msg_silent = msg_silent; ++ msg_silent = 0; ++ continue; ++ ++ case 'v': if (checkforcmd(&eap->cmd, "vertical", 4)) ++ { ++ cmdmod.split |= WSP_VERT; ++ continue; ++ } ++ if (!checkforcmd(&p, "verbose", 4)) ++ break; ++ if (eap->verbose_save < 0) ++ eap->verbose_save = p_verbose; ++ if (vim_isdigit(*eap->cmd)) ++ p_verbose = atoi((char *)eap->cmd); ++ else ++ p_verbose = 1; ++ eap->cmd = p; ++ continue; ++ } ++ break; ++ } ++ ++ return OK; ++ } ++ ++ /* + * Parse the address range, if any, in "eap". + * Return FAIL and set "errormsg" or return OK. + */ +*** ../vim-8.1.0280/src/proto/ex_docmd.pro 2018-08-10 23:13:07.934024645 +0200 +--- src/proto/ex_docmd.pro 2018-08-13 23:24:18.797373050 +0200 +*************** +*** 4,9 **** +--- 4,10 ---- + int do_cmdline(char_u *cmdline, char_u *(*fgetline)(int, void *, int), void *cookie, int flags); + int getline_equal(char_u *(*fgetline)(int, void *, int), void *cookie, char_u *(*func)(int, void *, int)); + void *getline_cookie(char_u *(*fgetline)(int, void *, int), void *cookie); ++ int parse_command_modifiers(exarg_T *eap, char_u **errormsg); + int parse_cmd_address(exarg_T *eap, char_u **errormsg); + int checkforcmd(char_u **pp, char *cmd, int len); + int modifier_len(char_u *cmd); +*** ../vim-8.1.0280/src/ex_cmds.h 2018-07-10 19:39:14.994973018 +0200 +--- src/ex_cmds.h 2018-08-13 23:25:36.236870329 +0200 +*************** +*** 1792,1797 **** +--- 1792,1803 ---- + #ifdef FEAT_EVAL + struct condstack *cstack; /* condition stack for ":if" etc. */ + #endif ++ long verbose_save; // saved value of p_verbose ++ int save_msg_silent; // saved value of msg_silent ++ int did_esilent; // how many times emsg_silent was incremented ++ #ifdef HAVE_SANDBOX ++ int did_sandbox; // when TRUE did ++sandbox ++ #endif + }; + + #define FORCE_BIN 1 /* ":edit ++bin file" */ +*** ../vim-8.1.0280/src/globals.h 2018-08-11 16:40:39.064311995 +0200 +--- src/globals.h 2018-08-13 23:18:14.323704509 +0200 +*************** +*** 678,685 **** + * changed, no buffer can be deleted and + * current directory can't be changed. + * Used for SwapExists et al. */ +! #ifdef FEAT_EVAL +! # define HAVE_SANDBOX + EXTERN int sandbox INIT(= 0); + /* Non-zero when evaluating an expression in a + * "sandbox". Several things are not allowed +--- 678,684 ---- + * changed, no buffer can be deleted and + * current directory can't be changed. + * Used for SwapExists et al. */ +! #ifdef HAVE_SANDBOX + EXTERN int sandbox INIT(= 0); + /* Non-zero when evaluating an expression in a + * "sandbox". Several things are not allowed +*** ../vim-8.1.0280/src/feature.h 2018-07-29 16:09:14.644945560 +0200 +--- src/feature.h 2018-08-13 23:19:07.623368124 +0200 +*************** +*** 355,360 **** +--- 355,364 ---- + # endif + #endif + ++ #ifdef FEAT_EVAL ++ # define HAVE_SANDBOX ++ #endif ++ + /* + * +profile Profiling for functions and scripts. + */ +*** ../vim-8.1.0280/src/version.c 2018-08-13 22:54:31.456665135 +0200 +--- src/version.c 2018-08-13 23:04:38.032484283 +0200 +*************** +*** 796,797 **** +--- 796,799 ---- + { /* Add new patch number below this line */ ++ /**/ ++ 281, + /**/ + +-- +Violators can be fined, arrested or jailed for making ugly faces at a dog. + [real standing law in Oklahoma, United States of America] + + /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ +/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ +\\\ an exciting new programming language -- http://www.Zimbu.org /// + \\\ help me help AIDS victims -- http://ICCF-Holland.org /// |