fix(omnibox): pass query through chain to prevent ghost text race condition
- commit
- 88b49b5ae5753478ec6c1789a7dbf94e576802fe
- author
- brice · · 2026-01-24 03:55 UTC
- parent
- 478ef93
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +22 -15
M internal/ui/component/omnibox.go +22 -15
| @@ -876,16 +876,19 @@ func (o *Omnibox) acceptGhostCompletion() { | |||
| 876 | 876 | } | |
| 877 | 877 | ||
| 878 | 878 | // updateGhostFromSuggestion updates ghost text based on the current autocomplete suggestion. | |
| 879 | - | func (o *Omnibox) updateGhostFromSuggestion() { | |
| 879 | + | // The query parameter is the search query that was used, ensuring we don't use stale input. | |
| 880 | + | func (o *Omnibox) updateGhostFromSuggestion(query string) { | |
| 880 | 881 | if o.autocompleteUC == nil { | |
| 881 | 882 | return | |
| 882 | 883 | } | |
| 883 | 884 | ||
| 884 | 885 | o.mu.RLock() | |
| 885 | - | userInput := o.realInput | |
| 886 | 886 | bangMode := o.bangMode | |
| 887 | 887 | o.mu.RUnlock() | |
| 888 | 888 | ||
| 889 | + | // Use the query that triggered this search, not realInput which may have changed | |
| 890 | + | userInput := query | |
| 891 | + | ||
| 889 | 892 | // Don't show ghost text in bang mode (it has its own completion) | |
| 890 | 893 | if bangMode || userInput == "" { | |
| 891 | 894 | o.clearGhostText() | |
| @@ -1060,8 +1063,8 @@ func (o *Omnibox) performSearch() { | |||
| 1060 | 1063 | }) | |
| 1061 | 1064 | } | |
| 1062 | 1065 | ||
| 1063 | - | // Marshal back to GTK main thread | |
| 1064 | - | o.idleAddUpdateSuggestions(suggestions) | |
| 1066 | + | // Marshal back to GTK main thread, passing query to ensure ghost text uses correct input | |
| 1067 | + | o.idleAddUpdateSuggestions(suggestions, query) | |
| 1065 | 1068 | }() | |
| 1066 | 1069 | } | |
| 1067 | 1070 | ||
| @@ -1078,7 +1081,7 @@ func (o *Omnibox) loadInitialHistory() { | |||
| 1078 | 1081 | ||
| 1079 | 1082 | switch o.initialBehavior { | |
| 1080 | 1083 | case "none": | |
| 1081 | - | o.idleAddUpdateSuggestions(nil) | |
| 1084 | + | o.idleAddUpdateSuggestions(nil, "") | |
| 1082 | 1085 | return | |
| 1083 | 1086 | ||
| 1084 | 1087 | case "most_visited", "recent", "": | |
| @@ -1123,7 +1126,7 @@ func (o *Omnibox) loadInitialHistory() { | |||
| 1123 | 1126 | } | |
| 1124 | 1127 | } | |
| 1125 | 1128 | ||
| 1126 | - | o.idleAddUpdateSuggestions(suggestions) | |
| 1129 | + | o.idleAddUpdateSuggestions(suggestions, "") | |
| 1127 | 1130 | }() | |
| 1128 | 1131 | } | |
| 1129 | 1132 | ||
| @@ -1161,7 +1164,7 @@ func (o *Omnibox) loadFavorites(query string) { | |||
| 1161 | 1164 | }) | |
| 1162 | 1165 | } | |
| 1163 | 1166 | ||
| 1164 | - | o.idleAddUpdateFavorites(favorites) | |
| 1167 | + | o.idleAddUpdateFavorites(favorites, query) | |
| 1165 | 1168 | }() | |
| 1166 | 1169 | } | |
| 1167 | 1170 | ||
| @@ -1263,7 +1266,8 @@ func (o *Omnibox) updateBangSuggestions(suggestions []BangSuggestion) { | |||
| 1263 | 1266 | } | |
| 1264 | 1267 | ||
| 1265 | 1268 | // updateSuggestions updates the list with history suggestions. | |
| 1266 | - | func (o *Omnibox) updateSuggestions(suggestions []Suggestion) { | |
| 1269 | + | // The query parameter is the search query that triggered this update. | |
| 1270 | + | func (o *Omnibox) updateSuggestions(suggestions []Suggestion, query string) { | |
| 1267 | 1271 | o.mu.Lock() | |
| 1268 | 1272 | o.bangMode = false | |
| 1269 | 1273 | o.bangSuggestions = nil | |
| @@ -1284,14 +1288,15 @@ func (o *Omnibox) updateSuggestions(suggestions []Suggestion) { | |||
| 1284 | 1288 | if rowCount > 0 { | |
| 1285 | 1289 | o.selectIndex(0) | |
| 1286 | 1290 | // Update ghost text from first suggestion | |
| 1287 | - | o.updateGhostFromSuggestion() | |
| 1291 | + | o.updateGhostFromSuggestion(query) | |
| 1288 | 1292 | } else { | |
| 1289 | 1293 | o.clearGhostText() | |
| 1290 | 1294 | } | |
| 1291 | 1295 | } | |
| 1292 | 1296 | ||
| 1293 | 1297 | // updateFavorites updates the list with favorites. | |
| 1294 | - | func (o *Omnibox) updateFavorites(favorites []Favorite) { | |
| 1298 | + | // The query parameter is the search query that triggered this update. | |
| 1299 | + | func (o *Omnibox) updateFavorites(favorites []Favorite, query string) { | |
| 1295 | 1300 | o.mu.Lock() | |
| 1296 | 1301 | o.bangMode = false | |
| 1297 | 1302 | o.bangSuggestions = nil | |
| @@ -1312,7 +1317,7 @@ func (o *Omnibox) updateFavorites(favorites []Favorite) { | |||
| 1312 | 1317 | if rowCount > 0 { | |
| 1313 | 1318 | o.selectIndex(0) | |
| 1314 | 1319 | // Update ghost text from first favorite | |
| 1315 | - | o.updateGhostFromSuggestion() | |
| 1320 | + | o.updateGhostFromSuggestion(query) | |
| 1316 | 1321 | } else { | |
| 1317 | 1322 | o.clearGhostText() | |
| 1318 | 1323 | } | |
| @@ -2034,9 +2039,10 @@ func (o *Omnibox) UpdateZoomIndicator(factor float64) { | |||
| 2034 | 2039 | } | |
| 2035 | 2040 | ||
| 2036 | 2041 | // idleAddUpdateSuggestions schedules updateSuggestions on the GTK main thread. | |
| 2037 | - | func (o *Omnibox) idleAddUpdateSuggestions(suggestions []Suggestion) { | |
| 2042 | + | // The query parameter is passed through to ensure ghost text uses the correct input. | |
| 2043 | + | func (o *Omnibox) idleAddUpdateSuggestions(suggestions []Suggestion, query string) { | |
| 2038 | 2044 | var cb glib.SourceFunc = func(data uintptr) bool { | |
| 2039 | - | o.updateSuggestions(suggestions) | |
| 2045 | + | o.updateSuggestions(suggestions, query) | |
| 2040 | 2046 | return false // One-shot callback | |
| 2041 | 2047 | } | |
| 2042 | 2048 | glib.IdleAdd(&cb, 0) | |
| @@ -2058,9 +2064,10 @@ func (o *Omnibox) getFavoriteURLs(ctx context.Context) map[string]struct{} { | |||
| 2058 | 2064 | } | |
| 2059 | 2065 | ||
| 2060 | 2066 | // idleAddUpdateFavorites schedules updateFavorites on the GTK main thread. | |
| 2061 | - | func (o *Omnibox) idleAddUpdateFavorites(favorites []Favorite) { | |
| 2067 | + | // The query parameter is passed through to ensure ghost text uses the correct input. | |
| 2068 | + | func (o *Omnibox) idleAddUpdateFavorites(favorites []Favorite, query string) { | |
| 2062 | 2069 | var cb glib.SourceFunc = func(data uintptr) bool { | |
| 2063 | - | o.updateFavorites(favorites) | |
| 2070 | + | o.updateFavorites(favorites, query) | |
| 2064 | 2071 | return false // One-shot callback, return false to remove source | |
| 2065 | 2072 | } | |
| 2066 | 2073 | glib.IdleAdd(&cb, 0) | |
| @@ -876,16 +876,19 @@ func (o *Omnibox) acceptGhostCompletion() { | |||||
| 876 | } | 876 | } | ||
| 877 | 877 | ||||
| 878 | // updateGhostFromSuggestion updates ghost text based on the current autocomplete suggestion. | 878 | // updateGhostFromSuggestion updates ghost text based on the current autocomplete suggestion. | ||
| 879 | - | func (o *Omnibox) updateGhostFromSuggestion() { | 879 | + | // The query parameter is the search query that was used, ensuring we don't use stale input. |
| 880 | + | func (o *Omnibox) updateGhostFromSuggestion(query string) { | |||
| 880 | if o.autocompleteUC == nil { | 881 | if o.autocompleteUC == nil { | ||
| 881 | return | 882 | return | ||
| 882 | } | 883 | } | ||
| 883 | 884 | ||||
| 884 | o.mu.RLock() | 885 | o.mu.RLock() | ||
| 885 | - | userInput := o.realInput | |||
| 886 | bangMode := o.bangMode | 886 | bangMode := o.bangMode | ||
| 887 | o.mu.RUnlock() | 887 | o.mu.RUnlock() | ||
| 888 | 888 | ||||
| 889 | + | // Use the query that triggered this search, not realInput which may have changed | |||
| 890 | + | userInput := query | |||
| 891 | + | ||||
| 889 | // Don't show ghost text in bang mode (it has its own completion) | 892 | // Don't show ghost text in bang mode (it has its own completion) | ||
| 890 | if bangMode || userInput == "" { | 893 | if bangMode || userInput == "" { | ||
| 891 | o.clearGhostText() | 894 | o.clearGhostText() | ||
| @@ -1060,8 +1063,8 @@ func (o *Omnibox) performSearch() { | |||||
| 1060 | }) | 1063 | }) | ||
| 1061 | } | 1064 | } | ||
| 1062 | 1065 | ||||
| 1063 | - | // Marshal back to GTK main thread | 1066 | + | // Marshal back to GTK main thread, passing query to ensure ghost text uses correct input |
| 1064 | - | o.idleAddUpdateSuggestions(suggestions) | 1067 | + | o.idleAddUpdateSuggestions(suggestions, query) |
| 1065 | }() | 1068 | }() | ||
| 1066 | } | 1069 | } | ||
| 1067 | 1070 | ||||
| @@ -1078,7 +1081,7 @@ func (o *Omnibox) loadInitialHistory() { | |||||
| 1078 | 1081 | ||||
| 1079 | switch o.initialBehavior { | 1082 | switch o.initialBehavior { | ||
| 1080 | case "none": | 1083 | case "none": | ||
| 1081 | - | o.idleAddUpdateSuggestions(nil) | 1084 | + | o.idleAddUpdateSuggestions(nil, "") |
| 1082 | return | 1085 | return | ||
| 1083 | 1086 | ||||
| 1084 | case "most_visited", "recent", "": | 1087 | case "most_visited", "recent", "": | ||
| @@ -1123,7 +1126,7 @@ func (o *Omnibox) loadInitialHistory() { | |||||
| 1123 | } | 1126 | } | ||
| 1124 | } | 1127 | } | ||
| 1125 | 1128 | ||||
| 1126 | - | o.idleAddUpdateSuggestions(suggestions) | 1129 | + | o.idleAddUpdateSuggestions(suggestions, "") |
| 1127 | }() | 1130 | }() | ||
| 1128 | } | 1131 | } | ||
| 1129 | 1132 | ||||
| @@ -1161,7 +1164,7 @@ func (o *Omnibox) loadFavorites(query string) { | |||||
| 1161 | }) | 1164 | }) | ||
| 1162 | } | 1165 | } | ||
| 1163 | 1166 | ||||
| 1164 | - | o.idleAddUpdateFavorites(favorites) | 1167 | + | o.idleAddUpdateFavorites(favorites, query) |
| 1165 | }() | 1168 | }() | ||
| 1166 | } | 1169 | } | ||
| 1167 | 1170 | ||||
| @@ -1263,7 +1266,8 @@ func (o *Omnibox) updateBangSuggestions(suggestions []BangSuggestion) { | |||||
| 1263 | } | 1266 | } | ||
| 1264 | 1267 | ||||
| 1265 | // updateSuggestions updates the list with history suggestions. | 1268 | // updateSuggestions updates the list with history suggestions. | ||
| 1266 | - | func (o *Omnibox) updateSuggestions(suggestions []Suggestion) { | 1269 | + | // The query parameter is the search query that triggered this update. |
| 1270 | + | func (o *Omnibox) updateSuggestions(suggestions []Suggestion, query string) { | |||
| 1267 | o.mu.Lock() | 1271 | o.mu.Lock() | ||
| 1268 | o.bangMode = false | 1272 | o.bangMode = false | ||
| 1269 | o.bangSuggestions = nil | 1273 | o.bangSuggestions = nil | ||
| @@ -1284,14 +1288,15 @@ func (o *Omnibox) updateSuggestions(suggestions []Suggestion) { | |||||
| 1284 | if rowCount > 0 { | 1288 | if rowCount > 0 { | ||
| 1285 | o.selectIndex(0) | 1289 | o.selectIndex(0) | ||
| 1286 | // Update ghost text from first suggestion | 1290 | // Update ghost text from first suggestion | ||
| 1287 | - | o.updateGhostFromSuggestion() | 1291 | + | o.updateGhostFromSuggestion(query) |
| 1288 | } else { | 1292 | } else { | ||
| 1289 | o.clearGhostText() | 1293 | o.clearGhostText() | ||
| 1290 | } | 1294 | } | ||
| 1291 | } | 1295 | } | ||
| 1292 | 1296 | ||||
| 1293 | // updateFavorites updates the list with favorites. | 1297 | // updateFavorites updates the list with favorites. | ||
| 1294 | - | func (o *Omnibox) updateFavorites(favorites []Favorite) { | 1298 | + | // The query parameter is the search query that triggered this update. |
| 1299 | + | func (o *Omnibox) updateFavorites(favorites []Favorite, query string) { | |||
| 1295 | o.mu.Lock() | 1300 | o.mu.Lock() | ||
| 1296 | o.bangMode = false | 1301 | o.bangMode = false | ||
| 1297 | o.bangSuggestions = nil | 1302 | o.bangSuggestions = nil | ||
| @@ -1312,7 +1317,7 @@ func (o *Omnibox) updateFavorites(favorites []Favorite) { | |||||
| 1312 | if rowCount > 0 { | 1317 | if rowCount > 0 { | ||
| 1313 | o.selectIndex(0) | 1318 | o.selectIndex(0) | ||
| 1314 | // Update ghost text from first favorite | 1319 | // Update ghost text from first favorite | ||
| 1315 | - | o.updateGhostFromSuggestion() | 1320 | + | o.updateGhostFromSuggestion(query) |
| 1316 | } else { | 1321 | } else { | ||
| 1317 | o.clearGhostText() | 1322 | o.clearGhostText() | ||
| 1318 | } | 1323 | } | ||
| @@ -2034,9 +2039,10 @@ func (o *Omnibox) UpdateZoomIndicator(factor float64) { | |||||
| 2034 | } | 2039 | } | ||
| 2035 | 2040 | ||||
| 2036 | // idleAddUpdateSuggestions schedules updateSuggestions on the GTK main thread. | 2041 | // idleAddUpdateSuggestions schedules updateSuggestions on the GTK main thread. | ||
| 2037 | - | func (o *Omnibox) idleAddUpdateSuggestions(suggestions []Suggestion) { | 2042 | + | // The query parameter is passed through to ensure ghost text uses the correct input. |
| 2043 | + | func (o *Omnibox) idleAddUpdateSuggestions(suggestions []Suggestion, query string) { | |||
| 2038 | var cb glib.SourceFunc = func(data uintptr) bool { | 2044 | var cb glib.SourceFunc = func(data uintptr) bool { | ||
| 2039 | - | o.updateSuggestions(suggestions) | 2045 | + | o.updateSuggestions(suggestions, query) |
| 2040 | return false // One-shot callback | 2046 | return false // One-shot callback | ||
| 2041 | } | 2047 | } | ||
| 2042 | glib.IdleAdd(&cb, 0) | 2048 | glib.IdleAdd(&cb, 0) | ||
| @@ -2058,9 +2064,10 @@ func (o *Omnibox) getFavoriteURLs(ctx context.Context) map[string]struct{} { | |||||
| 2058 | } | 2064 | } | ||
| 2059 | 2065 | ||||
| 2060 | // idleAddUpdateFavorites schedules updateFavorites on the GTK main thread. | 2066 | // idleAddUpdateFavorites schedules updateFavorites on the GTK main thread. | ||
| 2061 | - | func (o *Omnibox) idleAddUpdateFavorites(favorites []Favorite) { | 2067 | + | // The query parameter is passed through to ensure ghost text uses the correct input. |
| 2068 | + | func (o *Omnibox) idleAddUpdateFavorites(favorites []Favorite, query string) { | |||
| 2062 | var cb glib.SourceFunc = func(data uintptr) bool { | 2069 | var cb glib.SourceFunc = func(data uintptr) bool { | ||
| 2063 | - | o.updateFavorites(favorites) | 2070 | + | o.updateFavorites(favorites, query) |
| 2064 | return false // One-shot callback, return false to remove source | 2071 | return false // One-shot callback, return false to remove source | ||
| 2065 | } | 2072 | } | ||
| 2066 | glib.IdleAdd(&cb, 0) | 2073 | glib.IdleAdd(&cb, 0) | ||