walker+completion: surface list trailing-optionals + identifiers-first ordering (ADR-0022 Amendment 2)

walk_repeated discarded the last matched item's trailing-optional
expectations at a clean item boundary, so a comma-separated list
offered no continuation after a complete item: `order by Name `
gave no asc/desc, `select Name ` no `as`, `create table …
Code(text) ` no not/unique/default/check. Capture the last item's
skipped set and surface it when the list ends at an item boundary
(the separator `,` itself is deliberately not surfaced).

That fix made expression-position candidate lists long, which
exposed a visibility problem: the hint panel's candidate line is
single-row and window-scrolls on overflow, centring on item 0 when
nothing is selected — so with keywords-first, schema identifiers
scrolled off behind the `>` marker. Reverse the ordering: schema
identifiers (table/column/relationship names) now sort before
keywords, since a name the user would have to look up is the
highest-value completion and must stay visible (keywords are
learned over time; the tok_identifier/tok_keyword colour split
marks the boundary). This reverses the handoff-14 keywords-first
call, now recorded in ADR-0022 Amendment 2.

Tests: walker expected-set + completion-layer regressions for the
trailing-optionals and the ordering; candidate_ordering.rs header
invariant inverted; ~20 typing-surface snapshots re-baselined; a
two-line hint box recorded as a deferred follow-up.
This commit is contained in:
claude@clouddev1
2026-05-21 21:52:49 +00:00
parent 43c49f4d1b
commit 7f68a53f86
28 changed files with 716 additions and 329 deletions
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/candidate_ordering.rs
assertion_line: 131
description: "input=\"add column to \" cursor=14"
expression: "& a"
---
@@ -10,10 +11,6 @@ Assessment {
hint: Some(
Candidates {
items: [
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -22,6 +19,10 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "table",
kind: Keyword,
},
],
selected: None,
},
@@ -34,10 +35,6 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -46,6 +43,10 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "table",
kind: Keyword,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/candidate_ordering.rs
assertion_line: 98
description: "input=\"add column \" cursor=11"
expression: "& a"
---
@@ -10,14 +11,6 @@ Assessment {
hint: Some(
Candidates {
items: [
Candidate {
text: "to",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -26,6 +19,14 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "to",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
],
selected: None,
},
@@ -38,14 +39,6 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "to",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -54,6 +47,14 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "to",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/candidate_ordering.rs
assertion_line: 56
description: "input=\"add column \" cursor=11"
expression: "& a"
---
@@ -10,14 +11,6 @@ Assessment {
hint: Some(
Candidates {
items: [
Candidate {
text: "to",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -26,6 +19,14 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "to",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
],
selected: None,
},
@@ -38,14 +39,6 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "to",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -54,6 +47,14 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "to",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/candidate_ordering.rs
assertion_line: 80
description: "input=\"change column \" cursor=14"
expression: "& a"
---
@@ -10,14 +11,6 @@ Assessment {
hint: Some(
Candidates {
items: [
Candidate {
text: "in",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -26,6 +19,14 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "in",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
],
selected: None,
},
@@ -38,14 +39,6 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "in",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -54,6 +47,14 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "in",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/candidate_ordering.rs
assertion_line: 107
description: "input=\"drop column \" cursor=12"
expression: "& a"
---
@@ -10,14 +11,6 @@ Assessment {
hint: Some(
Candidates {
items: [
Candidate {
text: "from",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -26,6 +19,14 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "from",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
],
selected: None,
},
@@ -38,14 +39,6 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "from",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -54,6 +47,14 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "from",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/candidate_ordering.rs
assertion_line: 64
description: "input=\"drop column \" cursor=12"
expression: "& a"
---
@@ -10,14 +11,6 @@ Assessment {
hint: Some(
Candidates {
items: [
Candidate {
text: "from",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -26,6 +19,14 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "from",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
],
selected: None,
},
@@ -38,14 +39,6 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "from",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -54,6 +47,14 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "from",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/candidate_ordering.rs
assertion_line: 72
description: "input=\"rename column \" cursor=14"
expression: "& a"
---
@@ -10,14 +11,6 @@ Assessment {
hint: Some(
Candidates {
items: [
Candidate {
text: "in",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -26,6 +19,14 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "in",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
],
selected: None,
},
@@ -38,14 +39,6 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "in",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -54,6 +47,14 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "in",
kind: Keyword,
},
Candidate {
text: "table",
kind: Keyword,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/constraints.rs
assertion_line: 30
description: "input=\"create table Ages with pk age(int) check (age >= 0)\" cursor=51"
expression: "& a"
---
@@ -8,11 +9,55 @@ Assessment {
cursor: 51,
state: Valid,
hint: Some(
Prose(
"Submit with Enter",
),
Candidates {
items: [
Candidate {
text: "not",
kind: Keyword,
},
Candidate {
text: "unique",
kind: Keyword,
},
Candidate {
text: "default",
kind: Keyword,
},
Candidate {
text: "check",
kind: Keyword,
},
],
selected: None,
},
),
completion: Some(
Completion {
replaced_range: (
51,
51,
),
partial_prefix: "",
candidates: [
Candidate {
text: "not",
kind: Keyword,
},
Candidate {
text: "unique",
kind: Keyword,
},
Candidate {
text: "default",
kind: Keyword,
},
Candidate {
text: "check",
kind: Keyword,
},
],
},
),
completion: None,
parse_result: Ok(
"CreateTable",
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/constraints.rs
assertion_line: 19
description: "input=\"create table Books with pk isbn(text) default '000'\" cursor=51"
expression: "& a"
---
@@ -8,11 +9,55 @@ Assessment {
cursor: 51,
state: Valid,
hint: Some(
Prose(
"Submit with Enter",
),
Candidates {
items: [
Candidate {
text: "not",
kind: Keyword,
},
Candidate {
text: "unique",
kind: Keyword,
},
Candidate {
text: "default",
kind: Keyword,
},
Candidate {
text: "check",
kind: Keyword,
},
],
selected: None,
},
),
completion: Some(
Completion {
replaced_range: (
51,
51,
),
partial_prefix: "",
candidates: [
Candidate {
text: "not",
kind: Keyword,
},
Candidate {
text: "unique",
kind: Keyword,
},
Candidate {
text: "default",
kind: Keyword,
},
Candidate {
text: "check",
kind: Keyword,
},
],
},
),
completion: None,
parse_result: Ok(
"CreateTable",
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/create_table.rs
assertion_line: 117
description: "input=\"create table Memberships with pk UserId(int), GroupId(int)\" cursor=58"
expression: "& a"
---
@@ -8,11 +9,55 @@ Assessment {
cursor: 58,
state: Valid,
hint: Some(
Prose(
"Submit with Enter",
),
Candidates {
items: [
Candidate {
text: "not",
kind: Keyword,
},
Candidate {
text: "unique",
kind: Keyword,
},
Candidate {
text: "default",
kind: Keyword,
},
Candidate {
text: "check",
kind: Keyword,
},
],
selected: None,
},
),
completion: Some(
Completion {
replaced_range: (
58,
58,
),
partial_prefix: "",
candidates: [
Candidate {
text: "not",
kind: Keyword,
},
Candidate {
text: "unique",
kind: Keyword,
},
Candidate {
text: "default",
kind: Keyword,
},
Candidate {
text: "check",
kind: Keyword,
},
],
},
),
completion: None,
parse_result: Ok(
"CreateTable",
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/create_table.rs
assertion_line: 106
description: "input=\"create table Customers with pk Code(text)\" cursor=41"
expression: "& a"
---
@@ -8,11 +9,55 @@ Assessment {
cursor: 41,
state: Valid,
hint: Some(
Prose(
"Submit with Enter",
),
Candidates {
items: [
Candidate {
text: "not",
kind: Keyword,
},
Candidate {
text: "unique",
kind: Keyword,
},
Candidate {
text: "default",
kind: Keyword,
},
Candidate {
text: "check",
kind: Keyword,
},
],
selected: None,
},
),
completion: Some(
Completion {
replaced_range: (
41,
41,
),
partial_prefix: "",
candidates: [
Candidate {
text: "not",
kind: Keyword,
},
Candidate {
text: "unique",
kind: Keyword,
},
Candidate {
text: "default",
kind: Keyword,
},
Candidate {
text: "check",
kind: Keyword,
},
],
},
),
completion: None,
parse_result: Ok(
"CreateTable",
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/delete_with_where.rs
assertion_line: 60
description: "input=\"delete from Customers where Email=\" cursor=34"
expression: "& a"
---
@@ -20,18 +21,6 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "null",
kind: Keyword,
},
Candidate {
text: "true",
kind: Keyword,
},
Candidate {
text: "false",
kind: Keyword,
},
Candidate {
text: "Email",
kind: Identifier,
@@ -44,6 +33,18 @@ Assessment {
text: "id",
kind: Identifier,
},
Candidate {
text: "null",
kind: Keyword,
},
Candidate {
text: "true",
kind: Keyword,
},
Candidate {
text: "false",
kind: Keyword,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/delete_with_where.rs
assertion_line: 39
description: "input=\"delete from Customers where \" cursor=28"
expression: "& a"
---
@@ -10,6 +11,14 @@ Assessment {
hint: Some(
Candidates {
items: [
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
Candidate {
text: "not",
kind: Keyword,
@@ -30,14 +39,6 @@ Assessment {
text: "(",
kind: Punct,
},
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
],
selected: None,
},
@@ -50,6 +51,14 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
Candidate {
text: "not",
kind: Keyword,
@@ -70,14 +79,6 @@ Assessment {
text: "(",
kind: Punct,
},
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/delete_with_where.rs
assertion_line: 86
description: "input=\"delete from Things where ts=\" cursor=28"
expression: "& a"
---
@@ -20,18 +21,6 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "null",
kind: Keyword,
},
Candidate {
text: "true",
kind: Keyword,
},
Candidate {
text: "false",
kind: Keyword,
},
Candidate {
text: "auto",
kind: Identifier,
@@ -72,6 +61,18 @@ Assessment {
text: "ts",
kind: Identifier,
},
Candidate {
text: "null",
kind: Keyword,
},
Candidate {
text: "true",
kind: Keyword,
},
Candidate {
text: "false",
kind: Keyword,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/drop_column.rs
assertion_line: 19
description: "input=\"drop column from \" cursor=17"
expression: "& a"
---
@@ -10,10 +11,6 @@ Assessment {
hint: Some(
Candidates {
items: [
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -22,6 +19,10 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "table",
kind: Keyword,
},
],
selected: None,
},
@@ -34,10 +35,6 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "table",
kind: Keyword,
},
Candidate {
text: "Customers",
kind: Identifier,
@@ -46,6 +43,10 @@ Assessment {
text: "Orders",
kind: Identifier,
},
Candidate {
text: "table",
kind: Keyword,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/drop_relationship.rs
assertion_line: 37
description: "input=\"drop relationship \" cursor=18"
expression: "& a"
---
@@ -10,14 +11,14 @@ Assessment {
hint: Some(
Candidates {
items: [
Candidate {
text: "from",
kind: Keyword,
},
Candidate {
text: "Orders_CustId_to_Customers",
kind: Identifier,
},
Candidate {
text: "from",
kind: Keyword,
},
],
selected: None,
},
@@ -30,14 +31,14 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "from",
kind: Keyword,
},
Candidate {
text: "Orders_CustId_to_Customers",
kind: Identifier,
},
Candidate {
text: "from",
kind: Keyword,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/explain.rs
assertion_line: 54
description: "input=\"explain show data Customers where \" cursor=34"
expression: "& a"
---
@@ -10,6 +11,14 @@ Assessment {
hint: Some(
Candidates {
items: [
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
Candidate {
text: "not",
kind: Keyword,
@@ -30,14 +39,6 @@ Assessment {
text: "(",
kind: Punct,
},
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
],
selected: None,
},
@@ -50,6 +51,14 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
Candidate {
text: "not",
kind: Keyword,
@@ -70,14 +79,6 @@ Assessment {
text: "(",
kind: Punct,
},
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/update_with_where.rs
assertion_line: 152
description: "input=\"update Customers set Email='x' where id=\" cursor=40"
expression: "& a"
---
@@ -20,18 +21,6 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "null",
kind: Keyword,
},
Candidate {
text: "true",
kind: Keyword,
},
Candidate {
text: "false",
kind: Keyword,
},
Candidate {
text: "Email",
kind: Identifier,
@@ -44,6 +33,18 @@ Assessment {
text: "id",
kind: Identifier,
},
Candidate {
text: "null",
kind: Keyword,
},
Candidate {
text: "true",
kind: Keyword,
},
Candidate {
text: "false",
kind: Keyword,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/update_with_where.rs
assertion_line: 135
description: "input=\"update Customers set Name='x' where \" cursor=36"
expression: "& a"
---
@@ -10,6 +11,14 @@ Assessment {
hint: Some(
Candidates {
items: [
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
Candidate {
text: "not",
kind: Keyword,
@@ -30,14 +39,6 @@ Assessment {
text: "(",
kind: Punct,
},
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
],
selected: None,
},
@@ -50,6 +51,14 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
Candidate {
text: "not",
kind: Keyword,
@@ -70,14 +79,6 @@ Assessment {
text: "(",
kind: Punct,
},
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/where_expression.rs
assertion_line: 42
description: "input=\"delete from Customers where not \" cursor=32"
expression: "& a"
---
@@ -10,6 +11,18 @@ Assessment {
hint: Some(
Candidates {
items: [
Candidate {
text: "Email",
kind: Identifier,
},
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
Candidate {
text: "not",
kind: Keyword,
@@ -30,18 +43,6 @@ Assessment {
text: "(",
kind: Punct,
},
Candidate {
text: "Email",
kind: Identifier,
},
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
],
selected: None,
},
@@ -54,6 +55,18 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "Email",
kind: Identifier,
},
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
Candidate {
text: "not",
kind: Keyword,
@@ -74,18 +87,6 @@ Assessment {
text: "(",
kind: Punct,
},
Candidate {
text: "Email",
kind: Identifier,
},
Candidate {
text: "Name",
kind: Identifier,
},
Candidate {
text: "id",
kind: Identifier,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/where_expression.rs
assertion_line: 50
description: "input=\"delete from Things where k between \" cursor=35"
expression: "& a"
---
@@ -20,18 +21,6 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "null",
kind: Keyword,
},
Candidate {
text: "true",
kind: Keyword,
},
Candidate {
text: "false",
kind: Keyword,
},
Candidate {
text: "auto",
kind: Identifier,
@@ -72,6 +61,18 @@ Assessment {
text: "ts",
kind: Identifier,
},
Candidate {
text: "null",
kind: Keyword,
},
Candidate {
text: "true",
kind: Keyword,
},
Candidate {
text: "false",
kind: Keyword,
},
],
},
),
@@ -1,5 +1,6 @@
---
source: tests/typing_surface/where_expression.rs
assertion_line: 58
description: "input=\"delete from Things where k in (\" cursor=31"
expression: "& a"
---
@@ -20,18 +21,6 @@ Assessment {
),
partial_prefix: "",
candidates: [
Candidate {
text: "null",
kind: Keyword,
},
Candidate {
text: "true",
kind: Keyword,
},
Candidate {
text: "false",
kind: Keyword,
},
Candidate {
text: "auto",
kind: Identifier,
@@ -72,6 +61,18 @@ Assessment {
text: "ts",
kind: Identifier,
},
Candidate {
text: "null",
kind: Keyword,
},
Candidate {
text: "true",
kind: Keyword,
},
Candidate {
text: "false",
kind: Keyword,
},
],
},
),