fix: fixing the exit message service to use constants
- Avoiding mouse events for exit messages on terminal on stop process
This commit is contained in:
34
src/constants/exit-message.ts
Normal file
34
src/constants/exit-message.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Exit message constants for the post-exit banner
|
||||
*
|
||||
* Displayed after the TUI exits to show session info
|
||||
* and the resume command.
|
||||
*/
|
||||
|
||||
/** Small block art logo (3 rows) used as visual marker */
|
||||
export const EXIT_LOGO = [
|
||||
"█▀▀█",
|
||||
"█ █",
|
||||
"▀▀▀▀",
|
||||
] as const;
|
||||
|
||||
/** ANSI style codes for exit message */
|
||||
export const EXIT_STYLES = {
|
||||
RESET: "\x1b[0m",
|
||||
DIM: "\x1b[90m",
|
||||
HIGHLIGHT: "\x1b[96m",
|
||||
BOLD: "\x1b[1m",
|
||||
LOGO_COLOR: "\x1b[36m",
|
||||
} as const;
|
||||
|
||||
/** Maximum width for the session description before truncation */
|
||||
export const EXIT_DESCRIPTION_MAX_WIDTH = 50;
|
||||
|
||||
/** Padding before each exit message line */
|
||||
export const EXIT_LINE_PADDING = " ";
|
||||
|
||||
/** Gap between logo and text */
|
||||
export const EXIT_LOGO_GAP = " ";
|
||||
|
||||
/** Truncation indicator */
|
||||
export const EXIT_TRUNCATION_MARKER = "\u2026";
|
||||
@@ -15,6 +15,7 @@ export interface TuiInput {
|
||||
export interface TuiOutput {
|
||||
exitCode: number;
|
||||
sessionId?: string;
|
||||
sessionTitle?: string;
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
|
||||
50
src/services/exit-message.ts
Normal file
50
src/services/exit-message.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Exit message formatter
|
||||
*
|
||||
* Formats the post-exit banner shown after the TUI closes,
|
||||
* displaying session info and the resume command.
|
||||
*/
|
||||
|
||||
import { EOL } from "os";
|
||||
import {
|
||||
EXIT_LOGO,
|
||||
EXIT_STYLES,
|
||||
EXIT_DESCRIPTION_MAX_WIDTH,
|
||||
EXIT_LINE_PADDING,
|
||||
EXIT_LOGO_GAP,
|
||||
EXIT_TRUNCATION_MARKER,
|
||||
} from "@constants/exit-message";
|
||||
|
||||
/** Truncate text to a max width, appending ellipsis if needed */
|
||||
const truncateText = (text: string, maxWidth: number): string => {
|
||||
if (text.length <= maxWidth) return text;
|
||||
return text.slice(0, maxWidth - 1) + EXIT_TRUNCATION_MARKER;
|
||||
};
|
||||
|
||||
/** Format the exit banner with session info */
|
||||
export const formatExitMessage = (
|
||||
sessionId?: string,
|
||||
sessionTitle?: string,
|
||||
): string => {
|
||||
if (!sessionId) return "";
|
||||
|
||||
const { RESET, DIM, HIGHLIGHT, LOGO_COLOR } = EXIT_STYLES;
|
||||
const pad = EXIT_LINE_PADDING;
|
||||
const gap = EXIT_LOGO_GAP;
|
||||
|
||||
const description = sessionTitle
|
||||
? truncateText(sessionTitle, EXIT_DESCRIPTION_MAX_WIDTH)
|
||||
: "";
|
||||
|
||||
const resumeCommand = `codetyper --resume ${sessionId}`;
|
||||
|
||||
const lines: string[] = [
|
||||
"",
|
||||
`${pad}${LOGO_COLOR}${EXIT_LOGO[0]}${RESET}${gap}${HIGHLIGHT}${description}${RESET}`,
|
||||
`${pad}${LOGO_COLOR}${EXIT_LOGO[1]}${RESET}${gap}${DIM}${resumeCommand}${RESET}`,
|
||||
`${pad}${LOGO_COLOR}${EXIT_LOGO[2]}${RESET}`,
|
||||
"",
|
||||
];
|
||||
|
||||
return lines.join(EOL);
|
||||
};
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
getExecutionState,
|
||||
} from "@services/chat-tui-service";
|
||||
import { TERMINAL_RESET } from "@constants/terminal";
|
||||
import { formatExitMessage } from "@services/exit-message";
|
||||
import { copyToClipboard } from "@services/clipboard/text-clipboard";
|
||||
import versionData from "@/version.json";
|
||||
import { ExitProvider, useExit } from "@tui-solid/context/exit";
|
||||
@@ -25,6 +26,7 @@ import {
|
||||
AppStoreProvider,
|
||||
useAppStore,
|
||||
setAppStoreRef,
|
||||
appStore,
|
||||
} from "@tui-solid/context/app";
|
||||
import { ThemeProvider, useTheme } from "@tui-solid/context/theme";
|
||||
import { KeybindProvider } from "@tui-solid/context/keybind";
|
||||
@@ -111,6 +113,7 @@ function AppContent(props: AppProps) {
|
||||
const toast = useToast();
|
||||
const theme = useTheme();
|
||||
const renderer = useRenderer();
|
||||
renderer.disableStdoutInterception();
|
||||
const [fileList, setFileList] = createSignal<string[]>([]);
|
||||
|
||||
setAppStoreRef(app);
|
||||
@@ -561,6 +564,16 @@ export function tui(options: TuiRenderOptions): Promise<TuiOutput> {
|
||||
const handleExit = (output: TuiOutput): void => {
|
||||
try {
|
||||
writeSync(1, TERMINAL_RESET);
|
||||
|
||||
const state = appStore.getState();
|
||||
const firstUserLog = state?.logs?.find(
|
||||
(log: { type: string }) => log.type === "user",
|
||||
);
|
||||
const sessionTitle = firstUserLog?.content;
|
||||
const exitMsg = formatExitMessage(output.sessionId, sessionTitle);
|
||||
if (exitMsg) {
|
||||
writeSync(1, exitMsg);
|
||||
}
|
||||
} catch {
|
||||
// Ignore - stdout may already be closed
|
||||
}
|
||||
@@ -571,7 +584,6 @@ export function tui(options: TuiRenderOptions): Promise<TuiOutput> {
|
||||
targetFps: 60,
|
||||
exitOnCtrlC: false,
|
||||
useKittyKeyboard: {},
|
||||
useMouse: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user