Replace RangeHighlighter field in Exchange with HighlightId. Use
injector.highlightingService for adding/removing highlights instead
of direct markupModel access. Update Util.clearExchange to take
VimEditor. Update test assertHighlighter to check markup model
directly (area validation lost — tracked with TODO).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The old condition `!isVisualLine && (hlArea == EXACT_RANGE || isVisual)`
was equivalent to `ex.type != LINE_WISE` because when !isVisualLine is
true, hlArea is always EXACT_RANGE, making the isVisual branch
unreachable. Pure logic simplification, no behavior change.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace separate nnoremap+nmap/putExtensionHandlerMapping+putKeyMappingIfMissing
with the combined nmapPluginAction/xmapPluginAction helpers for all four
mappings (cx, cxx, cxc, X). Remove ExchangeClearHandler and VExchangeHandler
classes; their logic is now in top-level bridge functions that still delegate
to the old Operator/Util code.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Preparation for new API migration: Exchange now stores startLine/startCol/
startOffset/endLine/endCol/endOffset directly, removing dependency on the
internal Mark type. All comparison and cursor logic updated accordingly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace ExchangeHandler class with suspend fun VimApi.exchangeAction()
and register via initApi.mappings { nnoremap/nmap }.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
No behavior change — just switches from the old init() to
init(initApi) so we can incrementally migrate to the new API.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The command() handler now receives startLine and endLine (0-based)
from the resolved ex-command range. Previously the range was received
by the internal CommandAliasHandler but discarded before reaching the
plugin lambda.
Also fix using editor.projectId instead of the VimApiImpl's own
projectId, so the handler resolves the correct editor context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per VIM-4144 coroutine audit: methods inside non-locking scopes
(OptionScope, DigraphScope, OutputPanelScope) should be suspend
for RemDev future-proofing. Updated interfaces, implementations,
and extension functions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per VIM-4144 coroutine audit: read/change functions stay non-suspend
(Kotlin contracts don't support suspend, and they're already callable
from the suspend editor {} block). Block parameters stay non-suspend
(inside locks). Updated stale KDoc that referenced Deferred/Job.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per VIM-4144 coroutine audit: handler lambdas should be suspend
for RemDev future-proofing. Implementation uses runBlocking bridge.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per VIM-4144 coroutine audit: handler lambdas should be suspend
for RemDev future-proofing. Implementation uses runBlocking bridge.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per VIM-4144 coroutine audit: handler lambdas should be suspend
for RemDev future-proofing. Also exposes command() at init time.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per VIM-4144 coroutine audit: handler lambdas should be suspend
for RemDev future-proofing. Implementation uses runBlocking bridge.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove enterInsertMode(), enterNormalMode(), enterVisualMode() from VimApi.
Mode changes should use normal() — e.g., normal("<Esc>"), normal("i"),
normal("v") — matching how real Vim plugins handle mode transitions.
Neither Vim nor Neovim has a direct "set mode" API. All mode changes in
real plugins (surround, exchange, commentary, ReplaceWithRegister) use
normal!, feedkeys(), or :stopinsert. The removed methods used incomplete
internal delegation (changeMode Level 2) that skipped proper entry/exit
setup (marks, strokes, dot-repeat, document listeners).
Also removes the now-unused changeMode() function from Modes.kt.
See VIM-4143 for future proper mode-changing API design.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After setAsCurrentWindow(), getSelectedTextEditor() returns stale data
because the platform propagates the change asynchronously via
flatMapLatest + stateIn, and there is no way to observe when
propagation completes.
Comment out window APIs in VimApi, VimApiImpl, CaretRead, CaretReadImpl.
Add limitation comment to VimWindowGroup. Update EditorContextTest to
call injector.window directly. Track re-enablement in VIM-4138.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduce VimInitApi as a restricted wrapper around VimApi that exposes
only init-safe methods (getVariable, mappings, textObjects,
exportOperatorFunction). During plugin init() there is no editor context,
so editor operations should not be callable. VimInitApi enforces this at
the type level via delegation rather than inheritance.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Verify that getSelectedEditor(projectId) correctly tracks the active
editor. After opening a new editor in a split window, VimApi's
editor { read { ... } } returns data from the newly selected editor.
Also update tasks.md: mark T005, T005b, T005c complete; drop T007,
T008 per VIM-4122 ADR; mark T009 as already done.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use FileEditorManager's selected editor (internal model) instead of
focus-based detection. Falls back to injector.fallbackWindow when
projectId is null (init phase, project loading).
- Add getSelectedEditor(projectId) to VimEditorGroup interface
- Implement in EditorGroup.java using FileEditorManager
- Convert all thinapi scope impls from objects to classes accepting projectId
- Fix exportOperatorFunction to use execution-time editor.projectId
instead of init-time captured null
- Update all thinapi mock tests to mock fallbackWindow and restore
injector before tearDown
- Update CaretTransactionTest to use real projectId
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add projectId to VimApiImpl and propagate through scope implementations.
This is a pre-refactoring step before switching from getFocusedEditor()
to getSelectedEditor() API.
- VimApiImpl: Add projectId parameter (nullable), with KDoc explaining
that it's null during init and falls back to fallback editor
- Scope implementations: Pass projectId through construction chain
- MappingScopeImpl, TextObjectScopeImpl: Get projectId from editor
at execution time via editor.projectId
- Tests: Pass null for projectId (no editor context in setup)
- Remove VimApi.kt extension function (no longer needed)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add init(VimApi) experimental method to VimExtension interface
- Make init() a default empty method for backward compatibility
- Create VimApi in VimExtensionRegistrar and pass to extensions
- Migrate 7 extensions from api() to init(api: VimApi) pattern:
MiniAI, VimTextObjEntireExtension, VimIndentObject,
VimArgTextObjExtension, ParagraphMotion, ReplaceWithRegister
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
During macro execution, commands like <C-w>h can change the active
editor. Previously, the editor was captured once at macro start and
reused for all keystrokes, causing window-switching commands to
have no effect on subsequent operations.
Now we re-query FileEditorManager.selectedTextEditor on each keystroke
to get the currently selected editor.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
It's not necessary to explicitly catch the cancellation exception and return on that. Moreover, it's wrong not to re-throw the ProcessCanceledException
Decision: VimApi works in editor context only, not IDE-wide.
See YouTrack ADR for full rationale.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New task to understand and document how to obtain editors reliably:
- Why focused approach is unreliable (global state, can change mid-op)
- Normal case: capture at shortcut entry point
- Edge cases: macros with :wincmd, API commands that switch windows
Renumbered all subsequent tasks (now 82 total).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Swap K1 and K2 in Phase 2 tasks - editor context is more critical.
Add decision task T004 to define API scope (IDE-wide vs editor-only).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Verified API module structure, documented VimApi interface methods,
and identified all VimExtensionFacade usages requiring migration.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Document TeamCity CI compatibility checker in spec, plan, and tasks
- Enhance T038 with specific Vimscript execution test cases
- Enhance T039 with specific variable scope test cases
- Add T043a for vim-engine separation verification
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
94 tasks organized by user story:
- US4 (API Finalization): 24 tasks for K1-K4 issues and G1-G4 gaps
- US1 (Complete API): 14 tasks for API module completeness
- US2 (Internal Migration): 24 tasks for built-in extension migrations
- US3 (External Experience): 18 tasks for documentation and external plugin PRs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The caret can legitimately be at position chars.length (end-of-file), which is valid in IntelliJ but not a valid character index. findBlock and getQuoteRangeNoPSI assumed the caret was always on a character, causing a crash when text objects like a) were used at EOF.
Return null early when pos is out of character index range, since there is no block or quote to match at that position.
Formatting was broken in split mode and also in monolith mode cursor position restoring didn't match vim actual behaviour. refactored it to work in same way as commenting works
Commentary was doing visual selection on frontend and actual commenting
on backend which resulted in strange undo behaviour.
Moving whole commenting logic fixes all undo issues by making all actions single undo group.
Add focusNew parameter to splitWindow to allow NERDTree preview
mappings (gs, gi, ga) to keep focus on the tree.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>