Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

vscode-zap

Package Overview
Dependencies
Maintainers
1
Versions
107
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

vscode-zap - npm Package Compare versions

Comparing version 0.0.12 to 0.0.13

out/src/workspace.d.ts

38

out/src/controller.d.ts
import { Client, ClientOptions, ServerOptions } from "libzap/lib/remote/client";
import { Client as OTClient } from "libzap/lib/ot/client";
import { WorkspaceOp } from "libzap/lib/ot/workspace";
import { OperationalTransformationHandler, RefIdentifier } from "libzap/lib/remote/ot";
import { Handler } from "libzap/lib/remote/handler";
import { RefIdentifier, RefInfoResult } from "libzap/lib/remote/protocol";
import * as environment from "./environment";
export interface RefInfo {
repo: string;
ref: string;
base: string;
branch: string;
}
export interface WatchRefOptions {
create: boolean;
reset: boolean;
}
export declare class Controller {

@@ -21,25 +10,10 @@ private serverOptions;

client: Client;
otClient: OTClient;
otHandler: OperationalTransformationHandler;
handler: Handler;
private toDispose;
private ignoreSelectionChange;
private suppressRecord;
private suppressRecordEdit?;
private outputChannel;
constructor(serverOptions: ServerOptions, clientOptions: ClientOptions, environment: environment.IEnvironment);
dispose(): void;
start(refID?: RefIdentifier): Thenable<void>;
attachWorkspace(refID: RefIdentifier, workspaceEnvironment: environment.IEnvironment): Thenable<void>;
queryRefInfo(refID: RefIdentifier): Thenable<RefInfoResult>;
start(): Thenable<void>;
stop(): Thenable<void>;
private initHooks();
private onDidChangeActiveTextEditor(editor);
private onDidChangeTextEditorSelection(ev);
private onDidOpenTextDocument(doc);
private onDidCloseTextDocument(doc);
private recordSelection(doc, sel);
private documentDirty;
private onDidChangeTextDocument(ev);
private onDidSaveTextDocument(doc);
private onWillSaveTextDocument(event);
private recordOp(op);
applyOp(op: WorkspaceOp): Promise<void>;
}
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
const client_1 = require("libzap/lib/remote/client");
const client_2 = require("libzap/lib/ot/client");
const workspace_1 = require("libzap/lib/ot/workspace");
const protocol_1 = require("libzap/lib/workspace/protocol");
const ot_1 = require("libzap/lib/remote/ot");
const op_1 = require("./op");
const environment = require("./environment");
const handler_1 = require("libzap/lib/remote/handler");
const protocol_1 = require("libzap/lib/remote/protocol");
const workspace_1 = require("./workspace");
class Controller {

@@ -23,14 +12,7 @@ constructor(serverOptions, clientOptions, environment) {

this.toDispose = [];
this.ignoreSelectionChange = new Map();
this.suppressRecord = false;
this.documentDirty = new Map();
this.outputChannel = environment.createOutputChannel("zap controller");
// this.toDispose.push(this.outputChannel);// TODO(sqs): add this
this.client = new client_1.Client(this.serverOptions, this.clientOptions);
this.otClient = new client_2.Client();
this.otClient.apply = op => this.applyOp(op);
this.otHandler = new ot_1.OperationalTransformationHandler(this.client, this.otClient);
this.toDispose.push(this.otHandler);
this.handler = new handler_1.Handler(this.client);
this.toDispose.push(this.handler);
// Register client features.
this.client.registerHandler(ot_1.OperationalTransformationHandler.id, this.otHandler);
this.client.registerHandler(handler_1.Handler.id, this.handler);
}

@@ -43,21 +25,19 @@ dispose() {

}
start(refID) {
attachWorkspace(refID, workspaceEnvironment) {
return this.start().then(() => {
return this.handler.repoWatch({ repo: refID.repo, refspec: "*" }).then(() => {
return this.handler.attachWorkspace(refID, new workspace_1.Workspace(workspaceEnvironment));
});
});
}
queryRefInfo(refID) {
return this.client.sendRequest(protocol_1.RefInfoRequest.type, refID);
}
start() {
if (!this.client.needsStart()) {
return Promise.resolve();
}
return this.client.start().initialStart.then(() => __awaiter(this, void 0, void 0, function* () {
// TODO(sqs): handle refID better, and allowing controller
// to be used for multiple refs.
if (refID) {
this.otHandler.refIdentifier = refID;
yield this.client.sendRequest(ot_1.RepoWatchRequest.type, { repo: refID.repo, refspec: refID.ref });
const info = yield this.client.sendRequest(ot_1.RefInfoRequest.type, refID);
this.otHandler.refState = info.state;
this.otHandler.refTarget = info.target;
this.initHooks();
}
})).then((v) => v, (err) => {
this.outputChannel.appendLine(`Controller start failed: ${err}`);
this.outputChannel.show(true);
});
const { initialStart, disposable } = this.client.start();
this.toDispose.push(disposable);
return initialStart;
}

@@ -70,201 +50,4 @@ stop() {

}
initHooks() {
this.toDispose.push(this.environment.onDidChangeActiveTextEditor(e => this.onDidChangeActiveTextEditor(e)));
this.toDispose.push(this.environment.onDidChangeTextDocument(e => this.onDidChangeTextDocument(e)));
this.toDispose.push(this.environment.onDidChangeTextEditorSelection(e => this.onDidChangeTextEditorSelection(e)));
this.toDispose.push(this.environment.onDidCloseTextDocument(e => this.onDidCloseTextDocument(e)));
this.toDispose.push(this.environment.onDidOpenTextDocument(e => this.onDidOpenTextDocument(e)));
this.toDispose.push(this.environment.onWillSaveTextDocument(e => this.onWillSaveTextDocument(e)));
this.toDispose.push(this.environment.onDidSaveTextDocument(e => this.onDidSaveTextDocument(e)));
// Handle documents/editors that are open initially.
for (let doc of this.environment.textDocuments) {
this.onDidOpenTextDocument(doc);
}
for (let editor of this.environment.visibleTextEditors) {
this.onDidChangeTextEditorSelection({ textEditor: editor, selections: editor.selections });
}
}
onDidChangeActiveTextEditor(editor) {
if (editor) {
this.onDidChangeTextEditorSelection({
textEditor: editor,
selections: editor.selections || [environment.constructors.Selection(environment.constructors.Position(0, 0), environment.constructors.Position(0, 0))],
});
}
for (const otherEditor of this.environment.visibleTextEditors) {
if (!editor || otherEditor.document.uri.toString() !== editor.document.uri.toString()) {
this.recordSelection(otherEditor.document, null);
}
}
}
onDidChangeTextEditorSelection(ev) {
if (!this.environment.getWorkspaceConfiguration("zap", "share.selections")) {
return;
}
const doc = ev.textEditor.document;
// Ignore selection changes that were caused by edits. E.g., typing "x" inserts "x" into the document
// and causes the insertion cursor to move by one letter. zap already accounts for cursor movement due
// to edits, so if we emitted a sel op, it would move the cursor by two positions (incorrectly).
if (this.ignoreSelectionChange.get(doc.uri) === doc.version) {
this.ignoreSelectionChange.delete(doc.uri);
return;
}
return this.recordSelection(doc, ev.textEditor.selections[0]);
}
onDidOpenTextDocument(doc) {
// If file is dirty, create the buffered file.
const fileName = this.environment.asRelativePath(doc.uri);
if (fileName === null) {
return;
}
if (this.environment.textDocumentIsDirtyHack(doc)) {
console.log("WARNING: doc is dirty but we currently have no way of diffing in JS");
}
}
onDidCloseTextDocument(doc) {
// Clear selection.
this.recordSelection(doc, null);
// Remove buffered file.
const fileName = this.environment.asRelativePath(doc.uri);
if (fileName === null) {
return;
}
this.recordOp({ delete: [`#${fileName}`] });
}
recordSelection(doc, sel) {
if (!this.environment.getWorkspaceConfiguration("zap", "share.selections")) {
return;
}
const fileName = this.environment.asRelativePath(doc.uri);
if (fileName === null) {
return;
}
this.recordOp({
sel: {
[fileName]: {
[process.env.ZAP_E2E_NAME || process.env.USER]: sel ? [doc.offsetAt(sel.anchor), doc.offsetAt(sel.active)] : null,
},
},
});
}
onDidChangeTextDocument(ev) {
const doc = ev.document;
const fileName = this.environment.asRelativePath(doc.uri);
if (fileName === null) {
return;
}
for (let change of ev.contentChanges) {
// For some reason, it sometimes triggers noop deletions
// and (re)additions of the whole file. Suppress these.
if (change.range.start.line === 0 && change.range.start.character === 0 &&
change.rangeLength === ev.document.getText().length &&
change.text === ev.document.getText()) {
continue;
}
// Suppress recording ops that we ourselves applied (in the apply method).
if (this.suppressRecordEdit && op_1.workspaceEditContains(this.suppressRecordEdit, doc.uri, { range: change.range, newText: change.text })) {
continue;
}
// Store information about this change so we can suppress selection events that are caused by this edit.
this.ignoreSelectionChange.set(doc.uri, doc.version);
const wasDirty = this.documentDirty.get(doc.uri.toString());
const isDirty = this.environment.textDocumentIsDirtyHack(doc);
this.documentDirty.set(doc.uri.toString(), isDirty);
const op = {
edit: {
[`#${fileName}`]: op_1.editOpsFromContentChange(doc, change),
},
};
if (isDirty && !wasDirty) {
op.copy = { [`#${fileName}`]: `/${fileName}` };
}
const msg = `Change ${doc.uri.toString()}: ${JSON.stringify(op_1.editOpsFromContentChange(doc, change))} dirty=${isDirty} wasDirty=${wasDirty} contents=${JSON.stringify(doc.getText())}`;
console.log(msg);
this.outputChannel.appendLine(msg);
this.recordOp(op);
}
}
onDidSaveTextDocument(doc) {
if (this.suppressRecord) {
return;
}
const fileName = this.environment.asRelativePath(doc.uri);
if (fileName === null) {
return;
}
this.recordOp({ save: [`#${fileName}`] });
this.documentDirty.set(doc.uri.toString(), false);
}
// onWillSaveTextDocument notifies the workspace watcher that a
// save op will be sent soon and to ignore all edits to the file
// until the next save op is received. This lets us avoid the
// problem of duplicate ops being created when you save a file in
// your editor (both the "save" op and from the file system
// watcher's "edit" op).
onWillSaveTextDocument(event) {
const doc = event.document;
const fileName = this.environment.asRelativePath(doc.uri);
if (fileName === null) {
return;
}
event.waitUntil(this.client.sendRequest(protocol_1.WorkspaceWillSaveFileRequest.type, { uri: doc.uri.toString() })
.then(() => (void 0), (err) => {
this.outputChannel.appendLine(`Unable to notify local Zap server of imminent save: ${err}`);
}));
}
recordOp(op) {
this.otClient.record(op);
}
applyOp(op) {
return __awaiter(this, void 0, void 0, function* () {
if (op.save) {
this.suppressRecord = true;
try {
for (const file of op.save) {
const doc = this.environment.textDocuments.find(doc => this.environment.asRelativePath(doc.uri) === workspace_1.stripFileOrBufferPathPrefix(file));
if (doc) {
if (!(yield doc.save())) {
throw new Error(`failed to apply save op for file ${file}`);
}
this.documentDirty.set(doc.uri.toString(), false);
}
}
}
finally {
this.suppressRecord = false;
}
}
const edit = op_1.workspaceEditFromOp(this.environment.textDocuments, this.environment, op);
if (edit && edit.entries().length > 0) {
// Mark files with buffer changes as dirty.
for (const [uri] of edit.entries()) {
const file = this.environment.asRelativePath(uri);
this.documentDirty.set(uri.toString(), Boolean(op.edit[`#${file}`]));
}
this.suppressRecordEdit = edit;
yield this.environment.applyWorkspaceEdit(edit).then((ok) => {
this.suppressRecordEdit = undefined;
if (!ok) {
throw new Error(`applyWorkspaceEdit failed: ${JSON.stringify(op)}`);
}
}, (err) => {
this.suppressRecordEdit = undefined;
throw new Error(`applyWorkspaceEdit failed: ${err}`);
});
}
if (op.sel) {
for (const fileName in op.sel) {
if (op.sel.hasOwnProperty(fileName)) {
for (const userID in op.sel[fileName]) {
if (op.sel[fileName].hasOwnProperty(userID)) {
this.environment.setUserSelection(fileName, userID, op.sel[fileName][userID]);
}
}
}
}
}
});
}
}
exports.Controller = Controller;
//# sourceMappingURL=controller.js.map

@@ -23,5 +23,7 @@ import { Sel } from "libzap/lib/ot/workspace";

getWorkspaceConfiguration<T>(section: string, subsection: string): T;
executeCommand<T>(command: string, ...rest: any[]): Thenable<T | undefined>;
setUserSelection(fileName: string, userID: string, sel: Sel | null): void;
textDocumentIsDirtyHack(doc: TextDocument): boolean;
automaticallyApplyingFileSystemChanges: boolean;
revertTextDocument(doc: TextDocument): Thenable<void>;
}

@@ -106,2 +108,3 @@ export interface URI {

show(preserveFocus?: boolean): void;
dispose(): void;
}

@@ -108,0 +111,0 @@ export interface Event<T> {

@@ -77,3 +77,4 @@ "use strict";

function startAndMonitor(controller) {
controller.start({ repo: extensionEnvironment_1.default.rootURI.fsPath, ref: "HEAD" }).then(() => (void 0), () => {
const refID = { repo: extensionEnvironment_1.default.rootURI.fsPath, ref: "HEAD" };
controller.attachWorkspace(refID, extensionEnvironment_1.default).then(() => (void 0), () => {
vscode.window.showErrorMessage(`Zap failed to start.`);

@@ -80,0 +81,0 @@ });

@@ -78,2 +78,5 @@ "use strict";

}
executeCommand(command, ...rest) {
return vscode.commands.executeCommand(command, ...rest);
}
setUserSelection(fileName, userID, sel) {

@@ -106,2 +109,12 @@ const editor = vscode.window.visibleTextEditors.find(e => this.asRelativePath(e.document.uri) === fileName);

}
revertTextDocument(doc) {
const data = fs_1.readFileSync(doc.uri.fsPath, "utf8");
const edit = new vscode.WorkspaceEdit();
edit.replace(doc.uri, new vscode.Range(new vscode.Position(0, 0), doc.positionAt(doc.getText().length)), data);
return this.applyWorkspaceEdit(edit).then(() => {
return doc.save();
});
// return this.executeCommand("workbench.action.files.revert", doc.uri).then(() => {
// });
}
}

@@ -108,0 +121,0 @@ Object.defineProperty(exports, "__esModule", { value: true });

@@ -33,4 +33,5 @@ "use strict";

this._remoteClient.onDidChangeState((event) => {
exports.outputChannel.appendLine(`Status: ${client_1.State[event.oldState]} ⟶ ${client_1.State[event.newState]}`);
if (event.newState === client_1.State.Stopped) {
setWindowStatus(protocol_1.StatusType.StatusTypeError, "Stopped");
setWindowStatus(protocol_1.StatusType.StatusTypeError, "Offline");
}

@@ -37,0 +38,0 @@ else {

import * as vscode from "vscode";
export declare function activate(context: vscode.ExtensionContext): void;
export declare function openInBrowser(uri: vscode.Uri, sel: vscode.Selection | null, trackingEventName: "OpenFile" | "OpenAtCursor"): true | undefined;
export declare function openInBrowser(uri: vscode.Uri, sel: vscode.Selection | null, trackingEventName: "OpenFile" | "OpenAtCursor"): void;

@@ -24,21 +24,24 @@ "use strict";

const controller = vscode.extensions.getExtension("sqs.vscode-zap").exports;
if (!controller.otHandler.refIdentifier || !controller.otHandler.refState) {
vscode.window.showErrorMessage("Opening in Web browser failed: unable to determine Zap branch.");
return;
}
let repo = controller.otHandler.refIdentifier.repo;
const ref = controller.otHandler.refTarget;
const gitBranch = controller.otHandler.refState.gitBranch;
// HACK TODO(sqs): instead of doing this hack, need to get the remote repo
// name by examining the zap local repo's upstream/remote.
repo = repo.replace(/^.*\/(github\.com\/.*)$/, "$1");
let url = vscode.workspace.getConfiguration("zap").get("web.url") +
"/${REPO}@${GITBRANCH}/-/blob/${PATH}${QUERY}#${LINE}"
.replace("${REPO}", repo)
.replace("${GITBRANCH}", gitBranch)
.replace("${PATH}", vscode.workspace.asRelativePath(uri))
.replace("${QUERY}", `?_event=${trackingEventName}&_source=${versionString()}&tmpZapRef=${ref}`)
.replace("${LINE}", sel ? formatSelection(sel) : "");
open(url);
return true;
const refID = { repo: vscode.workspace.rootPath, ref: "HEAD" };
controller.queryRefInfo(refID).then((refInfo) => {
if (!refInfo.target || !refInfo.state) {
vscode.window.showErrorMessage("Opening in Web browser failed: unable to determine Zap branch.");
return;
}
let repo = refID.repo;
const ref = refInfo.target;
const gitBranch = refInfo.state.gitBranch;
// HACK TODO(sqs): instead of doing this hack, need to get the remote repo
// name by examining the zap local repo's upstream/remote.
repo = repo.replace(/^.*\/(github\.com\/.*)$/, "$1");
let url = vscode.workspace.getConfiguration("zap").get("web.url") +
"/${REPO}@${GITBRANCH}/-/blob/${PATH}${QUERY}#${LINE}"
.replace("${REPO}", repo)
.replace("${GITBRANCH}", gitBranch)
.replace("${PATH}", vscode.workspace.asRelativePath(uri))
.replace("${QUERY}", `?_event=${trackingEventName}&_source=${versionString()}&tmpZapRef=${ref}`)
.replace("${LINE}", sel ? formatSelection(sel) : "");
open(url);
return true;
});
}

@@ -45,0 +48,0 @@ exports.openInBrowser = openInBrowser;

@@ -215,2 +215,3 @@ "use strict";

{
label: "same (simple)",
a: () => {

@@ -229,2 +230,3 @@ const e = environment.constructors.WorkspaceEdit();

{
label: "same (opposite order)",
a: () => {

@@ -245,2 +247,3 @@ const e = environment.constructors.WorkspaceEdit();

{
label: "different",
a: () => {

@@ -247,0 +250,0 @@ const e = environment.constructors.WorkspaceEdit();

@@ -5,3 +5,3 @@ {

"description": "WIP",
"version": "0.0.12",
"version": "0.0.13",
"publisher": "sqs",

@@ -44,3 +44,3 @@ "preview": true,

"vscode-jsonrpc": "3.0.1-alpha.7",
"libzap": "^0.0.11"
"libzap": "^0.0.13"
},

@@ -47,0 +47,0 @@ "contributes": {

import { Client, ClientOptions, ServerOptions } from "libzap/lib/remote/client";
import { Client as OTClient } from "libzap/lib/ot/client";
import { WorkspaceOp, stripFileOrBufferPathPrefix } from "libzap/lib/ot/workspace";
import { WorkspaceWillSaveFileRequest, WorkspaceWillSaveFileParams } from "libzap/lib/workspace/protocol";
import { OperationalTransformationHandler, RefIdentifier, RepoWatchRequest, RefInfoRequest } from "libzap/lib/remote/ot";
import { editOpsFromContentChange, workspaceEditFromOp, workspaceEditContains } from "./op";
import { Handler } from "libzap/lib/remote/handler";
import { RefIdentifier, RefInfoResult, RefInfoRequest } from "libzap/lib/remote/protocol";
import * as environment from "./environment";
import { Workspace } from "./workspace";
export interface RefInfo {
repo: string;
ref: string;
base: string;
branch: string;
}
export interface WatchRefOptions {
create: boolean;
reset: boolean;
}
export class Controller {
public client: Client; // TODO(sqs): only public for testing
public otClient: OTClient;
public otHandler: OperationalTransformationHandler;
public client: Client;
public handler: Handler;
private toDispose: environment.IDisposable[] = [];
private ignoreSelectionChange = new Map<environment.URI, number>();
private suppressRecord: boolean = false;
private suppressRecordEdit?: environment.WorkspaceEdit;
private outputChannel: environment.OutputChannel;
constructor(

@@ -38,15 +17,8 @@ private serverOptions: ServerOptions,

) {
this.outputChannel = environment.createOutputChannel("zap controller");
// this.toDispose.push(this.outputChannel);// TODO(sqs): add this
this.client = new Client(this.serverOptions, this.clientOptions);
this.handler = new Handler(this.client);
this.toDispose.push(this.handler);
this.otClient = new OTClient();
this.otClient.apply = op => this.applyOp(op);
this.otHandler = new OperationalTransformationHandler(this.client, this.otClient);
this.toDispose.push(this.otHandler);
// Register client features.
this.client.registerHandler(OperationalTransformationHandler.id, this.otHandler);
this.client.registerHandler(Handler.id, this.handler);
}

@@ -61,245 +33,25 @@

public start(refID?: RefIdentifier): Thenable<void> {
if (!this.client.needsStart()) { return Promise.resolve(); }
return this.client.start().initialStart.then(async () => {
// TODO(sqs): handle refID better, and allowing controller
// to be used for multiple refs.
if (refID) {
this.otHandler.refIdentifier = refID;
await this.client.sendRequest(RepoWatchRequest.type, { repo: refID.repo, refspec: refID.ref });
const info = await this.client.sendRequest(RefInfoRequest.type, refID);
this.otHandler.refState = info.state;
this.otHandler.refTarget = info.target;
this.initHooks();
}
}).then((v) => v, (err) => {
this.outputChannel.appendLine(`Controller start failed: ${err}`);
this.outputChannel.show(true);
});
}
public stop(): Thenable<void> {
if (!this.client.needsStop()) { return Promise.resolve(); }
return this.client.stop();
}
private initHooks(): void {
this.toDispose.push(this.environment.onDidChangeActiveTextEditor(e => this.onDidChangeActiveTextEditor(e)));
this.toDispose.push(this.environment.onDidChangeTextDocument(e => this.onDidChangeTextDocument(e)));
this.toDispose.push(this.environment.onDidChangeTextEditorSelection(e => this.onDidChangeTextEditorSelection(e)));
this.toDispose.push(this.environment.onDidCloseTextDocument(e => this.onDidCloseTextDocument(e)));
this.toDispose.push(this.environment.onDidOpenTextDocument(e => this.onDidOpenTextDocument(e)));
this.toDispose.push(this.environment.onWillSaveTextDocument(e => this.onWillSaveTextDocument(e)));
this.toDispose.push(this.environment.onDidSaveTextDocument(e => this.onDidSaveTextDocument(e)));
// Handle documents/editors that are open initially.
for (let doc of this.environment.textDocuments) {
this.onDidOpenTextDocument(doc);
}
for (let editor of this.environment.visibleTextEditors) {
this.onDidChangeTextEditorSelection({ textEditor: editor, selections: editor.selections });
}
}
private onDidChangeActiveTextEditor(editor: environment.TextEditor | undefined): void {
if (editor) {
this.onDidChangeTextEditorSelection({
textEditor: editor,
selections: editor.selections || [environment.constructors.Selection(environment.constructors.Position(0, 0), environment.constructors.Position(0, 0))],
public attachWorkspace(refID: RefIdentifier, workspaceEnvironment: environment.IEnvironment): Thenable<void> {
return this.start().then(() => {
return this.handler.repoWatch({ repo: refID.repo, refspec: "*" }).then(() => {
return this.handler.attachWorkspace(refID, new Workspace(workspaceEnvironment));
});
}
for (const otherEditor of this.environment.visibleTextEditors) {
if (!editor || otherEditor.document.uri.toString() !== editor.document.uri.toString()) {
this.recordSelection(otherEditor.document, null);
}
}
}
private onDidChangeTextEditorSelection(ev: environment.TextEditorSelectionChangeEvent) {
if (!this.environment.getWorkspaceConfiguration<boolean>("zap", "share.selections")) {
return;
}
const doc = ev.textEditor.document;
// Ignore selection changes that were caused by edits. E.g., typing "x" inserts "x" into the document
// and causes the insertion cursor to move by one letter. zap already accounts for cursor movement due
// to edits, so if we emitted a sel op, it would move the cursor by two positions (incorrectly).
if (this.ignoreSelectionChange.get(doc.uri) === doc.version) {
this.ignoreSelectionChange.delete(doc.uri);
return;
}
return this.recordSelection(doc, ev.textEditor.selections[0]);
}
private onDidOpenTextDocument(doc: environment.TextDocument) {
// If file is dirty, create the buffered file.
const fileName = this.environment.asRelativePath(doc.uri);
if (fileName === null) {
return;
}
if (this.environment.textDocumentIsDirtyHack(doc)) {
console.log("WARNING: doc is dirty but we currently have no way of diffing in JS");
/// this.recordOp({ copy: { [`#${fileName}`]: `/${fileName}` } });
}
}
private onDidCloseTextDocument(doc: environment.TextDocument) {
// Clear selection.
this.recordSelection(doc, null);
// Remove buffered file.
const fileName = this.environment.asRelativePath(doc.uri);
if (fileName === null) {
return;
}
this.recordOp({ delete: [`#${fileName}`] });
}
private recordSelection(doc: environment.TextDocument, sel: environment.Selection | null): void {
if (!this.environment.getWorkspaceConfiguration<boolean>("zap", "share.selections")) {
return;
}
const fileName = this.environment.asRelativePath(doc.uri);
if (fileName === null) {
return;
}
this.recordOp({
sel: {
[fileName]: {
[process.env.ZAP_E2E_NAME || process.env.USER || "<no-name>"]: sel ? [doc.offsetAt(sel.anchor), doc.offsetAt(sel.active)] : null,
},
},
});
}
private documentDirty = new Map<string, boolean>();
private onDidChangeTextDocument(ev: environment.TextDocumentChangeEvent): void {
const doc = ev.document;
const fileName = this.environment.asRelativePath(doc.uri);
if (fileName === null) {
return;
}
for (let change of ev.contentChanges) {
// For some reason, it sometimes triggers noop deletions
// and (re)additions of the whole file. Suppress these.
if (change.range.start.line === 0 && change.range.start.character === 0 &&
change.rangeLength === ev.document.getText().length &&
change.text === ev.document.getText()) {
continue;
}
// Suppress recording ops that we ourselves applied (in the apply method).
if (this.suppressRecordEdit && workspaceEditContains(this.suppressRecordEdit, doc.uri, { range: change.range, newText: change.text })) {
continue;
}
// Store information about this change so we can suppress selection events that are caused by this edit.
this.ignoreSelectionChange.set(doc.uri, doc.version);
const wasDirty = this.documentDirty.get(doc.uri.toString());
const isDirty = this.environment.textDocumentIsDirtyHack(doc);
this.documentDirty.set(doc.uri.toString(), isDirty);
const op: WorkspaceOp = {
edit: {
[`#${fileName}`]: editOpsFromContentChange(doc, change),
},
};
if (isDirty && !wasDirty) {
op.copy = { [`#${fileName}`]: `/${fileName}` };
}
const msg = `Change ${doc.uri.toString()}: ${JSON.stringify(editOpsFromContentChange(doc, change))} dirty=${isDirty} wasDirty=${wasDirty} contents=${JSON.stringify(doc.getText())}`;
console.log(msg);
this.outputChannel.appendLine(msg);
this.recordOp(op);
}
public queryRefInfo(refID: RefIdentifier): Thenable<RefInfoResult> {
return this.client.sendRequest(RefInfoRequest.type, refID);
}
private onDidSaveTextDocument(doc: environment.TextDocument) {
if (this.suppressRecord) { return; }
const fileName = this.environment.asRelativePath(doc.uri);
if (fileName === null) {
return;
}
this.recordOp({ save: [`#${fileName}`] });
this.documentDirty.set(doc.uri.toString(), false);
public start(): Thenable<void> {
if (!this.client.needsStart()) { return Promise.resolve(); }
const {initialStart, disposable} = this.client.start();
this.toDispose.push(disposable);
return initialStart;
}
// onWillSaveTextDocument notifies the workspace watcher that a
// save op will be sent soon and to ignore all edits to the file
// until the next save op is received. This lets us avoid the
// problem of duplicate ops being created when you save a file in
// your editor (both the "save" op and from the file system
// watcher's "edit" op).
private onWillSaveTextDocument(event: environment.TextDocumentWillSaveEvent) {
const doc = event.document;
const fileName = this.environment.asRelativePath(doc.uri);
if (fileName === null) {
return;
}
event.waitUntil(
this.client.sendRequest(WorkspaceWillSaveFileRequest.type, { uri: doc.uri.toString() } as WorkspaceWillSaveFileParams)
.then(() => (void 0), (err) => {
this.outputChannel.appendLine(`Unable to notify local Zap server of imminent save: ${err}`);
}),
);
public stop(): Thenable<void> {
if (!this.client.needsStop()) { return Promise.resolve(); }
return this.client.stop();
}
private recordOp(op: WorkspaceOp): void {
this.otClient.record(op);
}
async applyOp(op: WorkspaceOp): Promise<void> {
if (op.save) {
this.suppressRecord = true;
try {
for (const file of op.save) {
const doc = this.environment.textDocuments.find(doc => this.environment.asRelativePath(doc.uri) === stripFileOrBufferPathPrefix(file));
if (doc) {
if (!await doc.save()) {
throw new Error(`failed to apply save op for file ${file}`);
}
this.documentDirty.set(doc.uri.toString(), false);
}
}
} finally {
this.suppressRecord = false;
}
}
const edit = workspaceEditFromOp(this.environment.textDocuments, this.environment, op);
if (edit && edit.entries().length > 0) {
// Mark files with buffer changes as dirty.
for (const [uri] of edit.entries()) {
const file: string = this.environment.asRelativePath(uri) !;
this.documentDirty.set(uri.toString(), Boolean(op.edit![`#${file}`]));
}
this.suppressRecordEdit = edit;
await this.environment.applyWorkspaceEdit(edit).then((ok) => {
this.suppressRecordEdit = undefined;
if (!ok) {
throw new Error(`applyWorkspaceEdit failed: ${JSON.stringify(op)}`);
}
}, (err) => {
this.suppressRecordEdit = undefined;
throw new Error(`applyWorkspaceEdit failed: ${err}`);
});
}
if (op.sel) {
for (const fileName in op.sel) {
if (op.sel.hasOwnProperty(fileName)) {
for (const userID in op.sel[fileName]) {
if (op.sel[fileName].hasOwnProperty(userID)) {
this.environment.setUserSelection(fileName, userID, op.sel[fileName][userID]);
}
}
}
}
}
}
}

@@ -67,2 +67,5 @@ import { Sel } from "libzap/lib/ot/workspace";

// vscode.commands.executeCommand
executeCommand<T>(command: string, ...rest: any[]): Thenable<T | undefined>;
////////////////////////////////////////////////////////////////////////////

@@ -88,2 +91,4 @@ // Everything below here is a custom interface that does not

automaticallyApplyingFileSystemChanges: boolean;
revertTextDocument(doc: TextDocument): Thenable<void>;
}

@@ -195,2 +200,3 @@

show(preserveFocus?: boolean): void;
dispose(): void;
}

@@ -197,0 +203,0 @@

@@ -80,3 +80,4 @@ import * as path from "path";

function startAndMonitor(controller: Controller): void {
controller.start({ repo: extensionEnvironment.rootURI!.fsPath, ref: "HEAD" }).then(() => (void 0), () => {
const refID = { repo: extensionEnvironment.rootURI!.fsPath, ref: "HEAD" };
controller.attachWorkspace(refID, extensionEnvironment).then(() => (void 0), () => {
vscode.window.showErrorMessage(`Zap failed to start.`);

@@ -83,0 +84,0 @@ });

@@ -82,2 +82,6 @@ import { sep as pathSeparator } from "path";

executeCommand<T>(command: string, ...rest: any[]): Thenable<T | undefined> {
return vscode.commands.executeCommand<T>(command, ...rest);
}
////////////////////////////////////////////////////////////////////////////

@@ -119,2 +123,17 @@ // internal sourcegraph-related things

automaticallyApplyingFileSystemChanges = true;
revertTextDocument(doc: environment.TextDocument): Thenable<any> {
const data = readFileSync(doc.uri.fsPath, "utf8");
const edit = new vscode.WorkspaceEdit();
edit.replace(
doc.uri as vscode.Uri,
new vscode.Range(new vscode.Position(0, 0), doc.positionAt(doc.getText().length) as vscode.Position),
data,
);
return this.applyWorkspaceEdit(edit).then(() => {
return doc.save();
});
// return this.executeCommand("workbench.action.files.revert", doc.uri).then(() => {
// });
}
}

@@ -121,0 +140,0 @@

@@ -47,4 +47,5 @@ import * as vscode from "vscode";

this._remoteClient.onDidChangeState((event: StateChangeEvent) => {
outputChannel.appendLine(`Status: ${State[event.oldState]} ⟶ ${State[event.newState]}`);
if (event.newState === State.Stopped) {
setWindowStatus(StatusType.StatusTypeError, "Stopped");
setWindowStatus(StatusType.StatusTypeError, "Offline");
} else {

@@ -51,0 +52,0 @@ setWindowStatus(StatusType.StatusTypeOK, "Online");

@@ -30,23 +30,26 @@ import * as fs from "fs";

const controller: Controller = vscode.extensions.getExtension("sqs.vscode-zap").exports;
if (!controller.otHandler.refIdentifier || !controller.otHandler.refState) {
vscode.window.showErrorMessage("Opening in Web browser failed: unable to determine Zap branch.");
return;
}
let repo = controller.otHandler.refIdentifier.repo;
const ref = controller.otHandler.refTarget;
const gitBranch = controller.otHandler.refState.gitBranch;
const refID = { repo: vscode.workspace.rootPath, ref: "HEAD" };
controller.queryRefInfo(refID).then((refInfo) => {
if (!refInfo.target || !refInfo.state) {
vscode.window.showErrorMessage("Opening in Web browser failed: unable to determine Zap branch.");
return;
}
let repo = refID.repo;
const ref = refInfo.target;
const gitBranch = refInfo.state.gitBranch;
// HACK TODO(sqs): instead of doing this hack, need to get the remote repo
// name by examining the zap local repo's upstream/remote.
repo = repo.replace(/^.*\/(github\.com\/.*)$/, "$1");
// HACK TODO(sqs): instead of doing this hack, need to get the remote repo
// name by examining the zap local repo's upstream/remote.
repo = repo.replace(/^.*\/(github\.com\/.*)$/, "$1");
let url = vscode.workspace.getConfiguration("zap").get<string>("web.url") +
"/${REPO}@${GITBRANCH}/-/blob/${PATH}${QUERY}#${LINE}"
.replace("${REPO}", repo)
.replace("${GITBRANCH}", gitBranch)
.replace("${PATH}", vscode.workspace.asRelativePath(uri))
.replace("${QUERY}", `?_event=${trackingEventName}&_source=${versionString()}&tmpZapRef=${ref}`)
.replace("${LINE}", sel ? formatSelection(sel) : "");
open(url);
return true;
let url = vscode.workspace.getConfiguration("zap").get<string>("web.url") +
"/${REPO}@${GITBRANCH}/-/blob/${PATH}${QUERY}#${LINE}"
.replace("${REPO}", repo)
.replace("${GITBRANCH}", gitBranch)
.replace("${PATH}", vscode.workspace.asRelativePath(uri))
.replace("${QUERY}", `?_event=${trackingEventName}&_source=${versionString()}&tmpZapRef=${ref}`)
.replace("${LINE}", sel ? formatSelection(sel) : "");
open(url);
return true;
});
}

@@ -53,0 +56,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc