Outline: enable moving items across boundaries
parent
8d85031a14
commit
8b860194d7
|
@ -6,27 +6,52 @@ export async function moveItemUp() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const currentItemBounds = determineItemBounds(text, cursorPos);
|
const currentItemBounds = determineItemBounds(text, cursorPos);
|
||||||
const previousItemBounds = determineItemBounds(
|
let previousItemBounds: ReturnType<typeof determineItemBounds> | undefined;
|
||||||
text,
|
|
||||||
currentItemBounds.from - 1,
|
|
||||||
currentItemBounds.indentLevel,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (currentItemBounds.from === previousItemBounds.from) {
|
try {
|
||||||
throw new Error("Already at the top");
|
previousItemBounds = determineItemBounds(
|
||||||
|
text,
|
||||||
|
currentItemBounds.from - 1,
|
||||||
|
currentItemBounds.indentLevel,
|
||||||
|
);
|
||||||
|
if (currentItemBounds.from === previousItemBounds.from) {
|
||||||
|
throw new Error("Already at the top");
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Ok, top of the list, let's find the previous item at any other indent level and adapt
|
||||||
|
previousItemBounds = determineItemBounds(
|
||||||
|
text,
|
||||||
|
currentItemBounds.from - 1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let newPreviousText = text.slice(
|
||||||
|
previousItemBounds.from,
|
||||||
|
previousItemBounds.to,
|
||||||
|
);
|
||||||
|
// If the current item is embedded inside the previous item, we need to strip it out
|
||||||
|
if (
|
||||||
|
currentItemBounds.from >= previousItemBounds.from &&
|
||||||
|
currentItemBounds.to <= previousItemBounds.to
|
||||||
|
) {
|
||||||
|
newPreviousText =
|
||||||
|
text.slice(previousItemBounds.from, currentItemBounds.from) +
|
||||||
|
text.slice(currentItemBounds.to, previousItemBounds.to);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newText =
|
const newText =
|
||||||
ensureNewLine(text.slice(currentItemBounds.from, currentItemBounds.to)) +
|
ensureNewLine(text.slice(currentItemBounds.from, currentItemBounds.to)) +
|
||||||
text.slice(previousItemBounds.from, previousItemBounds.to);
|
newPreviousText;
|
||||||
const newCursorPos = (cursorPos - currentItemBounds.from) +
|
const newCursorPos = (cursorPos - currentItemBounds.from) +
|
||||||
previousItemBounds.from;
|
previousItemBounds.from;
|
||||||
|
|
||||||
|
// console.log("New replacement text", newText);
|
||||||
|
|
||||||
await editor.dispatch({
|
await editor.dispatch({
|
||||||
changes: [
|
changes: [
|
||||||
{
|
{
|
||||||
from: previousItemBounds.from,
|
from: Math.min(previousItemBounds.from, currentItemBounds.from),
|
||||||
to: currentItemBounds.to,
|
to: Math.max(currentItemBounds.to, previousItemBounds.to),
|
||||||
insert: newText,
|
insert: newText,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -45,19 +70,34 @@ export async function moveItemDown() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const currentItemBounds = determineItemBounds(text, cursorPos);
|
const currentItemBounds = determineItemBounds(text, cursorPos);
|
||||||
const nextItemBounds = determineItemBounds(
|
let nextItemBounds: ReturnType<typeof determineItemBounds> | undefined;
|
||||||
text,
|
try {
|
||||||
currentItemBounds.to + 1,
|
nextItemBounds = determineItemBounds(
|
||||||
currentItemBounds.indentLevel,
|
text,
|
||||||
);
|
currentItemBounds.to + 1,
|
||||||
|
currentItemBounds.indentLevel,
|
||||||
|
);
|
||||||
|
|
||||||
if (currentItemBounds.from === nextItemBounds.from) {
|
if (currentItemBounds.from === nextItemBounds.from) {
|
||||||
|
throw new Error("Already at the bottom");
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
nextItemBounds = determineItemBounds(
|
||||||
|
text,
|
||||||
|
currentItemBounds.to + 1,
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentItemBounds.to === nextItemBounds.to) {
|
||||||
throw new Error("Already at the bottom");
|
throw new Error("Already at the bottom");
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextItemText = ensureNewLine(
|
const nextItemText = ensureNewLine(
|
||||||
text.slice(nextItemBounds.from, nextItemBounds.to),
|
text.slice(nextItemBounds.from, nextItemBounds.to),
|
||||||
);
|
);
|
||||||
|
// console.log("Next item text", nextItemText);
|
||||||
const newText = nextItemText +
|
const newText = nextItemText +
|
||||||
text.slice(currentItemBounds.from, currentItemBounds.to);
|
text.slice(currentItemBounds.from, currentItemBounds.to);
|
||||||
const newCursorPos = (cursorPos - currentItemBounds.from) +
|
const newCursorPos = (cursorPos - currentItemBounds.from) +
|
||||||
|
@ -65,8 +105,8 @@ export async function moveItemDown() {
|
||||||
await editor.dispatch({
|
await editor.dispatch({
|
||||||
changes: [
|
changes: [
|
||||||
{
|
{
|
||||||
from: currentItemBounds.from,
|
from: Math.min(nextItemBounds.from, currentItemBounds.from),
|
||||||
to: nextItemBounds.to,
|
to: Math.max(nextItemBounds.to, currentItemBounds.to),
|
||||||
insert: newText,
|
insert: newText,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -152,6 +192,7 @@ function determineItemBounds(
|
||||||
text: string,
|
text: string,
|
||||||
pos: number,
|
pos: number,
|
||||||
minIndentLevel?: number,
|
minIndentLevel?: number,
|
||||||
|
withChildren = true,
|
||||||
): { from: number; to: number; indentLevel: number } {
|
): { from: number; to: number; indentLevel: number } {
|
||||||
// Find the start of the item marked with a bullet
|
// Find the start of the item marked with a bullet
|
||||||
let currentItemStart = pos;
|
let currentItemStart = pos;
|
||||||
|
@ -199,6 +240,10 @@ function determineItemBounds(
|
||||||
while (currentItemEnd < text.length && text[currentItemEnd - 1] !== "\n") {
|
while (currentItemEnd < text.length && text[currentItemEnd - 1] !== "\n") {
|
||||||
currentItemEnd++;
|
currentItemEnd++;
|
||||||
}
|
}
|
||||||
|
if (!withChildren) {
|
||||||
|
// We're not interested in the children, so let's stop here
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Check the indent level of the next line
|
// Check the indent level of the next line
|
||||||
let nextIndentLevel = 0;
|
let nextIndentLevel = 0;
|
||||||
while (text[currentItemEnd + nextIndentLevel] === " ") {
|
while (text[currentItemEnd + nextIndentLevel] === " ") {
|
||||||
|
|
Loading…
Reference in New Issue