detached bf83908

fix(workspace): prevent script messages stealing focus

commit
bf83908b7654970aa8b041b6983140f2f8b5893f
author
bamen · · 2025-10-12 08:08 UTC
parent
b511179
signature
unsigned
1 file · +32 -15
M internal/app/browser/webview.go +32 -15
@@ -78,22 +78,22 @@ func (app *BrowserApp) buildAppearanceConfigJSON() string {
7878 // It looks for window.__dumber_palette = { "light": {...}, "dark": {...} }
7979 paletteConfig := map[string]interface{}{
8080 "light": map[string]string{
81- "background": app.config.Appearance.LightPalette.Background,
82- "surface": app.config.Appearance.LightPalette.Surface,
83- "surface_variant": app.config.Appearance.LightPalette.SurfaceVariant,
84- "text": app.config.Appearance.LightPalette.Text,
85- "muted": app.config.Appearance.LightPalette.Muted,
86- "accent": app.config.Appearance.LightPalette.Accent,
87- "border": app.config.Appearance.LightPalette.Border,
81+ "background": app.config.Appearance.LightPalette.Background,
82+ "surface": app.config.Appearance.LightPalette.Surface,
83+ "surface_variant": app.config.Appearance.LightPalette.SurfaceVariant,
84+ "text": app.config.Appearance.LightPalette.Text,
85+ "muted": app.config.Appearance.LightPalette.Muted,
86+ "accent": app.config.Appearance.LightPalette.Accent,
87+ "border": app.config.Appearance.LightPalette.Border,
8888 },
8989 "dark": map[string]string{
90- "background": app.config.Appearance.DarkPalette.Background,
91- "surface": app.config.Appearance.DarkPalette.Surface,
92- "surface_variant": app.config.Appearance.DarkPalette.SurfaceVariant,
93- "text": app.config.Appearance.DarkPalette.Text,
94- "muted": app.config.Appearance.DarkPalette.Muted,
95- "accent": app.config.Appearance.DarkPalette.Accent,
96- "border": app.config.Appearance.DarkPalette.Border,
90+ "background": app.config.Appearance.DarkPalette.Background,
91+ "surface": app.config.Appearance.DarkPalette.Surface,
92+ "surface_variant": app.config.Appearance.DarkPalette.SurfaceVariant,
93+ "text": app.config.Appearance.DarkPalette.Text,
94+ "muted": app.config.Appearance.DarkPalette.Muted,
95+ "accent": app.config.Appearance.DarkPalette.Accent,
96+ "border": app.config.Appearance.DarkPalette.Border,
9797 },
9898 }
9999
@@ -190,7 +190,7 @@ func (app *BrowserApp) attachPaneHandlers(pane *BrowserPane) {
190190 })
191191
192192 pane.webView.RegisterScriptMessageHandler(func(payload string) {
193- if app.workspace != nil {
193+ if app.workspace != nil && shouldFocusForScriptMessage(payload) {
194194 app.workspace.focusByView(pane.webView)
195195 }
196196 pane.messageHandler.Handle(payload)
@@ -210,6 +210,23 @@ func (app *BrowserApp) attachPaneHandlers(pane *BrowserPane) {
210210 }
211211 }
212212
213+// shouldFocusForScriptMessage filters out bootstrap messages that fire without user
214+// interaction (palette sync, shortcut preload, etc.). Only actionable payloads should
215+// bump the pane back to the front.
216+func shouldFocusForScriptMessage(payload string) bool {
217+ var msg messaging.Message
218+ if err := json.Unmarshal([]byte(payload), &msg); err != nil {
219+ return true // keep legacy behaviour if parsing fails
220+ }
221+
222+ switch msg.Type {
223+ case "get_color_palettes", "get_search_shortcuts", "request-webview-id", "console-message":
224+ return false
225+ default:
226+ return true
227+ }
228+}
229+
213230 // createWebView creates and configures the WebView
214231 func (app *BrowserApp) createWebView() error {
215232 log.Printf("Creating WebView (native backend expected: %v)", webkit.IsNativeAvailable())
@@ -78,22 +78,22 @@ func (app *BrowserApp) buildAppearanceConfigJSON() string {
78 // It looks for window.__dumber_palette = { "light": {...}, "dark": {...} }78 // It looks for window.__dumber_palette = { "light": {...}, "dark": {...} }
79 paletteConfig := map[string]interface{}{79 paletteConfig := map[string]interface{}{
80 "light": map[string]string{80 "light": map[string]string{
81- "background": app.config.Appearance.LightPalette.Background,81+ "background": app.config.Appearance.LightPalette.Background,
82- "surface": app.config.Appearance.LightPalette.Surface,82+ "surface": app.config.Appearance.LightPalette.Surface,
83- "surface_variant": app.config.Appearance.LightPalette.SurfaceVariant,83+ "surface_variant": app.config.Appearance.LightPalette.SurfaceVariant,
84- "text": app.config.Appearance.LightPalette.Text,84+ "text": app.config.Appearance.LightPalette.Text,
85- "muted": app.config.Appearance.LightPalette.Muted,85+ "muted": app.config.Appearance.LightPalette.Muted,
86- "accent": app.config.Appearance.LightPalette.Accent,86+ "accent": app.config.Appearance.LightPalette.Accent,
87- "border": app.config.Appearance.LightPalette.Border,87+ "border": app.config.Appearance.LightPalette.Border,
88 },88 },
89 "dark": map[string]string{89 "dark": map[string]string{
90- "background": app.config.Appearance.DarkPalette.Background,90+ "background": app.config.Appearance.DarkPalette.Background,
91- "surface": app.config.Appearance.DarkPalette.Surface,91+ "surface": app.config.Appearance.DarkPalette.Surface,
92- "surface_variant": app.config.Appearance.DarkPalette.SurfaceVariant,92+ "surface_variant": app.config.Appearance.DarkPalette.SurfaceVariant,
93- "text": app.config.Appearance.DarkPalette.Text,93+ "text": app.config.Appearance.DarkPalette.Text,
94- "muted": app.config.Appearance.DarkPalette.Muted,94+ "muted": app.config.Appearance.DarkPalette.Muted,
95- "accent": app.config.Appearance.DarkPalette.Accent,95+ "accent": app.config.Appearance.DarkPalette.Accent,
96- "border": app.config.Appearance.DarkPalette.Border,96+ "border": app.config.Appearance.DarkPalette.Border,
97 },97 },
98 }98 }
99 99
@@ -190,7 +190,7 @@ func (app *BrowserApp) attachPaneHandlers(pane *BrowserPane) {
190 })190 })
191 191
192 pane.webView.RegisterScriptMessageHandler(func(payload string) {192 pane.webView.RegisterScriptMessageHandler(func(payload string) {
193- if app.workspace != nil {193+ if app.workspace != nil && shouldFocusForScriptMessage(payload) {
194 app.workspace.focusByView(pane.webView)194 app.workspace.focusByView(pane.webView)
195 }195 }
196 pane.messageHandler.Handle(payload)196 pane.messageHandler.Handle(payload)
@@ -210,6 +210,23 @@ func (app *BrowserApp) attachPaneHandlers(pane *BrowserPane) {
210 }210 }
211 }211 }
212 212
213+// shouldFocusForScriptMessage filters out bootstrap messages that fire without user
214+// interaction (palette sync, shortcut preload, etc.). Only actionable payloads should
215+// bump the pane back to the front.
216+func shouldFocusForScriptMessage(payload string) bool {
217+ var msg messaging.Message
218+ if err := json.Unmarshal([]byte(payload), &msg); err != nil {
219+ return true // keep legacy behaviour if parsing fails
220+ }
221+
222+ switch msg.Type {
223+ case "get_color_palettes", "get_search_shortcuts", "request-webview-id", "console-message":
224+ return false
225+ default:
226+ return true
227+ }
228+}
229+
213 // createWebView creates and configures the WebView230 // createWebView creates and configures the WebView
214 func (app *BrowserApp) createWebView() error {231 func (app *BrowserApp) createWebView() error {
215 log.Printf("Creating WebView (native backend expected: %v)", webkit.IsNativeAvailable())232 log.Printf("Creating WebView (native backend expected: %v)", webkit.IsNativeAvailable())

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close