IdeaVim extension with advanced text increment and decrement functionality. It enhances the standard increment/decrement functionality found in Vim editors by adding support for complex text patterns beyond simple numbers.
Cycle through related values from various text elements, including numbers, dates, boolean values, operators, and programming language-specific keywords.
- Vim-like Behavior: Increment or decrement numbers just like Vim's
Ctrl+A/Ctrl+X - Search from cursor: Transforms the first matching word found from the cursor position forward within the current line
- Works within words: Cursor can be also within the target word
- Customizable: Define your own sets of transformations and enable them in your
.ideavimrc
- Numeric Values: Increment/decrement integers, decimals, and scientific notation
- Boolean Values: Toggle between
true/false,True/False - Logical Operators: Switch between
&&/||,and/or,AND/OR - Comparison Operators: Toggle
==/!=,is/is not,>/<,>=/<= - Bitwise Operators: Switch between
&/| - Directional Values: Cycle through
up/down/left/right - Quote Styles: Rotate between
"string",'string', `string` - Date/Time: Smart date and time manipulation
- Language-specific: Support specific transformations for Java, Python, JavaScript, Rust or Markdown
- Cursor Position Sensitive: Works regardless of where your cursor is within or before the target text
- Word Boundary Recognition: Distinguishes between whole words and partial matches
- Case Preservation: Maintains original case when transforming text
- Multiple Matches: Automatically selects the closest match to your cursor
- Install the plugin from the IntelliJ IDEA Plugin Marketplace
- Ensure you have the IdeaVim plugin installed and enabled
- Activate the plugin in your
.ideavimrc - Restart IntelliJ IDEA
- Download the latest release
- Install manually using Settings/Preferences > Plugins > ⚙️ > Install plugin from disk...
Configure which transformation groups to enable in your .ideavimrc:
" Activate plugin
set dial
" Enable multiple groups
let g:dial_include = "basic,numbers,dates"
" Enable some categories (basic, numbers, dates, java) and some specific transformations (python:async, markdown:task_item)
let g:dial_include = "basic,numbers,dates,java,python:async,markdown:task_item"
" Custom transformations
let g:dial_custom_definitions = [
['normalizedCaseWords', ['one', 'two', 'three']],
['words', ['un', 'deux', 'trois']],
['normalizedCasePattern', ['alpha', 'beta', 'gamma']],
['pattern', ['start', 'middle', 'end']]
]Add these mappings to your .ideavimrc:
" Map Ctrl+A to increment
nnoremap <C-a> :DialIncrement<cr>
" Map Ctrl+X to decrement
nnoremap <C-x> :DialDecrement<cr>If not specified, basic, number, and date groups are enabled by default. Also, specific language groups are enabled by default based on the JetBrains application in use. For example, IntelliJ IDEA will enable Java specific transformations, Pycharm will enable Python transformations, etc.
basic: Boolean values, operators, directions, quotesnumbers: Integer, decimal, and scientific notationdates: Date and time patternsjava: Java-specific patterns (visibility, basic types, collections methods, streams, etc.)python: Python-specific patterns (basic types, loops, collections, etc.)javascript: JavaScript-specific patternsmarkdown: Markdown formattingrust: Rust-specific patterns
| Category | Transformation |
|---|---|
| Boolean Values | true ↔ false |
True ↔ False |
|
| Logical Operators | and ↔ or |
AND ↔ OR |
|
&& ↔ || |
|
| Comparison | == ↔ != |
is ↔ is not |
|
> ↔ < |
|
>= ↔ <= |
|
| Directional Words | up ↔ down ↔ left ↔ right |
| HTTP Methods | GET ↔ POST ↔ PUT ↔ DELETE |
| Log Levels | debug ↔ info ↔ warn ↔ error |
| Category | Before | After (Increment) | After (Decrement) | Description |
|---|---|---|---|---|
| Unsigned Integers | 42 |
43 |
41 |
Positive whole numbers |
0 |
1 |
-1 |
Zero becomes negative when decremented | |
999 |
1000 |
998 |
Large integers | |
| Signed Integers | +15 |
+16 |
+14 |
Explicitly positive integers |
-5 |
-4 |
-6 |
Negative integers | |
-1 |
0 |
-2 |
Negative to zero transition | |
| Unsigned Decimals | 3.14 |
3.15 |
3.13 |
Decimal precision maintained |
1.0 |
1.1 |
0.9 |
Single decimal place | |
10.123 |
10.124 |
10.122 |
Multiple decimal places | |
0.001 |
0.002 |
0.000 |
Small increments | |
| Signed Decimals | +2.5 |
+2.6 |
+2.4 |
Explicitly positive decimals |
-1.75 |
-1.74 |
-1.76 |
Negative decimals | |
-0.1 |
0.0 |
-0.2 |
Crossing zero boundary | |
| Scientific Notation | 1e2 |
2e2 |
0e2 |
Integer base with exponent |
1E-3 |
2E-3 |
0E-3 |
Uppercase E notation | |
2.5e10 |
3.5e10 |
1.5e10 |
Decimal base with exponent | |
-1.0E-2 |
-0.0E-2 |
-2.0E-2 |
Negative scientific notation |
| Format | Example | Increment Unit |
|---|---|---|
| ISO Date | 2023-12-25 |
Days |
| European Date | 25.12.2023 |
Days |
| US Date | 12/25/2023 |
Days |
| Time 24h | 14:30 |
Minutes |
| Time with Seconds | 14:30:45 |
Seconds |
| Time 12h | 2:30 PM |
Minutes |
| ISO DateTime | 2023-12-25T14:30:45 |
Seconds |
| ISO DateTime with TZ | 2023-12-25T14:30:45Z |
Seconds |
| Category | Transformation |
|---|---|
| Assertions | assertEquals ↔ assertNotEquals |
assertFalse ↔ assertTrue |
|
assertNull ↔ assertNotNull |
|
| Visibility Modifiers | public ↔ private ↔ protected |
| Optional Methods | .isPresent ↔ .isEmpty |
| Collection Types | ArrayList ↔ HashSet |
| Data Types | int ↔ long ↔ float ↔ double ↔ boolean |
| Flow Control | if ↔ else if |
| Loop Types | for ↔ while |
| Loop Control | break ↔ continue |
| Collection Operations | .add ↔ .remove |
| String Case | .toLowerCase ↔ .toUpperCase |
| Streams | .map ↔ .flatMap |
.filter ↔ .peek |
|
.findAny ↔ .findFirst |
|
.anyMatch ↔ .allMatch ↔ .noneMatch |
| Category | Transformation |
|---|---|
| Comparison Operators | == ↔ != |
is ↔ is not |
|
in ↔ not in |
|
| Data Types | int ↔ float ↔ str ↔ bool |
| Flow Control | if ↔ elif |
| Loop Types | for ↔ while |
| Loop Control | break ↔ continue |
| Function Definitions | def ↔ async def |
| Context Managers | with ↔ async with |
| Class Decorators | @property↔@classmethod↔@staticmethod |
| Collection Types | list(↔tuple(↔set(↔dict( |
| Collection Operations | .append(↔.extend(↔.insert(↔.remove(↔.pop( |
| String Case | .upper()↔.lower() |
| Assertions | assertFalse assertTrue |
assertEqual ↔ assertNotEqual |
|
assertIn ↔ assertNotIn |
|
| String Quotes | 'text' ↔ "text" |
| Category | Transformation |
|---|---|
| Named functions / Arrow functions expressions | function name() {} ↔ const name = () => {} |
| Arrow functions / Anonymous functions | () => {} ↔ function() {} |
| Anonymous functions expressions / Named functions | const name = function(){} ↔ function name() {} |
| Variable Declarations | let ↔ var ↔ const |
Note: Function transformations preserve parameter lists and async keywords when present.
| Category | Transformation |
|---|---|
| Basic Types | string ↔ number ↔ boolean ↔ object ↔ any ↔ unknown ↔ never ↔ void |
| Utility Types | Partial ↔ Required ↔ Readonly ↔ Pick ↔ Omit ↔ Record |
| Access Modifiers | public ↔ private ↔ protected ↔ readonly |
| Category | Transformation |
|---|---|
| Task Lists | - [ ] ↔ - [x] |
| Category | Transformation |
|---|---|
| Boolean Values | true ↔ false |
| Mutability | let mut ↔ let |
| Visibility | pub ↔ pub(crate) ↔ pub(super) ↔ pub(self) |
| Result Handling | .unwrap() ↔ .expect() ↔ .unwrap_or_default() |
| Option Handling | .some() ↔ .none() |
| Comparison Operators | == ↔ != |
| Logical Operators | && ↔ || |
| Memory Management | Box::new() ↔ Rc::new() ↔ Arc::new() |
| String Types | &str ↔ String |
| Integer Types | i32 ↔ i64 ↔ u32 ↔ u64 ↔ usize ↔ isize |
| Float Types | f32 ↔ f64 |
| Collection Methods | .iter() ↔ .iter_mut() ↔ .into_iter() |
| Vector Operations | .push() ↔ .pop() |
| Assertions | assert! ↔ assert_eq! ↔ assert_ne! |
| Debug/Release | debug_assert! ↔ assert! |
| Match Arms | Some(_) ↔ None |
| Error Propagation | ? ↔ .unwrap() |
Add custom definitions to your file using the following format: .ideavimrc
let g:dial_custom_definitions = [
['normalizedCaseWords', ['one', 'two', 'three']],
['words', ['un', 'deux', 'trois']],
['normalizedCasePattern', ['alpha', 'beta', 'gamma']],
['pattern', ['start', 'middle', 'end']]
]- Case insensitive matching
- Word boundaries required (won't match partial words)
- Example:
One→ →Three→OneTwo
- Case sensitive matching
- Word boundaries required (won't match partial words)
- Example:
un→deux→trois→un
- Case insensitive matching
- No word boundaries (matches anywhere in text)
- Example:
Alpha123→Beta123→Gamma123→Alpha123
- Case sensitive matching
- No word boundaries (matches anywhere in text)
- Example:
start_var→middle_var→end_var→start_var
" Define custom word cycling sets
let g:dial_custom_definitions = [
" HTTP status categories (case insensitive, whole words)
['normalizedCaseWords', ['success', 'redirect', 'client_error', 'server_error']],
" Git commands (case sensitive, whole words)
['words', ['add', 'commit', 'push', 'pull', 'merge', 'rebase']],
" CSS units (case insensitive, partial matches)
['normalizedCasePattern', ['px', 'em', 'rem', '%', 'vh', 'vw']],
" Priority levels (case sensitive, partial matches)
['pattern', ['low', 'medium', 'high', 'critical']]
]Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests.
This project is licensed under the MIT License - see the LICENSE file for details.
- Built on top of IdeaVim plugin
- Inspired by dial.nvim for Neovim and ideavim-switch plugin for JetBrains IDEs