From 117d10001925e4b887c8fbf66d6e3afd4f49d468 Mon Sep 17 00:00:00 2001 From: Jinjing <6427696+AmethystLiang@users.noreply.github.com> Date: Mon, 13 Apr 2026 18:51:59 -0700 Subject: [PATCH] feat: add Reveal in Finder to editor header and tab context menus (#603) (#609) Add a right-click context menu to the editor header file path button with Copy Path, Copy Relative Path, and platform-aware Reveal in Finder/File Explorer. Also add the same reveal action to the editor tab context menu, and reorder tab close actions so Close All appears above Close Tabs To The Right. --- .../src/components/editor/EditorPanel.tsx | 75 ++++++++++++++++++- .../src/components/tab-bar/EditorFileTab.tsx | 23 +++++- 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/src/renderer/src/components/editor/EditorPanel.tsx b/src/renderer/src/components/editor/EditorPanel.tsx index 77616d92c..519dc6247 100644 --- a/src/renderer/src/components/editor/EditorPanel.tsx +++ b/src/renderer/src/components/editor/EditorPanel.tsx @@ -5,11 +5,19 @@ across multiple components. Autosave now lives in a smaller headless controller so hidden editor UI no longer participates in shutdown. */ import React, { useCallback, useEffect, useRef, useState, Suspense } from 'react' import * as monaco from 'monaco-editor' -import { Columns2, FileText, Rows2 } from 'lucide-react' +import { Columns2, Copy, ExternalLink, FileText, Rows2 } from 'lucide-react' import { useAppStore } from '@/store' import { detectLanguage } from '@/lib/language-detect' import { getEditorHeaderCopyState, getEditorHeaderOpenFileState } from './editor-header' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger +} from '@/components/ui/dropdown-menu' +import { CLOSE_ALL_CONTEXT_MENUS_EVENT } from '../tab-bar/SortableTab' import type { MarkdownViewMode, OpenFile } from '@/store/slices/editor' import MarkdownViewToggle from './MarkdownViewToggle' import { EditorContent } from './EditorContent' @@ -24,6 +32,16 @@ import { type EditorPathMutationTarget } from './editor-autosave' +const isMac = navigator.userAgent.includes('Mac') +const isLinux = navigator.userAgent.includes('Linux') + +/** Platform-appropriate label: macOS → Finder, Windows → File Explorer, Linux → Files */ +const revealLabel = isMac + ? 'Reveal in Finder' + : isLinux + ? 'Open Containing Folder' + : 'Reveal in File Explorer' + type FileContent = { content: string isBinary: boolean @@ -61,6 +79,8 @@ export default function EditorPanel({ ) const [sideBySide, setSideBySide] = useState(settings?.diffDefaultView === 'side-by-side') const [prevDiffView, setPrevDiffView] = useState(settings?.diffDefaultView) + const [pathMenuOpen, setPathMenuOpen] = useState(false) + const [pathMenuPoint, setPathMenuPoint] = useState({ x: 0, y: 0 }) // Why: When the user changes their global diff-view preference in Settings, // sync the local toggle to match during render (avoids flash of stale diff mode). @@ -74,6 +94,12 @@ export default function EditorPanel({ const openFilesRef = useRef(openFiles) openFilesRef.current = openFiles + useEffect(() => { + const closeMenu = (): void => setPathMenuOpen(false) + window.addEventListener(CLOSE_ALL_CONTEXT_MENUS_EVENT, closeMenu) + return () => window.removeEventListener(CLOSE_ALL_CONTEXT_MENUS_EVENT, closeMenu) + }, []) + // Why: keepCurrentModel / keepCurrent*Model retain Monaco models after unmount // so undo history survives tab switches. When a tab is *closed*, the user has // signalled they're done with the file — dispose the models to reclaim memory @@ -454,7 +480,15 @@ export default function EditorPanel({ {!isCombinedDiff && (