fix: autospace cursor wonkyness

This commit is contained in:
2025-11-28 17:33:55 +01:00
parent 6895fa4a82
commit 7beab5ac07

View File

@@ -11,6 +11,7 @@
import { get } from "svelte/store"; import { get } from "svelte/store";
import { action } from "$lib/title"; import { action } from "$lib/title";
import semverGte from "semver/functions/gte"; import semverGte from "semver/functions/gte";
import Action from "$lib/components/Action.svelte";
let { chord }: { chord: ChordInfo } = $props(); let { chord }: { chord: ChordInfo } = $props();
@@ -27,14 +28,14 @@
if (!event.shiftKey && event.key === "ArrowUp") { if (!event.shiftKey && event.key === "ArrowUp") {
addSpecial(event); addSpecial(event);
} else if (!event.shiftKey && event.key === "ArrowLeft") { } else if (!event.shiftKey && event.key === "ArrowLeft") {
moveCursor(cursorPosition - 1); moveCursor(cursorPosition - 1, true);
} else if (!event.shiftKey && event.key === "ArrowRight") { } else if (!event.shiftKey && event.key === "ArrowRight") {
moveCursor(cursorPosition + 1); moveCursor(cursorPosition + 1, true);
} else if (event.key === "Backspace") { } else if (event.key === "Backspace") {
deleteAction(cursorPosition - 1); deleteAction(cursorPosition - 1, 1, true);
moveCursor(cursorPosition - 1); moveCursor(cursorPosition - 1, true);
} else if (event.key === "Delete") { } else if (event.key === "Delete") {
deleteAction(cursorPosition); deleteAction(cursorPosition, 1, true);
} else { } else {
if (event.key === "Shift") return; if (event.key === "Shift") return;
const action = inputToAction(event, get(serialPort)?.device === "X"); const action = inputToAction(event, get(serialPort)?.device === "X");
@@ -45,14 +46,24 @@
} }
} }
function moveCursor(to: number) { function moveCursor(to: number, user = false) {
if (!box) return; if (!box) return;
cursorPosition = Math.max(0, Math.min(to, chord.phrase.length)); cursorPosition = Math.max(
user ? chord.phrase.findIndex((it, i, arr) => !isHidden(it, i, arr)) : 0,
Math.min(
to,
user
? chord.phrase.findLastIndex((it, i, arr) => !isHidden(it, i, arr)) +
1 || chord.phrase.length
: chord.phrase.length,
),
);
const item = box.children.item(cursorPosition) as HTMLElement; const item = box.children.item(cursorPosition) as HTMLElement;
cursorOffset = item.offsetLeft + item.offsetWidth; cursorOffset = item.offsetLeft + item.offsetWidth;
} }
function deleteAction(at: number, count = 1) { function deleteAction(at: number, count = 1, user = false) {
if (user && isHidden(chord.phrase[at]!, at, chord.phrase)) return;
if (!(at in chord.phrase)) return; if (!(at in chord.phrase)) return;
changes.update((changes) => { changes.update((changes) => {
changes.push([ changes.push([
@@ -89,12 +100,12 @@
for (const child of box.children) { for (const child of box.children) {
const { offsetLeft, offsetWidth } = child as HTMLElement; const { offsetLeft, offsetWidth } = child as HTMLElement;
if (distance < offsetLeft + offsetWidth / 2) { if (distance < offsetLeft + offsetWidth / 2) {
moveCursor(i - 1); moveCursor(i - 1, true);
return; return;
} }
i++; i++;
} }
moveCursor(i - 1); moveCursor(i - 1, true);
} }
function addSpecial(event: MouseEvent | KeyboardEvent) { function addSpecial(event: MouseEvent | KeyboardEvent) {
@@ -118,6 +129,7 @@
) )
) { ) {
deleteAction(chord.phrase.length - 1); deleteAction(chord.phrase.length - 1);
moveCursor(cursorPosition, true);
} else { } else {
return; return;
} }
@@ -126,13 +138,16 @@
return; return;
} else if (chord.phrase.at(-1) === NO_CONCATENATOR_ACTION) { } else if (chord.phrase.at(-1) === NO_CONCATENATOR_ACTION) {
deleteAction(chord.phrase.length - 1); deleteAction(chord.phrase.length - 1);
moveCursor(cursorPosition, true);
} else { } else {
insertAction(chord.phrase.length, JOIN_ACTION); insertAction(chord.phrase.length, JOIN_ACTION);
moveCursor(cursorPosition, true);
} }
} }
} else { } else {
if (chord.phrase.at(-1) === JOIN_ACTION) { if (chord.phrase.at(-1) === JOIN_ACTION) {
deleteAction(chord.phrase.length - 1); deleteAction(chord.phrase.length - 1);
moveCursor(cursorPosition, true);
} else { } else {
if (chord.phrase.at(-1) === NO_CONCATENATOR_ACTION) { if (chord.phrase.at(-1) === NO_CONCATENATOR_ACTION) {
if ( if (
@@ -144,9 +159,11 @@
return; return;
} else { } else {
deleteAction(chord.phrase.length - 1); deleteAction(chord.phrase.length - 1);
moveCursor(cursorPosition, true);
} }
} else { } else {
insertAction(chord.phrase.length, NO_CONCATENATOR_ACTION); insertAction(chord.phrase.length, NO_CONCATENATOR_ACTION);
moveCursor(cursorPosition, true);
} }
} }
} }
@@ -171,16 +188,13 @@
isPrintable || chord.phrase.at(-1) === JOIN_ACTION, isPrintable || chord.phrase.at(-1) === JOIN_ACTION,
); );
let displayPhrase = $derived( function isHidden(action: number, index: number, array: number[]) {
chord.phrase.filter( return (
(it, i, arr) => (index === 0 && action === JOIN_ACTION) ||
!( (index === array.length - 1 &&
(i === 0 && it === JOIN_ACTION) || (action === JOIN_ACTION || action === NO_CONCATENATOR_ACTION))
(i === arr.length - 1 && );
(it === JOIN_ACTION || it === NO_CONCATENATOR_ACTION)) }
),
),
);
</script> </script>
<div <div
@@ -196,18 +210,22 @@
use:action={{ title: "Remove previous concatenator" }} use:action={{ title: "Remove previous concatenator" }}
><span class="icon">join_inner</span><input ><span class="icon">join_inner</span><input
checked={chord.phrase[0] === JOIN_ACTION} checked={chord.phrase[0] === JOIN_ACTION}
onchange={(event) => { onchange={async (event) => {
const autospace = hasAutospace; const autospace = hasAutospace;
if ((event.target as HTMLInputElement).checked) { if ((event.target as HTMLInputElement).checked) {
if (chord.phrase[0] !== JOIN_ACTION) { if (chord.phrase[0] !== JOIN_ACTION) {
insertAction(0, JOIN_ACTION); insertAction(0, JOIN_ACTION);
moveCursor(cursorPosition + 1, true);
} }
} else { } else {
if (chord.phrase[0] === JOIN_ACTION) { if (chord.phrase[0] === JOIN_ACTION) {
deleteAction(0, 1); deleteAction(0, 1);
await tick();
moveCursor(cursorPosition - 1, true);
} }
} }
tick().then(() => resolveAutospace(autospace)); await tick();
resolveAutospace(autospace);
}} }}
type="checkbox" type="checkbox"
/></label /></label
@@ -233,7 +251,13 @@
<div></div> <div></div>
<!-- placeholder for cursor placement --> <!-- placeholder for cursor placement -->
{/if} {/if}
<ActionString actions={displayPhrase} /> {#each chord.phrase as action, i}
{#if isHidden(action, i, chord.phrase)}
<span style:display="none"></span>
{:else}
<Action display="inline-keys" {action} />
{/if}
{/each}
</div> </div>
{#if supportsAutospace} {#if supportsAutospace}
<label class="auto-space-edit" use:action={{ title: "Add concatenator" }} <label class="auto-space-edit" use:action={{ title: "Add concatenator" }}