To: vim-dev@vim.org Subject: Patch 6.1.423 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit ------------ Patch 6.1.423 Problem: Can't find arbitrary text in help files. Solution: Added the ":helpgrep" command. Files: runtime/doc/various.txt, src/ex_cmds.h, src/ex_docmd.c, src/proto/quickfix.pro, src/quickfix.c *** ../vim61.422/runtime/doc/various.txt Sat Mar 8 20:33:31 2003 --- runtime/doc/various.txt Fri Mar 28 21:59:30 2003 *************** *** 1,4 **** ! *various.txt* For Vim version 6.1. Last change: 2003 Feb 15 VIM REFERENCE MANUAL by Bram Moolenaar --- 1,4 ---- ! *various.txt* For Vim version 6.1. Last change: 2003 Mar 28 VIM REFERENCE MANUAL by Bram Moolenaar *************** *** 534,542 **** :help soonly < {not in Vi} ! When no argument is given the file given with the 'helpfile' option will be ! opened. Otherwise the specified tag is searched for in all "doc/tags" files ! in the directories specified in the 'runtimepath' option. The initial height of the help window can be set with the 'helpheight' option (default 20). --- 542,569 ---- :help soonly < {not in Vi} ! *:helpg* *:helpgrep* ! :helpg[rep] {pattern} ! Search all help text files and make a list of lines ! in which {pattern} matches. Jumps to the first match. ! You can navigate through the matches with the ! |quickfix| commands, e.g., |:cnext| to jump to the ! next one. Or use |:cwindow| to get the list of ! matches in the quickfix window. ! {pattern} is used as a Vim regexp |pattern|. ! 'ignorecase' is not used, add "\c" to ignore case. ! Example for case sensitive search: > ! :helpgrep Uganda ! < Example for case ignoring search: > ! :helpgrep uganda\c ! < Cannot be followed by another command, everything is ! used as part of the pattern. But you can use ! |:execute| when needed. ! ! ! When no argument is given to |:help| the file given with the 'helpfile' option ! will be opened. Otherwise the specified tag is searched for in all "doc/tags" ! files in the directories specified in the 'runtimepath' option. The initial height of the help window can be set with the 'helpheight' option (default 20). *** ../vim61.422/src/ex_cmds.h Sat Mar 15 16:33:38 2003 --- src/ex_cmds.h Fri Mar 28 21:26:14 2003 *************** *** 380,385 **** --- 380,387 ---- EXTRA|NOTRLCOM), EX(CMD_helpfind, "helpfind", ex_helpfind, EXTRA|NOTRLCOM), + EX(CMD_helpgrep, "helpgrep", ex_helpgrep, + EXTRA|NOTRLCOM|NEEDARG), EX(CMD_helptags, "helptags", ex_helptags, NEEDARG|FILE1|TRLBAR|CMDWIN), EX(CMD_hardcopy, "hardcopy", ex_hardcopy, *** ../vim61.422/src/ex_docmd.c Sat Mar 15 17:55:18 2003 --- src/ex_docmd.c Fri Mar 28 19:33:38 2003 *************** *** 115,120 **** --- 115,121 ---- # define ex_cfile ex_ni # define qf_list ex_ni # define qf_age ex_ni + # define ex_helpgrep ex_ni #endif #if !defined(FEAT_QUICKFIX) || !defined(FEAT_WINDOWS) # define ex_cclose ex_ni *** ../vim61.422/src/proto/quickfix.pro Fri Mar 22 21:41:19 2002 --- src/proto/quickfix.pro Thu Mar 27 23:19:13 2003 *************** *** 17,20 **** --- 17,21 ---- void ex_cc __ARGS((exarg_T *eap)); void ex_cnext __ARGS((exarg_T *eap)); void ex_cfile __ARGS((exarg_T *eap)); + void ex_helpgrep __ARGS((exarg_T *eap)); /* vim: set ft=c : */ *** ../vim61.422/src/quickfix.c Sun Mar 9 14:08:43 2003 --- src/quickfix.c Thu Mar 27 23:40:41 2003 *************** *** 21,43 **** char_u *dirname; }; - static void qf_msg __ARGS((void)); - static void qf_free __ARGS((int idx)); - static char_u *qf_types __ARGS((int, int)); - static int qf_get_fnum __ARGS((char_u *, char_u *)); - static char_u *qf_push_dir __ARGS((char_u *, struct dir_stack_T **)); - static char_u *qf_pop_dir __ARGS((struct dir_stack_T **)); - static char_u *qf_guess_filepath __ARGS((char_u *)); - static void qf_fmt_text __ARGS((char_u *text, char_u *buf, int bufsize)); - static void qf_clean_dir_stack __ARGS((struct dir_stack_T **)); - #ifdef FEAT_WINDOWS - static int qf_win_pos_update __ARGS((int old_qf_index)); - static buf_T *qf_find_buf __ARGS((void)); - static void qf_update_buffer __ARGS((void)); - static void qf_fill_buffer __ARGS((void)); - #endif - static char_u *get_mef_name __ARGS((void)); - static struct dir_stack_T *dir_stack = NULL; /* --- 21,26 ---- *************** *** 54,60 **** char_u *qf_text; /* description of the error */ char_u qf_virt_col; /* set to TRUE if qf_col is screen column */ char_u qf_cleared;/* set to TRUE if line has been deleted */ ! char_u qf_type; /* type of the error (mostly 'E') */ char_u qf_valid; /* valid error message detected */ }; --- 37,44 ---- char_u *qf_text; /* description of the error */ char_u qf_virt_col; /* set to TRUE if qf_col is screen column */ char_u qf_cleared;/* set to TRUE if line has been deleted */ ! char_u qf_type; /* type of the error (mostly 'E'); 1 for ! :helpgrep */ char_u qf_valid; /* valid error message detected */ }; *************** *** 102,107 **** --- 86,110 ---- /* '-' do not include this line */ }; + static void qf_new_list __ARGS((void)); + static int qf_add_entry __ARGS((struct qf_line **prevp, char_u *dir, char_u *fname, char_u *msg, long lnum, int col, int virt_col, int nr, int type, int valid)); + static void qf_msg __ARGS((void)); + static void qf_free __ARGS((int idx)); + static char_u *qf_types __ARGS((int, int)); + static int qf_get_fnum __ARGS((char_u *, char_u *)); + static char_u *qf_push_dir __ARGS((char_u *, struct dir_stack_T **)); + static char_u *qf_pop_dir __ARGS((struct dir_stack_T **)); + static char_u *qf_guess_filepath __ARGS((char_u *)); + static void qf_fmt_text __ARGS((char_u *text, char_u *buf, int bufsize)); + static void qf_clean_dir_stack __ARGS((struct dir_stack_T **)); + #ifdef FEAT_WINDOWS + static int qf_win_pos_update __ARGS((int old_qf_index)); + static buf_T *qf_find_buf __ARGS((void)); + static void qf_update_buffer __ARGS((void)); + static void qf_fill_buffer __ARGS((void)); + #endif + static char_u *get_mef_name __ARGS((void)); + /* * Read the errorfile into memory, line by line, building the error list. * Return -1 for error, number of errors for success. *************** *** 122,128 **** long lnum = 0L; int enr = 0; FILE *fd; - struct qf_line *qfp = NULL; struct qf_line *qfprev = NULL; /* init to make SASC shut up */ char_u *efmp; struct eformat *fmt_first = NULL; --- 125,130 ---- *************** *** 176,213 **** } if (newlist || qf_curlist == qf_listcount) ! { ! /* ! * If the current entry is not the last entry, delete entries below ! * the current entry. This makes it possible to browse in a tree-like ! * way with ":grep'. ! */ ! while (qf_listcount > qf_curlist + 1) ! qf_free(--qf_listcount); ! ! /* ! * When the stack is full, remove to oldest entry ! * Otherwise, add a new entry. ! */ ! if (qf_listcount == LISTCOUNT) ! { ! qf_free(0); ! for (i = 1; i < LISTCOUNT; ++i) ! qf_lists[i - 1] = qf_lists[i]; ! qf_curlist = LISTCOUNT - 1; ! } ! else ! qf_curlist = qf_listcount++; ! qf_lists[qf_curlist].qf_index = 0; ! qf_lists[qf_curlist].qf_count = 0; ! } else if (qf_lists[qf_curlist].qf_count > 0) - { /* Adding to existing list, find last entry. */ for (qfprev = qf_lists[qf_curlist].qf_start; qfprev->qf_next != qfprev; qfprev = qfprev->qf_next) ; - } /* * Each part of the format string is copied and modified from errorformat to --- 178,190 ---- } if (newlist || qf_curlist == qf_listcount) ! /* make place for a new list */ ! qf_new_list(); else if (qf_lists[qf_curlist].qf_count > 0) /* Adding to existing list, find last entry. */ for (qfprev = qf_lists[qf_curlist].qf_start; qfprev->qf_next != qfprev; qfprev = qfprev->qf_next) ; /* * Each part of the format string is copied and modified from errorformat to *************** *** 518,527 **** if (*namebuf == NUL) { EMSG(_("E379: Missing or empty directory name")); ! goto error1; } if ((directory = qf_push_dir(namebuf, &dir_stack)) == NULL) ! goto error1; } else if (idx == 'X') /* leave directory */ directory = qf_pop_dir(&dir_stack); --- 495,504 ---- if (*namebuf == NUL) { EMSG(_("E379: Missing or empty directory name")); ! goto error2; } if ((directory = qf_push_dir(namebuf, &dir_stack)) == NULL) ! goto error2; } else if (idx == 'X') /* leave directory */ directory = qf_pop_dir(&dir_stack); *************** *** 540,569 **** else if (vim_strchr((char_u *)"CZ", idx) != NULL) { /* continuation of multi-line msg */ if (qfprev == NULL) ! goto error1; if (*errmsg && !multiignore) { len = (int)STRLEN(qfprev->qf_text); if ((ptr = alloc((unsigned)(len + STRLEN(errmsg) + 2))) == NULL) ! goto error1; STRCPY(ptr, qfprev->qf_text); vim_free(qfprev->qf_text); qfprev->qf_text = ptr; *(ptr += len) = '\n'; STRCPY(++ptr, errmsg); } ! if (qfp->qf_nr == -1) ! qfp->qf_nr = enr; ! if (vim_isprintc(type) && !qfp->qf_type) ! qfp->qf_type = type; /* only printable chars allowed */ ! if (!qfp->qf_lnum) ! qfp->qf_lnum = lnum; ! if (!qfp->qf_col) ! qfp->qf_col = col; ! qfp->qf_virt_col = use_virt_col; ! if (!qfp->qf_fnum) ! qfp->qf_fnum = qf_get_fnum(directory, *namebuf || directory ? namebuf : currfile && valid ? currfile : 0); if (idx == 'Z') --- 517,546 ---- else if (vim_strchr((char_u *)"CZ", idx) != NULL) { /* continuation of multi-line msg */ if (qfprev == NULL) ! goto error2; if (*errmsg && !multiignore) { len = (int)STRLEN(qfprev->qf_text); if ((ptr = alloc((unsigned)(len + STRLEN(errmsg) + 2))) == NULL) ! goto error2; STRCPY(ptr, qfprev->qf_text); vim_free(qfprev->qf_text); qfprev->qf_text = ptr; *(ptr += len) = '\n'; STRCPY(++ptr, errmsg); } ! if (qfprev->qf_nr == -1) ! qfprev->qf_nr = enr; ! if (vim_isprintc(type) && !qfprev->qf_type) ! qfprev->qf_type = type; /* only printable chars allowed */ ! if (!qfprev->qf_lnum) ! qfprev->qf_lnum = lnum; ! if (!qfprev->qf_col) ! qfprev->qf_col = col; ! qfprev->qf_virt_col = use_virt_col; ! if (!qfprev->qf_fnum) ! qfprev->qf_fnum = qf_get_fnum(directory, *namebuf || directory ? namebuf : currfile && valid ? currfile : 0); if (idx == 'Z') *************** *** 598,640 **** } } ! if ((qfp = (struct qf_line *)alloc((unsigned)sizeof(struct qf_line))) ! == NULL) goto error2; - - qfp->qf_fnum = qf_get_fnum(directory, *namebuf || directory ? - namebuf : currfile && valid ? currfile : 0); - if ((qfp->qf_text = vim_strsave(errmsg)) == NULL) - goto error1; - if (!vim_isprintc(type)) /* only printable chars allowed */ - type = 0; - qfp->qf_lnum = lnum; - qfp->qf_col = col; - qfp->qf_virt_col = use_virt_col; - qfp->qf_nr = enr; - qfp->qf_type = type; - qfp->qf_valid = valid; - - if (qf_lists[qf_curlist].qf_count == 0) /* first element in the list */ - { - qf_lists[qf_curlist].qf_start = qfp; - qfp->qf_prev = qfp; /* first element points to itself */ - } - else - { - qfp->qf_prev = qfprev; - qfprev->qf_next = qfp; - } - qfp->qf_next = qfp; /* last element points to itself */ - qfp->qf_cleared = FALSE; - qfprev = qfp; - ++qf_lists[qf_curlist].qf_count; - if (qf_lists[qf_curlist].qf_index == 0 && qfp->qf_valid) - /* first valid entry */ - { - qf_lists[qf_curlist].qf_index = qf_lists[qf_curlist].qf_count; - qf_lists[qf_curlist].qf_ptr = qfp; - } line_breakcheck(); } if (!ferror(fd)) --- 575,593 ---- } } ! if (qf_add_entry(&qfprev, ! directory, ! *namebuf || directory ! ? namebuf ! : currfile && valid ? currfile : NULL, ! errmsg, ! lnum, ! col, ! use_virt_col, ! enr, ! type, ! valid) == FAIL) goto error2; line_breakcheck(); } if (!ferror(fd)) *************** *** 655,662 **** goto qf_init_ok; } EMSG(_(e_readerrf)); - error1: - vim_free(qfp); error2: qf_free(qf_curlist); qf_listcount--; --- 608,613 ---- *************** *** 685,690 **** --- 636,735 ---- } /* + * Prepare for adding a new quickfix list. + */ + static void + qf_new_list() + { + int i; + + /* + * If the current entry is not the last entry, delete entries below + * the current entry. This makes it possible to browse in a tree-like + * way with ":grep'. + */ + while (qf_listcount > qf_curlist + 1) + qf_free(--qf_listcount); + + /* + * When the stack is full, remove to oldest entry + * Otherwise, add a new entry. + */ + if (qf_listcount == LISTCOUNT) + { + qf_free(0); + for (i = 1; i < LISTCOUNT; ++i) + qf_lists[i - 1] = qf_lists[i]; + qf_curlist = LISTCOUNT - 1; + } + else + qf_curlist = qf_listcount++; + qf_lists[qf_curlist].qf_index = 0; + qf_lists[qf_curlist].qf_count = 0; + } + + /* + * Add an entry to the end of the list of errors. + * Returns OK or FAIL. + */ + static int + qf_add_entry(prevp, dir, fname, msg, lnum, col, virt_col, nr, type, valid) + struct qf_line **prevp; /* pointer to previously added entry or NULL */ + char_u *dir; /* optional directory name */ + char_u *fname; /* file name or NULL */ + char_u *msg; /* message */ + long lnum; /* line number */ + int col; /* column */ + int virt_col; /* using virtual column */ + int nr; /* error number */ + int type; /* type character */ + int valid; /* valid entry */ + { + struct qf_line *qfp; + + if ((qfp = (struct qf_line *)alloc((unsigned)sizeof(struct qf_line))) + == NULL) + return FAIL; + qfp->qf_fnum = qf_get_fnum(dir, fname); + if ((qfp->qf_text = vim_strsave(msg)) == NULL) + { + vim_free(qfp); + return FAIL; + } + qfp->qf_lnum = lnum; + qfp->qf_col = col; + qfp->qf_virt_col = virt_col; + qfp->qf_nr = nr; + if (type != 1 && !vim_isprintc(type)) /* only printable chars allowed */ + type = 0; + qfp->qf_type = type; + qfp->qf_valid = valid; + + if (qf_lists[qf_curlist].qf_count == 0) /* first element in the list */ + { + qf_lists[qf_curlist].qf_start = qfp; + qfp->qf_prev = qfp; /* first element points to itself */ + } + else + { + qfp->qf_prev = *prevp; + (*prevp)->qf_next = qfp; + } + qfp->qf_next = qfp; /* last element points to itself */ + qfp->qf_cleared = FALSE; + *prevp = qfp; + ++qf_lists[qf_curlist].qf_count; + if (qf_lists[qf_curlist].qf_index == 0 && qfp->qf_valid) + /* first valid entry */ + { + qf_lists[qf_curlist].qf_index = qf_lists[qf_curlist].qf_count; + qf_lists[qf_curlist].qf_ptr = qfp; + } + + return OK; + } + + /* * get buffer number for file "dir.name" */ static int *************** *** 1261,1267 **** --- 1306,1316 ---- fname = NULL; if (qfp->qf_fnum != 0 && (buf = buflist_findnr(qfp->qf_fnum)) != NULL) + { fname = buf->b_fname; + if (qfp->qf_type == 1) /* :helpgrep */ + fname = gettail(fname); + } if (fname == NULL) sprintf((char *)IObuff, "%2d", i); else *************** *** 1452,1457 **** --- 1501,1507 ---- * i or I n " info n" * 0 n " error n" * other n " c n" + * 1 x "" :helpgrep */ static char_u * qf_types(c, nr) *************** *** 1467,1473 **** p = (char_u *)" info"; else if (c == 'E' || c == 'e' || (c == 0 && nr > 0)) p = (char_u *)" error"; ! else if (c == 0) p = (char_u *)""; else { --- 1517,1523 ---- p = (char_u *)" info"; else if (c == 'E' || c == 'e' || (c == 0 && nr > 0)) p = (char_u *)" error"; ! else if (c == 0 || c == 1) p = (char_u *)""; else { *************** *** 1751,1757 **** && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL && errbuf->b_fname != NULL) { ! STRCPY(IObuff, errbuf->b_fname); len = (int)STRLEN(IObuff); } else --- 1801,1810 ---- && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL && errbuf->b_fname != NULL) { ! if (qfp->qf_type == 1) /* :helpgrep */ ! STRCPY(IObuff, gettail(errbuf->b_fname)); ! else ! STRCPY(IObuff, errbuf->b_fname); len = (int)STRLEN(IObuff); } else *************** *** 2032,2037 **** --- 2085,2182 ---- set_string_option_direct((char_u *)"ef", -1, eap->arg, OPT_FREE); if (qf_init(p_ef, p_efm, TRUE) > 0 && eap->cmdidx == CMD_cfile) qf_jump(0, 0, eap->forceit); /* display first error */ + } + + /* + * ":helpgrep {pattern}" + */ + void + ex_helpgrep(eap) + exarg_T *eap; + { + regmatch_T regmatch; + char_u *save_cpo; + char_u *p; + int fcount; + char_u **fnames; + FILE *fd; + int fi; + struct qf_line *prevp = NULL; + long lnum; + + /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ + save_cpo = p_cpo; + p_cpo = (char_u *)""; + + regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING); + regmatch.rm_ic = FALSE; + if (regmatch.regprog != NULL) + { + /* create a new quickfix list */ + qf_new_list(); + + /* Go through all directories in 'runtimepath' */ + p = p_rtp; + while (*p != NUL && !got_int) + { + copy_option_part(&p, NameBuff, MAXPATHL, ","); + + /* Find all "doc / *.txt" files in this directory. */ + add_pathsep(NameBuff); + STRCAT(NameBuff, "doc/*.txt"); + if (gen_expand_wildcards(1, &NameBuff, &fcount, + &fnames, EW_FILE|EW_SILENT) == OK + && fcount > 0) + { + for (fi = 0; fi < fcount && !got_int; ++fi) + { + fd = fopen((char *)fnames[fi], "r"); + if (fd != NULL) + { + lnum = 1; + while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) + { + if (vim_regexec(®match, IObuff, (colnr_T)0)) + if (qf_add_entry(&prevp, + NULL, /* dir */ + fnames[fi], + IObuff, + lnum, + 0, /* col */ + FALSE, /* virt_col */ + 0, /* nr */ + 1, /* type */ + TRUE /* valid */ + ) == FAIL) + { + got_int = TRUE; + break; + } + ++lnum; + line_breakcheck(); + } + fclose(fd); + } + } + FreeWild(fcount, fnames); + } + } + vim_free(regmatch.regprog); + + qf_lists[qf_curlist].qf_nonevalid = FALSE; + qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start; + qf_lists[qf_curlist].qf_index = 1; + } + + p_cpo = save_cpo; + + #ifdef FEAT_WINDOWS + qf_update_buffer(); + #endif + + /* Jump to first match. */ + if (qf_lists[qf_curlist].qf_count > 0) + qf_jump(0, 0, FALSE); } #endif /* FEAT_QUICKFIX */ *** ../vim61.422/src/version.c Wed Mar 26 22:26:31 2003 --- src/version.c Fri Mar 28 21:42:45 2003 *************** *** 613,614 **** --- 613,616 ---- { /* Add new patch number below this line */ + /**/ + 423, /**/ -- hundred-and-one symptoms of being an internet addict: 254. You wake up daily with your keyboard printed on your forehead. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// Creator of Vim - Vi IMproved -- http://www.Vim.org \\\ \\\ Project leader for A-A-P -- http://www.A-A-P.org /// \\\ Help AIDS victims, buy at Amazon -- http://ICCF.nl/click1.html ///