Skip to content

Commit 7fdd6fc

Browse files
committed
Allow changing font and shell
1 parent c471f7d commit 7fdd6fc

File tree

6 files changed

+84
-8
lines changed

6 files changed

+84
-8
lines changed

src-tauri/src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use tauri::Manager;
4444
use tauri_plugin_cli::CliExt;
4545
use tauri_plugin_store::StoreExt;
4646
use templates::create_template;
47-
use terminal::{create_terminal, write_terminal, TermManager};
47+
use terminal::{close_terminal, create_terminal, write_terminal, TermManager};
4848
use tokio::sync::Mutex;
4949
use windows::{has_wsl, install_wsl, is_windows};
5050

@@ -162,6 +162,7 @@ fn main() {
162162
take_screenshot,
163163
create_terminal,
164164
write_terminal,
165+
close_terminal,
165166
])
166167
.run(tauri::generate_context!())
167168
.expect("error while running tauri application");

src-tauri/src/terminal.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,30 @@ impl TermInfo {
4141
pub async fn create_terminal(
4242
window: Window,
4343
term_info: State<'_, TermManager>,
44+
shell: Option<String>,
4445
) -> Result<String, String> {
4546
let (pty, pts) = pty_process::open().map_err(|e| format!("Failed to spawn terminal: {}", e))?;
46-
let mut cmd = pty_process::Command::new("/bin/bash");
47+
let command = match shell {
48+
Some(s) => s,
49+
None => {
50+
#[cfg(target_os = "windows")]
51+
{
52+
String::from("pwsh.exe")
53+
}
54+
#[cfg(not(target_os = "windows"))]
55+
{
56+
std::env::var("SHELL").unwrap_or_else(|_| String::from("sh"))
57+
}
58+
}
59+
};
60+
let cmd = pty_process::Command::new(command);
4761
let child = cmd
4862
.spawn(pts)
4963
.map_err(|e| format!("Failed to spawn shell: {}", e))?;
5064

5165
let (reader, writer) = split(pty);
5266

53-
let (term_id, writer_ref) = {
67+
let (term_id, _) = {
5468
let mut terms = term_info.terminals.write().await;
5569
let term_id = format!("term-{}", terms.len() + 1);
5670
let info = TermInfo::new(writer, child);
@@ -101,3 +115,22 @@ pub async fn write_terminal(
101115
.await
102116
.map_err(|e| format!("Failed to write to terminal: {}", e))
103117
}
118+
119+
#[tauri::command]
120+
pub async fn close_terminal(term_info: State<'_, TermManager>, id: String) -> Result<(), String> {
121+
let child = {
122+
let terms = term_info.terminals.read().await;
123+
terms
124+
.get(&id)
125+
.map(|info| info.child.clone())
126+
.ok_or_else(|| "Terminal ID not found".to_string())?
127+
};
128+
let mut guard = child.lock().await;
129+
if let Some(mut child_proc) = guard.take() {
130+
child_proc
131+
.kill()
132+
.await
133+
.map_err(|e| format!("Failed to kill terminal process: {}", e))?;
134+
}
135+
Ok(())
136+
}

src/components/Tiles/MultiTerminal.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Button, Tab, TabList, TabPanel, Tabs } from "@mui/joy";
44
import TerminalComponent from "./Terminal";
55
import { listen } from "@tauri-apps/api/event";
66
import { Terminal } from "@xterm/xterm";
7+
import { useStore } from "../../utilities/StoreContext";
78

89
declare global {
910
interface Window {
@@ -14,13 +15,16 @@ declare global {
1415
export default function MultiTerminal({}: {}) {
1516
const [terminals, setTerminals] = useState<string[]>([]);
1617
const isListening = useRef<boolean>(false);
18+
const [shell] = useStore<string | null>("terminal/shell", null);
1719

1820
const createTerm = useCallback(async () => {
19-
const id = await invoke<string>("create_terminal");
21+
const id = await invoke<string>("create_terminal", {
22+
shell: shell !== "" ? shell : null,
23+
});
2024
setTerminals((old) => {
2125
return [...old, id];
2226
});
23-
}, []);
27+
}, [shell]);
2428

2529
useEffect(() => {
2630
let unlisten: () => void = () => {};

src/components/Tiles/Terminal.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,39 @@ import { Terminal } from "@xterm/xterm";
22
import { useEffect, useRef } from "react";
33
import "@xterm/xterm/css/xterm.css";
44
import { invoke } from "@tauri-apps/api/core";
5+
import { useStore } from "../../utilities/StoreContext";
56

67
export default ({ id }: { id: string }) => {
78
const elem = useRef<HTMLDivElement>(null);
9+
const termRef = useRef<Terminal>();
10+
const [font] = useStore<string | null>("terminal/font-family", null);
811

912
useEffect(() => {
1013
if (!elem.current) return;
1114
if (!window.terminals) window.terminals = {};
1215

13-
const term = new Terminal();
16+
const term = new Terminal({
17+
fontFamily: font !== "" ? font || undefined : undefined,
18+
});
1419
window.terminals[id] = term;
1520
term.open(elem.current);
1621
term.onData(async (data) => {
17-
console.log(await invoke("write_terminal", { id: id, data: data }));
22+
await invoke("write_terminal", { id: id, data: data });
1823
});
24+
termRef.current = term;
1925

2026
return () => {
2127
term.dispose();
2228
};
2329
}, [id]);
2430

31+
useEffect(() => {
32+
if (termRef.current) {
33+
termRef.current.options.fontFamily =
34+
font !== "" ? font || undefined : undefined;
35+
termRef.current.refresh(0, termRef.current.rows - 1);
36+
}
37+
}, [font]);
38+
2539
return <div ref={elem}></div>;
2640
};

src/preferences/pages/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ import { appIdsPage } from "./appIds";
99
import { developerPage } from "./developer";
1010
import { swiftPage } from "./swift";
1111
import { sourceKitPage } from "./sourcekit";
12+
import { terminalPage } from "./terminal";
1213

1314
const generalCategory: PreferenceCategory = {
1415
id: "general",
1516
name: "General",
16-
pages: [generalPage, appearancePage],
17+
pages: [generalPage, appearancePage, terminalPage],
1718
};
1819

1920
const appleCategory: PreferenceCategory = {

src/preferences/pages/terminal.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { createItems, createPreferencePage } from "../helpers";
2+
3+
export const terminalPage = createPreferencePage(
4+
"terminal",
5+
"Terminal",
6+
[
7+
createItems.text(
8+
"shell",
9+
"Default Shell",
10+
"The shell to use (e.x /bin/bash). If unset, defaults to $SHELL on linux/macOS and pwsh.exe on Windows."
11+
),
12+
createItems.text(
13+
"font-family",
14+
"Font Family",
15+
"Recommended to use a monospace font (e.x. monospace)",
16+
"monospace"
17+
),
18+
],
19+
{
20+
description: "Configure the integrated terminal",
21+
category: "general",
22+
}
23+
);

0 commit comments

Comments
 (0)