Skip to content

Instantly share code, notes, and snippets.

@mmkathurima
Last active February 5, 2023 10:14
Show Gist options
  • Save mmkathurima/d5c4f3791dc487892656db94ea8c05fe to your computer and use it in GitHub Desktop.
Save mmkathurima/d5c4f3791dc487892656db94ea8c05fe to your computer and use it in GitHub Desktop.
Basic shell control created using JavaFX. Can be embedded into Swing and JavaFX applications. Emulates a command line UI. To process commands, use the `onEnter` functional interface.
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyEvent;
import java.util.ArrayList;
import java.util.function.Consumer;
public class ShellControl extends TextArea {
private String prompt = ">>>";
private String input;
private int caretPos, histIndex = 0;
public Consumer<ShellControl> onEnter;
private ArrayList<String> history;
public String getPrompt() {
return this.prompt + " ";
}
public void setPrompt(String prompt) {
this.setText(this.getText().replace(this.prompt, prompt));
this.prompt = prompt;
}
public String getInput() {
return this.input;
}
private void setInput(String input) {
this.input = input;
}
public void print(String text) {
this.appendText("\n" + text);
}
public void println(String text) {
this.appendText(String.format("\n%s\n", text));
}
public void println() {
this.appendText("\n");
}
public void printf(String format, Object... args) {
this.appendText(String.format("\n" + format, args));
}
private int getLongLastPos() {
return this.getText().lastIndexOf(this.getPrompt()) + this.getPrompt().length();
}
public ArrayList<String> getHistory() {
return this.history;
}
public ShellControl() {
history = new ArrayList<>();
this.setText(this.getPrompt());
this.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
caretPos = getCaretPosition();
int pos = oldValue.lastIndexOf(getPrompt()) + getPrompt().length() + 1;
if (caretPos < pos && oldValue.length() > newValue.length()) {
setText(oldValue);
positionCaret(caretPos);
}
}
});
this.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case ENTER:
event.consume();
setInput(getText().substring(getLongLastPos()));
if (getInput().equals("cls") | getInput().equals("clear"))
clear();
else
onEnter.accept(ShellControl.this);
appendText(getPrompt());
caretPos = getCaretPosition();
history.add(getInput());
histIndex++;
break;
case UP:
event.consume();
if (!history.isEmpty() & histIndex > 0)
replaceText(getLongLastPos(), getText().length(), history.get(--histIndex));
break;
case DOWN:
event.consume();
if (!history.isEmpty() & histIndex < history.size())
replaceText(getLongLastPos(), getText().length(), history.get(++histIndex));
break;
case RIGHT:
if (!history.isEmpty() && getText().substring(getLongLastPos()).isEmpty()) {
event.consume();
replaceText(getLongLastPos(), getText().length(), history.get(history.size() - 1));
}
break;
}
}
});
this.positionCaret(getLongLastPos());
}
}
package shellcontrol;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javax.swing.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ShellTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JFXPanel panel = new JFXPanel();
frame.add(panel);
Platform.runLater(() -> {
ShellControl control = new ShellControl();
/*control.setStyle("-fx-control-inner-background: black; -fx-text-fill: white");
control.setFont(new Font("Consolas", control.getFont().getSize() + 3));
control.setPrompt("4ZVla =>> ");*/
control.requestFocus();
/*control.onEnter = (ShellControl c) -> {
try {
//c.printf("%s\n", c.getInput());
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", c.getInput());
builder.redirectErrorStream(true);
Process process = builder.start();
new BufferedReader(new InputStreamReader(process.getInputStream())).lines().forEach(c::print);
c.println();
} catch (IOException e) {
c.printf("ERROR: %s\n", e.toString());
}
};*/
control.onEnter = c -> c.println(c.getInput());
Scene scene = new Scene(control);
panel.setScene(scene);
});
frame.setSize(500, 500);
frame.setVisible(true);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment