Improve code selection and undo, add tests (#10160)

This commit is contained in:
Chris LaFreniere
2020-04-28 16:26:23 -07:00
committed by GitHub
parent fb1fbb214d
commit 98f3f57f77
2 changed files with 97 additions and 44 deletions

View File

@@ -85,30 +85,9 @@ export class MarkdownTextTransformer {
let markdownLineType = this.getMarkdownLineType(type);
isUndo = this.isUndoOperation(selection, type, markdownLineType, editorModel);
if (isUndo) {
if (markdownLineType === MarkdownLineType.BEGIN_AND_END_LINES) {
startRange = this.getIRangeWithOffsets(startRange, -1 * beginInsertedCode.length, 0, 0, 0);
endRange = this.getIRangeWithOffsets(endRange, 0, 0, endInsertedCode.length, 0);
editorModel.pushEditOperations(selections, [{ range: endRange, text: '' }, { range: startRange, text: '' }], null);
} else {
let operations: IIdentifiedSingleEditOperation[] = [];
startRange = this.getIRangeWithOffsets(startRange, 0, 0, beginInsertedCode.length, 0);
for (let i = 0; i < selection.endLineNumber - selection.startLineNumber + 1; i++) {
operations.push({ range: this.transformRangeByLineOffset(startRange, i), text: '' });
}
editorModel.pushEditOperations(selections, operations, null);
}
this.handleUndoOperation(markdownLineType, startRange, endRange, editorModel, beginInsertedCode, endInsertedCode, selections, selection);
} else {
// If the markdown we're inserting only needs to be added to the begin and end lines, add those edit operations directly
if (markdownLineType === MarkdownLineType.BEGIN_AND_END_LINES) {
editorModel.pushEditOperations(selections, [{ range: startRange, text: beginInsertedCode }, { range: endRange, text: endInsertedCode }], null);
} else { // Otherwise, add an operation per line (plus the operation at the last column + line)
let operations: IIdentifiedSingleEditOperation[] = [];
for (let i = 0; i < selection.endLineNumber - selection.startLineNumber + 1; i++) {
operations.push({ range: this.transformRangeByLineOffset(startRange, i), text: beginInsertedCode });
}
operations.push({ range: endRange, text: endInsertedCode });
editorModel.pushEditOperations(selections, operations, null);
}
this.handleTransformOperation(markdownLineType, startRange, endRange, editorModel, beginInsertedCode, endInsertedCode, selections, selection);
}
}
@@ -116,7 +95,7 @@ export class MarkdownTextTransformer {
// Otherwise, the selection will not be correct after the transformation
let offset = selection.startLineNumber === selection.endLineNumber ? beginInsertedCode.length : 0;
endRange = this.getIRangeWithOffsets(endRange, offset, 0, offset, 0);
this.setEndSelection(endRange, type, editorControl, nothingSelected, isUndo);
this.setEndSelection(endRange, type, editorControl, editorModel, nothingSelected, isUndo);
}
// Always give focus back to the editor after pressing the button
editorControl.focus();
@@ -182,6 +161,8 @@ export class MarkdownTextTransformer {
case MarkdownButtonType.UNORDERED_LIST:
case MarkdownButtonType.ORDERED_LIST:
return MarkdownLineType.EVERY_LINE;
case MarkdownButtonType.CODE:
return MarkdownLineType.WRAPPED_ABOVE_AND_BELOW;
default:
return MarkdownLineType.BEGIN_AND_END_LINES;
}
@@ -205,7 +186,7 @@ export class MarkdownTextTransformer {
private getEditorControl(): CodeEditorWidget | undefined {
if (!this._notebookEditor) {
this._notebookEditor = this._notebookService.findNotebookEditor(this._cellModel.notebookModel.notebookUri);
this._notebookEditor = this._notebookService.findNotebookEditor(this._cellModel?.notebookModel?.notebookUri);
}
if (this._notebookEditor?.cellEditors?.length > 0) {
// Find cell editor provider via cell guid
@@ -232,28 +213,48 @@ export class MarkdownTextTransformer {
* @param editorControl code editor widget
* @param noSelection controls whether there was no previous selection in the editor
*/
private setEndSelection(endRange: IRange, type: MarkdownButtonType, editorControl: CodeEditorWidget, noSelection: boolean, isUndo: boolean): void {
private setEndSelection(endRange: IRange, type: MarkdownButtonType, editorControl: CodeEditorWidget, editorModel: TextModel, noSelection: boolean, isUndo: boolean): void {
if (!endRange || !editorControl || isUndo) {
return;
}
let offset = this.getColumnOffsetForSelection(type, noSelection);
if (offset > -1) {
let newRange: IRange = {
startColumn: endRange.startColumn + offset,
startLineNumber: endRange.startLineNumber,
endColumn: endRange.startColumn + offset,
endLineNumber: endRange.endLineNumber
};
let newRange: IRange;
if (type !== MarkdownButtonType.CODE) {
newRange = {
startColumn: endRange.startColumn + offset,
startLineNumber: endRange.startLineNumber,
endColumn: endRange.startColumn + offset,
endLineNumber: endRange.endLineNumber
};
} else {
newRange = {
startColumn: 1,
startLineNumber: endRange.startLineNumber + 1,
endColumn: 1,
endLineNumber: endRange.endLineNumber + 1
};
}
editorControl.setSelection(newRange);
} else {
if (this.getMarkdownLineType(type) === MarkdownLineType.BEGIN_AND_END_LINES) {
let currentSelection = editorControl.getSelection();
let markdownLineType = this.getMarkdownLineType(type);
let currentSelection = editorControl.getSelection();
if (markdownLineType === MarkdownLineType.BEGIN_AND_END_LINES) {
editorControl.setSelection({
startColumn: currentSelection.startColumn + this.getStartTextToInsert(type).length,
startLineNumber: currentSelection.startLineNumber,
endColumn: currentSelection.endColumn - this.getEndTextToInsert(type).length,
endLineNumber: currentSelection.endLineNumber
});
} else if (markdownLineType === MarkdownLineType.WRAPPED_ABOVE_AND_BELOW) {
// Subtracting 1 because the last line will have the end text (e.g. ``` for code)
let endLineLength = editorModel.getLineLength(currentSelection.endLineNumber - 1);
editorControl.setSelection({
startColumn: 1,
startLineNumber: currentSelection.startLineNumber + 1,
endColumn: endLineLength + 1,
endLineNumber: currentSelection.endLineNumber - 1
});
}
}
}
@@ -266,7 +267,7 @@ export class MarkdownTextTransformer {
* @param editorModel text model for the cell
*/
private isUndoOperation(selection: Selection, type: MarkdownButtonType, lineType: MarkdownLineType, editorModel: TextModel): boolean {
if (lineType === MarkdownLineType.BEGIN_AND_END_LINES) {
if (lineType === MarkdownLineType.BEGIN_AND_END_LINES || lineType === MarkdownLineType.WRAPPED_ABOVE_AND_BELOW) {
let selectedText = this.getExtendedSelectedText(selection, type, lineType, editorModel);
return selectedText && selectedText.startsWith(this.getStartTextToInsert(type)) && selectedText.endsWith(this.getEndTextToInsert(type));
} else {
@@ -274,6 +275,39 @@ export class MarkdownTextTransformer {
}
}
private handleUndoOperation(markdownLineType: MarkdownLineType, startRange: IRange, endRange: IRange, editorModel: TextModel, beginInsertedCode: string, endInsertedCode: string, selections: Selection[], selection: Selection): void {
if (markdownLineType === MarkdownLineType.BEGIN_AND_END_LINES) {
startRange = this.getIRangeWithOffsets(startRange, -1 * beginInsertedCode.length, 0, 0, 0);
endRange = this.getIRangeWithOffsets(endRange, 0, 0, endInsertedCode.length, 0);
editorModel.pushEditOperations(selections, [{ range: endRange, text: '' }, { range: startRange, text: '' }], null);
} else if (markdownLineType === MarkdownLineType.WRAPPED_ABOVE_AND_BELOW) {
startRange = this.getIRangeWithOffsets(startRange, 0, -1, 0, 0);
endRange = this.getIRangeWithOffsets(endRange, 0, 0, endInsertedCode.length, 1);
editorModel.pushEditOperations(selections, [{ range: endRange, text: '' }, { range: startRange, text: '' }], null);
} else {
let operations: IIdentifiedSingleEditOperation[] = [];
startRange = this.getIRangeWithOffsets(startRange, 0, 0, beginInsertedCode.length, 0);
for (let i = 0; i < selection.endLineNumber - selection.startLineNumber + 1; i++) {
operations.push({ range: this.transformRangeByLineOffset(startRange, i), text: '' });
}
editorModel.pushEditOperations(selections, operations, null);
}
}
handleTransformOperation(markdownLineType: MarkdownLineType, startRange: IRange, endRange: IRange, editorModel: TextModel, beginInsertedCode: string, endInsertedCode: string, selections: Selection[], selection: Selection): void {
// If the markdown we're inserting only needs to be added to the begin and end lines, add those edit operations directly
if (markdownLineType === MarkdownLineType.BEGIN_AND_END_LINES || markdownLineType === MarkdownLineType.WRAPPED_ABOVE_AND_BELOW) {
editorModel.pushEditOperations(selections, [{ range: startRange, text: beginInsertedCode }, { range: endRange, text: endInsertedCode }], null);
} else { // Otherwise, add an operation per line (plus the operation at the last column + line)
let operations: IIdentifiedSingleEditOperation[] = [];
for (let i = 0; i < selection.endLineNumber - selection.startLineNumber + 1; i++) {
operations.push({ range: this.transformRangeByLineOffset(startRange, i), text: beginInsertedCode });
}
operations.push({ range: endRange, text: endInsertedCode });
editorModel.pushEditOperations(selections, operations, null);
}
}
/**
* Gets the extended selected text (current selection + potential beginning + ending transformed text)
* @param selection Current selection in editor
@@ -289,6 +323,13 @@ export class MarkdownTextTransformer {
endColumn: selection.endColumn + this.getEndTextToInsert(type).length,
endLineNumber: selection.endLineNumber
});
} else if (lineType === MarkdownLineType.WRAPPED_ABOVE_AND_BELOW) {
return editorModel.getValueInRange({
startColumn: 1,
startLineNumber: selection.startLineNumber - 1,
endColumn: this.getEndTextToInsert(type).length + 1,
endLineNumber: selection.endLineNumber + 1
});
}
return '';
}
@@ -300,9 +341,6 @@ export class MarkdownTextTransformer {
* @param editorModel TextModel
*/
private everyLineMatchesBeginString(selection: Selection, type: MarkdownButtonType, editorModel: TextModel): boolean {
if (this.getMarkdownLineType(type) !== MarkdownLineType.EVERY_LINE) {
return false;
}
for (let selectionLine = selection.startLineNumber; selectionLine <= selection.endLineNumber; selectionLine++) {
if (!editorModel.getLineContent(selectionLine).startsWith(this.getStartTextToInsert(type))) {
return false;
@@ -341,7 +379,9 @@ export enum MarkdownButtonType {
}
// If ALL_LINES, we need to insert markdown at each line (e.g. lists)
// WRAPPED_ABOVE_AND_BELOW puts text above and below the highlighted text
export enum MarkdownLineType {
BEGIN_AND_END_LINES,
EVERY_LINE
EVERY_LINE,
WRAPPED_ABOVE_AND_BELOW
}