Skip to content

Commit cc6354f

Browse files
committed
wip
1 parent 6189be6 commit cc6354f

File tree

8 files changed

+165
-29
lines changed

8 files changed

+165
-29
lines changed

package-lock.json

Lines changed: 65 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
4444
},
4545
"keywords": [],
4646
"dependencies": {
47-
"electron-squirrel-startup": "^1.0.1"
47+
"@xterm/xterm": "^5.5.0",
48+
"electron-squirrel-startup": "^1.0.1",
49+
"node-pty": "^1.1.0-beta30",
50+
"xterm-addon-fit": "^0.8.0"
4851
}
4952
}

src/Ucm/WorkspaceScreen.elm

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
module Ucm.WorkspaceScreen exposing (..)
1+
port module Ucm.WorkspaceScreen exposing (..)
22

33
import Browser
44
import Code.BranchRef as BranchRef
55
import Code.CodebaseTree as CodebaseTree
66
import Code.Config
77
import Html exposing (Html, div, text)
8-
import Html.Attributes exposing (class)
8+
import Html.Attributes exposing (class, id)
9+
import Lib.Util as Util
910
import RemoteData exposing (RemoteData(..))
1011
import UI.AnchoredOverlay as AnchoredOverlay
1112
import UI.Button as Button
@@ -72,6 +73,7 @@ init appContext workspaceContext =
7273
, Cmd.batch
7374
[ Cmd.map CodebaseTreeMsg codebaseTreeCmd
7475
, Cmd.map WorkspacePanesMsg panesCmd
76+
, Util.delayMsg 5000 OpenTerminal
7577
]
7678
)
7779

@@ -88,6 +90,7 @@ type Msg
8890
| ToggleSidebar
8991
| ToggleRightPane
9092
| RefreshCodebase
93+
| OpenTerminal
9194
| Keydown KeyboardEvent.KeyboardEvent
9295
| CodebaseTreeMsg CodebaseTree.Msg
9396
| WorkspacePanesMsg WorkspacePanes.Msg
@@ -104,6 +107,9 @@ type OutMsg
104107
update : AppContext -> Msg -> Model -> ( Model, Cmd Msg, OutMsg )
105108
update appContext msg model =
106109
case msg of
110+
OpenTerminal ->
111+
( model, openTerminal "terminal-pane", None )
112+
107113
CodebaseTreeMsg codebaseTreeMsg ->
108114
let
109115
( codebaseTree, codebaseTreeCmd, outMsg ) =
@@ -388,6 +394,13 @@ update appContext msg model =
388394

389395

390396

397+
-- PORTS
398+
399+
400+
port openTerminal : String -> Cmd msg
401+
402+
403+
391404
-- SUBSCRIPTIONS
392405

393406

@@ -538,7 +551,10 @@ view appContext model =
538551
window_
539552

540553
content =
541-
[ Html.map WorkspacePanesMsg (WorkspacePanes.view model.panes) ]
554+
[ Html.map WorkspacePanesMsg
555+
(WorkspacePanes.view model.panes)
556+
, div [ id "terminal-pane" ] []
557+
]
542558
in
543559
window__
544560
|> Window.withTitlebarLeft (titlebarLeft model)

src/css/ucm/workspace-screen.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,12 @@
6363
color: var(--u-color_icon);
6464
}
6565
}
66+
67+
#terminal-pane {
68+
border-top: 1px solid var(--u-color_border);
69+
position: absolute;
70+
bottom: 0;
71+
left: 0;
72+
right: 0;
73+
height: 300px;
74+
}

src/main.js

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { app, BrowserWindow } from 'electron';
2-
import path from 'node:path';
1+
import { app, BrowserWindow, ipcMain } from 'electron';
32
import started from 'electron-squirrel-startup';
3+
import * as os from 'os';
4+
import * as pty from 'node-pty';
45

56
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
67
if (started) {
@@ -22,13 +23,15 @@ const createWindow = () => {
2223

2324
// and load the index.html of the app.
2425
mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);
26+
27+
return mainWindow;
2528
};
2629

2730
// This method will be called when Electron has finished
2831
// initialization and is ready to create browser windows.
2932
// Some APIs can only be used after this event occurs.
3033
app.whenReady().then(() => {
31-
createWindow();
34+
const mainWindow = createWindow();
3235

3336
// On OS X it's common to re-create a window in the app when the
3437
// dock icon is clicked and there are no other windows open.
@@ -37,6 +40,13 @@ app.whenReady().then(() => {
3740
createWindow();
3841
}
3942
});
43+
44+
try {
45+
initPty(mainWindow);
46+
}
47+
catch (ex) {
48+
console.error(ex);
49+
}
4050
});
4151

4252
// Quit when all windows are closed, except on macOS. There, it's common
@@ -50,3 +60,20 @@ app.on('window-all-closed', () => {
5060

5161
// In this file you can include the rest of your app's specific main process
5262
// code. You can also put them in separate files and import them here.
63+
//
64+
65+
function initPty(mainWindow) {
66+
const shell = os.platform() === 'win32' ? 'powershell.exe' : 'bash';
67+
const ptyProcess = pty.spawn(shell, [], {});
68+
69+
ptyProcess.write('ucm\r');
70+
ptyProcess.write('clear\r');
71+
72+
ptyProcess.on("data", (data) => {
73+
mainWindow.webContents.send("pty-output", data);
74+
});
75+
76+
ipcMain.on("pty-input", (_evt, data) => {
77+
ptyProcess.write(data);
78+
});
79+
}

src/preload.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,13 @@
11
// See the Electron documentation for details on how to use preload scripts:
22
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
3+
//
4+
import { contextBridge, ipcRenderer } from 'electron';
5+
6+
contextBridge.exposeInMainWorld('electronAPI', {
7+
ptyInput: (command) => ipcRenderer.send('pty-input', command),
8+
onPtyOutput: (callback) => {
9+
ipcRenderer.on('pty-output', (_event, value) => {
10+
callback(value);
11+
});
12+
},
13+
})

src/renderer.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import "./main.css";
1515
import * as AppError from "./Ucm/AppError";
1616
import * as AppSettings from "./Ucm/AppSettings";
1717
import * as Theme from "./Ucm/Theme";
18+
import "@xterm/xterm/css/xterm.css";
19+
import { Terminal } from "@xterm/xterm";
20+
import { FitAddon } from 'xterm-addon-fit';
1821

1922
// @ts-ignore
2023
import { Elm } from './Main.elm';
@@ -32,6 +35,21 @@ try {
3235
const appSettings = AppSettings.init();
3336
const operatingSystem = detectOs(window.navigator);
3437

38+
// -- Terminal -----------------------------------------------------------
39+
const terminal = new Terminal({
40+
// fontFamily: "Fira Code var",
41+
theme: {
42+
background: "#18181c" //--color-gray-darken-30
43+
}
44+
});
45+
terminal.onData(data => window.electronAPI.ptyInput(data));
46+
47+
window.electronAPI.onPtyOutput((output) => {
48+
terminal.write(output);
49+
});
50+
const fitAddon = new FitAddon();
51+
terminal.loadAddon(fitAddon);
52+
3553
// -- Elm -------------------------------------------------------------------
3654
const flags = {
3755
operatingSystem: operatingSystem,
@@ -60,6 +78,14 @@ try {
6078
AppSettings.clear();
6179
window.location.reload();
6280
});
81+
82+
app.ports.openTerminal?.subscribe((targetId) => {
83+
const target = document.getElementById(targetId);
84+
if (target) {
85+
terminal.open(target);
86+
fitAddon.fit();
87+
}
88+
});
6389
}
6490

6591
// -- CSS env classes -------------------------------------------------------

webpack.main.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ module.exports = {
88
module: {
99
rules: require('./webpack.rules'),
1010
},
11+
externals: ['node-pty'],
1112
};

0 commit comments

Comments
 (0)