mirror of
https://github.com/Silverquark/dance.git
synced 2024-08-16 22:30:55 +03:00
api: remove all circular dependencies
This commit is contained in:
parent
d17c6cdebd
commit
a3213bdb37
@ -4,21 +4,19 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
name: "no-circular",
|
name: "no-circular",
|
||||||
severity: "error",
|
severity: "error",
|
||||||
from: {
|
from: {},
|
||||||
pathNot: "^src/api",
|
|
||||||
},
|
|
||||||
to: {
|
to: {
|
||||||
circular: true,
|
circular: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "api-only-depends-on-api/index-and-utils",
|
name: "api-only-depends-on-api-and-utils",
|
||||||
severity: "error",
|
severity: "error",
|
||||||
from: {
|
from: {
|
||||||
path: "^src/api/(?!index)",
|
path: "^src/api/(?!index)",
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
pathNot: "^src/(api/index|utils)",
|
pathNot: "^src/(api/(?!index)|utils)",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -32,10 +30,10 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "only-api/index-depends-on-api",
|
name: "only-api-depends-on-api",
|
||||||
severity: "error",
|
severity: "error",
|
||||||
from: {
|
from: {
|
||||||
pathNot: "^src/api/index",
|
pathNot: "^src/api",
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
path: "^src/api/(?!index)",
|
path: "^src/api/(?!index)",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context } from ".";
|
import { Context } from "./context";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies the given text to the clipboard.
|
* Copies the given text to the clipboard.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { SelectionBehavior, Selections } from ".";
|
import { SelectionBehavior } from "./types";
|
||||||
import type { CommandDescriptor } from "../commands";
|
import type { CommandDescriptor } from "../commands";
|
||||||
import type { PerEditorState } from "../state/editors";
|
import type { PerEditorState } from "../state/editors";
|
||||||
import type { Extension } from "../state/extension";
|
import type { Extension } from "../state/extension";
|
||||||
@ -302,7 +302,7 @@ export class Context extends ContextWithoutActiveEditor {
|
|||||||
const editor = this.editor as vscode.TextEditor;
|
const editor = this.editor as vscode.TextEditor;
|
||||||
|
|
||||||
if (this.selectionBehavior === SelectionBehavior.Character) {
|
if (this.selectionBehavior === SelectionBehavior.Character) {
|
||||||
return Selections.fromCharacterMode(editor.selections, editor.document);
|
return selectionsFromCharacterMode(editor.selections, editor.document);
|
||||||
}
|
}
|
||||||
|
|
||||||
return editor.selections;
|
return editor.selections;
|
||||||
@ -318,7 +318,7 @@ export class Context extends ContextWithoutActiveEditor {
|
|||||||
const editor = this.editor as vscode.TextEditor;
|
const editor = this.editor as vscode.TextEditor;
|
||||||
|
|
||||||
if (this.selectionBehavior === SelectionBehavior.Character) {
|
if (this.selectionBehavior === SelectionBehavior.Character) {
|
||||||
selections = Selections.toCharacterMode(selections, editor.document);
|
selections = selectionsToCharacterMode(selections, editor.document);
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.selections = selections as vscode.Selection[];
|
editor.selections = selections as vscode.Selection[];
|
||||||
@ -333,7 +333,7 @@ export class Context extends ContextWithoutActiveEditor {
|
|||||||
const editor = this.editor as vscode.TextEditor;
|
const editor = this.editor as vscode.TextEditor;
|
||||||
|
|
||||||
if (this.selectionBehavior === SelectionBehavior.Character) {
|
if (this.selectionBehavior === SelectionBehavior.Character) {
|
||||||
return Selections.fromCharacterMode([editor.selection], editor.document)[0];
|
return selectionsFromCharacterMode([editor.selection], editor.document)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return editor.selection;
|
return editor.selection;
|
||||||
@ -581,3 +581,221 @@ export function insertUndoStop(editor?: vscode.TextEditor) {
|
|||||||
|
|
||||||
return Context.current.insertUndoStop();
|
return Context.current.insertUndoStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms a list of caret-mode selections (that is, regular selections as
|
||||||
|
* manipulated internally) into a list of character-mode selections (that is,
|
||||||
|
* selections modified to include a block character in them).
|
||||||
|
*
|
||||||
|
* This function should be used before setting the selections of a
|
||||||
|
* `vscode.TextEditor` if the selection behavior is `Character`.
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
* Forward-facing, non-empty selections are reduced by one character.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* // One-character selection becomes empty.
|
||||||
|
* expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 0, 0, 1)]), "to satisfy", [
|
||||||
|
* expect.it("to be empty at coords", 0, 0),
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* // One-character selection becomes empty (at line break).
|
||||||
|
* expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 1, 1, 0)]), "to satisfy", [
|
||||||
|
* expect.it("to be empty at coords", 0, 1),
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* // Forward-facing selection becomes shorter.
|
||||||
|
* expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 0, 1, 1)]), "to satisfy", [
|
||||||
|
* expect.it("to have anchor at coords", 0, 0).and("to have cursor at coords", 1, 0),
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* // One-character selection becomes empty (reversed).
|
||||||
|
* expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 1, 0, 0)]), "to satisfy", [
|
||||||
|
* expect.it("to be empty at coords", 0, 0),
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* // One-character selection becomes empty (reversed, at line break).
|
||||||
|
* expect(Selections.toCharacterMode([Selections.fromAnchorActive(1, 0, 0, 1)]), "to satisfy", [
|
||||||
|
* expect.it("to be empty at coords", 0, 1),
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* // Reversed selection stays as-is.
|
||||||
|
* expect(Selections.toCharacterMode([Selections.fromAnchorActive(1, 1, 0, 0)]), "to satisfy", [
|
||||||
|
* expect.it("to have anchor at coords", 1, 1).and("to have cursor at coords", 0, 0),
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* // Empty selection stays as-is.
|
||||||
|
* expect(Selections.toCharacterMode([Selections.empty(1, 1)]), "to satisfy", [
|
||||||
|
* expect.it("to be empty at coords", 1, 1),
|
||||||
|
* ]);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* With:
|
||||||
|
* ```
|
||||||
|
* a
|
||||||
|
* b
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function selectionsToCharacterMode(
|
||||||
|
selections: readonly vscode.Selection[],
|
||||||
|
document?: vscode.TextDocument,
|
||||||
|
) {
|
||||||
|
const characterModeSelections = [] as vscode.Selection[];
|
||||||
|
|
||||||
|
for (const selection of selections) {
|
||||||
|
const selectionActive = selection.active,
|
||||||
|
selectionActiveLine = selectionActive.line,
|
||||||
|
selectionActiveCharacter = selectionActive.character,
|
||||||
|
selectionAnchor = selection.anchor,
|
||||||
|
selectionAnchorLine = selectionAnchor.line,
|
||||||
|
selectionAnchorCharacter = selectionAnchor.character;
|
||||||
|
let active = selectionActive,
|
||||||
|
anchor = selectionAnchor,
|
||||||
|
changed = false;
|
||||||
|
|
||||||
|
if (selectionAnchorLine === selectionActiveLine) {
|
||||||
|
if (selectionAnchorCharacter + 1 === selectionActiveCharacter) {
|
||||||
|
// Selection is one-character long: make it empty.
|
||||||
|
active = selectionAnchor;
|
||||||
|
changed = true;
|
||||||
|
} else if (selectionAnchorCharacter - 1 === selectionActiveCharacter) {
|
||||||
|
// Selection is reversed and one-character long: make it empty.
|
||||||
|
anchor = selectionActive;
|
||||||
|
changed = true;
|
||||||
|
} else if (selectionAnchorCharacter < selectionActiveCharacter) {
|
||||||
|
// Selection is strictly forward-facing: make it shorter.
|
||||||
|
active = new vscode.Position(selectionActiveLine, selectionActiveCharacter - 1);
|
||||||
|
changed = true;
|
||||||
|
} else {
|
||||||
|
// Selection is reversed or empty: do nothing.
|
||||||
|
}
|
||||||
|
} else if (selectionAnchorLine < selectionActiveLine) {
|
||||||
|
// Selection is strictly forward-facing: make it shorter.
|
||||||
|
if (selectionActiveCharacter > 0) {
|
||||||
|
active = new vscode.Position(selectionActiveLine, selectionActiveCharacter - 1);
|
||||||
|
changed = true;
|
||||||
|
} else {
|
||||||
|
// The active character is the first one, so we have to get some
|
||||||
|
// information from the document.
|
||||||
|
if (document === undefined) {
|
||||||
|
document = Context.current.document;
|
||||||
|
}
|
||||||
|
|
||||||
|
const activePrevLine = selectionActiveLine - 1,
|
||||||
|
activePrevLineLength = document.lineAt(activePrevLine).text.length;
|
||||||
|
|
||||||
|
active = new vscode.Position(activePrevLine, activePrevLineLength);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
} else if (selectionAnchorLine === selectionActiveLine + 1
|
||||||
|
&& selectionAnchorCharacter === 0
|
||||||
|
&& selectionActiveCharacter === (document ?? (document = Context.current.document))
|
||||||
|
.lineAt(selectionActiveLine).text.length) {
|
||||||
|
// Selection is reversed and one-character long: make it empty.
|
||||||
|
anchor = selectionActive;
|
||||||
|
changed = true;
|
||||||
|
} else {
|
||||||
|
// Selection is reversed: do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
characterModeSelections.push(changed ? new vscode.Selection(anchor, active) : selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return characterModeSelections;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverses the changes made by `toCharacterMode` by increasing by one the
|
||||||
|
* length of every empty or forward-facing selection.
|
||||||
|
*
|
||||||
|
* This function should be used on the selections of a `vscode.TextEditor` if
|
||||||
|
* the selection behavior is `Character`.
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
* Selections remain empty in empty documents.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* expect(Selections.fromCharacterMode([Selections.empty(0, 0)]), "to satisfy", [
|
||||||
|
* expect.it("to be empty at coords", 0, 0),
|
||||||
|
* ]);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* With:
|
||||||
|
* ```
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
* Empty selections automatically become 1-character selections.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* expect(Selections.fromCharacterMode([Selections.empty(0, 0)]), "to satisfy", [
|
||||||
|
* expect.it("to have anchor at coords", 0, 0).and("to have cursor at coords", 0, 1),
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* // At the end of the line, it selects the line ending:
|
||||||
|
* expect(Selections.fromCharacterMode([Selections.empty(0, 1)]), "to satisfy", [
|
||||||
|
* expect.it("to have anchor at coords", 0, 1).and("to have cursor at coords", 1, 0),
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* // But it does nothing at the end of the document:
|
||||||
|
* expect(Selections.fromCharacterMode([Selections.empty(2, 0)]), "to satisfy", [
|
||||||
|
* expect.it("to be empty at coords", 2, 0),
|
||||||
|
* ]);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* With:
|
||||||
|
* ```
|
||||||
|
* a
|
||||||
|
* b
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function selectionsFromCharacterMode(
|
||||||
|
selections: readonly vscode.Selection[],
|
||||||
|
document?: vscode.TextDocument,
|
||||||
|
) {
|
||||||
|
const caretModeSelections = [] as vscode.Selection[];
|
||||||
|
|
||||||
|
for (const selection of selections) {
|
||||||
|
const selectionActive = selection.active,
|
||||||
|
selectionActiveLine = selectionActive.line,
|
||||||
|
selectionActiveCharacter = selectionActive.character,
|
||||||
|
selectionAnchor = selection.anchor,
|
||||||
|
selectionAnchorLine = selectionAnchor.line,
|
||||||
|
selectionAnchorCharacter = selectionAnchor.character;
|
||||||
|
let active = selectionActive,
|
||||||
|
changed = false;
|
||||||
|
|
||||||
|
const isEmptyOrForwardFacing = selectionAnchorLine < selectionActiveLine
|
||||||
|
|| (selectionAnchorLine === selectionActiveLine
|
||||||
|
&& selectionAnchorCharacter <= selectionActiveCharacter);
|
||||||
|
|
||||||
|
if (isEmptyOrForwardFacing) {
|
||||||
|
// Selection is empty or forward-facing: extend it if possible.
|
||||||
|
if (document === undefined) {
|
||||||
|
document = Context.current.document;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lineLength = document.lineAt(selectionActiveLine).text.length;
|
||||||
|
|
||||||
|
if (selectionActiveCharacter === lineLength) {
|
||||||
|
// Character is at the end of the line.
|
||||||
|
if (selectionActiveLine + 1 < document.lineCount) {
|
||||||
|
// This is not the last line: we can extend the selection.
|
||||||
|
active = new vscode.Position(selectionActiveLine + 1, 0);
|
||||||
|
changed = true;
|
||||||
|
} else {
|
||||||
|
// This is the last line: we cannot do anything.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Character is not at the end of the line: we can extend the selection.
|
||||||
|
active = new vscode.Position(selectionActiveLine, selectionActiveCharacter + 1);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
caretModeSelections.push(changed ? new vscode.Selection(selectionAnchor, active) : selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return caretModeSelections;
|
||||||
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context, edit, Positions, Selections } from "..";
|
import { Context, edit } from "../context";
|
||||||
|
import { Positions } from "../positions";
|
||||||
|
import { Selections } from "../selections";
|
||||||
import { TrackedSelection } from "../../utils/tracked-selection";
|
import { TrackedSelection } from "../../utils/tracked-selection";
|
||||||
|
|
||||||
const enum Constants {
|
const enum Constants {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context, edit } from "..";
|
import { Context, edit } from "../context";
|
||||||
import { blankCharacters } from "../../utils/charset";
|
import { blankCharacters } from "../../utils/charset";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Context } from ".";
|
import { Context } from "./context";
|
||||||
|
|
||||||
export * from "../utils/errors";
|
export * from "../utils/errors";
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context } from ".";
|
import { Context } from "./context";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Un-does the last action.
|
* Un-does the last action.
|
||||||
|
@ -23,61 +23,7 @@ export * from "./search/pairs";
|
|||||||
export * from "./search/range";
|
export * from "./search/range";
|
||||||
export * from "./search/word";
|
export * from "./search/word";
|
||||||
export * from "./selections";
|
export * from "./selections";
|
||||||
|
export * from "./types";
|
||||||
/**
|
|
||||||
* Direction of an operation.
|
|
||||||
*/
|
|
||||||
export const enum Direction {
|
|
||||||
/**
|
|
||||||
* Forward direction (`1`).
|
|
||||||
*/
|
|
||||||
Forward = 1,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Backward direction (`-1`).
|
|
||||||
*/
|
|
||||||
Backward = -1,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Behavior of a shift.
|
|
||||||
*/
|
|
||||||
export const enum Shift {
|
|
||||||
/**
|
|
||||||
* Jump to the position.
|
|
||||||
*/
|
|
||||||
Jump,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Select to the position.
|
|
||||||
*/
|
|
||||||
Select,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extend to the position.
|
|
||||||
*/
|
|
||||||
Extend,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Selection behavior of an operation.
|
|
||||||
*/
|
|
||||||
export const enum SelectionBehavior {
|
|
||||||
/**
|
|
||||||
* VS Code-like caret selections.
|
|
||||||
*/
|
|
||||||
Caret = 1,
|
|
||||||
/**
|
|
||||||
* Kakoune-like character selections.
|
|
||||||
*/
|
|
||||||
Character = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Forward = Direction.Forward,
|
|
||||||
Backward = Direction.Backward,
|
|
||||||
Jump = Shift.Jump,
|
|
||||||
Select = Shift.Select,
|
|
||||||
Extend = Shift.Extend;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the module exported by the extension with the given identifier.
|
* Returns the module exported by the extension with the given identifier.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context } from ".";
|
import { Context } from "./context";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the 0-based number of the first visible line in the current editor.
|
* Returns the 0-based number of the first visible line in the current editor.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context, keypress, prompt } from ".";
|
import { Context } from "./context";
|
||||||
|
import { keypress, prompt } from "./prompt";
|
||||||
|
|
||||||
export interface Menu {
|
export interface Menu {
|
||||||
readonly items: Menu.Items;
|
readonly items: Menu.Items;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Context } from ".";
|
import { Context } from "./context";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switches to the mode with the given name.
|
* Switches to the mode with the given name.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context, Direction } from ".";
|
import { Context } from "./context";
|
||||||
|
import { Direction } from "./types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the position right after the given position, or `undefined` if
|
* Returns the position right after the given position, or `undefined` if
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context, Selections } from ".";
|
import { Context } from "./context";
|
||||||
|
import { Selections } from "./selections";
|
||||||
import type { Input, SetInput } from "../commands";
|
import type { Input, SetInput } from "../commands";
|
||||||
import { CancellationError } from "../utils/errors";
|
import { CancellationError } from "../utils/errors";
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context } from ".";
|
import { Context } from "./context";
|
||||||
import type { Register } from "../state/registers";
|
import type { Register } from "../state/registers";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context } from ".";
|
import { Context } from "./context";
|
||||||
import type { CommandDescriptor } from "../commands";
|
import type { CommandDescriptor } from "../commands";
|
||||||
import { parseRegExpWithReplacement } from "../utils/regexp";
|
import { parseRegExpWithReplacement } from "../utils/regexp";
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context, Direction, Positions } from "..";
|
import { Context } from "../context";
|
||||||
|
import { Positions } from "../positions";
|
||||||
|
import { Direction } from "../types";
|
||||||
import { canMatchLineFeed, execLast, matchesStaticStrings } from "../../utils/regexp";
|
import { canMatchLineFeed, execLast, matchesStaticStrings } from "../../utils/regexp";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context, lineByLine, Positions } from "..";
|
import { lineByLine } from "./move";
|
||||||
|
import { Context } from "../context";
|
||||||
|
import { Positions } from "../positions";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the range of lines matching the given `RegExp` before and after
|
* Returns the range of lines matching the given `RegExp` before and after
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context, Direction, Positions } from "..";
|
import { Context } from "../context";
|
||||||
|
import { Positions } from "../positions";
|
||||||
|
import { Direction } from "../types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves the given position towards the given direction until the given string
|
* Moves the given position towards the given direction until the given string
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context, Direction, Positions } from "..";
|
import { Context } from "../context";
|
||||||
|
import { Positions } from "../positions";
|
||||||
|
import { Direction } from "../types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves the given position towards the given direction as long as the given
|
* Moves the given position towards the given direction as long as the given
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context, Direction, Positions, search } from "..";
|
import { search } from "./index";
|
||||||
|
import { Context } from "../context";
|
||||||
|
import { Positions } from "../positions";
|
||||||
|
import { Direction } from "../types";
|
||||||
import { ArgumentError } from "../../utils/errors";
|
import { ArgumentError } from "../../utils/errors";
|
||||||
import { anyRegExp, escapeForRegExp } from "../../utils/regexp";
|
import { anyRegExp, escapeForRegExp } from "../../utils/regexp";
|
||||||
|
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context, Direction, Lines, moveWhile, Positions } from "..";
|
import { moveWhile } from "./move";
|
||||||
|
import { Context } from "../context";
|
||||||
|
import { Lines } from "../lines";
|
||||||
|
import { Positions } from "../positions";
|
||||||
|
import { Direction } from "../types";
|
||||||
import { CharSet, getCharSetFunction } from "../../utils/charset";
|
import { CharSet, getCharSetFunction } from "../../utils/charset";
|
||||||
import { CharCodes } from "../../utils/regexp";
|
import { CharCodes } from "../../utils/regexp";
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context, Direction, SelectionBehavior, skipEmptyLines } from "..";
|
import { skipEmptyLines } from "./move";
|
||||||
|
import { Context } from "../context";
|
||||||
|
import { Direction, SelectionBehavior } from "../types";
|
||||||
import { CharSet, getCharSetFunction } from "../../utils/charset";
|
import { CharSet, getCharSetFunction } from "../../utils/charset";
|
||||||
|
|
||||||
const enum WordCategory {
|
const enum WordCategory {
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Context, Direction, Lines, NotASelectionError, Positions, SelectionBehavior, Shift } from ".";
|
import { Context, selectionsFromCharacterMode, selectionsToCharacterMode } from "./context";
|
||||||
|
import { NotASelectionError } from "./errors";
|
||||||
|
import { Positions } from "./positions";
|
||||||
|
import { Direction, SelectionBehavior, Shift } from "./types";
|
||||||
import { execRange, splitRange } from "../utils/regexp";
|
import { execRange, splitRange } from "../utils/regexp";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1768,222 +1771,8 @@ export namespace Selections {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export const fromCharacterMode = selectionsFromCharacterMode,
|
||||||
* Transforms a list of caret-mode selections (that is, regular selections as
|
toCharacterMode = selectionsToCharacterMode;
|
||||||
* manipulated internally) into a list of character-mode selections (that is,
|
|
||||||
* selections modified to include a block character in them).
|
|
||||||
*
|
|
||||||
* This function should be used before setting the selections of a
|
|
||||||
* `vscode.TextEditor` if the selection behavior is `Character`.
|
|
||||||
*
|
|
||||||
* ### Example
|
|
||||||
* Forward-facing, non-empty selections are reduced by one character.
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* // One-character selection becomes empty.
|
|
||||||
* expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 0, 0, 1)]), "to satisfy", [
|
|
||||||
* expect.it("to be empty at coords", 0, 0),
|
|
||||||
* ]);
|
|
||||||
*
|
|
||||||
* // One-character selection becomes empty (at line break).
|
|
||||||
* expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 1, 1, 0)]), "to satisfy", [
|
|
||||||
* expect.it("to be empty at coords", 0, 1),
|
|
||||||
* ]);
|
|
||||||
*
|
|
||||||
* // Forward-facing selection becomes shorter.
|
|
||||||
* expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 0, 1, 1)]), "to satisfy", [
|
|
||||||
* expect.it("to have anchor at coords", 0, 0).and("to have cursor at coords", 1, 0),
|
|
||||||
* ]);
|
|
||||||
*
|
|
||||||
* // One-character selection becomes empty (reversed).
|
|
||||||
* expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 1, 0, 0)]), "to satisfy", [
|
|
||||||
* expect.it("to be empty at coords", 0, 0),
|
|
||||||
* ]);
|
|
||||||
*
|
|
||||||
* // One-character selection becomes empty (reversed, at line break).
|
|
||||||
* expect(Selections.toCharacterMode([Selections.fromAnchorActive(1, 0, 0, 1)]), "to satisfy", [
|
|
||||||
* expect.it("to be empty at coords", 0, 1),
|
|
||||||
* ]);
|
|
||||||
*
|
|
||||||
* // Reversed selection stays as-is.
|
|
||||||
* expect(Selections.toCharacterMode([Selections.fromAnchorActive(1, 1, 0, 0)]), "to satisfy", [
|
|
||||||
* expect.it("to have anchor at coords", 1, 1).and("to have cursor at coords", 0, 0),
|
|
||||||
* ]);
|
|
||||||
*
|
|
||||||
* // Empty selection stays as-is.
|
|
||||||
* expect(Selections.toCharacterMode([Selections.empty(1, 1)]), "to satisfy", [
|
|
||||||
* expect.it("to be empty at coords", 1, 1),
|
|
||||||
* ]);
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* With:
|
|
||||||
* ```
|
|
||||||
* a
|
|
||||||
* b
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export function toCharacterMode(
|
|
||||||
selections: readonly vscode.Selection[],
|
|
||||||
document?: vscode.TextDocument,
|
|
||||||
) {
|
|
||||||
const characterModeSelections = [] as vscode.Selection[];
|
|
||||||
|
|
||||||
for (const selection of selections) {
|
|
||||||
const selectionActive = selection.active,
|
|
||||||
selectionActiveLine = selectionActive.line,
|
|
||||||
selectionActiveCharacter = selectionActive.character,
|
|
||||||
selectionAnchor = selection.anchor,
|
|
||||||
selectionAnchorLine = selectionAnchor.line,
|
|
||||||
selectionAnchorCharacter = selectionAnchor.character;
|
|
||||||
let active = selectionActive,
|
|
||||||
anchor = selectionAnchor,
|
|
||||||
changed = false;
|
|
||||||
|
|
||||||
if (selectionAnchorLine === selectionActiveLine) {
|
|
||||||
if (selectionAnchorCharacter + 1 === selectionActiveCharacter) {
|
|
||||||
// Selection is one-character long: make it empty.
|
|
||||||
active = selectionAnchor;
|
|
||||||
changed = true;
|
|
||||||
} else if (selectionAnchorCharacter - 1 === selectionActiveCharacter) {
|
|
||||||
// Selection is reversed and one-character long: make it empty.
|
|
||||||
anchor = selectionActive;
|
|
||||||
changed = true;
|
|
||||||
} else if (selectionAnchorCharacter < selectionActiveCharacter) {
|
|
||||||
// Selection is strictly forward-facing: make it shorter.
|
|
||||||
active = new vscode.Position(selectionActiveLine, selectionActiveCharacter - 1);
|
|
||||||
changed = true;
|
|
||||||
} else {
|
|
||||||
// Selection is reversed or empty: do nothing.
|
|
||||||
}
|
|
||||||
} else if (selectionAnchorLine < selectionActiveLine) {
|
|
||||||
// Selection is strictly forward-facing: make it shorter.
|
|
||||||
if (selectionActiveCharacter > 0) {
|
|
||||||
active = new vscode.Position(selectionActiveLine, selectionActiveCharacter - 1);
|
|
||||||
changed = true;
|
|
||||||
} else {
|
|
||||||
// The active character is the first one, so we have to get some
|
|
||||||
// information from the document.
|
|
||||||
if (document === undefined) {
|
|
||||||
document = Context.current.document;
|
|
||||||
}
|
|
||||||
|
|
||||||
const activePrevLine = selectionActiveLine - 1,
|
|
||||||
activePrevLineLength = document.lineAt(activePrevLine).text.length;
|
|
||||||
|
|
||||||
active = new vscode.Position(activePrevLine, activePrevLineLength);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
} else if (selectionAnchorLine === selectionActiveLine + 1
|
|
||||||
&& selectionAnchorCharacter === 0
|
|
||||||
&& selectionActiveCharacter === Lines.length(selectionActiveLine, document)) {
|
|
||||||
// Selection is reversed and one-character long: make it empty.
|
|
||||||
anchor = selectionActive;
|
|
||||||
changed = true;
|
|
||||||
} else {
|
|
||||||
// Selection is reversed: do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
characterModeSelections.push(changed ? new vscode.Selection(anchor, active) : selection);
|
|
||||||
}
|
|
||||||
|
|
||||||
return characterModeSelections;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverses the changes made by `toCharacterMode` by increasing by one the
|
|
||||||
* length of every empty or forward-facing selection.
|
|
||||||
*
|
|
||||||
* This function should be used on the selections of a `vscode.TextEditor` if
|
|
||||||
* the selection behavior is `Character`.
|
|
||||||
*
|
|
||||||
* ### Example
|
|
||||||
* Selections remain empty in empty documents.
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* expect(Selections.fromCharacterMode([Selections.empty(0, 0)]), "to satisfy", [
|
|
||||||
* expect.it("to be empty at coords", 0, 0),
|
|
||||||
* ]);
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* With:
|
|
||||||
* ```
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* ### Example
|
|
||||||
* Empty selections automatically become 1-character selections.
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* expect(Selections.fromCharacterMode([Selections.empty(0, 0)]), "to satisfy", [
|
|
||||||
* expect.it("to have anchor at coords", 0, 0).and("to have cursor at coords", 0, 1),
|
|
||||||
* ]);
|
|
||||||
*
|
|
||||||
* // At the end of the line, it selects the line ending:
|
|
||||||
* expect(Selections.fromCharacterMode([Selections.empty(0, 1)]), "to satisfy", [
|
|
||||||
* expect.it("to have anchor at coords", 0, 1).and("to have cursor at coords", 1, 0),
|
|
||||||
* ]);
|
|
||||||
*
|
|
||||||
* // But it does nothing at the end of the document:
|
|
||||||
* expect(Selections.fromCharacterMode([Selections.empty(2, 0)]), "to satisfy", [
|
|
||||||
* expect.it("to be empty at coords", 2, 0),
|
|
||||||
* ]);
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* With:
|
|
||||||
* ```
|
|
||||||
* a
|
|
||||||
* b
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export function fromCharacterMode(
|
|
||||||
selections: readonly vscode.Selection[],
|
|
||||||
document?: vscode.TextDocument,
|
|
||||||
) {
|
|
||||||
const caretModeSelections = [] as vscode.Selection[];
|
|
||||||
|
|
||||||
for (const selection of selections) {
|
|
||||||
const selectionActive = selection.active,
|
|
||||||
selectionActiveLine = selectionActive.line,
|
|
||||||
selectionActiveCharacter = selectionActive.character,
|
|
||||||
selectionAnchor = selection.anchor,
|
|
||||||
selectionAnchorLine = selectionAnchor.line,
|
|
||||||
selectionAnchorCharacter = selectionAnchor.character;
|
|
||||||
let active = selectionActive,
|
|
||||||
changed = false;
|
|
||||||
|
|
||||||
const isEmptyOrForwardFacing = selectionAnchorLine < selectionActiveLine
|
|
||||||
|| (selectionAnchorLine === selectionActiveLine
|
|
||||||
&& selectionAnchorCharacter <= selectionActiveCharacter);
|
|
||||||
|
|
||||||
if (isEmptyOrForwardFacing) {
|
|
||||||
// Selection is empty or forward-facing: extend it if possible.
|
|
||||||
if (document === undefined) {
|
|
||||||
document = Context.current.document;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lineLength = document.lineAt(selectionActiveLine).text.length;
|
|
||||||
|
|
||||||
if (selectionActiveCharacter === lineLength) {
|
|
||||||
// Character is at the end of the line.
|
|
||||||
if (selectionActiveLine + 1 < document.lineCount) {
|
|
||||||
// This is not the last line: we can extend the selection.
|
|
||||||
active = new vscode.Position(selectionActiveLine + 1, 0);
|
|
||||||
changed = true;
|
|
||||||
} else {
|
|
||||||
// This is the last line: we cannot do anything.
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Character is not at the end of the line: we can extend the selection.
|
|
||||||
active = new vscode.Position(selectionActiveLine, selectionActiveCharacter + 1);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
caretModeSelections.push(changed ? new vscode.Selection(selectionAnchor, active) : selection);
|
|
||||||
}
|
|
||||||
|
|
||||||
return caretModeSelections;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortTopToBottom(a: vscode.Selection, b: vscode.Selection) {
|
function sortTopToBottom(a: vscode.Selection, b: vscode.Selection) {
|
||||||
|
54
src/api/types.ts
Normal file
54
src/api/types.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* Direction of an operation.
|
||||||
|
*/
|
||||||
|
export const enum Direction {
|
||||||
|
/**
|
||||||
|
* Forward direction (`1`).
|
||||||
|
*/
|
||||||
|
Forward = 1,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backward direction (`-1`).
|
||||||
|
*/
|
||||||
|
Backward = -1,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Behavior of a shift.
|
||||||
|
*/
|
||||||
|
export const enum Shift {
|
||||||
|
/**
|
||||||
|
* Jump to the position.
|
||||||
|
*/
|
||||||
|
Jump,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select to the position.
|
||||||
|
*/
|
||||||
|
Select,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend to the position.
|
||||||
|
*/
|
||||||
|
Extend,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selection behavior of an operation.
|
||||||
|
*/
|
||||||
|
export const enum SelectionBehavior {
|
||||||
|
/**
|
||||||
|
* VS Code-like caret selections.
|
||||||
|
*/
|
||||||
|
Caret = 1,
|
||||||
|
/**
|
||||||
|
* Kakoune-like character selections.
|
||||||
|
*/
|
||||||
|
Character = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Forward = Direction.Forward,
|
||||||
|
Backward = Direction.Backward,
|
||||||
|
Jump = Shift.Jump,
|
||||||
|
Select = Shift.Select,
|
||||||
|
Extend = Shift.Extend;
|
194
test/suite/api.test.ts
generated
194
test/suite/api.test.ts
generated
@ -89,6 +89,103 @@ suite("API tests", function () {
|
|||||||
// No expected end document.
|
// No expected end document.
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("function selectionsToCharacterMode", async function () {
|
||||||
|
const editorState = extension.editors.getState(editor)!,
|
||||||
|
context = new Context(editorState, cancellationToken),
|
||||||
|
before = ExpectedDocument.parseIndented(14, String.raw`
|
||||||
|
a
|
||||||
|
b
|
||||||
|
`);
|
||||||
|
|
||||||
|
await before.apply(editor);
|
||||||
|
|
||||||
|
await context.runAsync(async () => {
|
||||||
|
// One-character selection becomes empty.
|
||||||
|
expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 0, 0, 1)]), "to satisfy", [
|
||||||
|
expect.it("to be empty at coords", 0, 0),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// One-character selection becomes empty (at line break).
|
||||||
|
expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 1, 1, 0)]), "to satisfy", [
|
||||||
|
expect.it("to be empty at coords", 0, 1),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Forward-facing selection becomes shorter.
|
||||||
|
expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 0, 1, 1)]), "to satisfy", [
|
||||||
|
expect.it("to have anchor at coords", 0, 0).and("to have cursor at coords", 1, 0),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// One-character selection becomes empty (reversed).
|
||||||
|
expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 1, 0, 0)]), "to satisfy", [
|
||||||
|
expect.it("to be empty at coords", 0, 0),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// One-character selection becomes empty (reversed, at line break).
|
||||||
|
expect(Selections.toCharacterMode([Selections.fromAnchorActive(1, 0, 0, 1)]), "to satisfy", [
|
||||||
|
expect.it("to be empty at coords", 0, 1),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Reversed selection stays as-is.
|
||||||
|
expect(Selections.toCharacterMode([Selections.fromAnchorActive(1, 1, 0, 0)]), "to satisfy", [
|
||||||
|
expect.it("to have anchor at coords", 1, 1).and("to have cursor at coords", 0, 0),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Empty selection stays as-is.
|
||||||
|
expect(Selections.toCharacterMode([Selections.empty(1, 1)]), "to satisfy", [
|
||||||
|
expect.it("to be empty at coords", 1, 1),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// No expected end document.
|
||||||
|
});
|
||||||
|
|
||||||
|
test("function selectionsFromCharacterMode", async function () {
|
||||||
|
const editorState = extension.editors.getState(editor)!,
|
||||||
|
context = new Context(editorState, cancellationToken),
|
||||||
|
before = ExpectedDocument.parseIndented(14, String.raw`
|
||||||
|
`);
|
||||||
|
|
||||||
|
await before.apply(editor);
|
||||||
|
|
||||||
|
await context.runAsync(async () => {
|
||||||
|
expect(Selections.fromCharacterMode([Selections.empty(0, 0)]), "to satisfy", [
|
||||||
|
expect.it("to be empty at coords", 0, 0),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// No expected end document.
|
||||||
|
});
|
||||||
|
|
||||||
|
test("function selectionsFromCharacterMode#1", async function () {
|
||||||
|
const editorState = extension.editors.getState(editor)!,
|
||||||
|
context = new Context(editorState, cancellationToken),
|
||||||
|
before = ExpectedDocument.parseIndented(14, String.raw`
|
||||||
|
a
|
||||||
|
b
|
||||||
|
|
||||||
|
`);
|
||||||
|
|
||||||
|
await before.apply(editor);
|
||||||
|
|
||||||
|
await context.runAsync(async () => {
|
||||||
|
expect(Selections.fromCharacterMode([Selections.empty(0, 0)]), "to satisfy", [
|
||||||
|
expect.it("to have anchor at coords", 0, 0).and("to have cursor at coords", 0, 1),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// At the end of the line, it selects the line ending:
|
||||||
|
expect(Selections.fromCharacterMode([Selections.empty(0, 1)]), "to satisfy", [
|
||||||
|
expect.it("to have anchor at coords", 0, 1).and("to have cursor at coords", 1, 0),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// But it does nothing at the end of the document:
|
||||||
|
expect(Selections.fromCharacterMode([Selections.empty(2, 0)]), "to satisfy", [
|
||||||
|
expect.it("to be empty at coords", 2, 0),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// No expected end document.
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
suite("./src/api/functional.ts", function () {
|
suite("./src/api/functional.ts", function () {
|
||||||
@ -1308,102 +1405,5 @@ suite("API tests", function () {
|
|||||||
// No expected end document.
|
// No expected end document.
|
||||||
});
|
});
|
||||||
|
|
||||||
test("function toCharacterMode", async function () {
|
|
||||||
const editorState = extension.editors.getState(editor)!,
|
|
||||||
context = new Context(editorState, cancellationToken),
|
|
||||||
before = ExpectedDocument.parseIndented(14, String.raw`
|
|
||||||
a
|
|
||||||
b
|
|
||||||
`);
|
|
||||||
|
|
||||||
await before.apply(editor);
|
|
||||||
|
|
||||||
await context.runAsync(async () => {
|
|
||||||
// One-character selection becomes empty.
|
|
||||||
expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 0, 0, 1)]), "to satisfy", [
|
|
||||||
expect.it("to be empty at coords", 0, 0),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// One-character selection becomes empty (at line break).
|
|
||||||
expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 1, 1, 0)]), "to satisfy", [
|
|
||||||
expect.it("to be empty at coords", 0, 1),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Forward-facing selection becomes shorter.
|
|
||||||
expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 0, 1, 1)]), "to satisfy", [
|
|
||||||
expect.it("to have anchor at coords", 0, 0).and("to have cursor at coords", 1, 0),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// One-character selection becomes empty (reversed).
|
|
||||||
expect(Selections.toCharacterMode([Selections.fromAnchorActive(0, 1, 0, 0)]), "to satisfy", [
|
|
||||||
expect.it("to be empty at coords", 0, 0),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// One-character selection becomes empty (reversed, at line break).
|
|
||||||
expect(Selections.toCharacterMode([Selections.fromAnchorActive(1, 0, 0, 1)]), "to satisfy", [
|
|
||||||
expect.it("to be empty at coords", 0, 1),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Reversed selection stays as-is.
|
|
||||||
expect(Selections.toCharacterMode([Selections.fromAnchorActive(1, 1, 0, 0)]), "to satisfy", [
|
|
||||||
expect.it("to have anchor at coords", 1, 1).and("to have cursor at coords", 0, 0),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Empty selection stays as-is.
|
|
||||||
expect(Selections.toCharacterMode([Selections.empty(1, 1)]), "to satisfy", [
|
|
||||||
expect.it("to be empty at coords", 1, 1),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// No expected end document.
|
|
||||||
});
|
|
||||||
|
|
||||||
test("function fromCharacterMode", async function () {
|
|
||||||
const editorState = extension.editors.getState(editor)!,
|
|
||||||
context = new Context(editorState, cancellationToken),
|
|
||||||
before = ExpectedDocument.parseIndented(14, String.raw`
|
|
||||||
`);
|
|
||||||
|
|
||||||
await before.apply(editor);
|
|
||||||
|
|
||||||
await context.runAsync(async () => {
|
|
||||||
expect(Selections.fromCharacterMode([Selections.empty(0, 0)]), "to satisfy", [
|
|
||||||
expect.it("to be empty at coords", 0, 0),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// No expected end document.
|
|
||||||
});
|
|
||||||
|
|
||||||
test("function fromCharacterMode#1", async function () {
|
|
||||||
const editorState = extension.editors.getState(editor)!,
|
|
||||||
context = new Context(editorState, cancellationToken),
|
|
||||||
before = ExpectedDocument.parseIndented(14, String.raw`
|
|
||||||
a
|
|
||||||
b
|
|
||||||
|
|
||||||
`);
|
|
||||||
|
|
||||||
await before.apply(editor);
|
|
||||||
|
|
||||||
await context.runAsync(async () => {
|
|
||||||
expect(Selections.fromCharacterMode([Selections.empty(0, 0)]), "to satisfy", [
|
|
||||||
expect.it("to have anchor at coords", 0, 0).and("to have cursor at coords", 0, 1),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// At the end of the line, it selects the line ending:
|
|
||||||
expect(Selections.fromCharacterMode([Selections.empty(0, 1)]), "to satisfy", [
|
|
||||||
expect.it("to have anchor at coords", 0, 1).and("to have cursor at coords", 1, 0),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// But it does nothing at the end of the document:
|
|
||||||
expect(Selections.fromCharacterMode([Selections.empty(2, 0)]), "to satisfy", [
|
|
||||||
expect.it("to be empty at coords", 2, 0),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// No expected end document.
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user