diff options
Diffstat (limited to 'extension/src/util')
-rw-r--r-- | extension/src/util/util.ts | 115 | ||||
-rw-r--r-- | extension/src/util/vscode.ts | 152 |
2 files changed, 267 insertions, 0 deletions
diff --git a/extension/src/util/util.ts b/extension/src/util/util.ts new file mode 100644 index 00000000..d33593e1 --- /dev/null +++ b/extension/src/util/util.ts @@ -0,0 +1,115 @@ +import { RangeInFile, SerializedDebugContext } from "../client"; +import * as fs from "fs"; + +function charIsEscapedAtIndex(index: number, str: string): boolean { + if (index === 0) return false; + if (str[index - 1] !== "\\") return false; + return !charIsEscapedAtIndex(index - 1, str); +} + +export function convertSingleToDoubleQuoteJSON(json: string): string { + const singleQuote = "'"; + const doubleQuote = '"'; + const isQuote = (char: string) => + char === doubleQuote || char === singleQuote; + + let newJson = ""; + let insideString = false; + let enclosingQuoteType = doubleQuote; + for (let i = 0; i < json.length; i++) { + if (insideString) { + if (json[i] === enclosingQuoteType && !charIsEscapedAtIndex(i, json)) { + // Close string with a double quote + insideString = false; + newJson += doubleQuote; + } else if (json[i] === singleQuote) { + if (charIsEscapedAtIndex(i, json)) { + // Unescape single quote + newJson = newJson.slice(0, -1); + } + newJson += singleQuote; + } else if (json[i] === doubleQuote) { + if (!charIsEscapedAtIndex(i, json)) { + // Escape double quote + newJson += "\\"; + } + newJson += doubleQuote; + } else { + newJson += json[i]; + } + } else { + if (isQuote(json[i])) { + insideString = true; + enclosingQuoteType = json[i]; + newJson += doubleQuote; + } else { + newJson += json[i]; + } + } + } + + return newJson; +} + +export async function readRangeInFile( + rangeInFile: RangeInFile +): Promise<string> { + const range = rangeInFile.range; + return new Promise((resolve, reject) => { + fs.readFile(rangeInFile.filepath, (err, data) => { + if (err) { + reject(err); + } else { + let lines = data.toString().split("\n"); + if (range.start.line === range.end.line) { + resolve( + lines[rangeInFile.range.start.line].slice( + rangeInFile.range.start.character, + rangeInFile.range.end.character + ) + ); + } else { + let firstLine = lines[range.start.line].slice(range.start.character); + let lastLine = lines[range.end.line].slice(0, range.end.character); + let middleLines = lines.slice(range.start.line + 1, range.end.line); + resolve([firstLine, ...middleLines, lastLine].join("\n")); + } + } + }); + }); +} + +export function codeSelectionsToVirtualFileSystem( + codeSelections: RangeInFile[] +): { + [filepath: string]: string; +} { + let virtualFileSystem: { [filepath: string]: string } = {}; + for (let cs of codeSelections) { + if (!cs.filepath) continue; + if (cs.filepath in virtualFileSystem) continue; + let content = fs.readFileSync(cs.filepath, "utf8"); + virtualFileSystem[cs.filepath] = content; + } + return virtualFileSystem; +} + +export function addFileSystemToDebugContext( + ctx: SerializedDebugContext +): SerializedDebugContext { + ctx.filesystem = codeSelectionsToVirtualFileSystem(ctx.rangesInFiles); + return ctx; +} + +export function debounced(delay: number, fn: Function) { + let timerId: NodeJS.Timeout | null; + return function (...args: any[]) { + if (timerId) { + clearTimeout(timerId); + } + timerId = setTimeout(() => { + fn(...args); + timerId = null; + }, delay); + }; +} diff --git a/extension/src/util/vscode.ts b/extension/src/util/vscode.ts new file mode 100644 index 00000000..4eab98a7 --- /dev/null +++ b/extension/src/util/vscode.ts @@ -0,0 +1,152 @@ +import * as vscode from "vscode"; +import * as path from "path"; +import * as fs from "fs"; + +export function translate(range: vscode.Range, lines: number): vscode.Range { + return new vscode.Range( + range.start.line + lines, + range.start.character, + range.end.line + lines, + range.end.character + ); +} + +export function getNonce() { + let text = ""; + const possible = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + for (let i = 0; i < 32; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; +} + +export function getTestFile( + filename: string, + createFile: boolean = false +): string { + let basename = path.basename(filename).split(".")[0]; + switch (path.extname(filename)) { + case ".py": + basename += "_test"; + break; + case ".js": + case ".jsx": + case ".ts": + case ".tsx": + basename += ".test"; + break; + default: + basename += "_test"; + } + + const directory = path.join(path.dirname(filename), "tests"); + const testFilename = path.join(directory, basename + path.extname(filename)); + + // Optionally, create the file if it doesn't exist + if (createFile && !fs.existsSync(testFilename)) { + if (!fs.existsSync(directory)) { + fs.mkdirSync(directory); + } + fs.writeFileSync(testFilename, ""); + } + + return testFilename; +} + +export function getExtensionUri(): vscode.Uri { + return vscode.extensions.getExtension("Continue.continue")!.extensionUri; +} + +export function getViewColumnOfFile( + filepath: string +): vscode.ViewColumn | undefined { + for (let tabGroup of vscode.window.tabGroups.all) { + for (let tab of tabGroup.tabs) { + if ( + (tab?.input as any)?.uri && + (tab.input as any).uri.fsPath === filepath + ) { + return tabGroup.viewColumn; + } + } + } + return undefined; +} + +export function getRightViewColumn(): vscode.ViewColumn { + // When you want to place in the rightmost panel if there is already more than one, otherwise use Beside + let column = vscode.ViewColumn.Beside; + let columnOrdering = [ + vscode.ViewColumn.One, + vscode.ViewColumn.Beside, + vscode.ViewColumn.Two, + vscode.ViewColumn.Three, + vscode.ViewColumn.Four, + vscode.ViewColumn.Five, + vscode.ViewColumn.Six, + vscode.ViewColumn.Seven, + vscode.ViewColumn.Eight, + vscode.ViewColumn.Nine, + ]; + for (let tabGroup of vscode.window.tabGroups.all) { + if ( + columnOrdering.indexOf(tabGroup.viewColumn) > + columnOrdering.indexOf(column) + ) { + column = tabGroup.viewColumn; + } + } + return column; +} + +export async function readFileAtRange( + range: vscode.Range, + filepath: string +): Promise<string> { + return new Promise((resolve, reject) => { + fs.readFile(filepath, (err, data) => { + if (err) { + reject(err); + } else { + let lines = data.toString().split("\n"); + if (range.isSingleLine) { + resolve( + lines[range.start.line].slice( + range.start.character, + range.end.character + ) + ); + } else { + let firstLine = lines[range.start.line].slice(range.start.character); + let lastLine = lines[range.end.line].slice(0, range.end.character); + let middleLines = lines.slice(range.start.line + 1, range.end.line); + resolve([firstLine, ...middleLines, lastLine].join("\n")); + } + } + }); + }); +} + +export function openEditorAndRevealRange( + editorFilename: string, + range?: vscode.Range, + viewColumn?: vscode.ViewColumn +): Promise<vscode.TextEditor> { + return new Promise((resolve, _) => { + // Check if the editor is already open + vscode.workspace.openTextDocument(editorFilename).then((doc) => { + vscode.window + .showTextDocument( + doc, + getViewColumnOfFile(editorFilename) || viewColumn + ) + .then((editor) => { + if (range) { + editor.revealRange(range); + } + resolve(editor); + }); + }); + }); +} |