diff --git a/command.c b/command.c index ed5b323..a6a3e41 100755 --- a/command.c +++ b/command.c @@ -54,6 +54,8 @@ extern int screen_trashed; /* The screen has been overwritten */ extern int shift_count; extern int oldbot; extern int forw_prompt; +extern int incremental_search; +extern int same_pos_bell; #if SHELL_ESCAPE static char *shellcmd = NULL; /* For holding last shell command for "!!" */ @@ -68,6 +70,7 @@ static int optflag; static int optgetname; static POSITION bottompos; static int save_hshift; +static struct mark searchstack[CMDBUF_SIZE]; #if PIPEC static char pipec; #endif @@ -210,7 +213,7 @@ exec_mca() { case A_F_SEARCH: case A_B_SEARCH: - multi_search(cbuf, (int) number); + multi_search(cbuf, (int) number, 0); break; #if HILITE_SEARCH case A_FILTER: @@ -523,6 +526,7 @@ mca_search_char(c) mca_char(c) int c; { + char *cbuf; int ret; switch (mca) @@ -613,6 +617,43 @@ mca_char(c) return (MCA_DONE); } + if (incremental_search && (mca == A_F_SEARCH || mca == A_B_SEARCH)) + { + /* + * Special case for incremental search. + * Run multi_search with incremental=1 + * and repaint prompt after each char in search. + * Don't ring the same-position bell while typing. + */ + same_pos_bell = 0; + if (is_erase_char(c)) + { + /* Return to previous incremental search position. */ + struct mark *m = &searchstack[len_cmdbuf()]; + if (edit_ifile(m->m_ifile)) + return (MCA_DONE); + jump_loc(m->m_scrpos.pos, m->m_scrpos.ln); + forw_prompt = 0; + } else if (len_cmdbuf() > 0) + { + /* Remember this position for later erase_char. */ + struct mark *m = &searchstack[len_cmdbuf()-1]; + struct scrpos scrpos; + get_scrpos(&scrpos); + m->m_scrpos = scrpos; + m->m_ifile = curr_ifile; + } + cbuf = get_cmdbuf(); + if (len_cmdbuf() == 0) + undo_search(); + else if (valid_pattern(cbuf)) + multi_search(cbuf, (int) number, 1); + same_pos_bell = 1; + /* Repaint search prompt and pattern. */ + mca_search(); + cmd_putstr(cbuf); + } + /* * Need another character. */ @@ -778,7 +819,7 @@ getcc() * We have just run out of ungotten chars. */ unget_end = 0; - if (len_cmdbuf() == 0 || !empty_screen()) + if (len_cmdbuf() == 0) return (getchr()); /* * Command is incomplete, so try to complete it. @@ -863,9 +904,10 @@ ungetsc(s) * If SRCH_PAST_EOF is set, continue the search thru multiple files. */ static void -multi_search(pattern, n) +multi_search(pattern, n, incremental) char *pattern; int n; + int incremental; { register int nomore; IFILE save_ifile; @@ -940,7 +982,7 @@ multi_search(pattern, n) * Didn't find it. * Print an error message if we haven't already. */ - if (n > 0) + if (n > 0 && !incremental) error("Pattern not found", NULL_PARG); if (changed_file) @@ -1383,7 +1425,7 @@ commands() if (number <= 0) number = 1; \ mca_search(); \ cmd_exec(); \ - multi_search((char *)NULL, (int) number); + multi_search((char *)NULL, (int) number, 0); case A_F_SEARCH: diff --git a/forwback.c b/forwback.c index 21b500c..bd4ce11 100755 --- a/forwback.c +++ b/forwback.c @@ -20,6 +20,7 @@ public int screen_trashed; public int squished; public int no_back_scroll = 0; public int forw_prompt; +public int same_pos_bell = 1; extern int sigs; extern int top_scroll; @@ -271,7 +272,7 @@ forw(n, pos, force, only_last, nblank) forw_prompt = 1; } - if (nlines == 0) + if (nlines == 0 && same_pos_bell) eof_bell(); else if (do_repaint) repaint(); @@ -322,7 +323,7 @@ back(n, pos, force, only_last) } } - if (nlines == 0) + if (nlines == 0 && same_pos_bell) eof_bell(); else if (do_repaint) repaint(); diff --git a/help.c b/help.c index 46b8ff1..6a3d219 100644 --- a/help.c +++ b/help.c @@ -192,6 +192,8 @@ constant char helpdata[] = { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','o','n','\'','t',' ','u','s','e',' ','t','e','r','m','c','a','p',' ','i','n','i','t','/','d','e','i','n','i','t',' ','s','t','r','i','n','g','s','.','\n', ' ',' ','-','y',' ','[','_','\b','N',']',' ',' ','.','.','.','.',' ',' ','-','-','m','a','x','-','f','o','r','w','-','s','c','r','o','l','l','=','[','_','\b','N',']','\n', ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','F','o','r','w','a','r','d',' ','s','c','r','o','l','l',' ','l','i','m','i','t','.','\n', +' ',' ','-','Y',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','i','n','c','r','e','m','e','n','t','a','l','-','s','e','a','r','c','h','\n', +' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','a','r','c','h',' ','a','s',' ','t','h','e',' ','i','n','p','u','t',' ','p','a','t','t','e','r','n',' ','c','h','a','n','g','e','s','.','\n', ' ',' ','-','z',' ','[','_','\b','N',']',' ',' ','.','.','.','.',' ',' ','-','-','w','i','n','d','o','w','=','[','_','\b','N',']','\n', ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','s','i','z','e',' ','o','f',' ','w','i','n','d','o','w','.','\n', ' ',' ','-','"',' ','[','_','\b','c','[','_','\b','c',']',']',' ',' ','.',' ',' ','-','-','q','u','o','t','e','s','=','[','_','\b','c','[','_','\b','c',']',']','\n', diff --git a/less.h b/less.h index fada513..5884189 100755 --- a/less.h +++ b/less.h @@ -295,6 +295,15 @@ struct scrpos int ln; }; +/* + * A mark is an ifile (input file) plus a position within the file. + */ +struct mark +{ + IFILE m_ifile; + struct scrpos m_scrpos; +}; + typedef union parg { char *p_string; diff --git a/less.hlp b/less.hlp index 45a7fe5..fe9d055 100755 --- a/less.hlp +++ b/less.hlp @@ -189,6 +189,8 @@ Don't use termcap init/deinit strings. -y [_N] .... --max-forw-scroll=[_N] Forward scroll limit. + -Y ........ --incremental-search + Search as the input pattern changes. -z [_N] .... --window=[_N] Set size of window. -" [_c[_c]] . --quotes=[_c[_c]] diff --git a/mark.c b/mark.c index c61ce03..135f6fb 100755 --- a/mark.c +++ b/mark.c @@ -14,14 +14,6 @@ extern IFILE curr_ifile; extern int sc_height; extern int jump_sline; -/* - * A mark is an ifile (input file) plus a position within the file. - */ -struct mark { - IFILE m_ifile; - struct scrpos m_scrpos; -}; - /* * The table of marks. * Each mark is identified by a lowercase or uppercase letter. diff --git a/opttbl.c b/opttbl.c index 6f582bf..ff203b1 100755 --- a/opttbl.c +++ b/opttbl.c @@ -53,6 +53,7 @@ public int quit_on_intr; /* Quit on interrupt */ public int follow_mode; /* F cmd Follows file desc or file name? */ public int oldbot; /* Old bottom of screen behavior {{REMOVE}} */ public int opt_use_backslash; /* Use backslash escaping in option parsing */ +public int incremental_search; /* Display search results after each char in pattern */ #if HILITE_SEARCH public int hilite_search; /* Highlight matched search patterns? */ #endif @@ -108,6 +109,7 @@ static struct optname w_optname = { "hilite-unread", NULL }; static struct optname x_optname = { "tabs", NULL }; static struct optname X__optname = { "no-init", NULL }; static struct optname y_optname = { "max-forw-scroll", NULL }; +static struct optname Y__optname = { "incremental-search", NULL }; static struct optname z_optname = { "window", NULL }; static struct optname quote_optname = { "quotes", NULL }; static struct optname tilde_optname = { "tilde", NULL }; @@ -392,6 +394,14 @@ static struct loption option[] = NULL } }, + { 'Y', &Y__optname, + BOOL, OPT_OFF, &incremental_search, NULL, + { + "Normal search (press Enter to search)", + "Incremental search", + NULL + } + }, { 'z', &z_optname, NUMBER, -1, &swindow, NULL, { diff --git a/pattern.c b/pattern.c index fa26b99..69bb616 100755 --- a/pattern.c +++ b/pattern.c @@ -20,10 +20,11 @@ extern int caseless; * Compile a search pattern, for future use by match_pattern. */ static int -compile_pattern2(pattern, search_type, comp_pattern) +compile_pattern2(pattern, search_type, comp_pattern, show_error) char *pattern; int search_type; void **comp_pattern; + int show_error; { if (search_type & SRCH_NO_REGEX) return (0); @@ -37,7 +38,8 @@ compile_pattern2(pattern, search_type, comp_pattern) if (re_compile_pattern(pattern, strlen(pattern), comp)) { free(comp); - error("Invalid pattern", NULL_PARG); + if (show_error) + error("Invalid pattern", NULL_PARG); return (-1); } if (*pcomp != NULL) @@ -50,7 +52,8 @@ compile_pattern2(pattern, search_type, comp_pattern) if (regcomp(comp, pattern, REGCOMP_FLAG)) { free(comp); - error("Invalid pattern", NULL_PARG); + if (show_error) + error("Invalid pattern", NULL_PARG); return (-1); } if (*pcomp != NULL) @@ -68,7 +71,8 @@ compile_pattern2(pattern, search_type, comp_pattern) if (comp == NULL) { parg.p_string = (char *) errstring; - error("%s", &parg); + if (show_error) + error("%s", &parg); return (-1); } *pcomp = comp; @@ -78,7 +82,8 @@ compile_pattern2(pattern, search_type, comp_pattern) int *pcomp = (int *) comp_pattern; if ((parg.p_string = re_comp(pattern)) != NULL) { - error("%s", &parg); + if (show_error) + error("%s", &parg); return (-1); } *pcomp = 1; @@ -88,7 +93,8 @@ compile_pattern2(pattern, search_type, comp_pattern) char **pcomp = (char **) comp_pattern; if ((comp = regcmp(pattern, 0)) == NULL) { - error("Invalid pattern", NULL_PARG); + if (show_error) + error("Invalid pattern", NULL_PARG); return (-1); } if (pcomp != NULL) @@ -98,7 +104,10 @@ compile_pattern2(pattern, search_type, comp_pattern) #if HAVE_V8_REGCOMP struct regexp *comp; struct regexp **pcomp = (struct regexp **) comp_pattern; - if ((comp = regcomp(pattern)) == NULL) + reg_show_error = show_error; + comp = regcomp(pattern); + reg_show_error = 1; + if (comp == NULL) { /* * regcomp has already printed an error message @@ -133,7 +142,7 @@ compile_pattern(pattern, search_type, comp_pattern) cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC)); cvt_text(cvt_pattern, pattern, (int *)NULL, (int *)NULL, CVT_TO_LC); } - result = compile_pattern2(cvt_pattern, search_type, comp_pattern); + result = compile_pattern2(cvt_pattern, search_type, comp_pattern, 1); if (cvt_pattern != pattern) free(cvt_pattern); return (result); @@ -182,6 +191,24 @@ uncompile_pattern(pattern) #endif } +/* + * Can a pattern be successfully compiled? + */ + public int +valid_pattern(pattern) + char *pattern; +{ + void *comp_pattern; + int result; + + CLEAR_PATTERN(comp_pattern); + result = compile_pattern2(pattern, 0, &comp_pattern, 0); + if (result != 0) + return (0); + uncompile_pattern(&comp_pattern); + return (1); +} + /* * Is a compiled pattern null? */ diff --git a/search.c b/search.c index 24d4210..029ce32 100755 --- a/search.c +++ b/search.c @@ -1243,12 +1243,16 @@ is_filtering() * This function is called by the V8 regcomp to report * errors in regular expressions. */ +public int reg_show_error = 1; + void regerror(s) char *s; { PARG parg; + if (!reg_show_error) + return; parg.p_string = s; error("%s", &parg); }