Skip to content

Draw indent guides in the code editor - #267

Merged
jserv merged 1 commit into
sysprog21:mainfrom
sidney-Hung:editor-indent-guides
Oct 9, 2026
Merged

jserv merged 1 commit into
sysprog21:mainfrom
sidney-Hung:editor-indent-guides

Conversation

@sidney-Hung

@sidney-Hung sidney-Hung commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The code editor is a plain textarea, so when writing nested loops or branches there is no visual cue for which block a line belongs to. In Python that cue decides whether the code is correct. This adds vertical indent guides to the interview editor, one per indent level.

How it works

The syntax highlighter draws the guides, so they share the overlay's layout and scroll instead of needing a layer of their own. The textarea is unchanged.

  • web/indent-guides.js (new): indentGuides(code, tokens) measures the level width and returns one run per line that has guides: the line's leading whitespace wrapped in <span class="indent-guide"> elements.
  • web/highlight.js: highlight() splices each run into the line's leading whitespace.
  • web/interview.js: passes the runs to the highlighter, and re-syncs the overlay's scroll after each paint (see below).
  • web/styles.css: guide style, plus a --code-guide token next to --code-gutter-border: #404040 in the dark theme and #d3d3d3, VS Code Light+'s indent-guide color, in both light-theme blocks.

Design notes

  • Width from the buffer. The level width is the most common indent step between code lines, from 2 to 8 columns, with ties going to the smaller. With nothing to measure it is 4, what web/editor.js inserts for Tab. Lines continuing a comment or string don't vote, since a doc comment's * body would otherwise measure 1. JavaScript starters come out at 2; Python, Java, C and C++ at 4.
  • Partial levels keep their guide. A guide is drawn at every level column inside the leading whitespace, so 7 spaces at width 4 gives guides at columns 0 and 4. Lines continuing a comment or string are the exception, so no guide sits beside every *.
  • Whitespace-only lines take their own depth clamped between their neighbours'. An empty line inside a block keeps the guides it sits between, an empty line after a block drops the inner guide, a line just opened with Enter at the end of a block keeps the depth the caret is at, and stray spaces can't draw guides deeper than the surrounding code.
  • Guides are inline blocks; a plain inline span is shorter than the line height and the guides would render as dashes.
  • Scroll fix. The paint waits for the next frame but a scroll event doesn't, so Enter at the bottom of a long buffer could clamp the overlay's scrollTop to the old height and leave every row one above its code. The overlay's scroll is now re-synced when each paint finishes.
  • Trade-off: a buffer that mixes a 2-space starter with the 4 spaces web/editor.js inserts gets guides at 2. Making Enter and Tab insert the detected width is left for a separate change.

Screenshot

image image

Tests

  • tests/browser/indent-guides.test.js (new, 21 tests): width detection, partial levels, whitespace-only lines, comment and string lines, HTML escaping.
  • tests/browser/editor-font-size.test.js: a regression test for the scroll fix, which fails with the post-paint re-sync removed.

Closes #254

cubic-dev-ai[bot]

This comment was marked as resolved.

cubic-dev-ai[bot]

This comment was marked as resolved.

@jserv jserv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Rebase latest main branch and resolve conflicts.

Comment thread web/styles.css Outdated
@sidney-Hung
sidney-Hung force-pushed the editor-indent-guides branch from dcdefce to 22fb99e Compare October 9, 2026 03:15
@sidney-Hung

sidney-Hung commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor Author

Rebased onto main and added --code-guide next to --code-gutter-border:
#404040 in the dark default, so dark is unchanged,
and #d3d3d3, VS Code Light+'s indent-guide color, in both light blocks.
Fixed in 22fb99e.

@sidney-Hung
sidney-Hung requested a review from jserv October 9, 2026 03:54
@jserv
jserv requested review from ColtenOuO and alanhc October 9, 2026 04:27
Comment thread web/indent-guides.js Outdated
Comment thread web/interview.js Outdated
A candidate writing nested loops or branches in the plain textarea has
no visual cue for which block a line belongs to, and Python makes that
the difference between correct and broken code. The highlighter wraps
each level of a line's leading whitespace in a guide, so the guides
share the overlay's layout and scroll instead of needing a layer of
their own. The level width is measured from the buffer, because the
starters indent by two in JavaScript and by four elsewhere; the cost is
that a buffer mixing both widths gets guides at the narrower one.
@sidney-Hung
sidney-Hung force-pushed the editor-indent-guides branch from 22fb99e to cb8d07f Compare October 9, 2026 19:01
@sidney-Hung

Copy link
Copy Markdown
Contributor Author

Pushed an update addressing the review comments, and updated the PR description to match.

@ColtenOuO ColtenOuO left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, thanks for working on this.

@jserv
jserv merged commit cb5b492 into sysprog21:main Oct 9, 2026
6 checks passed
@jserv

jserv commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Thank @sidney-Hung for contributing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add indentation guides to the code editor

3 participants