Code Completion › Completion UX

Michael BrenndoerferFebruary 3, 20268 min read
Language AI HandbookAll chapters
Part 47 of 67Code Generation
Chapter 359Code Completion › Completion UX
Reading section 5 of 10 · Completion UX · 8 minSection 5 of 10 · 8 min

Book contents

Section 5 of 10 · 8 min read

Code Completion › Completion UXOne section · Sections in this chapter5 / 10 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

The best completion model in the world can fail to help developers if the suggestions are presented poorly. UX design for code completion is a careful balance between surfacing relevant suggestions and not distracting the developer from their current thought. Every design decision in this space reflects a fundamental tension: the more aggressively you surface suggestions, the more useful the system is when the suggestion is right, but the more disruptive it is when the suggestion is wrong.

Ghost Text and Inline Suggestions

The dominant UX pattern for modern LLM-based completion is ghost text: the suggested completion appears in-place at the cursor in a visually distinct style (typically grayed out or slightly transparent) as if it were already typed but not yet committed. The developer can accept the full suggestion by pressing Tab, reject it by continuing to type, or partially accept it (in systems that support it) by pressing a modifier key.

Ghost text is powerful because it is non-disruptive. The developer does not have to navigate to a dropdown or move their hands to a different control. If the suggestion is relevant, accepting it is a single keystroke. If it is not, it costs no extra effort beyond the keystrokes the developer was going to type anyway. This cost asymmetry matters: the downside of a bad suggestion is near zero, while the upside of a good one is significant.

The visual design of ghost text requires care. If it is too subtle, developers miss relevant suggestions. If it is too prominent, it becomes visually distracting when the suggestion is wrong. Most systems use a light gray color for ghost text, relying on the contrast with the editor's normal text color to make suggestions readable but non-intrusive. Font styling (italic, lighter weight) can reinforce the "provisional" nature of the suggestion without requiring strong color contrast.

Ghost text also creates a subtle psychological effect: by displaying the suggestion in-place, it makes accepting the suggestion feel like confirming rather than inserting. Developers often report that accepting a correct ghost text completion feels effortless in a way that selecting from a dropdown does not, even though the keystrokes required are similar. This perceived effortlessness increases adoption.

Multi-Line vs. Single-Line Completions

Single-line completions (completing the remainder of the current line) have a lower perceived risk for developers. The suggestion is small, easy to evaluate at a glance, and quick to dismiss if wrong. Multi-line completions (suggesting entire function bodies or code blocks) offer higher potential value but introduce new UX challenges.

A multi-line completion that is partially correct but partially wrong creates a new problem: the developer must edit the accepted suggestion rather than write from scratch. Whether this is faster than typing from scratch depends on how much editing is required. Systems that offer partial acceptance (accepting up to the end of the first line, or up to the first syntax unit) give developers finer control.

The cognitive cost of evaluating a multi-line suggestion is higher than for a single-line suggestion. A developer must read several lines, understand the proposed logic, identify any errors, and decide whether to accept or reject. For a 10-line function body, this evaluation might take 5-15 seconds, during which the developer is reading rather than writing. For suggestions that are mostly right (needing only minor tweaks), this is a worthwhile investment. For suggestions that are mostly wrong, it is pure overhead.

Automatic ghost-text multi-line completions are most useful when:

  • The developer has written a function signature and the body is predictable from the signature and surrounding context.
  • The developer is implementing a well-known pattern (sorting, filtering, error handling) that the model has seen in many forms.
  • The completion is short enough to read in under two seconds.

They are less useful for novel algorithms, business logic, or any code where the developer has not yet decided on the implementation approach. In those cases, the completion interrupts the developer's thinking rather than supporting it.

Some systems adapt their behavior based on inferred task type. Boilerplate detection heuristics (looking for patterns like "getter/setter", "constructor", "toString", or similar language-specific idioms) can identify high-confidence contexts where multi-line completions are likely to be correct, and route those requests to a larger, slower model while using a faster model for less predictable completions.

Trigger Conditions

Not every typing event should trigger a completion attempt. Showing suggestions on every keystroke would be visually overwhelming and would surface many irrelevant suggestions. Production systems use trigger conditions to decide when to initiate a request:

  • After whitespace: Pressing space or Enter after a keyword is a strong signal that the developer is starting a new construct.
  • After an opening delimiter: An open parenthesis suggests an argument list is being started, an open brace suggests a block body.
  • After a dot: Accessing a member of an object is a classic completion trigger, inherited from the original IDE completion paradigm.
  • After a pause: If the developer stops typing for more than the debounce threshold, that suggests they are thinking and may benefit from a suggestion.
  • Explicit invocation: Many systems allow manual trigger with a keyboard shortcut (Ctrl+Space or similar) for on-demand completions.

Systems also learn negative trigger conditions: if a developer has recently dismissed a suggestion at a particular cursor position, do not immediately re-trigger at the same position. This avoids the annoying behavior where the same unwanted suggestion keeps reappearing as the developer tries to dismiss it and type something different.

Trigger condition tuning is a product discipline as much as a technical one. The right set of triggers depends on the programming language (Python's dynamic typing makes member-access triggers less reliable than in Java), the editor's existing completion features (a language server may already handle symbol completion, leaving LLM completions to focus on multi-token suggestions), and the developer population's preferences (experienced developers often prefer explicit invocation over automatic triggers).

Acceptance Rates and Developer Behavior

The acceptance rate for completion suggestions varies widely across tool types and code styles. Research from GitHub Copilot and similar systems suggests acceptance rates typically range from 20% to 35% for shown completions, with significant variation by:

  • Language: Boilerplate-heavy languages (Java, C#) see higher acceptance rates than expressive languages (Python, Ruby) because boilerplate is more predictable.
  • Task type: Implementing well-known patterns sees higher acceptance. Novel logic sees lower acceptance.
  • Developer experience: More experienced developers are more selective, accepting completions that are closer to what they would have written.
  • Completion length: Shorter completions have higher acceptance rates per suggestion.
Acceptance Rate

The fraction of shown completions that a developer accepts. A key product metric for code completion systems, typically measured per session, per language, or per task type. Acceptance rate alone does not capture whether accepted completions were helpful or required subsequent editing.

Out[11]:
Visualization
Grouped bar chart of completion acceptance rates for single-line and multi-line completions across seven programming languages.
Simulated completion acceptance rates by programming language for single-line and multi-line completions. Java and C# lead due to verbose boilerplate patterns, while expressive languages like Ruby show lower rates because the same logic can be written in more ways.

Java and C# show higher acceptance rates because their verbose patterns (getter/setter boilerplate, interface implementations, XML documentation comments) are highly predictable and closely match the model's training data. Python and Ruby show lower rates because the language's expressiveness means there are more valid ways to write the same logic, making any particular suggestion less likely to match the developer's intent exactly.

Feedback Mechanisms

Beyond accept/dismiss, production systems benefit from richer feedback signals:

  • Edit after accept: If a developer accepts a completion and immediately edits it, the original suggestion needed improvement. Systems can track what was edited to identify systematic model weaknesses.
  • Re-type after dismiss: If a developer dismisses a suggestion and then types exactly what the model suggested, the suggestion was correct but perhaps poorly timed or presented.
  • Copy from suggestion: Some systems detect when a developer copies text that appeared in a dismissed suggestion, indicating partial utility.

These signals feed back into model fine-tuning pipelines, creating a continuous improvement loop between the deployed system and real developer behavior. The richest signal, however, comes from downstream outcomes: did the code that was accepted (or manually typed) work correctly? Did it require debugging? Did it appear in a subsequent bug report? These downstream signals are hard to attribute to specific completion events, but aggregating them over large populations can reveal which types of completions correlate with code quality outcomes.