Skip to content

Commit 6e756d7

Browse files
committed
Check structure health befor range-format
1 parent de643b4 commit 6e756d7

File tree

4 files changed

+61
-21
lines changed

4 files changed

+61
-21
lines changed

src/calva-fmt/src/config.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,5 @@ function _updateConfig(): FormatConfig {
9090
export function onConfigurationChanged(e: vscode.ConfigurationChangeEvent) {
9191
if (e.affectsConfiguration("calva.fmt")) {
9292
updateConfig();
93-
if (e.affectsConfiguration("calva.fmt.experimental.inferParensAsYouType")) {
94-
const parinferOn = getConfig()['infer-parens-as-you-type'];
95-
docMirror.getDocuments().forEach((doc: docMirror.MirroredDocument, _key: any) => {
96-
doc.model.performInferParens = parinferOn;
97-
});
98-
}
9993
}
10094
}

src/cursor-doc/model.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ export interface EditableModel {
9999
*/
100100
edit: (edits: ModelEdit[], options: ModelEditOptions) => Thenable<boolean>;
101101
parinferReadiness: parinfer.ParinferReadiness,
102-
performInferParens: boolean;
103102
isWritable: boolean;
104103
getText: (start: number, end: number, mustBeWithin?: boolean) => string;
105104
getLineText: (line: number) => string;
@@ -487,3 +486,48 @@ export class LineInputModel implements EditableModel {
487486
}
488487

489488

489+
export class StringDocument implements EditableDocument {
490+
constructor(contents: string) {
491+
this.insertString(contents);
492+
}
493+
494+
selectionLeft: number;
495+
selectionRight: number;
496+
497+
get selection() {
498+
return new ModelEditSelection(this.selectionLeft, this.selectionRight);
499+
}
500+
501+
set selection(sel: ModelEditSelection) {
502+
this.selectionLeft = sel.anchor;
503+
this.selectionRight = sel.active;
504+
}
505+
506+
model: LineInputModel = new LineInputModel(1, this);
507+
508+
selectionStack: ModelEditSelection[] = [];
509+
510+
getTokenCursor(offset?: number, previous?: boolean): LispTokenCursor {
511+
return this.model.getTokenCursor(offset);
512+
};
513+
514+
insertString(text: string) {
515+
this.model.insertString(0, text);
516+
};
517+
518+
getSelectionText: () => string;
519+
520+
delete() {
521+
const p = this.selectionLeft;
522+
return this.model.edit([
523+
new ModelEdit('deleteRange', [p, 1])
524+
], { selection: new ModelEditSelection(p) });
525+
};
526+
527+
backspace() {
528+
const p = this.selectionLeft;
529+
return this.model.edit([
530+
new ModelEdit('deleteRange', [p - 1, 1])
531+
], { selection: new ModelEditSelection(p - 1) });
532+
};
533+
}

src/doc-mirror/index.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as vscode from "vscode"
33
import * as utilities from '../utilities';
44
import * as formatter from '../calva-fmt/src/format';
55
import { LispTokenCursor } from "../cursor-doc/token-cursor";
6-
import { ModelEdit, EditableDocument, EditableModel, ModelEditOptions, LineInputModel, ModelEditSelection } from "../cursor-doc/model";
6+
import { ModelEdit, EditableDocument, EditableModel, ModelEditOptions, LineInputModel, ModelEditSelection, StringDocument } from "../cursor-doc/model";
77
import * as parinfer from "../calva-fmt/src/infer";
88
import * as formatConfig from '../calva-fmt/src/config';
99
import statusbar from '../statusbar';
@@ -29,8 +29,6 @@ export class DocumentModel implements EditableModel {
2929
this._parinferReadiness = readiness;
3030
}
3131

32-
performInferParens = formatConfig.getConfig()["infer-parens-as-you-type"];
33-
3432
isWritable = false;
3533

3634
constructor(private document: MirroredDocument) {
@@ -43,9 +41,6 @@ export class DocumentModel implements EditableModel {
4341
const undoStopBefore = !!options.undoStopBefore;
4442
return editor.edit(builder => {
4543
for (const modelEdit of modelEdits) {
46-
if (!options.performInferParens) {
47-
this.document.model.performInferParens = false;
48-
}
4944
switch (modelEdit.editFn) {
5045
case 'insertString':
5146
this.insertEdit.apply(this, [builder, ...modelEdit.args]);
@@ -116,6 +111,9 @@ export class DocumentModel implements EditableModel {
116111
export class MirroredDocument implements EditableDocument {
117112
constructor(public document: vscode.TextDocument) { }
118113

114+
parensInferred = false;
115+
rangeFormatted = false;
116+
119117
get selectionLeft(): number {
120118
return this.document.offsetAt(vscode.window.activeTextEditor.selection.anchor);
121119
}
@@ -180,7 +178,7 @@ function processChanges(event: vscode.TextDocumentChangeEvent) {
180178
const parinferOn = formatConfig.getConfig()["infer-parens-as-you-type"];
181179
const formatAsYouTypeOn = formatConfig.getConfig()["format-as-you-type"];
182180
const performFormatAsYouType = formatAsYouTypeOn && event.reason != vscode.TextDocumentChangeReason.Undo;
183-
const performInferParens = parinferOn && event.reason != vscode.TextDocumentChangeReason.Undo && model.performInferParens;
181+
const performInferParens = parinferOn && event.reason != vscode.TextDocumentChangeReason.Undo && !mirroredDoc.parensInferred;
184182
let performHealthCheck = !performFormatAsYouType;
185183
const edits: ModelEdit[] = event.contentChanges.map(change => {
186184
// vscode may have a \r\n marker, so it's line offsets are all wrong.
@@ -192,20 +190,27 @@ function processChanges(event: vscode.TextDocumentChangeEvent) {
192190
performInferParens: !vscode.TextDocumentChangeReason.Undo
193191
}).then(async _v => {
194192
if (event.document === vscode.window.activeTextEditor?.document) {
195-
if (performFormatAsYouType) {
193+
if (performFormatAsYouType && !mirroredDoc.rangeFormatted) {
196194
if (event.contentChanges.length === 1 && event.contentChanges[0].text.match(/[\[\](){}]/)) {
197195
const change = event.contentChanges[0];
198196
const start = event.document.offsetAt(change.range.start);
199197
const formatForwardIndex = formatter.indexForFormatForward(mirroredDoc);
200198
const end = formatForwardIndex !== mirroredDoc.selection.active ? formatForwardIndex + 1 : mirroredDoc.selection.active;
201-
await formatter.formatRangeEditableDoc(mirroredDoc, [start, end], true);
199+
const checkDoc = new StringDocument(mirroredDoc.model.getText(start, end));
200+
if (parinfer.getParinferReadiness(checkDoc).isStructureHealthy) {
201+
await formatter.formatRangeEditableDoc(mirroredDoc, [start, end], true);
202+
} else {
203+
await formatter.formatForward(mirroredDoc);
204+
}
205+
mirroredDoc.rangeFormatted = true;
202206
} else {
203207
await formatter.formatForward(mirroredDoc);
204208
}
205209
performHealthCheck = true;
206210
}
207211
if ((mirroredDoc.model.parinferReadiness.isIndentationHealthy || performHealthCheck) && performInferParens) {
208212
await parinfer.inferParens(mirroredDoc);
213+
mirroredDoc.parensInferred = true;
209214
}
210215
if (!performFormatAsYouType) {
211216
performHealthCheck = true;
@@ -216,9 +221,8 @@ function processChanges(event: vscode.TextDocumentChangeEvent) {
216221
statusBar.update(vscode.window.activeTextEditor?.document);
217222
}
218223
});
219-
if (event.contentChanges.length > 0) {
220-
model.performInferParens = formatConfig.getConfig()["infer-parens-as-you-type"];
221-
}
224+
mirroredDoc.parensInferred = false;
225+
mirroredDoc.rangeFormatted = false;
222226
model.lineInputModel.flushChanges()
223227

224228
// we must clear out the repaint cache data, since we don't use it.

src/extension-test/unit/common/mock.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import { LispTokenCursor } from '../../../cursor-doc/token-cursor'
44
model.initScanner(20000);
55

66
export class MockDocument implements model.EditableDocument {
7-
isIndentationHealthy = true;
8-
isStructureHealthy = true;
97
selectionLeft: number;
108
selectionRight: number;
119

0 commit comments

Comments
 (0)