Split showing error message into two separate methods. Once that appends the error to the current output panel and the second that clears the output panel before showing the error. So when no search results are found we don;t show hit enter message,
Commands entered from Visual mode (e.g. :'<,'>sort) fail because Command.execute wraps selection cleanup in runReadAction, but exitVisualMode nests a runWriteAction inside it, which deadlocks off-EDT. Remove the unnecessary runWriteAction from exitVisualMode since removeSelection only requires EDT, not a write lock.
When using \/, \?, or \& in an Ex command range (e.g., :\/ d) without a
previous search or substitute pattern, the code stored null in the
patterns list and then threw NullPointerException via the !! assertion
in calculateLine1.
Instead, throw the appropriate Vim error eagerly when building the
SearchAddress: E35 for \/ and \? (no previous search), E33 for \& (no
previous substitute). The patterns list is now non-nullable, eliminating
the !! assertion.
Add regression tests that would have caught this NPE.
Instead of checking e.message.startsWith("E130"), use the dedicated code
field on ExException, which is set by exExceptionMessage() when the exception
is created. This is more robust since it doesn't depend on message formatting.
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: 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>
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>
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
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>
- Use this.javaClass.classLoader instead of object {}.javaClass.classLoader
- Alphabetize imports in VimInjector.kt
- Remove outdated TODO in VimMotionGroupBase.kt
- Fix missing trailing newline in VimPsiService.kt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The field was used to break out of the mapping replay loop when max
recursion depth was hit. This is unnecessary since handleKey already
returns early on max depth, stopping further processing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>