Getting the client to run (#12)
* Clean up workbench and integrate initialization data * Uncomment Electron fill * Run server & client together * Clean up Electron fill & patch * Bind fs methods This makes them usable with the promise form: `promisify(access)(...)`. * Add space between tag and title to browser logger * Add typescript dep to server and default __dirname for path * Serve web files from server * Adjust some dev options * Rework workbench a bit to use a class and catch unexpected errors * No mkdirs for now, fix util fill, use bash with exec * More fills, make general client abstract * More fills * Fix cp.exec * Fix require calls in fs fill being aliased * Create data and storage dir * Implement fs.watch Using exec for now. * Implement storage database fill * Fix os export and homedir * Add comment to use navigator.sendBeacon * Fix fs callbacks (some args are optional) * Make sure data directory exists when passing it back * Update patch * Target es5 * More fills * Add APIs required for bootstrap-fork to function (#15) * Add bootstrap-fork execution * Add createConnection * Bundle bootstrap-fork into cli * Remove .node directory created from spdlog * Fix npm start * Remove unnecessary comment * Add webpack-hot-middleware if CLI env is not set * Add restarting to shared process * Fix starting with yarn
This commit is contained in:
11
packages/vscode/src/fill/amd.ts
Normal file
11
packages/vscode/src/fill/amd.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { URI } from "vs/base/common/uri";
|
||||
|
||||
export const getPathFromAmdModule = (_: typeof require, relativePath: string): string => {
|
||||
if (process.mainModule && process.mainModule.filename) {
|
||||
const index = process.mainModule.filename.lastIndexOf("/");
|
||||
|
||||
return process.mainModule.filename.slice(0, index);
|
||||
}
|
||||
|
||||
return relativePath ? URI.parse(require.toUrl(relativePath)).fsPath : "";
|
||||
};
|
1
packages/vscode/src/fill/graceful-fs.ts
Normal file
1
packages/vscode/src/fill/graceful-fs.ts
Normal file
@ -0,0 +1 @@
|
||||
export const gracefulify = (): void => undefined;
|
@ -1,8 +1,13 @@
|
||||
module.exports = {
|
||||
getCurrentKeyboardLayout: (): null => {
|
||||
class NativeKeymap {
|
||||
|
||||
public getCurrentKeyboardLayout(): null {
|
||||
return null;
|
||||
},
|
||||
getKeyMap: (): undefined[] => {
|
||||
}
|
||||
|
||||
public getKeyMap(): undefined[] {
|
||||
return [];
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export = new NativeKeymap();
|
||||
|
@ -70,4 +70,4 @@ const ptyType: nodePtyType = {
|
||||
|
||||
};
|
||||
|
||||
module.exports = ptyType;
|
||||
exports = ptyType;
|
||||
|
2
packages/vscode/src/fill/package.ts
Normal file
2
packages/vscode/src/fill/package.ts
Normal file
@ -0,0 +1,2 @@
|
||||
// TODO: obtain this in a reasonable way.
|
||||
export default { name: "vscode", version: "1.31.1" };
|
7
packages/vscode/src/fill/paths.ts
Normal file
7
packages/vscode/src/fill/paths.ts
Normal file
@ -0,0 +1,7 @@
|
||||
const paths = {
|
||||
appData: "/tmp",
|
||||
defaultUserData: "/tmp",
|
||||
};
|
||||
|
||||
export let getAppDataPath = (): string => paths.appData;
|
||||
export let getDefaultUserDataPath = (): string => paths.defaultUserData;
|
24
packages/vscode/src/fill/product.ts
Normal file
24
packages/vscode/src/fill/product.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { IProductConfiguration } from "vs/platform/node/product";
|
||||
|
||||
const product = {
|
||||
nameShort: "VSCode",
|
||||
nameLong: "vscode online",
|
||||
dataFolderName: ".vscode-online",
|
||||
extensionsGallery: {
|
||||
serviceUrl: "",
|
||||
},
|
||||
extensionExecutionEnvironments: {
|
||||
"wayou.vscode-todo-highlight": "worker",
|
||||
"vscodevim.vim": "worker",
|
||||
"coenraads.bracket-pair-colorizer": "worker",
|
||||
},
|
||||
fetchUrl: "",
|
||||
} as IProductConfiguration;
|
||||
|
||||
if (process.env['VSCODE_DEV']) {
|
||||
product.nameShort += ' Dev';
|
||||
product.nameLong += ' Dev';
|
||||
product.dataFolderName += '-dev';
|
||||
}
|
||||
|
||||
export default product;
|
3
packages/vscode/src/fill/require.ts
Normal file
3
packages/vscode/src/fill/require.ts
Normal file
@ -0,0 +1,3 @@
|
||||
// TODO: ?
|
||||
// tslint:disable-next-line no-any
|
||||
(global as any).requireToUrl = (path: string): string => `${location.protocol}//{location.host}/${path}`;
|
186
packages/vscode/src/fill/spdlog.ts
Normal file
186
packages/vscode/src/fill/spdlog.ts
Normal file
@ -0,0 +1,186 @@
|
||||
import { exec } from "child_process";
|
||||
import { promisify } from "util";
|
||||
import { appendFile, stat, readdir } from "fs";
|
||||
import { RotatingLogger as NodeRotatingLogger } from "spdlog";
|
||||
import { logger, field } from "@coder/logger";
|
||||
import { escapePath } from "@coder/protocol";
|
||||
|
||||
// TODO: It would be better to spawn an actual spdlog instance on the server and
|
||||
// use that for the logging. Or maybe create an instance when the server starts,
|
||||
// and just always use that one (make it part of the protocol).
|
||||
export class RotatingLogger implements NodeRotatingLogger {
|
||||
|
||||
private format = true;
|
||||
private buffer = "";
|
||||
private flushPromise: Promise<void> | undefined;
|
||||
private name: string;
|
||||
private logDirectory: string;
|
||||
private escapedLogDirectory: string;
|
||||
private fullFilePath: string;
|
||||
private fileName: string;
|
||||
private fileExt: string | undefined;
|
||||
private escapedFilePath: string;
|
||||
private filesize: number;
|
||||
private filecount: number;
|
||||
|
||||
public constructor(name: string, filePath: string, filesize: number, filecount: number) {
|
||||
this.name = name;
|
||||
this.filesize = filesize;
|
||||
this.filecount = filecount;
|
||||
|
||||
this.fullFilePath = filePath;
|
||||
const slashIndex = filePath.lastIndexOf("/");
|
||||
const dotIndex = filePath.lastIndexOf(".");
|
||||
this.logDirectory = slashIndex !== -1 ? filePath.substring(0, slashIndex) : "/";
|
||||
this.fileName = filePath.substring(slashIndex + 1, dotIndex !== -1 ? dotIndex : undefined);
|
||||
this.fileExt = dotIndex !== -1 ? filePath.substring(dotIndex + 1) : undefined;
|
||||
|
||||
this.escapedLogDirectory = escapePath(this.logDirectory);
|
||||
this.escapedFilePath = escapePath(filePath);
|
||||
|
||||
this.flushPromise = new Promise((resolve): void => {
|
||||
exec(`mkdir -p ${this.escapedLogDirectory}; touch ${this.escapedFilePath}`, async (error) => {
|
||||
if (!error) {
|
||||
try {
|
||||
await this.doFlush();
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
logger.error(error.message, field("error", error));
|
||||
}
|
||||
this.flushPromise = undefined;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public trace(message: string): void {
|
||||
this.write("trace", message);
|
||||
}
|
||||
|
||||
public debug(message: string): void {
|
||||
this.write("debug", message);
|
||||
}
|
||||
|
||||
public info(message: string): void {
|
||||
this.write("info", message);
|
||||
}
|
||||
|
||||
public warn(message: string): void {
|
||||
this.write("warn", message);
|
||||
}
|
||||
|
||||
public error(message: string): void {
|
||||
this.write("error", message);
|
||||
}
|
||||
|
||||
public critical(message: string): void {
|
||||
this.write("critical", message);
|
||||
}
|
||||
|
||||
public setLevel(): void {
|
||||
// Should output everything.
|
||||
}
|
||||
|
||||
public clearFormatters(): void {
|
||||
this.format = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the buffer. Only one process runs at a time to prevent race
|
||||
* conditions.
|
||||
*/
|
||||
public flush(): Promise<void> {
|
||||
if (!this.flushPromise) {
|
||||
this.flushPromise = this.doFlush().then(() => {
|
||||
this.flushPromise = undefined;
|
||||
}).catch((error) => {
|
||||
this.flushPromise = undefined;
|
||||
logger.error(error.message, field("error", error));
|
||||
});
|
||||
}
|
||||
|
||||
return this.flushPromise;
|
||||
}
|
||||
|
||||
public drop(): void {
|
||||
this.buffer = "";
|
||||
}
|
||||
|
||||
private pad(num: number, length: number = 2, prefix: string = "0"): string {
|
||||
const str = num.toString();
|
||||
|
||||
return (length > str.length ? prefix.repeat(length - str.length) : "") + str;
|
||||
}
|
||||
|
||||
private write(severity: string, message: string): void {
|
||||
if (this.format) {
|
||||
const date = new Date();
|
||||
const dateStr = `${date.getFullYear()}-${this.pad(date.getMonth() + 1)}-${this.pad(date.getDate())}`
|
||||
+ ` ${this.pad(date.getHours())}:${this.pad(date.getMinutes())}:${this.pad(date.getSeconds())}.${this.pad(date.getMilliseconds(), 3)}`;
|
||||
this.buffer += `[${dateStr}] [${this.name}] [${severity}] `;
|
||||
}
|
||||
this.buffer += message;
|
||||
if (this.format) {
|
||||
this.buffer += "\n";
|
||||
}
|
||||
this.flush();
|
||||
}
|
||||
|
||||
private async rotate(): Promise<void> {
|
||||
const stats = await promisify(stat)(this.fullFilePath);
|
||||
if (stats.size < this.filesize) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reExt = typeof this.fileExt !== "undefined" ? `\\.${this.fileExt}` : "";
|
||||
const re = new RegExp(`^${this.fileName}(?:\\.(\\d+))?${reExt}$`);
|
||||
const orderedFiles: string[] = [];
|
||||
(await promisify(readdir)(this.logDirectory)).forEach((file) => {
|
||||
const match = re.exec(file);
|
||||
if (match) {
|
||||
orderedFiles[typeof match[1] !== "undefined" ? parseInt(match[1], 10) : 0] = file;
|
||||
}
|
||||
});
|
||||
|
||||
// Rename in reverse so we don't overwrite before renaming something.
|
||||
let count = 0;
|
||||
const command = orderedFiles.map((file) => {
|
||||
const fileExt = typeof this.fileExt !== "undefined" ? `.${this.fileExt}` : "";
|
||||
const newFile = `${this.logDirectory}/${this.fileName}.${++count}${fileExt}`;
|
||||
|
||||
return count >= this.filecount
|
||||
? `rm ${escapePath(this.logDirectory + "/" + file)}`
|
||||
: `mv ${escapePath(this.logDirectory + "/" + file)} ${escapePath(newFile)}`;
|
||||
}).reverse().concat([
|
||||
`touch ${escapePath(this.fullFilePath)}`,
|
||||
]).join(";");
|
||||
|
||||
await promisify(exec)(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the entire buffer, including anything added in the meantime, and
|
||||
* rotates the log if necessary.
|
||||
*/
|
||||
private async doFlush(): Promise<void> {
|
||||
const writeBuffer = async (): Promise<void> => {
|
||||
const toWrite = this.buffer;
|
||||
this.buffer = "";
|
||||
|
||||
await promisify(appendFile)(this.fullFilePath, toWrite);
|
||||
};
|
||||
|
||||
while (this.buffer.length > 0) {
|
||||
await writeBuffer();
|
||||
await this.rotate();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const setAsyncMode = (): void => {
|
||||
// Nothing to do.
|
||||
};
|
22
packages/vscode/src/fill/stdioElectron.ts
Normal file
22
packages/vscode/src/fill/stdioElectron.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { StdioIpcHandler } from "@coder/server/src/ipc";
|
||||
import { IpcRenderer } from "electron";
|
||||
|
||||
export * from "@coder/ide/src/fill/electron";
|
||||
|
||||
class StdioIpcRenderer extends StdioIpcHandler implements IpcRenderer {
|
||||
|
||||
public sendTo(windowId: number, channel: string, ...args: any[]): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public sendToHost(channel: string, ...args: any[]): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public eventNames(): string[] {
|
||||
return super.eventNames() as string[];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const ipcRenderer = new StdioIpcRenderer();
|
78
packages/vscode/src/fill/storageDatabase.ts
Normal file
78
packages/vscode/src/fill/storageDatabase.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import { readFile, writeFile } from "fs";
|
||||
import { promisify } from "util";
|
||||
import { Event } from "vs/base/common/event";
|
||||
import * as storage from "vs/base/node/storage";
|
||||
|
||||
export class StorageDatabase implements storage.IStorageDatabase {
|
||||
|
||||
public readonly onDidChangeItemsExternal = Event.None;
|
||||
private items = new Map<string, string>();
|
||||
private fetched: boolean = false;
|
||||
|
||||
public constructor(private readonly path: string) {
|
||||
window.addEventListener("unload", () => {
|
||||
if (!navigator.sendBeacon) {
|
||||
throw new Error("cannot save state");
|
||||
}
|
||||
// TODO: Need to use navigator.sendBeacon instead of the web socket, or we
|
||||
// need to save when there is a change. Should we save as a sqlite3
|
||||
// database instead of JSON? Could send to the server the way the global
|
||||
// storage works. Or maybe fill `vscode-sqlite3` to do that.
|
||||
this.save();
|
||||
});
|
||||
}
|
||||
|
||||
public async getItems(): Promise<Map<string, string>> {
|
||||
if (this.fetched) {
|
||||
return this.items;
|
||||
}
|
||||
try {
|
||||
const contents = await promisify(readFile)(this.path, "utf8");
|
||||
const json = JSON.parse(contents);
|
||||
Object.keys(json).forEach((key) => {
|
||||
this.items.set(key, json[key]);
|
||||
});
|
||||
} catch (error) {
|
||||
if (error.code && error.code !== "ENOENT") {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
this.fetched = true;
|
||||
|
||||
return this.items;
|
||||
}
|
||||
|
||||
public updateItems(request: storage.IUpdateRequest): Promise<void> {
|
||||
if (request.insert) {
|
||||
request.insert.forEach((value, key) => this.items.set(key, value));
|
||||
}
|
||||
|
||||
if (request.delete) {
|
||||
request.delete.forEach(key => this.items.delete(key));
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public close(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public checkIntegrity(): Promise<string> {
|
||||
return Promise.resolve("ok");
|
||||
}
|
||||
|
||||
private save(): Promise<void> {
|
||||
const json: { [key: string]: string } = {};
|
||||
this.items.forEach((value, key) => {
|
||||
json[key] = value;
|
||||
});
|
||||
|
||||
return promisify(writeFile)(this.path, JSON.stringify(json));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
storage.SQLiteStorageDatabase = StorageDatabase;
|
274
packages/vscode/src/fill/windowsService.ts
Normal file
274
packages/vscode/src/fill/windowsService.ts
Normal file
@ -0,0 +1,274 @@
|
||||
import * as electron from "electron";
|
||||
import { Emitter } from "@coder/events";
|
||||
import * as windowsIpc from "vs/platform/windows/node/windowsIpc";
|
||||
import { IWindowsService, INativeOpenDialogOptions, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions, IMessageBoxResult, IDevToolsOptions, IEnterWorkspaceResult, CrashReporterStartOptions, INewWindowOptions } from "vs/platform/windows/common/windows";
|
||||
import { ParsedArgs } from "vs/platform/environment/common/environment";
|
||||
import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier } from "vs/platform/workspaces/common/workspaces";
|
||||
import { URI } from "vs/base/common/uri";
|
||||
import { IRecentlyOpened } from "vs/platform/history/common/history";
|
||||
import { ISerializableCommandAction } from "vs/platform/actions/common/actions";
|
||||
|
||||
// TODO: Might make sense to hook these straight in if we can.
|
||||
// import { WindowsService as VSWindowsService } from "vs/platform/windows/electron-main/windowsService";
|
||||
// import { WindowsManager } from "vs/code/electron-main/windows";
|
||||
|
||||
/**
|
||||
* Instead of going to the shared process, we'll directly run these methods on
|
||||
* the client. This setup means we can only control the current window.
|
||||
*/
|
||||
class WindowsService implements IWindowsService {
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public _serviceBrand: any;
|
||||
|
||||
private openEmitter = new Emitter<number>();
|
||||
private focusEmitter = new Emitter<number>();
|
||||
private blurEmitter = new Emitter<number>();
|
||||
private maximizeEmitter = new Emitter<number>();
|
||||
private unmaximizeEmitter = new Emitter<number>();
|
||||
private recentlyOpenedChangeEmitter = new Emitter<void>();
|
||||
|
||||
public onWindowOpen = this.openEmitter.event;
|
||||
public onWindowFocus = this.focusEmitter.event;
|
||||
public onWindowBlur = this.blurEmitter.event;
|
||||
public onWindowMaximize = this.maximizeEmitter.event;
|
||||
public onWindowUnmaximize = this.unmaximizeEmitter.event;
|
||||
public onRecentlyOpenedChange = this.recentlyOpenedChangeEmitter.event;
|
||||
|
||||
private window = new electron.BrowserWindow();
|
||||
|
||||
// Dialogs
|
||||
public pickFileFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public pickFileAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public pickFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public pickWorkspaceAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public showMessageBox(_windowId: number, _options: MessageBoxOptions): Promise<IMessageBoxResult> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public showSaveDialog(_windowId: number, _options: SaveDialogOptions): Promise<string> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public showOpenDialog(_windowId: number, _options: OpenDialogOptions): Promise<string[]> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public reloadWindow(windowId: number, _args?: ParsedArgs): Promise<void> {
|
||||
return Promise.resolve(this.getWindowById(windowId).reload());
|
||||
}
|
||||
|
||||
public openDevTools(_windowId: number, _options?: IDevToolsOptions): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public toggleDevTools(_windowId: number): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public closeWorkspace(_windowId: number): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public enterWorkspace(_windowId: number, _path: string): Promise<IEnterWorkspaceResult> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public createAndEnterWorkspace(_windowId: number, _folders?: IWorkspaceFolderCreationData[], _path?: string): Promise<IEnterWorkspaceResult> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public saveAndEnterWorkspace(_windowId: number, _path: string): Promise<IEnterWorkspaceResult> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public toggleFullScreen(windowId: number): Promise<void> {
|
||||
const win = this.getWindowById(windowId);
|
||||
|
||||
return Promise.resolve(win.setFullScreen(!win.isFullScreen()));
|
||||
}
|
||||
|
||||
public setRepresentedFilename(windowId: number, fileName: string): Promise<void> {
|
||||
return Promise.resolve(this.getWindowById(windowId).setRepresentedFilename(fileName));
|
||||
}
|
||||
|
||||
public addRecentlyOpened(_files: URI[]): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public removeFromRecentlyOpened(_paths: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | URI | string)[]): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public clearRecentlyOpened(): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public getRecentlyOpened(_windowId: number): Promise<IRecentlyOpened> {
|
||||
// TODO: properly implement.
|
||||
return Promise.resolve({
|
||||
workspaces: [],
|
||||
files: [],
|
||||
});
|
||||
}
|
||||
|
||||
public focusWindow(windowId: number): Promise<void> {
|
||||
return Promise.resolve(this.getWindowById(windowId).focus());
|
||||
}
|
||||
|
||||
public closeWindow(_windowId: number): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public isFocused(windowId: number): Promise<boolean> {
|
||||
return Promise.resolve(this.getWindowById(windowId).isFocused());
|
||||
}
|
||||
|
||||
public isMaximized(_windowId: number): Promise<boolean> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public maximizeWindow(_windowId: number): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public unmaximizeWindow(_windowId: number): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public minimizeWindow(_windowId: number): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public onWindowTitleDoubleClick(_windowId: number): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public setDocumentEdited(_windowId: number, _flag: boolean): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public quit(): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public relaunch(_options: { addArgs?: string[], removeArgs?: string[] }): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
// macOS Native Tabs
|
||||
public newWindowTab(): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public showPreviousWindowTab(): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public showNextWindowTab(): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public moveWindowTabToNewWindow(): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public mergeAllWindowTabs(): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public toggleWindowTabsBar(): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
// macOS TouchBar
|
||||
public updateTouchBar(_windowId: number, _items: ISerializableCommandAction[][]): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
// Shared process
|
||||
public whenSharedProcessReady(): Promise<void> {
|
||||
// TODO: Update once shared process is tied in.
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public toggleSharedProcess(): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
// Global methods
|
||||
public openWindow(_windowId: number, _paths: URI[], _options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean, forceOpenWorkspaceAsFile?: boolean, args?: ParsedArgs }): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public openNewWindow(_options?: INewWindowOptions): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public showWindow(windowId: number): Promise<void> {
|
||||
return Promise.resolve(this.getWindowById(windowId).show());
|
||||
}
|
||||
|
||||
public getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public getWindowCount(): Promise<number> {
|
||||
return Promise.resolve(1);
|
||||
}
|
||||
|
||||
public log(_severity: string, ..._messages: string[]): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public showItemInFolder(_path: string): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public getActiveWindowId(): Promise<number | undefined> {
|
||||
return Promise.resolve(1);
|
||||
}
|
||||
|
||||
public openExternal(_url: string): Promise<boolean> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public startCrashReporter(_config: CrashReporterStartOptions): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public openAboutDialog(): Promise<void> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public resolveProxy(windowId: number, url: string): Promise<string | undefined> {
|
||||
return new Promise((resolve): void => {
|
||||
this.getWindowById(windowId).webContents.session.resolveProxy(url, (proxy) => {
|
||||
resolve(proxy);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get window by ID. For now this is always the current window.
|
||||
*/
|
||||
private getWindowById(_windowId: number): electron.BrowserWindow {
|
||||
return this.window;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
windowsIpc.WindowsChannelClient = WindowsService;
|
Reference in New Issue
Block a user