Download scripts/generate-keybindings-doc.ts from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 4.91 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/scripts/generate-keybindings-doc.ts
- Command line
-
hf download hf://SaylorTwift/gemini-cli/scripts/generate-keybindings-doc.ts
-
curl -L -o generate-keybindings-doc.ts https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/scripts/generate-keybindings-doc.ts
4.91 kB
| /** | |
| * @license | |
| * Copyright 2025 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import path from 'node:path'; | |
| import { fileURLToPath, pathToFileURL } from 'node:url'; | |
| import { readFile, writeFile } from 'node:fs/promises'; | |
| import type { KeyBinding } from '../packages/cli/src/ui/key/keyBindings.js'; | |
| import { | |
| commandCategories, | |
| commandDescriptions, | |
| defaultKeyBindingConfig, | |
| Command, | |
| getPlatformUndoBindings, | |
| getPlatformRedoBindings, | |
| } from '../packages/cli/src/ui/key/keyBindings.js'; | |
| import { | |
| formatWithPrettier, | |
| injectBetweenMarkers, | |
| normalizeForCompare, | |
| } from './utils/autogen.js'; | |
| const START_MARKER = '<!-- KEYBINDINGS-AUTOGEN:START -->'; | |
| const END_MARKER = '<!-- KEYBINDINGS-AUTOGEN:END -->'; | |
| const OUTPUT_RELATIVE_PATH = ['docs', 'reference', 'keyboard-shortcuts.md']; | |
| import { formatKeyBinding } from '../packages/cli/src/ui/key/keybindingUtils.js'; | |
| export interface KeybindingDocCommand { | |
| command: string; | |
| description: string; | |
| bindings: readonly KeyBinding[]; | |
| } | |
| export interface KeybindingDocSection { | |
| title: string; | |
| commands: readonly KeybindingDocCommand[]; | |
| } | |
| export async function main(argv = process.argv.slice(2)) { | |
| const checkOnly = argv.includes('--check'); | |
| const repoRoot = path.resolve( | |
| path.dirname(fileURLToPath(import.meta.url)), | |
| '..', | |
| ); | |
| const docPath = path.join(repoRoot, ...OUTPUT_RELATIVE_PATH); | |
| const sections = buildDefaultDocSections(); | |
| const generatedBlock = renderDocumentation(sections); | |
| const currentDoc = await readFile(docPath, 'utf8'); | |
| const injectedDoc = injectBetweenMarkers({ | |
| document: currentDoc, | |
| startMarker: START_MARKER, | |
| endMarker: END_MARKER, | |
| newContent: generatedBlock, | |
| paddingBefore: '\n\n', | |
| paddingAfter: '\n', | |
| }); | |
| const updatedDoc = await formatWithPrettier(injectedDoc, docPath); | |
| if (normalizeForCompare(updatedDoc) === normalizeForCompare(currentDoc)) { | |
| if (!checkOnly) { | |
| console.log('Keybinding documentation already up to date.'); | |
| } | |
| return; | |
| } | |
| if (checkOnly) { | |
| console.error( | |
| 'Keybinding documentation is out of date. Run `npm run docs:keybindings` to regenerate.', | |
| ); | |
| process.exitCode = 1; | |
| return; | |
| } | |
| await writeFile(docPath, updatedDoc, 'utf8'); | |
| console.log('Keybinding documentation regenerated.'); | |
| } | |
| export function buildDefaultDocSections(): readonly KeybindingDocSection[] { | |
| return commandCategories.map((category) => ({ | |
| title: category.title, | |
| commands: category.commands.map((command) => { | |
| // For UNDO and REDO, we want to show all platform variants in the docs | |
| if (command === Command.UNDO) { | |
| return { | |
| command: command, | |
| description: commandDescriptions[command], | |
| bindings: getMergedPlatformBindings(getPlatformUndoBindings), | |
| }; | |
| } | |
| if (command === Command.REDO) { | |
| return { | |
| command: command, | |
| description: commandDescriptions[command], | |
| bindings: getMergedPlatformBindings(getPlatformRedoBindings), | |
| }; | |
| } | |
| return { | |
| command: command, | |
| description: commandDescriptions[command], | |
| bindings: defaultKeyBindingConfig.get(command) ?? [], | |
| }; | |
| }), | |
| })); | |
| } | |
| function getMergedPlatformBindings( | |
| getBindings: (platform: string) => readonly KeyBinding[], | |
| ): readonly KeyBinding[] { | |
| const win32 = getBindings('win32'); | |
| const darwin = getBindings('darwin'); | |
| const linux = getBindings('linux'); | |
| const all = [...win32, ...darwin, ...linux]; | |
| const seen = new Set<string>(); | |
| const unique: KeyBinding[] = []; | |
| for (const b of all) { | |
| const key = `${b.name}-${b.ctrl}-${b.shift}-${b.alt}-${b.cmd}`; | |
| if (!seen.has(key)) { | |
| seen.add(key); | |
| unique.push(b); | |
| } | |
| } | |
| return unique; | |
| } | |
| export function renderDocumentation( | |
| sections: readonly KeybindingDocSection[], | |
| ): string { | |
| const renderedSections = sections.map((section) => { | |
| const rows = section.commands.map((command) => { | |
| const formattedBindings = formatBindings(command.bindings); | |
| const keysCell = formattedBindings.join('<br />'); | |
| return `| \`${command.command}\` | ${command.description} | ${keysCell} |`; | |
| }); | |
| return [ | |
| `#### ${section.title}`, | |
| '', | |
| '| Command | Action | Keys |', | |
| '| --- | --- | --- |', | |
| ...rows, | |
| ].join('\n'); | |
| }); | |
| return renderedSections.join('\n\n'); | |
| } | |
| function formatBindings(bindings: readonly KeyBinding[]): string[] { | |
| const seen = new Set<string>(); | |
| const results: string[] = []; | |
| for (const binding of bindings) { | |
| const label = formatKeyBinding(binding, 'default'); | |
| if (label && !seen.has(label)) { | |
| seen.add(label); | |
| results.push(`\`${label}\``); | |
| } | |
| } | |
| return results; | |
| } | |
| if (process.argv[1]) { | |
| const entryUrl = pathToFileURL(path.resolve(process.argv[1])).href; | |
| if (entryUrl === import.meta.url) { | |
| await main(); | |
| } | |
| } | |