| Age | Commit message (Collapse) | Author | Files | Lines |
|
Showing the popup takes focus away from the query bar and the popup
window grabs the keyboard, so keys pressed while it is up are delivered
to the popup. An event filter installed on the line edit therefore never
ran at the one moment it had to, leaving Tab to move focus to the next
widget and Return to reach the thread list and open a message.
Install the key filter on the application instead, which sees events
before any widget receives them. It returns immediately unless our own
popup is visible, so it cannot affect keyboard handling elsewhere. The
FocusIn filter stays on the line edit, where it is correctly scoped: it
only fires with the popup down.
Accepting a completion now also reopens the popup when the caret lands
somewhere more can be offered, so taking "tag:" goes straight on to the
tag list instead of needing a second complete_query. The chain stops on
a stem that is already a complete candidate, which is what every accept
produces. The mouse path chains identically.
The previous tests passed against the broken code because they posted
events straight to the line edit, bypassing the delivery path a real
keypress takes. The new tests route keys through the active popup and
run against a real X display; offscreen does not grab the keyboard and
cannot reproduce this class of bug.
|
|
QLineEdit::setCompleter hands completion to the line edit, which then
resets the completer's completionPrefix to the widget's entire text on
every keystroke. The prefix has to be the stem, so once the query grew
past its first token the whole-line prefix matched no candidate, the
popup stopped appearing, and the two reported symptoms followed: nothing
was there for Tab to accept, and Tab fell through to focus navigation.
Attach the completer with setWidget instead, which keeps the popup
anchored without ceding control of the prefix. complete() dereferences
widget() unconditionally, so leaving it unset segfaults rather than
degrading. Opening the popup then becomes ours to do on every edit.
Extend the existing event filter to route the keys the popup needs while
it is visible, and install it unconditionally now that it does more than
the completion_on_focus case. Enter accepts a completion only while the
popup is up, so returnPressed still runs the query when it is closed.
The existing tests called acceptCompletion() directly and so never
touched the widget, which is why neither bug was caught. Add four tests
that drive the real widget path plus one covering both settings of
completion_on_focus; the first two fail against the old code.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
The free-form date hint is a footer label rather than a model row: a row
would be filtered away by the first non-matching keystroke and could be
selected and inserted, producing a query that errors.
QCompleter::setPopup takes a QAbstractItemView, so the label cannot be laid
out beside the view in a container widget. The footer sits in space reserved
with setViewportMargins inside the list view instead.
setItemDelegate must run after setPopup, not before: setPopup installs a
plain QStyledItemDelegate of its own and discards whatever was already set,
which silently drops the description column.
Accepting replaces exactly the span the tokenizer identified rather than
QCompleter's own completion prefix, which is a different span once a prefix
or a range bound is involved. Four tests drive that path directly instead of
through synthetic key events, since whether a key needs Shift is a
keyboard-layout property and could not decide the question.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
tag: and is: share the tag list, since notmuch aliases them. path: offers
each account maildir in both bare and recursive forms, the latter being
what Account::scopedQuery builds and not something a user would guess.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
Keywords are syntax and stay untranslated; the descriptions beside them are
prose and go through tr().
The tables are free functions with no QObject to inherit tr() from, so the
file declares a VocabularyStrings context with Q_DECLARE_TR_FUNCTIONS rather
than borrowing QObject::tr, which would file every string under the QObject
context.
|
|
date:las..today put the caret at the end of the lower bound, where the
whole-bound span and the typed-so-far span are both 3 characters long, so
the test passed even against a tokenizer that truncates at the caret and
never sees the range separator. Moving the caret mid-bound with
date:lastweek..today separates the two: 8 under correct code, 3 under the
truncating one. Mutation-verified in both directions.
|
|
Each side of '..' is an independent value against the same model. Entries
that are themselves ranges are withheld once a range exists, since
date:1week....today is malformed.
The token is read to its full extent rather than truncated at the caret:
the separator deciding which bound is being edited can sit to the right
of the caret. Stems stay caret-bounded so matching never uses untyped
text.
|
|
subject:"foo bar has the cursor in free text, where offering keywords
would be wrong.
|
|
The replace span covers the value only, so accepting a completion never
overwrites the prefix that selected it.
|
|
Prefix completion only so far: the token under the cursor, bounded by
whitespace or an opening parenthesis rather than by the start of the line.
|