bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

word selection in history expansion - !?word?%


From: Jess M
Subject: word selection in history expansion - !?word?%
Date: Thu, 8 Aug 2024 23:15:27 -0700

Observed behaviour:
```
$ echo word01 word02 word03 floogle
word01 word02 word03 floogle
$ echo !?word?%
echo word03
word03
$ # I expected to get word01
$ echo $BASH_VERSION
5.2.26(1)-release
```

The bash manual for word designators sounds to me as if word01 should be
selected.

https://www.gnu.org/software/bash/manual/html_node/Word-Designators.html
---
Word designators are used to select desired words from the event. A ‘:’
separates the event specification from the word designator. It may be
omitted if the word designator begins with a ‘^’, ‘$’, ‘*’, ‘-’, or ‘%’.
Words are numbered from the beginning of the line, with the first word
being denoted by 0 (zero). Words are inserted into the current line
separated by single spaces.
...
%    The first word matched by the most recent ‘?string?’ search, if the
search string begins with a character that is part of a word.
---

The page header has words numbered from the beginning of the line, and the
description of `%` says first.  Thus, I would expect the history expansion
to provide word01.

Looking at the code that performs % interpolation, that behaviour is
hard-coded to do a reverse search on the line.  The way this reverse search
comes about seems odd, as the search direction choice is used in two
different contexts.  That is, specifying the reverse direction seems to
want to primarily govern whether the line search proceeds by going in the
previous direction in all of history or the subsequent history direction.
However specifying the reverse direction has the in-line word search start
from the end of the line; providing a positive direction value has the word
search proceed from the start of the line.  Thus, direction controls two
distinct facets: history search direction and line search direction.

This code behaviour may be intended.  If so, the documentation needs
updated.  But if the documentation describes the intended behaviour, then
the code needs adjusted.

My opinion would be to allow the user to further guide the shell in whether
they want a forward or backward search for that line.  I'm happy to help
craft a patch for this, but would appreciate some guidance as C isn't a
daily driver for me.


-- Jess M



p.s.
These are my notes in reading through the code:

:% is processed in lib/readline/histexpand.cL1327
it returns value of search_match, from L296
search_match returns the identified word to % using the value of
local_index in a call to history_find_word

we're in a block that starts at L273.  There, we're substring_okay, so we
save "history_search" as the function to search lines with.
local_index is set from a function call on L276
we pass in the hardcoded value of -1 for Direction, indicating we want to
search through previous history entries, not subsequent history entries

lib/readline/history.h describes search direction:
L175:
/* Search the history for STRING, starting at history_offset.
   If DIRECTION < 0, then the search is through previous entries,
   else through subsequent.  If the string is found, then
   current_history () is the history entry, and the value of this function
   is the offset in the line of that history entry that the string was
   found in.  Otherwise, nothing is changed, and a -1 is returned. */

Jump to lib/readline/histsearch.cL257 -- The history_search() we used wraps
history_search_internal()
history_search_internal starts on L67
It's longish; our substring search starts processing on L141 with the
crucial check of `if (reverse)`
the if controls the direction of the scanning of the line.  if reverse,
start checking the index = line_length i.e. from the end of the string and
decrement our index as we search the string.  if not reverse, start
checking with index = 0 and increment our index as we search across the
line.
Going back to histexpand.cL276, we hard-coded reverse as the direction in
our call to history_search().
Presumably this reverse direction intends only to designate a search
through previous history; but it also has the effect of hard-coding us to
search the command line for matching word, starting at the end of the
string.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]