Replace old ExtensionHandler/TextObjectActionHandler pattern with the
new api.textObjects {} DSL. The indentation-based text object algorithm
is preserved but now uses VimApi extension function.
- Use api.textObjects { register() } for ai, aI, ii text objects
- Replace TextRange with TextObjectRange.LineWise
- Remove IndentObject and IndentObjectHandler classes
- Reduce code from ~280 to ~188 lines
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace old VimExtensionFacade/ExtensionHandler pattern with
VimApi.textObjects { register(...) } API
- Use Range.Simple from API module instead of internal TextRange
- Remove PortedMiniAiAction, addAction helper, and PLUG/KEY constants
- Simplify findQuoteRange and findBracketRange as VimApi extensions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace the FLAG_TEXT_BLOCK command flag with a more descriptive
`preserveSelectionAnchor` property in TextObjectActionHandler.
This property controls what happens when the selection anchor is outside
the target text object range in visual mode:
- true (default): extends selection from current anchor
- false: jumps to select only the text object
Commands like iw/aw preserve anchor (extend), while structural text
objects like i(/a(, i"/a", is/as reset anchor (jump).
Also adds comprehensive documentation with examples to both the
internal handler and the public API.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Per Vim docs: "Any trailing white space is included, unless there is
none, then leading white space is included."
Previously IdeaVim only selected the quotes and content without any
surrounding whitespace.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduce TextObjectScope for registering custom text objects via the
plugin API. Text objects can be used with operators (d, c, y) or in
visual mode.
- Add TextObjectScope interface with register() method
- Add TextObjectRange sealed interface (CharacterWise/LineWise)
- Implement TextObjectScopeImpl using IdeaVim's internal mechanisms
- Migrate VimTextObjEntireExtension from Java to Kotlin using new API
- Add textObjects() function to VimApi
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added description parameter to @TestWithoutNeovim annotations in
option mapper test classes to clarify why these tests are excluded
from Neovim verification. These tests verify integration between
IdeaVim options and IntelliJ's EditorSettingsExternalizable, which
is IDE-specific behavior not present in Neovim.
Modified files:
- ScrollOffOptionMapperTest
- SideScrollOffOptionMapperTest
- SideScrollOptionMapperTest
- ScrollJumpOptionMapperTest
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Rewrite ParagraphMotion extension using the new VimApi DSL instead of
the legacy VimExtensionFacade API. The functionality remains identical.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
In very nomagic mode (\V), backslash still has special meaning and
introduces escape sequences. When selected text contained a backslash
(e.g., \IntegerField), it was interpreted as a regex atom instead of
a literal character.
The fix escapes backslashes in the search text before building the
pattern, ensuring literal matching.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove selection parameter from updateCaret - selection now extends
automatically if present, matching Vim's native cursor movement behavior.
- Remove selection: Range.Simple? parameter from updateCaret
- Add mode-aware range validation ([0, fileSize) vs [0, fileSize])
- Remove selection-related tests that are no longer applicable
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Range.Simple and Range.Block now always have start <= end
- Document that ranges are normalized with exclusive end semantics
- Normalize Range.Block by using min/max on vimSelectionStart and offset
- Add tests verifying ranges are normalized regardless of selection direction
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change Range.Block from storing an array of per-line ranges to using
simple start/end offsets, matching how block selection is stored
internally in VimBlockSelection. The conversion to per-line ranges
now happens internally in CaretTransactionImpl.
Changes:
- Range.Block now uses (start: Int, end: Int) like Range.Simple
- Add replaceTextBlockwise(Range.Block, String) overload for single text
- Update CaretReadImpl to return block start/end from primary caret
- Add blockToLineRanges() helper in CaretTransactionImpl
- Update ReplaceWithRegisterNewApi to use simplified API
- Add 17 new tests for block selection and replacement
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added comprehensive test coverage for all ExitCommand variants that were
previously untested. The ExitCommand implementation supports multiple
command aliases (qa/qall, xa/xall, wqa/wqall, quita/quitall), but the
test suite only covered qa and qall.
Changes:
- Added tests for xa and xall commands (exit all, with save)
- Added tests for wqa and wqall commands (write quit all)
- Added tests for quita and quitall commands (alternative quit all spelling)
- Added assertPluginError(false) checks to all tests to ensure commands
execute without errors, following the pattern used in similar test files
This ensures all command variants are properly tested and prevents
regressions in any of the exit command aliases.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Also VimFuncref. This is required to protect against unbounded recursion in generated equals and hashCode functions when the list or dictionary contains internally recursive references
Add tests for previously uncovered edge cases in the index() function:
- Start index beyond list size
- Start index at list size boundary
- Negative start beyond list size
- Nested list comparisons
- Float value comparisons
- Float vs int type distinction
- ignoreCase parameter with non-string types
These tests ensure the implementation correctly handles boundary
conditions and type distinctions, improving test coverage and
preventing regressions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The removeTabAt method was incorrectly passing indexToDelete twice
instead of using the indexToSelect parameter. This caused the wrong
tab to be selected after closing a tab.
The TabCloseCommand calculates which tab should be selected after
deletion (either index + 1 if closing current tab, or keep current
selection), but this information was being ignored.
This fix ensures the correct tab is selected after :tabclose, matching
expected Vim behavior.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add test case for when caret is at the beginning of the command line
to ensure the action correctly handles this edge case without side effects.
This matches test coverage patterns in similar actions like
DeletePreviousWordActionTest and DeletePreviousCharActionTest.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fix potential ConcurrentModificationException in statistics collection by using thread-safe collections.
Issues found:
- VimscriptState.Util and PluginState.Util used non-thread-safe HashSets
- Collections were modified from EDT/user actions but read from getMetrics()
- IntelliJ's ApplicationUsagesCollector.getMetrics() may be called on background threads
- Race conditions could cause ConcurrentModificationException or data corruption
Changes:
- Replace HashSet with ConcurrentHashMap.newKeySet() for thread-safe add/read operations
- Add @Volatile annotations to boolean flags to ensure visibility across threads
- This ensures safe concurrent access between statistics writers and collectors
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This breaks a specific construct: `echo(42)(999)`. The `echo` command can parse multiple expressions without separating whitespace. IdeaVim now treats this example as a function call of the resul of the `(42)` expression, which is, of course, invalid. Vim evaluates expressions as it is parsing and declines to apply the `(999)` subscript because it knows the first expression is not a funcref/partial.
IdeaVim does not have this context, so cannot know that this is two expressions and not a function call.
I think it is better to support the `expr10(expr1, ...)` syntax and break this (what feels like niche) functionality than not have function calls through expression results at all.
The only change to the rules themselves is to add unary plus/minus to IntExpression and FloatExpression. This matches Vim's precedence, where the unary operator applies to numeric constants at a higher precedence than to other expressions. E.g. `-4->abs()` invokes `abs` on `-4`, while `-a->abs()` is the negative value of `abs(a)`.