To: vim_dev@googlegroups.com Subject: Patch 8.1.0266 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.0266 Problem: Parsing Ex address range is not a separate function. Solution: Refactor do_one_cmd() to separate address parsing. Files: src/ex_docmd.c, src/proto/ex_docmd.pro *** ../vim-8.1.0265/src/ex_docmd.c 2018-08-07 22:30:26.670240840 +0200 --- src/ex_docmd.c 2018-08-10 23:08:38.139696671 +0200 *************** *** 1719,1725 **** cmdmod_T save_cmdmod; int ni; /* set when Not Implemented */ char_u *cmd; - int address_count = 1; vim_memset(&ea, 0, sizeof(ea)); ea.line1 = 1; --- 1719,1724 ---- *************** *** 2045,2212 **** get_wincmd_addr_type(skipwhite(p), &ea); } - /* repeat for all ',' or ';' separated addresses */ ea.cmd = cmd; ! for (;;) ! { ! ea.line1 = ea.line2; ! switch (ea.addr_type) ! { ! case ADDR_LINES: ! /* default is current line number */ ! ea.line2 = curwin->w_cursor.lnum; ! break; ! case ADDR_WINDOWS: ! ea.line2 = CURRENT_WIN_NR; ! break; ! case ADDR_ARGUMENTS: ! ea.line2 = curwin->w_arg_idx + 1; ! if (ea.line2 > ARGCOUNT) ! ea.line2 = ARGCOUNT; ! break; ! case ADDR_LOADED_BUFFERS: ! case ADDR_BUFFERS: ! ea.line2 = curbuf->b_fnum; ! break; ! case ADDR_TABS: ! ea.line2 = CURRENT_TAB_NR; ! break; ! case ADDR_TABS_RELATIVE: ! ea.line2 = 1; ! break; ! #ifdef FEAT_QUICKFIX ! case ADDR_QUICKFIX: ! ea.line2 = qf_get_cur_valid_idx(&ea); ! break; ! #endif ! } ! ea.cmd = skipwhite(ea.cmd); ! lnum = get_address(&ea, &ea.cmd, ea.addr_type, ea.skip, ! ea.addr_count == 0, address_count++); ! if (ea.cmd == NULL) /* error detected */ ! goto doend; ! if (lnum == MAXLNUM) ! { ! if (*ea.cmd == '%') /* '%' - all lines */ ! { ! ++ea.cmd; ! switch (ea.addr_type) ! { ! case ADDR_LINES: ! ea.line1 = 1; ! ea.line2 = curbuf->b_ml.ml_line_count; ! break; ! case ADDR_LOADED_BUFFERS: ! { ! buf_T *buf = firstbuf; ! ! while (buf->b_next != NULL ! && buf->b_ml.ml_mfp == NULL) ! buf = buf->b_next; ! ea.line1 = buf->b_fnum; ! buf = lastbuf; ! while (buf->b_prev != NULL ! && buf->b_ml.ml_mfp == NULL) ! buf = buf->b_prev; ! ea.line2 = buf->b_fnum; ! break; ! } ! case ADDR_BUFFERS: ! ea.line1 = firstbuf->b_fnum; ! ea.line2 = lastbuf->b_fnum; ! break; ! case ADDR_WINDOWS: ! case ADDR_TABS: ! if (IS_USER_CMDIDX(ea.cmdidx)) ! { ! ea.line1 = 1; ! ea.line2 = ea.addr_type == ADDR_WINDOWS ! ? LAST_WIN_NR : LAST_TAB_NR; ! } ! else ! { ! /* there is no Vim command which uses '%' and ! * ADDR_WINDOWS or ADDR_TABS */ ! errormsg = (char_u *)_(e_invrange); ! goto doend; ! } ! break; ! case ADDR_TABS_RELATIVE: ! errormsg = (char_u *)_(e_invrange); ! goto doend; ! break; ! case ADDR_ARGUMENTS: ! if (ARGCOUNT == 0) ! ea.line1 = ea.line2 = 0; ! else ! { ! ea.line1 = 1; ! ea.line2 = ARGCOUNT; ! } ! break; ! #ifdef FEAT_QUICKFIX ! case ADDR_QUICKFIX: ! ea.line1 = 1; ! ea.line2 = qf_get_size(&ea); ! if (ea.line2 == 0) ! ea.line2 = 1; ! break; ! #endif ! } ! ++ea.addr_count; ! } ! /* '*' - visual area */ ! else if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL) ! { ! pos_T *fp; ! ! if (ea.addr_type != ADDR_LINES) ! { ! errormsg = (char_u *)_(e_invrange); ! goto doend; ! } ! ! ++ea.cmd; ! if (!ea.skip) ! { ! fp = getmark('<', FALSE); ! if (check_mark(fp) == FAIL) ! goto doend; ! ea.line1 = fp->lnum; ! fp = getmark('>', FALSE); ! if (check_mark(fp) == FAIL) ! goto doend; ! ea.line2 = fp->lnum; ! ++ea.addr_count; ! } ! } ! } ! else ! ea.line2 = lnum; ! ea.addr_count++; ! ! if (*ea.cmd == ';') ! { ! if (!ea.skip) ! { ! curwin->w_cursor.lnum = ea.line2; ! /* don't leave the cursor on an illegal line or column */ ! check_cursor(); ! } ! } ! else if (*ea.cmd != ',') ! break; ! ++ea.cmd; ! } ! ! /* One address given: set start and end lines */ ! if (ea.addr_count == 1) ! { ! ea.line1 = ea.line2; ! /* ... but only implicit: really no address given */ ! if (lnum == MAXLNUM) ! ea.addr_count = 0; ! } /* * 5. Parse the command. --- 2044,2052 ---- get_wincmd_addr_type(skipwhite(p), &ea); } ea.cmd = cmd; ! if (parse_cmd_address(&ea, &errormsg) == FAIL) ! goto doend; /* * 5. Parse the command. *************** *** 2989,2994 **** --- 2829,3007 ---- #endif /* + * Parse the address range, if any, in "eap". + * Return FAIL and set "errormsg" or return OK. + */ + int + parse_cmd_address(exarg_T *eap, char_u **errormsg) + { + int address_count = 1; + linenr_T lnum; + + // Repeat for all ',' or ';' separated addresses. + for (;;) + { + eap->line1 = eap->line2; + switch (eap->addr_type) + { + case ADDR_LINES: + // default is current line number + eap->line2 = curwin->w_cursor.lnum; + break; + case ADDR_WINDOWS: + eap->line2 = CURRENT_WIN_NR; + break; + case ADDR_ARGUMENTS: + eap->line2 = curwin->w_arg_idx + 1; + if (eap->line2 > ARGCOUNT) + eap->line2 = ARGCOUNT; + break; + case ADDR_LOADED_BUFFERS: + case ADDR_BUFFERS: + eap->line2 = curbuf->b_fnum; + break; + case ADDR_TABS: + eap->line2 = CURRENT_TAB_NR; + break; + case ADDR_TABS_RELATIVE: + eap->line2 = 1; + break; + #ifdef FEAT_QUICKFIX + case ADDR_QUICKFIX: + eap->line2 = qf_get_cur_valid_idx(eap); + break; + #endif + } + eap->cmd = skipwhite(eap->cmd); + lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip, + eap->addr_count == 0, address_count++); + if (eap->cmd == NULL) // error detected + return FAIL; + if (lnum == MAXLNUM) + { + if (*eap->cmd == '%') // '%' - all lines + { + ++eap->cmd; + switch (eap->addr_type) + { + case ADDR_LINES: + eap->line1 = 1; + eap->line2 = curbuf->b_ml.ml_line_count; + break; + case ADDR_LOADED_BUFFERS: + { + buf_T *buf = firstbuf; + + while (buf->b_next != NULL + && buf->b_ml.ml_mfp == NULL) + buf = buf->b_next; + eap->line1 = buf->b_fnum; + buf = lastbuf; + while (buf->b_prev != NULL + && buf->b_ml.ml_mfp == NULL) + buf = buf->b_prev; + eap->line2 = buf->b_fnum; + break; + } + case ADDR_BUFFERS: + eap->line1 = firstbuf->b_fnum; + eap->line2 = lastbuf->b_fnum; + break; + case ADDR_WINDOWS: + case ADDR_TABS: + if (IS_USER_CMDIDX(eap->cmdidx)) + { + eap->line1 = 1; + eap->line2 = eap->addr_type == ADDR_WINDOWS + ? LAST_WIN_NR : LAST_TAB_NR; + } + else + { + // there is no Vim command which uses '%' and + // ADDR_WINDOWS or ADDR_TABS + *errormsg = (char_u *)_(e_invrange); + return FAIL; + } + break; + case ADDR_TABS_RELATIVE: + *errormsg = (char_u *)_(e_invrange); + return FAIL; + case ADDR_ARGUMENTS: + if (ARGCOUNT == 0) + eap->line1 = eap->line2 = 0; + else + { + eap->line1 = 1; + eap->line2 = ARGCOUNT; + } + break; + #ifdef FEAT_QUICKFIX + case ADDR_QUICKFIX: + eap->line1 = 1; + eap->line2 = qf_get_size(eap); + if (eap->line2 == 0) + eap->line2 = 1; + break; + #endif + } + ++eap->addr_count; + } + else if (*eap->cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL) + { + pos_T *fp; + + // '*' - visual area + if (eap->addr_type != ADDR_LINES) + { + *errormsg = (char_u *)_(e_invrange); + return FAIL; + } + + ++eap->cmd; + if (!eap->skip) + { + fp = getmark('<', FALSE); + if (check_mark(fp) == FAIL) + return FAIL; + eap->line1 = fp->lnum; + fp = getmark('>', FALSE); + if (check_mark(fp) == FAIL) + return FAIL; + eap->line2 = fp->lnum; + ++eap->addr_count; + } + } + } + else + eap->line2 = lnum; + eap->addr_count++; + + if (*eap->cmd == ';') + { + if (!eap->skip) + { + curwin->w_cursor.lnum = eap->line2; + // don't leave the cursor on an illegal line or column + check_cursor(); + } + } + else if (*eap->cmd != ',') + break; + ++eap->cmd; + } + + // One address given: set start and end lines. + if (eap->addr_count == 1) + { + eap->line1 = eap->line2; + // ... but only implicit: really no address given + if (lnum == MAXLNUM) + eap->addr_count = 0; + } + return OK; + } + + /* * Check for an Ex command with optional tail. * If there is a match advance "pp" to the argument and return TRUE. */ *************** *** 4292,4298 **** } /* ! * skip a range specifier of the form: addr [,addr] [;addr] .. * * Backslashed delimiters after / or ? will be skipped, and commands will * not be expanded between /'s and ?'s or after "'". --- 4305,4311 ---- } /* ! * Skip a range specifier of the form: addr [,addr] [;addr] .. * * Backslashed delimiters after / or ? will be skipped, and commands will * not be expanded between /'s and ?'s or after "'". *** ../vim-8.1.0265/src/proto/ex_docmd.pro 2018-07-29 17:35:19.493750319 +0200 --- src/proto/ex_docmd.pro 2018-08-10 23:08:41.983672969 +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_cmd_address(exarg_T *eap, char_u **errormsg); int checkforcmd(char_u **pp, char *cmd, int len); int modifier_len(char_u *cmd); int cmd_exists(char_u *name); *** ../vim-8.1.0265/src/version.c 2018-08-10 22:07:28.821903829 +0200 --- src/version.c 2018-08-10 22:39:25.770183225 +0200 *************** *** 796,797 **** --- 796,799 ---- { /* Add new patch number below this line */ + /**/ + 266, /**/ -- Permission is granted to read this message out aloud on Kings Cross Road, London, under the condition that the orator is properly dressed. /// 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 ///