add a flag to limit history search results

This adds a flag to the `history search` command to limit the number of
matching entries to the first "n". The default is unlimited. This is
mostly useful in conjunction with aliases (i.e., functions) that are
intended to report the "n" most recent matching history entries without
piping the result through the user's pager.

Fixes #3244
This commit is contained in:
Kurtis Rader 2016-09-20 22:32:38 -07:00
parent c2a8de4873
commit e9b5505169
6 changed files with 58 additions and 12 deletions

View file

@ -2,7 +2,7 @@
\subsection history-synopsis Synopsis
\fish{synopsis}
history search [ --show-time ] [ --exact | --prefix | --contains ] [ "search string"... ]
history search [ --show-time ] [ --exact | --prefix | --contains ] [ --max=n ] [ "search string"... ]
history delete [ --show-time ] [ --exact | --prefix | --contains ] "search string"...
history merge
history save
@ -30,7 +30,7 @@ The following operations (sub-commands) are available:
The following options are available:
These flags can appear before or immediately after on of the sub-commands listed above.
These flags can appear before or immediately after one of the sub-commands listed above.
- `-c` or `--contains` searches or deletes items in the history that contain the specified text string. This is the default for the `--search` flag. This is not currently supported by the `--delete` flag.
@ -40,6 +40,8 @@ These flags can appear before or immediately after on of the sub-commands listed
- `-t` or `--show-time` prepends each history entry with the date and time the entry was recorded . By default it uses the strftime format `# %c%n`. You can specify another format; e.g., `--show-time='%Y-%m-%d %H:%M:%S '` or `--show-time='%a%I%p'`. The short option, `-t` doesn't accept a stftime format string; it only uses the default format. Any strftime format is allowed, including `%s` to get the raw UNIX seconds since the epoch. Note that `--with-time` is also allowed but is deprecated and will be removed at a future date.
- `-<number>` `-n <number>` or `--max=<number>` limits the matched history items to the first "n" matching entries. This is only valid for `history search`.
- `-h` or `--help` display help for this command.
\subsection history-examples Example

View file

@ -10,6 +10,8 @@ complete -c history -n '__fish_seen_subcommand_from search delete' \
-s e -l exact -d "Match items identical to the string"
complete -c history -n '__fish_seen_subcommand_from search delete' \
-s t -l show-time -d "Output with timestamps"
complete -c history -n '__fish_seen_subcommand_from search' \
-s n -l max -d "Limit output to the first 'n' matches"
# We don't include a completion for the "save" subcommand because it should not be used
# interactively.

View file

@ -34,6 +34,7 @@ function history --description "display or manipulate interactive command histor
set -l hist_cmd
set -l search_mode
set -l show_time
set -l max_count
# Check for a recognized subcommand as the first argument.
if set -q argv[1]
@ -78,11 +79,24 @@ function history --description "display or manipulate interactive command histor
set search_mode --contains
case -e --exact
set search_mode --exact
case -n --max
if string match -- '-n?*' $argv[1]
or string match -- '--max=*' $argv[1]
set max_count $argv[1]
else
set max_count $argv[1] $argv[2]
set -e argv[1]
end
case --
set -e argv[1]
break
case '*'
break
if string match -r -- '-\d+' $argv[1]
set max_count $argv[1]
set -e argv[1]
else
break
end
end
set -e argv[1]
end
@ -107,13 +121,14 @@ function history --description "display or manipulate interactive command histor
test -z "$search_mode"
and set search_mode "--contains"
echo "builtin history search $search_mode $show_time $max_count -- $argv" >>/tmp/x
if isatty stdout
set -l pager less
set -q PAGER
and set pager $PAGER
builtin history search $search_mode $show_time -- $argv | eval $pager
builtin history search $search_mode $show_time $max_count -- $argv | eval $pager
else
builtin history search $search_mode $show_time -- $argv
builtin history search $search_mode $show_time $max_count -- $argv
end
case delete # interactively delete history

View file

@ -2846,18 +2846,20 @@ static int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **ar
int argc = builtin_count_args(argv);
hist_cmd_t hist_cmd = HIST_NOOP;
history_search_type_t search_type = (history_search_type_t)-1;
long max_items = LONG_MAX;
bool history_search_type_defined = false;
const wchar_t *show_time_format = NULL;
// TODO: Remove the long options that correspond to subcommands (e.g., '--delete') on or after
// 2017-10 (which will be a full year after these flags have been deprecated).
const wchar_t *short_options = L":mepcht";
const wchar_t *short_options = L":mn:epcht";
const struct woption long_options[] = {{L"prefix", no_argument, NULL, 'p'},
{L"contains", no_argument, NULL, 'c'},
{L"help", no_argument, NULL, 'h'},
{L"show-time", optional_argument, NULL, 't'},
{L"with-time", optional_argument, NULL, 't'},
{L"exact", no_argument, NULL, 'e'},
{L"max", required_argument, NULL, 'n'},
{L"delete", no_argument, NULL, 1},
{L"search", no_argument, NULL, 2},
{L"save", no_argument, NULL, 3},
@ -2923,6 +2925,17 @@ static int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **ar
show_time_format = w.woptarg ? w.woptarg : L"# %c%n";
break;
}
case 'n': {
wchar_t *end = 0;
max_items = wcstol(w.woptarg, &end, 10);
if (!(*w.woptarg != L'\0' && *end == L'\0')) {
streams.err.append_format(
_(L"%ls: max value '%ls' is not a valid number\n"), argv[0],
w.woptarg);
return STATUS_BUILTIN_ERROR;
}
break;
}
case 'h': {
builtin_print_help(parser, streams, cmd, streams.out);
return STATUS_BUILTIN_OK;
@ -2932,13 +2945,26 @@ static int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **ar
return STATUS_BUILTIN_ERROR;
}
case '?': {
streams.err.append_format(BUILTIN_ERR_UNKNOWN, cmd, argv[w.woptind - 1]);
return STATUS_BUILTIN_ERROR;
// Try to parse it as a number; e.g., "-123".
wchar_t *end = 0;
max_items = wcstol(argv[w.woptind - 1] + 1, &end, 10);
if (!(argv[w.woptind - 1][1] != L'\0' && *end == L'\0')) {
streams.err.append_format(BUILTIN_ERR_UNKNOWN, cmd, argv[w.woptind - 1]);
return STATUS_BUILTIN_ERROR;
}
w.nextchar = NULL;
break;
}
default: { DIE("unexpected retval from wgetopt_long"); }
}
}
if (max_items <= 0) {
streams.err.append_format(_(L"%ls: max value '%ls' is not a valid number\n"), argv[0],
w.woptarg);
return STATUS_BUILTIN_ERROR;
}
// If a history command hasn't already been specified via a flag check the first word.
// Note that this can be simplified after we eliminate allowing subcommands as flags.
// See the TODO above regarding the `long_options` array.
@ -2963,7 +2989,7 @@ static int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **ar
int status = STATUS_BUILTIN_OK;
switch (hist_cmd) {
case HIST_SEARCH: {
if (!history->search(search_type, args, show_time_format, streams)) {
if (!history->search(search_type, args, show_time_format, max_items, streams)) {
status = STATUS_BUILTIN_ERROR;
}
break;

View file

@ -1415,11 +1415,11 @@ static bool format_history_record(const history_item_t &item, const wchar_t *sho
}
bool history_t::search(history_search_type_t search_type, wcstring_list_t search_args,
const wchar_t *show_time_format, io_streams_t &streams) {
const wchar_t *show_time_format, long max_items, io_streams_t &streams) {
// scoped_lock locker(lock);
if (search_args.empty()) {
// Start at one because zero is the current command.
for (int i = 1; !this->item_at_index(i).empty(); ++i) {
for (int i = 1; !this->item_at_index(i).empty() && max_items; ++i, --max_items) {
if (!format_history_record(this->item_at_index(i), show_time_format, streams)) {
return false;
}
@ -1439,6 +1439,7 @@ bool history_t::search(history_search_type_t search_type, wcstring_list_t search
if (!format_history_record(searcher.current_item(), show_time_format, streams)) {
return false;
}
if (--max_items == 0) return true;
}
}

View file

@ -227,7 +227,7 @@ class history_t {
// Searches history.
bool search(history_search_type_t search_type, wcstring_list_t search_args,
const wchar_t *show_time_format, io_streams_t &streams);
const wchar_t *show_time_format, long max_items, io_streams_t &streams);
// Enable / disable automatic saving. Main thread only!
void disable_automatic_saving();