mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-10-01 09:19:34 +05:30
feat(quick-switcher): wire Cmd+P into File menu + renderer
End-to-end wiring of the Quick Switcher overlay:
- main.js File menu: new 'Quick Switcher...' item with Cmd+P
accelerator (moved from Print Preview; Print Preview stays in
File > Print submenu but loses its shortcut). Recent Files
submenu and its buildRecentFilesMenu() helper removed.
- new 'recent-files:get' invoke IPC handler returns the recent
files array on demand.
- preload.js: 'recent-files:get' + 'show-quick-switcher' added
to channel whitelists; quickSwitcher.getRecentFiles() exposed.
- renderer.js: lazy-mounts the overlay on first 'show-quick-switcher'
message, fetches recent files via IPC, and shows the overlay.
File-open goes through the existing 'open-file-path' channel.
Workspace dir is intentionally null for v4.13.0 — the workspace
search toggle is wired but a no-op until the explorer panel exposes
its current directory (next iteration).
Amit Haridas
This commit is contained in:
+12
-61
@@ -684,62 +684,6 @@ function createWindow() {
|
|||||||
// Wait for the page to fully load before sending file data
|
// Wait for the page to fully load before sending file data
|
||||||
mainWindow.webContents.on('did-finish-load', () => {});
|
mainWindow.webContents.on('did-finish-load', () => {});
|
||||||
}
|
}
|
||||||
function buildRecentFilesMenu() {
|
|
||||||
const recentFiles = getRecentFiles();
|
|
||||||
if (recentFiles.length === 0) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: 'No recent files',
|
|
||||||
enabled: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
const recentFileItems = recentFiles.map((filePath) => ({
|
|
||||||
label: filePath.split(/[\\/]/).pop(),
|
|
||||||
// Get filename only
|
|
||||||
click: () => {
|
|
||||||
if (fs.existsSync(filePath)) {
|
|
||||||
const stats = fs.statSync(filePath);
|
|
||||||
if (stats.size > MAX_FILE_SIZE) {
|
|
||||||
dialog.showErrorBox(
|
|
||||||
'File Too Large',
|
|
||||||
`File exceeds the ${MAX_FILE_SIZE_MB}MB size limit.`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
currentFile = filePath;
|
|
||||||
const content = fs.readFileSync(filePath, 'utf-8');
|
|
||||||
mainWindow.webContents.send('file-opened', {
|
|
||||||
path: filePath,
|
|
||||||
content,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
dialog.showErrorBox(
|
|
||||||
'File Not Found',
|
|
||||||
sanitizeErrorMessage(`The file "${filePath}" could not be found.`)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toolTip: filePath, // Show full path in tooltip
|
|
||||||
}));
|
|
||||||
return [
|
|
||||||
...recentFileItems,
|
|
||||||
{
|
|
||||||
type: 'separator',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Clear Recent Files',
|
|
||||||
click: () => {
|
|
||||||
try {
|
|
||||||
clearRecentFilesOnDisk();
|
|
||||||
mainWindow.webContents.send('recent-files-cleared');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error clearing recent files:', error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
function getRecentFiles() {
|
function getRecentFiles() {
|
||||||
try {
|
try {
|
||||||
const recentFiles = JSON.parse(
|
const recentFiles = JSON.parse(
|
||||||
@@ -783,12 +727,19 @@ function createMenu() {
|
|||||||
{
|
{
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// v4.13.0 — Quick Switcher replaces the Recent Files submenu.
|
||||||
|
// Cmd+P moved here from Print Preview; the Print Preview menu
|
||||||
|
// entry is still reachable via File → Print but lost its shortcut.
|
||||||
|
label: 'Quick Switcher...',
|
||||||
|
accelerator: 'CmdOrCtrl+P',
|
||||||
|
click: () => mainWindow.webContents.send('show-quick-switcher'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Print',
|
label: 'Print',
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
label: 'Print Preview',
|
label: 'Print Preview',
|
||||||
accelerator: 'CmdOrCtrl+P',
|
|
||||||
click: () => mainWindow.webContents.send('print-preview'),
|
click: () => mainWindow.webContents.send('print-preview'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -800,10 +751,6 @@ function createMenu() {
|
|||||||
{
|
{
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'Recent Files',
|
|
||||||
submenu: buildRecentFilesMenu(),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
},
|
},
|
||||||
@@ -4957,6 +4904,10 @@ ipcMain.on('clear-recent-files', (event) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Quick-switcher (v4.13.0): renderer asks for the recent-files list when
|
||||||
|
// the Cmd+P overlay opens. Read-only — write paths remain send-only.
|
||||||
|
ipcMain.handle('recent-files:get', () => getRecentFiles());
|
||||||
|
|
||||||
// Plugins (loaded in the renderer) report the export formats they've
|
// Plugins (loaded in the renderer) report the export formats they've
|
||||||
// registered; rebuild the Export menu so they show up as entries.
|
// registered; rebuild the Export menu so they show up as entries.
|
||||||
// createMenu() is idempotent and already re-invoked elsewhere (e.g. after
|
// createMenu() is idempotent and already re-invoked elsewhere (e.g. after
|
||||||
|
|||||||
@@ -191,6 +191,7 @@ const ALLOWED_SEND_CHANNELS = [
|
|||||||
|
|
||||||
// Quick-switcher (Cmd+P workspace file picker)
|
// Quick-switcher (Cmd+P workspace file picker)
|
||||||
'quick-switcher:list-files',
|
'quick-switcher:list-files',
|
||||||
|
'recent-files:get',
|
||||||
|
|
||||||
// Document version history
|
// Document version history
|
||||||
'version-history:list',
|
'version-history:list',
|
||||||
@@ -330,6 +331,9 @@ const ALLOWED_RECEIVE_CHANNELS = [
|
|||||||
'toggle-sidebar-panel',
|
'toggle-sidebar-panel',
|
||||||
'toggle-bottom-panel',
|
'toggle-bottom-panel',
|
||||||
|
|
||||||
|
// v4.13.0 — quick-switcher overlay trigger
|
||||||
|
'show-quick-switcher',
|
||||||
|
|
||||||
// Plugin export formats
|
// Plugin export formats
|
||||||
'run-plugin-export-format',
|
'run-plugin-export-format',
|
||||||
];
|
];
|
||||||
@@ -557,6 +561,7 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
|||||||
// fuzzy matcher (src/quick-switcher/fuzzy-matcher.js) does the ranking.
|
// fuzzy matcher (src/quick-switcher/fuzzy-matcher.js) does the ranking.
|
||||||
quickSwitcher: {
|
quickSwitcher: {
|
||||||
listFiles: (dir, options) => ipcRenderer.invoke('quick-switcher:list-files', { dir, options }),
|
listFiles: (dir, options) => ipcRenderer.invoke('quick-switcher:list-files', { dir, options }),
|
||||||
|
getRecentFiles: () => ipcRenderer.invoke('recent-files:get'),
|
||||||
},
|
},
|
||||||
|
|
||||||
getAppVersion: () => ipcRenderer.invoke('get-app-version'),
|
getAppVersion: () => ipcRenderer.invoke('get-app-version'),
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ let _SidebarManager,
|
|||||||
_renderGitPanel,
|
_renderGitPanel,
|
||||||
_renderSnippetsPanel;
|
_renderSnippetsPanel;
|
||||||
let _ReplPanel, _CommandPalette, _PrintPreview, _createWelcomeContent;
|
let _ReplPanel, _CommandPalette, _PrintPreview, _createWelcomeContent;
|
||||||
|
let _createQuickSwitcherOverlay;
|
||||||
function getSidebarManager() {
|
function getSidebarManager() {
|
||||||
if (!_SidebarManager) _SidebarManager = require('./sidebar/sidebar-manager').SidebarManager;
|
if (!_SidebarManager) _SidebarManager = require('./sidebar/sidebar-manager').SidebarManager;
|
||||||
return _SidebarManager;
|
return _SidebarManager;
|
||||||
@@ -213,6 +214,12 @@ function getCommandPalette() {
|
|||||||
if (!_CommandPalette) _CommandPalette = require('./command-palette').CommandPalette;
|
if (!_CommandPalette) _CommandPalette = require('./command-palette').CommandPalette;
|
||||||
return _CommandPalette;
|
return _CommandPalette;
|
||||||
}
|
}
|
||||||
|
function getCreateQuickSwitcherOverlay() {
|
||||||
|
if (!_createQuickSwitcherOverlay)
|
||||||
|
_createQuickSwitcherOverlay =
|
||||||
|
require('./quick-switcher/quick-switcher-overlay').createQuickSwitcherOverlay;
|
||||||
|
return _createQuickSwitcherOverlay;
|
||||||
|
}
|
||||||
function getPrintPreview() {
|
function getPrintPreview() {
|
||||||
if (!_PrintPreview) _PrintPreview = require('./print-preview').PrintPreview;
|
if (!_PrintPreview) _PrintPreview = require('./print-preview').PrintPreview;
|
||||||
return _PrintPreview;
|
return _PrintPreview;
|
||||||
@@ -2541,6 +2548,33 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
// Initialize command palette
|
// Initialize command palette
|
||||||
const CommandPalette = getCommandPalette();
|
const CommandPalette = getCommandPalette();
|
||||||
const commandPalette = new CommandPalette();
|
const commandPalette = new CommandPalette();
|
||||||
|
|
||||||
|
// Quick-switcher (Cmd+P) overlay — lazy-mounted on first trigger.
|
||||||
|
// Workspace dir is sourced from the explorer panel when it has one open;
|
||||||
|
// for the initial v4.13.0 release we ship without workspace tracking and
|
||||||
|
// the "Search workspace" toggle silently stays off.
|
||||||
|
let quickSwitcherOverlayInstance = null;
|
||||||
|
function ensureQuickSwitcherOverlay() {
|
||||||
|
if (quickSwitcherOverlayInstance) return quickSwitcherOverlayInstance;
|
||||||
|
const create = getCreateQuickSwitcherOverlay();
|
||||||
|
const host = document.createElement('div');
|
||||||
|
host.id = 'quick-switcher-host';
|
||||||
|
document.body.appendChild(host);
|
||||||
|
quickSwitcherOverlayInstance = create(host, {
|
||||||
|
getOpenTabPaths: () =>
|
||||||
|
Array.from(tabManager.tabs.values())
|
||||||
|
.map((t) => t.filePath)
|
||||||
|
.filter(Boolean),
|
||||||
|
listWorkspaceFiles: (dir, options) =>
|
||||||
|
window.electronAPI.quickSwitcher.listFiles(dir, options),
|
||||||
|
onOpenFile: (filePath) => ipcRenderer.send('open-file-path', filePath),
|
||||||
|
// v4.13.0 — explorer-driven workspace dir is the next iteration;
|
||||||
|
// for now the workspace toggle is a no-op and we surface only
|
||||||
|
// recent files + open tabs.
|
||||||
|
getWorkspaceDir: () => null,
|
||||||
|
});
|
||||||
|
return quickSwitcherOverlayInstance;
|
||||||
|
}
|
||||||
const pluginRegistry = new PluginRegistry({
|
const pluginRegistry = new PluginRegistry({
|
||||||
sidebar: sidebarManager,
|
sidebar: sidebarManager,
|
||||||
commands: commandPalette,
|
commands: commandPalette,
|
||||||
@@ -2934,6 +2968,18 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// File menu: Cmd+P opens the Quick Switcher overlay (v4.13.0).
|
||||||
|
ipcRenderer.on('show-quick-switcher', async () => {
|
||||||
|
const overlay = ensureQuickSwitcherOverlay();
|
||||||
|
let recent = [];
|
||||||
|
try {
|
||||||
|
recent = (await window.electronAPI.quickSwitcher.getRecentFiles()) || [];
|
||||||
|
} catch {
|
||||||
|
recent = [];
|
||||||
|
}
|
||||||
|
overlay.show({ recent });
|
||||||
|
});
|
||||||
|
|
||||||
// Keyboard shortcuts
|
// Keyboard shortcuts
|
||||||
document.addEventListener('keydown', (e) => {
|
document.addEventListener('keydown', (e) => {
|
||||||
// Ctrl+Shift+P — Command Palette
|
// Ctrl+Shift+P — Command Palette
|
||||||
|
|||||||
Reference in New Issue
Block a user