mirror of
https://github.com/wavetermdev/waveterm
synced 2026-05-24 09:18:27 +00:00
Working on bug fixes and UX. Streams restarting, fixed lots of bugs, timing issues, concurrency bugs. Get status shipped to the FE to drive "shield" state display. Deal with stale streams. Also big UX changes to the block headers. Specialize the terminal headers to prioritize the connection (sense of place), remove old terminal icon and word "Terminal" from the header. Also drop "Web" and "Preview" labels on web/preview blocks. Added `wsh focusblock` command.
110 lines
3.6 KiB
TypeScript
110 lines
3.6 KiB
TypeScript
// Copyright 2025, Command Line Inc.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import { MonacoCodeEditor } from "@/app/monaco/monaco-react";
|
|
import { useOverrideConfigAtom } from "@/app/store/global";
|
|
import { boundNumber } from "@/util/util";
|
|
import type * as MonacoTypes from "monaco-editor";
|
|
import * as MonacoModule from "monaco-editor";
|
|
import React, { useMemo, useRef } from "react";
|
|
|
|
function defaultEditorOptions(): MonacoTypes.editor.IEditorOptions {
|
|
const opts: MonacoTypes.editor.IEditorOptions = {
|
|
scrollBeyondLastLine: false,
|
|
fontSize: 12,
|
|
fontFamily: "Hack",
|
|
smoothScrolling: true,
|
|
scrollbar: {
|
|
useShadows: false,
|
|
verticalScrollbarSize: 5,
|
|
horizontalScrollbarSize: 5,
|
|
},
|
|
minimap: {
|
|
enabled: true,
|
|
},
|
|
stickyScroll: {
|
|
enabled: false,
|
|
},
|
|
};
|
|
return opts;
|
|
}
|
|
|
|
interface CodeEditorProps {
|
|
blockId: string;
|
|
text: string;
|
|
readonly: boolean;
|
|
language?: string;
|
|
fileName?: string;
|
|
onChange?: (text: string) => void;
|
|
onMount?: (monacoPtr: MonacoTypes.editor.IStandaloneCodeEditor, monaco: typeof MonacoModule) => () => void;
|
|
}
|
|
|
|
export function CodeEditor({ blockId, text, language, fileName, readonly, onChange, onMount }: CodeEditorProps) {
|
|
const divRef = useRef<HTMLDivElement>(null);
|
|
const unmountRef = useRef<() => void>(null);
|
|
const minimapEnabled = useOverrideConfigAtom(blockId, "editor:minimapenabled") ?? false;
|
|
const stickyScrollEnabled = useOverrideConfigAtom(blockId, "editor:stickyscrollenabled") ?? false;
|
|
const wordWrap = useOverrideConfigAtom(blockId, "editor:wordwrap") ?? false;
|
|
const fontSize = boundNumber(useOverrideConfigAtom(blockId, "editor:fontsize"), 6, 64);
|
|
const uuidRef = useRef(crypto.randomUUID()).current;
|
|
let editorPath: string;
|
|
if (fileName) {
|
|
const separator = fileName.startsWith("/") ? "" : "/";
|
|
editorPath = blockId + separator + fileName;
|
|
} else {
|
|
editorPath = uuidRef;
|
|
}
|
|
|
|
React.useEffect(() => {
|
|
return () => {
|
|
// unmount function
|
|
if (unmountRef.current) {
|
|
unmountRef.current();
|
|
}
|
|
};
|
|
}, []);
|
|
|
|
function handleEditorChange(text: string) {
|
|
if (onChange) {
|
|
onChange(text);
|
|
}
|
|
}
|
|
|
|
function handleEditorOnMount(
|
|
editor: MonacoTypes.editor.IStandaloneCodeEditor,
|
|
monaco: typeof MonacoModule
|
|
): () => void {
|
|
if (onMount) {
|
|
const cleanup = onMount(editor, monaco);
|
|
unmountRef.current = cleanup;
|
|
return cleanup;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
const editorOpts = useMemo(() => {
|
|
const opts = defaultEditorOptions();
|
|
opts.minimap.enabled = minimapEnabled;
|
|
opts.stickyScroll.enabled = stickyScrollEnabled;
|
|
opts.wordWrap = wordWrap ? "on" : "off";
|
|
opts.fontSize = fontSize;
|
|
opts.copyWithSyntaxHighlighting = false;
|
|
return opts;
|
|
}, [minimapEnabled, stickyScrollEnabled, wordWrap, fontSize, readonly]);
|
|
|
|
return (
|
|
<div className="flex flex-col w-full h-full overflow-hidden items-center justify-center">
|
|
<div className="flex flex-col h-full w-full" ref={divRef}>
|
|
<MonacoCodeEditor
|
|
readonly={readonly}
|
|
text={text}
|
|
options={editorOpts}
|
|
onChange={handleEditorChange}
|
|
onMount={handleEditorOnMount}
|
|
path={editorPath}
|
|
language={language}
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|