mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-22 21:42:49 +01:00
File/Code Editor Working (#9)
* save works * ready for Fri night PR - Code editor working --------- Authored-by: Amarsh Anand
This commit is contained in:
parent
238c8fb250
commit
c81a01aa9c
@ -276,13 +276,12 @@ input[type="checkbox"] {
|
||||
background-color: #aaaea7;
|
||||
cursor: default !important;
|
||||
}
|
||||
.error {
|
||||
background-color: red;
|
||||
.message {
|
||||
color: white;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 1rem;
|
||||
padding: 4px 1rem;
|
||||
max-width: 16rem;
|
||||
max-width: 80vw;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,6 +269,7 @@ class SimpleBlobRenderer extends React.Component<
|
||||
cmdstr={cmdstr}
|
||||
exitcode={exitcode}
|
||||
data={simpleModel.dataBlob}
|
||||
readOnly={simpleModel.readOnly}
|
||||
lineState={simpleModel.lineState}
|
||||
context={simpleModel.context}
|
||||
opts={simpleModel.opts}
|
||||
|
@ -6,9 +6,10 @@ import { GlobalModel } from "../model";
|
||||
class SourceCodeRenderer extends React.Component<
|
||||
{
|
||||
data: Blob;
|
||||
cmdstr: String;
|
||||
cwd: String;
|
||||
exitcode: Number;
|
||||
cmdstr: string;
|
||||
cwd: string;
|
||||
readOnly: boolean;
|
||||
exitcode: number;
|
||||
context: RendererContext;
|
||||
opts: RendererOpts;
|
||||
savedHeight: number;
|
||||
@ -18,16 +19,14 @@ class SourceCodeRenderer extends React.Component<
|
||||
{}
|
||||
> {
|
||||
/**
|
||||
* codeCache is a Hashmap with key=filepath and value=code
|
||||
* codeCache is a Hashmap with key=screenId:lineId:filepath and value=code
|
||||
* Editor should never read the code directly from the filesystem. it should read from the cache.
|
||||
* Upon loading a file (props.data contains the file-contents) FOR THE FIRST TIME,
|
||||
* we will put it in the cache, and will update the contents of the cache upon every onChange().
|
||||
* ALl this is to ensure that the file contents doesnt get reloaded when the line scrolls out of the viewport
|
||||
* (and hence the react component gets destroyed)
|
||||
*/
|
||||
static codeCache = new Map();
|
||||
|
||||
filePath;
|
||||
cacheKey;
|
||||
originalData;
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.editorRef = React.createRef();
|
||||
@ -39,26 +38,28 @@ class SourceCodeRenderer extends React.Component<
|
||||
isFullWindow: false,
|
||||
isSave: false,
|
||||
editorHeight: props.savedHeight,
|
||||
errorMessage: null,
|
||||
message: null,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
// DANGEROUS ... I AM ASSUMING THE COMMAND IS IN FORMAT cat prompt_samples/sample.java
|
||||
// filePath should be saved in the new lineOpts field that Mike is working on :)
|
||||
this.filePath = `${this.props.cwd}/${this.props.cmdstr.split(" ")[1]}`;
|
||||
const code = SourceCodeRenderer.codeCache.get(this.filePath);
|
||||
this.filePath = this.props.lineState["prompt:file"];
|
||||
const { screenId, lineId } = this.props.context;
|
||||
this.cacheKey = `${screenId}-${lineId}-${this.filePath}`;
|
||||
const code = SourceCodeRenderer.codeCache.get(this.cacheKey);
|
||||
if (code) {
|
||||
this.setState({ code });
|
||||
} else
|
||||
this.props.data.text().then((code) => {
|
||||
this.originalData = code;
|
||||
this.setState({ code });
|
||||
SourceCodeRenderer.codeCache.set(this.filePath, code);
|
||||
SourceCodeRenderer.codeCache.set(this.cacheKey, code);
|
||||
});
|
||||
}
|
||||
|
||||
handleEditorDidMount = (editor, monaco) => {
|
||||
const extension = this.props.cmdstr.match(/(?:[^\\\/:*?"<>|\r\n]+\.)([a-zA-Z0-9]+)\b/)?.[1] || "";
|
||||
const extension =
|
||||
(this.filePath && this.filePath.match(/(?:[^\\\/:*?"<>|\r\n]+\.)([a-zA-Z0-9]+)\b/)?.[1]) || "";
|
||||
const detectedLanguage = monaco.languages
|
||||
.getLanguages()
|
||||
.find((lang) => lang.extensions?.includes("." + extension));
|
||||
@ -73,6 +74,12 @@ class SourceCodeRenderer extends React.Component<
|
||||
}
|
||||
}
|
||||
this.setEditorHeight();
|
||||
editor.onKeyDown((e) => {
|
||||
if (e.code === "KeyS" && (e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault();
|
||||
this.doSave();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
handleLanguageChange = (event) => {
|
||||
@ -95,17 +102,27 @@ class SourceCodeRenderer extends React.Component<
|
||||
};
|
||||
|
||||
doSave = () => {
|
||||
// call the function that would save the file to filesystem. would likely be async
|
||||
// as a result of the save operation, the entire component should get reloaded (** HOW **)
|
||||
// once its reloaded, this.props.data.text() should contain the latest code
|
||||
// in which case, the cache will get refilled and we can consider the transaction "committed"
|
||||
this.setState({ errorMessage: "File could not be saved" });
|
||||
setTimeout(() => this.setState({ errorMessage: null }), 3000);
|
||||
const { screenId, lineId } = this.props.context;
|
||||
const encodedCode = new TextEncoder().encode(this.state.code);
|
||||
debugger;
|
||||
GlobalModel.writeRemoteFile(screenId, lineId, this.filePath, encodedCode, { useTemp: true })
|
||||
.then(() => {
|
||||
this.originalData = this.state.code;
|
||||
this.setState({
|
||||
isSave: false,
|
||||
message: { status: "success", text: `Saved to ${this.props.cwd}/${this.filePath}` },
|
||||
});
|
||||
setTimeout(() => this.setState({ message: null }), 3000);
|
||||
})
|
||||
.catch((e) => {
|
||||
this.setState({ message: { status: "error", text: e.message } });
|
||||
setTimeout(() => this.setState({ message: null }), 3000);
|
||||
});
|
||||
};
|
||||
|
||||
handleEditorChange = (code) => {
|
||||
this.setState({ isFullWindow: true, code });
|
||||
SourceCodeRenderer.codeCache.set(this.filePath, code);
|
||||
SourceCodeRenderer.codeCache.set(this.cacheKey, code);
|
||||
this.setEditorHeight();
|
||||
setTimeout(() => this.props.scrollToBringIntoViewport(), 350);
|
||||
this.props.data.text().then((originalCode) => this.setState({ isSave: code !== originalCode }));
|
||||
@ -155,7 +172,17 @@ class SourceCodeRenderer extends React.Component<
|
||||
scrollBeyondLastLine: false,
|
||||
fontSize: GlobalModel.termFontSize.get(),
|
||||
fontFamily: "JetBrains Mono",
|
||||
readOnly: this.props.opts.readOnly,
|
||||
readOnly: this.props.readOnly,
|
||||
keybindings: [
|
||||
{
|
||||
key: "ctrl+s",
|
||||
command: "-editor.action.filesave",
|
||||
},
|
||||
{
|
||||
key: "cmd+s",
|
||||
command: "-editor.action.filesave",
|
||||
},
|
||||
],
|
||||
}}
|
||||
onChange={this.handleEditorChange}
|
||||
/>
|
||||
@ -189,13 +216,17 @@ class SourceCodeRenderer extends React.Component<
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{this.state.errorMessage && (
|
||||
{this.state.message && (
|
||||
<div style={{ position: "absolute", bottom: "-3px", left: "14px" }}>
|
||||
<div
|
||||
className="error"
|
||||
style={{ fontSize: GlobalModel.termFontSize.get(), fontFamily: "JetBrains Mono" }}
|
||||
className="message"
|
||||
style={{
|
||||
fontSize: GlobalModel.termFontSize.get(),
|
||||
fontFamily: "JetBrains Mono",
|
||||
background: `${this.state.message.status === "error" ? "red" : "#4e9a06"}`,
|
||||
}}
|
||||
>
|
||||
{this.state.errorMessage}
|
||||
{this.state.message.text}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
Loading…
Reference in New Issue
Block a user