mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 12:44:18 +08:00
refactor(terminal): unify terminal selection using global settings
- Remove terminal selector from Session Manager page - Backend now reads terminal preference from global settings - Add terminal name mapping (iterm2 → iterm) for compatibility - Add WezTerm support to macOS terminal options - Add WezTerm translations for zh/en/ja
This commit is contained in:
@@ -652,6 +652,7 @@ exec bash --norc --noprofile
|
||||
"alacritty" => launch_macos_open_app("Alacritty", &script_file, true),
|
||||
"kitty" => launch_macos_open_app("kitty", &script_file, false),
|
||||
"ghostty" => launch_macos_open_app("Ghostty", &script_file, true),
|
||||
"wezterm" => launch_macos_open_app("WezTerm", &script_file, true),
|
||||
_ => launch_macos_terminal_app(&script_file), // "terminal" or default
|
||||
};
|
||||
|
||||
|
||||
@@ -26,16 +26,24 @@ pub async fn get_session_messages(
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn launch_session_terminal(
|
||||
target: String,
|
||||
command: String,
|
||||
cwd: Option<String>,
|
||||
custom_config: Option<String>,
|
||||
) -> Result<bool, String> {
|
||||
let command = command.clone();
|
||||
let target = target.clone();
|
||||
let cwd = cwd.clone();
|
||||
let custom_config = custom_config.clone();
|
||||
|
||||
// Read preferred terminal from global settings
|
||||
let preferred = crate::settings::get_preferred_terminal();
|
||||
// Map global setting terminal names to session terminal names
|
||||
// Global uses "iterm2", session terminal uses "iterm"
|
||||
let target = match preferred.as_deref() {
|
||||
Some("iterm2") => "iterm".to_string(),
|
||||
Some(t) => t.to_string(),
|
||||
None => "terminal".to_string(), // Default to Terminal.app on macOS
|
||||
};
|
||||
|
||||
tauri::async_runtime::spawn_blocking(move || {
|
||||
session_manager::terminal::launch_terminal(
|
||||
&target,
|
||||
|
||||
@@ -10,9 +10,7 @@ import {
|
||||
MessageSquare,
|
||||
Clock,
|
||||
FolderOpen,
|
||||
Terminal,
|
||||
X,
|
||||
SquareTerminal,
|
||||
} from "lucide-react";
|
||||
import { useSessionMessagesQuery, useSessionsQuery } from "@/lib/query";
|
||||
import { sessionsApi } from "@/lib/api";
|
||||
@@ -24,7 +22,6 @@ import {
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
@@ -37,13 +34,6 @@ import {
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
import { isMac } from "@/lib/platform";
|
||||
import { ProviderIcon } from "@/components/ProviderIcon";
|
||||
import {
|
||||
AlacrittyIcon,
|
||||
GhosttyIcon,
|
||||
ITermIcon,
|
||||
KittyIcon,
|
||||
WezTermIcon,
|
||||
} from "@/components/icons/TerminalIcons";
|
||||
import { SessionItem } from "./SessionItem";
|
||||
import { SessionMessageItem } from "./SessionMessageItem";
|
||||
import { SessionTocDialog, SessionTocSidebar } from "./SessionToc";
|
||||
@@ -56,16 +46,6 @@ import {
|
||||
getSessionKey,
|
||||
} from "./utils";
|
||||
|
||||
const TERMINAL_TARGET_KEY = "session_manager_terminal_target";
|
||||
|
||||
type TerminalTarget =
|
||||
| "terminal"
|
||||
| "iterm"
|
||||
| "ghostty"
|
||||
| "kitty"
|
||||
| "wezterm"
|
||||
| "alacritty";
|
||||
|
||||
type ProviderFilter = "all" | "codex" | "claude";
|
||||
|
||||
export function SessionManagerPage() {
|
||||
@@ -85,26 +65,6 @@ export function SessionManagerPage() {
|
||||
const [search, setSearch] = useState("");
|
||||
const [providerFilter, setProviderFilter] = useState<ProviderFilter>("all");
|
||||
const [selectedKey, setSelectedKey] = useState<string | null>(null);
|
||||
const [terminalTarget, setTerminalTarget] =
|
||||
useState<TerminalTarget>("terminal");
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const storedTarget = window.localStorage.getItem(
|
||||
TERMINAL_TARGET_KEY
|
||||
) as TerminalTarget | null;
|
||||
if (storedTarget) {
|
||||
setTerminalTarget(storedTarget);
|
||||
}
|
||||
|
||||
setIsLoaded(true);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoaded) {
|
||||
window.localStorage.setItem(TERMINAL_TARGET_KEY, terminalTarget);
|
||||
}
|
||||
}, [terminalTarget, isLoaded]);
|
||||
|
||||
// 使用 FlexSearch 全文搜索
|
||||
const { search: searchSessions } = useSessionSearch({
|
||||
@@ -205,7 +165,6 @@ export function SessionManagerPage() {
|
||||
|
||||
try {
|
||||
await sessionsApi.launchTerminal({
|
||||
target: terminalTarget,
|
||||
command: selectedSession.resumeCommand,
|
||||
cwd: selectedSession.projectDir ?? undefined,
|
||||
});
|
||||
@@ -493,84 +452,32 @@ export function SessionManagerPage() {
|
||||
{/* 右侧:操作按钮组 */}
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
{isMac() && (
|
||||
<>
|
||||
<Select
|
||||
value={terminalTarget}
|
||||
onValueChange={(value) =>
|
||||
setTerminalTarget(value as TerminalTarget)
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="h-8 min-w-[110px] w-auto text-xs px-2.5">
|
||||
<Terminal className="size-3 mr-1.5" />
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent align="end">
|
||||
<SelectItem value="terminal">
|
||||
<div className="flex items-center gap-2">
|
||||
<SquareTerminal className="size-3.5" />
|
||||
<span>Terminal</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value="iterm">
|
||||
<div className="flex items-center gap-2">
|
||||
<ITermIcon className="size-3.5" />
|
||||
<span>iTerm2 (Untested)</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value="ghostty">
|
||||
<div className="flex items-center gap-2">
|
||||
<GhosttyIcon className="size-3.5" />
|
||||
<span>Ghostty</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value="kitty">
|
||||
<div className="flex items-center gap-2">
|
||||
<KittyIcon className="size-3.5" />
|
||||
<span>Kitty</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value="wezterm">
|
||||
<div className="flex items-center gap-2">
|
||||
<WezTermIcon className="size-3.5" />
|
||||
<span>WezTerm (Untested)</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value="alacritty">
|
||||
<div className="flex items-center gap-2">
|
||||
<AlacrittyIcon className="size-3.5" />
|
||||
<span>Alacritty (Untested)</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
className="gap-1.5"
|
||||
onClick={() => void handleResume()}
|
||||
disabled={!selectedSession.resumeCommand}
|
||||
>
|
||||
<Play className="size-3.5" />
|
||||
<span className="hidden sm:inline">
|
||||
{t("sessionManager.resume", {
|
||||
defaultValue: "恢复会话",
|
||||
})}
|
||||
</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{selectedSession.resumeCommand
|
||||
? t("sessionManager.resumeTooltip", {
|
||||
defaultValue: "在终端中恢复此会话",
|
||||
})
|
||||
: t("sessionManager.noResumeCommand", {
|
||||
defaultValue: "此会话无法恢复",
|
||||
})}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
className="gap-1.5"
|
||||
onClick={() => void handleResume()}
|
||||
disabled={!selectedSession.resumeCommand}
|
||||
>
|
||||
<Play className="size-3.5" />
|
||||
<span className="hidden sm:inline">
|
||||
{t("sessionManager.resume", {
|
||||
defaultValue: "恢复会话",
|
||||
})}
|
||||
</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{selectedSession.resumeCommand
|
||||
? t("sessionManager.resumeTooltip", {
|
||||
defaultValue: "在终端中恢复此会话",
|
||||
})
|
||||
: t("sessionManager.noResumeCommand", {
|
||||
defaultValue: "此会话无法恢复",
|
||||
})}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,6 +15,7 @@ const MACOS_TERMINALS = [
|
||||
{ value: "alacritty", labelKey: "settings.terminal.options.macos.alacritty" },
|
||||
{ value: "kitty", labelKey: "settings.terminal.options.macos.kitty" },
|
||||
{ value: "ghostty", labelKey: "settings.terminal.options.macos.ghostty" },
|
||||
{ value: "wezterm", labelKey: "settings.terminal.options.macos.wezterm" },
|
||||
] as const;
|
||||
|
||||
const WINDOWS_TERMINALS = [
|
||||
|
||||
@@ -300,7 +300,8 @@
|
||||
"iterm2": "iTerm2",
|
||||
"alacritty": "Alacritty",
|
||||
"kitty": "Kitty",
|
||||
"ghostty": "Ghostty"
|
||||
"ghostty": "Ghostty",
|
||||
"wezterm": "WezTerm"
|
||||
},
|
||||
"windows": {
|
||||
"cmd": "Command Prompt",
|
||||
|
||||
@@ -300,7 +300,8 @@
|
||||
"iterm2": "iTerm2",
|
||||
"alacritty": "Alacritty",
|
||||
"kitty": "Kitty",
|
||||
"ghostty": "Ghostty"
|
||||
"ghostty": "Ghostty",
|
||||
"wezterm": "WezTerm"
|
||||
},
|
||||
"windows": {
|
||||
"cmd": "コマンドプロンプト",
|
||||
|
||||
@@ -300,7 +300,8 @@
|
||||
"iterm2": "iTerm2",
|
||||
"alacritty": "Alacritty",
|
||||
"kitty": "Kitty",
|
||||
"ghostty": "Ghostty"
|
||||
"ghostty": "Ghostty",
|
||||
"wezterm": "WezTerm"
|
||||
},
|
||||
"windows": {
|
||||
"cmd": "命令提示符",
|
||||
|
||||
@@ -14,14 +14,12 @@ export const sessionsApi = {
|
||||
},
|
||||
|
||||
async launchTerminal(options: {
|
||||
target: string;
|
||||
command: string;
|
||||
cwd?: string | null;
|
||||
customConfig?: string | null;
|
||||
}): Promise<boolean> {
|
||||
const { target, command, cwd, customConfig } = options;
|
||||
const { command, cwd, customConfig } = options;
|
||||
return await invoke("launch_session_terminal", {
|
||||
target,
|
||||
command,
|
||||
cwd,
|
||||
customConfig,
|
||||
|
||||
Reference in New Issue
Block a user