Skip to content

shell: handle CTRL+BACKSPACE to clear filter#6307

Merged
dhh merged 8 commits into
basecamp:quattrofrom
RushiChaganti:fix/emoji-ctrl-backspace
Jul 20, 2026
Merged

shell: handle CTRL+BACKSPACE to clear filter#6307
dhh merged 8 commits into
basecamp:quattrofrom
RushiChaganti:fix/emoji-ctrl-backspace

Conversation

@RushiChaganti

@RushiChaganti RushiChaganti commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Align filter-field editing with Qt's standard keyboard shortcuts across all menu panels (clipboard, emojis, image-picker, launcher, menu, reminders):

  • Backspace: delete previous character
  • Ctrl+Backspace: delete previous word (Qt DeleteStartOfWord)
  • Ctrl+U: clear entire filter

Previously Ctrl+Backspace cleared the whole field, diverging from Qt on KDE/GNOME. Preserves per-panel behavior (menu goBack, image-picker filterable gating) and fixes an indentation regression in the emoji handler.

Copilot AI review requested due to automatic review settings July 18, 2026 23:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support in the emoji panel overlay for Ctrl+Backspace to clear the entire search filter at once, while preserving existing Backspace behavior (delete one character).

Changes:

  • Detects the Control modifier alongside Backspace in the panel key handler.
  • Clears filterText on Ctrl+Backspace; otherwise deletes a single character on Backspace.

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread shell/plugins/emojis/Emojis.qml Outdated
Comment on lines +203 to +212
} else if (event.key === Qt.Key_Backspace) {
if ((event.modifiers & Qt.ControlModifier) === Qt.ControlModifier) {
// CTRL+BACKSPACE: clear entire filter
root.setFilter("")
} else if (root.filterText.length > 0) {
// BACKSPACE: remove one character
root.setFilter(root.filterText.slice(0, -1))
}
event.accepted = true
} else if (event.key === Qt.Key_Left) {
@RushiChaganti
RushiChaganti marked this pull request as draft July 18, 2026 23:57
@RushiChaganti RushiChaganti changed the title emoji panel: handle CTRL+BACKSPACE to clear filter shell: handle CTRL+BACKSPACE to clear filter Jul 19, 2026
@RushiChaganti
RushiChaganti marked this pull request as ready for review July 19, 2026 00:16
Copilot AI review requested due to automatic review settings July 19, 2026 00:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

shell/plugins/emojis/Emojis.qml:213

  • The } else if (event.key === Qt.Key_Left) line is indented much deeper than the rest of this if/else if chain, which makes the control flow easy to misread. Align it with the other branches.
            event.accepted = true
              } else if (event.key === Qt.Key_Left) {
            root.select(-1)

Comment thread shell/plugins/menu/Menu.qml Outdated
Comment on lines +138 to +142
} else if (event.key === Qt.Key_Backspace) {
if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1))
if ((event.modifiers & Qt.ControlModifier) === Qt.ControlModifier) {
// CTRL+BACKSPACE: clear entire filter
root.setFilter("")
} else if (root.filterText.length > 0) {
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 19, 2026 00:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (2)

shell/plugins/emojis/Emojis.qml:212

  • The } else if (event.key === Qt.Key_Left) line is mis-indented compared to the rest of this if/else if chain, which makes the control flow harder to read and looks like an accidental edit.
              } else if (event.key === Qt.Key_Left) {

shell/plugins/reminders/ReminderFlow.qml:145

  • This block’s indentation is inconsistent, and the Ctrl modifier check is overly strict (=== Qt.ControlModifier won’t match when other modifiers are present). Consider using a bitmask test and reindenting for readability.
            if ((event.modifiers & Qt.ControlModifier) === Qt.ControlModifier) {
            // CTRL+BACKSPACE: clear entire filter
            root.setFilter("")
          } else if (root.filterText.length > 0) {
            // BACKSPACE: remove one character
            root.setFilter(root.filterText.slice(0, -1))
          }

Comment thread shell/plugins/emojis/Emojis.qml Outdated
event.accepted = true
} else if (event.key === Qt.Key_Backspace) {
if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1))
if ((event.modifiers & Qt.ControlModifier) === Qt.ControlModifier) {
Comment thread shell/plugins/menu/Menu.qml Outdated
} else if (event.key === Qt.Key_Backspace) {
if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1))
else root.goBack()
if ((event.modifiers & Qt.ControlModifier) === Qt.ControlModifier) {
Comment thread shell/plugins/launcher/Launcher.qml Outdated
event.accepted = true
} else if (event.key === Qt.Key_Backspace) {
if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1))
if ((event.modifiers & Qt.ControlModifier) === Qt.ControlModifier) {
} else if (event.key === Qt.Key_Backspace && root.filterable) {
if (root.filterText.length > 0)
} else if (event.key === Qt.Key_Backspace && root.filterable) {
if ((event.modifiers & Qt.ControlModifier) === Qt.ControlModifier) {
Comment thread shell/plugins/clipboard/Clipboard.qml Outdated
event.accepted = true
} else if (event.key === Qt.Key_Backspace) {
if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1))
if ((event.modifiers & Qt.ControlModifier) === Qt.ControlModifier) {
Comment thread shell/plugins/emojis/Emojis.qml Outdated
Comment on lines +203 to +210
} else if (event.key === Qt.Key_Backspace) {
if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1))
if ((event.modifiers & Qt.ControlModifier) === Qt.ControlModifier) {
// CTRL+BACKSPACE: clear entire filter
root.setFilter("")
} else if (root.filterText.length > 0) {
// BACKSPACE: remove one character
root.setFilter(root.filterText.slice(0, -1))
}
@dhh

dhh commented Jul 19, 2026

Copy link
Copy Markdown
Member

Could we align this with Qt’s standard keyboard behavior?

Qt defines Ctrl+Backspace as DeleteStartOfWord on both KDE and GNOME, so it should remove the previous word rather than clear the entire filter. For clearing the complete filter, Ctrl+U is the standard shortcut.

Suggested behavior:

  • Backspace: remove the previous character
  • Ctrl+Backspace: remove the previous word
  • Ctrl+U: clear the entire filter

Please also fix the indentation inconsistencies introduced in Emojis.qml, ReminderFlow.qml, and ImagePicker.qml.

Copilot AI review requested due to automatic review settings July 19, 2026 05:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (1)

shell/plugins/menu/Menu.qml:853

  • CTRL+BACKSPACE is described as “clear the entire filter”, but the current implementation removes only the previous word. Consider making CTRL+BACKSPACE clear the full filter, and keep the existing goBack() behavior when the filter is already empty (even when Ctrl is held).
          } else if (event.key === Qt.Key_Backspace) {
            if (event.modifiers & Qt.ControlModifier) {
              // CTRL+BACKSPACE: remove the previous word
              root.setFilter(root.filterText.replace(/\s+$/, "").replace(/\S+$/, ""))
            } else if (root.filterText.length > 0) {
              // BACKSPACE: remove the previous character
              root.setFilter(root.filterText.slice(0, -1))
            } else {
              root.goBack()
            }

Comment on lines +142 to +149
} else if (event.key === Qt.Key_Backspace) {
if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1))
if (event.modifiers & Qt.ControlModifier) {
// CTRL+BACKSPACE: remove the previous word
root.setFilter(root.filterText.replace(/\s+$/, "").replace(/\S+$/, ""))
} else if (root.filterText.length > 0) {
// BACKSPACE: remove the previous character
root.setFilter(root.filterText.slice(0, -1))
}
Comment thread shell/plugins/launcher/Launcher.qml Outdated
Comment on lines +471 to +478
} else if (event.key === Qt.Key_Backspace) {
if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1))
if (event.modifiers & Qt.ControlModifier) {
// CTRL+BACKSPACE: remove the previous word
root.setFilter(root.filterText.replace(/\s+$/, "").replace(/\S+$/, ""))
} else if (root.filterText.length > 0) {
// BACKSPACE: remove the previous character
root.setFilter(root.filterText.slice(0, -1))
}
Comment on lines +424 to +431
} else if (event.key === Qt.Key_Backspace && root.filterable) {
if (root.filterText.length > 0)
if (event.modifiers & Qt.ControlModifier) {
// CTRL+BACKSPACE: remove the previous word
root.updateFilter(root.filterText.replace(/\s+$/, "").replace(/\S+$/, ""))
} else if (root.filterText.length > 0) {
// BACKSPACE: remove the previous character
root.updateFilter(root.filterText.slice(0, -1))
}
Comment thread shell/plugins/emojis/Emojis.qml Outdated
Comment on lines +207 to +214
} else if (event.key === Qt.Key_Backspace) {
if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1))
if (event.modifiers & Qt.ControlModifier) {
// CTRL+BACKSPACE: remove the previous word
root.setFilter(root.filterText.replace(/\s+$/, "").replace(/\S+$/, ""))
} else if (root.filterText.length > 0) {
// BACKSPACE: remove the previous character
root.setFilter(root.filterText.slice(0, -1))
}
Comment thread shell/plugins/clipboard/Clipboard.qml Outdated
Comment on lines +352 to +359
} else if (event.key === Qt.Key_Backspace) {
if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1))
if (event.modifiers & Qt.ControlModifier) {
// CTRL+BACKSPACE: remove the previous word
root.setFilter(root.filterText.replace(/\s+$/, "").replace(/\S+$/, ""))
} else if (root.filterText.length > 0) {
// BACKSPACE: remove the previous character
root.setFilter(root.filterText.slice(0, -1))
}
@RushiChaganti

Copy link
Copy Markdown
Contributor Author
qt-standard-filter-shortcuts.mp4

A video preview

@RushiChaganti

Copy link
Copy Markdown
Contributor Author

Hey @dhh,

I also noticed that the Wi-Fi networks aren't being imported. I've already written a migration script for that.

Would you prefer that I include it in this PR, or should I submit it in a separate PR after this one is merged?

@dhh

dhh commented Jul 19, 2026

Copy link
Copy Markdown
Member

Always keep PRs focused on a single issue.

@dhh

dhh commented Jul 19, 2026

Copy link
Copy Markdown
Member

Lots of duplicated code in this PR. Find a way to abstract and extract.

Copilot AI review requested due to automatic review settings July 19, 2026 17:30
@RushiChaganti

Copy link
Copy Markdown
Contributor Author

Good call — the Ctrl+U / Ctrl+Backspace / Backspace handling was copy-pasted across all six searchable panels (clipboard, emojis, image-picker, launcher, menu, reminders). I've extracted it.

The shared logic now lives in two pure helpers on the Util singleton (shell/Commons/Util.qml)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Comment thread shell/Commons/Util.qml Outdated
Comment on lines +88 to +91
function isFilterEditKey(event) {
return event.key === Qt.Key_Backspace
|| (event.key === Qt.Key_U && (event.modifiers & Qt.ControlModifier))
}
Comment thread shell/plugins/menu/Menu.qml Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 19, 2026 17:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

shell/plugins/menu/Menu.qml:844

  • Menu back-navigation on an empty filter now only triggers when event.modifiers === Qt.NoModifier. Previously it triggered for any Backspace press when the filter was empty, so Shift+Backspace (which is commonly equivalent to Backspace) will no longer step back a menu level.
          } else if (event.key === Qt.Key_Backspace && event.modifiers === Qt.NoModifier && root.filterText.length === 0) {
            // BACKSPACE on an empty filter steps back a menu level
            root.goBack()
            event.accepted = true
          } else if (Util.isFilterEditKey(event)) {

Copilot AI review requested due to automatic review settings July 19, 2026 17:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

shell/plugins/menu/Menu.qml:844

  • Menu back-navigation on an empty filter now only triggers for an unmodified Backspace. Previously, Shift+Backspace on an empty filter would also reach the Backspace handler and call goBack(); with the new Util.isFilterEditKey branch, Shift+Backspace will be treated as a filter edit key and will no longer step back a menu level. This is a likely regression for users who keep Shift held while navigating/typing.

Consider allowing both NoModifier and ShiftModifier for the empty-filter goBack() case, while still keeping Ctrl+Backspace as a word-delete.

          } else if (event.key === Qt.Key_Backspace && event.modifiers === Qt.NoModifier && root.filterText.length === 0) {
            // BACKSPACE on an empty filter steps back a menu level
            root.goBack()
            event.accepted = true
          } else if (Util.isFilterEditKey(event)) {

Backspace/Ctrl+U on an empty filter no longer calls setFilter(""),
which was resetting the list selection back to the top. This also lets
the menu's empty-filter Backspace fall through to goBack() with any
modifier held, as it did before the Util extraction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 20, 2026 00:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@dhh
dhh merged commit 7721228 into basecamp:quattro Jul 20, 2026
katrushenkov pushed a commit to katrushenkov/omarchy that referenced this pull request Jul 20, 2026
* emoji panel: handle CTRL+BACKSPACE to clear filter

* shell: handle CTRL+BACKSPACE to clear filter in all search overlays

* Indentation fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* menu filters: align keyboard editing with Qt standard shortcuts

* menu filters: extract shared filter-editing helpers

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* potential fix for pull request findings

* Only treat filter edit keys as edits when they change the text

Backspace/Ctrl+U on an empty filter no longer calls setFilter(""),
which was resetting the list selection back to the top. This also lets
the menu's empty-filter Backspace fall through to goBack() with any
modifier held, as it did before the Util extraction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: David Heinemeier Hansson <david@hey.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants