Skip to content

Commit

Permalink
commands/api: fix rotation logic (fixes #322)
Browse files Browse the repository at this point in the history
  • Loading branch information
71 committed Dec 1, 2023
1 parent 333d47d commit 3ca3d83
Show file tree
Hide file tree
Showing 10 changed files with 319 additions and 72 deletions.
12 changes: 6 additions & 6 deletions src/api/data/commands.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2368,7 +2368,7 @@ selections.rotate.both:

keys:
qwerty: |-
`a-(` (kakoune: normal)
`a-)` (kakoune: normal)
doc:
en: |
Expand All @@ -2379,7 +2379,7 @@ selections.rotate.both:
| Title | Identifier | Keybinding | Command |
| ----------------------------------- | -------------- | ----------------------- | ------------------------------------------------ |
| Rotate selections counter-clockwise | `both.reverse` | `a-)` (kakoune: normal) | `[".selections.rotate.both", { reverse: true }]` |
| Rotate selections counter-clockwise | `both.reverse` | `a-(` (kakoune: normal) | `[".selections.rotate.both", { reverse: true }]` |
selections.rotate.both.reverse:
title:
Expand All @@ -2390,7 +2390,7 @@ selections.rotate.both.reverse:
keys:
qwerty: |-
`a-)` (kakoune: normal)
`a-(` (kakoune: normal)
selections.rotate.contents:
title:
Expand Down Expand Up @@ -2419,7 +2419,7 @@ selections.rotate.selections:

keys:
qwerty: |-
`(` (kakoune: normal)
`)` (kakoune: normal)
doc:
en: |
Expand All @@ -2430,7 +2430,7 @@ selections.rotate.selections:
| Title | Identifier | Keybinding | Command |
| ----------------------------------------------------- | -------------------- | --------------------- | ------------------------------------------------------ |
| Rotate selections counter-clockwise (selections only) | `selections.reverse` | `)` (kakoune: normal) | `[".selections.rotate.selections", { reverse: true }]` |
| Rotate selections counter-clockwise (selections only) | `selections.reverse` | `(` (kakoune: normal) | `[".selections.rotate.selections", { reverse: true }]` |
selections.rotate.selections.reverse:
title:
Expand All @@ -2441,7 +2441,7 @@ selections.rotate.selections.reverse:
keys:
qwerty: |-
`)` (kakoune: normal)
`(` (kakoune: normal)
selections.save:
title:
Expand Down
40 changes: 26 additions & 14 deletions src/api/edit/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as vscode from "vscode";
import { Context, edit } from "../context";
import * as Positions from "../positions";
import * as Selections from "../selections";
import { Direction } from "../types";
import * as TrackedSelection from "../../utils/tracked-selection";

const enum Constants {
Expand Down Expand Up @@ -722,10 +723,10 @@ export declare namespace replaceByIndex {
*
* After:
* ```
* b c a
* ^ 1
* ^ 2
* ^ 0
* c a b
* ^ 2
* ^ 0
* ^ 1
* ```
*/
export function rotate(by: number, selections?: readonly vscode.Selection[]) {
Expand All @@ -752,13 +753,13 @@ export function rotate(by: number, selections?: readonly vscode.Selection[]) {
*
* After:
* ```
* b c a
* c a b
* ^ 0
* ^ 1
* ^ 2
* ```
*/
export function rotateContents(
export async function rotateContents(
by: number,
selections: readonly vscode.Selection[] = Context.current.selections,
) {
Expand All @@ -768,13 +769,24 @@ export function rotateContents(
by = (by % len) + len;

if (by === len) {
return Context.wrap(Promise.resolve(selections.slice()));
return selections.slice();
}

return replaceByIndex(
(i, _, document) => document.getText(selections[(i + by) % len]),
selections,
const sortedSelections = Selections.sort(Direction.Forward, selections.slice());
const rotatedSortedSelections =
Array.from({ length: len }, (_, i) => sortedSelections[(i + by) % len]);
const rotatedSortedSelectionsAfterEdit = await replaceByIndex(
(i, _, document) => document.getText(sortedSelections[i]),
rotatedSortedSelections,
);

// We want to return the new selections (which may have changed because sizes
// of selections may be different), but we need to revert their indices first.
return selections.map((selection) => {
const rotatedSortedIndex = rotatedSortedSelections.indexOf(selection);

return rotatedSortedSelectionsAfterEdit[rotatedSortedIndex];
});
}

/**
Expand All @@ -798,11 +810,11 @@ export function rotateContents(
* After:
* ```
* a b c
* ^ 1
* ^ 2
* ^ 0
* ^ 2
* ^ 0
* ^ 1
* ```
*/
export function rotateSelections(by: number, selections?: readonly vscode.Selection[]) {
Selections.set(Selections.rotate(by, selections));
return Selections.set(Selections.rotate(by, selections));
}
44 changes: 34 additions & 10 deletions src/api/selections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -611,15 +611,15 @@ export function updateWithFallbackByIndex<
* Before:
* ```
* foo bar baz
* ^^^ 0 ^^^ 2
* ^^^ 1
* ^^^ 1 ^^^ 0
* ^^^ 2
* ```
*
* After:
* ```
* foo bar baz
* ^^^ 1 ^^^ 0
* ^^^ 2
* ^^^ 0 ^^^ 2
* ^^^ 1
* ```
*
* ### Example
Expand All @@ -631,8 +631,8 @@ export function updateWithFallbackByIndex<
* Before:
* ```
* foo bar baz
* ^^^ 0 ^^^ 2
* ^^^ 1
* ^^^ 1 ^^^ 0
* ^^^ 2
* ```
*
* After:
Expand All @@ -655,13 +655,37 @@ export function rotate(
return selections.slice();
}

const newSelections = new Array<vscode.Selection>(selections.length);
// Figure out how much the main selection should rotate (in terms of indices)
// to rotate (visually) by `by`.
const sortedIndices = Array.from({ length: len }, (_, i) => i)
.sort((a, b) => sortTopToBottom(selections[a], selections[b]));

return Array.from({ length: len }, (_, i) => {
const indexInSortedArray = sortedIndices.indexOf(i);
const rotatedIndexInSortedArray = (indexInSortedArray + by) % len;
const rotatedIndex = sortedIndices[rotatedIndexInSortedArray];

return selections[rotatedIndex];
});
const mainIndexInSortedArray = sortedIndices.indexOf(0);
const rotatedMainIndexInSortedArray = (mainIndexInSortedArray + by) % len;
const rotatedMainIndex = sortedIndices[rotatedMainIndexInSortedArray];

// Apply that rotation with other selections.
by = rotatedMainIndex;

// Sort selections to rotate them in the order in which they appear in the
// document, _not_ in the order in which they appear in the array.
const results = new Array<vscode.Selection>(len);

for (let i = 0; i < len; i++) {
newSelections[(i + by) % len] = selections[i];
//results[(i + by) % len] = selections[i];
results[i] = selections[(i + by) % len];
}

return newSelections;
return results;
return Array.from({ length: len }, (_, i) => (i + by) % len)
.sort((a, b) => sortTopToBottom(selections[a], selections[b]))
.map((i) => selections[i]);
}

/**
Expand Down
16 changes: 8 additions & 8 deletions src/commands/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions src/commands/layouts/azerty.fr.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3ca3d83

Please sign in to comment.