Skip to content

Commit 704b235

Browse files
committed
WIP
1 parent 51e5b9a commit 704b235

File tree

6 files changed

+98
-131
lines changed

6 files changed

+98
-131
lines changed

packages/@types/ot/index.d.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ declare module 'ot' {
22
export type SerializedTextOperation = (string | number)[];
33

44
class TextOperation {
5+
ops: SerializedTextOperation;
6+
57
delete(length: number): TextOperation;
68
insert(str: string): TextOperation;
79
retain(length: number): TextOperation;
@@ -13,9 +15,9 @@ declare module 'ot' {
1315
compose(operation: TextOperation): TextOperation;
1416

1517
static transform(left: TextOperation, right: TextOperation): TextOperation;
16-
static isRetain(operation: TextOperation): boolean;
17-
static isInsert(operation: TextOperation): boolean;
18-
static isDelete(operation: TextOperation): boolean;
18+
static isRetain(operation: string | number): boolean;
19+
static isInsert(operation: string | number): boolean;
20+
static isDelete(operation: string | number): boolean;
1921

2022
static fromJSON(operation: SerializedTextOperation): TextOperation;
2123
toJSON(): SerializedTextOperation;

packages/app/src/app/overmind/effects/vscode/ModelsHandler.ts

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export type ModuleModel = {
5555
selections: any[];
5656
currentLine: number;
5757
path: string;
58-
model: Promise<any>;
58+
model: null | any;
5959
comments: Array<{ commentId: string; range: [number, number] }>;
6060
currentCommentDecorations: string[];
6161
};
@@ -162,7 +162,7 @@ export class ModelsHandler {
162162

163163
this.updateUserSelections(module, moduleModel.selections);
164164

165-
const model = await moduleModel.model;
165+
const model = moduleModel.model;
166166

167167
if (COMMENTS) {
168168
const newDecorationComments = this.createCommentDecorations(
@@ -200,10 +200,10 @@ export class ModelsHandler {
200200
});
201201

202202
// Apply the decorations
203-
Object.keys(this.moduleModels).forEach(async path => {
203+
Object.keys(this.moduleModels).forEach(path => {
204204
const moduleModel = this.moduleModels[path];
205205
const relativePath = path.replace('/sandbox', '');
206-
const model = await moduleModel.model;
206+
const model = moduleModel.model;
207207

208208
if (!model) {
209209
return;
@@ -232,9 +232,9 @@ export class ModelsHandler {
232232
const newModelPath = '/sandbox' + newPath;
233233

234234
return Promise.all(
235-
Object.keys(this.moduleModels).map(async path => {
235+
Object.keys(this.moduleModels).map(path => {
236236
if (oldModelPath === path && this.moduleModels[path].model) {
237-
const model = await this.moduleModels[path].model;
237+
const model = this.moduleModels[path].model;
238238

239239
// This runs remove/add automatically
240240
return this.editorApi.textFileService.move(
@@ -266,17 +266,17 @@ export class ModelsHandler {
266266
// the model is actually resolved. This creates a "natural" queue
267267
if (!moduleModel.model) {
268268
if (modelEditor) {
269-
moduleModel.model = modelEditor.textModelReference.then(
269+
moduleModel.model = await modelEditor.textModelReference.then(
270270
ref => ref.object.textEditorModel
271271
);
272272
} else {
273-
moduleModel.model = this.editorApi.textFileService.models
273+
moduleModel.model = await this.editorApi.textFileService.models
274274
.loadOrCreate(this.monaco.Uri.file(moduleModel.path))
275275
.then(model => model.textEditorModel);
276276
}
277277
}
278278

279-
const model = await moduleModel.model;
279+
const model = moduleModel.model;
280280

281281
this.isApplyingOperation = true;
282282
this.applyOperationToModel(operation, false, model);
@@ -289,33 +289,43 @@ export class ModelsHandler {
289289
});
290290
}
291291

292-
public async setModuleCode(module: Module) {
292+
/**
293+
* Sets the code of a model in VSCode. This means that we directly change the in-memory
294+
* model and the user will immediately see the code.
295+
* @param module The module to apply the changes of
296+
* @param triggerChangeEvent Whether we should trigger this event to listeners listening to the model (for eg. live)
297+
*/
298+
public setModuleCode(module: Module, triggerChangeEvent = false) {
293299
const moduleModel = this.getModuleModelByPath(module.path);
294-
const model = await moduleModel.model;
300+
const model = moduleModel.model;
295301

296302
if (!model) {
297303
return;
298304
}
299305

300306
const oldCode = model.getValue();
301307
const changeOperation = getTextOperation(oldCode, module.code);
302-
this.isApplyingOperation = true;
308+
if (!triggerChangeEvent) {
309+
this.isApplyingOperation = true;
310+
}
303311
this.applyOperationToModel(changeOperation, false, model);
304-
this.isApplyingOperation = false;
312+
if (!triggerChangeEvent) {
313+
this.isApplyingOperation = false;
314+
}
305315
}
306316

307317
public clearUserSelections(userId: string) {
308318
const decorations = Object.keys(this.userSelectionDecorations).filter(d =>
309319
d.startsWith(userId)
310320
);
311-
Object.keys(this.moduleModels).forEach(async key => {
321+
Object.keys(this.moduleModels).forEach(key => {
312322
const moduleModel = this.moduleModels[key];
313323

314324
if (!moduleModel.model) {
315325
return;
316326
}
317327

318-
const model = await moduleModel.model;
328+
const model = moduleModel.model;
319329

320330
decorations.forEach(decorationId => {
321331
if (decorationId.startsWith(userId + model.id)) {
@@ -330,7 +340,7 @@ export class ModelsHandler {
330340

331341
nameTagTimeouts: { [name: string]: number } = {};
332342

333-
public async updateUserSelections(
343+
public updateUserSelections(
334344
module: Module,
335345
userSelections: EditorSelection[],
336346
showNameTag = true
@@ -343,7 +353,7 @@ export class ModelsHandler {
343353
return;
344354
}
345355

346-
const model = await moduleModel.model;
356+
const model = moduleModel.model;
347357
const lines = model.getLinesContent() || [];
348358

349359
userSelections.forEach((data: EditorSelection) => {
@@ -551,7 +561,7 @@ export class ModelsHandler {
551561
}
552562

553563
private applyOperationToModel(
554-
operation,
564+
operation: TextOperation,
555565
pushStack = false,
556566
model = this.editorApi.getActiveCodeEditor().getModel()
557567
) {
@@ -574,8 +584,9 @@ export class ModelsHandler {
574584
for (let i = 0; i < operation.ops.length; i++) {
575585
const op = operation.ops[i];
576586
if (TextOperation.isRetain(op)) {
577-
index += op;
587+
index += op as number;
578588
} else if (TextOperation.isInsert(op)) {
589+
const textOp = op as string;
579590
const { lineNumber, column } = indexToLineAndColumn(
580591
model.getValue().split(/\n/) || [],
581592
index
@@ -588,8 +599,8 @@ export class ModelsHandler {
588599
);
589600

590601
// if there's a new line
591-
if (/\n/.test(op)) {
592-
const eol = /\r\n/.test(op) ? 2 : 1;
602+
if (/\n/.test(textOp)) {
603+
const eol = /\r\n/.test(textOp) ? 2 : 1;
593604
if (eol !== currentEOLLength) {
594605
// With this insert the EOL of the document changed on the other side. We need
595606
// to accomodate our EOL to it.
@@ -599,13 +610,14 @@ export class ModelsHandler {
599610

600611
results.push({
601612
range,
602-
text: op,
613+
text: textOp,
603614
forceMoveMarkers: true,
604615
});
605616
} else if (TextOperation.isDelete(op)) {
617+
const delOp = op as number;
606618
const lines = model.getValue().split(/\n/) || [];
607619
const from = indexToLineAndColumn(lines, index);
608-
const to = indexToLineAndColumn(lines, index - op);
620+
const to = indexToLineAndColumn(lines, index - delOp);
609621
results.push({
610622
range: new this.monaco.Range(
611623
from.lineNumber,
@@ -615,7 +627,7 @@ export class ModelsHandler {
615627
),
616628
text: '',
617629
});
618-
index -= op;
630+
index -= delOp;
619631
}
620632
}
621633

packages/app/src/app/overmind/effects/vscode/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,12 +473,12 @@ export class VSCodeEffect {
473473
}
474474
}
475475

476-
public async setModuleCode(module: Module) {
476+
public setModuleCode(module: Module, triggerChangeEvent = false) {
477477
if (!this.modelsHandler) {
478478
return;
479479
}
480480

481-
await this.modelsHandler.setModuleCode(module);
481+
this.modelsHandler.setModuleCode(module, triggerChangeEvent);
482482
}
483483

484484
public async closeAllTabs() {

packages/app/src/app/overmind/namespaces/editor/actions.ts

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -354,12 +354,17 @@ export const codeChanged: Action<{
354354
return;
355355
}
356356

357+
// If the module is already synced we don't want to save an event, because operations
358+
// should not be used to sync saved state, only dirty state. Saved state is handled by
359+
// other means.
360+
const isSynced = getSavedCode(module.code, module.savedCode) === module.code;
361+
357362
// module.code !== code check is there to make sure that we don't end up sending
358363
// duplicate updates to live. module.code === code only when VSCode detected a change
359364
// from the filesystem (fs changed, vscode sees it, sends update). If this happens we
360365
// never want to send that code update, since this actual code change goes through this
361366
// specific code flow already.
362-
if (state.live.isLive && module.code !== code) {
367+
if (state.live.isLive && module.code !== code && !isSynced) {
363368
let operation: TextOperation;
364369
if (event) {
365370
logBreadcrumb({
@@ -623,28 +628,6 @@ export const tabMoved: Action<{
623628
state.editor.tabs.splice(nextIndex, 0, tab);
624629
};
625630

626-
export const prettifyClicked: AsyncAction = async ({
627-
state,
628-
effects,
629-
actions,
630-
}) => {
631-
effects.analytics.track('Prettify Code');
632-
const module = state.editor.currentModule;
633-
if (!module.id) {
634-
return;
635-
}
636-
const newCode = await effects.prettyfier.prettify(
637-
module.id,
638-
module.title,
639-
module.code || ''
640-
);
641-
642-
actions.editor.codeChanged({
643-
code: newCode,
644-
moduleShortid: module.shortid,
645-
});
646-
};
647-
648631
// TODO(@CompuIves): Look into whether we even want to call this function.
649632
// We can probably call the dispatch from the bundler itself instead.
650633
export const errorsCleared: Action = ({ state, effects }) => {

packages/app/src/app/overmind/namespaces/editor/internalActions.ts

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,6 @@ export const saveCode: AsyncAction<{
142142

143143
const savedCode =
144144
updatedModule.code === module.code ? null : updatedModule.code;
145-
if (savedCode === undefined) {
146-
logBreadcrumb({
147-
type: 'error',
148-
message: `SETTING UNDEFINED SAVEDCODE FOR CODE: ${updatedModule.code}`,
149-
});
150-
captureException(new Error('SETTING UNDEFINED SAVEDCODE'));
151-
}
152145

153146
module.savedCode = savedCode;
154147

@@ -268,7 +261,7 @@ export const updateCurrentTemplate: AsyncAction = async ({
268261
};
269262

270263
export const removeNpmDependencyFromPackageJson: AsyncAction<string> = async (
271-
{ state, actions },
264+
{ state, actions, effects },
272265
name
273266
) => {
274267
if (
@@ -282,9 +275,22 @@ export const removeNpmDependencyFromPackageJson: AsyncAction<string> = async (
282275

283276
delete packageJson.dependencies[name];
284277

278+
const code = JSON.stringify(packageJson, null, 2);
279+
const moduleShortid = state.editor.currentPackageJSON.shortid;
280+
const module = state.editor.currentSandbox.modules.find(
281+
m => m.shortid === moduleShortid
282+
);
283+
284+
if (!module) {
285+
return;
286+
}
287+
288+
effects.vscode.setModuleCode({ ...module, code }, true);
289+
module.code = code;
290+
285291
await actions.editor.codeSaved({
286-
code: JSON.stringify(packageJson, null, 2),
287-
moduleShortid: state.editor.currentPackageJSON.shortid,
292+
code,
293+
moduleShortid,
288294
cbID: null,
289295
});
290296
};
@@ -293,7 +299,7 @@ export const addNpmDependencyToPackageJson: AsyncAction<{
293299
name: string;
294300
version?: string;
295301
isDev: boolean;
296-
}> = async ({ state, actions }, { name, isDev, version }) => {
302+
}> = async ({ state, actions, effects }, { name, isDev, version }) => {
297303
if (
298304
!state.editor.currentPackageJSONCode ||
299305
!state.editor.currentPackageJSON
@@ -309,9 +315,23 @@ export const addNpmDependencyToPackageJson: AsyncAction<{
309315
packageJson[type][name] = version || 'latest';
310316
packageJson[type] = sortObjectByKeys(packageJson[type]);
311317

318+
const code = JSON.stringify(packageJson, null, 2);
319+
const moduleShortid = state.editor.currentPackageJSON.shortid;
320+
321+
const module = state.editor.currentSandbox.modules.find(
322+
m => m.shortid === moduleShortid
323+
);
324+
325+
if (!module) {
326+
return;
327+
}
328+
329+
effects.vscode.setModuleCode({ ...module, code }, true);
330+
module.code = code;
331+
312332
await actions.editor.codeSaved({
313-
code: JSON.stringify(packageJson, null, 2),
314-
moduleShortid: state.editor.currentPackageJSON.shortid,
333+
code,
334+
moduleShortid,
315335
cbID: null,
316336
});
317337
};
@@ -474,6 +494,7 @@ export const setCurrentModule: AsyncAction<Module> = async (
474494

475495
export const updateSandboxPackageJson: AsyncAction = async ({
476496
state,
497+
effects,
477498
actions,
478499
}) => {
479500
const sandbox = state.editor.currentSandbox;
@@ -499,6 +520,17 @@ export const updateSandboxPackageJson: AsyncAction = async ({
499520
const code = JSON.stringify(parsed, null, 2);
500521
const moduleShortid = state.editor.currentPackageJSON.shortid;
501522

523+
const module = state.editor.currentSandbox.modules.find(
524+
m => m.shortid === moduleShortid
525+
);
526+
527+
if (!module) {
528+
return;
529+
}
530+
531+
effects.vscode.setModuleCode({ ...module, code }, true);
532+
module.code = code;
533+
502534
await actions.editor.codeSaved({
503535
code,
504536
moduleShortid,
@@ -518,6 +550,10 @@ export const updateDevtools: AsyncAction<{
518550
state.editor.modulesByPath['/.codesandbox/workspace.json'];
519551

520552
if (devtoolsModule) {
553+
actions.editor.codeChanged({
554+
moduleShortid: devtoolsModule.shortid,
555+
code,
556+
});
521557
await actions.editor.codeSaved({
522558
code,
523559
moduleShortid: devtoolsModule.shortid,

0 commit comments

Comments
 (0)