├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── emacs.xml ├── emacsIDEAs.iml ├── encodings.xml ├── misc.xml ├── modules.xml ├── scopes │ └── scope_settings.xml ├── vcs.xml ├── workspace.xml └── xtextAutoBuilderState.xml ├── LICENSE ├── META-INF ├── plugin.xml └── plugin_windows.xml ├── README.md ├── emacsIDEAs.jar ├── emacsideas-windows.jar ├── emacsideas.iml ├── letsedit.properties ├── letsedit.xml ├── module_letsedit.xml ├── resources └── META-INF │ ├── plugin.xml │ └── plugin_windows.xml ├── src └── org │ └── hunmr │ ├── .DS_Store │ ├── acejump │ ├── AceJumpAction.java │ ├── AceJumpAndReplaceRangeAction.java │ ├── AceJumpCharAction.java │ ├── AceJumpCopyAction.java │ ├── AceJumpCopyRangeAction.java │ ├── AceJumpCutAction.java │ ├── AceJumpDeleteRangeAction.java │ ├── AceJumpMoveRangeAction.java │ ├── AceJumpObtainThenReplaceRangeAction.java │ ├── AceJumpSelectAction.java │ ├── command │ │ ├── CommandAroundJump.java │ │ ├── CopyAfterJumpCommand.java │ │ ├── CopyRangeAfterJumpCommand.java │ │ ├── CutAfterJumpCommand.java │ │ ├── DeleteRangeAfterJumpCommand.java │ │ ├── MoveRangeAfterJumpCommand.java │ │ ├── ObtainAndPasteRangeAfterJumpCommand.java │ │ ├── PasteAfterJumpCommand.java │ │ ├── ReplaceAfterJumpCommand.java │ │ ├── ReplaceRangeAfterJumpCommand.java │ │ └── SelectAfterJumpCommand.java │ ├── marker │ │ ├── JOffset.java │ │ ├── Marker.java │ │ ├── MarkerCollection.java │ │ └── MarkersPanel.java │ ├── offsets │ │ ├── CharOffsetsFinder.java │ │ ├── OffsetsFinder.java │ │ └── WordOffsetsFinder.java │ └── runnable │ │ ├── JumpRunnable.java │ │ └── ShowMarkersRunnable.java │ ├── buildin │ └── JustOneSpace.java │ ├── common │ ├── ChainActionEvent.java │ ├── CommandContext.java │ ├── Consts.java │ ├── EmacsIdeasAction.java │ ├── predictor │ │ ├── Predictor.java │ │ └── SymbolPredictor.java │ └── selector │ │ ├── BlockSelector.java │ │ ├── GroupSelector.java │ │ ├── LineSelector.java │ │ ├── ParagraphSelector.java │ │ ├── QuoteSelector.java │ │ ├── Selection.java │ │ ├── Selector.java │ │ ├── SelectorFactory.java │ │ ├── StringSelector.java │ │ ├── ToLineEndSelector.java │ │ ├── ToLineStartSelector.java │ │ ├── ToParagraphEndSelector.java │ │ ├── ToParagraphStartSelector.java │ │ └── WordSelector.java │ ├── copycutwithoutselection │ ├── CopyAndReplaceAction.java │ └── CopyCutWithoutSelectAction.java │ ├── highlightsymbol │ ├── HighlightNextSymbolAction.java │ ├── HighlightPrevSymbolAction.java │ └── HighlightSymbolAction.java │ ├── options │ ├── IdeaConfigurable.form │ ├── IdeaConfigurable.java │ └── PluginConfig.java │ └── util │ ├── AppUtil.java │ ├── Chars.java │ ├── EditorUtils.java │ ├── Str.java │ └── ThreadUtil.java └── tutorials ├── 1_basic_word_jump.gif ├── 2_copy_without_selection.gif ├── 3_replace_target_range.gif ├── 4_obtain_target_range.gif ├── 5_copy_target_range.gif ├── 6_cut_target_range.gif └── 7_delete_target_range.gif /.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | .DS_Store 3 | .idea/workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | emacsIDEAs -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/emacs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/emacsIDEAs.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/xtextAutoBuilderState.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | rO0ABXNyADtvcmcuZWNsaXBzZS54dGV4dC5yZXNvdXJjZS5pbXBsLkNodW5rZWRSZXNvdXJjZURlc2NyaXB0aW9uc4nX+GBmyGixDAAAeHB3FAAAAAEACmVtYWNzSURFQXMAAAAAeA== 6 | rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAF3CAAAAAIAAAABdAAKZW1hY3NJREVBc3NyAC9vcmcuZWNsaXBzZS54dGV4dC5idWlsZC5Tb3VyY2UyR2VuZXJhdGVkTWFwcGluZ2DBzUbtkYbKDAAAeHB3BAAAAAB4eA== 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | emacsIDEAs 3 | 4 | Porting some great extensions of emacs to Intellij IDEA. such as AceJump, CopyWithoutSelectAction. And new created EditWithoutSelection (Cut/Move/Replace without selection).

6 |

AceJump

7 | 11 |
12 |

AceJump, jump to special place

13 | 17 |
18 | 19 |

Copy without selection:

20 | 37 |
38 | 39 |

Replace target (word | line | paragraph) with text at current caret:

40 | 53 |
54 | 55 |

Obtain target (word | line | paragraph), then replace text at current caret:

56 | 69 |
70 | 71 |

Copy target (word | line | paragraph), then insert text at current caret:

72 | 85 |
86 | 87 |

Cut target (word | line | paragraph), then insert text at current caret:

88 | 101 |
102 | 103 |

Delete target (word | line | paragraph...)

104 | 117 |
118 | 119 |
120 |

Highlight symbol:

121 | 125 |
126 |

Just one space:

127 | 130 |
131 | 132 | 133 |

Separate AceJump copy,cut,select command:

134 | 140 |
141 | 142 | 143 |

Copy and Replace:

144 | 147 | 148 | ]]> 149 |
150 | 152 |
153 |
1.4.4
154 |
--- fix wrong width of the jump marker background.
155 |
156 |
1.4.3
157 |
--- fix https://github.com/whunmr/emacsIDEAs/issues/14 overlay and markers in splitted panes not get cleared after jump.
158 |
159 |
1.4.2
160 |
--- Add support for jump/move/copy/cut texts cross Split pane editors.
161 |
162 |
1.4.1
163 |
--- Add `paragraph group' concept, which denotes the `paragraph' including white lines.
164 | Useful when you need copy/cut/move/delete function with white lines inside.
165 |
166 |
1.4.0
167 |
--- fix post selection error, in C-O C-A command.
168 |
169 |
1.3.9
170 |
--- Add plugin settings panel in the Prefereces -> Other Settings -> emacsIDEAs.
171 | to config jump marker char's color, and whether select the moved text.
172 |
173 |
1.3.8
174 |
--- zap-to-char and copy-to-char. Can be done by C-I C-X and C-I C-C
175 |
176 |
1.3.7
177 |
--- compile based on JDK 1.6. to fix error when running in Android Studio 2.1.3.
178 |
179 |
1.3.6
180 |
--- fix wrong selection range issue, after using AceJumpMove.* actions.
181 |
182 |
1.3.5
183 |
--- Add jump and delete target range action. such as delete target paragraph by: C-d C-p.
184 | so do not need: First jump to target place, then delete paragraph by C-c space p.
185 | also apply to other range like (w | s | l | q | a | A | e | E | p | u | d).
186 |
187 |
1.3.4
188 |
--- adjust mark char order to make the two level jump markers generates from easy press chars like 'lkasdfj'.
189 |
190 |
1.3.3
191 |
--- Upgrade the jump more like avy-jump. http://emacsredux.com/blog/2015/07/19/ace-jump-mode-is-dead-long-live-avy/
192 | This also fix issue posted by @jmdodge [AceJump: Show two-letter combos up front], https://github.com/whunmr/emacsIDEAs/issues/3
193 |
194 |
1.3.2
195 |
--- fix wrong selection issue after "Cut target paragraph" command. C-x C-p 't' 'm'
196 |
197 |
1.3.0
198 |
1. C-i C-s 't' 'm': Select jump area ---changed_to----> C-i C-i 't' 'm'
199 | 200 | 2. Add obtain(copy) remote target(w,l,e,p,b) and replace current(w,l,e,p,b) command:
201 | C-o C-(w | s | l | q | a | e | p | u | d | b) 202 | 203 | 3. extend C-i C-(w|l|p) to C-I C-(w | s | l | q | a | e | p | u | d | b) 204 |
205 |
1.2.0
206 |
--- Remove support for command: C-L 't' (c, x, p, P, s) 'm'
207 | instead using the command: C-i C-(c,x,s) 't' 'm'
208 |
209 |
1.1.9
210 |
--- Add action to copy current word | line | paragraph, jump, then replace target word/line/paragraph.
211 | C-I C-R (w | s | l | q | a | A | e | E | p | u | d) 't' 'm' 212 |
213 |
1.1.8
214 |
--- Add hightlight-symbol-prev and hightlight-symbol-next
215 |
1.1.7
216 |
--- Let cut to paragraph end(C-c ' ' d) and cut paragraph (C-c ' ' p) skip ending brackets.
217 |
1.1.6
218 |
--- Add Jump Word Action, and assigned to C-L. Jump Char Action assigned to C-J.
219 |
1.1.5
220 |
--- Changed AceJump's keymap to be more intuitive one. such as "C-L C-s" for select jump area.
221 |
1.1.0
222 |
--- Add copy without selection
223 |
1.0
224 |
--- Add basic AceJump function
225 |
226 | 227 | ]]> 228 |
229 | 1.4.4 230 | whunmr@gmail.com 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | com.intellij.modules.platform 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 446 | 447 | 448 | 449 | 450 | 452 | 453 | 454 | 455 | 456 | 457 | 459 | 460 | 461 | 462 | 463 | 465 | 466 | 467 | 468 | 469 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 |
482 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | emacsIDEAs 2 | ========== 3 | 4 | Porting some great extensions of emacs to Intellij IDEA. 5 | Such as AceJump, CopyWithoutSelection, 6 | And new created EditWithoutSelection (Cut/Move/Replace without selection). 7 | 8 | plugin page: http://plugins.jetbrains.com/plugin/?idea_ce&pluginId=7163 9 | 10 | 11 | --- 12 | 13 | ![usage sample](https://plugins.jetbrains.com/files/7163/screenshot_16138.png) 14 | 15 | 16 | --- 17 | ``` 18 | AceJump 19 | 20 | C-L 't' 'm' : Basic Word Jump | Type C-L, then type target char (eg. 't') to jump to, then type marker char (eg. 'm') to move caret. 21 | C-J 't' 'm' : Basic Char Jump 22 | ``` 23 | ![basic word jump gif](https://github.com/whunmr/emacsIDEAs/blob/master/tutorials/1_basic_word_jump.gif?raw=true) 24 | 25 | 26 | ``` 27 | AceJump, jump to special place 28 | 29 | C-L ' ' 'm' : Jump to line end or start. | To show marker on line end and line start, type space ' ' as target char 30 | C-L ',' 'm' : Jump to symbol key | Show markers on .{}(|`/\;.{}()[]?_=-+'"!@#$%^&*)_= 31 | ``` 32 | 33 | --- 34 | ``` 35 | Copy without selection: 36 | 37 | C-c w : Copy word 38 | C-c s : Copy string, begin and end by whitespaces 39 | C-c l : Copy line 40 | C-c b : Copy block between balanced { and } 41 | C-c q : Copy quoted, such as abcd in "abcd" 42 | C-c a : Copy to line beginning 43 | C-c A : Copy to file beginning 44 | C-c e : Copy to line end 45 | C-c E : Copy to file end 46 | C-c p : Copy paragraph 47 | C-c g : Copy paragraph group (e.g.: entire function including white lines) 48 | C-c u : Copy to paragraph begining 49 | C-c d : Copy to paragraph end 50 | ``` 51 | ![Copy without selection gif](https://github.com/whunmr/emacsIDEAs/blob/master/tutorials/2_copy_without_selection.gif?raw=true) 52 | 53 | 54 | ``` 55 | Cut without selection: 56 | 57 | C-c ' ' (w | s | l | q | a | A | e | E | p | g | u | d | b) : Type one space to cut related area 58 | ``` 59 | 60 | 61 | 62 | ``` 63 | Selection: 64 | 65 | C-c ' ' ' ' (w | s | l | q | a | A | e | E | p | g | u | d | b) : Type two space to select related area 66 | ``` 67 | 68 | 69 | --- 70 | ``` 71 | Replace target (word | line | paragraph) with text at current caret: 72 | *Tips: Consider i in C-i means "input to target" or "replace into" or "invade". * 73 | 74 | C-i C-w 't' 'm' : replace target word | C-i C-w means type C-i then continue type C-w 75 | C-i C-s 't' 'm' : replace target string 76 | C-i C-l 't' 'm' : replace target line 77 | C-i C-b 't' 'm' : replace target block 78 | C-i C-q 't' 'm' : replace target quote 79 | C-i C-a 't' 'm' : replace target to line begining 80 | C-i C-e 't' 'm' : replace target char to line end 81 | C-i C-p 't' 'm' : replace target paragraph 82 | C-i C-g 't' 'm' : replace target paragraph group 83 | C-i C-u 't' 'm' : replace target to paragraph beginning 84 | C-i C-d 't' 'm' : replace target to paragraph end 85 | ``` 86 | ![Replace target range gif](https://github.com/whunmr/emacsIDEAs/blob/master/tutorials/3_replace_target_range.gif?raw=true) 87 | 88 | --- 89 | ``` 90 | Obtain target (word | line | paragraph), then replace text at current caret: 91 | *Tips: Consider o in C-o means "output from target" or "obtain from target". * 92 | 93 | C-o C-w 't' 'm' : obtain target word, then replace current word 94 | C-o C-s 't' 'm' : obtain target string, then replace current string 95 | C-o C-l 't' 'm' : obtain target line, then replace current line 96 | C-o C-b 't' 'm' : obtain target block 97 | C-o C-q 't' 'm' : obtain target quote 98 | C-o C-a 't' 'm' : obtain target to line beginning 99 | C-o C-e 't' 'm' : obtain target char to line end 100 | C-o C-p 't' 'm' : obtain target paragraph 101 | C-o C-g 't' 'm' : obtain target paragraph group 102 | C-o C-u 't' 'm' : obtain target to paragraph beginning 103 | C-o C-d 't' 'm' : obtain target to paragraph end 104 | ``` 105 | ![Obtain target range gif](https://github.com/whunmr/emacsIDEAs/blob/master/tutorials/4_obtain_target_range.gif?raw=true) 106 | 107 | --- 108 | ``` 109 | Copy target (word | line | paragraph), then insert text at current caret: 110 | *Tips: Consider w in C-w follows emacs' command "Alt-w" as copy, or "with target". * 111 | 112 | C-w C-w 't' 'm' : Copy target word, then insert at current caret 113 | C-w C-s 't' 'm' : Copy target string, then insert at current caret 114 | C-w C-l 't' 'm' : Copy target line, then insert at current caret 115 | C-w C-b 't' 'm' : Copy target block 116 | C-w C-q 't' 'm' : Copy target quote 117 | C-w C-a 't' 'm' : Copy target to line beginning 118 | C-w C-e 't' 'm' : Copy target char to line end 119 | C-w C-p 't' 'm' : Copy target paragraph 120 | C-w C-g 't' 'm' : Copy target paragraph group 121 | C-w C-u 't' 'm' : Copy target to paragraph beginning 122 | C-w C-d 't' 'm' : Copy target to paragraph end 123 | ``` 124 | ![Copy target range gif](https://github.com/whunmr/emacsIDEAs/blob/master/tutorials/5_copy_target_range.gif?raw=true) 125 | 126 | 127 | --- 128 | ``` 129 | Cut target (word | line | paragraph), then insert text at current caret: 130 | 131 | C-x C-w 't' 'm' : Cut target word, then insert at current caret 132 | C-x C-s 't' 'm' : Cut target string, then insert at current caret 133 | C-x C-l 't' 'm' : Cut target line, then insert at current caret 134 | C-x C-b 't' 'm' : Cut target block 135 | C-x C-q 't' 'm' : Cut target quote 136 | C-x C-a 't' 'm' : Cut target to line beginning 137 | C-x C-e 't' 'm' : Cut target char to line end 138 | C-x C-p 't' 'm' : Cut target paragraph 139 | C-x C-g 't' 'm' : Cut target paragraph group 140 | C-x C-u 't' 'm' : Cut target to paragraph beginning 141 | C-x C-d 't' 'm' : Cut target to paragraph end 142 | ``` 143 | ![Cut target range gif](https://github.com/whunmr/emacsIDEAs/blob/master/tutorials/6_cut_target_range.gif?raw=true) 144 | 145 | 146 | --- 147 | ``` 148 | Delete target (word | line | paragraph...) 149 | 150 | C-d C-w 't' 'm' : delete target word 151 | C-d C-s 't' 'm' : delete target string 152 | C-d C-l 't' 'm' : delete target line 153 | C-d C-b 't' 'm' : delete target block 154 | C-d C-q 't' 'm' : delete target quote 155 | C-d C-a 't' 'm' : delete target to line beginning 156 | C-d C-e 't' 'm' : delete target char to line end 157 | C-d C-p 't' 'm' : delete target paragraph 158 | C-d C-g 't' 'm' : delete target paragraph group 159 | C-d C-u 't' 'm' : delete target to paragraph beginning 160 | C-d C-d 't' 'm' : delete target to paragraph end 161 | ``` 162 | ![Delete target range gif](https://github.com/whunmr/emacsIDEAs/blob/master/tutorials/7_delete_target_range.gif?raw=true) 163 | 164 | 165 | --- 166 | ``` 167 | Highlight symbol: 168 | 169 | C-, : hightlight-symbol-prev | Jump to prev occurrence of symbol that around caret 170 | C-. : hightlight-symbol-next | Jump to next occurrence of symbol that around caret 171 | ``` 172 | 173 | --- 174 | ``` 175 | Just one space: 176 | 177 | C-M-Space : Make just one space around caret by Ctrl-Cmd-Space. 178 | ``` 179 | 180 | --- 181 | ``` 182 | Separate AceJump copy,cut,select command: 183 | 184 | C-i C-c 't' 'm' : Copy jump area 185 | C-i C-x 't' 'm' : Cut jump area 186 | C-i C-i 't' 'm' : Select jump area 187 | C-i C-f 't' 'm' : Basic Jump alias 188 | ``` 189 | 190 | --- 191 | Download statistics: 192 | ![download_per_day](https://raw.githubusercontent.com/whunmr/emacsIDEAs-status/master/download_per_day.png) 193 | ![download_per_product](https://raw.githubusercontent.com/whunmr/emacsIDEAs-status/master/download_per_product.png) 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | -------------------------------------------------------------------------------- /emacsIDEAs.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whunmr/emacsIDEAs/cf49f068c9d92d3c5eac7c1c8dbc8f2520a37729/emacsIDEAs.jar -------------------------------------------------------------------------------- /emacsideas-windows.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whunmr/emacsIDEAs/cf49f068c9d92d3c5eac7c1c8dbc8f2520a37729/emacsideas-windows.jar -------------------------------------------------------------------------------- /emacsideas.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /letsedit.properties: -------------------------------------------------------------------------------- 1 | path.variable.maven_repository=/Users/twer/.m2/repository 2 | jdk.home.idea_ic-117.963=/Applications/IntelliJ IDEA 11 CE.app -------------------------------------------------------------------------------- /letsedit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /module_letsedit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/org/hunmr/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whunmr/emacsIDEAs/cf49f068c9d92d3c5eac7c1c8dbc8f2520a37729/src/org/hunmr/.DS_Store -------------------------------------------------------------------------------- /src/org/hunmr/acejump/AceJumpAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.application.ApplicationManager; 5 | import com.intellij.openapi.editor.Editor; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.openapi.wm.ToolWindowManager; 8 | import org.hunmr.acejump.command.CommandAroundJump; 9 | import org.hunmr.acejump.command.SelectAfterJumpCommand; 10 | import org.hunmr.acejump.marker.JOffset; 11 | import org.hunmr.acejump.marker.MarkerCollection; 12 | import org.hunmr.acejump.marker.MarkersPanel; 13 | import org.hunmr.acejump.offsets.CharOffsetsFinder; 14 | import org.hunmr.acejump.offsets.OffsetsFinder; 15 | import org.hunmr.acejump.offsets.WordOffsetsFinder; 16 | import org.hunmr.acejump.runnable.JumpRunnable; 17 | import org.hunmr.acejump.runnable.ShowMarkersRunnable; 18 | import org.hunmr.common.EmacsIdeasAction; 19 | import org.hunmr.util.EditorUtils; 20 | import org.hunmr.util.Str; 21 | 22 | import java.awt.*; 23 | import java.awt.event.KeyEvent; 24 | import java.awt.event.KeyListener; 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | import java.util.Stack; 28 | 29 | public class AceJumpAction extends EmacsIdeasAction { 30 | private MarkerCollection _markers; 31 | private ArrayList _markersPanels; 32 | private KeyListener _showMarkersKeyListener; 33 | private KeyListener _jumpToMarkerKeyListener; 34 | private Stack _commandsAroundJump = new Stack(); 35 | private static volatile AceJumpAction _instance; 36 | private boolean _isCalledFromOtherAction; //TODO 37 | private OffsetsFinder _offsetsFinder = new WordOffsetsFinder(); 38 | 39 | public AceJumpAction() { 40 | _instance = this; 41 | } 42 | 43 | public void performAction(AnActionEvent e) { 44 | _offsetsFinder = new CharOffsetsFinder(); 45 | _isCalledFromOtherAction = true; 46 | this.actionPerformed(e); 47 | } 48 | 49 | @Override 50 | public void actionPerformed(AnActionEvent e) { 51 | if (isCalledFromOtherAction()) { 52 | _offsetsFinder = new CharOffsetsFinder(); 53 | } 54 | 55 | Project p = getProjectFrom(e); 56 | 57 | if (!ToolWindowManager.getInstance(p).isEditorComponentActive()) { 58 | ToolWindowManager.getInstance(p).activateEditorComponent(); 59 | return; 60 | } 61 | 62 | if (super.initAction(e)) { 63 | _contentComponent.addKeyListener(_showMarkersKeyListener); 64 | } 65 | } 66 | 67 | private boolean handleShowMarkersKey(char key) { 68 | if (EditorUtils.isPrintableChar(key)) { 69 | runReadAction(new ShowMarkersRunnable(getOffsetsOfCharInVisibleArea(key), (AceJumpAction) _action)); 70 | 71 | if (_markers.hasNoPlaceToJump()) { 72 | cleanupSetupsInAndBackToNormalEditingMode(); 73 | return false; 74 | } 75 | 76 | if (_isCalledFromOtherAction && _markers.hasOnlyOnePlaceToJump()) { 77 | jumpToOffset(_markers.getFirstOffset()); 78 | return false; 79 | } 80 | 81 | _contentComponent.addKeyListener(_jumpToMarkerKeyListener); 82 | return true; 83 | } 84 | 85 | return false; 86 | } 87 | 88 | private boolean handleJumpToMarkerKey(char key) { 89 | if (!_markers.containsMarkerWithKey(key)) { 90 | key = Str.getCounterCase(key); 91 | } 92 | 93 | if (EditorUtils.isPrintableChar(key) && _markers.containsMarkerWithKey(key)) { 94 | ArrayList offsetsOfKey = _markers.getOffsetsOfKey(key); 95 | 96 | if (offsetsOfKey.size() > 1) { 97 | _markers.clear(); 98 | runReadAction(new ShowMarkersRunnable(offsetsOfKey, (AceJumpAction) _action)); 99 | return false; 100 | } 101 | 102 | jumpToOffset(offsetsOfKey.get(0)); 103 | return true; 104 | } 105 | 106 | return false; 107 | } 108 | 109 | private KeyListener createShowMarkersKeyListener() { 110 | return new KeyListener() { 111 | public void keyTyped(KeyEvent keyEvent) { 112 | keyEvent.consume(); 113 | boolean showMarkersFinished = handleShowMarkersKey(keyEvent.getKeyChar()); 114 | if (showMarkersFinished) { 115 | _contentComponent.removeKeyListener(_showMarkersKeyListener); 116 | } 117 | } 118 | 119 | public void keyPressed(KeyEvent keyEvent) { 120 | if (KeyEvent.VK_ESCAPE == keyEvent.getKeyChar()) { 121 | cleanupSetupsInAndBackToNormalEditingMode(); 122 | } 123 | } 124 | 125 | public void keyReleased(KeyEvent keyEvent) { 126 | } 127 | }; 128 | } 129 | 130 | private KeyListener createJumpToMarkupKeyListener(final AnActionEvent e) { 131 | return new KeyListener() { 132 | public void keyTyped(KeyEvent keyEvent) { 133 | keyEvent.consume(); 134 | 135 | if (KeyEvent.VK_SPACE == keyEvent.getKeyChar() || KeyEvent.VK_SEMICOLON == keyEvent.getKeyChar()) { 136 | cleanupSetupsInAndBackToNormalEditingMode(); 137 | } 138 | 139 | if (keyEvent.isShiftDown()) { 140 | addCommandAroundJump(new SelectAfterJumpCommand(_editor)); 141 | } 142 | 143 | boolean jumpFinished = handleJumpToMarkerKey(keyEvent.getKeyChar()); 144 | if (jumpFinished) { 145 | _contentComponent.removeKeyListener(_jumpToMarkerKeyListener); 146 | handlePendingActionOnSuccess(); 147 | } 148 | } 149 | 150 | public void keyPressed(KeyEvent keyEvent) { 151 | if (KeyEvent.VK_ESCAPE == keyEvent.getKeyChar()) { 152 | cleanupSetupsInAndBackToNormalEditingMode(); 153 | } 154 | } 155 | 156 | public void keyReleased(KeyEvent keyEvent) { 157 | } 158 | }; 159 | } 160 | 161 | private List getOffsetsOfCharInVisibleArea(char key) { 162 | if (_markers.get(key) != null) { 163 | return _markers.get(key).getOffsets(); 164 | } 165 | 166 | return findOffsetsInEditors(key); 167 | } 168 | 169 | private List findOffsetsInEditors(char key) { 170 | List joffsets = new ArrayList(); 171 | 172 | for (Editor editor : _editors) { 173 | List offsets = _offsetsFinder.getOffsets(key, editor, _editor); 174 | for (Integer offset : offsets) { 175 | joffsets.add(new JOffset(editor, offset)); 176 | } 177 | } 178 | 179 | return joffsets; 180 | } 181 | 182 | private void jumpToOffset(final JOffset jumpOffset) { 183 | for (CommandAroundJump cmd : _commandsAroundJump) { 184 | cmd.beforeJump(jumpOffset); 185 | } 186 | 187 | ApplicationManager.getApplication().runReadAction(new JumpRunnable(jumpOffset, this)); 188 | 189 | for (CommandAroundJump cmd : _commandsAroundJump) { 190 | cmd.preAfterJump(jumpOffset); 191 | cmd.afterJump(); 192 | } 193 | 194 | cleanupSetupsInAndBackToNormalEditingMode(); 195 | } 196 | 197 | public void cleanupSetupsInAndBackToNormalEditingMode() { 198 | if (_showMarkersKeyListener != null) { 199 | _contentComponent.removeKeyListener(_showMarkersKeyListener); 200 | _showMarkersKeyListener = null; 201 | } 202 | 203 | if (_jumpToMarkerKeyListener != null) { 204 | _contentComponent.removeKeyListener(_jumpToMarkerKeyListener); 205 | _showMarkersKeyListener = null; 206 | } 207 | 208 | if (_markersPanels != null) { 209 | for (MarkersPanel markersPanel : _markersPanels) { 210 | Container parent = markersPanel.getParent(); 211 | if (parent != null) { 212 | parent.remove(markersPanel); 213 | parent.repaint(); 214 | } 215 | } 216 | } 217 | 218 | for (Editor editor : _editors) { 219 | editor.getComponent().repaint(); 220 | } 221 | 222 | _commandsAroundJump = new Stack(); 223 | _offsetsFinder = new WordOffsetsFinder(); 224 | _isCalledFromOtherAction = false; 225 | super.cleanupSetupsInAndBackToNormalEditingMode(); 226 | } 227 | 228 | protected void initMemberVariableForConvenientAccess(AnActionEvent e) { 229 | super.initMemberVariableForConvenientAccess(e); 230 | 231 | _markers = new MarkerCollection(); 232 | _showMarkersKeyListener = createShowMarkersKeyListener(); 233 | _jumpToMarkerKeyListener = createJumpToMarkupKeyListener(e); 234 | } 235 | 236 | public void showNewMarkersPanel(ArrayList markersPanels) { 237 | if (_markersPanels != null) { 238 | for (MarkersPanel markersPanel : _markersPanels) { 239 | Container parent = markersPanel.getParent(); 240 | if (parent != null) { 241 | parent.remove(markersPanel); 242 | parent.repaint(); 243 | } 244 | } 245 | } 246 | 247 | _markersPanels = markersPanels; 248 | 249 | for (MarkersPanel markersPanel : markersPanels) { 250 | markersPanel._editor.getContentComponent().add(markersPanel); 251 | markersPanel._editor.getContentComponent().repaint(); 252 | } 253 | } 254 | 255 | public MarkerCollection getMarkerCollection() { 256 | return _markers; 257 | } 258 | 259 | public static AceJumpAction getInstance() { 260 | if (_instance == null) { 261 | _instance = new AceJumpAction(); 262 | } 263 | return _instance; 264 | } 265 | 266 | public void addCommandAroundJump(CommandAroundJump commandAroundJump) { 267 | _commandsAroundJump.push(commandAroundJump); 268 | } 269 | 270 | public boolean isCalledFromOtherAction() { 271 | return _isCalledFromOtherAction; 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/AceJumpAndReplaceRangeAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 6 | import com.intellij.openapi.editor.Editor; 7 | import org.hunmr.acejump.command.ReplaceAfterJumpCommand; 8 | import org.hunmr.common.selector.Selector; 9 | import org.hunmr.util.EditorUtils; 10 | 11 | public class AceJumpAndReplaceRangeAction extends AnAction { 12 | @Override 13 | public void actionPerformed(AnActionEvent e) { 14 | Editor editor = e.getData(PlatformDataKeys.EDITOR); 15 | String actionId = e.getActionManager().getId(this); 16 | String selectorClassName = "org.hunmr.common.selector." 17 | + actionId.substring("emacsIDEAs.AceJumpAndReplace.".length()) 18 | + "Selector"; 19 | 20 | try { 21 | Class selectorClass = (Class) Class.forName(selectorClassName); 22 | EditorUtils.copyRange(selectorClass, editor); 23 | 24 | AceJumpAction.getInstance().switchEditorIfNeed(e); 25 | AceJumpAction.getInstance().addCommandAroundJump(new ReplaceAfterJumpCommand(editor, selectorClass)); 26 | AceJumpAction.getInstance().performAction(e); 27 | 28 | 29 | } catch (ClassNotFoundException e1) { 30 | e1.printStackTrace(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/AceJumpCharAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | 6 | public class AceJumpCharAction extends AnAction { 7 | @Override 8 | public void actionPerformed(AnActionEvent e) { 9 | AceJumpAction.getInstance().performAction(e); 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/AceJumpCopyAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 6 | import com.intellij.openapi.editor.Editor; 7 | import org.hunmr.acejump.command.CopyAfterJumpCommand; 8 | 9 | public class AceJumpCopyAction extends AnAction { 10 | @Override 11 | public void actionPerformed(AnActionEvent e) { 12 | Editor editor = e.getData(PlatformDataKeys.EDITOR); 13 | 14 | AceJumpAction.getInstance().switchEditorIfNeed(e); 15 | AceJumpAction.getInstance().addCommandAroundJump(new CopyAfterJumpCommand(editor)); 16 | AceJumpAction.getInstance().performAction(e); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/AceJumpCopyRangeAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 6 | import com.intellij.openapi.editor.Editor; 7 | import org.hunmr.acejump.command.CopyRangeAfterJumpCommand; 8 | import org.hunmr.common.selector.Selector; 9 | 10 | public class AceJumpCopyRangeAction extends AnAction { 11 | @Override 12 | public void actionPerformed(AnActionEvent e) { 13 | Editor editor = e.getData(PlatformDataKeys.EDITOR); 14 | String actionId = e.getActionManager().getId(this); 15 | String selectorClassName = "org.hunmr.common.selector." 16 | + actionId.substring("emacsIDEAs.AceJumpCopy.".length()) 17 | + "Selector"; 18 | 19 | try { 20 | Class selectorClass = (Class) Class.forName(selectorClassName); 21 | //EditorUtils.copyRange(selectorClass, editor); 22 | 23 | AceJumpAction.getInstance().switchEditorIfNeed(e); 24 | AceJumpAction.getInstance().addCommandAroundJump(new CopyRangeAfterJumpCommand(editor, selectorClass)); 25 | 26 | AceJumpAction.getInstance().performAction(e); 27 | } catch (ClassNotFoundException e1) { 28 | e1.printStackTrace(); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/org/hunmr/acejump/AceJumpCutAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 6 | import com.intellij.openapi.editor.Editor; 7 | import org.hunmr.acejump.command.CutAfterJumpCommand; 8 | 9 | public class AceJumpCutAction extends AnAction { 10 | @Override 11 | public void actionPerformed(AnActionEvent e) { 12 | Editor editor = e.getData(PlatformDataKeys.EDITOR); 13 | 14 | AceJumpAction.getInstance().switchEditorIfNeed(e); 15 | AceJumpAction.getInstance().addCommandAroundJump(new CutAfterJumpCommand(editor)); 16 | AceJumpAction.getInstance().performAction(e); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/AceJumpDeleteRangeAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 6 | import com.intellij.openapi.editor.Editor; 7 | import org.hunmr.acejump.command.DeleteRangeAfterJumpCommand; 8 | import org.hunmr.common.selector.Selector; 9 | import org.hunmr.util.EditorUtils; 10 | 11 | public class AceJumpDeleteRangeAction extends AnAction { 12 | @Override 13 | public void actionPerformed(AnActionEvent e) { 14 | Editor editor = e.getData(PlatformDataKeys.EDITOR); 15 | String actionId = e.getActionManager().getId(this); 16 | String selectorClassName = "org.hunmr.common.selector." 17 | + actionId.substring("emacsIDEAs.AceJumpDelete.".length()) 18 | + "Selector"; 19 | 20 | try { 21 | Class selectorClass = (Class) Class.forName(selectorClassName); 22 | AceJumpAction.getInstance().switchEditorIfNeed(e); 23 | AceJumpAction.getInstance().addCommandAroundJump(new DeleteRangeAfterJumpCommand(editor, selectorClass)); 24 | AceJumpAction.getInstance().performAction(e); 25 | } catch (ClassNotFoundException e1) { 26 | e1.printStackTrace(); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/org/hunmr/acejump/AceJumpMoveRangeAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 6 | import com.intellij.openapi.editor.Editor; 7 | import org.hunmr.acejump.command.MoveRangeAfterJumpCommand; 8 | import org.hunmr.common.selector.Selector; 9 | import org.hunmr.util.EditorUtils; 10 | 11 | public class AceJumpMoveRangeAction extends AnAction { 12 | @Override 13 | public void actionPerformed(AnActionEvent e) { 14 | Editor editor = e.getData(PlatformDataKeys.EDITOR); 15 | String actionId = e.getActionManager().getId(this); 16 | String selectorClassName = "org.hunmr.common.selector." 17 | + actionId.substring("emacsIDEAs.AceJumpMove.".length()) 18 | + "Selector"; 19 | 20 | try { 21 | Class selectorClass = (Class) Class.forName(selectorClassName); 22 | EditorUtils.copyRange(selectorClass, editor); 23 | 24 | AceJumpAction.getInstance().switchEditorIfNeed(e); 25 | AceJumpAction.getInstance().addCommandAroundJump(new MoveRangeAfterJumpCommand(editor, selectorClass)); 26 | AceJumpAction.getInstance().performAction(e); 27 | } catch (ClassNotFoundException e1) { 28 | e1.printStackTrace(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/AceJumpObtainThenReplaceRangeAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 6 | import com.intellij.openapi.editor.Editor; 7 | import org.hunmr.acejump.command.ObtainAndPasteRangeAfterJumpCommand; 8 | import org.hunmr.common.selector.Selector; 9 | 10 | public class AceJumpObtainThenReplaceRangeAction extends AnAction { 11 | @Override 12 | public void actionPerformed(AnActionEvent e) { 13 | Editor editor = e.getData(PlatformDataKeys.EDITOR); 14 | 15 | String actionId = e.getActionManager().getId(this); 16 | String selectorClassName = "org.hunmr.common.selector." 17 | + actionId.substring("emacsIDEAs.AceJumpObtainThenReplace.".length()) 18 | + "Selector"; 19 | 20 | try { 21 | Class selectorClass = (Class) Class.forName(selectorClassName); 22 | AceJumpAction.getInstance().switchEditorIfNeed(e); 23 | AceJumpAction.getInstance().addCommandAroundJump(new ObtainAndPasteRangeAfterJumpCommand(editor, selectorClass)); 24 | AceJumpAction.getInstance().performAction(e); 25 | } catch (ClassNotFoundException e1) { 26 | e1.printStackTrace(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/AceJumpSelectAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 6 | import com.intellij.openapi.editor.Editor; 7 | import org.hunmr.acejump.command.SelectAfterJumpCommand; 8 | 9 | public class AceJumpSelectAction extends AnAction { 10 | 11 | @Override 12 | public void actionPerformed(AnActionEvent e) { 13 | Editor editor = e.getData(PlatformDataKeys.EDITOR); 14 | AceJumpAction.getInstance().switchEditorIfNeed(e); 15 | AceJumpAction.getInstance().addCommandAroundJump(new SelectAfterJumpCommand(editor)); 16 | AceJumpAction.getInstance().performAction(e); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/command/CommandAroundJump.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.command; 2 | 3 | import com.intellij.openapi.components.ServiceManager; 4 | import com.intellij.openapi.editor.Editor; 5 | import org.hunmr.acejump.marker.JOffset; 6 | import org.hunmr.options.PluginConfig; 7 | 8 | public class CommandAroundJump { 9 | protected Editor _se; /*source editor*/ 10 | protected int _soff; 11 | 12 | protected Editor _te; /*target editor*/ 13 | protected int _toff; 14 | 15 | final PluginConfig _config = ServiceManager.getService(PluginConfig.class); 16 | 17 | public CommandAroundJump(Editor editor) { 18 | _se = editor; 19 | } 20 | 21 | public void beforeJump(final JOffset jumpTargetOffset) { 22 | _soff = _se.getCaretModel().getOffset(); 23 | } 24 | 25 | public void preAfterJump(final JOffset jumpTargetOffset) { 26 | _te = jumpTargetOffset.editor; 27 | _toff = jumpTargetOffset.offset; 28 | } 29 | 30 | public void afterJump() { 31 | } 32 | 33 | public void focusSourceCaret() { 34 | _se.getContentComponent().requestFocus(); 35 | _se.getCaretModel().moveToOffset(_soff); 36 | } 37 | 38 | public void focusTargetCaret() { 39 | _te.getContentComponent().requestFocus(); 40 | _te.getCaretModel().moveToOffset(_toff); 41 | } 42 | 43 | protected void selectJumpArea() { 44 | if (inSameEditor()) { 45 | if (_soff < _toff) 46 | _se.getSelectionModel().setSelection(_soff, _toff); 47 | else 48 | _se.getSelectionModel().setSelection(_toff, _soff); 49 | } 50 | } 51 | 52 | public boolean inSameEditor() { 53 | return _se == _te; 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/command/CopyAfterJumpCommand.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.command; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.editor.SelectionModel; 5 | import org.hunmr.acejump.marker.JOffset; 6 | import org.hunmr.util.AppUtil; 7 | 8 | public class CopyAfterJumpCommand extends CommandAroundJump { 9 | public CopyAfterJumpCommand(Editor editor) { 10 | super(editor); 11 | } 12 | 13 | @Override 14 | public void afterJump() { 15 | final Runnable runnable = new Runnable() { 16 | @Override 17 | public void run() { 18 | selectJumpArea(); 19 | _te.getSelectionModel().copySelectionToClipboard(); 20 | _te.getSelectionModel().removeSelection(); 21 | } 22 | }; 23 | 24 | AppUtil.runWriteAction(runnable, _se); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/command/CopyRangeAfterJumpCommand.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.command; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.editor.impl.EditorCopyPasteHelperImpl; 5 | import com.intellij.openapi.util.TextRange; 6 | import org.hunmr.acejump.marker.JOffset; 7 | import org.hunmr.common.selector.Selector; 8 | import org.hunmr.util.AppUtil; 9 | import org.hunmr.util.EditorUtils; 10 | 11 | public class CopyRangeAfterJumpCommand extends CommandAroundJump { 12 | private final Class _selectorClass; 13 | 14 | public CopyRangeAfterJumpCommand(Editor editor, Class selectorClass) { 15 | super(editor); 16 | _selectorClass = selectorClass; 17 | } 18 | 19 | 20 | @Override 21 | public void afterJump() { 22 | final Runnable runnable = new Runnable() { 23 | @Override 24 | public void run() { 25 | EditorUtils.copyRange(_selectorClass, _te); 26 | pasteClipboardToOffset(); 27 | } 28 | 29 | private void pasteClipboardToOffset() { 30 | focusSourceCaret(); 31 | 32 | TextRange[] tr = EditorCopyPasteHelperImpl.getInstance().pasteFromClipboard(_se); 33 | 34 | if (_config._needSelectTextAfterJump) 35 | EditorUtils.selectTextRange(_se, tr); 36 | } 37 | }; 38 | 39 | AppUtil.runWriteAction(runnable, _se); 40 | } 41 | } -------------------------------------------------------------------------------- /src/org/hunmr/acejump/command/CutAfterJumpCommand.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.command; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.editor.EditorModificationUtil; 5 | import org.hunmr.acejump.marker.JOffset; 6 | import org.hunmr.util.AppUtil; 7 | 8 | public class CutAfterJumpCommand extends CommandAroundJump { 9 | public CutAfterJumpCommand(Editor editor) { 10 | super(editor); 11 | } 12 | 13 | @Override 14 | public void afterJump() { 15 | final Runnable runnable = new Runnable() { 16 | @Override 17 | public void run() { 18 | if (inSameEditor()) { 19 | selectJumpArea(); 20 | 21 | _se.getSelectionModel().copySelectionToClipboard(); 22 | EditorModificationUtil.deleteSelectedText(_se); 23 | _se.getSelectionModel().removeSelection(); 24 | } 25 | } 26 | }; 27 | 28 | AppUtil.runWriteAction(runnable, _se); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/command/DeleteRangeAfterJumpCommand.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.command; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import org.hunmr.acejump.marker.JOffset; 5 | import org.hunmr.common.selector.Selector; 6 | import org.hunmr.util.AppUtil; 7 | import org.hunmr.util.EditorUtils; 8 | 9 | public class DeleteRangeAfterJumpCommand extends CommandAroundJump { 10 | private final Class _selectorClass; 11 | 12 | public DeleteRangeAfterJumpCommand(Editor editor, Class selectorClass) { 13 | super(editor); 14 | _selectorClass = selectorClass; 15 | } 16 | 17 | 18 | @Override 19 | public void afterJump() { 20 | final Runnable runnable = new Runnable() { 21 | @Override 22 | public void run() { 23 | //TODO: add option to specify whether copy or not before delete 24 | EditorUtils.copyRange(_selectorClass, _te); 25 | EditorUtils.deleteRange(_selectorClass, _te); 26 | } 27 | }; 28 | 29 | AppUtil.runWriteAction(runnable, _se); 30 | } 31 | } -------------------------------------------------------------------------------- /src/org/hunmr/acejump/command/MoveRangeAfterJumpCommand.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.command; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.editor.EditorModificationUtil; 5 | import com.intellij.openapi.editor.impl.EditorCopyPasteHelperImpl; 6 | import com.intellij.openapi.util.TextRange; 7 | import org.hunmr.acejump.marker.JOffset; 8 | import org.hunmr.common.selector.Selector; 9 | import org.hunmr.util.AppUtil; 10 | import org.hunmr.util.EditorUtils; 11 | 12 | public class MoveRangeAfterJumpCommand extends CommandAroundJump { 13 | private final Class _selectorClass; 14 | private int _length; 15 | 16 | public MoveRangeAfterJumpCommand(Editor editor, Class selectorClass) { 17 | super(editor); 18 | _selectorClass = selectorClass; 19 | _length = 0; 20 | } 21 | 22 | 23 | @Override 24 | public void afterJump() { 25 | final Runnable runnable = new Runnable() { 26 | @Override 27 | public void run() { 28 | TextRange sourceRange = EditorUtils.getRangeOf(_selectorClass, _te); 29 | 30 | if (inSameEditor()) { 31 | boolean noNeedToMove = sourceRange.contains(_soff); 32 | if (noNeedToMove) { 33 | _se.getCaretModel().moveToOffset(_soff); 34 | return; 35 | } 36 | } 37 | 38 | int textSourceStartOffset = sourceRange.getStartOffset(); 39 | 40 | EditorUtils.copyRange(_selectorClass, _te); 41 | 42 | if ( !inSameEditor() || textSourceStartOffset > _soff) { 43 | deleteTextSource(_te); 44 | 45 | pasteClipboardToOffset(); 46 | } else { 47 | pasteClipboardToOffset(); 48 | 49 | focusTargetCaret(); 50 | deleteTextSource(_te); 51 | focusSourceCaret(); 52 | 53 | int cur_offset = _se.getCaretModel().getOffset(); 54 | 55 | if (_config._needSelectTextAfterJump) { 56 | EditorUtils.selectTextRange(_se, cur_offset - _length, cur_offset); 57 | } 58 | } 59 | } 60 | 61 | private void deleteTextSource(Editor editor) { 62 | EditorUtils.selectRangeOf(_selectorClass, editor); 63 | EditorModificationUtil.deleteSelectedText(editor); 64 | } 65 | 66 | private void pasteClipboardToOffset() { 67 | focusSourceCaret(); 68 | 69 | TextRange[] tr = EditorCopyPasteHelperImpl.getInstance().pasteFromClipboard(_se); 70 | if (_config._needSelectTextAfterJump) { 71 | EditorUtils.selectTextRange(_se, tr); 72 | } 73 | _length = tr[0].getEndOffset() - tr[0].getStartOffset(); 74 | } 75 | }; 76 | 77 | AppUtil.runWriteAction(runnable, _se); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/command/ObtainAndPasteRangeAfterJumpCommand.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.command; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.editor.impl.EditorCopyPasteHelperImpl; 5 | import com.intellij.openapi.util.TextRange; 6 | import org.hunmr.acejump.marker.JOffset; 7 | import org.hunmr.common.selector.Selector; 8 | import org.hunmr.util.AppUtil; 9 | import org.hunmr.util.EditorUtils; 10 | 11 | public class ObtainAndPasteRangeAfterJumpCommand extends CommandAroundJump { 12 | 13 | private final Class _selectorClass; 14 | 15 | public ObtainAndPasteRangeAfterJumpCommand(Editor editor, Class selectorClass) { 16 | super(editor); 17 | _selectorClass = selectorClass; 18 | } 19 | 20 | @Override 21 | public void afterJump() { 22 | final Runnable runnable = new Runnable() { 23 | @Override 24 | public void run() { 25 | EditorUtils.copyRange(_selectorClass, _te); 26 | focusSourceCaret(); 27 | 28 | EditorUtils.selectRangeOf(_selectorClass, _se); 29 | EditorUtils.deleteRange(_selectorClass, _se); 30 | TextRange[] tr = EditorCopyPasteHelperImpl.getInstance().pasteFromClipboard(_se); 31 | 32 | if (_config._needSelectTextAfterJump) { 33 | EditorUtils.selectTextRange(_se, tr); 34 | } 35 | } 36 | }; 37 | 38 | AppUtil.runWriteAction(runnable, _se); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/command/PasteAfterJumpCommand.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.command; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.editor.impl.EditorCopyPasteHelperImpl; 5 | import com.intellij.openapi.util.TextRange; 6 | import org.hunmr.acejump.marker.JOffset; 7 | import org.hunmr.util.AppUtil; 8 | 9 | public class PasteAfterJumpCommand extends CommandAroundJump { 10 | private boolean _addNewLineBeforePaste; 11 | 12 | public PasteAfterJumpCommand(Editor editor) { 13 | super(editor); 14 | _addNewLineBeforePaste = false; 15 | } 16 | 17 | public PasteAfterJumpCommand(Editor editor, boolean addNewLineBeforePaste) { 18 | super(editor); 19 | _addNewLineBeforePaste = addNewLineBeforePaste; 20 | } 21 | 22 | @Override 23 | public void beforeJump(final JOffset jumpTargetOffset) { 24 | } 25 | 26 | public TextRange getTextRangeToReplace() 27 | { 28 | return null; 29 | } 30 | 31 | @Override 32 | public void afterJump() { 33 | TextRange tr = getTextRangeToReplace(); 34 | if (tr != null) 35 | { 36 | _se.getSelectionModel().setSelection(tr.getStartOffset(), tr.getEndOffset()); 37 | } 38 | 39 | final Runnable runnable = new Runnable() { 40 | @Override 41 | public void run() { 42 | if (_addNewLineBeforePaste) { 43 | _se.getDocument().insertString(_se.getCaretModel().getOffset(), "\n"); 44 | _se.getCaretModel().moveToOffset(_se.getCaretModel().getOffset() + 1); 45 | } 46 | 47 | EditorCopyPasteHelperImpl.getInstance().pasteFromClipboard(_se); 48 | } 49 | }; 50 | 51 | AppUtil.runWriteAction(runnable, _se); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/command/ReplaceAfterJumpCommand.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.command; 2 | 3 | import com.intellij.openapi.editor.CaretModel; 4 | import com.intellij.openapi.editor.Editor; 5 | import com.intellij.openapi.editor.impl.EditorCopyPasteHelperImpl; 6 | import com.intellij.openapi.util.TextRange; 7 | import org.hunmr.acejump.marker.JOffset; 8 | import org.hunmr.common.selector.Selector; 9 | import org.hunmr.util.AppUtil; 10 | import org.hunmr.util.EditorUtils; 11 | 12 | public class ReplaceAfterJumpCommand extends CommandAroundJump { 13 | private boolean _addNewLineBeforePaste; 14 | protected final Class _selectorClass; 15 | 16 | private int _caretOffsetFromSelectRangeStartBeforeJump; 17 | 18 | public ReplaceAfterJumpCommand(Editor editor, Class selectorClass) { 19 | super(editor); 20 | _addNewLineBeforePaste = false; 21 | _selectorClass = selectorClass; 22 | } 23 | 24 | @Override 25 | public void beforeJump(final JOffset jumpTargetOffset) { 26 | super.beforeJump(jumpTargetOffset); 27 | EditorUtils.selectRangeOf(_selectorClass, _se); 28 | _caretOffsetFromSelectRangeStartBeforeJump = _soff - _se.getSelectionModel().getSelectionStart(); 29 | focusSourceCaret(); 30 | } 31 | 32 | @Override 33 | public void afterJump() { 34 | final Runnable runnable = new Runnable() { 35 | @Override 36 | public void run() { 37 | 38 | TextRange tr = EditorUtils.getRangeOf(_selectorClass, _te); 39 | if (tr != null) 40 | { 41 | _te.getSelectionModel().setSelection(tr.getStartOffset(), tr.getEndOffset()); 42 | EditorUtils.deleteRange(tr, _te); 43 | } 44 | 45 | CaretModel targetCaret = _te.getCaretModel(); 46 | 47 | if (_addNewLineBeforePaste) { 48 | _te.getDocument().insertString(targetCaret.getOffset(), "\n"); 49 | targetCaret.moveToOffset(targetCaret.getOffset() + 1); 50 | } 51 | 52 | TextRange[] textRanges = EditorCopyPasteHelperImpl.getInstance().pasteFromClipboard(_te); 53 | 54 | if (_config._needSelectTextAfterJump) { 55 | int caret = textRanges[0].getStartOffset() + _caretOffsetFromSelectRangeStartBeforeJump; 56 | targetCaret.moveToOffset(caret); 57 | EditorUtils.selectRangeOf(_selectorClass, _te); 58 | } 59 | } 60 | }; 61 | 62 | AppUtil.runWriteAction(runnable, _se); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/command/ReplaceRangeAfterJumpCommand.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.command; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.util.TextRange; 5 | import org.hunmr.common.selector.Selector; 6 | import org.hunmr.util.EditorUtils; 7 | 8 | public class ReplaceRangeAfterJumpCommand extends PasteAfterJumpCommand { 9 | private final Class _selectorClass; 10 | 11 | public ReplaceRangeAfterJumpCommand(Editor editor, Class selectorClass) { 12 | super(editor); 13 | _selectorClass = selectorClass; 14 | } 15 | 16 | public TextRange getTextRangeToReplace() 17 | { 18 | return EditorUtils.getRangeOf(_selectorClass, _se); 19 | } 20 | } -------------------------------------------------------------------------------- /src/org/hunmr/acejump/command/SelectAfterJumpCommand.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.command; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import org.hunmr.acejump.marker.JOffset; 5 | 6 | public class SelectAfterJumpCommand extends CommandAroundJump { 7 | public SelectAfterJumpCommand(Editor editor) { 8 | super(editor); 9 | } 10 | 11 | @Override 12 | public void beforeJump(final JOffset jumpTargetOffset) { 13 | super.beforeJump(jumpTargetOffset); 14 | } 15 | 16 | @Override 17 | public void afterJump() { 18 | selectJumpArea(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/marker/JOffset.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.marker; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | 5 | public class JOffset { 6 | public Editor editor; 7 | public int offset; 8 | 9 | public JOffset(Editor editor, int offset) { 10 | this.editor = editor; 11 | this.offset = offset; 12 | } 13 | 14 | public void restoreCaret() { 15 | editor.getContentComponent().requestFocus(); 16 | editor.getCaretModel().moveToOffset(offset); 17 | } 18 | 19 | @Override 20 | public boolean equals(Object o) { 21 | if (this == o) return true; 22 | if (o == null || getClass() != o.getClass()) return false; 23 | 24 | JOffset jOffset = (JOffset) o; 25 | 26 | if (offset != jOffset.offset) return false; 27 | return !(editor != null ? !editor.equals(jOffset.editor) : jOffset.editor != null); 28 | 29 | } 30 | 31 | @Override 32 | public int hashCode() { 33 | int result = editor != null ? editor.hashCode() : 0; 34 | result = 31 * result + offset; 35 | return result; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/marker/Marker.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.marker; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class Marker { 6 | private String _marker; 7 | private ArrayList _offsets = new ArrayList(); 8 | 9 | public Marker(String marker, JOffset offset) { 10 | _marker = marker; 11 | addOffsetToMarker(offset); 12 | } 13 | 14 | public void addOffsetToMarker(JOffset offset) { 15 | _offsets.add(offset); 16 | } 17 | 18 | public ArrayList getOffsets() { 19 | return _offsets; 20 | } 21 | 22 | public char getMarkerChar() { 23 | return _marker.charAt(0); 24 | } 25 | 26 | public String getMarker() { 27 | return _marker; 28 | } 29 | 30 | public JOffset getOffset() { 31 | return _offsets.get(0); 32 | } 33 | 34 | public boolean isMappingToMultipleOffset() { 35 | return _offsets.size() > 1; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/marker/MarkerCollection.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.marker; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | 7 | public class MarkerCollection extends HashMap { 8 | 9 | public ArrayList getOffsetsOfKey(char key) { 10 | ArrayList ai = new ArrayList(); 11 | 12 | for (Marker marker : this.values()) { 13 | if (marker.getMarkerChar() == key) { 14 | ai.addAll(marker.getOffsets()); 15 | } 16 | } 17 | 18 | Collections.reverse(ai); 19 | return ai; 20 | } 21 | 22 | public void addMarker(String key, JOffset offset) { 23 | Marker marker = this.get(key); 24 | 25 | if (marker == null) { 26 | this.put(key, new Marker(key, offset)); 27 | return; 28 | } 29 | 30 | marker.addOffsetToMarker(offset); 31 | } 32 | 33 | public JOffset getFirstOffset() { 34 | return this.values().iterator().next().getOffset(); 35 | } 36 | 37 | public boolean hasOnlyOnePlaceToJump() { 38 | return this.size() == 1; 39 | } 40 | 41 | public boolean hasNoPlaceToJump() { 42 | return this.isEmpty(); 43 | } 44 | 45 | public boolean containsMarkerWithKey(char key) { 46 | for (Marker marker : this.values()) { 47 | if (marker.getMarkerChar() == key) { 48 | return true; 49 | } 50 | } 51 | 52 | return false; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/marker/MarkersPanel.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.marker; 2 | 3 | import com.intellij.openapi.components.ServiceManager; 4 | import com.intellij.openapi.editor.Editor; 5 | import com.intellij.openapi.editor.colors.EditorFontType; 6 | import org.hunmr.options.PluginConfig; 7 | 8 | import javax.swing.*; 9 | import java.awt.*; 10 | import java.awt.geom.Rectangle2D; 11 | import java.util.*; 12 | 13 | public class MarkersPanel extends JComponent { 14 | public static final Color PANEL_BACKGROUND_COLOR = new Color(128, 138, 142); 15 | public Editor _editor; 16 | private MarkerCollection _markerCollection; 17 | 18 | final PluginConfig _config = ServiceManager.getService(PluginConfig.class); 19 | 20 | public MarkersPanel(Editor editor, MarkerCollection markerCollection) { 21 | _editor = editor; 22 | _markerCollection = markerCollection; 23 | setupLocationAndBoundsOfPanel(editor); 24 | } 25 | 26 | private boolean isLineEndOffset(Marker marker) { 27 | int offset = marker.getOffset().offset; 28 | Editor editor = marker.getOffset().editor; 29 | 30 | int lineA = editor.getDocument().getLineNumber(offset); 31 | int lineEndOffset = editor.getDocument().getLineEndOffset(lineA); 32 | 33 | return offset == lineEndOffset; 34 | } 35 | 36 | @Override 37 | public void paint(Graphics g) { 38 | Font font = _editor.getColorsScheme().getFont(EditorFontType.BOLD); 39 | FontMetrics fontMetrics = _editor.getContentComponent().getFontMetrics(font); 40 | 41 | g.setFont(font); 42 | drawPanelBackground(g); 43 | 44 | HashSet firstJumpOffsets = new HashSet(); 45 | for (Marker marker : _markerCollection.values()) { 46 | if (marker.getOffset().editor != _editor) continue; 47 | 48 | for (JOffset offset : marker.getOffsets()) { 49 | firstJumpOffsets.add(offset); 50 | 51 | Rectangle2D fontRect = fontMetrics.getStringBounds(String.valueOf(marker.getMarkerChar()), g); 52 | drawBackground(g, __x(offset), __y(offset), _config.getFirstJumpBackground(), fontRect); 53 | drawMarkerChar(g, __x(offset), __y(offset) + font.getSize() * 0.9, marker.getMarkerChar(), _config.getFirstJumpForeground()); 54 | } 55 | } 56 | 57 | for (Marker marker : _markerCollection.values()) { 58 | if (marker.getOffset().editor != _editor) continue; 59 | if (marker.getMarker().length() == 1 || marker.isMappingToMultipleOffset()) continue; 60 | if (isAlreadyHasFirstJumpCharInPlace(firstJumpOffsets, marker) && !isLineEndOffset(marker)) continue; 61 | 62 | for (JOffset offset : marker.getOffsets()) { 63 | Rectangle2D fontRect = fontMetrics.getStringBounds(String.valueOf(marker.getMarker().charAt(1)), g); 64 | drawBackground(g, __x(offset) + fontRect.getWidth(), __y(offset), _config.getSecondJumpBackground(), fontRect); 65 | drawMarkerChar(g, __x(offset) + fontRect.getWidth(), __y(offset) + font.getSize() * 0.9, marker.getMarker().charAt(1), _config.getSecondJumpForeground()); 66 | } 67 | } 68 | 69 | super.paint(g); 70 | } 71 | 72 | private boolean isAlreadyHasFirstJumpCharInPlace(HashSet firstJumpOffsets, Marker marker) { 73 | JOffset o = new JOffset(marker.getOffset().editor, marker.getOffset().offset + 1); 74 | return firstJumpOffsets.contains(o); 75 | } 76 | 77 | private double __y(JOffset offset) { 78 | Point parentLocation = _editor.getContentComponent().getLocation(); 79 | return getVisiblePosition(offset).getY() + parentLocation.getY(); 80 | } 81 | 82 | private double __x(JOffset offset) { 83 | Point parentLocation = _editor.getContentComponent().getLocation(); 84 | return getVisiblePosition(offset).getX() + parentLocation.getX(); 85 | } 86 | 87 | private void drawMarkerChar(Graphics g, double x, double y, char markerChar, Color firstJumpForeground) { 88 | g.setColor(firstJumpForeground); 89 | ((Graphics2D)g).drawString(String.valueOf(markerChar), (float)x, (float)y); 90 | } 91 | 92 | private void drawBackground(Graphics g, double x, double y, Color firstJumpBackground, Rectangle2D fontRect) { 93 | g.setColor(firstJumpBackground); 94 | g.fillRect((int)x, (int)y, (int) (fontRect.getWidth() * 1.02), (int) (fontRect.getHeight() * 1.08)); 95 | } 96 | 97 | private Point getVisiblePosition(JOffset offset) { 98 | return offset.editor.visualPositionToXY(offset.editor.offsetToVisualPosition(offset.offset)); 99 | } 100 | 101 | private void drawPanelBackground(Graphics g) { 102 | ((Graphics2D)g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f)); 103 | g.setColor(PANEL_BACKGROUND_COLOR); 104 | g.fillRect(0, 0, (int) this.getBounds().getWidth(), (int) this.getBounds().getHeight()); 105 | ((Graphics2D)g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)); 106 | } 107 | 108 | private void setupLocationAndBoundsOfPanel(Editor editor) { 109 | this.setLocation(0, 0); 110 | Rectangle visibleArea = editor.getScrollingModel().getVisibleArea(); 111 | JComponent parent = editor.getContentComponent(); 112 | int x = (int) (parent.getLocation().getX() + visibleArea.getX() + editor.getScrollingModel().getHorizontalScrollOffset()); 113 | this.setBounds(x, (int) (visibleArea.getY()), (int) visibleArea.getWidth(), (int) visibleArea.getHeight()); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/offsets/CharOffsetsFinder.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.offsets; 2 | 3 | public class CharOffsetsFinder extends OffsetsFinder { 4 | 5 | @Override 6 | protected boolean isValidOffset(char c, String visibleText, int index, int offset, int caretOffset) { 7 | return !isSpaceAndShouldIgnore(c, visibleText, index); 8 | } 9 | 10 | private boolean isSpaceAndShouldIgnore(char c, String visibleText, int index) { 11 | if (isSpace(c)) { 12 | boolean isAfterSpace = (index != 0) && (isSpace(visibleText.charAt(index - 1))); 13 | if (isAfterSpace) { 14 | return true; 15 | } 16 | } 17 | return false; 18 | } 19 | 20 | private boolean isSpace(char c) { 21 | return c == ' ' || c == '\t'; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/offsets/OffsetsFinder.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.offsets; 2 | 3 | import com.intellij.openapi.editor.Document; 4 | import com.intellij.openapi.editor.Editor; 5 | import com.intellij.openapi.util.TextRange; 6 | import org.hunmr.util.EditorUtils; 7 | 8 | import java.awt.event.KeyEvent; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | public class OffsetsFinder { 13 | public List getOffsets(char key, Editor editor, Editor selectedEditor) { 14 | Document document = editor.getDocument(); 15 | TextRange visibleRange = EditorUtils.getVisibleTextRange(editor); 16 | List offsets = getOffsetsOfCharIgnoreCase(String.valueOf(key), visibleRange, document, editor, selectedEditor); 17 | 18 | if (key == KeyEvent.VK_SPACE) { 19 | offsets.addAll(getOffsetsOfCharIgnoreCase("\t\r\n", visibleRange, document, editor, selectedEditor)); 20 | addStartLineOffsetsTo(offsets, editor); 21 | } else if (key == ',') { 22 | offsets.addAll(getOffsetsOfCharIgnoreCase("|`/\\;.{}()[]<>?_=-+'\"!@#$%^&*", visibleRange, document, editor, selectedEditor)); 23 | } 24 | 25 | return offsets; 26 | } 27 | 28 | private void addStartLineOffsetsTo(List offsets, Editor editor) { 29 | ArrayList visibleLineStartOffsets = EditorUtils.getVisibleLineStartOffsets(editor); 30 | for (Integer i : visibleLineStartOffsets) { 31 | if (!offsets.contains(i)) { 32 | offsets.add(i); 33 | } 34 | } 35 | } 36 | 37 | protected ArrayList getOffsetsOfCharIgnoreCase(String charSet, TextRange markerRange, Document document, Editor editor, Editor selectedEditor) { 38 | ArrayList offsets = new ArrayList(); 39 | String visibleText = document.getText(markerRange); 40 | 41 | for (char charToFind : charSet.toCharArray()) { 42 | char lowCase = Character.toLowerCase(charToFind); 43 | char upperCase = Character.toUpperCase(charToFind); 44 | 45 | offsets.addAll(getOffsetsOfChar(markerRange.getStartOffset(), lowCase, visibleText, editor, selectedEditor)); 46 | if (upperCase != lowCase) { 47 | offsets.addAll(getOffsetsOfChar(markerRange.getStartOffset(), upperCase, visibleText, editor, selectedEditor)); 48 | } 49 | } 50 | 51 | return offsets; 52 | } 53 | 54 | private ArrayList getOffsetsOfChar(int startOffset, char c, String visibleText, Editor editor, Editor selectedEditor) { 55 | int caretOffset = editor.getCaretModel().getOffset(); 56 | 57 | ArrayList offsets = new ArrayList(); 58 | 59 | int index = visibleText.indexOf(c); 60 | while (index >= 0) { 61 | int offset = startOffset + index; 62 | 63 | if (isValidOffset(c, visibleText, index, offset, caretOffset)) { 64 | if (editor != selectedEditor || offset != caretOffset) 65 | offsets.add(offset); 66 | } 67 | 68 | index = visibleText.indexOf(c, index + 1); 69 | } 70 | 71 | return offsets; 72 | } 73 | 74 | protected boolean isValidOffset(char c, String visibleText, int index, int offset, int caretOffset) { 75 | return true; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/offsets/WordOffsetsFinder.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.offsets; 2 | 3 | public class WordOffsetsFinder extends OffsetsFinder { 4 | @Override 5 | protected boolean isValidOffset(char c, String visibleText, int index, int offset, int caretOffset) { 6 | if (!Character.isLetterOrDigit(c)) { 7 | return true; 8 | } 9 | 10 | boolean isBeginningChar = index == 0; 11 | if (isBeginningChar) { 12 | return true; 13 | } 14 | 15 | char charBeforeOffset = visibleText.charAt(index - 1); 16 | if (isCharInDifferentCategory(c, charBeforeOffset)) { 17 | return true; 18 | } 19 | 20 | char charAtOffset = visibleText.charAt(index); 21 | if (Character.isUpperCase(charAtOffset) && Character.isLowerCase(charBeforeOffset)) { 22 | return true; 23 | } 24 | 25 | return false; 26 | } 27 | 28 | private boolean isCharInDifferentCategory(char c, char charBeforeOffset) { 29 | return Character.isLetter(c) ^ Character.isLetter(charBeforeOffset) 30 | || Character.isDigit(c) ^ Character.isDigit(charBeforeOffset); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/runnable/JumpRunnable.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.runnable; 2 | 3 | import org.hunmr.acejump.AceJumpAction; 4 | import org.hunmr.acejump.marker.JOffset; 5 | 6 | public class JumpRunnable implements Runnable{ 7 | 8 | private JOffset _offsetToJump; 9 | private AceJumpAction _action; 10 | 11 | public JumpRunnable(JOffset _offsetToJump, AceJumpAction _action) { 12 | this._offsetToJump = _offsetToJump; 13 | this._action = _action; 14 | } 15 | 16 | @Override 17 | public void run() { 18 | _offsetToJump.editor.getContentComponent().requestFocus(); 19 | _offsetToJump.editor.getCaretModel().moveToOffset(_offsetToJump.offset); 20 | _offsetToJump.editor.getSelectionModel().removeSelection(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/org/hunmr/acejump/runnable/ShowMarkersRunnable.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.acejump.runnable; 2 | 3 | import com.intellij.openapi.editor.Document; 4 | import com.intellij.openapi.editor.Editor; 5 | import org.hunmr.acejump.AceJumpAction; 6 | import org.hunmr.acejump.marker.JOffset; 7 | import org.hunmr.acejump.marker.MarkerCollection; 8 | import org.hunmr.acejump.marker.MarkersPanel; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Collections; 12 | import java.util.Comparator; 13 | import java.util.List; 14 | 15 | public class ShowMarkersRunnable implements Runnable { 16 | public static final char INFINITE_JUMP_CHAR = '/'; 17 | private static final String MARKER_CHARSET = "asdfjeghiybcmnopqrtuvwkl"; //TODO: customizable 18 | private final List _offsets; 19 | private final AceJumpAction _action; 20 | private final Editor _editor; 21 | private final ArrayList _editors; 22 | private MarkerCollection _markerCollection; 23 | 24 | public ShowMarkersRunnable(List offsets, AceJumpAction currentExecutingAction) { 25 | _offsets = offsets; 26 | _editor = currentExecutingAction.getEditor(); 27 | _editors = currentExecutingAction.getEditors(); 28 | this._action = currentExecutingAction; 29 | _markerCollection = _action.getMarkerCollection(); 30 | } 31 | 32 | @Override 33 | public void run() { 34 | if (_offsets.isEmpty()) { 35 | return; 36 | } 37 | 38 | int caretOffset = _editor.getCaretModel().getOffset(); 39 | sortOffsetsByDistanceToCaret(caretOffset); 40 | sortOffsetsToImprovePriorityOfLineEnd(); 41 | 42 | int twiceJumpGroupCount = calcTwiceJumpGroupCount(); 43 | int singleJumpCount = Math.min(MARKER_CHARSET.length() - twiceJumpGroupCount, _offsets.size()); 44 | 45 | createSingleJumpMarkers(singleJumpCount); 46 | if (twiceJumpGroupCount > 0) { 47 | createMultipleJumpMarkers(singleJumpCount); 48 | } 49 | 50 | ArrayList panels = new ArrayList(); 51 | for (Editor editor : _editors) { 52 | MarkersPanel markersPanel = new MarkersPanel(editor, _markerCollection); 53 | panels.add(markersPanel); 54 | } 55 | 56 | _action.showNewMarkersPanel(panels); 57 | } 58 | 59 | private void createSingleJumpMarkers(int singleJumpCount) { 60 | for (int i = 0; i < singleJumpCount ; i++) { 61 | String marker = String.valueOf(MARKER_CHARSET.charAt(i)); 62 | _markerCollection.addMarker(marker, _offsets.get(i)); 63 | } 64 | } 65 | 66 | private void createMultipleJumpMarkers(int singleJumpCount) { 67 | int i = singleJumpCount; 68 | 69 | for (;i < _offsets.size(); i++) { 70 | int group = (i - singleJumpCount) / MARKER_CHARSET.length(); 71 | int markerCharIndex = singleJumpCount + group; 72 | 73 | if (markerCharIndex > MARKER_CHARSET.length() - 1) { 74 | break; 75 | } 76 | 77 | char markerChar = MARKER_CHARSET.charAt(markerCharIndex); 78 | char secondJumpMarkerChar = MARKER_CHARSET.charAt((i - singleJumpCount) % MARKER_CHARSET.length()); 79 | 80 | String marker = "" + markerChar + secondJumpMarkerChar; 81 | _markerCollection.addMarker(marker, _offsets.get(i)); 82 | } 83 | 84 | 85 | boolean hasMarkersNeedMoreJumps = i < _offsets.size(); 86 | if (hasMarkersNeedMoreJumps) { 87 | for (; i < _offsets.size(); i++) { 88 | _markerCollection.addMarker(String.valueOf(INFINITE_JUMP_CHAR), _offsets.get(i)); 89 | } 90 | } 91 | } 92 | 93 | private int calcTwiceJumpGroupCount() { 94 | int makerCharSetSize = MARKER_CHARSET.length(); 95 | 96 | for (int groupsNeedMultipleJump = 0; groupsNeedMultipleJump <= makerCharSetSize; groupsNeedMultipleJump++) { 97 | int oneJumpMarkerCount = makerCharSetSize - groupsNeedMultipleJump; 98 | if (groupsNeedMultipleJump * makerCharSetSize + oneJumpMarkerCount >= _offsets.size()) { 99 | return groupsNeedMultipleJump; 100 | } 101 | } 102 | 103 | return makerCharSetSize; 104 | } 105 | 106 | private void sortOffsetsByDistanceToCaret(final int caretOffset) { 107 | Collections.sort(_offsets, new Comparator() { 108 | @Override 109 | public int compare(JOffset joA, JOffset joB) { 110 | if (joA.editor != joB.editor) { 111 | return joA.editor.hashCode() - joB.editor.hashCode(); 112 | } 113 | 114 | Integer oA = joA.offset; 115 | Integer oB = joB.offset; 116 | 117 | int distA = Math.abs(oA - caretOffset); 118 | int distB = Math.abs(oB - caretOffset); 119 | 120 | if (distA == distB) { 121 | return oA - oB; 122 | } 123 | 124 | return distA - distB; 125 | } 126 | }); 127 | } 128 | 129 | private void sortOffsetsToImprovePriorityOfLineEnd() { 130 | Collections.sort(_offsets, new Comparator() { 131 | @Override 132 | public int compare(JOffset joA, JOffset joB) { 133 | if (joA.editor != joB.editor) { 134 | return joA.editor.hashCode() - joB.editor.hashCode(); 135 | } 136 | 137 | Document document = joA.editor.getDocument(); 138 | boolean oAIsLineEndOffset = isLineEndOffset(joA.offset, document); 139 | boolean oBIsLineEndOffset = isLineEndOffset(joB.offset, document); 140 | 141 | if (!(oAIsLineEndOffset ^ oBIsLineEndOffset)) { 142 | return 0; 143 | } 144 | 145 | return oAIsLineEndOffset ? -1 : 1; 146 | } 147 | 148 | private boolean isLineEndOffset(Integer oA, Document document) { 149 | int lineA = document.getLineNumber(oA); 150 | int lineEndOffset = document.getLineEndOffset(lineA); 151 | return oA == lineEndOffset; 152 | } 153 | }); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/org/hunmr/buildin/JustOneSpace.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.buildin; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.application.ApplicationManager; 5 | import com.intellij.openapi.editor.EditorModificationUtil; 6 | import org.hunmr.common.EmacsIdeasAction; 7 | import org.hunmr.util.AppUtil; 8 | 9 | public class JustOneSpace extends EmacsIdeasAction { 10 | @Override 11 | public void actionPerformed(AnActionEvent e) { 12 | if (super.initAction(e)) { 13 | int offset = _editor.getCaretModel().getOffset(); 14 | JustOneSpaceAt(offset, _document.getText()); 15 | cleanupSetupsInAndBackToNormalEditingMode(); 16 | } 17 | } 18 | 19 | private void JustOneSpaceAt(int offset, String doc) { 20 | int begin = backwardToBeginOffset(offset, doc); 21 | int end = forwardToEndOffset(offset, doc, doc.length()); 22 | 23 | if (end > begin - 1) { 24 | makeOneSpaceBetween(begin, end); 25 | } 26 | } 27 | 28 | private void makeOneSpaceBetween(final int begin, final int end) { 29 | Runnable runnable = new Runnable() { 30 | @Override 31 | public void run() { 32 | _editor.getSelectionModel().setSelection(begin, end); 33 | EditorModificationUtil.deleteSelectedText(_editor); 34 | EditorModificationUtil.insertStringAtCaret(_editor, " "); 35 | } 36 | }; 37 | AppUtil.runWriteAction(runnable, _editor); 38 | } 39 | 40 | private int forwardToEndOffset(int end, String doc, int textLength) { 41 | while (end < textLength && Character.isWhitespace(doc.charAt(end))) { 42 | end++; 43 | } 44 | return end; 45 | } 46 | 47 | private int backwardToBeginOffset(int offset, String doc) { 48 | int begin = offset; 49 | boolean atLineBeginning = isAtLineBeginning(offset, doc); 50 | while (begin > 0 && Character.isWhitespace(doc.charAt(begin - 1)) && (atLineBeginning || doc.charAt(begin - 1) != '\n')) { 51 | begin--; 52 | } 53 | return begin; 54 | } 55 | 56 | private boolean isAtLineBeginning(int offset, String doc) { 57 | boolean isAtLineBeginning = false; 58 | int lineNumber = _document.getLineNumber(offset); 59 | int lineStartOffset = _document.getLineStartOffset(lineNumber); 60 | if (offset - lineStartOffset == 1 && !Character.isWhitespace(doc.charAt(offset))) { 61 | isAtLineBeginning = true; 62 | } 63 | return isAtLineBeginning; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/org/hunmr/common/ChainActionEvent.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.editor.Editor; 5 | import com.intellij.openapi.project.Project; 6 | 7 | public class ChainActionEvent extends AnActionEvent { 8 | private Runnable _pendingAction; 9 | private final Editor _editor; 10 | private final Project _project; 11 | 12 | public ChainActionEvent(AnActionEvent e, Runnable runnable, Editor _editor, Project _project) { 13 | super(e.getInputEvent(), e.getDataContext(), e.getPlace(), e.getPresentation(), e.getActionManager(), e.getModifiers()); 14 | this._pendingAction = runnable; 15 | this._editor = _editor; 16 | this._project = _project; 17 | } 18 | 19 | public Runnable getPendingAction() { 20 | return _pendingAction; 21 | } 22 | 23 | public Editor getEditor() { 24 | return _editor; 25 | } 26 | 27 | public Project getProject() { 28 | return _project; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/org/hunmr/common/CommandContext.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common; 2 | 3 | public class CommandContext { 4 | private int _spacePrefixCount; 5 | private char _lastCmdKey; 6 | 7 | public int getPrefixCount() { 8 | return _spacePrefixCount; 9 | } 10 | 11 | public boolean consume(char key) { 12 | if (key == ' ') { 13 | _spacePrefixCount++; 14 | return true; 15 | } 16 | 17 | _lastCmdKey = key; 18 | return false; 19 | } 20 | 21 | public char getLastCmdKey() { 22 | return _lastCmdKey; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/org/hunmr/common/Consts.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common; 2 | 3 | public class Consts { 4 | public static final boolean STOP_LISTEN_KEY = true; 5 | public static final boolean CONTINUE_LISTEN_KEY = false; 6 | } 7 | -------------------------------------------------------------------------------- /src/org/hunmr/common/EmacsIdeasAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.CommonDataKeys; 6 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 7 | import com.intellij.openapi.application.ApplicationManager; 8 | import com.intellij.openapi.editor.Document; 9 | import com.intellij.openapi.editor.Editor; 10 | import com.intellij.openapi.fileEditor.FileEditor; 11 | import com.intellij.openapi.fileEditor.TextEditor; 12 | import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; 13 | import com.intellij.openapi.project.Project; 14 | import org.hunmr.acejump.runnable.ShowMarkersRunnable; 15 | 16 | import javax.swing.*; 17 | import java.awt.event.KeyListener; 18 | import java.util.*; 19 | 20 | public abstract class EmacsIdeasAction extends AnAction { 21 | protected volatile boolean _isStillRunning = false; 22 | protected EmacsIdeasAction _action; 23 | protected Editor _editor; 24 | protected ArrayList _editors; 25 | protected JComponent _contentComponent; 26 | protected Document _document; 27 | protected KeyListener[] _keyListeners; 28 | protected AnActionEvent _event; 29 | protected Project _project; 30 | 31 | public void cleanupSetupsInAndBackToNormalEditingMode() { 32 | restoreOldKeyListeners(); 33 | _contentComponent.repaint(); 34 | _isStillRunning = false; 35 | } 36 | 37 | protected void restoreOldKeyListeners() { 38 | for (KeyListener kl : _keyListeners) { 39 | _contentComponent.addKeyListener(kl); 40 | } 41 | } 42 | 43 | public boolean initAction(AnActionEvent e) { 44 | if (getEditorFrom(e) == null) { 45 | return false; 46 | } 47 | 48 | switchEditorIfNeed(e); 49 | 50 | if (_isStillRunning) { 51 | cleanupSetupsInAndBackToNormalEditingMode(); 52 | } 53 | 54 | initMemberVariableForConvenientAccess(e); 55 | disableAllExistingKeyListeners(); 56 | 57 | return true; 58 | } 59 | 60 | private Editor getEditorFrom(AnActionEvent e) { 61 | if (e instanceof ChainActionEvent) { 62 | ChainActionEvent chainActionEvent = (ChainActionEvent) e; 63 | Editor editor = chainActionEvent.getEditor(); 64 | if (editor != null) { 65 | return editor; 66 | } 67 | } 68 | 69 | return e.getData(PlatformDataKeys.EDITOR); 70 | } 71 | 72 | public void switchEditorIfNeed(AnActionEvent e) { 73 | Editor newEditor = getEditorFrom(e); 74 | if (_editor != null && _editor != newEditor) { 75 | cleanupSetupsInAndBackToNormalEditingMode(); 76 | } 77 | 78 | _editor = newEditor; 79 | _editors = collect_active_editors(e); 80 | } 81 | 82 | private ArrayList collect_active_editors(AnActionEvent e) { 83 | ArrayList editors = new ArrayList(); 84 | 85 | final Project project = e.getData(CommonDataKeys.PROJECT); 86 | final FileEditorManagerEx fileEditorManager = FileEditorManagerEx.getInstanceEx(project); 87 | FileEditor[] selectedEditors = fileEditorManager.getSelectedEditors(); 88 | 89 | for (FileEditor selectedEditor : selectedEditors) { 90 | if (selectedEditor instanceof TextEditor) { 91 | Editor editor = ((TextEditor) selectedEditor).getEditor(); 92 | editors.add(editor); 93 | } 94 | } 95 | 96 | return editors; 97 | } 98 | 99 | protected void initMemberVariableForConvenientAccess(AnActionEvent e) { 100 | _event = e; 101 | _isStillRunning = true; 102 | _document = _editor.getDocument(); 103 | _action = this; 104 | _contentComponent = _editor.getContentComponent(); 105 | _project = getProjectFrom(e); 106 | } 107 | 108 | protected void disableAllExistingKeyListeners() { 109 | _keyListeners = _contentComponent.getKeyListeners(); 110 | for (KeyListener kl : _keyListeners) { 111 | _contentComponent.removeKeyListener(kl); 112 | } 113 | } 114 | 115 | public Editor getEditor() { 116 | return _editor; 117 | } 118 | 119 | public ArrayList getEditors() { 120 | return _editors; 121 | } 122 | 123 | protected void runReadAction(ShowMarkersRunnable action) { 124 | ApplicationManager.getApplication().runReadAction(action); 125 | } 126 | 127 | protected void handlePendingActionOnSuccess() { 128 | if (_event instanceof ChainActionEvent) { 129 | ChainActionEvent chainActionEvent = (ChainActionEvent) _event; 130 | chainActionEvent.getPendingAction().run(); 131 | } 132 | } 133 | 134 | protected Project getProjectFrom(AnActionEvent e) { 135 | if (e instanceof ChainActionEvent) { 136 | ChainActionEvent chainActionEvent = (ChainActionEvent) e; 137 | Project project = chainActionEvent.getProject(); 138 | if (project != null) { 139 | return project; 140 | } 141 | } 142 | 143 | return e.getData(PlatformDataKeys.PROJECT); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/org/hunmr/common/predictor/Predictor.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.predictor; 2 | 3 | public abstract class Predictor { 4 | abstract boolean is(T t); 5 | 6 | public boolean isNot(T t) { 7 | return !is(t); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/org/hunmr/common/predictor/SymbolPredictor.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.predictor; 2 | 3 | import org.hunmr.util.Chars; 4 | 5 | public class SymbolPredictor extends Predictor { 6 | 7 | @Override 8 | public boolean is(Character character) { 9 | return Chars.isSymbol(character); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/BlockSelector.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.util.TextRange; 5 | import org.hunmr.common.CommandContext; 6 | 7 | public class BlockSelector extends Selector { 8 | 9 | public static final int NOT_FOUND = -1; 10 | public static final String OPEN_BRACKETS = "{[("; 11 | public static final String CLOSE_BRACKETS = "}])"; 12 | 13 | public BlockSelector(Editor editor) { 14 | super(editor); 15 | } 16 | 17 | public TextRange getRange(CommandContext cmdCtx) { 18 | if (caretIsAtEdge()) { 19 | return null; 20 | } 21 | 22 | final int caretOffset = _editor.getCaretModel().getOffset(); 23 | 24 | int start = getOffsetOfOpenBracket(caretOffset); 25 | if (start == NOT_FOUND) { 26 | return null; 27 | } 28 | 29 | int end = getOffsetOfCloseBracket(caretOffset); 30 | if (end == NOT_FOUND) { 31 | return null; 32 | } 33 | 34 | if (cmdCtx.getLastCmdKey() == 'B') { 35 | start--; 36 | end++; 37 | } 38 | 39 | return end > start ? new TextRange(start, end) : null; 40 | } 41 | 42 | private int getOffsetOfOpenBracket(int caretOffset) { 43 | int i = 0; 44 | for (int offset = caretOffset; offset > 0; offset--) { 45 | i = i + getCharScore(_docText.charAt(offset - 1)); 46 | 47 | if (i > 0) { 48 | return offset; 49 | } 50 | } 51 | 52 | return NOT_FOUND; 53 | } 54 | 55 | private int getOffsetOfCloseBracket(int caretOffset) { 56 | int i = 0; 57 | int docEndOffset = _docText.length(); 58 | 59 | for (int offset = caretOffset; offset < docEndOffset; offset++) { 60 | i = i + getCharScore(_docText.charAt(offset)); 61 | 62 | if (i < 0) { 63 | return offset; 64 | } 65 | } 66 | 67 | return NOT_FOUND; 68 | } 69 | 70 | private int getCharScore(char c) { 71 | boolean isOpenBracketChar = OPEN_BRACKETS.indexOf(c) != -1; 72 | if (isOpenBracketChar) { 73 | return 1; 74 | } 75 | 76 | boolean isCloseBracketChar = CLOSE_BRACKETS.indexOf(c) != -1; 77 | if (isCloseBracketChar) { 78 | return -1; 79 | } 80 | 81 | return 0; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/GroupSelector.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.util.TextRange; 5 | import org.hunmr.common.CommandContext; 6 | 7 | import java.util.regex.Matcher; 8 | import java.util.regex.Pattern; 9 | 10 | public class GroupSelector extends BlockSelector { 11 | 12 | public GroupSelector(Editor editor) { 13 | super(editor); 14 | } 15 | 16 | public TextRange getRange(CommandContext cmdCtx) { 17 | TextRange r = super.getRange(cmdCtx); 18 | 19 | if (r != null) { 20 | int startLine = _document.getLineNumber(r.getStartOffset() - 1); 21 | int start = _document.getLineStartOffset(startLine); 22 | int end = _document.getLineEndOffset(_document.getLineNumber(r.getEndOffset() + 1)); 23 | 24 | if (end + 1 < _docText.length()) { 25 | end++; //extend to include the ending newline char 26 | } 27 | 28 | if (isBeginningOfBody(_document.getText(new TextRange(start, end)))) { 29 | //To include function-name line if { starts at newline. 30 | // void function-name 31 | // { 32 | // ... 33 | // } 34 | start = _document.getLineStartOffset(startLine - 1); 35 | } 36 | 37 | return new TextRange(start, end); 38 | } 39 | 40 | return r; 41 | } 42 | 43 | private boolean isBeginningOfBody(String text) { 44 | Pattern p = Pattern.compile("^\\s*\\{.*"); 45 | Matcher m = p.matcher(text); 46 | return m.find(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/LineSelector.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.util.TextRange; 5 | import org.hunmr.common.CommandContext; 6 | 7 | public class LineSelector extends Selector { 8 | public LineSelector(Editor editor) { 9 | super(editor); 10 | } 11 | 12 | public TextRange getRange(CommandContext cmdCtx) { 13 | int lineNumber = _document.getLineNumber(_editor.getCaretModel().getOffset()); 14 | int lineEnd = _document.getLineEndOffset(lineNumber); 15 | 16 | int lineStart = _document.getLineStartOffset(lineNumber); 17 | if (lineStart > 0) { 18 | lineStart--; 19 | } 20 | 21 | return lineEnd > lineStart ? new TextRange(lineStart, lineEnd) : null; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/ParagraphSelector.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.util.TextRange; 5 | import org.hunmr.common.CommandContext; 6 | 7 | public class ParagraphSelector extends Selector { 8 | public ParagraphSelector(Editor editor) { 9 | super(editor); 10 | } 11 | 12 | protected int getParagraphStartOffset(int caretOffset) { 13 | int offset = caretOffset; 14 | while (offset > 0) { 15 | if (offsetIsAtEmptyLine(offset - 1)) { 16 | break; 17 | } 18 | 19 | offset--; 20 | } 21 | 22 | //include the leading newline char 23 | if (offset > 0) { 24 | offset--; 25 | } 26 | 27 | return offset; 28 | } 29 | 30 | protected int getParagraphEndOffset(int caretOffset) { 31 | int offset = caretOffset; 32 | int length = _docText.length(); 33 | 34 | while (offset < length - 1) { 35 | if (charAt(offset) == '\n' && offsetIsAtEmptyLine(offset + 1)) { 36 | offset++; 37 | break; 38 | } 39 | 40 | offset++; 41 | } 42 | 43 | //offset = backWindToSkipEndingBracket(offset); 44 | return offset; 45 | } 46 | 47 | private boolean offsetIsAtEmptyLine(int offset) { 48 | int lineNumber = _document.getLineNumber(offset); 49 | int lineStartOffset = _document.getLineStartOffset(lineNumber); 50 | int lineEndOffset = _document.getLineEndOffset(lineNumber); 51 | 52 | String line = _document.getText(new TextRange(lineStartOffset, lineEndOffset)); 53 | 54 | return line.trim().isEmpty(); 55 | } 56 | 57 | public TextRange getRange(CommandContext cmdCtx) { 58 | final int caretOffset = getNearestStringEndOffset(_editor); 59 | 60 | int paraStart = getParagraphStartOffset(caretOffset); 61 | int paraEnd = getParagraphEndOffset(caretOffset); 62 | 63 | return paraEnd > paraStart ? new TextRange(paraStart, paraEnd) : null; 64 | } 65 | 66 | protected int backWindToSkipEndingBracket(final int paraEnd) { 67 | int end = paraEnd; 68 | String preSelectedText = _document.getText(new TextRange(_editor.getCaretModel().getOffset(), paraEnd)); 69 | String[] lines = preSelectedText.split("\n"); 70 | 71 | for (int i = lines.length-1; i >= 0; i--) { 72 | String line = lines[i]; 73 | if (!isBracketLine(line)) { 74 | break; 75 | } 76 | 77 | end -= line.length(); 78 | } 79 | 80 | if (end != paraEnd) { 81 | end--; 82 | } 83 | 84 | return end; 85 | } 86 | 87 | private boolean isBracketLine(String line) { 88 | for (char aChar : line.toCharArray()) { 89 | boolean isBracketOrSpace = aChar == '{' || aChar == '}' || Character.isSpaceChar(aChar); 90 | if (!isBracketOrSpace) { 91 | return false; 92 | } 93 | } 94 | 95 | return true; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/QuoteSelector.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.util.TextRange; 5 | import org.hunmr.common.CommandContext; 6 | 7 | public class QuoteSelector extends Selector{ 8 | public QuoteSelector(Editor editor) { 9 | super(editor); 10 | } 11 | 12 | @Override 13 | public TextRange getRange(CommandContext cmdCtx) { 14 | if (caretIsAtEdge()) { 15 | return null; 16 | } 17 | 18 | final String docText = normalizeDocumentText(); 19 | 20 | final int quoteCharIndex = backwardFindNearestQuoteCharOffset(docText); 21 | if (quoteCharIndex == -1) { 22 | return null; 23 | } 24 | 25 | final char quoteChar = _docText.charAt(quoteCharIndex); 26 | TextRange tr = findQuotedTextRange(docText, quoteChar); 27 | 28 | return tr != null ? tr : findQuotedTextRange(docText, nextQuoteChar(quoteChar)); 29 | } 30 | 31 | private char nextQuoteChar(char quoteChar) { 32 | return quoteChar == '\'' ? '"' : '\''; 33 | } 34 | 35 | private TextRange findQuotedTextRange(String docText, char quoteChar) { 36 | final int caretOffset = _editor.getCaretModel().getOffset(); 37 | final int startQuoteOffset = docText.lastIndexOf(quoteChar, caretOffset-1); 38 | if (startQuoteOffset == -1) { 39 | return null; 40 | } 41 | 42 | int start = startQuoteOffset + 1; 43 | int end = docText.indexOf(quoteChar, caretOffset); 44 | 45 | return end > start ? new TextRange(start, end) : null; 46 | } 47 | 48 | private int backwardFindNearestQuoteCharOffset(String docText) { 49 | int offset = _editor.getCaretModel().getOffset(); 50 | return Math.max(docText.lastIndexOf("'", offset-1), docText.lastIndexOf("\"", offset-1)); 51 | } 52 | 53 | private String normalizeDocumentText() { 54 | return _docText.replace("\\\\", "aa").replace("\\\"", "aa").replace("\\\'", "aa"); 55 | } 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/Selection.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.codeInsight.hint.HintManager; 4 | import com.intellij.openapi.editor.Editor; 5 | import com.intellij.openapi.util.TextRange; 6 | import org.hunmr.common.CommandContext; 7 | 8 | public class Selection { 9 | public static TextRange getTextRangeBy(Editor editor, CommandContext cmdCtx) { 10 | char key = cmdCtx.getLastCmdKey(); 11 | Selector selector = SelectorFactory.createSelectorBy(key, editor); 12 | 13 | if (selector == null) { 14 | HintManager.getInstance().showInformationHint(editor, SelectorFactory.HELP_MSG); 15 | return null; 16 | } 17 | 18 | TextRange tr = selector.getRange(cmdCtx); 19 | if (tr == null) { 20 | HintManager.getInstance().showInformationHint(editor, "404"); 21 | } 22 | 23 | return tr; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/Selector.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.openapi.editor.Document; 4 | import com.intellij.openapi.editor.Editor; 5 | import com.intellij.openapi.util.TextRange; 6 | import org.hunmr.common.CommandContext; 7 | 8 | public abstract class Selector { 9 | 10 | protected Editor _editor; 11 | protected final String _docText; 12 | protected final Document _document; 13 | 14 | public Selector(Editor editor) { 15 | _editor = editor; 16 | _document = _editor.getDocument(); 17 | _docText = _document.getText(); 18 | } 19 | 20 | public abstract TextRange getRange(CommandContext cmdCtx); 21 | 22 | protected boolean isCaretBetweenSpaces(Editor editor) { 23 | int caretOffset = editor.getCaretModel().getOffset(); 24 | int textLength = _docText.length(); 25 | 26 | return caretOffset - 1 > 0 27 | && caretOffset + 1 < textLength 28 | && Character.isWhitespace(charAt(caretOffset - 1)) 29 | && Character.isWhitespace(charAt(caretOffset + 1)); 30 | } 31 | 32 | protected int getNearestStringEndOffset(Editor editor) { 33 | int offset = editor.getCaretModel().getOffset(); 34 | 35 | if (isCaretBetweenSpaces(editor)) { 36 | while (offset > 0 && Character.isWhitespace(charAt(offset - 1))) { 37 | offset--; 38 | } 39 | } 40 | 41 | return offset; 42 | } 43 | 44 | protected char charAt(int index) { 45 | return _docText.charAt(index); 46 | } 47 | 48 | protected boolean caretIsAtEdge() { 49 | int offset = _editor.getCaretModel().getOffset(); 50 | return offset == 0 || offset == _docText.length(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/SelectorFactory.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | 5 | import java.awt.*; 6 | 7 | public class SelectorFactory { 8 | public static final String HELP_MSG = "C-c w : Copy word\n" + 9 | "C-c s : Copy String\n" + 10 | "C-c l : Copy Line\n" + 11 | "C-c q : Copy Quoted\n" + 12 | "C-c a : Copy Quoted\n" + 13 | "C-c p : Copy Paragraph\n" + 14 | "C-c g : Copy Group\n"; 15 | public static final Color HIGHLIGHT_COLOR = new Color(122, 214, 162); 16 | 17 | public static boolean isSelectorKey(char c) { 18 | return "wslpbqaeudg".indexOf(Character.toLowerCase(c)) != -1; 19 | } 20 | 21 | public static Selector createSelectorBy(char key, Editor editor) { 22 | Selector selector = null; 23 | 24 | switch (Character.toLowerCase(key)) { 25 | case 'w': 26 | selector = new WordSelector(editor); 27 | break; 28 | case 's': 29 | selector = new StringSelector(editor); 30 | break; 31 | case 'l': 32 | selector = new LineSelector(editor); 33 | break; 34 | case 'b': 35 | selector = new BlockSelector(editor); 36 | break; 37 | case 'q': 38 | selector = new QuoteSelector(editor); 39 | break; 40 | case 'a': 41 | selector = new ToLineStartSelector(editor); 42 | break; 43 | case 'e': 44 | selector = new ToLineEndSelector(editor); 45 | break; 46 | case 'p': 47 | selector = new ParagraphSelector(editor); 48 | break; 49 | case 'u': 50 | selector = new ToParagraphStartSelector(editor); 51 | break; 52 | case 'd': 53 | selector = new ToParagraphEndSelector(editor); 54 | break; 55 | case 'g': 56 | selector = new GroupSelector(editor); 57 | break; 58 | 59 | default: 60 | break; 61 | } 62 | return selector; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/StringSelector.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.util.TextRange; 5 | import org.hunmr.common.CommandContext; 6 | 7 | public class StringSelector extends Selector { 8 | public StringSelector(Editor editor) { 9 | super(editor); 10 | } 11 | 12 | private int getStringStartOffset(final int caretOffset) { 13 | int offset = caretOffset; 14 | while (offset > 0 && !Character.isWhitespace(charAt(offset - 1))) { 15 | offset--; 16 | } 17 | 18 | return offset; 19 | } 20 | 21 | private int getStringEndOffset(final int caretOffset) { 22 | int offset = caretOffset; 23 | while (offset < _docText.length() && !Character.isWhitespace(charAt(offset))) { 24 | offset++; 25 | } 26 | 27 | return offset; 28 | } 29 | 30 | public TextRange getRange(CommandContext cmdCtx) { 31 | final int caretOffset = getNearestStringEndOffset(_editor); 32 | 33 | int strStart = getStringStartOffset(caretOffset); 34 | int strEnd = getStringEndOffset(caretOffset); 35 | 36 | return strEnd > strStart ? new TextRange(strStart, strEnd) : null; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/ToLineEndSelector.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.util.TextRange; 5 | import org.hunmr.common.CommandContext; 6 | 7 | public class ToLineEndSelector extends Selector { 8 | public ToLineEndSelector(Editor editor) { 9 | super(editor); 10 | } 11 | 12 | @Override 13 | public TextRange getRange(CommandContext cmdCtx) { 14 | final int startOffset = _editor.getCaretModel().getOffset(); 15 | int endOffset; 16 | 17 | if (cmdCtx.getLastCmdKey() == 'E') { 18 | endOffset = _document.getTextLength(); 19 | } else { 20 | endOffset = _document.getLineEndOffset(_document.getLineNumber(startOffset)); 21 | } 22 | 23 | return endOffset > startOffset ? new TextRange(startOffset, endOffset) : null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/ToLineStartSelector.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.util.TextRange; 5 | import org.hunmr.common.CommandContext; 6 | 7 | public class ToLineStartSelector extends Selector { 8 | public ToLineStartSelector(Editor editor) { 9 | super(editor); 10 | } 11 | 12 | @Override 13 | public TextRange getRange(CommandContext cmdCtx) { 14 | int startOffset; 15 | int endOffset = _editor.getCaretModel().getOffset(); 16 | 17 | if (cmdCtx.getLastCmdKey() == 'A') { 18 | startOffset = 0; 19 | } else { 20 | startOffset = _document.getLineStartOffset(_document.getLineNumber(endOffset)); 21 | } 22 | 23 | return endOffset > startOffset ? new TextRange(startOffset, endOffset) : null; 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/ToParagraphEndSelector.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.util.TextRange; 5 | import org.hunmr.common.CommandContext; 6 | 7 | public class ToParagraphEndSelector extends ParagraphSelector { 8 | public ToParagraphEndSelector(Editor editor) { 9 | super(editor); 10 | } 11 | 12 | @Override 13 | public TextRange getRange(CommandContext cmdCtx) { 14 | final int caretOffset = getNearestStringEndOffset(_editor); 15 | 16 | int paraEnd = getParagraphEndOffset(caretOffset); 17 | return paraEnd > caretOffset ? new TextRange(caretOffset, paraEnd) : null; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/ToParagraphStartSelector.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.util.TextRange; 5 | import org.hunmr.common.CommandContext; 6 | 7 | public class ToParagraphStartSelector extends ParagraphSelector { 8 | public ToParagraphStartSelector(Editor editor) { 9 | super(editor); 10 | } 11 | 12 | @Override 13 | public TextRange getRange(CommandContext cmdCtx) { 14 | final int caretOffset = getNearestStringEndOffset(_editor); 15 | int paraStart = getParagraphStartOffset(caretOffset); 16 | return caretOffset > paraStart ? new TextRange(paraStart, caretOffset) : null; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/org/hunmr/common/selector/WordSelector.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.common.selector; 2 | 3 | import com.intellij.openapi.editor.Editor; 4 | import com.intellij.openapi.util.TextRange; 5 | import org.hunmr.common.CommandContext; 6 | 7 | public class WordSelector extends Selector { 8 | 9 | public WordSelector(Editor editor) { 10 | super(editor); 11 | } 12 | 13 | public TextRange getRange(CommandContext cmdCtx) { 14 | _editor.getSelectionModel().selectWordAtCaret(false); 15 | int wordStart = _editor.getSelectionModel().getSelectionStart(); 16 | int wordEnd = _editor.getSelectionModel().getSelectionEnd(); 17 | 18 | return wordEnd > wordStart ? new TextRange(wordStart, wordEnd) : null; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/org/hunmr/copycutwithoutselection/CopyAndReplaceAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.copycutwithoutselection; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.application.ApplicationManager; 5 | import com.intellij.openapi.editor.impl.EditorCopyPasteHelperImpl; 6 | import com.intellij.openapi.util.TextRange; 7 | import org.hunmr.acejump.AceJumpAction; 8 | import org.hunmr.common.ChainActionEvent; 9 | import org.hunmr.common.CommandContext; 10 | import org.hunmr.common.EmacsIdeasAction; 11 | import org.hunmr.common.selector.Selection; 12 | import org.hunmr.util.AppUtil; 13 | 14 | public class CopyAndReplaceAction extends EmacsIdeasAction { 15 | @Override 16 | public void actionPerformed(final AnActionEvent e) { 17 | if (super.initAction(e)) { 18 | final ChainActionEvent pendingJumpAction = new ChainActionEvent(e, createPendingJumpAction(e), _editor, _project); 19 | CopyCutWithoutSelectAction.getInstance().actionPerformed(pendingJumpAction); 20 | cleanupSetupsInAndBackToNormalEditingMode(); 21 | } 22 | } 23 | 24 | private Runnable createPendingJumpAction(final AnActionEvent e) { 25 | return new Runnable() { 26 | @Override 27 | public void run() { 28 | AceJumpAction.getInstance().actionPerformed(createPendingSelectAndPasteAction(e)); 29 | } 30 | }; 31 | } 32 | 33 | private ChainActionEvent createPendingSelectAndPasteAction(AnActionEvent e) { 34 | Runnable selectAndPaste = new Runnable() { 35 | @Override 36 | public void run() { 37 | Runnable runnable = new Runnable() { 38 | @Override 39 | public void run() { 40 | CommandContext cmdCtx = CopyCutWithoutSelectAction.getInstance().getCmdContext(); 41 | TextRange tr = Selection.getTextRangeBy(_editor, cmdCtx); 42 | if (tr != null) { 43 | _editor.getSelectionModel().setSelection(tr.getStartOffset(), tr.getEndOffset()); 44 | EditorCopyPasteHelperImpl.getInstance().pasteFromClipboard(_editor); 45 | } 46 | } 47 | }; 48 | 49 | AppUtil.runWriteAction(runnable, _editor); 50 | } 51 | }; 52 | 53 | return new ChainActionEvent(e, selectAndPaste, _editor, _project); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/org/hunmr/copycutwithoutselection/CopyCutWithoutSelectAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.copycutwithoutselection; 2 | 3 | import com.intellij.codeInsight.highlighting.HighlightManager; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.application.ApplicationManager; 6 | import com.intellij.openapi.editor.EditorModificationUtil; 7 | import com.intellij.openapi.editor.SelectionModel; 8 | import com.intellij.openapi.editor.markup.HighlighterLayer; 9 | import com.intellij.openapi.editor.markup.HighlighterTargetArea; 10 | import com.intellij.openapi.editor.markup.RangeHighlighter; 11 | import com.intellij.openapi.editor.markup.TextAttributes; 12 | import com.intellij.openapi.util.TextRange; 13 | import org.hunmr.common.CommandContext; 14 | import org.hunmr.common.EmacsIdeasAction; 15 | import org.hunmr.common.selector.Selection; 16 | import org.hunmr.common.selector.SelectorFactory; 17 | import org.hunmr.util.AppUtil; 18 | import org.hunmr.util.ThreadUtil; 19 | 20 | import java.awt.event.KeyEvent; 21 | import java.awt.event.KeyListener; 22 | 23 | public class CopyCutWithoutSelectAction extends EmacsIdeasAction { 24 | private static CopyCutWithoutSelectAction _instance; 25 | private KeyListener _handleCopyKeyListener; 26 | protected SelectionModel _selection; 27 | protected CommandContext _cmdCtx; 28 | 29 | public CopyCutWithoutSelectAction() { 30 | this._instance = this; 31 | } 32 | 33 | public void actionPerformed(AnActionEvent e) { 34 | if (super.initAction(e)) { 35 | _contentComponent.addKeyListener(_handleCopyKeyListener); 36 | } 37 | } 38 | 39 | @Override 40 | protected void initMemberVariableForConvenientAccess(AnActionEvent e) { 41 | super.initMemberVariableForConvenientAccess(e); 42 | _handleCopyKeyListener = createHandleCopyWithoutSelectionKeyListener(); 43 | _selection = _editor.getSelectionModel(); 44 | _cmdCtx = new CommandContext(); 45 | } 46 | 47 | private KeyListener createHandleCopyWithoutSelectionKeyListener() { 48 | return new KeyListener() { 49 | public void keyTyped(KeyEvent keyEvent) { 50 | keyEvent.consume(); 51 | boolean copyFinished = handleKey(keyEvent.getKeyChar()); 52 | if (copyFinished) { 53 | cleanupSetupsInAndBackToNormalEditingMode(); 54 | handlePendingActionOnSuccess(); 55 | } 56 | } 57 | 58 | public void keyPressed(KeyEvent keyEvent) { 59 | if (KeyEvent.VK_ESCAPE == keyEvent.getKeyChar()) { 60 | cleanupSetupsInAndBackToNormalEditingMode(); 61 | } 62 | } 63 | 64 | public void keyReleased(KeyEvent keyEvent) { 65 | } 66 | }; 67 | } 68 | 69 | protected boolean handleKey(char key) { 70 | if (_cmdCtx.consume(key)) { 71 | return false; 72 | } 73 | 74 | if (SelectorFactory.isSelectorKey(key)) { 75 | final TextRange tr = Selection.getTextRangeBy(_editor, _cmdCtx); 76 | if (tr != null) { 77 | _selection.setSelection(tr.getStartOffset(), tr.getEndOffset()); 78 | doActionOnSelectedRange(tr); 79 | } 80 | 81 | return true; 82 | } 83 | 84 | return true; 85 | } 86 | 87 | private void doActionOnSelectedRange(TextRange tr) { 88 | if (_cmdCtx.getPrefixCount() == 0) { 89 | copySelection(tr); 90 | } else if (_cmdCtx.getPrefixCount() == 1) { 91 | cutSelection(); 92 | } 93 | } 94 | 95 | private void cutSelection() { 96 | Runnable cutRunnable = new Runnable() { 97 | @Override 98 | public void run() { 99 | _editor.getSelectionModel().copySelectionToClipboard(); 100 | EditorModificationUtil.deleteSelectedText(_editor); 101 | } 102 | }; 103 | 104 | AppUtil.runWriteAction(cutRunnable, _editor); 105 | } 106 | 107 | private void copySelection(TextRange tr) { 108 | _selection.copySelectionToClipboard(); 109 | _selection.removeSelection(); 110 | 111 | final RangeHighlighter rh = addHighlighterOnCopiedRange(tr); 112 | ApplicationManager.getApplication().invokeLater(createClearHighlighterRunnable(rh)); 113 | } 114 | 115 | private Runnable createClearHighlighterRunnable(final RangeHighlighter rh) { 116 | return new Runnable() { 117 | @Override 118 | public void run() { 119 | ThreadUtil.sleep(200); 120 | _editor.getMarkupModel().removeHighlighter(rh); 121 | } 122 | }; 123 | } 124 | 125 | private RangeHighlighter addHighlighterOnCopiedRange(TextRange tr) { 126 | TextAttributes textAttributes = new TextAttributes(); 127 | textAttributes.setBackgroundColor(SelectorFactory.HIGHLIGHT_COLOR); 128 | return _editor.getMarkupModel().addRangeHighlighter(tr.getStartOffset(), tr.getEndOffset(), 129 | HighlighterLayer.LAST + 1, textAttributes, HighlighterTargetArea.EXACT_RANGE); 130 | } 131 | 132 | public void cleanupSetupsInAndBackToNormalEditingMode() { 133 | if (_handleCopyKeyListener != null) { 134 | _contentComponent.removeKeyListener(_handleCopyKeyListener); 135 | _handleCopyKeyListener = null; 136 | } 137 | 138 | super.cleanupSetupsInAndBackToNormalEditingMode(); 139 | } 140 | 141 | public static CopyCutWithoutSelectAction getInstance() { 142 | if (_instance == null) { 143 | _instance = new CopyCutWithoutSelectAction(); 144 | } 145 | return _instance; 146 | } 147 | 148 | public CommandContext getCmdContext() { 149 | return _instance._cmdCtx; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/org/hunmr/highlightsymbol/HighlightNextSymbolAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.highlightsymbol; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | 5 | public class HighlightNextSymbolAction extends HighlightSymbolAction { 6 | @Override 7 | public void actionPerformed(AnActionEvent e) { 8 | super.actionPerformed(e, true); 9 | } 10 | 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/org/hunmr/highlightsymbol/HighlightPrevSymbolAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.highlightsymbol; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | 5 | public class HighlightPrevSymbolAction extends HighlightSymbolAction{ 6 | @Override 7 | public void actionPerformed(AnActionEvent e) { 8 | super.actionPerformed(e, false); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/org/hunmr/highlightsymbol/HighlightSymbolAction.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.highlightsymbol; 2 | 3 | import com.intellij.find.FindManager; 4 | import com.intellij.find.FindModel; 5 | import com.intellij.find.FindResult; 6 | import com.intellij.openapi.actionSystem.AnActionEvent; 7 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 8 | import com.intellij.openapi.editor.ScrollType; 9 | import com.intellij.openapi.project.Project; 10 | import com.intellij.openapi.util.TextRange; 11 | import com.intellij.openapi.wm.ToolWindowManager; 12 | import org.hunmr.common.EmacsIdeasAction; 13 | 14 | public class HighlightSymbolAction extends EmacsIdeasAction { 15 | 16 | public void actionPerformed(AnActionEvent e, boolean searchForward) { 17 | Project project = e.getData(PlatformDataKeys.PROJECT); 18 | if (!ToolWindowManager.getInstance(project).isEditorComponentActive()) { 19 | ToolWindowManager.getInstance(project).activateEditorComponent(); 20 | return; 21 | } 22 | 23 | if (super.initAction(e)) { 24 | int nextSymbolOffset = getNextSymbolOffset(searchForward, project); 25 | if (-1 != nextSymbolOffset) { 26 | _editor.getCaretModel().moveToOffset(nextSymbolOffset); 27 | _editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); 28 | _editor.getSelectionModel().selectWordAtCaret(false); 29 | } 30 | } 31 | 32 | super.cleanupSetupsInAndBackToNormalEditingMode(); 33 | } 34 | 35 | private int getNextSymbolOffset(boolean searchForward, Project project) { 36 | _editor.getSelectionModel().selectWordAtCaret(false); 37 | 38 | int symbolStart = _editor.getSelectionModel().getSelectionStart(); 39 | int symbolEnd = _editor.getSelectionModel().getSelectionEnd(); 40 | 41 | if (symbolStart >= 0 && symbolEnd > symbolStart) { 42 | String symbol = _editor.getDocument().getText(new TextRange(symbolStart, symbolEnd)); 43 | 44 | FindManager findManager = FindManager.getInstance(project); 45 | FindModel findModel = (FindModel) findManager.getFindInFileModel().clone(); 46 | findModel.setFindAll(false); 47 | findModel.setFromCursor(true); 48 | findModel.setForward(searchForward); 49 | findModel.setRegularExpressions(false); 50 | findModel.setWholeWordsOnly(true); 51 | findModel.setCaseSensitive(true); 52 | findModel.setSearchHighlighters(false); 53 | findModel.setPreserveCase(false); 54 | 55 | findModel.setStringToFind(symbol); 56 | 57 | int startOffset = _editor.getCaretModel().getOffset(); 58 | if (searchForward) { 59 | startOffset++; 60 | } 61 | 62 | FindResult findResult = findManager.findString(_editor.getDocument().getText(), startOffset, findModel); 63 | 64 | //fix errors in Appcode, which is the findManager.findString return 0, when string not found. 65 | if (findResult.getStartOffset() == 0) { 66 | String potentialSymbol = _editor.getDocument().getText(new TextRange(0, symbol.length())); 67 | if (!potentialSymbol.equals(symbol)) { 68 | return -1; 69 | } 70 | } 71 | 72 | return findResult.getStartOffset(); 73 | } 74 | 75 | return -1; 76 | } 77 | 78 | @Override 79 | public void actionPerformed(AnActionEvent e) { 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/org/hunmr/options/IdeaConfigurable.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 |
119 | -------------------------------------------------------------------------------- /src/org/hunmr/options/IdeaConfigurable.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.options; 2 | 3 | import com.intellij.openapi.components.ServiceManager; 4 | import com.intellij.openapi.options.Configurable; 5 | import com.intellij.openapi.options.ConfigurationException; 6 | import com.intellij.ui.ColorPanel; 7 | import org.jetbrains.annotations.Nls; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import javax.swing.*; 11 | import java.awt.*; 12 | 13 | public class IdeaConfigurable implements Configurable { 14 | private JPanel _optionsPanel; 15 | private ColorPanel _firstJumpBackground; 16 | private ColorPanel _firstJumpForeground; 17 | private ColorPanel _secondJumpBackground; 18 | private ColorPanel _secondJumpForeground; 19 | private JCheckBox _needSelectTextAfterJump; 20 | 21 | final PluginConfig config = ServiceManager.getService(PluginConfig.class); 22 | 23 | @Nls 24 | @Override 25 | public String getDisplayName() { 26 | return "emacsIDEAs"; 27 | } 28 | 29 | @Nullable 30 | @Override 31 | public String getHelpTopic() { 32 | return "preferences.topic"; 33 | } 34 | 35 | private void setFromConfig() { 36 | _firstJumpBackground.setSelectedColor(config.getFirstJumpBackground()); 37 | _firstJumpForeground.setSelectedColor(config.getFirstJumpForeground()); 38 | _secondJumpBackground.setSelectedColor(config.getSecondJumpBackground()); 39 | _secondJumpForeground.setSelectedColor(config.getSecondJumpForeground()); 40 | _needSelectTextAfterJump.setSelected(config._needSelectTextAfterJump); 41 | } 42 | 43 | @Nullable 44 | @Override 45 | public JComponent createComponent() { 46 | setFromConfig(); 47 | return _optionsPanel; 48 | } 49 | 50 | @Override 51 | public boolean isModified() { 52 | return _firstJumpBackground.getSelectedColor() != config.getFirstJumpBackground() 53 | || _firstJumpForeground.getSelectedColor() != config.getFirstJumpForeground() 54 | || _secondJumpBackground.getSelectedColor() != config.getSecondJumpBackground() 55 | || _secondJumpForeground.getSelectedColor() != config.getSecondJumpForeground() 56 | || _needSelectTextAfterJump.isSelected() != config._needSelectTextAfterJump; 57 | } 58 | 59 | @Override 60 | public void apply() throws ConfigurationException { 61 | if (!isModified()) { 62 | return; 63 | } 64 | 65 | config._firstJumpBackground = _firstJumpBackground.getSelectedColor().getRGB(); 66 | config._firstJumpForeground = _firstJumpForeground.getSelectedColor().getRGB(); 67 | config._secondJumpBackground = _secondJumpBackground.getSelectedColor().getRGB(); 68 | config._secondJumpForeground = _secondJumpForeground.getSelectedColor().getRGB(); 69 | config._needSelectTextAfterJump = _needSelectTextAfterJump.isSelected(); 70 | } 71 | 72 | @Override 73 | public void reset() { 74 | setFromConfig(); 75 | } 76 | 77 | @Override 78 | public void disposeUIResources() { 79 | _optionsPanel.removeAll(); 80 | _optionsPanel.getParent().remove(_optionsPanel); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/org/hunmr/options/PluginConfig.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.options; 2 | 3 | import com.intellij.openapi.components.*; 4 | import com.intellij.openapi.project.Project; 5 | import com.intellij.util.xmlb.XmlSerializerUtil; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import java.awt.*; 9 | 10 | @State( 11 | name = "emacsIDEAsPluginConfig", 12 | storages = { 13 | @Storage( 14 | id = "other", 15 | file = "$APP_CONFIG$/emacsIDEAs_plugin.xml") 16 | } 17 | ) 18 | public class PluginConfig implements PersistentStateComponent { 19 | public int _firstJumpBackground = Color.blue.getRGB(); 20 | public int _firstJumpForeground = Color.white.getRGB(); 21 | public int _secondJumpBackground = Color.red.getRGB(); 22 | public int _secondJumpForeground = Color.white.getRGB(); 23 | public boolean _needSelectTextAfterJump = true; 24 | 25 | public Color getFirstJumpBackground() { 26 | return new Color(_firstJumpBackground); 27 | } 28 | 29 | public Color getFirstJumpForeground() { 30 | return new Color(_firstJumpForeground); 31 | } 32 | 33 | public Color getSecondJumpBackground() { 34 | return new Color(_secondJumpBackground); 35 | } 36 | 37 | public Color getSecondJumpForeground() { 38 | return new Color(_secondJumpForeground); 39 | } 40 | 41 | @Nullable 42 | @Override 43 | public PluginConfig getState() { 44 | return this; 45 | } 46 | 47 | @Override 48 | public void loadState(PluginConfig config) { 49 | XmlSerializerUtil.copyBean(config, this); 50 | } 51 | 52 | @Nullable 53 | public static PluginConfig getInstance(Project project) { 54 | return ServiceManager.getService(project, PluginConfig.class); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/org/hunmr/util/AppUtil.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.util; 2 | 3 | import com.intellij.codeInsight.hint.HintManager; 4 | import com.intellij.openapi.actionSystem.ActionGroup; 5 | import com.intellij.openapi.application.ApplicationManager; 6 | import com.intellij.openapi.command.CommandProcessor; 7 | import com.intellij.openapi.editor.Editor; 8 | 9 | public class AppUtil { 10 | private static Runnable getRunnableWrapper(final Runnable runnable, final Editor editor) { 11 | return new Runnable() { 12 | @Override 13 | public void run() { 14 | CommandProcessor.getInstance().executeCommand(editor.getProject(), runnable, "", ActionGroup.EMPTY_GROUP); 15 | } 16 | }; 17 | } 18 | 19 | public static void runWriteAction(final Runnable runnable, final Editor editor) { 20 | try { 21 | ApplicationManager.getApplication().runWriteAction(AppUtil.getRunnableWrapper(runnable, editor)); 22 | } catch (Exception e) { 23 | HintManager.getInstance().showInformationHint(editor, e.getMessage()); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/org/hunmr/util/Chars.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.util; 2 | 3 | public class Chars { 4 | 5 | public static boolean isSymbol(Character character) { 6 | return Chars.isSymbol(character); 7 | } 8 | 9 | public static boolean isSymbol(char c) { 10 | return c == '_' || Character.isLowerCase(c) || Character.isUpperCase(c) || Character.isDigit(c); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/org/hunmr/util/EditorUtils.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.util; 2 | 3 | import com.intellij.codeInsight.actions.ReformatCodeAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.editor.Document; 6 | import com.intellij.openapi.editor.Editor; 7 | import com.intellij.openapi.editor.EditorModificationUtil; 8 | import com.intellij.openapi.editor.LogicalPosition; 9 | import com.intellij.openapi.util.TextRange; 10 | import org.hunmr.common.CommandContext; 11 | import org.hunmr.common.selector.Selector; 12 | 13 | import java.awt.*; 14 | import java.awt.event.KeyEvent; 15 | import java.lang.reflect.InvocationTargetException; 16 | import java.util.ArrayList; 17 | 18 | public class EditorUtils { 19 | public static TextRange getVisibleTextRange(Editor editor) { 20 | Rectangle visibleArea = editor.getScrollingModel().getVisibleArea(); 21 | 22 | LogicalPosition startLogicalPosition = editor.xyToLogicalPosition(visibleArea.getLocation()); 23 | 24 | Double endVisualX = visibleArea.getX() + visibleArea.getWidth(); 25 | Double endVisualY = visibleArea.getY() + visibleArea.getHeight(); 26 | LogicalPosition endLogicalPosition = editor.xyToLogicalPosition(new Point(endVisualX.intValue(), endVisualY.intValue())); 27 | 28 | return new TextRange(editor.logicalPositionToOffset(startLogicalPosition), editor.logicalPositionToOffset(endLogicalPosition)); 29 | } 30 | 31 | 32 | public static boolean isPrintableChar( char c ) { 33 | Character.UnicodeBlock block = Character.UnicodeBlock.of( c ); 34 | return (!Character.isISOControl(c)) && 35 | c != KeyEvent.CHAR_UNDEFINED && 36 | block != null && 37 | block != Character.UnicodeBlock.SPECIALS; 38 | } 39 | 40 | public static ArrayList getVisibleLineStartOffsets(Editor editor) { 41 | Document document = editor.getDocument(); 42 | ArrayList offsets = new ArrayList(); 43 | 44 | TextRange visibleTextRange = getVisibleTextRange(editor); 45 | int startLine = document.getLineNumber(visibleTextRange.getStartOffset()); 46 | int endLine = document.getLineNumber(visibleTextRange.getEndOffset()); 47 | 48 | for (int i = startLine; i < endLine; i++) { 49 | offsets.add(document.getLineStartOffset(i)); 50 | } 51 | 52 | return offsets; 53 | } 54 | 55 | private static Selector getSelector(Class selectorClass, Editor editor) { 56 | try { 57 | return selectorClass.getDeclaredConstructor(Editor.class).newInstance(editor); 58 | } catch (InstantiationException e) { 59 | e.printStackTrace(); 60 | } catch (IllegalAccessException e) { 61 | e.printStackTrace(); 62 | } catch (NoSuchMethodException e) { 63 | e.printStackTrace(); 64 | } catch (InvocationTargetException e) { 65 | e.printStackTrace(); 66 | } 67 | return null; 68 | } 69 | 70 | public static TextRange getRangeOf(Class selectorClass, Editor editor) { 71 | Selector selector = getSelector(selectorClass, editor); 72 | return selector.getRange(new CommandContext()); 73 | } 74 | 75 | public static void selectRangeOf(Class selectorClass, Editor editor) { 76 | TextRange tr = getRangeOf(selectorClass, editor); 77 | if (tr != null) { 78 | editor.getSelectionModel().setSelection(tr.getStartOffset(), tr.getEndOffset()); 79 | } 80 | } 81 | 82 | public static void copyRange(Class selectorClass, Editor editor) { 83 | selectRangeOf(selectorClass, editor); 84 | editor.getSelectionModel().copySelectionToClipboard(); 85 | editor.getSelectionModel().removeSelection(); 86 | } 87 | 88 | public static void deleteRange(Class selectorClass, Editor editor) { 89 | selectRangeOf(selectorClass, editor); 90 | EditorModificationUtil.deleteSelectedText(editor); 91 | } 92 | 93 | public static void reformatCode(AnActionEvent e) { 94 | ReformatCodeAction reformat = new ReformatCodeAction(); 95 | reformat.actionPerformed(e); 96 | } 97 | 98 | public static void selectTextRange(Editor editor, TextRange[] tr) { 99 | if (editor != null && tr != null) { 100 | editor.getSelectionModel().setSelection(tr[0].getStartOffset(), tr[0].getEndOffset()); 101 | } 102 | } 103 | 104 | public static void selectTextRange(Editor editor, int startOffset, int endOffset) { 105 | if (editor != null) { 106 | editor.getSelectionModel().setSelection(startOffset, endOffset); 107 | } 108 | } 109 | 110 | public static void deleteRange(TextRange tr, Editor editor) { 111 | selectTextRange(editor, new TextRange[] {tr} ); 112 | EditorModificationUtil.deleteSelectedText(editor); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/org/hunmr/util/Str.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.util; 2 | 3 | public class Str { 4 | public static char getCounterCase(char c) { 5 | return Character.isUpperCase(c) ? Character.toLowerCase(c) : Character.toUpperCase(c); 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/org/hunmr/util/ThreadUtil.java: -------------------------------------------------------------------------------- 1 | package org.hunmr.util; 2 | 3 | public class ThreadUtil { 4 | public static void sleep(long milli) { 5 | try { 6 | Thread.sleep(milli); 7 | } catch (InterruptedException e) { 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tutorials/1_basic_word_jump.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whunmr/emacsIDEAs/cf49f068c9d92d3c5eac7c1c8dbc8f2520a37729/tutorials/1_basic_word_jump.gif -------------------------------------------------------------------------------- /tutorials/2_copy_without_selection.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whunmr/emacsIDEAs/cf49f068c9d92d3c5eac7c1c8dbc8f2520a37729/tutorials/2_copy_without_selection.gif -------------------------------------------------------------------------------- /tutorials/3_replace_target_range.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whunmr/emacsIDEAs/cf49f068c9d92d3c5eac7c1c8dbc8f2520a37729/tutorials/3_replace_target_range.gif -------------------------------------------------------------------------------- /tutorials/4_obtain_target_range.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whunmr/emacsIDEAs/cf49f068c9d92d3c5eac7c1c8dbc8f2520a37729/tutorials/4_obtain_target_range.gif -------------------------------------------------------------------------------- /tutorials/5_copy_target_range.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whunmr/emacsIDEAs/cf49f068c9d92d3c5eac7c1c8dbc8f2520a37729/tutorials/5_copy_target_range.gif -------------------------------------------------------------------------------- /tutorials/6_cut_target_range.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whunmr/emacsIDEAs/cf49f068c9d92d3c5eac7c1c8dbc8f2520a37729/tutorials/6_cut_target_range.gif -------------------------------------------------------------------------------- /tutorials/7_delete_target_range.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whunmr/emacsIDEAs/cf49f068c9d92d3c5eac7c1c8dbc8f2520a37729/tutorials/7_delete_target_range.gif --------------------------------------------------------------------------------