mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-11-11 00:30:57 +00:00
Add the Global history clear-all action with confirmation and five-language copy. Clear local shell history, autocomplete and compose recall while preserving drafts, keeping peer windows consistent on clears, and allowing new commands afterwards. Verified with 116 focused checks, two clean independent final reviews, real Electron multi-window SSH-fixture interaction and restart, current-head Codex review, and both required CI jobs. Co-authored-by: fyhax1ki <fyhax1ki@gmail.com>
64 lines
2.4 KiB
TypeScript
64 lines
2.4 KiB
TypeScript
import { useCallback, useEffect, useLayoutEffect, useRef } from 'react';
|
|
import { navigateComposeBarHistory, type ComposeBarHistoryDirection } from '../../domain/composeBarHistory';
|
|
import {
|
|
getComposeBarHistory,
|
|
createComposeBarHistoryRecorder,
|
|
subscribeComposeBarHistoryCleared,
|
|
} from './composeBarHistoryStore';
|
|
|
|
export function useComposeBarHistory(sessionId: string, restoreDraft?: (draft: string) => void) {
|
|
const cursor = useRef<{ index: number; draft: string; entries?: readonly string[] }>({ index: Infinity, draft: '' });
|
|
|
|
const reset = useCallback(() => {
|
|
cursor.current = { index: Infinity, draft: '' };
|
|
}, []);
|
|
|
|
// Keep the existing textarea draft when workspace focus changes, but begin
|
|
// a fresh history walk in the newly focused session.
|
|
useLayoutEffect(() => {
|
|
if (cursor.current.entries) restoreDraft?.(cursor.current.draft);
|
|
reset();
|
|
}, [reset, restoreDraft, sessionId]);
|
|
|
|
/**
|
|
* Restore the pre-walk draft and drop the cached history walk.
|
|
*
|
|
* While the user is in an ArrowUp walk the textarea shows the recalled
|
|
* command, so resetting the cursor alone would leave a deleted command ready
|
|
* for Enter. Put the saved draft back first, exactly like the session-change
|
|
* path above.
|
|
*/
|
|
const handleHistoryCleared = useCallback(() => {
|
|
if (cursor.current.entries) restoreDraft?.(cursor.current.draft);
|
|
reset();
|
|
}, [reset, restoreDraft]);
|
|
|
|
useEffect(
|
|
() => subscribeComposeBarHistoryCleared(handleHistoryCleared),
|
|
[handleHistoryCleared],
|
|
);
|
|
|
|
const prepareRecord = useCallback(() => createComposeBarHistoryRecorder(sessionId), [sessionId]);
|
|
|
|
const navigate = useCallback((currentValue: string, direction: ComposeBarHistoryDirection) => {
|
|
// A late send can evict old entries. Keep one walk stable until the user
|
|
// returns to the draft or edits, then pick up the latest history.
|
|
const entries = cursor.current.entries ?? getComposeBarHistory(sessionId);
|
|
const result = navigateComposeBarHistory({
|
|
...cursor.current,
|
|
entries,
|
|
currentValue,
|
|
}, direction);
|
|
if (result) {
|
|
cursor.current = {
|
|
index: result.index === entries.length ? Infinity : result.index,
|
|
draft: result.draft,
|
|
entries: result.index === entries.length ? undefined : entries,
|
|
};
|
|
}
|
|
return result?.value;
|
|
}, [sessionId]);
|
|
|
|
return { prepareRecord, navigate, reset };
|
|
}
|