diff --git a/src/components/PlanEditor.vue b/src/components/PlanEditor.vue
index 9b84f4d..18242a7 100644
--- a/src/components/PlanEditor.vue
+++ b/src/components/PlanEditor.vue
@@ -1,6 +1,7 @@
@@ -63,7 +164,24 @@ function syncScroll() {
aria-label="Macroplan TOML source"
@input="onInput"
@scroll="syncScroll"
+ @keydown="onKeydown"
+ @blur="completion = null"
>
+
+ -
+ {{ item.label }}
+ {{ item.detail }}
+
+
Can’t parse: {{ error }}
@@ -133,6 +251,42 @@ function syncScroll() {
.input::selection {
background: color-mix(in oklch, var(--color-primary) 28%, transparent);
}
+/* Completion popup, anchored just below the caret (see position()). */
+.completion {
+ position: absolute;
+ z-index: 2;
+ margin: 0;
+ padding: 0.25rem;
+ list-style: none;
+ min-width: 13rem;
+ max-width: 22rem;
+ max-height: 14rem;
+ overflow-y: auto;
+ background: var(--color-base-100);
+ border: 1px solid var(--color-base-300);
+ border-radius: 0.4rem;
+ box-shadow: 0 8px 24px color-mix(in oklch, black 16%, transparent);
+}
+.completion li {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ gap: 1.25rem;
+ padding: 0.2rem 0.5rem;
+ border-radius: 0.25rem;
+ cursor: pointer;
+ white-space: nowrap;
+}
+.completion li.active {
+ background: color-mix(in oklch, var(--color-primary) 18%, transparent);
+}
+.completion .label {
+ font-size: 0.78rem;
+}
+.completion .detail {
+ font-size: 0.68rem;
+ color: color-mix(in oklch, var(--color-base-content) 55%, transparent);
+}
.editor-error {
padding: 0.6rem 1rem;
font-size: 0.74rem;