Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions tests/browser/editor-font-size.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,73 @@ test("a scroll before the repaint leaves the overlay on its rows", async (t) =>
await page.close();
}
});

test("the active line highlight tracks the caret and clears on blur or selection", async (t) => {
if (!browser) return t.skip("playwright chromium unavailable");
const page = await browser.newPage();
try {
await page.goto(`${base}/interview.html`, {
waitUntil: "domcontentloaded",
});
await openEditor(page);
await fillLongBuffer(page);

const activeLine = () =>
page.evaluate(() =>
document
.querySelector("#editor")
.parentElement.style.getPropertyValue("--active-line"),
);

const expectActiveLine = async (expected, message) => {
await page.waitForFunction(
(exp) =>
document
.querySelector("#editor")
.parentElement.style.getPropertyValue("--active-line") === exp,
expected,
);

assert.equal(await activeLine(), expected, message);
};

await page.focus("#editor");
await page.evaluate(() => {
const editor = document.querySelector("#editor");
editor.setSelectionRange(0, 0);
document.dispatchEvent(new Event("selectionchange"));
});
await expectActiveLine("0", "highlight initializes at line 0");

await page.keyboard.press("ArrowDown");
await page.keyboard.press("ArrowDown");
await expectActiveLine(
"2",
"highlight tracks a collapsed caret moved by the keyboard",
);

await page.evaluate(() => {
document.querySelector("#editor").scrollBy(0, 200);
});
await expectActiveLine(
"2",
"highlight stays anchored to its row when scrolled natively",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This scroll assertion only rereads --active-line, so it passes even if the gradient scrolls away from line 2. Assert the rendered layers’ scroll behavior, such as their background-attachment, or measure the painted row after scrolling.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At tests/browser/editor-font-size.test.js, line 223:

<comment>This scroll assertion only rereads `--active-line`, so it passes even if the gradient scrolls away from line 2. Assert the rendered layers’ scroll behavior, such as their `background-attachment`, or measure the painted row after scrolling.</comment>

<file context>
@@ -181,3 +181,72 @@ test("a stored size the page does not offer falls back to the default", async (t
+    assert.equal(
+      await activeLine(),
+      "2",
+      "highlight stays anchored to its row when scrolled natively",
+    );
+
</file context>

);

await page.keyboard.down("Shift");
await page.keyboard.press("ArrowRight");
await page.keyboard.up("Shift");
await expectActiveLine("", "highlight clears on a range selection");

await page.keyboard.press("ArrowRight");
await expectActiveLine("2", "highlight restores when selection collapses");

await page.evaluate(() => {
document.querySelector("#editor").blur();
document.dispatchEvent(new Event("selectionchange"));
});
await expectActiveLine("", "highlight clears when the editor loses focus");
} finally {
await page.close();
}
});
10 changes: 10 additions & 0 deletions web/interview.js
Original file line number Diff line number Diff line change
Expand Up @@ -3327,6 +3327,16 @@ function paintEditor(showMatch = document.activeElement === nodes.editor) {
editorPaintFrame = null;
}
const code = currentCode();
const activeLine =
showMatch && nodes.editor.selectionStart === nodes.editor.selectionEnd
? code.slice(0, nodes.editor.selectionStart).split("\n").length - 1
: -1;
if (activeLine >= 0) {
nodes.editorStack?.style.setProperty("--active-line", String(activeLine));
} else {
nodes.editorStack?.style.removeProperty("--active-line");
}

const brackets =
editorOptions.highlight && showMatch
? matchingBrackets(
Expand Down
18 changes: 17 additions & 1 deletion web/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
--code-gutter: #181816;
--code-caret: #f4f4f0;
--code-selection: #264f78;
--code-active-line: #ffffff0f;
/* Selected text needs its own color: --ink is a light page color that would
stay light on a light selection background in the light theme. */
--code-selection-ink: var(--ink);
Expand Down Expand Up @@ -1024,6 +1025,7 @@ p {
--code-gutter-ink: #595959;
--code-gutter-border: #dddddd;
--code-guide: #d3d3d3;
--code-active-line: #0000000d;
--tok-keyword: #0000ff;
--tok-string: #a31515;
--tok-comment: #008000;
Expand All @@ -1049,6 +1051,7 @@ p {
--code-gutter-ink: #595959;
--code-gutter-border: #dddddd;
--code-guide: #d3d3d3;
--code-active-line: #0000000d;
--tok-keyword: #0000ff;
--tok-string: #a31515;
--tok-comment: #008000;
Expand Down Expand Up @@ -1092,6 +1095,19 @@ p {
box-shadow: inset 1px 0 0 var(--code-guide);
}

#editor-highlight,
#editor-lines {
background-image: linear-gradient(
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
var(--code-active-line),
var(--code-active-line)
);
background-repeat: no-repeat;
background-size: 100% calc(var(--editor-font-size) * 1.5);
background-position: 0
calc(1rem + var(--active-line, -100) * var(--editor-font-size) * 1.5);
background-attachment: local;
}

/* The user-agent stylesheet gives <code> its own monospace family, which
beats the inherited stack and paints the overlay in a different font from
the textarea, so the text drifts from the caret line by line. */
Expand All @@ -1107,7 +1123,7 @@ p {
padding: 1rem 0.5rem;
overflow: hidden;
color: var(--code-gutter-ink);
background: var(--code-gutter);
background-color: var(--code-active-line);
border-right: 1px solid var(--code-gutter-border);
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: var(--editor-font-size);
Expand Down