mui 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +163 -0
  3. data/CHANGELOG.md +448 -0
  4. data/README.md +309 -6
  5. data/docs/_config.yml +56 -0
  6. data/docs/configuration.md +301 -0
  7. data/docs/getting-started.md +140 -0
  8. data/docs/index.md +55 -0
  9. data/docs/jobs.md +297 -0
  10. data/docs/keybindings.md +229 -0
  11. data/docs/plugins.md +285 -0
  12. data/docs/syntax-highlighting.md +149 -0
  13. data/exe/mui +1 -2
  14. data/lib/mui/autocmd.rb +66 -0
  15. data/lib/mui/buffer.rb +275 -0
  16. data/lib/mui/buffer_word_cache.rb +131 -0
  17. data/lib/mui/buffer_word_completer.rb +77 -0
  18. data/lib/mui/color_manager.rb +136 -0
  19. data/lib/mui/color_scheme.rb +63 -0
  20. data/lib/mui/command_completer.rb +30 -0
  21. data/lib/mui/command_context.rb +90 -0
  22. data/lib/mui/command_history.rb +89 -0
  23. data/lib/mui/command_line.rb +167 -0
  24. data/lib/mui/command_registry.rb +44 -0
  25. data/lib/mui/completion_renderer.rb +84 -0
  26. data/lib/mui/completion_state.rb +58 -0
  27. data/lib/mui/config.rb +58 -0
  28. data/lib/mui/editor.rb +395 -0
  29. data/lib/mui/error.rb +29 -0
  30. data/lib/mui/file_completer.rb +51 -0
  31. data/lib/mui/floating_window.rb +161 -0
  32. data/lib/mui/handler_result.rb +107 -0
  33. data/lib/mui/highlight.rb +22 -0
  34. data/lib/mui/highlighters/base.rb +23 -0
  35. data/lib/mui/highlighters/search_highlighter.rb +27 -0
  36. data/lib/mui/highlighters/selection_highlighter.rb +48 -0
  37. data/lib/mui/highlighters/syntax_highlighter.rb +107 -0
  38. data/lib/mui/input.rb +17 -0
  39. data/lib/mui/insert_completion_renderer.rb +92 -0
  40. data/lib/mui/insert_completion_state.rb +77 -0
  41. data/lib/mui/job.rb +81 -0
  42. data/lib/mui/job_manager.rb +113 -0
  43. data/lib/mui/key_code.rb +30 -0
  44. data/lib/mui/key_handler/base.rb +187 -0
  45. data/lib/mui/key_handler/command_mode.rb +511 -0
  46. data/lib/mui/key_handler/insert_mode.rb +323 -0
  47. data/lib/mui/key_handler/motions/motion_handler.rb +56 -0
  48. data/lib/mui/key_handler/normal_mode.rb +552 -0
  49. data/lib/mui/key_handler/operators/base_operator.rb +134 -0
  50. data/lib/mui/key_handler/operators/change_operator.rb +179 -0
  51. data/lib/mui/key_handler/operators/delete_operator.rb +176 -0
  52. data/lib/mui/key_handler/operators/paste_operator.rb +119 -0
  53. data/lib/mui/key_handler/operators/yank_operator.rb +127 -0
  54. data/lib/mui/key_handler/search_mode.rb +191 -0
  55. data/lib/mui/key_handler/visual_line_mode.rb +20 -0
  56. data/lib/mui/key_handler/visual_mode.rb +402 -0
  57. data/lib/mui/key_handler/window_command.rb +112 -0
  58. data/lib/mui/key_handler.rb +16 -0
  59. data/lib/mui/key_notation_parser.rb +152 -0
  60. data/lib/mui/key_sequence.rb +67 -0
  61. data/lib/mui/key_sequence_buffer.rb +85 -0
  62. data/lib/mui/key_sequence_handler.rb +163 -0
  63. data/lib/mui/key_sequence_matcher.rb +79 -0
  64. data/lib/mui/layout/calculator.rb +15 -0
  65. data/lib/mui/layout/leaf_node.rb +33 -0
  66. data/lib/mui/layout/node.rb +29 -0
  67. data/lib/mui/layout/split_node.rb +132 -0
  68. data/lib/mui/line_renderer.rb +173 -0
  69. data/lib/mui/mode.rb +13 -0
  70. data/lib/mui/mode_manager.rb +186 -0
  71. data/lib/mui/motion.rb +139 -0
  72. data/lib/mui/plugin.rb +35 -0
  73. data/lib/mui/plugin_manager.rb +106 -0
  74. data/lib/mui/register.rb +110 -0
  75. data/lib/mui/screen.rb +103 -0
  76. data/lib/mui/search_completer.rb +50 -0
  77. data/lib/mui/search_input.rb +40 -0
  78. data/lib/mui/search_state.rb +121 -0
  79. data/lib/mui/selection.rb +55 -0
  80. data/lib/mui/status_line_renderer.rb +40 -0
  81. data/lib/mui/syntax/language_detector.rb +106 -0
  82. data/lib/mui/syntax/lexer_base.rb +106 -0
  83. data/lib/mui/syntax/lexers/c_lexer.rb +127 -0
  84. data/lib/mui/syntax/lexers/css_lexer.rb +121 -0
  85. data/lib/mui/syntax/lexers/go_lexer.rb +205 -0
  86. data/lib/mui/syntax/lexers/html_lexer.rb +118 -0
  87. data/lib/mui/syntax/lexers/javascript_lexer.rb +197 -0
  88. data/lib/mui/syntax/lexers/markdown_lexer.rb +210 -0
  89. data/lib/mui/syntax/lexers/ruby_lexer.rb +114 -0
  90. data/lib/mui/syntax/lexers/rust_lexer.rb +148 -0
  91. data/lib/mui/syntax/lexers/typescript_lexer.rb +203 -0
  92. data/lib/mui/syntax/token.rb +42 -0
  93. data/lib/mui/syntax/token_cache.rb +91 -0
  94. data/lib/mui/tab_bar_renderer.rb +87 -0
  95. data/lib/mui/tab_manager.rb +96 -0
  96. data/lib/mui/tab_page.rb +35 -0
  97. data/lib/mui/terminal_adapter/base.rb +92 -0
  98. data/lib/mui/terminal_adapter/curses.rb +164 -0
  99. data/lib/mui/terminal_adapter.rb +4 -0
  100. data/lib/mui/themes/default.rb +315 -0
  101. data/lib/mui/undo_manager.rb +83 -0
  102. data/lib/mui/undoable_action.rb +175 -0
  103. data/lib/mui/unicode_width.rb +100 -0
  104. data/lib/mui/version.rb +1 -1
  105. data/lib/mui/window.rb +201 -0
  106. data/lib/mui/window_manager.rb +256 -0
  107. data/lib/mui/wrap_cache.rb +40 -0
  108. data/lib/mui/wrap_helper.rb +84 -0
  109. data/lib/mui.rb +171 -2
  110. metadata +123 -5
@@ -0,0 +1,140 @@
1
+ ---
2
+ title: Getting Started
3
+ layout: default
4
+ nav_order: 2
5
+ ---
6
+
7
+ # Getting Started
8
+ {: .no_toc }
9
+
10
+ ## Table of contents
11
+ {: .no_toc .text-delta }
12
+
13
+ 1. TOC
14
+ {:toc}
15
+
16
+ ---
17
+
18
+ ## Installation
19
+
20
+ Install Mui from RubyGems:
21
+
22
+ ```bash
23
+ gem install mui
24
+ ```
25
+
26
+ ### Requirements
27
+
28
+ - Ruby 3.0 or later
29
+ - A terminal that supports 256 colors
30
+
31
+ ## Basic Usage
32
+
33
+ ### Opening a File
34
+
35
+ ```bash
36
+ mui filename.rb
37
+ ```
38
+
39
+ ### Creating a New File
40
+
41
+ ```bash
42
+ mui
43
+ ```
44
+
45
+ Or open a non-existent file path:
46
+
47
+ ```bash
48
+ mui new_file.rb
49
+ ```
50
+
51
+ ## Modes
52
+
53
+ Mui is a modal editor, similar to Vim. Understanding modes is essential.
54
+
55
+ ### Normal Mode
56
+
57
+ The default mode. Used for navigation and commands.
58
+
59
+ - Press `Esc` from any mode to return to Normal mode
60
+
61
+ ### Insert Mode
62
+
63
+ For typing text. Enter from Normal mode with:
64
+
65
+ | Key | Action |
66
+ |-----|--------|
67
+ | `i` | Insert before cursor |
68
+ | `a` | Append after cursor |
69
+ | `o` | Open new line below |
70
+ | `O` | Open new line above |
71
+
72
+ ### Visual Mode
73
+
74
+ For selecting text:
75
+
76
+ | Key | Action |
77
+ |-----|--------|
78
+ | `v` | Character-wise selection |
79
+ | `V` | Line-wise selection |
80
+
81
+ ### Command Mode
82
+
83
+ For Ex commands. Press `:` from Normal mode.
84
+
85
+ ## Essential Commands
86
+
87
+ ### Saving and Quitting
88
+
89
+ | Command | Action |
90
+ |---------|--------|
91
+ | `:w` | Save file |
92
+ | `:q` | Quit (fails if unsaved changes) |
93
+ | `:q!` | Force quit without saving |
94
+ | `:wq` | Save and quit |
95
+
96
+ ### Opening Files
97
+
98
+ | Command | Action |
99
+ |---------|--------|
100
+ | `:e filename` | Open file |
101
+ | `:sp filename` | Open in horizontal split |
102
+ | `:vs filename` | Open in vertical split |
103
+ | `:tabnew filename` | Open in new tab |
104
+
105
+ ### Navigation
106
+
107
+ | Key | Action |
108
+ |-----|--------|
109
+ | `h`, `j`, `k`, `l` | Left, down, up, right |
110
+ | `w`, `b` | Word forward, backward |
111
+ | `0`, `$` | Line start, end |
112
+ | `gg`, `G` | File start, end |
113
+ | `/pattern` | Search forward |
114
+ | `?pattern` | Search backward |
115
+ | `n`, `N` | Next, previous match |
116
+
117
+ ## Configuration
118
+
119
+ Create `~/.muirc` for global settings:
120
+
121
+ ```ruby
122
+ # Set color scheme
123
+ Mui.set :colorscheme, "tokyo_night"
124
+
125
+ # Enable syntax highlighting
126
+ Mui.set :syntax, true
127
+
128
+ # Set indentation
129
+ Mui.set :tabstop, 2
130
+ Mui.set :shiftwidth, 2
131
+ Mui.set :expandtab, true
132
+ ```
133
+
134
+ See [Configuration]({{ site.baseurl }}/configuration) for all options.
135
+
136
+ ## Next Steps
137
+
138
+ - [Key Bindings]({{ site.baseurl }}/keybindings) - Complete key reference
139
+ - [Configuration]({{ site.baseurl }}/configuration) - Customize Mui
140
+ - [Plugins]({{ site.baseurl }}/plugins) - Extend functionality
data/docs/index.md ADDED
@@ -0,0 +1,55 @@
1
+ ---
2
+ title: Home
3
+ layout: home
4
+ nav_order: 1
5
+ ---
6
+
7
+ # Mui (無為)
8
+
9
+ A Vim-like TUI text editor written in Ruby.
10
+ {: .fs-6 .fw-300 }
11
+
12
+ > **無為 (むい, mui)** - "Effortless action" from Taoist philosophy.
13
+ > *"Form without forcing, existing as it is. Yet from nothing, something is born."*
14
+
15
+ [Get Started]({{ site.baseurl }}/getting-started){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 }
16
+ [View on GitHub](https://github.com/S-H-GAMELINKS/mui){: .btn .fs-5 .mb-4 .mb-md-0 .mr-2 }
17
+ [RubyGems](https://rubygems.org/gems/mui){: .btn .btn-green .fs-5 .mb-4 .mb-md-0 }
18
+
19
+ ---
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ gem install mui
25
+ ```
26
+
27
+ ## Features
28
+
29
+ - **Modal Editing** - Vim-like Normal, Insert, Visual, Command modes
30
+ - **Syntax Highlighting** - Ruby, C, Go, Rust, JavaScript, TypeScript, Markdown, HTML, CSS
31
+ - **Tab Pages & Window Splits** - Multiple files with flexible layouts
32
+ - **Plugin System** - Extend functionality with Ruby gems
33
+ - **LSP Support** - Language Server Protocol via mui-lsp plugin
34
+ - **Japanese/UTF-8 Support** - Full multibyte character support
35
+
36
+ ## Quick Start
37
+
38
+ ```bash
39
+ # Install from RubyGems
40
+ gem install mui
41
+
42
+ # Open a file
43
+ mui myfile.rb
44
+
45
+ # Or start with an empty buffer
46
+ mui
47
+ ```
48
+
49
+ ## Official Plugins
50
+
51
+ | Plugin | Description |
52
+ |--------|-------------|
53
+ | [mui-lsp](https://github.com/S-H-GAMELINKS/mui-lsp) | LSP (Language Server Protocol) support |
54
+ | [mui-git](https://github.com/S-H-GAMELINKS/mui-git) | Git integration |
55
+ | [mui-fzf](https://github.com/S-H-GAMELINKS/mui-fzf) | Fuzzy finder integration with fzf |
data/docs/jobs.md ADDED
@@ -0,0 +1,297 @@
1
+ ---
2
+ title: Jobs
3
+ layout: default
4
+ nav_order: 6
5
+ ---
6
+
7
+ # Asynchronous Jobs
8
+ {: .no_toc }
9
+
10
+ ## Table of contents
11
+ {: .no_toc .text-delta }
12
+
13
+ 1. TOC
14
+ {:toc}
15
+
16
+ ---
17
+
18
+ ## Overview
19
+
20
+ Mui's job system allows plugins to run background tasks without blocking the editor. This is essential for:
21
+
22
+ - Running tests
23
+ - Executing linters/formatters
24
+ - Making HTTP requests
25
+ - Any long-running operation
26
+
27
+ ## Running Async Ruby Code
28
+
29
+ Use `ctx.run_async` to execute Ruby code in a background thread:
30
+
31
+ ```ruby
32
+ command :slow_task do |ctx|
33
+ ctx.set_message("Starting task...")
34
+
35
+ ctx.run_async do
36
+ # This runs in a background thread
37
+ sleep 5 # Simulate slow operation
38
+ "Task completed!"
39
+ end
40
+ end
41
+ ```
42
+
43
+ ### With Callback
44
+
45
+ ```ruby
46
+ command :fetch_data do |ctx|
47
+ ctx.run_async(on_complete: ->(result) {
48
+ ctx.set_message("Result: #{result}")
49
+ }) do
50
+ # Perform async work
51
+ fetch_from_api
52
+ end
53
+ end
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Running Shell Commands
59
+
60
+ Use `ctx.run_shell_command` for external processes:
61
+
62
+ ```ruby
63
+ command :run_tests do |ctx|
64
+ ctx.set_message("Running tests...")
65
+
66
+ ctx.run_shell_command("bundle exec rake test") do |result|
67
+ if result[:success]
68
+ ctx.open_scratch_buffer("[Test Results]", result[:stdout])
69
+ ctx.set_message("Tests passed!")
70
+ else
71
+ ctx.open_scratch_buffer("[Test Errors]", result[:stderr])
72
+ ctx.set_error("Tests failed!")
73
+ end
74
+ end
75
+ end
76
+ ```
77
+
78
+ ### Result Object
79
+
80
+ The callback receives a hash with:
81
+
82
+ | Key | Description |
83
+ |-----|-------------|
84
+ | `:success` | Boolean indicating exit status |
85
+ | `:stdout` | Standard output as string |
86
+ | `:stderr` | Standard error as string |
87
+ | `:exit_status` | Process exit code |
88
+
89
+ ### Example: Linter
90
+
91
+ ```ruby
92
+ command :lint do |ctx|
93
+ file = ctx.buffer.file_path
94
+
95
+ ctx.run_shell_command("rubocop #{file}") do |result|
96
+ if result[:success]
97
+ ctx.set_message("No lint errors!")
98
+ else
99
+ ctx.open_scratch_buffer("[Lint Results]", result[:stdout])
100
+ end
101
+ end
102
+ end
103
+ ```
104
+
105
+ ---
106
+
107
+ ## Job Management
108
+
109
+ ### Checking Job Status
110
+
111
+ ```ruby
112
+ command :status do |ctx|
113
+ if ctx.jobs_running?
114
+ ctx.set_message("Jobs are running...")
115
+ else
116
+ ctx.set_message("No active jobs")
117
+ end
118
+ end
119
+ ```
120
+
121
+ ### Cancelling Jobs
122
+
123
+ ```ruby
124
+ command :start_job do |ctx|
125
+ job_id = ctx.run_async do
126
+ # Long running task
127
+ loop do
128
+ sleep 1
129
+ end
130
+ end
131
+
132
+ # Store job_id for later cancellation
133
+ @current_job = job_id
134
+ end
135
+
136
+ command :cancel_job do |ctx|
137
+ if @current_job
138
+ ctx.cancel_job(@current_job)
139
+ ctx.set_message("Job cancelled")
140
+ end
141
+ end
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Scratch Buffers
147
+
148
+ Display job results in a scratch buffer:
149
+
150
+ ```ruby
151
+ ctx.open_scratch_buffer(name, content)
152
+ ```
153
+
154
+ - Opens in a horizontal split
155
+ - Buffer is read-only
156
+ - Subsequent calls with same name update existing buffer
157
+
158
+ ### Example: Test Runner
159
+
160
+ ```ruby
161
+ command :test do |ctx|
162
+ ctx.run_shell_command("rake test") do |result|
163
+ output = []
164
+ output << "=== Test Results ==="
165
+ output << ""
166
+ output << result[:stdout]
167
+
168
+ if result[:stderr].length > 0
169
+ output << ""
170
+ output << "=== Errors ==="
171
+ output << result[:stderr]
172
+ end
173
+
174
+ output << ""
175
+ output << "Exit status: #{result[:exit_status]}"
176
+
177
+ ctx.open_scratch_buffer("[Test Output]", output.join("\n"))
178
+ end
179
+ end
180
+ ```
181
+
182
+ ---
183
+
184
+ ## Job Events
185
+
186
+ React to job lifecycle with autocmd:
187
+
188
+ ```ruby
189
+ autocmd :JobStarted do |ctx|
190
+ ctx.set_message("Job started")
191
+ end
192
+
193
+ autocmd :JobCompleted do |ctx|
194
+ ctx.set_message("Job completed successfully")
195
+ end
196
+
197
+ autocmd :JobFailed do |ctx|
198
+ ctx.set_error("Job failed!")
199
+ end
200
+
201
+ autocmd :JobCancelled do |ctx|
202
+ ctx.set_message("Job was cancelled")
203
+ end
204
+ ```
205
+
206
+ ---
207
+
208
+ ## Complete Example: Build Plugin
209
+
210
+ ```ruby
211
+ class BuildPlugin < Mui::Plugin
212
+ name :build
213
+ version "1.0.0"
214
+ description "Build and test runner"
215
+
216
+ def setup
217
+ command :build do |ctx|
218
+ run_build(ctx)
219
+ end
220
+
221
+ command :test do |ctx|
222
+ run_tests(ctx)
223
+ end
224
+
225
+ command :check do |ctx|
226
+ run_build(ctx)
227
+ run_tests(ctx)
228
+ end
229
+
230
+ keymap :normal, "<Leader>b" do |ctx|
231
+ run_build(ctx)
232
+ end
233
+
234
+ keymap :normal, "<Leader>t" do |ctx|
235
+ run_tests(ctx)
236
+ end
237
+
238
+ autocmd :JobCompleted do |ctx|
239
+ # Could trigger notifications, update status line, etc.
240
+ end
241
+ end
242
+
243
+ private
244
+
245
+ def run_build(ctx)
246
+ ctx.set_message("Building...")
247
+
248
+ ctx.run_shell_command("make build") do |result|
249
+ if result[:success]
250
+ ctx.set_message("Build succeeded!")
251
+ else
252
+ ctx.open_scratch_buffer("[Build Errors]", result[:stderr])
253
+ ctx.set_error("Build failed!")
254
+ end
255
+ end
256
+ end
257
+
258
+ def run_tests(ctx)
259
+ ctx.set_message("Running tests...")
260
+
261
+ ctx.run_shell_command("make test") do |result|
262
+ ctx.open_scratch_buffer("[Test Results]", result[:stdout])
263
+
264
+ if result[:success]
265
+ ctx.set_message("All tests passed!")
266
+ else
267
+ ctx.set_error("Tests failed!")
268
+ end
269
+ end
270
+ end
271
+ end
272
+ ```
273
+
274
+ ---
275
+
276
+ ## Interactive Commands
277
+
278
+ For commands that require user interaction (like fzf), use `run_interactive_command`:
279
+
280
+ ```ruby
281
+ command :find_file do |ctx|
282
+ unless ctx.command_exists?("fzf")
283
+ ctx.set_error("fzf is not installed")
284
+ return
285
+ end
286
+
287
+ # This temporarily exits curses mode
288
+ result = ctx.run_interactive_command("find . -type f | fzf")
289
+
290
+ if result && !result.empty?
291
+ ctx.editor.execute_command("e #{result.strip}")
292
+ end
293
+ end
294
+ ```
295
+
296
+ {: .note }
297
+ `run_interactive_command` blocks and waits for the command to complete. Use this only for interactive CLI tools that require terminal access.
@@ -0,0 +1,229 @@
1
+ ---
2
+ title: Key Bindings
3
+ layout: default
4
+ nav_order: 3
5
+ ---
6
+
7
+ # Key Bindings
8
+ {: .no_toc }
9
+
10
+ ## Table of contents
11
+ {: .no_toc .text-delta }
12
+
13
+ 1. TOC
14
+ {:toc}
15
+
16
+ ---
17
+
18
+ ## Normal Mode
19
+
20
+ ### Cursor Movement
21
+
22
+ | Key | Action |
23
+ |-----|--------|
24
+ | `h` | Move left |
25
+ | `j` | Move down |
26
+ | `k` | Move up |
27
+ | `l` | Move right |
28
+ | `0` | Move to line start |
29
+ | `^` | Move to first non-blank character |
30
+ | `$` | Move to line end |
31
+
32
+ ### Word Movement
33
+
34
+ | Key | Action |
35
+ |-----|--------|
36
+ | `w` | Move to next word start |
37
+ | `b` | Move to previous word start |
38
+ | `e` | Move to word end |
39
+
40
+ ### File Movement
41
+
42
+ | Key | Action |
43
+ |-----|--------|
44
+ | `gg` | Go to first line |
45
+ | `G` | Go to last line |
46
+ | `:{number}` | Go to line number |
47
+
48
+ ### Character Search
49
+
50
+ | Key | Action |
51
+ |-----|--------|
52
+ | `f{char}` | Find character forward (on character) |
53
+ | `F{char}` | Find character backward (on character) |
54
+ | `t{char}` | Find character forward (before character) |
55
+ | `T{char}` | Find character backward (after character) |
56
+
57
+ ### Search
58
+
59
+ | Key | Action |
60
+ |-----|--------|
61
+ | `/pattern` | Search forward |
62
+ | `?pattern` | Search backward |
63
+ | `n` | Next match |
64
+ | `N` | Previous match |
65
+ | `*` | Search word under cursor (forward) |
66
+ | `#` | Search word under cursor (backward) |
67
+
68
+ ### Entering Insert Mode
69
+
70
+ | Key | Action |
71
+ |-----|--------|
72
+ | `i` | Insert before cursor |
73
+ | `a` | Append after cursor |
74
+ | `I` | Insert at line start |
75
+ | `A` | Append at line end |
76
+ | `o` | Open line below |
77
+ | `O` | Open line above |
78
+
79
+ ### Operators
80
+
81
+ Operators can be combined with motions (e.g., `dw` = delete word).
82
+
83
+ | Key | Action |
84
+ |-----|--------|
85
+ | `d` | Delete |
86
+ | `c` | Change (delete and enter Insert mode) |
87
+ | `y` | Yank (copy) |
88
+
89
+ ### Common Operations
90
+
91
+ | Key | Action |
92
+ |-----|--------|
93
+ | `dd` | Delete line |
94
+ | `cc` | Change line |
95
+ | `yy` | Yank line |
96
+ | `x` | Delete character at cursor |
97
+ | `p` | Paste after cursor |
98
+ | `P` | Paste before cursor |
99
+ | `u` | Undo |
100
+ | `Ctrl-r` | Redo |
101
+
102
+ ### Visual Mode
103
+
104
+ | Key | Action |
105
+ |-----|--------|
106
+ | `v` | Enter Visual mode |
107
+ | `V` | Enter Visual Line mode |
108
+ | `gv` | Reselect last visual selection |
109
+
110
+ ### Tabs and Windows
111
+
112
+ | Key | Action |
113
+ |-----|--------|
114
+ | `gt` | Go to next tab |
115
+ | `gT` | Go to previous tab |
116
+ | `Ctrl-w h` | Go to left window |
117
+ | `Ctrl-w j` | Go to below window |
118
+ | `Ctrl-w k` | Go to above window |
119
+ | `Ctrl-w l` | Go to right window |
120
+ | `Ctrl-w w` | Cycle to next window |
121
+ | `Ctrl-w c` | Close current window |
122
+ | `Ctrl-w o` | Close all other windows |
123
+
124
+ ### Registers
125
+
126
+ | Key | Action |
127
+ |-----|--------|
128
+ | `"a` - `"z` | Use named register |
129
+ | `""` | Use unnamed register |
130
+ | `"0` | Use yank register |
131
+ | `"1` - `"9` | Use delete history |
132
+ | `"_` | Use black hole register (discard) |
133
+
134
+ Example: `"ayy` yanks line to register `a`, `"ap` pastes from register `a`.
135
+
136
+ ---
137
+
138
+ ## Insert Mode
139
+
140
+ | Key | Action |
141
+ |-----|--------|
142
+ | `Esc` | Return to Normal mode |
143
+ | `Ctrl-n` | Next completion candidate |
144
+ | `Ctrl-p` | Previous completion candidate |
145
+ | `Tab` | Accept completion |
146
+ | Arrow keys | Move cursor |
147
+ | `Backspace` | Delete character before cursor |
148
+
149
+ ---
150
+
151
+ ## Visual Mode
152
+
153
+ | Key | Action |
154
+ |-----|--------|
155
+ | `Esc` | Return to Normal mode |
156
+ | `d` | Delete selection |
157
+ | `c` | Change selection |
158
+ | `y` | Yank selection |
159
+ | `>` | Indent selection |
160
+ | `<` | Unindent selection |
161
+ | `*` | Search for selected text (forward) |
162
+ | `#` | Search for selected text (backward) |
163
+ | All motion keys | Extend selection |
164
+
165
+ ---
166
+
167
+ ## Command Mode
168
+
169
+ Enter with `:` from Normal mode.
170
+
171
+ ### File Commands
172
+
173
+ | Command | Action |
174
+ |---------|--------|
175
+ | `:w` | Save file |
176
+ | `:w filename` | Save as filename |
177
+ | `:q` | Quit |
178
+ | `:q!` | Force quit |
179
+ | `:wq` | Save and quit |
180
+ | `:e filename` | Open file |
181
+
182
+ ### Window Commands
183
+
184
+ | Command | Action |
185
+ |---------|--------|
186
+ | `:sp [filename]` | Horizontal split |
187
+ | `:vs [filename]` | Vertical split |
188
+ | `:close` | Close window |
189
+ | `:only` | Close all other windows |
190
+
191
+ ### Tab Commands
192
+
193
+ | Command | Action |
194
+ |---------|--------|
195
+ | `:tabnew [filename]` | New tab |
196
+ | `:tabclose` | Close tab |
197
+ | `:tabnext` | Next tab |
198
+ | `:tabprev` | Previous tab |
199
+ | `:tabfirst` | First tab |
200
+ | `:tablast` | Last tab |
201
+ | `:tabmove N` | Move tab to position N |
202
+
203
+ ### Shell Commands
204
+
205
+ | Command | Action |
206
+ |---------|--------|
207
+ | `:!cmd` | Run shell command |
208
+
209
+ ### Navigation
210
+
211
+ | Command | Action |
212
+ |---------|--------|
213
+ | `:{number}` | Go to line number |
214
+
215
+ ---
216
+
217
+ ## Search Mode
218
+
219
+ Enter with `/` or `?` from Normal mode.
220
+
221
+ | Key | Action |
222
+ |-----|--------|
223
+ | `Enter` | Execute search |
224
+ | `Esc` | Cancel search |
225
+ | `Tab` | Cycle through completion |
226
+ | `Shift-Tab` | Cycle backward |
227
+ | `Backspace` | Delete character |
228
+
229
+ Search supports regular expressions.