move stringDiff and make minal code, reuse for all format operations (doc, range, on type)
This commit is contained in:
parent
b2ae03678a
commit
a0a56c041f
|
@ -6,6 +6,20 @@
|
|||
|
||||
import {DiffChange} from 'vs/base/common/diff/diffChange';
|
||||
|
||||
|
||||
function createStringSequence(a: string): ISequence {
|
||||
|
||||
return {
|
||||
getLength() { return a.length; },
|
||||
getElementHash(pos: number) { return a[pos]; }
|
||||
};
|
||||
}
|
||||
|
||||
export function stringDiff(original: string, modified: string): IDiffChange[] {
|
||||
return new LcsDiff(createStringSequence(original), createStringSequence(modified)).ComputeDiff();
|
||||
}
|
||||
|
||||
|
||||
export interface ISequence {
|
||||
getLength(): number;
|
||||
getElementHash(index:number): string;
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import {TPromise} from 'vs/base/common/winjs.base';
|
||||
import {ISequence, LcsDiff, IDiffChange} from 'vs/base/common/diff/diff';
|
||||
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
|
||||
import {IThreadService} from 'vs/workbench/services/thread/common/threadService';
|
||||
import * as vscode from 'vscode';
|
||||
|
@ -325,18 +324,6 @@ class QuickFixAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
function createStringSequence(a: string): ISequence {
|
||||
|
||||
return {
|
||||
getLength() { return a.length; },
|
||||
getElementHash(pos: number) { return a[pos]; }
|
||||
};
|
||||
}
|
||||
|
||||
function stringDiff(a: string, b: string): IDiffChange[] {
|
||||
return new LcsDiff(createStringSequence(a), createStringSequence(b)).ComputeDiff();
|
||||
}
|
||||
|
||||
class DocumentFormattingAdapter {
|
||||
|
||||
private _documents: ExtHostDocuments;
|
||||
|
@ -352,43 +339,11 @@ class DocumentFormattingAdapter {
|
|||
const {document, version} = this._documents.getDocumentData(resource);
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideDocumentFormattingEdits(document, <any>options, token)).then(value => {
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
value = DocumentFormattingAdapter.minimizeTextEdits(document, version, value);
|
||||
return value.map(TypeConverters.TextEdit.from);
|
||||
return TypeConverters.TextEdit.minimalEditOperations(value, document, version);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// todo@joh find a better place for this
|
||||
// todo@joh reuse in other places
|
||||
static minimizeTextEdits(document: vscode.TextDocument, beforeVersion: number, edits: vscode.TextEdit[]): vscode.TextEdit[] {
|
||||
if (document.version !== beforeVersion) {
|
||||
return edits;
|
||||
}
|
||||
|
||||
const result: vscode.TextEdit[] = [];
|
||||
|
||||
for (let i = 0; i < edits.length; i++) {
|
||||
const original = document.getText(edits[i].range);
|
||||
const modified = edits[i].newText;
|
||||
const changes = stringDiff(original, modified);
|
||||
|
||||
if (changes.length <= 1) {
|
||||
result.push(edits[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let j = 0; j < changes.length; j++) {
|
||||
const {originalStart, originalLength, modifiedStart, modifiedLength} = changes[j];
|
||||
const range = new Range(<any> document.positionAt(originalStart), <any> document.positionAt(originalStart + originalLength));
|
||||
const newText = modified.substr(modifiedStart, modifiedLength);
|
||||
result.push({ range, newText });
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class RangeFormattingAdapter {
|
||||
|
@ -403,12 +358,12 @@ class RangeFormattingAdapter {
|
|||
|
||||
provideDocumentRangeFormattingEdits(resource: URI, range: IRange, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
|
||||
|
||||
let doc = this._documents.getDocumentData(resource).document;
|
||||
let ran = TypeConverters.toRange(range);
|
||||
const {document, version} = this._documents.getDocumentData(resource);
|
||||
const ran = TypeConverters.toRange(range);
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideDocumentRangeFormattingEdits(doc, ran, <any>options, token)).then(value => {
|
||||
return asWinJsPromise(token => this._provider.provideDocumentRangeFormattingEdits(document, ran, <any>options, token)).then(value => {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(TypeConverters.TextEdit.from);
|
||||
return TypeConverters.TextEdit.minimalEditOperations(value, document, version);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -428,12 +383,12 @@ class OnTypeFormattingAdapter {
|
|||
|
||||
provideOnTypeFormattingEdits(resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
|
||||
|
||||
let doc = this._documents.getDocumentData(resource).document;
|
||||
let pos = TypeConverters.toPosition(position);
|
||||
const {document, version} = this._documents.getDocumentData(resource);
|
||||
const pos = TypeConverters.toPosition(position);
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideOnTypeFormattingEdits(doc, pos, ch, <any> options, token)).then(value => {
|
||||
return asWinJsPromise(token => this._provider.provideOnTypeFormattingEdits(document, pos, ch, <any> options, token)).then(value => {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(TypeConverters.TextEdit.from);
|
||||
return TypeConverters.TextEdit.minimalEditOperations(value, document, version);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import {ExtHostCommands} from 'vs/workbench/api/node/extHostCommands';
|
|||
import Severity from 'vs/base/common/severity';
|
||||
import {isFalsyOrEmpty} from 'vs/base/common/arrays';
|
||||
import {IDisposable} from 'vs/base/common/lifecycle';
|
||||
import {stringDiff} from 'vs/base/common/diff/diff';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import * as types from './extHostTypes';
|
||||
import {Position as EditorPosition} from 'vs/platform/editor/common/editor';
|
||||
|
@ -154,6 +155,43 @@ export function fromRangeOrRangeWithMessage(ranges:vscode.Range[]|vscode.Decorat
|
|||
}
|
||||
|
||||
export const TextEdit = {
|
||||
|
||||
minimalEditOperations(edits: vscode.TextEdit[], document: vscode.TextDocument, beforeDocumentVersion: number): ISingleEditOperation[] {
|
||||
|
||||
// document has changed in the meantime and we shouldn't do
|
||||
// offset math as it's likely to be all wrong
|
||||
if (document.version !== beforeDocumentVersion) {
|
||||
return edits.map(TextEdit.from);
|
||||
}
|
||||
|
||||
const result: ISingleEditOperation[] = [];
|
||||
|
||||
for (let edit of edits) {
|
||||
|
||||
const original = document.getText(edit.range);
|
||||
const modified = edit.newText;
|
||||
const changes = stringDiff(original, modified);
|
||||
|
||||
if (changes.length <= 1) {
|
||||
result.push(TextEdit.from(edit));
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let j = 0; j < changes.length; j++) {
|
||||
const {originalStart, originalLength, modifiedStart, modifiedLength} = changes[j];
|
||||
const start = fromPosition(<types.Position> document.positionAt(originalStart));
|
||||
const end = fromPosition(<types.Position> document.positionAt(originalStart + originalLength));
|
||||
|
||||
result.push({
|
||||
text: modified.substr(modifiedStart, modifiedLength),
|
||||
range: { startLineNumber: start.lineNumber, startColumn: start.column, endLineNumber: end.lineNumber, endColumn: end.column }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
from(edit: vscode.TextEdit): ISingleEditOperation{
|
||||
return <ISingleEditOperation>{
|
||||
text: edit.newText,
|
||||
|
|
Loading…
Reference in a new issue