mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-02-10 00:41:25 +01:00
Rudimentary terminal search
This commit is contained in:
parent
cb2cd72cd4
commit
5a90debb2e
@ -3,6 +3,7 @@
|
||||
|
||||
import { Block, SubBlock } from "@/app/block/block";
|
||||
import { BlockNodeModel } from "@/app/block/blocktypes";
|
||||
import { Search, useSearch } from "@/app/element/search";
|
||||
import { getAllGlobalKeyBindings } from "@/app/store/keymodel";
|
||||
import { waveEventSubscribe } from "@/app/store/wps";
|
||||
import { RpcApi } from "@/app/store/wshclientapi";
|
||||
@ -24,7 +25,7 @@ import {
|
||||
} from "@/store/global";
|
||||
import * as services from "@/store/services";
|
||||
import * as keyutil from "@/util/keyutil";
|
||||
import { boundNumber } from "@/util/util";
|
||||
import { boundNumber, fireAndForget } from "@/util/util";
|
||||
import clsx from "clsx";
|
||||
import debug from "debug";
|
||||
import * as jotai from "jotai";
|
||||
@ -71,6 +72,7 @@ class TermViewModel implements ViewModel {
|
||||
shellProcStatusUnsubFn: () => void;
|
||||
isCmdController: jotai.Atom<boolean>;
|
||||
isRestarting: jotai.PrimitiveAtom<boolean>;
|
||||
searchAtoms?: SearchAtoms;
|
||||
|
||||
constructor(blockId: string, nodeModel: BlockNodeModel) {
|
||||
this.viewType = "term";
|
||||
@ -785,6 +787,22 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
||||
const fullConfig = globalStore.get(atoms.fullConfigAtom);
|
||||
const connFontFamily = fullConfig.connections?.[blockData?.meta?.connection]?.["term:fontfamily"];
|
||||
|
||||
const searchProps = useSearch(viewRef, model);
|
||||
const searchVal = jotai.useAtomValue<string>(searchProps.searchAtom);
|
||||
searchProps.onSearch = React.useCallback((searchText: string) => {
|
||||
if (searchText == "") {
|
||||
model.termRef.current?.searchAddon.clearDecorations();
|
||||
return;
|
||||
}
|
||||
model.termRef.current?.searchAddon.findNext(searchText);
|
||||
}, []);
|
||||
searchProps.onPrev = React.useCallback(() => {
|
||||
model.termRef.current?.searchAddon.findPrevious(searchVal);
|
||||
}, [searchVal]);
|
||||
searchProps.onNext = React.useCallback(() => {
|
||||
model.termRef.current?.searchAddon.findNext(searchVal);
|
||||
}, [searchVal]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const fullConfig = globalStore.get(atoms.fullConfigAtom);
|
||||
const termThemeName = globalStore.get(model.termThemeNameAtom);
|
||||
@ -822,13 +840,18 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
||||
useWebGl: !termSettings?.["term:disablewebgl"],
|
||||
}
|
||||
);
|
||||
termWrap.onSearchResultsDidChange = (results) => {
|
||||
console.log("search results", results);
|
||||
globalStore.set(searchProps.numResultsAtom, results.resultCount);
|
||||
globalStore.set(searchProps.indexAtom, results.resultIndex);
|
||||
};
|
||||
(window as any).term = termWrap;
|
||||
model.termRef.current = termWrap;
|
||||
const rszObs = new ResizeObserver(() => {
|
||||
termWrap.handleResize_debounced();
|
||||
});
|
||||
rszObs.observe(connectElemRef.current);
|
||||
termWrap.initTerminal();
|
||||
fireAndForget(termWrap.initTerminal.bind(termWrap));
|
||||
if (wasFocused) {
|
||||
setTimeout(() => {
|
||||
model.giveFocus();
|
||||
@ -867,6 +890,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
||||
cols: model.termRef.current?.terminal.cols ?? 80,
|
||||
blockId: blockId,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={clsx("view-term", "term-mode-" + termMode)} ref={viewRef}>
|
||||
<TermResyncHandler blockId={blockId} model={model} />
|
||||
@ -882,6 +906,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
||||
onPointerOver={onScrollbarHideObserver}
|
||||
/>
|
||||
</div>
|
||||
<Search {...searchProps} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ import { PLATFORM, WOS, atoms, fetchWaveFile, getSettingsKeyAtom, globalStore, o
|
||||
import * as services from "@/store/services";
|
||||
import * as util from "@/util/util";
|
||||
import { base64ToArray, fireAndForget } from "@/util/util";
|
||||
import { SearchAddon } from "@xterm/addon-search";
|
||||
import { SerializeAddon } from "@xterm/addon-serialize";
|
||||
import { WebLinksAddon } from "@xterm/addon-web-links";
|
||||
import { WebglAddon } from "@xterm/addon-webgl";
|
||||
@ -50,12 +51,14 @@ export class TermWrap {
|
||||
terminal: Terminal;
|
||||
connectElem: HTMLDivElement;
|
||||
fitAddon: FitAddon;
|
||||
searchAddon: SearchAddon;
|
||||
serializeAddon: SerializeAddon;
|
||||
mainFileSubject: SubjectWithRef<WSFileEventData>;
|
||||
loaded: boolean;
|
||||
heldData: Uint8Array[];
|
||||
handleResize_debounced: () => void;
|
||||
hasResized: boolean;
|
||||
onSearchResultsDidChange?: (result: { resultIndex: number; resultCount: number }) => void;
|
||||
|
||||
constructor(
|
||||
blockId: string,
|
||||
@ -72,6 +75,8 @@ export class TermWrap {
|
||||
this.fitAddon = new FitAddon();
|
||||
this.fitAddon.noScrollbar = PLATFORM == "darwin";
|
||||
this.serializeAddon = new SerializeAddon();
|
||||
this.searchAddon = new SearchAddon();
|
||||
this.terminal.loadAddon(this.searchAddon);
|
||||
this.terminal.loadAddon(this.fitAddon);
|
||||
this.terminal.loadAddon(this.serializeAddon);
|
||||
this.terminal.loadAddon(
|
||||
@ -149,6 +154,8 @@ export class TermWrap {
|
||||
}
|
||||
})
|
||||
);
|
||||
if (this.onSearchResultsDidChange)
|
||||
this.searchAddon.onDidChangeResults(this.onSearchResultsDidChange.bind(this));
|
||||
this.mainFileSubject = getFileSubject(this.blockId, TermFileName);
|
||||
this.mainFileSubject.subscribe(this.handleNewFileSubjectData.bind(this));
|
||||
try {
|
||||
@ -299,4 +306,8 @@ export class TermWrap {
|
||||
});
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
search(search: string) {
|
||||
this.searchAddon.findNext(search);
|
||||
}
|
||||
}
|
||||
|
@ -552,7 +552,7 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => {
|
||||
const searchVal = useAtomValue<string>(searchProps.searchAtom);
|
||||
const setSearchIndex = useSetAtom(searchProps.indexAtom);
|
||||
const setNumSearchResults = useSetAtom(searchProps.numResultsAtom);
|
||||
const onSearch = useCallback((search: string) => {
|
||||
searchProps.onSearch = useCallback((search: string) => {
|
||||
try {
|
||||
if (search) {
|
||||
model.webviewRef.current?.findInPage(search, { findNext: true });
|
||||
@ -563,7 +563,7 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => {
|
||||
console.error("Failed to search", e);
|
||||
}
|
||||
}, []);
|
||||
const onSearchNext = useCallback(() => {
|
||||
searchProps.onNext = useCallback(() => {
|
||||
try {
|
||||
console.log("search next", searchVal);
|
||||
model.webviewRef.current?.findInPage(searchVal, { findNext: false, forward: true });
|
||||
@ -571,7 +571,7 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => {
|
||||
console.error("Failed to search next", e);
|
||||
}
|
||||
}, [searchVal]);
|
||||
const onSearchPrev = useCallback(() => {
|
||||
searchProps.onPrev = useCallback(() => {
|
||||
try {
|
||||
console.log("search prev", searchVal);
|
||||
model.webviewRef.current?.findInPage(searchVal, { findNext: false, forward: false });
|
||||
@ -760,7 +760,7 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => {
|
||||
<div>{errorText}</div>
|
||||
</div>
|
||||
)}
|
||||
<Search {...searchProps} onSearch={onSearch} onNext={onSearchNext} onPrev={onSearchPrev} />
|
||||
<Search {...searchProps} />
|
||||
</Fragment>
|
||||
);
|
||||
});
|
||||
|
@ -93,6 +93,7 @@
|
||||
"@table-nav/react": "^0.0.7",
|
||||
"@tanstack/react-table": "^8.20.5",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/addon-search": "^0.15.0",
|
||||
"@xterm/addon-serialize": "^0.13.0",
|
||||
"@xterm/addon-web-links": "^0.11.0",
|
||||
"@xterm/addon-webgl": "^0.18.0",
|
||||
|
10
yarn.lock
10
yarn.lock
@ -7314,6 +7314,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@xterm/addon-search@npm:^0.15.0":
|
||||
version: 0.15.0
|
||||
resolution: "@xterm/addon-search@npm:0.15.0"
|
||||
peerDependencies:
|
||||
"@xterm/xterm": ^5.0.0
|
||||
checksum: 10c0/2d68233d234eabc9ffe1bc9e4fcd28cd50c1f8c316b0e71a81ee2005b5e4da87c1c0361f2aa117ec566afbbbc35cd37456c7eb889ebc936416d14953c82e5a2a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@xterm/addon-serialize@npm:^0.13.0":
|
||||
version: 0.13.0
|
||||
resolution: "@xterm/addon-serialize@npm:0.13.0"
|
||||
@ -21982,6 +21991,7 @@ __metadata:
|
||||
"@vitejs/plugin-react-swc": "npm:^3.7.2"
|
||||
"@vitest/coverage-istanbul": "npm:^2.1.8"
|
||||
"@xterm/addon-fit": "npm:^0.10.0"
|
||||
"@xterm/addon-search": "npm:^0.15.0"
|
||||
"@xterm/addon-serialize": "npm:^0.13.0"
|
||||
"@xterm/addon-web-links": "npm:^0.11.0"
|
||||
"@xterm/addon-webgl": "npm:^0.18.0"
|
||||
|
Loading…
Reference in New Issue
Block a user