diff --git a/src/application.tsx b/src/application.tsx index 1c9a718..02ce559 100644 --- a/src/application.tsx +++ b/src/application.tsx @@ -33,7 +33,7 @@ export default class C0VMApplication extends React.Component< BC0SourceCode: "", BC0BreakPoints: new Set(), - C0Editors: [{ title: "Untitled_0.c0", key: 0, content: "", breakpoints: [] }], + C0Editors: [{ title: "Untitled_0.c0", key: 0, content: "", breakpoints: [], noCompile: false }], ActiveEditor: 0, PrintoutValue: "", diff --git a/src/components/code-editor.tsx b/src/components/code-editor.tsx index 927c471..1e45044 100644 --- a/src/components/code-editor.tsx +++ b/src/components/code-editor.tsx @@ -67,6 +67,7 @@ export default class CodeEditor extends React.Component key: this.state.C0_nextKey, content: "", breakpoints: [], + noCompile: false, }); this.props.set_app_state({C0Editors: new_editors, ActiveEditor: this.state.C0_nextKey}); this.setState({C0_nextKey: this.state.C0_nextKey + 1}); @@ -77,7 +78,7 @@ export default class CodeEditor extends React.Component handle_import_folder(F: RcFile, FList: RcFile[]) { if (DEBUG) console.debug("received a folder upload, processing one of them") - if (!(F.name.endsWith('.c0') || F.name.endsWith('.c1'))) { + if (!(F.name.endsWith('.c0') || F.name.endsWith('.c1') || F.name.toLowerCase() === "readme.txt")) { globalThis.MSG_EMITTER.warn( "File is not Imported", `${F.name} is not a c0/c1 file and is thus ignored.` @@ -100,6 +101,7 @@ export default class CodeEditor extends React.Component key: -1, content: res, breakpoints: [], + noCompile: F.name.endsWith(".txt") }) }; reader.readAsText(F, "utf-8"); @@ -119,7 +121,7 @@ export default class CodeEditor extends React.Component update_content(key: number, s: string) { let ns: C0EditorTab[] = [...this.props.app_state.C0Editors]; ns = ns.map((tab) => tab.key === key ? { - key: tab.key, title: tab.title, content: s, breakpoints: tab.breakpoints + key: tab.key, title: tab.title, content: s, breakpoints: tab.breakpoints, noCompile: tab.noCompile } : tab); this.props.set_app_state({C0Editors: ns, contentChanged: true}); } diff --git a/src/components/code_editor/c0-editor-group.tsx b/src/components/code_editor/c0-editor-group.tsx index e328744..1c44e52 100644 --- a/src/components/code_editor/c0-editor-group.tsx +++ b/src/components/code_editor/c0-editor-group.tsx @@ -8,9 +8,10 @@ import DraggableTabs from "./draggable_tabs"; import EditableTab from "./editable_tabs"; import type { RcFile } from 'antd/lib/upload'; +import TextEditor from "./text-editor"; const { TabPane } = Tabs; -const regex_valid_file_name = /^[0-9a-zA-Z_-]+\.c(0|1)$/; +const regex_valid_file_name = /^[0-9a-zA-Z_-]+\.(c(0|1)|txt)$/; export default class C0EditorGroup extends React.Component @@ -29,29 +30,44 @@ export default class C0EditorGroup extends React.Component if (!regex_valid_file_name.test(name)) { globalThis.MSG_EMITTER.warn( "Failed to rename editor tab", - "Editor tab's name can't contain special character and should end in .c0" + "Editor tab's name can't contain special character and should end in .c0 or .c1" ); return; } if (this.props.appState.C0Runtime !== undefined && this.props.appState.C0Runtime.state.CurrLineNumber !== 0) { globalThis.MSG_EMITTER.warn( "Failed to rename editor tab", - "Can't rename editor tab when a C0/BC0 program is running in background" + "Can't rename editor tab when a C0/C1 program is running in background" ); return; } for (let i = 0; i < this.props.appState.C0Editors.length; i ++) { const tab = this.props.appState.C0Editors[i]; if (tab.title === name && tab.key !== key) { - globalThis.MSG_EMITTER.warn("Failed to rename editor tab", "Editor tabs must have different name."); + globalThis.MSG_EMITTER.warn("Failed to rename editor tab", "Editor tabs must have unique names."); return; } } + if (name.endsWith(".txt")) { + let containsTextTab = false; + for (let tab of this.props.appState.C0Editors) { + if (tab.title.endsWith(".txt") && tab.key !== key) containsTextTab = true; + } + if (containsTextTab) { + globalThis.MSG_EMITTER.warn("Failed to rename editor tab", "Only one editor tab with filename '*.txt' can exist.") + return; + } + } + this.props.set_app_state( (S) => { let new_tabs = [...S.C0Editors]; for (let i = 0; i < new_tabs.length; i ++) { - if (new_tabs[i].key === key) new_tabs[i].title = name; + if (new_tabs[i].key === key) { + new_tabs[i].title = name; + if (name.endsWith(".txt")) new_tabs[i].noCompile = true; + else new_tabs[i].noCompile = false; + } } return { C0Editors: new_tabs }; } @@ -126,8 +142,7 @@ export default class C0EditorGroup extends React.Component } return this.set_current_tab_name(k, s)} @@ -136,7 +151,15 @@ export default class C0EditorGroup extends React.Component closable = {this.props.appState.C0Editors.length !== 1} closeIcon={} > - this.props.updateContent(editor.key, s)} + updateCompileLine = {fileArr => console.log(fileArr)} + updateName = {(name) => this.set_tab_name(editor.key, name)} + /> + : setBreakPts = {(bps) => this.set_brkpt_for_editor(editor.key, bps)} editable = {this.props.currLine === undefined} handle_import_folder = {(F: RcFile, FList: RcFile[]) => this.props.handle_import_folder(F, FList)} - /> + />} ; } ) diff --git a/src/components/code_editor/editor_extension/c0editor_theme.ts b/src/components/code_editor/editor_extension/c0editor_theme.ts index 0d06e4d..dce0e31 100644 --- a/src/components/code_editor/editor_extension/c0editor_theme.ts +++ b/src/components/code_editor/editor_extension/c0editor_theme.ts @@ -10,7 +10,8 @@ export const backgroundColor = "#FFFFFF", selectText = "#526FFF", textBackground = "#BBDEE3", searchBackground = "#AACDD2", - execLineBackground = "#FFFF90" + execLineBackground = "#FFFF90", + compileLineOKBackground = "#CFFECA" const highlighter = { @@ -76,6 +77,9 @@ export const C0LightStyle = EditorView.theme({ ".cm-execLine-light": { backgroundColor: execLineBackground }, + ".cm-compileLine-ok": { + backgroundColor: compileLineOKBackground + }, ".cm-foldGutter": { FontFace: "menlo-regular", fontSize: "1rem" diff --git a/src/components/code_editor/editor_extension/compileline_position.ts b/src/components/code_editor/editor_extension/compileline_position.ts new file mode 100644 index 0000000..59305fe --- /dev/null +++ b/src/components/code_editor/editor_extension/compileline_position.ts @@ -0,0 +1,32 @@ +import { EditorView } from "codemirror"; +import { Decoration, ViewPlugin } from "@codemirror/view"; + + + +function CompileLineHighlighter(lineNum: number) { + const currExecLineDeco = Decoration.line({ class: "cm-compileLine-ok" }); + return ViewPlugin.fromClass(class { + public decorations; + + constructor(view: EditorView) { + this.decorations = this.getDeco(view) + } + update(update: any) { + this.decorations = this.getDeco(update.view) + return; + } + getDeco(view: EditorView) { + if (lineNum <= 0 || + view.state.doc.lines < lineNum) { + return Decoration.none; // When we are not running, no line to highlight + } + const execLineStart = view.state.doc.line(lineNum).from; + return Decoration.set([currExecLineDeco.range(execLineStart)]); + } + }, { + decorations: v => v.decorations + } + ); +} + +export default CompileLineHighlighter; diff --git a/src/components/code_editor/text-editor.tsx b/src/components/code_editor/text-editor.tsx new file mode 100644 index 0000000..8310130 --- /dev/null +++ b/src/components/code_editor/text-editor.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import ReactCodeMirror, { basicSetup } from "@uiw/react-codemirror"; + +import BC0LightTheme from "./editor_extension/bc0editor_theme"; +import { LoadDocumentPlugin } from "./editor_extension/blank_load"; +import CompileLineHighlighter from "./editor_extension/compileline_position"; + + +// const cc0_compile_line_regex = ; + + +export default class TextEditor extends React.Component +{ + render() { + return + { + if (v.docChanged) { + this.props.updateContent(v.state.doc.toString()); + // for (let lineNum = 1; lineNum < v.state.doc.lines; lineNum ++) { + // if (v.state.doc.line(lineNum).text.) + // } + } + } + } + value = {this.props.editorValue} + extensions={[ + basicSetup(), + CompileLineHighlighter(1), + LoadDocumentPlugin(".txt", this.props.updateName) + ]} + editable={true} + /> + } +} diff --git a/src/network/c0_parser.ts b/src/network/c0_parser.ts index 681413f..6493f43 100644 --- a/src/network/c0_parser.ts +++ b/src/network/c0_parser.ts @@ -277,7 +277,7 @@ export function is_all_library_supported(editors: C0EditorTab[]){ libraries.has("args") || libraries.has("img") || libraries.has("file") || - libraries.has("curses") + libraries.has("cursor") ); } diff --git a/src/network/remote_compile.ts b/src/network/remote_compile.ts index 9f7917b..8936604 100644 --- a/src/network/remote_compile.ts +++ b/src/network/remote_compile.ts @@ -9,7 +9,7 @@ export default function remote_compile( print_update: (s: string) => void, ): void { if (!is_all_library_supported(app_state.C0Editors)){ - globalThis.MSG_EMITTER.warn( + globalThis.MSG_EMITTER.err( "Unsupported Library Used", "The C0 visualizer does not support 'file', 'img', 'args', and 'cursor' libraries, please remove these dependencies." ); @@ -18,7 +18,10 @@ export default function remote_compile( /** Update since v1.0.4 - print out the compile command when user hit compile button */ let compile_command = "$ cc0 "; - for (let tab of app_state.C0Editors) compile_command += " " + tab.title; + for (let tab of app_state.C0Editors) { + if (tab.noCompile) continue; + compile_command += " " + tab.title; + } compile_command += app_state.CompilerFlags["d"] ? " -d" : ""; print_update("Compiling the code with command line \n"); @@ -33,8 +36,8 @@ export default function remote_compile( "Access-Control-Allow-Origin": "*", }, body: JSON.stringify({ - codes : app_state.C0Editors.map((tab) => tab.content), - filenames: app_state.C0Editors.map((tab) => tab.title), + codes : app_state.C0Editors.filter(tab => !tab.noCompile).map(tab => tab.content), + filenames: app_state.C0Editors.filter(tab => !tab.noCompile).map(tab => tab.title), }) }) .then( diff --git a/src/types/react-interface.d.ts b/src/types/react-interface.d.ts index 157b479..554cac8 100644 --- a/src/types/react-interface.d.ts +++ b/src/types/react-interface.d.ts @@ -22,7 +22,8 @@ type C0EditorTab = { title : string, /* Title of editor tab */ key : number, /* Key of editor tab */ content: string, /* Content (raw string) of that tab */ - breakpoints: BreakPoint[] /* Breakpoints attatched to that tab */ + breakpoints: BreakPoint[], /* Breakpoints attatched to that tab */ + noCompile: boolean /* true to ignore this file in compile process */ }; interface C0VMApplicationProps { @@ -141,6 +142,13 @@ interface BC0EditorProps { updateBrkPts : (ns: BreakPoint[]) => void, } +interface TextEditorProps { + updateContent : (s: string) => void, + editorValue : string, + updateCompileLine : (fileSeq: string[]) => void + updateName : (s: string) => void, +} + // The props that CompilerOption component will accept interface CompilerOptionPropInterface { d_flag_stat: boolean;