Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed
- Properly map all hotkeys in UI based on the platform [#784](https://github.com/sourcebot-dev/sourcebot/pull/784)

## [4.10.16] - 2026-01-22

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const BottomPanel = ({ order }: BottomPanelProps) => {
>
<VscReferences className="w-4 h-4" />
Explore
<KeyboardShortcutHint shortcut="⇧ ⌘ E" />
<KeyboardShortcutHint shortcut="shift+mod+e" />
</Button>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ export const ChatSidePanel = ({
</Button>
</TooltipTrigger>
<TooltipContent side="bottom" className="flex flex-row items-center gap-2">
<KeyboardShortcutHint shortcut="⌘ B" />
<KeyboardShortcutHint shortcut="mod+b" />
<Separator orientation="vertical" className="h-4" />
<span>Open side panel</span>
</TooltipContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,13 +411,13 @@ const SearchSuggestionsBox = forwardRef(({
Syntax help:
</p>
<div className="flex flex-row gap-0.5 items-center">
<KeyboardShortcutHint shortcut="" />
<KeyboardShortcutHint shortcut="mod" />
<KeyboardShortcutHint shortcut="/" />
</div>
</div>
{isFocused && (
<span className="flex flex-row gap-1.5 items-center">
<KeyboardShortcutHint shortcut="" />
<KeyboardShortcutHint shortcut="enter" />
<span className="text-muted-foreground text-sm font-medium">
to select
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export const SearchModeSelector = ({
<span>Search</span>
<div className="flex flex-row items-center gap-2">
<Separator orientation="vertical" className="h-4" />
<KeyboardShortcutHint shortcut="⌘ P" />
<KeyboardShortcutHint shortcut="mod+p" />
</div>
</div>

Expand Down Expand Up @@ -135,7 +135,7 @@ export const SearchModeSelector = ({

<div className="flex flex-row items-center gap-2">
<Separator orientation="vertical" className="h-4" />
<KeyboardShortcutHint shortcut="⌘ I" />
<KeyboardShortcutHint shortcut="mod+i" />
</div>
</div>
</SelectItemNoItemText>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const SyntaxReferenceGuideHint = () => {
className="text-sm cursor-pointer"
onClick={() => onOpenChanged(!isOpen)}
>
<span className="dark:text-gray-300">Reference guide: </span><KeyboardShortcutHint shortcut="" /> <KeyboardShortcutHint shortcut="/" />
<span className="dark:text-gray-300">Reference guide: </span><KeyboardShortcutHint shortcut="mod" /> <KeyboardShortcutHint shortcut="/" />
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ const PanelGroup = ({
</Button>
</TooltipTrigger>
<TooltipContent side="right" className="flex flex-row items-center gap-2">
<KeyboardShortcutHint shortcut="⌘ B" />
<KeyboardShortcutHint shortcut="mod+b" />
<Separator orientation="vertical" className="h-4" />
<span>Open filter panel</span>
</TooltipContent>
Expand Down
89 changes: 78 additions & 11 deletions packages/web/src/app/components/keyboardShortcutHint.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,89 @@ import { cn, IS_MAC } from '@/lib/utils'
import React, { useMemo } from 'react'

interface KeyboardShortcutHintProps {
shortcut: string
label?: string
className?: string
shortcut: string
label?: string
className?: string
}

/**
* Converts Mac-specific keyboard shortcuts to platform-appropriate shortcuts.
* On Mac: displays the shortcut as-is (e.g., "⌘")
* On Windows/Linux: replaces "⌘" with "Ctrl"
* Maps for converting react-hotkeys syntax to platform-specific symbols.
* Accepts shortcuts like "mod+b", "alt+shift+f12", etc.
*/
function getPlatformShortcut(shortcut: string): string {
if (IS_MAC) {
return shortcut;
const MAC_KEY_MAP: Record<string, string> = {
mod: '⌘',
meta: '⌘',
ctrl: '⌃',
control: '⌃',
alt: '⌥',
option: '⌥',
shift: '⇧',
enter: '↵',
return: '↵',
backspace: '⌫',
delete: '⌦',
escape: '⎋',
esc: '⎋',
tab: '⇥',
space: '␣',
up: '↑',
down: '↓',
left: '←',
right: '→',
};

const WINDOWS_KEY_MAP: Record<string, string> = {
mod: 'Ctrl',
meta: 'Win',
ctrl: 'Ctrl',
control: 'Ctrl',
alt: 'Alt',
option: 'Alt',
shift: 'Shift',
enter: 'Enter',
return: 'Enter',
backspace: 'Backspace',
delete: 'Delete',
escape: 'Esc',
esc: 'Esc',
tab: 'Tab',
space: 'Space',
up: '↑',
down: '↓',
left: '←',
right: '→',
};

/**
* Converts a single key from react-hotkeys syntax to platform-appropriate display.
*/
function mapKey(key: string, keyMap: Record<string, string>): string {
const lowerKey = key.toLowerCase();
if (keyMap[lowerKey]) {
return keyMap[lowerKey];
}
// For single letters, keep uppercase
if (key.length === 1) {
return key.toUpperCase();
}
// Replace Mac Command key symbol with Ctrl for non-Mac platforms
return shortcut.replace(/⌘/g, 'Ctrl');
// For function keys (F1-F12), keep as-is but uppercase
if (/^f\d{1,2}$/i.test(key)) {
return key.toUpperCase();
}
// Default: return the key with first letter capitalized
return key.charAt(0).toUpperCase() + key.slice(1).toLowerCase();
}

/**
* Converts react-hotkeys syntax to platform-appropriate keyboard shortcut display.
* Accepts formats like: "mod+b", "alt+shift+f12", "ctrl enter"
*/
function getPlatformShortcut(shortcut: string): string {
// Split by + or space to handle both "mod+b" and "⌘ B" formats
const keys = shortcut.split(/[+\s]+/).filter(Boolean);
const keyMap = IS_MAC ? MAC_KEY_MAP : WINDOWS_KEY_MAP;

return keys.map(key => mapKey(key, keyMap)).join(' ');
}

export function KeyboardShortcutHint({ shortcut, label, className }: KeyboardShortcutHintProps) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export const ExploreMenu = ({
<TooltipContent side="top" align="center">
Search all repositories
<KeyboardShortcutHint
shortcut="⇧ A"
shortcut="shift+a"
className="ml-2"
/>
</TooltipContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ export const SymbolHoverPopup: React.FC<SymbolHoverPopupProps> = ({
side="bottom"
className="flex flex-row items-center gap-2"
>
<KeyboardShortcutHint shortcut="⌥ F12" />
<KeyboardShortcutHint shortcut="alt+f12" />
<Separator orientation="vertical" className="h-4" />
<span>{`Go to ${symbolInfo.symbolDefinitions && symbolInfo.symbolDefinitions.length > 1 ? "definitions" : "definition"}`}</span>
</TooltipContent>
Expand All @@ -306,7 +306,7 @@ export const SymbolHoverPopup: React.FC<SymbolHoverPopupProps> = ({
side="bottom"
className="flex flex-row items-center gap-2"
>
<KeyboardShortcutHint shortcut="⌥ ⇧ F12" />
<KeyboardShortcutHint shortcut="alt+shift+f12" />
<Separator orientation="vertical" className="h-4" />
<span>Find references</span>
</TooltipContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export const FileTreePanel = ({ order }: FileTreePanelProps) => {
</Button>
</TooltipTrigger>
<TooltipContent side="bottom" className="flex flex-row items-center gap-2">
<KeyboardShortcutHint shortcut="⌘ B" />
<KeyboardShortcutHint shortcut="mod+b" />
<Separator orientation="vertical" className="h-4" />
<span>Close file tree</span>
</TooltipContent>
Expand All @@ -175,7 +175,7 @@ export const FileTreePanel = ({ order }: FileTreePanelProps) => {
</Button>
</TooltipTrigger>
<TooltipContent side="bottom" className="flex flex-row items-center gap-2">
<KeyboardShortcutHint shortcut="⌘ P" />
<KeyboardShortcutHint shortcut="mod+p" />
<Separator orientation="vertical" className="h-4" />
<span>Search files</span>
</TooltipContent>
Expand Down Expand Up @@ -217,7 +217,7 @@ export const FileTreePanel = ({ order }: FileTreePanelProps) => {
</Button>
</TooltipTrigger>
<TooltipContent side="bottom" className="flex flex-row items-center gap-2">
<KeyboardShortcutHint shortcut="⌘ B" />
<KeyboardShortcutHint shortcut="mod+b" />
<Separator orientation="vertical" className="h-4" />
<span>Open file tree</span>
</TooltipContent>
Expand Down