UNPKG

arepl

Version:
156 lines (123 loc) 6.21 kB
'use strict' import {PythonEvaluator} from "arepl-backend" import {EOL} from "os" import * as vscode from "vscode" import { PreviewContainer } from "./previewContainer"; import Reporter from "./telemetry" import {ToAREPLLogic} from "./toAREPLLogic" // This class initializes the previewmanager based on extension type and manages all the subscriptions export default class PreviewManager { reporter: Reporter; disposable: vscode.Disposable; pythonEditor: vscode.TextDocument; pythonEvaluator: PythonEvaluator; status: vscode.StatusBarItem; settings: vscode.WorkspaceConfiguration; toAREPLLogic: ToAREPLLogic previewContainer: PreviewContainer subscriptions: vscode.Disposable[] = []; constructor(context: vscode.ExtensionContext) { this.settings = vscode.workspace.getConfiguration("AREPL"); this.pythonEditor = vscode.window.activeTextEditor.document; this.reporter = new Reporter(this.settings.get<boolean>("telemetry")) this.status = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100); this.status.text = "Running python..." this.status.tooltip = "AREPL is currently running your python file. Close the AREPL preview to stop" this.previewContainer = new PreviewContainer(this.reporter, context) } async startArepl(){ this.subscriptions.push(this.previewContainer.register()) this.startAndBindPython() if(this.pythonEditor.isUntitled && this.pythonEditor.getText() == "") { await this.insertDefaultImports(vscode.window.activeTextEditor) // waiting for this to complete so i dont accidentily trigger // the edit doc handler when i insert imports } this.subscribeHandlersToDoc() } runArepl(){ this.onAnyDocChange(vscode.window.activeTextEditor.document) } dispose() { if(this.pythonEvaluator.pyshell != null && this.pythonEvaluator.pyshell.childProcess != null){ this.pythonEvaluator.stop() } this.disposable = vscode.Disposable.from(...this.subscriptions); this.disposable.dispose(); this.status.dispose(); this.reporter.sendFinishedEvent(this.settings) this.reporter.dispose(); } /** * starts AREPL python backend and binds print&result output to the handlers */ private startAndBindPython(){ const pythonPath = this.settings.get<string>("pythonPath") const pythonOptions = this.settings.get<string[]>("pythonOptions") this.pythonEvaluator = new PythonEvaluator(pythonPath, pythonOptions) this.pythonEvaluator.startPython() this.pythonEvaluator.pyshell.childProcess.on("error", err => { const error: any = err; // typescript complains about type for some reason so defining to any this.previewContainer.handleSpawnError(error.path, error.spawnargs[0], error.stack); this.reporter.sendError("error starting python: " + error.path) }) this.toAREPLLogic = new ToAREPLLogic(this.pythonEvaluator, this.previewContainer) // binding this to the class so it doesn't get overwritten by PythonEvaluator this.pythonEvaluator.onPrint = this.previewContainer.handlePrint.bind(this.previewContainer) this.pythonEvaluator.onResult = result => { this.status.hide() // @ts-ignore todo: fix typing in backend this.previewContainer.handleResult(result) } } /** * binds various funcs to activate upon edit of document / switching of active doc / etc... */ private subscribeHandlersToDoc(){ const debounce = this.settings.get<number>("delay"); const restartExtraDebounce = this.settings.get<number>("restartDelay"); if(this.settings.get<boolean>("skipLandingPage")){ this.onAnyDocChange(this.pythonEditor); } if(this.settings.get<string>("whenToExecute") == "onSave"){ vscode.workspace.onDidSaveTextDocument((e) => { this.onAnyDocChange(e) }, this, this.subscriptions) } else if(this.settings.get<string>("whenToExecute") == "afterDelay"){ vscode.workspace.onDidChangeTextDocument((e) => { const delay = this.toAREPLLogic.restartMode ? debounce + restartExtraDebounce : debounce this.pythonEvaluator.debounce(this.onAnyDocChange.bind(this, e.document), delay) }, this, this.subscriptions) } else {} //third option is onKeybinding in which case user manually invokes arepl vscode.workspace.onDidCloseTextDocument((e) => { if(e == this.pythonEditor || e.uri.scheme == this.previewContainer.scheme) this.dispose() }, this, this.subscriptions) } private insertDefaultImports(editor: vscode.TextEditor){ return editor.edit((editBuilder) => { let imports = this.settings.get<string[]>("defaultImports") imports = imports.filter(i => i.trim() != "") if(imports.length == 0) return imports = imports.map(i => { const words = i.split(" ") // python import syntax: "import library" or "from library import method" // so if user didnt specify import we will do that for them :) if(words[0] != "import" && words[0] != "from" && words[0].length > 0){ i = "import " + i } return i }) editBuilder.insert(new vscode.Position(0, 0), imports.join(EOL) + EOL) }) } private onAnyDocChange(event: vscode.TextDocument){ if(event == this .pythonEditor){ this.status.show(); const text = event.getText() const filePath = this.pythonEditor.isUntitled ? "" : this.pythonEditor.fileName this.toAREPLLogic.onUserInput(text, filePath) } } }