index.html RawHistoryFolder

1<!doctype html>
2<html lang="en">
3<head>
4  <meta charset="utf-8">
5  <meta name="viewport" content="width=device-width, initial-scale=1">
6  <meta name="color-scheme" content="dark light">
7  <title>systemviews</title>
8  <link rel="stylesheet" href="./systemviews.css">
9  <script src="./wasm_exec.js"></script>
10  <script>
11    // One terminal-error guard: the loading shell reports its first fatal
12    // failure exactly once. Streaming fallback noise stays console-only.
13    let terminalErrorReported = false;
14    function renderWasmError(prefixText, err) {
15      console.error(prefixText, err);
16      if (terminalErrorReported) return;
17      terminalErrorReported = true;
18      const render = () => {
19        const app = document.getElementById('app');
20        if (!app) return;
21        // innerHTML replacement alone does not clear outer state: drop
22        // the busy flag so assistive tech leaves the loading state.
23        app.removeAttribute('aria-busy');
24        app.setAttribute('data-failed', 'true');
25        app.innerHTML = '';
26        const message = document.createElement('div');
27        message.className = 'sv-error';
28        const prefix = document.createElement('span');
29        prefix.textContent = prefixText;
30        const details = document.createElement('span');
31        details.textContent = err && err.message ? err.message : String(err || 'unsupported browser');
32        message.append(prefix, details);
33        app.append(message);
34      };
35      if (document.readyState === 'loading' && !document.getElementById('app')) {
36        document.addEventListener('DOMContentLoaded', render, { once: true });
37      } else {
38        render();
39      }
40    }
41
42    // Fetch exactly once: retain a clone for byte fallback before streaming
43    // starts, so a streaming failure never issues a second fetch. An
44    // unsuccessful status fails fast without consuming the body.
45    function instantiateWasm(go, wasmURL) {
46      const instantiateFromBytes = (bytes) => WebAssembly.instantiate(bytes, go.importObject);
47
48      if (!WebAssembly.instantiateStreaming) {
49        return fetch(wasmURL)
50          .then((response) => {
51            if (!response.ok) {
52              throw new Error(`HTTP ${response.status} loading ${wasmURL}`);
53            }
54            return response.arrayBuffer();
55          })
56          .then(instantiateFromBytes);
57      }
58      let fallback = null;
59      return fetch(wasmURL)
60        .then((response) => {
61          if (!response.ok) {
62            throw new Error(`HTTP ${response.status} loading ${wasmURL}`);
63          }
64          fallback = response.clone();
65          return WebAssembly.instantiateStreaming(response, go.importObject);
66        })
67        .catch((err) => {
68          if (!fallback) throw err;
69          console.error(`Streaming WebAssembly load failed for ${wasmURL}; falling back to ArrayBuffer instantiation`, err);
70          return fallback.arrayBuffer().then(instantiateFromBytes);
71        });
72    }
73
74    function waitForBridge() {
75      if (window.dumber && typeof window.dumber.postMessage === 'function') return Promise.resolve();
76      if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.dumber) return Promise.resolve();
77      return new Promise((resolve, reject) => {
78        const deadline = Date.now() + 5000;
79        const check = () => {
80          if (window.dumber && typeof window.dumber.postMessage === 'function') return resolve();
81          if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.dumber) return resolve();
82          if (Date.now() >= deadline) return reject(new Error('no bridge transport available'));
83          setTimeout(check, 10);
84        };
85        check();
86      });
87    }
88
89    if (typeof WebAssembly !== 'object') {
90      renderWasmError('WebAssembly is not supported in this browser: ');
91    } else if (typeof Go !== 'function') {
92      renderWasmError('Go WebAssembly runtime failed to load: ');
93    } else {
94      const go = new Go();
95      // Record the runtime exit code: wasm_exec.js routes runtime.wasmExit
96      // through go.exit, whose default only logs. Reporting the actual
97      // status beats the misleading generic suffix on unexpected exits.
98      let goExitCode = null;
99      const goExit = go.exit.bind(go);
100      go.exit = (code) => {
101        goExitCode = code;
102        goExit(code);
103      };
104      waitForBridge()
105        .then(() => instantiateWasm(go, './systemviews.wasm'))
106        // The runtime stays alive: a resolved go.run means main returned
107        // instead of serving, which is itself a terminal failure.
108        .then((result) => go.run(result.instance))
109        .then(
110          () => {
111            // Go renders fatal mount/bind failures itself and marks
112            // data-failed: never overwrite its terminal state here.
113            const app = document.getElementById('app');
114            if (app && app.dataset && app.dataset.failed) return;
115            const code = goExitCode === null ? 'unknown' : String(goExitCode);
116            renderWasmError('systemviews runtime exited: ', new Error(`exit status ${code}`));
117          },
118          (err) => renderWasmError('Failed to load systemviews WebAssembly: ', err),
119        );
120    }
121  </script>
122</head>
123<body>
124  <main id="app" aria-busy="true">Loading systemviews…</main>
125  <noscript>
126    <p>JavaScript is required to run Dumber system views. Enable JavaScript for <code>dumb://history</code>, <code>dumb://favorites</code>, and <code>dumb://config</code>.</p>
127  </noscript>
128</body>
129</html>

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