From 0384efae2812e908053d1490e2fc9be30f1f7e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=AE=B6=E8=AE=AD?= Date: Mon, 3 Aug 2026 15:05:04 +0800 Subject: [PATCH] Add cross-platform IDEA launch commands --- .../biz/gitreview/GitReviewService.java | 11 ++-- .../biz/gitreview/GitReviewWindow.java | 3 +- .../biz/gitreview/IdeaLaunchCommands.java | 53 ++++++++++++++++++ .../biz/gitreview/IdeaLaunchCommandsTest.java | 54 +++++++++++++++++++ 4 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/example/workutils/biz/gitreview/IdeaLaunchCommands.java create mode 100644 src/test/java/com/example/workutils/biz/gitreview/IdeaLaunchCommandsTest.java diff --git a/src/main/java/com/example/workutils/biz/gitreview/GitReviewService.java b/src/main/java/com/example/workutils/biz/gitreview/GitReviewService.java index 663d7f2..40ae853 100644 --- a/src/main/java/com/example/workutils/biz/gitreview/GitReviewService.java +++ b/src/main/java/com/example/workutils/biz/gitreview/GitReviewService.java @@ -337,15 +337,10 @@ public class GitReviewService { private boolean startIdea(String ideaCommand, List args, LogSink logs) { List configured = splitCommandLine(ideaCommand); - List candidates = configured.isEmpty() - ? Arrays.asList("idea64.exe", "idea.bat", "idea") - : Collections.singletonList(String.join(" ", configured)); + List> candidates = IdeaLaunchCommands.candidates( + IdeaLaunchCommands.currentOperatingSystem(), configured, args); - for (String candidate : candidates) { - List command = configured.isEmpty() - ? new ArrayList<>(Collections.singletonList(candidate)) - : new ArrayList<>(configured); - command.addAll(args); + for (List command : candidates) { if (startProcess(command)) { return true; } diff --git a/src/main/java/com/example/workutils/biz/gitreview/GitReviewWindow.java b/src/main/java/com/example/workutils/biz/gitreview/GitReviewWindow.java index ad038da..b56fa0a 100644 --- a/src/main/java/com/example/workutils/biz/gitreview/GitReviewWindow.java +++ b/src/main/java/com/example/workutils/biz/gitreview/GitReviewWindow.java @@ -219,7 +219,8 @@ public class GitReviewWindow { projectValueLabel = valueLabel(); sourceBranchValueLabel = valueLabel(); targetBranchValueLabel = valueLabel(); - ideaCommandField = textField("idea64.exe"); + ideaCommandField = textField(""); + ideaCommandField.setPromptText("自动检测"); HBox ideaBox = new HBox(Theme.S2, ideaCommandField, smallButton("选择...", this::chooseIdeaCommand)); HBox.setHgrow(ideaCommandField, Priority.ALWAYS); diff --git a/src/main/java/com/example/workutils/biz/gitreview/IdeaLaunchCommands.java b/src/main/java/com/example/workutils/biz/gitreview/IdeaLaunchCommands.java new file mode 100644 index 0000000..07a307d --- /dev/null +++ b/src/main/java/com/example/workutils/biz/gitreview/IdeaLaunchCommands.java @@ -0,0 +1,53 @@ +package com.example.workutils.biz.gitreview; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +final class IdeaLaunchCommands { + + enum OperatingSystem { WINDOWS, MAC, LINUX } + + private IdeaLaunchCommands() { + } + + static OperatingSystem currentOperatingSystem() { + return detect(System.getProperty("os.name", "")); + } + + static OperatingSystem detect(String osName) { + String normalized = osName.toLowerCase(Locale.ROOT); + if (normalized.contains("win")) { + return OperatingSystem.WINDOWS; + } + if (normalized.contains("mac")) { + return OperatingSystem.MAC; + } + return OperatingSystem.LINUX; + } + + static List> candidates( + OperatingSystem operatingSystem, + List configured, + List projectArguments) { + if (!configured.isEmpty()) { + return List.of(append(configured, projectArguments)); + } + return switch (operatingSystem) { + case WINDOWS -> List.of( + append(List.of("idea64.exe"), projectArguments), + append(List.of("idea.bat"), projectArguments), + append(List.of("idea"), projectArguments)); + case MAC -> List.of( + append(List.of("idea"), projectArguments), + append(List.of("open", "-a", "IntelliJ IDEA"), projectArguments)); + case LINUX -> List.of(append(List.of("idea"), projectArguments)); + }; + } + + private static List append(List command, List arguments) { + List result = new ArrayList<>(command); + result.addAll(arguments); + return List.copyOf(result); + } +} diff --git a/src/test/java/com/example/workutils/biz/gitreview/IdeaLaunchCommandsTest.java b/src/test/java/com/example/workutils/biz/gitreview/IdeaLaunchCommandsTest.java new file mode 100644 index 0000000..85f76e6 --- /dev/null +++ b/src/test/java/com/example/workutils/biz/gitreview/IdeaLaunchCommandsTest.java @@ -0,0 +1,54 @@ +package com.example.workutils.biz.gitreview; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static com.example.workutils.biz.gitreview.IdeaLaunchCommands.OperatingSystem.LINUX; +import static com.example.workutils.biz.gitreview.IdeaLaunchCommands.OperatingSystem.MAC; +import static com.example.workutils.biz.gitreview.IdeaLaunchCommands.OperatingSystem.WINDOWS; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class IdeaLaunchCommandsTest { + + @Test + void macUsesCliThenOpenApplicationFallback() { + List> commands = IdeaLaunchCommands.candidates( + MAC, List.of(), List.of("/项目 空间/demo")); + + assertEquals(List.of("idea", "/项目 空间/demo"), commands.get(0)); + assertEquals(List.of("open", "-a", "IntelliJ IDEA", "/项目 空间/demo"), commands.get(1)); + } + + @Test + void windowsTriesExeBatchAndPathCommands() { + List> commands = IdeaLaunchCommands.candidates( + WINDOWS, List.of(), List.of("D:/项目 空间")); + + assertEquals(List.of("idea64.exe", "D:/项目 空间"), commands.get(0)); + assertEquals(List.of("idea.bat", "D:/项目 空间"), commands.get(1)); + assertEquals(List.of("idea", "D:/项目 空间"), commands.get(2)); + } + + @Test + void linuxUsesIdeaFromPath() { + assertEquals(List.of(List.of("idea", "/项目 空间")), + IdeaLaunchCommands.candidates(LINUX, List.of(), List.of("/项目 空间"))); + } + + @Test + void configuredCommandAlwaysWinsAndRetainsArgumentBoundaries() { + assertEquals( + List.of(List.of("/Applications/IntelliJ IDEA.app/Contents/MacOS/idea", "--wait", "/项目 空间")), + IdeaLaunchCommands.candidates(MAC, + List.of("/Applications/IntelliJ IDEA.app/Contents/MacOS/idea", "--wait"), + List.of("/项目 空间"))); + } + + @Test + void operatingSystemNamesAreDetectedCaseInsensitively() { + assertEquals(WINDOWS, IdeaLaunchCommands.detect("Windows 11")); + assertEquals(MAC, IdeaLaunchCommands.detect("Mac OS X")); + assertEquals(LINUX, IdeaLaunchCommands.detect("Linux")); + } +}