api: fix Selections.endsWithEntireLine (fixes #218)

This commit is contained in:
Grégoire Geis 2021-12-13 22:05:43 +01:00
parent 56d4e6b8b0
commit 29f4ab91a4
5 changed files with 210 additions and 2 deletions

View File

@ -1475,16 +1475,114 @@ export function isEntireLines(selection: vscode.Selection | vscode.Range) {
return start.character === 0 && end.character === 0 && start.line !== end.line;
}
/**
* Returns whether the given selection starts with an entire line.
*
* ### Example
*
* ```js
* expect(Selections.startsWithEntireLine(Selections.nth(0)!), "to be false");
* expect(Selections.startsWithEntireLine(Selections.nth(1)!), "to be false");
* expect(Selections.startsWithEntireLine(Selections.nth(2)!), "to be true");
* expect(Selections.startsWithEntireLine(Selections.nth(3)!), "to be true");
* ```
*
* With:
* ```
* abc
* ^ 0
* def
* ^^ 1
* ghi
* ^^^^ 1
* jkl
* mno
* ^^^^ 2
* pqr
* ^^ 2
* stu
* ^^^^ 3
* vwx
* ```
*/
export function startsWithEntireLine(selection: vscode.Selection | vscode.Range) {
const start = selection.start;
return start.character === 0 && start.line !== selection.end.line;
}
/**
* Returns whether the given selection ends with an entire line.
*
* ### Example
*
* ```js
* expect(Selections.endsWithEntireLine(Selections.nth(0)!), "to be false");
* expect(Selections.endsWithEntireLine(Selections.nth(1)!), "to be true");
* expect(Selections.endsWithEntireLine(Selections.nth(2)!), "to be false");
* expect(Selections.endsWithEntireLine(Selections.nth(3)!), "to be true");
* ```
*
* With:
* ```
* abc
* ^ 0
* def
* ^^ 1
* ghi
* ^^^^ 1
* jkl
* mno
* ^^^^ 2
* pqr
* ^^ 2
* stu
* ^^^^ 3
* vwx
* ```
*/
export function endsWithEntireLine(selection: vscode.Selection | vscode.Range) {
const end = selection.end;
return end.character === 0 && selection.start.line !== end.line;
return end.character === 0
&& (selection.start.line < end.line - 1
|| (selection.start.line === end.line - 1 && selection.start.character === 0));
}
/**
* Returns whether the given selection ends with a line break (included).
*
* ### Example
*
* ```js
* expect(Selections.endsWithLineBreak(Selections.nth(0)!), "to be true");
* expect(Selections.endsWithLineBreak(Selections.nth(1)!), "to be true");
* expect(Selections.endsWithLineBreak(Selections.nth(2)!), "to be false");
* expect(Selections.endsWithLineBreak(Selections.nth(3)!), "to be true");
* ```
*
* With:
* ```
* abc
* ^ 0
* def
* ^^ 1
* ghi
* ^^^^ 1
* jkl
* mno
* ^^^^ 2
* pqr
* ^^ 2
* stu
* ^^^^ 3
* vwx
* ``` */
export function endsWithLineBreak(selection: vscode.Selection | vscode.Range) {
const end = selection.end;
return end.character === 0 && selection.start.line < end.line;
}
export function activeLineIsFullySelected(selection: vscode.Selection) {

View File

@ -80,7 +80,7 @@ export function vertically(
const activeEnd = (selection: vscode.Selection) => {
const active = selection.active;
if (active === selection.end && Selections.endsWithEntireLine(selection)) {
if (active === selection.end && Selections.endsWithLineBreak(selection)) {
return Lines.columns(active.line - 1, _.editor) + 1;
} else if (active === selection.start && isCharacterMode) {
return Lines.column(active.line, active.character, _.editor) + 1;

64
test/suite/api.test.ts generated
View File

@ -1327,6 +1327,70 @@ suite("API tests", function () {
// No expected end document.
});
test("function startsWithEntireLine", async function () {
const editorState = extension.editors.getState(editor)!,
context = new Context(editorState, cancellationToken),
before = ExpectedDocument.parseIndented(14, String.raw`
abc
^ 0
def
^^ 1
ghi
^^^^ 1
jkl
mno
^^^^ 2
pqr
^^ 2
stu
^^^^ 3
vwx
`);
await before.apply(editor);
await context.runAsync(async () => {
expect(Selections.startsWithEntireLine(Selections.nth(0)!), "to be false");
expect(Selections.startsWithEntireLine(Selections.nth(1)!), "to be false");
expect(Selections.startsWithEntireLine(Selections.nth(2)!), "to be true");
expect(Selections.startsWithEntireLine(Selections.nth(3)!), "to be true");
});
// No expected end document.
});
test("function endsWithEntireLine", async function () {
const editorState = extension.editors.getState(editor)!,
context = new Context(editorState, cancellationToken),
before = ExpectedDocument.parseIndented(14, String.raw`
abc
^ 0
def
^^ 1
ghi
^^^^ 1
jkl
mno
^^^^ 2
pqr
^^ 2
stu
^^^^ 3
vwx
`);
await before.apply(editor);
await context.runAsync(async () => {
expect(Selections.endsWithEntireLine(Selections.nth(0)!), "to be false");
expect(Selections.endsWithEntireLine(Selections.nth(1)!), "to be true");
expect(Selections.endsWithEntireLine(Selections.nth(2)!), "to be false");
expect(Selections.endsWithEntireLine(Selections.nth(3)!), "to be true");
});
// No expected end document.
});
test("function text", async function () {
const editorState = extension.editors.getState(editor)!,
context = new Context(editorState, cancellationToken),

View File

@ -348,3 +348,26 @@ bar
baz
quux
```
# 7
> behavior <- character
```
foo
^ 0
bar
baz
```
## 7 line-extend
[up](#7)
- .select.line.below.extend
```
foo
^^^^ 0
bar
baz
```

View File

@ -515,5 +515,28 @@ suite("./test/suite/commands/select-lines.md", function () {
`);
});
test("7 > line-extend", async function () {
// Set-up document to be in expected initial state.
await ExpectedDocument.apply(editor, 6, String.raw`
foo
^ 0
bar
baz
`);
// Perform all operations.
await executeCommand("dance.dev.setSelectionBehavior", { mode: "normal", value: "character" });
await executeCommand("dance.select.line.below.extend");
await executeCommand("dance.dev.setSelectionBehavior", { mode: "normal", value: "caret" });
// Ensure document is as expected.
ExpectedDocument.assertEquals(editor, "./test/suite/commands/select-lines.md:363:1", 6, String.raw`
foo
^^^^ 0
bar
baz
`);
});
groupTestsByParentName(this);
});