66import java .io .File ;
77import java .io .IOException ;
88import java .nio .charset .StandardCharsets ;
9+ import java .nio .file .Files ;
910import java .nio .file .Paths ;
10- import java .util .ArrayList ;
11- import java .util .Collections ;
12- import java .util .List ;
1311import java .util .concurrent .Executor ;
1412import java .util .concurrent .Executors ;
13+ import java .util .stream .Collectors ;
1514
1615import org .apache .commons .io .IOUtils ;
17- import org .apache .commons .lang3 .StringUtils ;
1816import org .apache .commons .lang3 .SystemUtils ;
1917import org .fxmisc .flowless .VirtualizedScrollPane ;
2018import org .fxmisc .wellbehaved .event .EventPattern ;
@@ -45,8 +43,23 @@ public class SimpleTerminalPane extends BorderPane implements ToolbarOwner, Inpu
4543 private final Executor commandExecutor = Executors .newSingleThreadExecutor ();
4644
4745 public SimpleTerminalPane () {
46+ this (SystemUtils .USER_HOME );
47+ }
48+
49+ public SimpleTerminalPane (String initialDirectory ) {
50+
51+ if (initialDirectory != null && !initialDirectory .isBlank ()) {
52+ this .currentDirectory = Paths .get (initialDirectory )
53+ .toAbsolutePath ()
54+ .normalize ()
55+ .toString ();
56+ } else {
57+ this .currentDirectory = SystemUtils .USER_HOME ;
58+ }
59+
4860 commandLineField .setPromptText ("Enter command here..." );
4961 setCommandLineFieldAction ();
62+
5063 historyArea .setEditable (false );
5164 historyArea .setFocusTraversable (false );
5265 historyArea .prefWidthProperty ().bind (this .widthProperty ());
@@ -71,71 +84,98 @@ private void setCommandLineFieldAction() {
7184
7285 private void executeCommand () {
7386 commandExecutor .execute (() -> {
87+ String command = commandLineField .getText ().trim ();
88+
7489 try {
75- var arguments = createProcessArguments ();
76- var processBuilder = new ProcessBuilder (arguments );
77- processBuilder .directory (new File (currentDirectory ));
78- var process = processBuilder .start ();
79- var output = IOUtils .toString (process .getInputStream (), StandardCharsets .UTF_8 );
80- var error = IOUtils .toString (process .getErrorStream (), StandardCharsets .UTF_8 );
81-
82- if (!output .isEmpty ()) {
83- Platform .runLater (() -> historyArea .appendText (output ));
84- }
85- if (!error .isEmpty ()) {
86- Platform .runLater (() -> historyArea .appendText (error ));
87- }
8890
89- var processSucceeded = process .exitValue () == 0 ;
90- var isCdCommand = List .of (arguments ).contains ("cd" );
91+ // Handle cd internally (cannot be done via ProcessBuilder)
92+ if (command .startsWith ("cd" )) {
93+
94+ var parts = command .split ("\\ s+" , 2 );
95+ var newDirectory = parts .length > 1 ? parts [1 ] : SystemUtils .USER_HOME ;
96+
97+ if (newDirectory .startsWith ("~" )) {
98+ newDirectory = newDirectory .replace ("~" , SystemUtils .USER_HOME );
99+ }
91100
92- if (processSucceeded && isCdCommand ) {
93- var newDirectory = arguments [3 ];
101+ var newPath = Paths .get (newDirectory );
94102
95- var goToHomeDirectory = newDirectory .startsWith ("~" );
96- if (goToHomeDirectory ) {
97- newDirectory = StringUtils .replace (newDirectory , "~" , SystemUtils .USER_HOME );
103+ if (!newPath .isAbsolute ()) {
104+ newPath = Paths .get (currentDirectory ).resolve (newPath );
98105 }
99- if (!goToHomeDirectory && !newDirectory .startsWith ("/" )) {
100- newDirectory = "/" + newDirectory ;
106+
107+ newPath = newPath .normalize ().toAbsolutePath ();
108+
109+ if (Files .exists (newPath ) && Files .isDirectory (newPath )) {
110+ currentDirectory = newPath .toString ();
111+ var finalDir = currentDirectory ;
112+
113+ Platform .runLater (() ->
114+ historyArea .appendText ("Directory changed to: " + finalDir + "\n " ));
115+ } else {
116+ var finalNewDirectory = newDirectory ;
117+ Platform .runLater (() ->
118+ historyArea .appendText ("Directory not found: " + finalNewDirectory + "\n " ));
101119 }
102- if (!goToHomeDirectory ) {
103- newDirectory = this .currentDirectory + newDirectory ;
120+
121+ } else {
122+
123+ var arguments = createProcessArguments ();
124+
125+ var processBuilder = new ProcessBuilder (arguments );
126+ processBuilder .directory (new File (currentDirectory ));
127+
128+ var process = processBuilder .start ();
129+
130+ var output = IOUtils .toString (process .getInputStream (), StandardCharsets .UTF_8 )
131+ .replaceAll ("\\ u001B\\ [[;\\ d]*[ -/]*[@-~]" , "" );
132+ var error = IOUtils .toString (process .getErrorStream (), StandardCharsets .UTF_8 )
133+ .lines ()
134+ .map (line -> "[ERROR] " + line )
135+ .collect (Collectors .joining (System .lineSeparator ()));
136+
137+ process .waitFor ();
138+
139+ if (!output .isEmpty ()) {
140+ Platform .runLater (() -> historyArea .appendText (output ));
104141 }
105- // set normalized path without '.', '..'
106- this .currentDirectory = Paths .get (new File (newDirectory ).getAbsolutePath ()).normalize ().toAbsolutePath ().toString ();
107142
108- Platform .runLater (() -> historyArea .appendText ("Directory changed to: " + this .currentDirectory + "\n " ));
143+ if (!error .isEmpty ()) {
144+ Platform .runLater (() -> historyArea .appendText (error ));
145+ }
109146 }
110- } catch (IOException e ) {
147+
148+ } catch (IOException | InterruptedException e ) {
111149 DialogFactory .createErrorDialog (e );
112150 } finally {
113151 Platform .runLater (() -> {
114152 historyListView .getItems ().add (commandLineField .getText ());
115153 commandLineField .clear ();
116- historyArea .appendText (this . currentDirectory + "\n " );
154+ historyArea .appendText (currentDirectory + "\n " );
117155 historyArea .requestFollowCaret ();
118156 commandLineField .setDisable (false );
119157 commandLineField .requestFocus ();
120158 });
121159 }
122160 });
123161 }
162+
124163 private String [] createProcessArguments () {
125164 var isWindows = SystemUtils .OS_NAME .toLowerCase ().contains ("windows" );
126- var arguments = new ArrayList < String >();
165+
127166 if (isWindows ) {
128- arguments .add ("C:\\ Windows\\ System32\\ WindowsPowerShell\\ v1.0\\ powershell.exe" );
129- arguments .add ("-Command" );
167+ return new String [] {
168+ "C:\\ Windows\\ System32\\ WindowsPowerShell\\ v1.0\\ powershell.exe" ,
169+ "-Command" ,
170+ commandLineField .getText ()
171+ };
130172 } else {
131- arguments .add ("/bin/bash" );
132- arguments .add ("-c" );
173+ return new String [] {
174+ "/bin/bash" ,
175+ "-c" ,
176+ commandLineField .getText ()
177+ };
133178 }
134- var split = commandLineField .getText ().split (" " );
135- Collections .addAll (arguments , split );
136-
137- var resultArray = new String [arguments .size ()];
138- return arguments .toArray (resultArray );
139179 }
140180
141181 @ Override
0 commit comments