Content-Length: 4718 | pFad | http://github.com/coder/coder/pull/19021.patch
thub.com
From 963f4d05ab2bd504141179eb9dd99b72d04257a1 Mon Sep 17 00:00:00 2001
From: Asher
Date: Wed, 23 Jul 2025 15:39:26 -0800
Subject: [PATCH 1/2] feat: support shift+enter in terminal
It acts the same alt+enter, but is more familiar to users.
---
.../pages/TerminalPage/TerminalPage.test.tsx | 18 ++++++++++++++++++
site/src/pages/TerminalPage/TerminalPage.tsx | 19 +++++++++++++++++++
2 files changed, 37 insertions(+)
diff --git a/site/src/pages/TerminalPage/TerminalPage.test.tsx b/site/src/pages/TerminalPage/TerminalPage.test.tsx
index 4591190ad9904..7530a45914a85 100644
--- a/site/src/pages/TerminalPage/TerminalPage.test.tsx
+++ b/site/src/pages/TerminalPage/TerminalPage.test.tsx
@@ -1,5 +1,6 @@
import "jest-canvas-mock";
import { waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
import { API } from "api/api";
import WS from "jest-websocket-mock";
import { http, HttpResponse } from "msw";
@@ -148,4 +149,21 @@ describe("TerminalPage", () => {
ws.send(text);
await expectTerminalText(container, text);
});
+
+ it("supports shift+enter", async () => {
+ const ws = new WS(
+ `ws://localhost/api/v2/workspaceagents/${MockWorkspaceAgent.id}/pty`,
+ );
+
+ const { container } = await renderTerminal();
+ // Ideally we could use ws.connected but that seems to pause React updates.
+ // For now, wait for the initial resize message instead.
+ await ws.nextMessage;
+
+ const msg = ws.nextMessage;
+ const terminal = container.getElementsByClassName("xterm");
+ await userEvent.type(terminal[0], "{Shift>}{Enter}{/Shift}");
+ const req = JSON.parse(new TextDecoder().decode((await msg) as Uint8Array));
+ expect(req.data).toBe("\x1b\r");
+ });
});
diff --git a/site/src/pages/TerminalPage/TerminalPage.tsx b/site/src/pages/TerminalPage/TerminalPage.tsx
index 5c13e89c30005..6b9bfb4a695d0 100644
--- a/site/src/pages/TerminalPage/TerminalPage.tsx
+++ b/site/src/pages/TerminalPage/TerminalPage.tsx
@@ -148,6 +148,22 @@ const TerminalPage: FC = () => {
}),
);
+ // Make shift+enter send ^[^M (escaped carriage return). Applications
+ // typically take this to mean to insert a literal newline. There is no way
+ // to remove this handler, so we must attach it once and rely on a ref to
+ // send it to the current socket.
+ terminal.attachCustomKeyEventHandler((ev) => {
+ if (ev.shiftKey && ev.key === "Enter") {
+ if (ev.type === "keydown") {
+ websocketRef.current?.send(
+ new TextEncoder().encode(JSON.stringify({ data: "\x1b\r" })),
+ );
+ }
+ return false;
+ }
+ return true;
+ });
+
terminal.open(terminalWrapperRef.current);
// We have to fit twice here. It's unknown why, but the first fit will
@@ -190,6 +206,7 @@ const TerminalPage: FC = () => {
}, [navigate, reconnectionToken, searchParams]);
// Hook up the terminal through a web socket.
+ const websocketRef = useRef();
useEffect(() => {
if (!terminal) {
return;
@@ -270,6 +287,7 @@ const TerminalPage: FC = () => {
.withBackoff(new ExponentialBackoff(1000, 6))
.build();
websocket.binaryType = "arraybuffer";
+ websocketRef.current = websocket;
websocket.addEventListener(WebsocketEvent.open, () => {
// Now that we are connected, allow user input.
terminal.options = {
@@ -333,6 +351,7 @@ const TerminalPage: FC = () => {
d.dispose();
}
websocket?.close(1000);
+ websocketRef.current = undefined;
};
}, [
command,
From 77d94ae103802d024dc4f6992888709ec93c3d95 Mon Sep 17 00:00:00 2001
From: Asher
Date: Thu, 24 Jul 2025 11:41:05 -0800
Subject: [PATCH 2/2] Name the escaped carriage return
---
site/src/pages/TerminalPage/TerminalPage.tsx | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/site/src/pages/TerminalPage/TerminalPage.tsx b/site/src/pages/TerminalPage/TerminalPage.tsx
index 6b9bfb4a695d0..14fe872be1e05 100644
--- a/site/src/pages/TerminalPage/TerminalPage.tsx
+++ b/site/src/pages/TerminalPage/TerminalPage.tsx
@@ -152,11 +152,12 @@ const TerminalPage: FC = () => {
// typically take this to mean to insert a literal newline. There is no way
// to remove this handler, so we must attach it once and rely on a ref to
// send it to the current socket.
+ const escapedCarriageReturn = "\x1b\r";
terminal.attachCustomKeyEventHandler((ev) => {
if (ev.shiftKey && ev.key === "Enter") {
if (ev.type === "keydown") {
websocketRef.current?.send(
- new TextEncoder().encode(JSON.stringify({ data: "\x1b\r" })),
+ new TextEncoder().encode(JSON.stringify({ data: escapedCarriageReturn })),
);
}
return false;
--- a PPN by Garber Painting Akron. With Image Size Reduction included!Fetched URL: http://github.com/coder/coder/pull/19021.patch
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy