File/Code Editor Working (#9)

* save works

* ready for Fri night PR - Code editor working

---------

Authored-by: Amarsh Anand
This commit is contained in:
sawka 2023-09-01 21:44:35 -07:00 committed by GitHub
parent 238c8fb250
commit c81a01aa9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 30 deletions

View File

@ -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;
}
}

View File

@ -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}

View File

@ -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>
)}