While awk is POSIX, perl isn't pre-installed on all *nix flavors.
This commit eliminates the mandatory dependency on perl by using awk
when perl is not available.
Related: #3295, #3309, #3310.
Test suite passed:
* `make error` all test sections 'PASS'
* `make docker-test` 215 runs, 1884 assertions, 0 failures, 0 errors, 0 skips.
Manually tested in the following environments:
* Linux amd64 with bash 3.2, 4.4, 5.2; gawk -P, one true awk, mawk, busybox awk.
* macOS Catalina, bash 3.2, macOS awk 20070501.
**Performance comparison:**
Mawk turned out the fastest, then perl.
One true awk's implementation should be the closest to macOS awk.
Test data: 230 KB history, 15102 entries, including multi-line and duplicates.
Linux, bash 4.4. Times in milliseconds.
| Command | Mean | Min | Max | Relative |
| :--- | ---: | ---: | ---: | -------: |
| `mawk 1.3.4` | 22.9 | 22.3 | 25.6 | **1.00** |
| `perl 5.26.1` | 34.3 | 33.6 | 35.1 | 1.49 |
| `one true awk 20221215` | 41.9 | 40.6 | 46.3 | 1.83 |
| `gawk 5.1.0` | 46.1 | 44.4 | 50.3 | 2.01 |
| `busybox awk 1.27.0` | 64.8 | 63.2 | 70.0 | 2.82 |
**Other Notes**
A bug affects bash, which fails restoring a saved multi-line history entry as a single entry. Bug fixed in version 5.0.[^1]
While developing this PR I discovered two unsubmitted issues affecting the current perl script. The output stream ends with `$'\n\0000'` instead of `$'\0000'`. Because of this, the script does not deduplicate a duplicated entry located at the end of the history list; therefore fzf displays two identical (not necessarily adjacent) entries. A minor point about the first issue is that the top fzf entry ends with a dangling line feed symbol, which is visible in the terminal.
[^1]: ec8113b986/CHANGES (L1511)
To enable: `shopt -s cmdhist lithist; HISTTIMEFORMAT='%F %T '`.
* Explicitly specify the list of fields for consistent experience
* Add fallback command for BusyBox (Close#3219)
* Apply `--header-lines=1` to show the column header
Unlike awk, which is even defined in POSIX, perl is not pre-installed
on all *nix systems. This awk command is functionally equivalent to
the original perl command.
- extract logical parts to separate variables (e.g. $opts)
- put options in $opts in similar order
- move +/-m into $opts (at the end, so they won't be overridden)
- split pipelines into multiple lines
- remove "echo" that seems to be redundant
All this should help with readability and also result in cleaner diffs
when changes are made.
This makes it easier to make customizations, for example instead of
bind -x '"\C-o\C-i": FZF_CTRL_T_COMMAND="fasd -Rl" FZF_DEFAULT_OPTS="$FZF_DEFAULT_OPTS --tiebreak=index " fzf-file-widget'
it's enough to just
bind -x '"\C-o\C-i": FZF_CTRL_T_COMMAND="fasd -Rl" fzf-file-widget --tiebreak=index'
I forgot to add the "not _fzf" check into __fzf_orig_completion, so
invoking it twice would rewrite the _fzf_orig_completion_xxx variables
and then cause an endless loop when completion is requested.
Fixes: ef2c29d5d4 ("[bash-completion] Optimize __fzf_orig_completion_filter")
Commit d4ad4a25 slowed loading of completion.bash significantly (on my
laptop from 10 ms to 30 ms), then 54891d11 improved that (to 20 ms) but
it still stands out as the heavy part of my .bashrc.
Rewriting __fzf_orig_completion_filter to pure bash without forking to
sed/awk brings this back under 10 ms.
before:
$ HISTFILE=/tmp/bashhist hyperfine 'bash --rcfile shell/completion.bash -i'
Benchmark #1: bash --rcfile shell/completion.bash -i
Time (mean ± σ): 21.2 ms ± 0.3 ms [User: 24.9 ms, System: 6.4 ms]
Range (min … max): 20.7 ms … 23.3 ms 132 runs
after:
$ HISTFILE=/tmp/bashhist hyperfine 'bash --rcfile shell/completion.bash -i'
Benchmark #1: bash --rcfile shell/completion.bash -i
Time (mean ± σ): 9.6 ms ± 0.3 ms [User: 8.0 ms, System: 2.2 ms]
Range (min … max): 9.3 ms … 11.4 ms 298 runs
Fixes: d4ad4a25db ("[bash-completion] Fix default alias/variable completion")
Fixes: 54891d11e0 ("[bash-completion] Minor optimization")
This prevents mistakes like the one fixed by the previous commit, and
also speeds bash startup a tiny bit:
before:
$ HISTFILE=/tmp/bashhist hyperfine 'bash --rcfile shell/completion.bash -i'
Benchmark #1: bash --rcfile shell/completion.bash -i
Time (mean ± σ): 22.4 ms ± 0.6 ms [User: 28.7 ms, System: 7.8 ms]
Range (min … max): 21.7 ms … 25.2 ms 123 runs
after:
$ HISTFILE=/tmp/bashhist hyperfine 'bash --rcfile shell/completion.bash -i'
Benchmark #1: bash --rcfile shell/completion.bash -i
Time (mean ± σ): 21.2 ms ± 0.3 ms [User: 24.9 ms, System: 6.4 ms]
Range (min … max): 20.7 ms … 23.3 ms 132 runs
This doesn't look right:
$ complete | grep ' _.$'
complete _a
complete _v
The __fzf_orig_completion_filter invocation in _fzf_setup_completion
needs the /-F/ filter, just like all the other invocations.
Fixes: d4ad4a25db ("[bash-completion] Fix default alias/variable completion")
Ideally, we could only use `print -sr` to update the command history.
However, the "cd" command by ALT-C is added to the history only after we
finalize the current command by pressing an additional enter key.
i.e. The cd command from ALT-C is not visible when you hit Up arrow. But
it appears once you hit enter key.
So when the current buffer is empty, we use `zle accept-line` so that
the command history is immediately updated.
Close#2200