v0.14.0 76d1892

omnibox.ts RawHistoryFolder

1/**
2 * Omnibox Module Initialization
3 *
4 * Initializes the Svelte 5 omnibox component system
5 */
6
7import { mount } from "svelte";
8import { Omnibox } from "../../components/omnibox";
9import { ensureShadowMount } from "./shadowHost";
10import type { OmniboxConfig } from "../../components/omnibox/types";
11import { omniboxBridge } from "../../components/omnibox/messaging";
12
13let omniboxComponent: ReturnType<typeof mount> | null = null;
14let isInitialized = false;
15
16export interface OmniboxInitConfig extends OmniboxConfig {
17  // Additional initialization options if needed
18  containerId?: string;
19}
20
21/**
22 * Initialize the omnibox component system
23 */
24export async function initializeOmnibox(
25  _config: OmniboxInitConfig = {},
26): Promise<void> {
27  if (isInitialized) {
28    console.warn("Omnibox already initialized");
29    return;
30  }
31
32  try {
33    // Ensure we're in the main frame (not an iframe)
34    if (window.self !== window.top) {
35      console.log("🚫 Omnibox skipped in iframe");
36      return;
37    }
38
39    // Check if DOM is ready
40    if (!document.body) {
41      console.warn("DOM body not ready for omnibox initialization");
42      return;
43    }
44
45    // Mount omnibox into the shared global Shadow DOM host
46    const mountEl = ensureShadowMount("dumber-omnibox");
47    omniboxComponent = mount(Omnibox, {
48      target: mountEl as unknown as Element,
49    });
50
51    // Wait for the component to mount and set up the global API
52    await new Promise<void>((resolve) => {
53      const checkAPI = () => {
54        if (
55          window.__dumber_omnibox &&
56          typeof window.__dumber_omnibox === "object"
57        ) {
58          console.log("✅ Omnibox component system initialized");
59          console.log(
60            "🔧 Global API is available:",
61            Object.keys(window.__dumber_omnibox),
62          );
63          isInitialized = true;
64
65          // Fetch search shortcuts from backend
66          omniboxBridge.fetchSearchShortcuts().catch((err) => {
67            console.warn("Failed to fetch search shortcuts:", err);
68          });
69
70          // Notify isolated bundle listeners that omnibox is ready
71          try {
72            document.dispatchEvent(new CustomEvent("dumber:omnibox-ready"));
73          } catch (e) {
74            console.warn("Failed to dispatch omnibox-ready event", e);
75          }
76          resolve();
77        } else {
78          setTimeout(checkAPI, 10); // Check again in 10ms
79        }
80      };
81      checkAPI();
82    });
83
84    // Bridge: listen for page-world events carrying suggestions and forward to API
85    const handleSuggestionsEvent = (e: Event) => {
86      try {
87        const detail = (e as CustomEvent).detail;
88        const suggestions = detail?.suggestions ?? detail;
89        if (
90          Array.isArray(suggestions) &&
91          window.__dumber_omnibox?.setSuggestions
92        ) {
93          console.log(
94            "🔗 [Bridge] Received page-world suggestions event:",
95            suggestions.length,
96          );
97          window.__dumber_omnibox.setSuggestions(suggestions);
98        } else {
99          console.warn(
100            "🔗 [Bridge] Suggestions event received but API not ready or invalid payload",
101          );
102        }
103      } catch (err) {
104        console.warn("🔗 [Bridge] Failed handling suggestions event:", err);
105      }
106    };
107
108    document.addEventListener(
109      "dumber:omnibox-suggestions",
110      handleSuggestionsEvent,
111      false,
112    );
113    // Unified event name
114    document.addEventListener(
115      "dumber:omnibox:suggestions",
116      handleSuggestionsEvent,
117      false,
118    );
119  } catch (error) {
120    console.error("❌ Failed to initialize omnibox component:", error);
121    throw error;
122  }
123}
124
125/**
126 * Get the current initialization status
127 */
128export function isOmniboxInitialized(): boolean {
129  return isInitialized;
130}
131
132/**
133 * Cleanup omnibox component (useful for hot reload during development)
134 */
135export function cleanupOmnibox(): void {
136  if (omniboxComponent) {
137    try {
138      omniboxComponent.$destroy?.();
139    } catch (error) {
140      console.warn("Error destroying omnibox component:", error);
141    }
142    omniboxComponent = null;
143  }
144
145  // The shared shadow host remains persistent; just log cleanup
146
147  isInitialized = false;
148  console.log("🧹 Omnibox component cleaned up");
149}

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