Skip to content

Conversation

@asukaminato0721
Copy link
Contributor

fix #686

Implemented LSP inline completion (ghost text) end‑to‑end and added Tab acceptance.
Inline completions are now requested on trigger/quick‑suggestion input and on manual completion, rendered as unpadded virtual text, and applied as proper LSP edits with snippet expansion.
Inlay hints no longer clear unrelated virtual text, so ghost text stays intact.
Updated LSP capability negotiation and tracking for inline completion support.

@asukaminato0721 asukaminato0721 marked this pull request as ready for review January 22, 2026 10:10
Copilot AI review requested due to automatic review settings January 22, 2026 10:10
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements end-to-end LSP inline completion (“ghost text”) support, including capability negotiation, rendering without padding, and Tab-to-accept behavior while keeping inlay hints from clearing unrelated virtual text.

Changes:

  • Added inline completion LSP request/response plumbing and per-language capability tracking.
  • Rendered ghost text as inline virtual text without automatic padding; ensured inlay hints only clear their own virtual text.
  • Implemented Tab acceptance to apply inline completion edits with snippet expansion, plus added tests.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
crates/fresh-editor/src/view/virtual_text.rs Adds pad_inline control and a new API for inline virtual text insertion with padding configuration.
crates/fresh-editor/src/view/ui/split_rendering.rs Respects pad_inline to render ghost text without added spaces.
crates/fresh-editor/src/services/lsp/manager.rs Tracks inline completion support per language.
crates/fresh-editor/src/services/lsp/async_handler.rs Negotiates inline completion capabilities and implements textDocument/inlineCompletion request handling.
crates/fresh-editor/src/services/async_bridge.rs Adds async message types and payloads for inline completion initialization and responses.
crates/fresh-editor/src/app/toggle_actions.rs Stops clearing all virtual text when disabling inlay hints; clears only inlay-hint virtual texts.
crates/fresh-editor/src/app/mod.rs Adds editor state for pending/active inline completion and routes async inline completion responses.
crates/fresh-editor/src/app/lsp_requests.rs Requests inline completions, renders ghost text, accepts via LSP edits/snippet expansion, and adds tests.
crates/fresh-editor/src/app/input.rs Adds Tab acceptance path and ensures ghost text is cleared on most edits/actions.
Cargo.toml Enables lsp-types proposed features required for inline completion types/capabilities.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +715 to +716
self.apply_event_to_active_buffer(&move_event);
self.active_event_log_mut().append(move_event);
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

accept_inline_completion applies the cursor move via apply_event_to_active_buffer and appends to active_event_log_mut(). If buffer_id differs from the active buffer (e.g., user switched buffers after ghost text appeared), this will move/log against the wrong buffer and break undo/cursor state. Apply the move event to buffer_id’s state and append it to that buffer’s event log instead (consistent with other cursor move handling).

Suggested change
self.apply_event_to_active_buffer(&move_event);
self.active_event_log_mut().append(move_event);
self.apply_event_to_buffer(buffer_id, &move_event);
self.event_log_for_buffer_mut(buffer_id).append(move_event);

Copilot uses AI. Check for mistakes.
Comment on lines +572 to +575
if sent {
self.next_lsp_request_id += 1;
self.pending_inline_completion_request = Some(request_id);
}
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

request_inline_completion overwrites pending_inline_completion_request when a new request is sent. If a previous inline completion request is still pending, its ID is lost so it can’t be canceled and the eventual response will be ignored, causing unnecessary server work. Consider canceling the previous pending inline-completion request (or skipping sending a new one) before setting a new pending request ID.

Copilot uses AI. Check for mistakes.
priority: i32,
string_id: String,
pad_inline: bool,
) -> VirtualTextId {
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

add_inline_with_id accepts any VirtualTextPosition but its name implies it should only be used with inline positions. Add a debug_assert!(vtext_position.is_inline(), ...) (similar to add_line) to prevent accidental misuse (e.g., passing LineAbove/LineBelow, where pad_inline is meaningless).

Suggested change
) -> VirtualTextId {
) -> VirtualTextId {
debug_assert!(
vtext_position.is_inline(),
"add_inline_with_id requires BeforeChar or AfterChar"
);

Copilot uses AI. Check for mistakes.
@sinelaw
Copy link
Owner

sinelaw commented Jan 22, 2026

I'm trying it but don't see anything - can you give an example I can try where it kicks in?

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.

support ghost text

2 participants