mirror of
				https://github.com/chylex/IntelliJ-AceJump.git
				synced 2025-11-04 09:40:10 +01:00 
			
		
		
		
	Compare commits
	
		
			100 Commits
		
	
	
		
			35003b0bab
			...
			pr-optimiz
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						04c1519261
	
				 | 
					
					
						|||
| 
						 | 
					efc81b8fde | ||
| 
						 | 
					974c5cf258 | ||
| 
						 | 
					ae458094cf | ||
| 
						 | 
					db62460d83 | ||
| 
						 | 
					09888c2c34 | ||
| 
						 | 
					1d1f469663 | ||
| 
						 | 
					21df680792 | ||
| 
						 | 
					1af49c2e91 | ||
| 
						 | 
					ec7a769ae7 | ||
| 
						 | 
					d6d162e4cc | ||
| 
						 | 
					9d478c5b6e | ||
| 
						 | 
					b66868664e | ||
| 
						 | 
					c68487c989 | ||
| 
						 | 
					ca2b0a8dbe | ||
| 
						 | 
					76bc72335b | ||
| 
						 | 
					fe4e180aeb | ||
| 
						 | 
					932c933969 | ||
| 
						 | 
					16f205b11b | ||
| 
						
						
							
						
						d0ead7d87a
	
				 | 
					
					
						|||
| 
						 | 
					c2e672f869 | ||
| 
						 | 
					1256ffc237 | ||
| 
						 | 
					29a71bdddc | ||
| 
						 | 
					9d2e7f7569 | ||
| 
						 | 
					751e6d890b | ||
| 
						 | 
					283c1a5644 | ||
| 
						 | 
					73a37df7e2 | ||
| 
						
						
							
						
						9921409aff
	
				 | 
					
					
						|||
| 
						 | 
					3039b5fbb3 | ||
| 
						
						
							
						
						cb3d4559f9
	
				 | 
					
					
						|||
| 
						 | 
					d905909e31 | ||
| 
						 | 
					64c6956b88 | ||
| 
						 | 
					b1a044dbf8 | ||
| 
						 | 
					e46cbe1d06 | ||
| 
						 | 
					f64e25a0a9 | ||
| 
						 | 
					eba043dfb2 | ||
| 
						 | 
					a746b0a516 | ||
| 
						 | 
					209b6c97b7 | ||
| 
						 | 
					3c89cd07b9 | ||
| 
						 | 
					2ffcc2c57a | ||
| 
						 | 
					56b1dfa9a9 | ||
| 
						 | 
					48cadfef4c | ||
| 
						 | 
					6d47331c71 | ||
| 
						 | 
					3339f6bdb8 | ||
| 
						 | 
					e7e85a6944 | ||
| 
						 | 
					1839efb59f | ||
| 
						 | 
					da913f61b6 | ||
| 
						 | 
					7dd12a0457 | ||
| 
						 | 
					dae7bd8fa4 | ||
| 
						 | 
					7d39ea2fef | ||
| 
						 | 
					64ad5039f2 | ||
| 
						 | 
					fb3bfa068e | ||
| 
						 | 
					c52f046a6f | ||
| 
						 | 
					ba739501e8 | ||
| 
						 | 
					e939479368 | ||
| 
						 | 
					1c604ce03c | ||
| 
						 | 
					099c852e32 | ||
| 
						 | 
					6642eff1e0 | ||
| 
						 | 
					73ba06b296 | ||
| 
						 | 
					9507496092 | ||
| 
						 | 
					99e0a50884 | ||
| 
						 | 
					c070b211e3 | ||
| 
						 | 
					6a2b5dd422 | ||
| 
						 | 
					b7024842ba | ||
| 
						 | 
					4831f38b34 | ||
| 
						 | 
					07014455e6 | ||
| 
						 | 
					ab6c6a702b | ||
| 
						 | 
					8b9e8bb89b | ||
| 
						 | 
					6c6544cf47 | ||
| 
						 | 
					7fe9d13f48 | ||
| 
						 | 
					f1f9ec5974 | ||
| 
						 | 
					5271d97c00 | ||
| 
						 | 
					872a99c84c | ||
| 
						 | 
					f8b2db5090 | ||
| 
						 | 
					5f0965c921 | ||
| 
						 | 
					5ee0245f0b | ||
| 
						 | 
					176d450855 | ||
| 
						 | 
					1341c6aff4 | ||
| 
						 | 
					0b0622dcdf | ||
| 
						 | 
					929b08e9d0 | ||
| 
						 | 
					54ea6ac9c1 | ||
| 
						 | 
					e477a487a2 | ||
| 
						 | 
					f56dc3d457 | ||
| 
						 | 
					0befd7895e | ||
| 
						 | 
					df94f4ce2a | ||
| 
						 | 
					978edff59e | ||
| 
						 | 
					f9938590fb | ||
| 
						 | 
					c534192902 | ||
| 
						 | 
					6deac53165 | ||
| 
						 | 
					2c4d4431bc | ||
| 
						 | 
					2185da7cb4 | ||
| 
						 | 
					c2a71a2c43 | ||
| 
						 | 
					d29dd3fa34 | ||
| 
						 | 
					fdbcea0b4f | ||
| 
						 | 
					c14ae702ba | ||
| 
						 | 
					8de4495885 | ||
| 
						 | 
					dd75e1ddea | ||
| 
						 | 
					02f9ecec5a | ||
| 
						
						
							
						
						f17f4ef8c4
	
				 | 
					
					
						|||
| 
						 | 
					c9034bced6 | 
							
								
								
									
										3
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +0,0 @@
 | 
				
			|||||||
# These are supported funding model platforms
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
github: breandan
 | 
					 | 
				
			||||||
							
								
								
									
										81
									
								
								CHANGES.md
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								CHANGES.md
									
									
									
									
									
								
							@@ -2,14 +2,79 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Unreleased
 | 
					## Unreleased
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.19
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Enable support for 2024.1, fixing ([#457](https://github.com/acejump/AceJump/issues/457))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.18
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Disable tagging and jumping to folded regions ([#453](https://github.com/acejump/AceJump/issues/453)), thanks to [@chylex](https://github.com/chylex)
 | 
				
			||||||
 | 
					- Update hint styling and show mode ([#394](https://github.com/acejump/AceJump/issues/394)) when "Show hint with search text" is enabled
 | 
				
			||||||
 | 
					- Fixes "Char sequence is empty" ([#404](https://github.com/acejump/AceJump/issues/404)) when "Map Unicode to ASCII" is enabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.17
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Add buttons to reset colors to default values in Settings, [#411](https://github.com/acejump/AceJump/issues/411), thanks to [@chylex](https://github.com/chylex)
 | 
				
			||||||
 | 
					- Unbundle conflicting Kotlin Standard Library version, [#449](https://github.com/acejump/AceJump/issues/449), thanks to [@chylex](https://github.com/chylex)
 | 
				
			||||||
 | 
					- Fix some instances of "Read access not allowed", [#447](https://github.com/acejump/AceJump/issues/447), thanks to [@h0tk3y](https://github.com/h0tk3y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fix issue with unselectable tags, [#446](https://github.com/acejump/AceJump/issues/446)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Forbid jumping to offscreen tags, [#442](https://github.com/acejump/AceJump/issues/442)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.14
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fixes NoSuchFieldError: Companion on older platform versions, [#432](https://github.com/acejump/AceJump/issues/432), [#434](https://github.com/acejump/AceJump/issues/434), [#435](https://github.com/acejump/AceJump/issues/432), [#437](https://github.com/acejump/AceJump/issues/437), [#438](https://github.com/acejump/AceJump/issues/438), thanks to [@wuruofan](https://github.com/wuruofan)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fixes color settings not being persisted, [#431](https://github.com/acejump/AceJump/issues/431)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fixes tag cycling issue with Enter/Shift+Enter, [#429](https://github.com/acejump/AceJump/issues/429)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fixes UI issue affecting mode cycling order, [#426](https://github.com/acejump/AceJump/issues/426)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fixes regression in 3.8.9 breaking cross-tab selection, [#417](https://github.com/acejump/AceJump/issues/417)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.9
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Add ids to editor action handlers, [#410](https://github.com/acejump/AceJump/pull/410), thanks to [@AlexPl292](https://github.com/AlexPl292)
 | 
				
			||||||
 | 
					- Update API to IJ-2022.3 and JDK to 17
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Add AZERTY keyboard layout, [#398](https://github.com/acejump/AceJump/pull/398), thanks to [@delphinaubin](https://github.com/delphinaubin)
 | 
				
			||||||
 | 
					- Add bounded toggle mode to start jump mode before or after the caret, [#401](https://github.com/acejump/AceJump/pull/401), thanks to [@colossatr0n](https://github.com/colossatr0n)
 | 
				
			||||||
 | 
					- Remove only the highlighters added by AceJump when jump session ends, [#407](https://github.com/acejump/AceJump/pull/407), thanks to [@huoguangjin](https://github.com/huoguangjin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fixes Unicode-ASCII regression, [#399](https://github.com/acejump/AceJump/issues/399)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.8.6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Adds AZERTY keyboard layout, [#398](https://github.com/acejump/AceJump/pull/398), thanks to [@delphinaubin](https://github.com/delphinaubin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 3.8.5
 | 
					## 3.8.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Improves tag order for non-QWERTY layouts, [#385](https://github.com/acejump/AceJump/issues/385)
 | 
				
			||||||
- Restores <kbd>Tab</kbd>/<kbd>Shift</kbd>+<kbd>Tab</kbd> functionality, [#356](https://github.com/acejump/AceJump/issues/356)
 | 
					- Restores <kbd>Tab</kbd>/<kbd>Shift</kbd>+<kbd>Tab</kbd> functionality, [#356](https://github.com/acejump/AceJump/issues/356)
 | 
				
			||||||
 | 
					- Fixes tag cycling with <kbd>Enter</kbd>/<kbd>Shift</kbd>+<kbd>Enter</kbd>, [#380](https://github.com/acejump/AceJump/issues/380), thanks [@AlexPl292](https://github.com/AlexPl292)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 3.8.4
 | 
					## 3.8.4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Fixes Declaration Mode in Rider, [#379](https://github.com/acejump/AceJump/issues/379), thanks to @igor-akhmetov for helping diagnose!
 | 
					- Fixes Declaration Mode in Rider, [#379](https://github.com/acejump/AceJump/issues/379), thanks to [@igor-akhmetov](https://github.com/igor-akhmetov) for helping diagnose!
 | 
				
			||||||
- Fixes highlight offset on high-DPI screens, [#362](https://github.com/acejump/AceJump/issues/362), thanks to @chylex for [the PR](https://github.com/acejump/AceJump/pull/384)!
 | 
					- Fixes highlight offset on high-DPI screens, [#362](https://github.com/acejump/AceJump/issues/362), thanks to [@chylex](https://github.com/chylex) for [the PR](https://github.com/acejump/AceJump/pull/384)!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 3.8.3
 | 
					## 3.8.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,7 +85,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- Add option to display current search text, [#375](https://github.com/acejump/AceJump/issues/375)
 | 
					- Add option to display current search text, [#375](https://github.com/acejump/AceJump/issues/375)
 | 
				
			||||||
- Fixes a bug where editor was not focused, [#374](https://github.com/acejump/AceJump/issues/374)
 | 
					- Fixes a bug where editor was not focused, [#374](https://github.com/acejump/AceJump/issues/374)
 | 
				
			||||||
- Thanks to @SaiKai for the PRs!
 | 
					- Thanks to [@SaiKai](https://github.com/SaiKai) for the PRs!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 3.8.1
 | 
					## 3.8.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -35,7 +100,7 @@
 | 
				
			|||||||
- Update AceJump extension API to include tag information, [#357](https://github.com/acejump/AceJump/pull/357)
 | 
					- Update AceJump extension API to include tag information, [#357](https://github.com/acejump/AceJump/pull/357)
 | 
				
			||||||
- Allow defining jump mode with boundaries, [#358](https://github.com/acejump/AceJump/pull/358)
 | 
					- Allow defining jump mode with boundaries, [#358](https://github.com/acejump/AceJump/pull/358)
 | 
				
			||||||
- Use Kotlin classes for actions, [#359](https://github.com/acejump/AceJump/pull/359)
 | 
					- Use Kotlin classes for actions, [#359](https://github.com/acejump/AceJump/pull/359)
 | 
				
			||||||
- Thanks to @AlexPl292 for the PRs!
 | 
					- Thanks to [@AlexPl292](https://github.com/AlexPl292) for the PRs!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 3.7.0
 | 
					## 3.7.0
 | 
				
			||||||
- Improvements to tag latency
 | 
					- Improvements to tag latency
 | 
				
			||||||
@@ -49,7 +114,7 @@
 | 
				
			|||||||
- Increase limit for what is considered a large file
 | 
					- Increase limit for what is considered a large file
 | 
				
			||||||
- Major refactoring, [#350](https://github.com/acejump/AceJump/pull/353)
 | 
					- Major refactoring, [#350](https://github.com/acejump/AceJump/pull/353)
 | 
				
			||||||
- [Many bug fixes](https://github.com/acejump/AceJump/issues/348#issuecomment-739454920): [#338](https://github.com/acejump/AceJump/issues/338), [#336](https://github.com/acejump/AceJump/issues/336), [#329](https://github.com/acejump/AceJump/issues/329), [#327](https://github.com/acejump/AceJump/issues/327), [#310](https://github.com/acejump/AceJump/issues/310), [#233](https://github.com/acejump/AceJump/issues/233), [#228](https://github.com/acejump/AceJump/issues/228), [#187](https://github.com/acejump/AceJump/issues/187), [#147](https://github.com/acejump/AceJump/issues/147), [#132](https://github.com/acejump/AceJump/issues/132), [#71](https://github.com/acejump/AceJump/issues/71)
 | 
					- [Many bug fixes](https://github.com/acejump/AceJump/issues/348#issuecomment-739454920): [#338](https://github.com/acejump/AceJump/issues/338), [#336](https://github.com/acejump/AceJump/issues/336), [#329](https://github.com/acejump/AceJump/issues/329), [#327](https://github.com/acejump/AceJump/issues/327), [#310](https://github.com/acejump/AceJump/issues/310), [#233](https://github.com/acejump/AceJump/issues/233), [#228](https://github.com/acejump/AceJump/issues/228), [#187](https://github.com/acejump/AceJump/issues/187), [#147](https://github.com/acejump/AceJump/issues/147), [#132](https://github.com/acejump/AceJump/issues/132), [#71](https://github.com/acejump/AceJump/issues/71)
 | 
				
			||||||
- Huge thanks to @chylex for [all the PRs](https://github.com/acejump/AceJump/pulls?q=is%3Apr+author%3Achylex)!
 | 
					- Huge thanks to [@chylex](https://github.com/chylex) for [all the PRs](https://github.com/acejump/AceJump/pulls?q=is%3Apr+author%3Achylex)!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 3.6.3
 | 
					## 3.6.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -59,12 +124,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## 3.6.2
 | 
					## 3.6.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Fixes [#226](https://github.com/acejump/AceJump/issues/226). Thanks @AlexPl292!
 | 
					- Fixes [#226](https://github.com/acejump/AceJump/issues/226). Thanks [@AlexPl292](https://github.com/AlexPl292)!
 | 
				
			||||||
- Update Pinyin engine.
 | 
					- Update Pinyin engine.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 3.6.1
 | 
					## 3.6.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Fixes [#324](https://github.com/acejump/AceJump/issues/324). Thanks @AlexPl292!
 | 
					- Fixes [#324](https://github.com/acejump/AceJump/issues/324). Thanks [@AlexPl292](https://github.com/AlexPl292)!
 | 
				
			||||||
- Fixes [#325](https://github.com/acejump/AceJump/issues/325).
 | 
					- Fixes [#325](https://github.com/acejump/AceJump/issues/325).
 | 
				
			||||||
- Fixes Pinyin support.
 | 
					- Fixes Pinyin support.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -72,7 +137,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- Adds support for Chinese [#314](https://github.com/acejump/AceJump/issues/314).
 | 
					- Adds support for Chinese [#314](https://github.com/acejump/AceJump/issues/314).
 | 
				
			||||||
- Fixes constantly loading settings page [#303](https://github.com/acejump/AceJump/issues/303).
 | 
					- Fixes constantly loading settings page [#303](https://github.com/acejump/AceJump/issues/303).
 | 
				
			||||||
- Honor camel humps [#315](https://github.com/acejump/AceJump/issues/315). Thanks to @clojj.
 | 
					- Honor camel humps [#315](https://github.com/acejump/AceJump/issues/315). Thanks to [@clojj](https://github.com/clojj).
 | 
				
			||||||
- Support dynamic application reloading [#322](https://github.com/acejump/AceJump/issues/322).
 | 
					- Support dynamic application reloading [#322](https://github.com/acejump/AceJump/issues/322).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 3.5.9
 | 
					## 3.5.9
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										62
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								README.md
									
									
									
									
									
								
							@@ -1,7 +1,7 @@
 | 
				
			|||||||
<p align="center"><a href="https://plugins.jetbrains.com/plugin/7086"> <img src="logo.png" alt="AceJumpLogo"></a></p>
 | 
					<p align="center"><a href="https://plugins.jetbrains.com/plugin/7086"> <img src="logo.png" alt="AceJumpLogo"></a></p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<p align="center">
 | 
					<p align="center">
 | 
				
			||||||
 	<a href="https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub" title="JetBrains on GitHub"><img src="http://jb.gg/badges/team.svg"></a>
 | 
					 	<a href="https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub" title="JetBrains on GitHub"><img src="https://jb.gg/badges/team.svg"></a>
 | 
				
			||||||
 	<a href="https://teamcity.jetbrains.com/viewType.html?buildTypeId=acejump_buildplugin&guest=1" title="Build Plugin"><img src="https://teamcity.jetbrains.com/app/rest/builds/buildType:acejump_buildplugin/statusIcon.svg"></a>
 | 
					 	<a href="https://teamcity.jetbrains.com/viewType.html?buildTypeId=acejump_buildplugin&guest=1" title="Build Plugin"><img src="https://teamcity.jetbrains.com/app/rest/builds/buildType:acejump_buildplugin/statusIcon.svg"></a>
 | 
				
			||||||
 	<a href="https://plugins.jetbrains.com/plugin/7086-acejump" title="Jetbrains Plugin"><img src="https://img.shields.io/jetbrains/plugin/v/7086-acejump.svg"></a>
 | 
					 	<a href="https://plugins.jetbrains.com/plugin/7086-acejump" title="Jetbrains Plugin"><img src="https://img.shields.io/jetbrains/plugin/v/7086-acejump.svg"></a>
 | 
				
			||||||
 	<a href="LICENSE" title="License"><img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg"></a>
 | 
					 	<a href="LICENSE" title="License"><img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg"></a>
 | 
				
			||||||
@@ -24,16 +24,18 @@ Press the AceJump shortcut, followed by <kbd>→</kbd> to target the last, <kbd>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||

 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AceJump search is [smart case](http://ideavim.sourceforge.net/vim/usr_27.html#vim.27%2E1) sensitive, however tag selection is *not* case sensitive. Holding down <kbd>Shift</kbd> when typing the last tag character will select all text from the current cursor position to that destination.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Tips
 | 
					## Tips
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Press <kbd>Tab</kbd> when searching to jump to the next group of matches in the editor. *This feature is unavailable in `3.6.4-3.8.4`.*
 | 
					- Press <kbd>Tab</kbd> when searching to jump to the next group of matches in the editor.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- If you make a mistake searching, just press <kbd>Backspace</kbd> to restart from scratch.
 | 
					- If you make a mistake searching, just press <kbd>Backspace</kbd> to restart from scratch.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- If no matches can be found on-screen, AceJump will scroll to the next match it can find.
 | 
					- If no matches can be found on-screen, AceJump will scroll to the next match it can find.
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 | 
					- Note that search is [smart case](http://ideavim.sourceforge.net/vim/usr_27.html#vim.27%2E1) sensitive, however tag selection is *not* case sensitive.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Holding down <kbd>Shift</kbd> when typing the last tag character will select all text from the current cursor position to that destination.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Pressing <kbd>Enter</kbd> or <kbd>Shift</kbd>+<kbd>Enter</kbd> during a search will cycle through tagged results on screen.
 | 
					- Pressing <kbd>Enter</kbd> or <kbd>Shift</kbd>+<kbd>Enter</kbd> during a search will cycle through tagged results on screen.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - To select a location and continue editing, just press <kbd>Esc</kbd>.
 | 
					  - To select a location and continue editing, just press <kbd>Esc</kbd>.
 | 
				
			||||||
@@ -54,8 +56,6 @@ AceJump search is [smart case](http://ideavim.sourceforge.net/vim/usr_27.html#vi
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
AceJump can be [installed directly from the IDE](https://www.jetbrains.com/help/idea/managing-plugins.html#install), via **Settings | Plugins | Browse Repositories... | 🔍 "AceJump"**.
 | 
					AceJump can be [installed directly from the IDE](https://www.jetbrains.com/help/idea/managing-plugins.html#install), via **Settings | Plugins | Browse Repositories... | 🔍 "AceJump"**.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[Canary builds](https://teamcity.jetbrains.com/repository/download/acejump_buildplugin/.lastSuccessful/AceJump.zip?guest=1) are provided courtesy of [TeamCity](https://www.jetbrains.com/teamcity/). These can be downloaded and [installed from disk](https://www.jetbrains.com/help/idea/managing-plugins.html#install_plugin_from_disk).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Configuring
 | 
					## Configuring
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[IdeaVim](https://plugins.jetbrains.com/plugin/164) users can choose to activate AceJump with a single keystroke (<kbd>f</kbd>, <kbd>F</kbd> and <kbd>g</kbd> are arbitrary) by running:
 | 
					[IdeaVim](https://plugins.jetbrains.com/plugin/164) users can choose to activate AceJump with a single keystroke (<kbd>f</kbd>, <kbd>F</kbd> and <kbd>g</kbd> are arbitrary) by running:
 | 
				
			||||||
@@ -64,15 +64,25 @@ AceJump can be [installed directly from the IDE](https://www.jetbrains.com/help/
 | 
				
			|||||||
echo -e '
 | 
					echo -e '
 | 
				
			||||||
 | 
					
 | 
				
			||||||
" Press `f` to activate AceJump
 | 
					" Press `f` to activate AceJump
 | 
				
			||||||
map f :action AceAction<CR>
 | 
					map f <Action>(AceAction)
 | 
				
			||||||
" Press `F` to activate Target Mode
 | 
					" Press `F` to activate Target Mode
 | 
				
			||||||
map F :action AceTargetAction<CR>
 | 
					map F <Action>(AceTargetAction)
 | 
				
			||||||
" Press `g` to activate Line Mode
 | 
					" Press `g` to activate Line Mode
 | 
				
			||||||
map g :action AceLineAction<CR>
 | 
					map g <Action>(AceLineAction)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
' >> ~/.ideavimrc
 | 
					' >> ~/.ideavimrc
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To customize AceJump's behavior further with additional actions, see the `<action>` tags in [plugin.xml](src/main/resources/META-INF/plugin.xml). The following example shows how to activate AceJump before or after the caret.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					" Press `S` in normal mode to activate AceJump mode before the caret
 | 
				
			||||||
 | 
					nmap S <Action>(AceBackwardAction)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					" Press `s` in normal mode to activate AceJump mode after the caret
 | 
				
			||||||
 | 
					nmap s <Action>(AceForwardAction)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To change the default keyboard shortcuts, open **File \| Settings \| Keymap \| 🔍 "AceJump" \| AceJump \|** <kbd>Enter⏎</kbd>.
 | 
					To change the default keyboard shortcuts, open **File \| Settings \| Keymap \| 🔍 "AceJump" \| AceJump \|** <kbd>Enter⏎</kbd>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||

 | 
					
 | 
				
			||||||
@@ -168,29 +178,38 @@ AceJump is inspired by prior work, but adds several improvements, including:
 | 
				
			|||||||
The following plugins have a similar UI for navigating text and web browsing:
 | 
					The following plugins have a similar UI for navigating text and web browsing:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Source Code                                                           |                                                        Download                                                        |                                                           Application                                                           | Actively Maintained |                                 Language                                 |
 | 
					| Source Code                                                           |                                                        Download                                                        |                                                           Application                                                           | Actively Maintained |                                 Language                                 |
 | 
				
			||||||
|:----------------------------------------------------------------------|:-------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------:|:-------------------:|:------------------------------------------------------------------------:|
 | 
					|:----------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------:|:-------------------:|:------------------------------------------------------------------------:|
 | 
				
			||||||
| AceJump                                                               |                                 [⬇](https://plugins.jetbrains.com/plugin/7086-acejump)                                 |                                           [IntelliJ Platform](https://jetbrains.com)                                            | :heavy_check_mark:  |                     [Kotlin](http://kotlinlang.org/)                     |
 | 
					| AceJump                                                               |                                 [⬇](https://plugins.jetbrains.com/plugin/7086-acejump)                                 |                                           [IntelliJ Platform](https://jetbrains.com)                                            | :heavy_check_mark:  |                     [Kotlin](http://kotlinlang.org/)                     |
 | 
				
			||||||
| [IdeaVim-EasyMotion](https://github.com/AlexPl292/IdeaVim-EasyMotion) |                                  [⬇](https://github.com/AlexPl292/IdeaVim-EasyMotion)                                  |                                           [IntelliJ Platform](https://jetbrains.com)                                            | :heavy_check_mark:  |                     [Kotlin](http://kotlinlang.org/)                     |
 | 
					| [IdeaVim-EasyMotion](https://github.com/AlexPl292/IdeaVim-EasyMotion) |                                  [⬇](https://github.com/AlexPl292/IdeaVim-EasyMotion)                                  |                                           [IntelliJ Platform](https://jetbrains.com)                                            | :heavy_check_mark:  |                     [Kotlin](http://kotlinlang.org/)                     |
 | 
				
			||||||
| [AceJump-Lite](https://github.com/EeeMt/AceJump-Lite)                 |                 [⬇](https://plugins.jetbrains.com/plugin/9803-acejump-lite)                 |                       [IntelliJ Platform](https://jetbrains.com)                       | :heavy_check_mark:  |                       [Java](https://www.java.com)                       |
 | 
					| [KJump](https://github.com/a690700752/KJump)                          |                                 [⬇](https://plugins.jetbrains.com/plugin/10149-kjump)                                  |                                           [IntelliJ Platform](https://jetbrains.com)                                            | :heavy_check_mark:  |                     [Kotlin](http://kotlinlang.org/)                     |
 | 
				
			||||||
| [KJump](https://github.com/a690700752/KJump)                          |                 [⬇](https://plugins.jetbrains.com/plugin/10149-kjump)                       |                       [IntelliJ Platform](https://jetbrains.com)                       | :heavy_check_mark:  |                       [Java](https://www.java.com)                       |
 | 
					| [AceJump-Lite](https://github.com/EeeMt/AceJump-Lite)                 |                              [⬇](https://plugins.jetbrains.com/plugin/9803-acejump-lite)                               |                                           [IntelliJ Platform](https://jetbrains.com)                                            |         :x:         |                       [Java](https://www.java.com)                       |
 | 
				
			||||||
| [emacsIDEAs](https://github.com/whunmr/emacsIDEAs)                    |                  [⬇](https://plugins.jetbrains.com/plugin/7163-emacsideas)                  |                       [IntelliJ Platform](https://jetbrains.com)                       | :heavy_check_mark:  |                       [Java](https://www.java.com)                       |
 | 
					| [emacsIDEAs](https://github.com/whunmr/emacsIDEAs)                    |                               [⬇](https://plugins.jetbrains.com/plugin/7163-emacsideas)                                |                                           [IntelliJ Platform](https://jetbrains.com)                                            |         :x:         |                       [Java](https://www.java.com)                       |
 | 
				
			||||||
| [TraceJump](https://github.com/acejump/tracejump)                     |                          [⬇](https://github.com/acejump/tracejump)                          |                                          Desktop                                       | :heavy_check_mark:  |                     [Kotlin](http://kotlinlang.org/)                     |
 | 
					| [TraceJump](https://github.com/acejump/tracejump)                     |                                       [⬇](https://github.com/acejump/tracejump)                                        |                                                             Desktop                                                             |         :x:         |                     [Kotlin](http://kotlinlang.org/)                     |
 | 
				
			||||||
| [ace-jump-mode](https://github.com/winterTTr/ace-jump-mode)           |                                         [⬇](https://melpa.org/#/ace-jump-mode)                                         |                                          [emacs](https://www.gnu.org/software/emacs/)                                           |         :x:         |    [Emacs Lisp](https://www.gnu.org/software/emacs/manual/eintr.html)    |
 | 
					| [ace-jump-mode](https://github.com/winterTTr/ace-jump-mode)           |                                         [⬇](https://melpa.org/#/ace-jump-mode)                                         |                                          [emacs](https://www.gnu.org/software/emacs/)                                           |         :x:         |    [Emacs Lisp](https://www.gnu.org/software/emacs/manual/eintr.html)    |
 | 
				
			||||||
| [avy](https://github.com/abo-abo/avy)                                 |                                              [⬇](https://melpa.org/#/avy)                                              |                                          [emacs](https://www.gnu.org/software/emacs/)                                           | :heavy_check_mark:  |    [Emacs Lisp](https://www.gnu.org/software/emacs/manual/eintr.html)    |
 | 
					| [avy](https://github.com/abo-abo/avy)                                 |                                              [⬇](https://melpa.org/#/avy)                                              |                                          [emacs](https://www.gnu.org/software/emacs/)                                           | :heavy_check_mark:  |    [Emacs Lisp](https://www.gnu.org/software/emacs/manual/eintr.html)    |
 | 
				
			||||||
| [EasyMotion](https://github.com/easymotion/vim-easymotion)            |                                     [⬇](https://vimawesome.com/plugin/easymotion)                                      |                                                   [Vim](http://www.vim.org/)                                                    |         :x:         |       [Vimscript](http://learnvimscriptthehardway.stevelosh.com/)        |
 | 
					| [EasyMotion](https://github.com/easymotion/vim-easymotion)            |                                     [⬇](https://vimawesome.com/plugin/easymotion)                                      |                                                   [Vim](http://www.vim.org/)                                                    |         :x:         |       [Vimscript](http://learnvimscriptthehardway.stevelosh.com/)        |
 | 
				
			||||||
 | 
					| [eyeliner.nvim](https://github.com/jinh0/eyeliner.nvim)               |                     [⬇](https://github.com/jinh0/eyeliner.nvim?tab=readme-ov-file#-installation)                       |                                                  [NeoVim](https://neovim.io/)                                                   | :heavy_check_mark:  |                       [Lua](https://www.lua.org/)                        |
 | 
				
			||||||
| [Hop](https://github.com/phaazon/hop.nvim)                            |                                 [⬇](https://github.com/phaazon/hop.nvim#installation)                                  |                                                  [NeoVim](https://neovim.io/)                                                   | :heavy_check_mark:  |                       [Lua](https://www.lua.org/)                        |
 | 
					| [Hop](https://github.com/phaazon/hop.nvim)                            |                                 [⬇](https://github.com/phaazon/hop.nvim#installation)                                  |                                                  [NeoVim](https://neovim.io/)                                                   | :heavy_check_mark:  |                       [Lua](https://www.lua.org/)                        |
 | 
				
			||||||
 | 
					| [leap.nvim](https://github.com/ggandor/leap.nvim)                     |                                 [⬇](https://github.com/ggandor/leap.nvim#installation)                                 |                                                  [NeoVim](https://neovim.io/)                                                   | :heavy_check_mark:  |                    [Fennel](https://fennel-lang.org)                     |
 | 
				
			||||||
 | 
					| [lightspeed.nvim](https://github.com/ggandor/lightspeed.nvim)         |                              [⬇](https://github.com/ggandor/lightspeed.nvim#installation)                              |                                                  [NeoVim](https://neovim.io/)                                                   |         :x:         |                    [Fennel](https://fennel-lang.org)                     |
 | 
				
			||||||
| [Sublime EasyMotion](https://github.com/tednaleid/sublime-EasyMotion) |                                   [⬇](https://packagecontrol.io/packages/EasyMotion)                                   |                                             [Sublime](https://www.sublimetext.com/)                                             |         :x:         |                    [Python](https://www.python.org/)                     |
 | 
					| [Sublime EasyMotion](https://github.com/tednaleid/sublime-EasyMotion) |                                   [⬇](https://packagecontrol.io/packages/EasyMotion)                                   |                                             [Sublime](https://www.sublimetext.com/)                                             |         :x:         |                    [Python](https://www.python.org/)                     |
 | 
				
			||||||
| [AceJump](https://github.com/ice9js/ace-jump-sublime)                 |                       [⬇](https://packagecontrol.io/packages/AceJump)                       |                        [Sublime](https://www.sublimetext.com/)                         | :heavy_check_mark:  |                    [Python](https://www.python.org/)                     |
 | 
					| [AceJump](https://github.com/ice9js/ace-jump-sublime)                 |                                    [⬇](https://packagecontrol.io/packages/AceJump)                                     |                                             [Sublime](https://www.sublimetext.com/)                                             |         :x:         |                    [Python](https://www.python.org/)                     |
 | 
				
			||||||
| [Jumpy](https://github.com/DavidLGoldberg/jumpy)                      |                             [⬇](https://atom.io/packages/jumpy)                             |                                [Atom](https://atom.io/)                                | :heavy_check_mark:  |                 [CoffeeScript](http://coffeescript.org/)                 |
 | 
					| [Jumpy](https://github.com/DavidLGoldberg/jumpy)                      |                                          [⬇](https://atom.io/packages/jumpy)                                           |                                                    [Atom](https://atom.io/)                                                     | :heavy_check_mark:  |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
				
			||||||
 | 
					| [Jumpy2](https://github.com/DavidLGoldberg/jumpy2)                    |                     [⬇](https://marketplace.visualstudio.com/items?itemName=DavidLGoldberg.jumpy2)                     |                                      [Visual Studio Code](https://code.visualstudio.com/)                                       | :heavy_check_mark:  |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
				
			||||||
| [Find-Jump](https://github.com/msafi/xvsc/tree/master/findJump)       |                       [⬇](https://marketplace.visualstudio.com/items?itemName=mksafi.find-jump)                        |                                      [Visual Studio Code](https://code.visualstudio.com/)                                       |         :x:         |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
					| [Find-Jump](https://github.com/msafi/xvsc/tree/master/findJump)       |                       [⬇](https://marketplace.visualstudio.com/items?itemName=mksafi.find-jump)                        |                                      [Visual Studio Code](https://code.visualstudio.com/)                                       |         :x:         |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
				
			||||||
| [MetaGo](https://github.com/metaseed/metaGo)                          |                        [⬇](https://marketplace.visualstudio.com/items?itemName=metaseed.metago)                        |                                      [Visual Studio Code](https://code.visualstudio.com/)                                       | :heavy_check_mark:  |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
					| [MetaGo](https://github.com/metaseed/metaGo)                          |                        [⬇](https://marketplace.visualstudio.com/items?itemName=metaseed.metago)                        |                                      [Visual Studio Code](https://code.visualstudio.com/)                                       | :heavy_check_mark:  |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
				
			||||||
| [VSCodeVim](https://github.com/VSCodeVim/Vim)                         |                         [⬇](https://marketplace.visualstudio.com/items?itemName=vscodevim.vim)                         |                                      [Visual Studio Code](https://code.visualstudio.com/)                                       | :heavy_check_mark:  |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
					| [VSCodeVim](https://github.com/VSCodeVim/Vim)                         |                         [⬇](https://marketplace.visualstudio.com/items?itemName=vscodevim.vim)                         |                                      [Visual Studio Code](https://code.visualstudio.com/)                                       | :heavy_check_mark:  |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
				
			||||||
| [CodeAceJumper](https://github.com/lucax88x/CodeAceJumper)            |       [⬇](https://marketplace.visualstudio.com/items?itemName=lucax88x.codeacejumper)       |                  [Visual Studio Code](https://code.visualstudio.com/)                  | :heavy_check_mark:  |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
					| [CodeAceJumper](https://github.com/lucax88x/CodeAceJumper)            |                    [⬇](https://marketplace.visualstudio.com/items?itemName=lucax88x.codeacejumper)                     |                                      [Visual Studio Code](https://code.visualstudio.com/)                                       |         :x:         |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
				
			||||||
| [AceJump](https://github.com/jsturtevant/ace-jump)                    |                      [⬇](https://marketplace.visualstudio.com/items?itemName=jsturtevant.AceJump)                      |                                         [Visual Studio](https://www.visualstudio.com/)                                          |         :x:         | [C#](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/) |
 | 
					| [AceJump](https://github.com/jsturtevant/ace-jump)                    |                      [⬇](https://marketplace.visualstudio.com/items?itemName=jsturtevant.AceJump)                      |                                         [Visual Studio](https://www.visualstudio.com/)                                          |         :x:         | [C#](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/) |
 | 
				
			||||||
| [EasyMotion](https://github.com/jaredpar/EasyMotion)                  |                    [⬇](https://marketplace.visualstudio.com/items?itemName=JaredParMSFT.EasyMotion)                    |                                         [Visual Studio](https://www.visualstudio.com/)                                          |         :x:         | [C#](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/) |
 | 
					| [EasyMotion](https://github.com/jaredpar/EasyMotion)                  |                    [⬇](https://marketplace.visualstudio.com/items?itemName=JaredParMSFT.EasyMotion)                    |                                         [Visual Studio](https://www.visualstudio.com/)                                          |         :x:         | [C#](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/) |
 | 
				
			||||||
| [cVim](https://github.com/1995eaton/chromium-vim)                     |    [⬇](https://chrome.google.com/webstore/detail/cvim/ihlenndgcmojhcghmfjfneahoeklbjjh)     |                        [Chrome](https://www.google.com/chrome)                         | :heavy_check_mark:  |                [JavaScript](https://www.javascript.com/)                 |
 | 
					| [tmux-fingers](https://github.com/Morantron/tmux-fingers)             |                        [⬇](https://github.com/Morantron/tmux-fingers#using-tmux-plugin-manager)                        |                                              [tmux](https://github.com/tmux/tmux)                                               | :heavy_check_mark:  |                  [Crystal](https://crystal-lang.org/)                    |
 | 
				
			||||||
| [SurfingKeys](https://github.com/brookhong/Surfingkeys)               | [⬇](https://chrome.google.com/webstore/detail/surfingkeys/gfbliohnnapiefjpjlpjnehglfpaknnc) |  [Chrome](https://www.google.com/chrome) / [Firefox](https://www.mozilla.org/firefox)  | :heavy_check_mark:  |                [JavaScript](https://www.javascript.com/)                 |
 | 
					| [tmux-thumb](https://github.com/Morantron/tmux-fingers)               |                        [⬇](https://github.com/fcsonline/tmux-thumbs#using-tmux-plugin-manager)                         |                                              [tmux](https://github.com/tmux/tmux)                                               | :heavy_check_mark:  |                    [Rust](https://www.rust-lang.org/)                    |
 | 
				
			||||||
| [Vimium](https://github.com/philc/vimium)                             |   [⬇](https://chrome.google.com/webstore/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb)    |                        [Chrome](https://www.google.com/chrome)                         | :heavy_check_mark:  |                 [CoffeeScript](http://coffeescript.org/)                 |
 | 
					| [tmux-jump](https://github.com/schasse/tmux-jump)                     |                             [⬇](https://github.com/schasse/tmux-jump#installation-via-tpm)                             |                                              [tmux](https://github.com/tmux/tmux)                                               | :heavy_check_mark:  |                    [Ruby](https://www.ruby-lang.org)                     |
 | 
				
			||||||
 | 
					| [tmux-copycat](https://github.com/tmux-plugins/tmux-copycat)          | [⬇](https://github.com/tmux-plugins/tmux-copycat?tab=readme-ov-file#installation-with-tmux-plugin-manager-recommended) |                                              [tmux](https://github.com/tmux/tmux)                                               |         :x:         |                   [Shell](https://www.shellscript.sh/)                   |
 | 
				
			||||||
 | 
					| [cVim](https://github.com/1995eaton/chromium-vim)                     |                  [⬇](https://chrome.google.com/webstore/detail/cvim/ihlenndgcmojhcghmfjfneahoeklbjjh)                  |                                             [Chrome](https://www.google.com/chrome)                                             |         :x:         |                [JavaScript](https://www.javascript.com/)                 |
 | 
				
			||||||
 | 
					| [SurfingKeys](https://github.com/brookhong/Surfingkeys)               |              [⬇](https://chrome.google.com/webstore/detail/surfingkeys/gfbliohnnapiefjpjlpjnehglfpaknnc)               | [Chrome](https://www.google.com/chrome)/[Firefox](https://www.mozilla.org/firefox)/[Edge](https://microsoftedge.microsoft.com/) | :heavy_check_mark:  |                [JavaScript](https://www.javascript.com/)                 |
 | 
				
			||||||
 | 
					| [Vimium](https://github.com/philc/vimium)                             |                 [⬇](https://chrome.google.com/webstore/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb)                 | [Chrome](https://www.google.com/chrome)/[Firefox](https://www.mozilla.org/firefox)/[Edge](https://microsoftedge.microsoft.com/) | :heavy_check_mark:  |                [JavaScript](https://www.javascript.com/)                 |
 | 
				
			||||||
 | 
					| [Vimium-C](https://github.com/gdh1995/vimium-c)                       |    [⬇](https://microsoftedge.microsoft.com/addons/detail/vimium-c-all-by-keyboar/aibcglbfblnogfjhbcmmpobjhnomhcdo)     | [Chrome](https://www.google.com/chrome)/[Firefox](https://www.mozilla.org/firefox)/[Edge](https://microsoftedge.microsoft.com/) | :heavy_check_mark:  |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
				
			||||||
| [Vrome](https://github.com/jinzhu/vrome)                              |                 [⬇](https://chrome.google.com/webstore/detail/vrome/godjoomfiimiddapohpmfklhgmbfffjj)                  |                                             [Chrome](https://www.google.com/chrome)                                             |         :x:         |                 [CoffeeScript](http://coffeescript.org/)                 |
 | 
					| [Vrome](https://github.com/jinzhu/vrome)                              |                 [⬇](https://chrome.google.com/webstore/detail/vrome/godjoomfiimiddapohpmfklhgmbfffjj)                  |                                             [Chrome](https://www.google.com/chrome)                                             |         :x:         |                 [CoffeeScript](http://coffeescript.org/)                 |
 | 
				
			||||||
| [ViChrome](https://github.com/k2nr/ViChrome)                          |                [⬇](https://chrome.google.com/webstore/detail/vichrome/gghkfhpblkcmlkmpcpgaajbbiikbhpdi)                |                                             [Chrome](https://www.google.com/chrome)                                             |         :x:         |                 [CoffeeScript](http://coffeescript.org/)                 |
 | 
					| [ViChrome](https://github.com/k2nr/ViChrome)                          |                [⬇](https://chrome.google.com/webstore/detail/vichrome/gghkfhpblkcmlkmpcpgaajbbiikbhpdi)                |                                             [Chrome](https://www.google.com/chrome)                                             |         :x:         |                 [CoffeeScript](http://coffeescript.org/)                 |
 | 
				
			||||||
| [VimFx](https://github.com/akhodakivskiy/VimFx)                       |                                  [⬇](https://github.com/akhodakivskiy/VimFx/releases)                                  |                                           [Firefox](https://www.mozilla.org/firefox)                                            | :heavy_check_mark:  |                 [CoffeeScript](http://coffeescript.org/)                 |
 | 
					| [VimFx](https://github.com/akhodakivskiy/VimFx)                       |                                  [⬇](https://github.com/akhodakivskiy/VimFx/releases)                                  |                                           [Firefox](https://www.mozilla.org/firefox)                                            | :heavy_check_mark:  |                 [CoffeeScript](http://coffeescript.org/)                 |
 | 
				
			||||||
@@ -198,7 +217,8 @@ The following plugins have a similar UI for navigating text and web browsing:
 | 
				
			|||||||
| [Pentadactyl](https://github.com/5digits/dactyl)                      |                                 [⬇](http://bug.5digits.org/pentadactyl/#sect-download)                                 |                                           [Firefox](https://www.mozilla.org/firefox)                                            |         :x:         |                [JavaScript](https://www.javascript.com/)                 |
 | 
					| [Pentadactyl](https://github.com/5digits/dactyl)                      |                                 [⬇](http://bug.5digits.org/pentadactyl/#sect-download)                                 |                                           [Firefox](https://www.mozilla.org/firefox)                                            |         :x:         |                [JavaScript](https://www.javascript.com/)                 |
 | 
				
			||||||
| [Vim Vixen](https://github.com/ueokande/vim-vixen)                    |                                [⬇](https://addons.mozilla.org/firefox/addon/vim-vixen/)                                |                     [Firefox 57+](https://blog.mozilla.org/addons/2017/09/28/webextensions-in-firefox-57/)                      | :heavy_check_mark:  |                [JavaScript](https://www.javascript.com/)                 |
 | 
					| [Vim Vixen](https://github.com/ueokande/vim-vixen)                    |                                [⬇](https://addons.mozilla.org/firefox/addon/vim-vixen/)                                |                     [Firefox 57+](https://blog.mozilla.org/addons/2017/09/28/webextensions-in-firefox-57/)                      | :heavy_check_mark:  |                [JavaScript](https://www.javascript.com/)                 |
 | 
				
			||||||
| [Tridactyl](https://github.com/tridactyl/tridactyl)                   |                              [⬇](https://addons.mozilla.org/firefox/addon/tridactyl-vim/)                              |                     [Firefox 57+](https://blog.mozilla.org/addons/2017/09/28/webextensions-in-firefox-57/)                      | :heavy_check_mark:  |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
					| [Tridactyl](https://github.com/tridactyl/tridactyl)                   |                              [⬇](https://addons.mozilla.org/firefox/addon/tridactyl-vim/)                              |                     [Firefox 57+](https://blog.mozilla.org/addons/2017/09/28/webextensions-in-firefox-57/)                      | :heavy_check_mark:  |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
				
			||||||
| [Vimari](https://github.com/guyht/vimari)                             |                        [⬇](https://github.com/guyht/vimari/releases)                        |                        [Safari](https://www.apple.com/safari/)                         | :heavy_check_mark:  |                [JavaScript](https://www.javascript.com/)                 |
 | 
					| [Vimari](https://github.com/guyht/vimari)                             |                                     [⬇](https://github.com/guyht/vimari/releases)                                      |                                             [Safari](https://www.apple.com/safari/)                                             |         :x:         |                [JavaScript](https://www.javascript.com/)                 |
 | 
				
			||||||
 | 
					| [Jump To Link](https://github.com/mrjackphil/obsidian-jump-to-link)   |                                  [⬇](https://obsidian.md/plugins?id=mrj-jump-to-link)                                  |                                                [Obsidian](https://obsidian.md/)                                                 | :heavy_check_mark:  |              [TypeScript](https://www.typescriptlang.org/)               |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Acknowledgements
 | 
					## Acknowledgements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										103
									
								
								build.gradle.kts
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								build.gradle.kts
									
									
									
									
									
								
							@@ -1,73 +1,100 @@
 | 
				
			|||||||
import org.jetbrains.changelog.*
 | 
					import org.jetbrains.changelog.Changelog.OutputType.HTML
 | 
				
			||||||
import org.jetbrains.intellij.tasks.*
 | 
					import org.jetbrains.changelog.date
 | 
				
			||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 | 
					import org.jetbrains.intellij.platform.gradle.TestFrameworkType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
  idea apply true
 | 
					  idea
 | 
				
			||||||
  kotlin("jvm") version "1.6.0-RC2"
 | 
					  alias(libs.plugins.kotlin) // Kotlin support
 | 
				
			||||||
  id("org.jetbrains.intellij") version "1.2.1"
 | 
					  alias(libs.plugins.intelliJPlatform) // IntelliJ Platform Gradle Plugin
 | 
				
			||||||
  id("org.jetbrains.changelog") version "1.3.1"
 | 
					  alias(libs.plugins.changelog) // Gradle Changelog Plugin
 | 
				
			||||||
  id("com.github.ben-manes.versions") version "0.39.0"
 | 
					  alias(libs.plugins.kover) // Gradle Kover Plugin
 | 
				
			||||||
 | 
					  id("com.github.ben-manes.versions") version "0.51.0"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tasks {
 | 
					tasks {
 | 
				
			||||||
  withType<KotlinCompile> {
 | 
					 | 
				
			||||||
    kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString()
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  named<Zip>("buildPlugin") {
 | 
					  named<Zip>("buildPlugin") {
 | 
				
			||||||
    dependsOn("test")
 | 
					    dependsOn("test")
 | 
				
			||||||
    archiveFileName.set("AceJump.zip")
 | 
					    archiveFileName = "AceJump.zip"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  withType<RunIdeTask> {
 | 
					  runIde {
 | 
				
			||||||
    dependsOn("test")
 | 
					 | 
				
			||||||
    findProperty("luginDev")?.let { args = listOf(projectDir.absolutePath) }
 | 
					    findProperty("luginDev")?.let { args = listOf(projectDir.absolutePath) }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  publishPlugin {
 | 
					  publishPlugin {
 | 
				
			||||||
    val intellijPublishToken: String? by project
 | 
					    val intellijPublishToken: String? by project
 | 
				
			||||||
    token.set(intellijPublishToken)
 | 
					    token = intellijPublishToken
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  patchPluginXml {
 | 
					  patchPluginXml {
 | 
				
			||||||
    sinceBuild.set("203.7717.56")
 | 
					    sinceBuild = "223.7571.182"
 | 
				
			||||||
    changeNotes.set(provider {
 | 
					    changeNotes = provider {
 | 
				
			||||||
      changelog.getAll().values.take(2).last().toHTML()
 | 
					      changelog.renderItem(changelog.getAll().values.take(2).last(), HTML)
 | 
				
			||||||
    })
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  runPluginVerifier {
 | 
					  // Remove pending: https://youtrack.jetbrains.com/issue/IDEA-278926
 | 
				
			||||||
    ideVersions.set(listOf("2021.2.1"))
 | 
					  val test by getting(Test::class) {
 | 
				
			||||||
 | 
					    isScanForTestClasses = false
 | 
				
			||||||
 | 
					    // Only run tests from classes that end with "Test"
 | 
				
			||||||
 | 
					    include("**/AceTest.class")
 | 
				
			||||||
 | 
					    include("**/ExternalUsageTest.class")
 | 
				
			||||||
 | 
					    include("**/LatencyTest.class")
 | 
				
			||||||
 | 
					    afterTest(
 | 
				
			||||||
 | 
					      KotlinClosure2({ desc: TestDescriptor, result: TestResult ->
 | 
				
			||||||
 | 
					        println("Completed `${desc.displayName}` in ${result.endTime - result.startTime}ms")
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					kotlin {
 | 
				
			||||||
 | 
					  jvmToolchain(17)
 | 
				
			||||||
 | 
					  sourceSets.all {
 | 
				
			||||||
 | 
					    languageSettings.apply {
 | 
				
			||||||
 | 
					      languageVersion = "2.0"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					val acejumpVersion = "3.8.19"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
changelog {
 | 
					changelog {
 | 
				
			||||||
  version.set("3.8.5")
 | 
					  version = acejumpVersion
 | 
				
			||||||
  path.set("${project.projectDir}/CHANGES.md")
 | 
					  path = "${project.projectDir}/CHANGES.md"
 | 
				
			||||||
  header.set(provider { "[${project.version}] - ${date()}" })
 | 
					  header = provider { "[${project.version}] - ${date()}" }
 | 
				
			||||||
  itemPrefix.set("-")
 | 
					  itemPrefix = "-"
 | 
				
			||||||
  unreleasedTerm.set("Unreleased")
 | 
					  unreleasedTerm = "Unreleased"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
repositories {
 | 
					repositories {
 | 
				
			||||||
  mavenCentral()
 | 
					  mavenCentral()
 | 
				
			||||||
  maven("https://jitpack.io")
 | 
					  intellijPlatform.defaultRepositories()
 | 
				
			||||||
 | 
					//  intellijPlatform.localPlatformArtifacts()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
  // gradle-intellij-plugin doesn't attach sources properly for Kotlin :(
 | 
					  // https://github.com/anyascii/anyascii
 | 
				
			||||||
  implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
 | 
					  implementation("com.anyascii:anyascii:0.3.2")
 | 
				
			||||||
  compileOnly(kotlin("stdlib-jdk8"))
 | 
					  intellijPlatform{
 | 
				
			||||||
  implementation("com.anyascii:anyascii:0.3.0")
 | 
					    testImplementation(libs.junit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bundledPlugins("com.intellij.java")
 | 
				
			||||||
 | 
					    create("IC", "2024.1.4")
 | 
				
			||||||
 | 
					    pluginVerifier()
 | 
				
			||||||
 | 
					    instrumentationTools()
 | 
				
			||||||
 | 
					    testFramework(TestFrameworkType.Platform)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
intellij {
 | 
					intellijPlatform {
 | 
				
			||||||
  version.set("2021.2.1")
 | 
					  pluginConfiguration {
 | 
				
			||||||
  pluginName.set("AceJump")
 | 
					    version = acejumpVersion
 | 
				
			||||||
  updateSinceUntilBuild.set(false)
 | 
					    name = "AceJump"
 | 
				
			||||||
  plugins.set(listOf("java"))
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  pluginVerification.ides.recommended()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
group = "org.acejump"
 | 
					group = "org.acejump"
 | 
				
			||||||
version = "3.8.5"
 | 
					version = acejumpVersion
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								gradle.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								gradle.properties
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					kotlin.stdlib.default.dependency=false
 | 
				
			||||||
 | 
					kotlin.incremental.useClasspathSnapshot=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					org.gradle.jvmargs=-Xmx2048m
 | 
				
			||||||
							
								
								
									
										18
									
								
								gradle/libs.versions.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								gradle/libs.versions.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					[versions]
 | 
				
			||||||
 | 
					# libraries
 | 
				
			||||||
 | 
					junit = "4.13.2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# plugins
 | 
				
			||||||
 | 
					changelog = "2.2.1"
 | 
				
			||||||
 | 
					intelliJPlatform = "2.0.0"
 | 
				
			||||||
 | 
					kotlin = "2.0.0"
 | 
				
			||||||
 | 
					kover = "0.8.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[libraries]
 | 
				
			||||||
 | 
					junit = { group = "junit", name = "junit", version.ref = "junit" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[plugins]
 | 
				
			||||||
 | 
					changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" }
 | 
				
			||||||
 | 
					intelliJPlatform = { id = "org.jetbrains.intellij.platform", version.ref = "intelliJPlatform" }
 | 
				
			||||||
 | 
					kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
 | 
				
			||||||
 | 
					kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
 | 
				
			||||||
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
distributionBase=GRADLE_USER_HOME
 | 
					distributionBase=GRADLE_USER_HOME
 | 
				
			||||||
distributionPath=wrapper/dists
 | 
					distributionPath=wrapper/dists
 | 
				
			||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
 | 
					distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
 | 
				
			||||||
zipStoreBase=GRADLE_USER_HOME
 | 
					zipStoreBase=GRADLE_USER_HOME
 | 
				
			||||||
zipStorePath=wrapper/dists
 | 
					zipStorePath=wrapper/dists
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,9 +2,12 @@ package org.acejump
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import com.anyascii.AnyAscii
 | 
					import com.anyascii.AnyAscii
 | 
				
			||||||
import com.intellij.diff.util.DiffUtil.getLineCount
 | 
					import com.intellij.diff.util.DiffUtil.getLineCount
 | 
				
			||||||
 | 
					import com.intellij.openapi.application.ApplicationManager
 | 
				
			||||||
import com.intellij.openapi.editor.*
 | 
					import com.intellij.openapi.editor.*
 | 
				
			||||||
 | 
					import com.intellij.openapi.util.Computable
 | 
				
			||||||
import it.unimi.dsi.fastutil.ints.IntArrayList
 | 
					import it.unimi.dsi.fastutil.ints.IntArrayList
 | 
				
			||||||
import org.acejump.config.AceConfig
 | 
					import org.acejump.config.AceConfig
 | 
				
			||||||
 | 
					import java.awt.Point
 | 
				
			||||||
import kotlin.math.*
 | 
					import kotlin.math.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -38,7 +41,7 @@ object EditorsCache {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun CharSequence.mapToASCII() =
 | 
					fun CharSequence.mapToASCII() =
 | 
				
			||||||
  map { AnyAscii.transliterate("$it").first() }.joinToString("")
 | 
					  map { AnyAscii.transliterate("$it").firstOrNull() ?: it }.joinToString("")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Returns true if [this] contains [otherText] at the specified offset.
 | 
					 * Returns true if [this] contains [otherText] at the specified offset.
 | 
				
			||||||
@@ -127,18 +130,15 @@ fun Editor.offsetCenter(first: Int, second: Int): LogicalPosition {
 | 
				
			|||||||
  return offsetToLogicalPosition(getLineStartOffset(center))
 | 
					  return offsetToLogicalPosition(getLineStartOffset(center))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Borrowed from Editor.calculateVisibleRange() but only available after 232.6095.10
 | 
				
			||||||
fun Editor.getView(): IntRange {
 | 
					fun Editor.getView(): IntRange {
 | 
				
			||||||
  val firstVisibleLine = max(0, getVisualLineAtTopOfScreen() - 1)
 | 
					  ApplicationManager.getApplication().assertIsDispatchThread()
 | 
				
			||||||
  val firstLine = visualLineToLogicalLine(firstVisibleLine)
 | 
					  val rect = scrollingModel.visibleArea
 | 
				
			||||||
  val startOffset = getLineStartOffset(firstLine)
 | 
					  val startPosition = xyToLogicalPosition(Point(rect.x, rect.y))
 | 
				
			||||||
 | 
					  val visibleStart = logicalPositionToOffset(startPosition)
 | 
				
			||||||
  val height = getScreenHeight() + 2
 | 
					  val endPosition = xyToLogicalPosition(Point(rect.x + rect.width, rect.y + rect.height))
 | 
				
			||||||
  val lastLine = visualLineToLogicalLine(firstVisibleLine + height)
 | 
					  val visibleEnd = logicalPositionToOffset(LogicalPosition(endPosition.line + 1, 0))
 | 
				
			||||||
  var endOffset = getLineEndOffset(lastLine, true)
 | 
					  return visibleStart..visibleEnd
 | 
				
			||||||
  endOffset = normalizeOffset(lastLine, endOffset)
 | 
					 | 
				
			||||||
  endOffset = min(max(0, document.textLength - 1), endOffset + 1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return startOffset..endOffset
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -253,3 +253,9 @@ fun Editor.normalizeOffset(line: Int, offset: Int, allowEnd: Boolean = true) =
 | 
				
			|||||||
  if (getFileSize(allowEnd) == 0) 0 else
 | 
					  if (getFileSize(allowEnd) == 0) 0 else
 | 
				
			||||||
    max(min(offset, getLineEndOffset(line, allowEnd)), getLineStartOffset(line))
 | 
					    max(min(offset, getLineEndOffset(line, allowEnd)), getLineStartOffset(line))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// https://plugins.jetbrains.com/docs/intellij/general-threading-rules.html#read-access
 | 
				
			||||||
 | 
					fun <T> read(action: () -> T): T =
 | 
				
			||||||
 | 
					  ApplicationManager.getApplication().runReadAction(Computable { action() })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun <T> write(action: () -> T): T =
 | 
				
			||||||
 | 
					  ApplicationManager.getApplication().runWriteAction(Computable { action() })
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,30 @@
 | 
				
			|||||||
package org.acejump.action
 | 
					package org.acejump.action
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.ActionUpdateThread
 | 
				
			||||||
import com.intellij.openapi.actionSystem.AnActionEvent
 | 
					import com.intellij.openapi.actionSystem.AnActionEvent
 | 
				
			||||||
import com.intellij.openapi.actionSystem.CommonDataKeys.EDITOR
 | 
					import com.intellij.openapi.actionSystem.CommonDataKeys.EDITOR
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.PlatformDataKeys.LAST_ACTIVE_FILE_EDITOR
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
 | 
					import com.intellij.openapi.fileEditor.FileEditorManager
 | 
				
			||||||
import com.intellij.openapi.fileEditor.TextEditor
 | 
					import com.intellij.openapi.fileEditor.TextEditor
 | 
				
			||||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
					import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
				
			||||||
import com.intellij.openapi.project.DumbAwareAction
 | 
					import com.intellij.openapi.project.DumbAwareAction
 | 
				
			||||||
import com.intellij.util.IncorrectOperationException
 | 
					import com.intellij.util.IncorrectOperationException
 | 
				
			||||||
import org.acejump.boundaries.Boundaries
 | 
					import org.acejump.boundaries.Boundaries
 | 
				
			||||||
import org.acejump.boundaries.StandardBoundaries.*
 | 
					import org.acejump.boundaries.StandardBoundaries.AFTER_CARET
 | 
				
			||||||
 | 
					import org.acejump.boundaries.StandardBoundaries.BEFORE_CARET
 | 
				
			||||||
 | 
					import org.acejump.boundaries.StandardBoundaries.WHOLE_FILE
 | 
				
			||||||
import org.acejump.input.JumpMode
 | 
					import org.acejump.input.JumpMode
 | 
				
			||||||
import org.acejump.input.JumpMode.*
 | 
					import org.acejump.input.JumpMode.DECLARATION
 | 
				
			||||||
 | 
					import org.acejump.input.JumpMode.JUMP
 | 
				
			||||||
 | 
					import org.acejump.input.JumpMode.JUMP_END
 | 
				
			||||||
 | 
					import org.acejump.input.JumpMode.TARGET
 | 
				
			||||||
import org.acejump.search.Pattern
 | 
					import org.acejump.search.Pattern
 | 
				
			||||||
import org.acejump.search.Pattern.*
 | 
					import org.acejump.search.Pattern.ALL_WORDS
 | 
				
			||||||
 | 
					import org.acejump.search.Pattern.LINE_ALL_MARKS
 | 
				
			||||||
 | 
					import org.acejump.search.Pattern.LINE_ENDS
 | 
				
			||||||
 | 
					import org.acejump.search.Pattern.LINE_INDENTS
 | 
				
			||||||
 | 
					import org.acejump.search.Pattern.LINE_STARTS
 | 
				
			||||||
import org.acejump.session.Session
 | 
					import org.acejump.session.Session
 | 
				
			||||||
import org.acejump.session.SessionManager
 | 
					import org.acejump.session.SessionManager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -19,25 +32,28 @@ import org.acejump.session.SessionManager
 | 
				
			|||||||
 * Base class for keyboard-activated actions that create or update an AceJump [Session].
 | 
					 * Base class for keyboard-activated actions that create or update an AceJump [Session].
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
sealed class AceAction: DumbAwareAction() {
 | 
					sealed class AceAction: DumbAwareAction() {
 | 
				
			||||||
 | 
					  override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  final override fun update(action: AnActionEvent) {
 | 
					  final override fun update(action: AnActionEvent) {
 | 
				
			||||||
    action.presentation.isEnabled = action.getData(EDITOR) != null
 | 
					    action.presentation.isEnabled =
 | 
				
			||||||
 | 
					      (action.getData(EDITOR) ?: (action.getData(LAST_ACTIVE_FILE_EDITOR) as? TextEditor)?.editor) != null
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  final override fun actionPerformed(e: AnActionEvent) {
 | 
					  final override fun actionPerformed(e: AnActionEvent) {
 | 
				
			||||||
    val editor = e.getData(EDITOR) ?: return
 | 
					    val editor = e.getData(EDITOR) ?: (e.getData(LAST_ACTIVE_FILE_EDITOR) as? TextEditor)?.editor ?: return
 | 
				
			||||||
    val project = e.project
 | 
					    val project = e.project
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
    if (project != null) {
 | 
					    if (project != null) {
 | 
				
			||||||
      try {
 | 
					      try {
 | 
				
			||||||
        val openEditors = FileEditorManagerEx.getInstanceEx(project).splitters.selectedEditors
 | 
					        val fem = FileEditorManager.getInstance(project) as FileEditorManagerEx
 | 
				
			||||||
 | 
					        val openEditors = fem.splitters.getSelectedEditors()
 | 
				
			||||||
          .mapNotNull { (it as? TextEditor)?.editor }
 | 
					          .mapNotNull { (it as? TextEditor)?.editor }
 | 
				
			||||||
          .sortedBy { if (it === editor) 0 else 1 }
 | 
					          .sortedBy { if (it === editor) 0 else 1 }
 | 
				
			||||||
        invoke(SessionManager.start(editor, openEditors))
 | 
					        invoke(SessionManager.start(editor, openEditors))
 | 
				
			||||||
      } catch (e: IncorrectOperationException) {
 | 
					      } catch (e: IncorrectOperationException) {
 | 
				
			||||||
        invoke(SessionManager.start(editor))
 | 
					        invoke(SessionManager.start(editor))
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    } else {
 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
      invoke(SessionManager.start(editor))
 | 
					      invoke(SessionManager.start(editor))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -51,6 +67,13 @@ sealed class AceAction: DumbAwareAction() {
 | 
				
			|||||||
    final override fun invoke(session: Session) = session.toggleJumpMode(mode)
 | 
					    final override fun invoke(session: Session) = session.toggleJumpMode(mode)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Generic action type that toggles a specific [JumpMode] with [Boundaries].
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  abstract class BaseToggleBoundedJumpModeAction(private val mode: JumpMode, private val boundaries: Boundaries): AceAction() {
 | 
				
			||||||
 | 
					    final override fun invoke(session: Session) = session.toggleJumpMode(mode, boundaries)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Generic action type that starts a regex search.
 | 
					   * Generic action type that starts a regex search.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
@@ -74,12 +97,17 @@ sealed class AceAction: DumbAwareAction() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // @formatter:off
 | 
					  // @formatter:off
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Unbounded Toggle Modes
 | 
				
			||||||
  class ToggleJumpMode        : BaseToggleJumpModeAction(JUMP)
 | 
					  class ToggleJumpMode        : BaseToggleJumpModeAction(JUMP)
 | 
				
			||||||
  class ToggleJumpEndMode     : BaseToggleJumpModeAction(JUMP_END)
 | 
					  class ToggleJumpEndMode     : BaseToggleJumpModeAction(JUMP_END)
 | 
				
			||||||
  class ToggleTargetMode      : BaseToggleJumpModeAction(TARGET)
 | 
					  class ToggleTargetMode      : BaseToggleJumpModeAction(TARGET)
 | 
				
			||||||
  class ToggleDeclarationMode : BaseToggleJumpModeAction(DECLARATION)
 | 
					  class ToggleDeclarationMode : BaseToggleJumpModeAction(DECLARATION)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Bounded Toggle Modes
 | 
				
			||||||
 | 
					  class ToggleBackwardJumpMode : BaseToggleBoundedJumpModeAction(JUMP, BEFORE_CARET)
 | 
				
			||||||
 | 
					  class ToggleForwardJumpMode  : BaseToggleBoundedJumpModeAction(JUMP, AFTER_CARET)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Regex Modes
 | 
				
			||||||
  class StartAllWordsMode          : BaseRegexSearchAction(ALL_WORDS, WHOLE_FILE)
 | 
					  class StartAllWordsMode          : BaseRegexSearchAction(ALL_WORDS, WHOLE_FILE)
 | 
				
			||||||
  class StartAllWordsBackwardsMode : BaseRegexSearchAction(ALL_WORDS, BEFORE_CARET)
 | 
					  class StartAllWordsBackwardsMode : BaseRegexSearchAction(ALL_WORDS, BEFORE_CARET)
 | 
				
			||||||
  class StartAllWordsForwardMode   : BaseRegexSearchAction(ALL_WORDS, AFTER_CARET)
 | 
					  class StartAllWordsForwardMode   : BaseRegexSearchAction(ALL_WORDS, AFTER_CARET)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,22 +1,31 @@
 | 
				
			|||||||
package org.acejump.action
 | 
					package org.acejump.action
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.intellij.openapi.actionSystem.*
 | 
					import com.intellij.openapi.actionSystem.ActionManager
 | 
				
			||||||
import com.intellij.openapi.actionSystem.IdeActions.*
 | 
					import com.intellij.openapi.actionSystem.AnAction
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.IdeActions.ACTION_GOTO_DECLARATION
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.IdeActions.ACTION_GOTO_TYPE_DECLARATION
 | 
				
			||||||
import com.intellij.openapi.command.CommandProcessor
 | 
					import com.intellij.openapi.command.CommandProcessor
 | 
				
			||||||
import com.intellij.openapi.command.UndoConfirmationPolicy
 | 
					import com.intellij.openapi.command.UndoConfirmationPolicy
 | 
				
			||||||
import com.intellij.openapi.editor.Document
 | 
					import com.intellij.openapi.editor.Document
 | 
				
			||||||
import com.intellij.openapi.editor.Editor
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
import com.intellij.openapi.editor.actionSystem.DocCommandGroupId
 | 
					import com.intellij.openapi.editor.actionSystem.DocCommandGroupId
 | 
				
			||||||
 | 
					import com.intellij.openapi.fileEditor.FileEditorManager
 | 
				
			||||||
import com.intellij.openapi.fileEditor.TextEditor
 | 
					import com.intellij.openapi.fileEditor.TextEditor
 | 
				
			||||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
					import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
				
			||||||
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory
 | 
					import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory
 | 
				
			||||||
import com.intellij.openapi.project.Project
 | 
					import com.intellij.openapi.project.Project
 | 
				
			||||||
import com.intellij.openapi.ui.playback.commands.ActionCommand
 | 
					import com.intellij.openapi.ui.playback.commands.ActionCommand
 | 
				
			||||||
import org.acejump.*
 | 
					import org.acejump.countMatchingCharacters
 | 
				
			||||||
 | 
					import org.acejump.immutableText
 | 
				
			||||||
import org.acejump.input.JumpMode
 | 
					import org.acejump.input.JumpMode
 | 
				
			||||||
import org.acejump.input.JumpMode.*
 | 
					import org.acejump.input.JumpMode.DECLARATION
 | 
				
			||||||
 | 
					import org.acejump.input.JumpMode.JUMP_END
 | 
				
			||||||
 | 
					import org.acejump.input.JumpMode.TARGET
 | 
				
			||||||
 | 
					import org.acejump.isWordPart
 | 
				
			||||||
import org.acejump.search.SearchProcessor
 | 
					import org.acejump.search.SearchProcessor
 | 
				
			||||||
import org.acejump.search.Tag
 | 
					import org.acejump.search.Tag
 | 
				
			||||||
 | 
					import org.acejump.wordEnd
 | 
				
			||||||
 | 
					import org.acejump.wordStart
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Performs [JumpMode] navigation and actions.
 | 
					 * Performs [JumpMode] navigation and actions.
 | 
				
			||||||
@@ -98,9 +107,9 @@ internal class TagJumper(private val mode: JumpMode, private val searchProcessor
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private fun ensureEditorFocused(editor: Editor) {
 | 
					    private fun ensureEditorFocused(editor: Editor) {
 | 
				
			||||||
      val project = editor.project ?: return
 | 
					      val project = editor.project ?: return
 | 
				
			||||||
      val fem = FileEditorManagerEx.getInstanceEx(project)
 | 
					      val fem = FileEditorManager.getInstance(project) as FileEditorManagerEx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      val window = fem.windows.firstOrNull { (it.selectedEditor?.selectedWithProvider?.fileEditor as? TextEditor)?.editor === editor }
 | 
					      val window = fem.windows.firstOrNull { (it.getSelectedComposite(false)?.selectedWithProvider?.fileEditor as? TextEditor)?.editor === editor }
 | 
				
			||||||
      if (window != null && window !== fem.currentWindow) {
 | 
					      if (window != null && window !== fem.currentWindow) {
 | 
				
			||||||
        fem.currentWindow = window
 | 
					        fem.currentWindow = window
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,10 @@ import org.acejump.*
 | 
				
			|||||||
import org.acejump.search.SearchProcessor
 | 
					import org.acejump.search.SearchProcessor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class TagScroller(private val editor: Editor, private val searchProcessor: SearchProcessor) {
 | 
					internal class TagScroller(private val editor: Editor, private val searchProcessor: SearchProcessor) {
 | 
				
			||||||
  fun scroll(forward: Boolean = true): Boolean {
 | 
					  fun scroll(
 | 
				
			||||||
    val position = if (forward) findNextPosition() else findPreviousPosition()
 | 
					    forward: Boolean = true,
 | 
				
			||||||
    return if (position != null) true.also { scrollTo(position) } else false
 | 
					    position: LogicalPosition? = if (forward) findNextPosition() else findPreviousPosition()
 | 
				
			||||||
  }
 | 
					  ) = if (position != null) true.also { scrollTo(position) } else false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun scrollTo(position: LogicalPosition) = editor.run {
 | 
					  private fun scrollTo(position: LogicalPosition) = editor.run {
 | 
				
			||||||
    scrollingModel.disableAnimation()
 | 
					    scrollingModel.disableAnimation()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,6 @@ package org.acejump.action
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import com.intellij.openapi.editor.*
 | 
					import com.intellij.openapi.editor.*
 | 
				
			||||||
import com.intellij.openapi.editor.ScrollType.*
 | 
					import com.intellij.openapi.editor.ScrollType.*
 | 
				
			||||||
import org.acejump.*
 | 
					 | 
				
			||||||
import org.acejump.search.SearchProcessor
 | 
					import org.acejump.search.SearchProcessor
 | 
				
			||||||
import org.acejump.search.Tag
 | 
					import org.acejump.search.Tag
 | 
				
			||||||
import kotlin.math.abs
 | 
					import kotlin.math.abs
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,12 +16,14 @@ interface Boundaries {
 | 
				
			|||||||
   * offsets outside the boundary, for ex. when the boundary is rectangular
 | 
					   * offsets outside the boundary, for ex. when the boundary is rectangular
 | 
				
			||||||
   * and the file has long lines which are only partially visible.
 | 
					   * and the file has long lines which are only partially visible.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  fun getOffsetRange(editor: Editor, cache: EditorOffsetCache = EditorOffsetCache.Uncached): IntRange
 | 
					  fun getOffsetRange(editor: Editor, cache: EditorOffsetCache = EditorOffsetCache.Uncached): IntRange =
 | 
				
			||||||
 | 
					    StandardBoundaries.VISIBLE_ON_SCREEN.getOffsetRange(editor, cache)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Returns whether the editor offset is included within the boundary.
 | 
					   * Returns whether the editor offset is included within the boundary.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  fun isOffsetInside(editor: Editor, offset: Int, cache: EditorOffsetCache = EditorOffsetCache.Uncached): Boolean
 | 
					  fun isOffsetInside(editor: Editor, offset: Int, cache: EditorOffsetCache = EditorOffsetCache.Uncached): Boolean =
 | 
				
			||||||
 | 
					    StandardBoundaries.VISIBLE_ON_SCREEN.isOffsetInside(editor, offset, cache)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Creates a boundary so that an offset/range is within the boundary
 | 
					   * Creates a boundary so that an offset/range is within the boundary
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ package org.acejump.boundaries
 | 
				
			|||||||
import com.intellij.openapi.editor.Editor
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
 | 
					import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
 | 
				
			||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
 | 
					import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
 | 
				
			||||||
 | 
					import org.acejump.read
 | 
				
			||||||
import java.awt.Point
 | 
					import java.awt.Point
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -20,6 +21,11 @@ sealed class EditorOffsetCache {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  abstract fun visibleArea(editor: Editor): Pair<Point, Point>
 | 
					  abstract fun visibleArea(editor: Editor): Pair<Point, Point>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Returns whether the offset is in the visible area rectangle.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  abstract fun isVisible(editor: Editor, offset: Int): Boolean
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Returns the editor offset at the provided pixel coordinate.
 | 
					   * Returns the editor offset at the provided pixel coordinate.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
@@ -30,32 +36,46 @@ sealed class EditorOffsetCache {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  abstract fun offsetToXY(editor: Editor, offset: Int): Point
 | 
					  abstract fun offsetToXY(editor: Editor, offset: Int): Point
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  companion object {
 | 
					  companion object { fun new(): EditorOffsetCache = Cache() }
 | 
				
			||||||
    fun new(): EditorOffsetCache = Cache()
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private class Cache: EditorOffsetCache() {
 | 
					  private class Cache: EditorOffsetCache() {
 | 
				
			||||||
    private var visibleArea: Pair<Point, Point>? = null
 | 
					    private var visibleArea: Pair<Point, Point>? = null
 | 
				
			||||||
    private val pointToOffset = Object2IntOpenHashMap<Point>().apply { defaultReturnValue(-1) }
 | 
					    private val lineToVisibleOffsetRange = Int2ObjectOpenHashMap<IntRange>()
 | 
				
			||||||
 | 
					    private val pointToOffset =
 | 
				
			||||||
 | 
					      Object2IntOpenHashMap<Point>().apply { defaultReturnValue(-1) }
 | 
				
			||||||
    private val offsetToPoint = Int2ObjectOpenHashMap<Point>()
 | 
					    private val offsetToPoint = Int2ObjectOpenHashMap<Point>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun visibleArea(editor: Editor): Pair<Point, Point> =
 | 
					    override fun visibleArea(editor: Editor): Pair<Point, Point> =
 | 
				
			||||||
      visibleArea ?: Uncached.visibleArea(editor).also { visibleArea = it }
 | 
					      visibleArea ?: Uncached.visibleArea(editor).also { visibleArea = it }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun isVisible(editor: Editor, offset: Int): Boolean {
 | 
				
			||||||
 | 
					      val visualLine = editor.offsetToVisualLine(offset, false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      var visibleRange = lineToVisibleOffsetRange.get(visualLine)
 | 
				
			||||||
 | 
					      if (visibleRange == null) {
 | 
				
			||||||
 | 
					        val (topLeft, bottomRight) = visibleArea(editor)
 | 
				
			||||||
 | 
					        val lineY = editor.visualLineToY(visualLine)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val firstVisibleOffset = xyToOffset(editor, Point(topLeft.x, lineY))
 | 
				
			||||||
 | 
					        val lastVisibleOffset = xyToOffset(editor, Point(bottomRight.x, lineY))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        visibleRange = firstVisibleOffset..lastVisibleOffset
 | 
				
			||||||
 | 
					        lineToVisibleOffsetRange.put(visualLine, visibleRange)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return offset in visibleRange
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun xyToOffset(editor: Editor, pos: Point): Int =
 | 
					    override fun xyToOffset(editor: Editor, pos: Point): Int =
 | 
				
			||||||
      pointToOffset.getInt(pos).let { offset ->
 | 
					      pointToOffset.getInt(pos).let { offset ->
 | 
				
			||||||
        if (offset != -1) offset
 | 
					        if (offset != -1) offset
 | 
				
			||||||
        else Uncached.xyToOffset(editor, pos).also {
 | 
					        else Uncached.xyToOffset(editor, pos)
 | 
				
			||||||
          @Suppress("ReplacePutWithAssignment")
 | 
					          .also { pointToOffset.put(pos, it) }
 | 
				
			||||||
          pointToOffset.put(pos, it)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun offsetToXY(editor: Editor, offset: Int) =
 | 
					    override fun offsetToXY(editor: Editor, offset: Int) =
 | 
				
			||||||
      offsetToPoint.get(offset) ?: Uncached.offsetToXY(editor, offset).also {
 | 
					      offsetToPoint.get(offset) ?: Uncached.offsetToXY(editor, offset)
 | 
				
			||||||
        @Suppress("ReplacePutWithAssignment")
 | 
					        .also { offsetToPoint.put(offset, it) }
 | 
				
			||||||
        offsetToPoint.put(offset, it)
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  object Uncached: EditorOffsetCache() {
 | 
					  object Uncached: EditorOffsetCache() {
 | 
				
			||||||
@@ -68,8 +88,17 @@ sealed class EditorOffsetCache {
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun isVisible(editor: Editor, offset: Int): Boolean {
 | 
				
			||||||
 | 
					      val (topLeft, bottomRight) = visibleArea(editor)
 | 
				
			||||||
 | 
					      val pos = offsetToXY(editor, offset)
 | 
				
			||||||
 | 
					      val x = pos.x
 | 
				
			||||||
 | 
					      val y = pos.y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return x >= topLeft.x && y >= topLeft.y && x <= bottomRight.x && y <= bottomRight.y
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun xyToOffset(editor: Editor, pos: Point): Int =
 | 
					    override fun xyToOffset(editor: Editor, pos: Point): Int =
 | 
				
			||||||
      editor.logicalPositionToOffset(editor.xyToLogicalPosition(pos))
 | 
					      read { editor.logicalPositionToOffset(editor.xyToLogicalPosition(pos)) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun offsetToXY(editor: Editor, offset: Int): Point =
 | 
					    override fun offsetToXY(editor: Editor, offset: Int): Point =
 | 
				
			||||||
      editor.offsetToXY(offset, true, false)
 | 
					      editor.offsetToXY(offset, true, false)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,10 @@ import com.intellij.openapi.editor.Editor
 | 
				
			|||||||
enum class StandardBoundaries : Boundaries {
 | 
					enum class StandardBoundaries : Boundaries {
 | 
				
			||||||
  WHOLE_FILE {
 | 
					  WHOLE_FILE {
 | 
				
			||||||
    override fun getOffsetRange(editor: Editor, cache: EditorOffsetCache) =
 | 
					    override fun getOffsetRange(editor: Editor, cache: EditorOffsetCache) =
 | 
				
			||||||
      0 until editor.document.textLength
 | 
					      0..editor.document.textLength
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    override fun isOffsetInside(editor: Editor, offset: Int, cache: EditorOffsetCache) =
 | 
					    override fun isOffsetInside(editor: Editor, offset: Int, cache: EditorOffsetCache) =
 | 
				
			||||||
      offset in (0 until editor.document.textLength)
 | 
					      offset in (0..editor.document.textLength)
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  VISIBLE_ON_SCREEN {
 | 
					  VISIBLE_ON_SCREEN {
 | 
				
			||||||
@@ -21,22 +21,7 @@ enum class StandardBoundaries : Boundaries {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    override fun isOffsetInside(editor: Editor, offset: Int, cache: EditorOffsetCache): Boolean {
 | 
					    override fun isOffsetInside(editor: Editor, offset: Int, cache: EditorOffsetCache): Boolean {
 | 
				
			||||||
      // If we are not using a cache, calling getOffsetRange will cause
 | 
					      return cache.isVisible(editor, offset)
 | 
				
			||||||
      // additional 1-2 pixel coordinate -> offset lookups, which is a lot
 | 
					 | 
				
			||||||
      // more expensive than one lookup compared against the visible area.
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      // However, if we are using a cache, it's likely that the topmost and
 | 
					 | 
				
			||||||
      // bottommost positions are already cached whereas the provided offset
 | 
					 | 
				
			||||||
      // isn't, so we save a lookup for every offset outside the range.
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      if (cache !== EditorOffsetCache.Uncached && offset !in getOffsetRange(editor, cache)) return false
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      val (topLeft, bottomRight) = cache.visibleArea(editor)
 | 
					 | 
				
			||||||
      val pos = cache.offsetToXY(editor, offset)
 | 
					 | 
				
			||||||
      val x = pos.x
 | 
					 | 
				
			||||||
      val y = pos.y
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
      return x >= topLeft.x && y >= topLeft.y && x <= bottomRight.x && y <= bottomRight.y
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
package org.acejump.config
 | 
					package org.acejump.config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.intellij.openapi.components.PersistentStateComponent
 | 
					import com.intellij.openapi.components.PersistentStateComponent
 | 
				
			||||||
import com.intellij.openapi.components.ServiceManager
 | 
					 | 
				
			||||||
import com.intellij.openapi.components.State
 | 
					import com.intellij.openapi.components.State
 | 
				
			||||||
import com.intellij.openapi.components.Storage
 | 
					import com.intellij.openapi.components.Storage
 | 
				
			||||||
 | 
					import com.intellij.util.application
 | 
				
			||||||
import org.acejump.input.KeyLayoutCache
 | 
					import org.acejump.input.KeyLayoutCache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -16,19 +16,19 @@ class AceConfig: PersistentStateComponent<AceSettings> {
 | 
				
			|||||||
  private var aceSettings = AceSettings()
 | 
					  private var aceSettings = AceSettings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  companion object {
 | 
					  companion object {
 | 
				
			||||||
    val settings get() = ServiceManager.getService(AceConfig::class.java).aceSettings
 | 
					    val settings get() = application.getService(AceConfig::class.java).aceSettings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // @formatter:off
 | 
					    // @formatter:off
 | 
				
			||||||
    val layout get()              = settings.layout
 | 
					    val layout get()              = settings.layout
 | 
				
			||||||
    val cycleModes get()          = settings.let { arrayOf(it.cycleMode1, it.cycleMode2, it.cycleMode3, it.cycleMode4) }
 | 
					    val cycleModes get()          = settings.let { arrayOf(it.cycleMode1, it.cycleMode2, it.cycleMode3, it.cycleMode4) }
 | 
				
			||||||
    val minQueryLength get()      = settings.minQueryLength
 | 
					    val minQueryLength get()      = settings.minQueryLength
 | 
				
			||||||
    val jumpModeColor get()       = settings.jumpModeColor
 | 
					    val jumpModeColor get()       = settings.getJumpModeJBC()
 | 
				
			||||||
    val jumpEndModeColor get()    = settings.jumpEndModeColor
 | 
					    val jumpEndModeColor get()    = settings.getJumpEndModeJBC()
 | 
				
			||||||
    val targetModeColor get()     = settings.targetModeColor
 | 
					    val targetModeColor get()     = settings.getTargetModeJBC()
 | 
				
			||||||
    val definitionModeColor get() = settings.definitionModeColor
 | 
					    val definitionModeColor get() = settings.getDefinitionModeJBC()
 | 
				
			||||||
    val textHighlightColor get()  = settings.textHighlightColor
 | 
					    val textHighlightColor get()  = settings.getTextHighlightJBC()
 | 
				
			||||||
    val tagForegroundColor get()  = settings.tagForegroundColor
 | 
					    val tagForegroundColor get()  = settings.getTagForegroundJBC()
 | 
				
			||||||
    val tagBackgroundColor get()  = settings.tagBackgroundColor
 | 
					    val tagBackgroundColor get()  = settings.getTagBackgroundJBC()
 | 
				
			||||||
    val searchWholeFile get()     = settings.searchWholeFile
 | 
					    val searchWholeFile get()     = settings.searchWholeFile
 | 
				
			||||||
    val mapToASCII get()        = settings.mapToASCII
 | 
					    val mapToASCII get()        = settings.mapToASCII
 | 
				
			||||||
    val showSearchNotification get()          = settings.showSearchNotification
 | 
					    val showSearchNotification get()          = settings.showSearchNotification
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,13 +19,13 @@ class AceConfigurable: Configurable {
 | 
				
			|||||||
      panel.cycleMode3 != settings.cycleMode3 ||
 | 
					      panel.cycleMode3 != settings.cycleMode3 ||
 | 
				
			||||||
      panel.cycleMode4 != settings.cycleMode4 ||
 | 
					      panel.cycleMode4 != settings.cycleMode4 ||
 | 
				
			||||||
      panel.minQueryLengthInt != settings.minQueryLength ||
 | 
					      panel.minQueryLengthInt != settings.minQueryLength ||
 | 
				
			||||||
      panel.jumpModeColor != settings.jumpModeColor ||
 | 
					      panel.jumpModeColor?.rgb != settings.jumpModeColor ||
 | 
				
			||||||
      panel.jumpEndModeColor != settings.jumpEndModeColor ||
 | 
					      panel.jumpEndModeColor?.rgb != settings.jumpEndModeColor ||
 | 
				
			||||||
      panel.targetModeColor != settings.targetModeColor ||
 | 
					      panel.targetModeColor?.rgb != settings.targetModeColor ||
 | 
				
			||||||
      panel.definitionModeColor != settings.definitionModeColor ||
 | 
					      panel.definitionModeColor?.rgb != settings.definitionModeColor ||
 | 
				
			||||||
      panel.textHighlightColor != settings.textHighlightColor ||
 | 
					      panel.textHighlightColor?.rgb != settings.textHighlightColor ||
 | 
				
			||||||
      panel.tagForegroundColor != settings.tagForegroundColor ||
 | 
					      panel.tagForegroundColor?.rgb != settings.tagForegroundColor ||
 | 
				
			||||||
      panel.tagBackgroundColor != settings.tagBackgroundColor ||
 | 
					      panel.tagBackgroundColor?.rgb != settings.tagBackgroundColor ||
 | 
				
			||||||
      panel.searchWholeFile != settings.searchWholeFile ||
 | 
					      panel.searchWholeFile != settings.searchWholeFile ||
 | 
				
			||||||
      panel.mapToASCII != settings.mapToASCII ||
 | 
					      panel.mapToASCII != settings.mapToASCII ||
 | 
				
			||||||
      panel.showSearchNotification != settings.showSearchNotification
 | 
					      panel.showSearchNotification != settings.showSearchNotification
 | 
				
			||||||
@@ -38,13 +38,13 @@ class AceConfigurable: Configurable {
 | 
				
			|||||||
    settings.cycleMode3 = panel.cycleMode3
 | 
					    settings.cycleMode3 = panel.cycleMode3
 | 
				
			||||||
    settings.cycleMode4 = panel.cycleMode4
 | 
					    settings.cycleMode4 = panel.cycleMode4
 | 
				
			||||||
    settings.minQueryLength = panel.minQueryLengthInt ?: settings.minQueryLength
 | 
					    settings.minQueryLength = panel.minQueryLengthInt ?: settings.minQueryLength
 | 
				
			||||||
    panel.jumpModeColor?.let { settings.jumpModeColor = it }
 | 
					    panel.jumpModeColor?.let { settings.jumpModeColor = it.rgb }
 | 
				
			||||||
    panel.jumpEndModeColor?.let { settings.jumpEndModeColor = it }
 | 
					    panel.jumpEndModeColor?.let { settings.jumpEndModeColor = it.rgb }
 | 
				
			||||||
    panel.targetModeColor?.let { settings.targetModeColor = it }
 | 
					    panel.targetModeColor?.let { settings.targetModeColor = it.rgb }
 | 
				
			||||||
    panel.definitionModeColor?.let { settings.definitionModeColor = it }
 | 
					    panel.definitionModeColor?.let { settings.definitionModeColor = it.rgb }
 | 
				
			||||||
    panel.textHighlightColor?.let { settings.textHighlightColor = it }
 | 
					    panel.textHighlightColor?.let { settings.textHighlightColor = it.rgb }
 | 
				
			||||||
    panel.tagForegroundColor?.let { settings.tagForegroundColor = it }
 | 
					    panel.tagForegroundColor?.let { settings.tagForegroundColor = it.rgb }
 | 
				
			||||||
    panel.tagBackgroundColor?.let { settings.tagBackgroundColor = it }
 | 
					    panel.tagBackgroundColor?.let { settings.tagBackgroundColor = it.rgb }
 | 
				
			||||||
    settings.searchWholeFile = panel.searchWholeFile
 | 
					    settings.searchWholeFile = panel.searchWholeFile
 | 
				
			||||||
    settings.mapToASCII = panel.mapToASCII
 | 
					    settings.mapToASCII = panel.mapToASCII
 | 
				
			||||||
    settings.showSearchNotification = panel.showSearchNotification
 | 
					    settings.showSearchNotification = panel.showSearchNotification
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,8 @@
 | 
				
			|||||||
package org.acejump.config
 | 
					package org.acejump.config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.intellij.util.xmlb.Converter
 | 
					import com.intellij.ui.JBColor
 | 
				
			||||||
import com.intellij.util.xmlb.annotations.OptionTag
 | 
					import org.acejump.input.*
 | 
				
			||||||
import org.acejump.input.JumpMode
 | 
					 | 
				
			||||||
import org.acejump.input.KeyLayout
 | 
					 | 
				
			||||||
import org.acejump.input.KeyLayout.QWERTY
 | 
					import org.acejump.input.KeyLayout.QWERTY
 | 
				
			||||||
import java.awt.Color
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
data class AceSettings(
 | 
					data class AceSettings(
 | 
				
			||||||
  var layout: KeyLayout = QWERTY,
 | 
					  var layout: KeyLayout = QWERTY,
 | 
				
			||||||
@@ -16,35 +13,31 @@ data class AceSettings(
 | 
				
			|||||||
  var cycleMode4: JumpMode = JumpMode.JUMP_END,
 | 
					  var cycleMode4: JumpMode = JumpMode.JUMP_END,
 | 
				
			||||||
  var minQueryLength: Int = 1,
 | 
					  var minQueryLength: Int = 1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @OptionTag("jumpModeRGB", converter = ColorConverter::class)
 | 
					  var jumpModeColor: Int = 0xFFFFFF,
 | 
				
			||||||
  var jumpModeColor: Color = Color(0xFFFFFF),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @OptionTag("jumpEndModeRGB", converter = ColorConverter::class)
 | 
					  var jumpEndModeColor: Int = 0x33E78A,
 | 
				
			||||||
  var jumpEndModeColor: Color = Color(0x33E78A),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @OptionTag("targetModeRGB", converter = ColorConverter::class)
 | 
					  var targetModeColor: Int = 0xFFB700,
 | 
				
			||||||
  var targetModeColor: Color = Color(0xFFB700),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @OptionTag("definitionModeRGB", converter = ColorConverter::class)
 | 
					  var definitionModeColor: Int = 0x6FC5FF,
 | 
				
			||||||
  var definitionModeColor: Color = Color(0x6FC5FF),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @OptionTag("textHighlightRGB", converter = ColorConverter::class)
 | 
					  var textHighlightColor: Int = 0x394B58,
 | 
				
			||||||
  var textHighlightColor: Color = Color(0x394B58),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @OptionTag("tagForegroundRGB", converter = ColorConverter::class)
 | 
					  var tagForegroundColor: Int = 0xFFFFFF,
 | 
				
			||||||
  var tagForegroundColor: Color = Color(0xFFFFFF),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @OptionTag("tagBackgroundRGB", converter = ColorConverter::class)
 | 
					  var tagBackgroundColor: Int = 0x008299,
 | 
				
			||||||
  var tagBackgroundColor: Color = Color(0x008299),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var searchWholeFile: Boolean = true,
 | 
					  var searchWholeFile: Boolean = true,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var mapToASCII : Boolean = false,
 | 
					  var mapToASCII: Boolean = false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var showSearchNotification : Boolean = false
 | 
					  var showSearchNotification: Boolean = false
 | 
				
			||||||
)
 | 
					) {
 | 
				
			||||||
 | 
					  fun getJumpModeJBC() = JBColor.namedColor("jumpModeRGB", jumpModeColor)
 | 
				
			||||||
internal class ColorConverter: Converter<Color>() {
 | 
					  fun getJumpEndModeJBC() = JBColor.namedColor("jumpEndModeRGB", jumpEndModeColor)
 | 
				
			||||||
  override fun toString(value: Color) = value.rgb.toString()
 | 
					  fun getTargetModeJBC() = JBColor.namedColor("targetModeRGB", targetModeColor)
 | 
				
			||||||
  override fun fromString(value: String) = value.toIntOrNull()?.let(::Color)
 | 
					  fun getDefinitionModeJBC() = JBColor.namedColor("definitionModeRGB", definitionModeColor)
 | 
				
			||||||
 | 
					  fun getTextHighlightJBC() = JBColor.namedColor("textHighlightRGB", textHighlightColor)
 | 
				
			||||||
 | 
					  fun getTagForegroundJBC() = JBColor.namedColor("tagForegroundRGB", tagForegroundColor)
 | 
				
			||||||
 | 
					  fun getTagBackgroundJBC() = JBColor.namedColor("tagBackgroundRGB", tagBackgroundColor)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,12 @@
 | 
				
			|||||||
package org.acejump.config
 | 
					package org.acejump.config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.intellij.openapi.ui.ComboBox
 | 
					import com.intellij.openapi.ui.ComboBox
 | 
				
			||||||
import com.intellij.ui.ColorPanel
 | 
					import com.intellij.ui.components.*
 | 
				
			||||||
import com.intellij.ui.components.JBCheckBox
 | 
					import com.intellij.ui.dsl.builder.*
 | 
				
			||||||
import com.intellij.ui.components.JBTextArea
 | 
					 | 
				
			||||||
import com.intellij.ui.components.JBTextField
 | 
					 | 
				
			||||||
import com.intellij.ui.layout.Cell
 | 
					 | 
				
			||||||
import com.intellij.ui.layout.GrowPolicy.MEDIUM_TEXT
 | 
					 | 
				
			||||||
import com.intellij.ui.layout.GrowPolicy.SHORT_TEXT
 | 
					 | 
				
			||||||
import com.intellij.ui.layout.panel
 | 
					 | 
				
			||||||
import org.acejump.input.JumpMode
 | 
					import org.acejump.input.JumpMode
 | 
				
			||||||
import org.acejump.input.KeyLayout
 | 
					import org.acejump.input.KeyLayout
 | 
				
			||||||
import java.awt.Color
 | 
					import java.awt.*
 | 
				
			||||||
import java.awt.Font
 | 
					import javax.swing.*
 | 
				
			||||||
import javax.swing.JCheckBox
 | 
					 | 
				
			||||||
import javax.swing.JComponent
 | 
					 | 
				
			||||||
import javax.swing.JPanel
 | 
					 | 
				
			||||||
import javax.swing.text.JTextComponent
 | 
					import javax.swing.text.JTextComponent
 | 
				
			||||||
import kotlin.reflect.KProperty
 | 
					import kotlin.reflect.KProperty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,6 +15,8 @@ import kotlin.reflect.KProperty
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
@Suppress("UsePropertyAccessSyntax")
 | 
					@Suppress("UsePropertyAccessSyntax")
 | 
				
			||||||
internal class AceSettingsPanel {
 | 
					internal class AceSettingsPanel {
 | 
				
			||||||
 | 
					  private val defaults = AceSettings()
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  private val tagCharsField = JBTextField()
 | 
					  private val tagCharsField = JBTextField()
 | 
				
			||||||
  private val keyboardLayoutCombo = ComboBox<KeyLayout>()
 | 
					  private val keyboardLayoutCombo = ComboBox<KeyLayout>()
 | 
				
			||||||
  private val keyboardLayoutArea = JBTextArea().apply { isEditable = false }
 | 
					  private val keyboardLayoutArea = JBTextArea().apply { isEditable = false }
 | 
				
			||||||
@@ -32,13 +25,13 @@ internal class AceSettingsPanel {
 | 
				
			|||||||
  private val cycleModeCombo3 = ComboBox<JumpMode>()
 | 
					  private val cycleModeCombo3 = ComboBox<JumpMode>()
 | 
				
			||||||
  private val cycleModeCombo4 = ComboBox<JumpMode>()
 | 
					  private val cycleModeCombo4 = ComboBox<JumpMode>()
 | 
				
			||||||
  private val minQueryLengthField = JBTextField()
 | 
					  private val minQueryLengthField = JBTextField()
 | 
				
			||||||
  private val jumpModeColorWheel = ColorPanel()
 | 
					  private val jumpModeColorWheel = ResettableColorPicker(defaults.getJumpModeJBC())
 | 
				
			||||||
  private val jumpEndModeColorWheel = ColorPanel()
 | 
					  private val jumpEndModeColorWheel = ResettableColorPicker(defaults.getJumpEndModeJBC())
 | 
				
			||||||
  private val targetModeColorWheel = ColorPanel()
 | 
					  private val targetModeColorWheel = ResettableColorPicker(defaults.getTargetModeJBC())
 | 
				
			||||||
  private val definitionModeColorWheel = ColorPanel()
 | 
					  private val definitionModeColorWheel = ResettableColorPicker(defaults.getDefinitionModeJBC())
 | 
				
			||||||
  private val textHighlightColorWheel = ColorPanel()
 | 
					  private val textHighlightColorWheel = ResettableColorPicker(defaults.getTextHighlightJBC())
 | 
				
			||||||
  private val tagForegroundColorWheel = ColorPanel()
 | 
					  private val tagForegroundColorWheel = ResettableColorPicker(defaults.getTagForegroundJBC())
 | 
				
			||||||
  private val tagBackgroundColorWheel = ColorPanel()
 | 
					  private val tagBackgroundColorWheel = ResettableColorPicker(defaults.getTagBackgroundJBC())
 | 
				
			||||||
  private val searchWholeFileCheckBox = JBCheckBox()
 | 
					  private val searchWholeFileCheckBox = JBCheckBox()
 | 
				
			||||||
  private val mapToASCIICheckBox = JBCheckBox()
 | 
					  private val mapToASCIICheckBox = JBCheckBox()
 | 
				
			||||||
  private val showSearchNotificationCheckBox = JBCheckBox()
 | 
					  private val showSearchNotificationCheckBox = JBCheckBox()
 | 
				
			||||||
@@ -54,45 +47,40 @@ internal class AceSettingsPanel {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  internal val rootPanel: JPanel = panel {
 | 
					  internal val rootPanel: JPanel = panel {
 | 
				
			||||||
    fun Cell.short(component: JComponent) = component(growPolicy = SHORT_TEXT)
 | 
					    group("Characters and Layout") {
 | 
				
			||||||
    fun Cell.medium(component: JComponent) = component(growPolicy = MEDIUM_TEXT)
 | 
					      row("Allowed characters in tags:") { cell(tagCharsField).columns(COLUMNS_LARGE) }
 | 
				
			||||||
 | 
					      row("Keyboard layout:") { cell(keyboardLayoutCombo).columns(COLUMNS_SHORT) }
 | 
				
			||||||
    titledRow("Characters and Layout") {
 | 
					      row("Keyboard design:") { cell(keyboardLayoutArea).columns(COLUMNS_SHORT) }
 | 
				
			||||||
      row("Allowed characters in tags:") { medium(tagCharsField) }
 | 
					 | 
				
			||||||
      row("Keyboard layout:") { short(keyboardLayoutCombo) }
 | 
					 | 
				
			||||||
      row("Keyboard design:") { short(keyboardLayoutArea) }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    titledRow("Modes") {
 | 
					    group("Modes") {
 | 
				
			||||||
      row("Cycle order:") { cell { cycleModeCombo1() } }
 | 
					      row("Cycle order:") {
 | 
				
			||||||
      row("") {
 | 
					        cell(cycleModeCombo1).columns(10)
 | 
				
			||||||
        cell(isVerticalFlow = true) {
 | 
					        cell(cycleModeCombo2).columns(10)
 | 
				
			||||||
          cycleModeCombo2()
 | 
					        cell(cycleModeCombo3).columns(10)
 | 
				
			||||||
          cycleModeCombo3()
 | 
					        cell(cycleModeCombo4).columns(10)
 | 
				
			||||||
          cycleModeCombo4()
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    titledRow("Colors") {
 | 
					    group("Colors") {
 | 
				
			||||||
      row("Jump mode caret background:") { short(jumpModeColorWheel) }
 | 
					      row("Jump mode caret background:") { cell(jumpModeColorWheel) }
 | 
				
			||||||
      row("Jump to End mode caret background:") { short(jumpEndModeColorWheel) }
 | 
					      row("Jump to End mode caret background:") { cell(jumpEndModeColorWheel) }
 | 
				
			||||||
      row("Target mode caret background:") { short(targetModeColorWheel) }
 | 
					      row("Target mode caret background:") { cell(targetModeColorWheel) }
 | 
				
			||||||
      row("Definition mode caret background:") { short(definitionModeColorWheel) }
 | 
					      row("Definition mode caret background:") { cell(definitionModeColorWheel) }
 | 
				
			||||||
      row("Searched text background:") { short(textHighlightColorWheel) }
 | 
					      row("Searched text background:") { cell(textHighlightColorWheel) }
 | 
				
			||||||
      row("Tag foreground:") { short(tagForegroundColorWheel) }
 | 
					      row("Tag foreground:") { cell(tagForegroundColorWheel) }
 | 
				
			||||||
      row("Tag background:") { short(tagBackgroundColorWheel) }
 | 
					      row("Tag background:") { cell(tagBackgroundColorWheel) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    titledRow("Behavior") {
 | 
					    group("Behavior") {
 | 
				
			||||||
      row { short(searchWholeFileCheckBox.apply { text = "Search whole file" }) }
 | 
					      row { cell(searchWholeFileCheckBox.apply { text = "Search whole file" }) }
 | 
				
			||||||
      row("Minimum typed characters (1-10):") { short(minQueryLengthField) }
 | 
					      row("Minimum typed characters (1-10):") { cell(minQueryLengthField) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    titledRow("Language Settings") {
 | 
					    group("Language Settings") {
 | 
				
			||||||
      row { short(mapToASCIICheckBox.apply { text = "Map unicode to ASCII" }) }
 | 
					      row { cell(mapToASCIICheckBox.apply { text = "Map unicode to ASCII" }) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    titledRow("Visual") {
 | 
					    group("Visual") {
 | 
				
			||||||
      row { short(showSearchNotificationCheckBox.apply { text = "Show hint with search text" }) }
 | 
					      row { cell(showSearchNotificationCheckBox.apply { text = "Show hint with search text" }) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -130,13 +118,13 @@ internal class AceSettingsPanel {
 | 
				
			|||||||
    cycleMode3 = settings.cycleMode3
 | 
					    cycleMode3 = settings.cycleMode3
 | 
				
			||||||
    cycleMode4 = settings.cycleMode4
 | 
					    cycleMode4 = settings.cycleMode4
 | 
				
			||||||
    minQueryLength = settings.minQueryLength.toString()
 | 
					    minQueryLength = settings.minQueryLength.toString()
 | 
				
			||||||
    jumpModeColor = settings.jumpModeColor
 | 
					    jumpModeColor = settings.getJumpModeJBC()
 | 
				
			||||||
    jumpEndModeColor = settings.jumpEndModeColor
 | 
					    jumpEndModeColor = settings.getJumpEndModeJBC()
 | 
				
			||||||
    targetModeColor = settings.targetModeColor
 | 
					    targetModeColor = settings.getTargetModeJBC()
 | 
				
			||||||
    definitionModeColor = settings.definitionModeColor
 | 
					    definitionModeColor = settings.getDefinitionModeJBC()
 | 
				
			||||||
    textHighlightColor = settings.textHighlightColor
 | 
					    textHighlightColor = settings.getTextHighlightJBC()
 | 
				
			||||||
    tagForegroundColor = settings.tagForegroundColor
 | 
					    tagForegroundColor = settings.getTagForegroundJBC()
 | 
				
			||||||
    tagBackgroundColor = settings.tagBackgroundColor
 | 
					    tagBackgroundColor = settings.getTagBackgroundJBC()
 | 
				
			||||||
    searchWholeFile = settings.searchWholeFile
 | 
					    searchWholeFile = settings.searchWholeFile
 | 
				
			||||||
    mapToASCII = settings.mapToASCII
 | 
					    mapToASCII = settings.mapToASCII
 | 
				
			||||||
    showSearchNotification = settings.showSearchNotification
 | 
					    showSearchNotification = settings.showSearchNotification
 | 
				
			||||||
@@ -147,8 +135,8 @@ internal class AceSettingsPanel {
 | 
				
			|||||||
  private operator fun JTextComponent.getValue(a: AceSettingsPanel, p: KProperty<*>) = text.lowercase()
 | 
					  private operator fun JTextComponent.getValue(a: AceSettingsPanel, p: KProperty<*>) = text.lowercase()
 | 
				
			||||||
  private operator fun JTextComponent.setValue(a: AceSettingsPanel, p: KProperty<*>, s: String) = setText(s)
 | 
					  private operator fun JTextComponent.setValue(a: AceSettingsPanel, p: KProperty<*>, s: String) = setText(s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private operator fun ColorPanel.getValue(a: AceSettingsPanel, p: KProperty<*>) = selectedColor
 | 
					  private operator fun ResettableColorPicker.getValue(a: AceSettingsPanel, p: KProperty<*>) = getSelectedColor()
 | 
				
			||||||
  private operator fun ColorPanel.setValue(a: AceSettingsPanel, p: KProperty<*>, c: Color?) = setSelectedColor(c)
 | 
					  private operator fun ResettableColorPicker.setValue(a: AceSettingsPanel, p: KProperty<*>, c: Color?) = setSelectedColor(c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private operator fun JCheckBox.getValue(a: AceSettingsPanel, p: KProperty<*>) = isSelected
 | 
					  private operator fun JCheckBox.getValue(a: AceSettingsPanel, p: KProperty<*>) = isSelected
 | 
				
			||||||
  private operator fun JCheckBox.setValue(a: AceSettingsPanel, p: KProperty<*>, selected: Boolean) = setSelected(selected)
 | 
					  private operator fun JCheckBox.setValue(a: AceSettingsPanel, p: KProperty<*>, selected: Boolean) = setSelected(selected)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								src/main/kotlin/org/acejump/config/ResettableColorPicker.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/main/kotlin/org/acejump/config/ResettableColorPicker.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					package org.acejump.config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.intellij.icons.AllIcons
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.*
 | 
				
			||||||
 | 
					import com.intellij.openapi.actionSystem.impl.ActionButton
 | 
				
			||||||
 | 
					import com.intellij.ui.ColorPanel
 | 
				
			||||||
 | 
					import com.intellij.ui.JBColor
 | 
				
			||||||
 | 
					import java.awt.*
 | 
				
			||||||
 | 
					import javax.swing.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal class ResettableColorPicker(private val defaultColor: JBColor) : JPanel(FlowLayout()) {
 | 
				
			||||||
 | 
					  private val resetAction = object : AnAction({ "Reset to Default" }, AllIcons.General.Reset) {
 | 
				
			||||||
 | 
					    override fun getActionUpdateThread(): ActionUpdateThread {
 | 
				
			||||||
 | 
					      return ActionUpdateThread.EDT
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    override fun update(e: AnActionEvent) {
 | 
				
			||||||
 | 
					      e.presentation.isEnabled = colorPanel.selectedColor != defaultColor
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    override fun actionPerformed(e: AnActionEvent) {
 | 
				
			||||||
 | 
					      setSelectedColor(defaultColor)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  private val colorPanel = ColorPanel()
 | 
				
			||||||
 | 
					  private val resetButton = ActionButton(resetAction, null, ActionPlaces.UNKNOWN, ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE)
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  init {
 | 
				
			||||||
 | 
					    add(colorPanel)
 | 
				
			||||||
 | 
					    add(resetButton)
 | 
				
			||||||
 | 
					    setSelectedColor(defaultColor)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    colorPanel.addActionListener {
 | 
				
			||||||
 | 
					      resetButton.update()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  fun getSelectedColor(): Color? {
 | 
				
			||||||
 | 
					    return colorPanel.selectedColor
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  fun setSelectedColor(color: Color?) {
 | 
				
			||||||
 | 
					    colorPanel.selectedColor = color
 | 
				
			||||||
 | 
					    resetButton.update()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -61,13 +61,12 @@ enum class JumpMode {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  DECLARATION;
 | 
					  DECLARATION;
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  val caretColor: Color
 | 
					  val caretColor: Color get() = when (this) {
 | 
				
			||||||
    get() = when (this) {
 | 
					    DISABLED    -> AbstractColorsScheme.INHERITED_COLOR_MARKER
 | 
				
			||||||
    JUMP        -> AceConfig.jumpModeColor
 | 
					    JUMP        -> AceConfig.jumpModeColor
 | 
				
			||||||
    JUMP_END    -> AceConfig.jumpEndModeColor
 | 
					    JUMP_END    -> AceConfig.jumpEndModeColor
 | 
				
			||||||
      DECLARATION -> AceConfig.definitionModeColor
 | 
					 | 
				
			||||||
    TARGET      -> AceConfig.targetModeColor
 | 
					    TARGET      -> AceConfig.targetModeColor
 | 
				
			||||||
      DISABLED    -> AbstractColorsScheme.INHERITED_COLOR_MARKER
 | 
					    DECLARATION -> AceConfig.definitionModeColor
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  override fun toString() = when (this) {
 | 
					  override fun toString() = when (this) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,10 @@ enum class KeyLayout(internal val rows: Array<String>, priority: String) {
 | 
				
			|||||||
  QWERTZ(arrayOf("1234567890", "qwertzuiop", "asdfghjkl", "yxcvbnm"), priority = "fjghdkslavncmbxyrutzeiwoqp5849673210"),
 | 
					  QWERTZ(arrayOf("1234567890", "qwertzuiop", "asdfghjkl", "yxcvbnm"), priority = "fjghdkslavncmbxyrutzeiwoqp5849673210"),
 | 
				
			||||||
  QGMLWY(arrayOf("1234567890", "qgmlwyfub", "dstnriaeoh", "zxcvjkp"), priority = "naterisodhvkcpjxzlfmuwygbq5849673210"),
 | 
					  QGMLWY(arrayOf("1234567890", "qgmlwyfub", "dstnriaeoh", "zxcvjkp"), priority = "naterisodhvkcpjxzlfmuwygbq5849673210"),
 | 
				
			||||||
  QGMLWB(arrayOf("1234567890", "qgmlwbyuv", "dstnriaeoh", "zxcfjkp"), priority = "naterisodhfkcpjxzlymuwbgvq5849673210"),
 | 
					  QGMLWB(arrayOf("1234567890", "qgmlwbyuv", "dstnriaeoh", "zxcfjkp"), priority = "naterisodhfkcpjxzlymuwbgvq5849673210"),
 | 
				
			||||||
  NORMAN(arrayOf("1234567890", "qwdfkjurl", "asetgynioh", "zxcvbpm"), priority = "tneigysoahbvpcmxzjkufrdlwq5849673210");
 | 
					  NORMAN(arrayOf("1234567890", "qwdfkjurl", "asetgynioh", "zxcvbpm"), priority = "tneigysoahbvpcmxzjkufrdlwq5849673210"),
 | 
				
			||||||
 | 
					  AZERTY(arrayOf("1234567890", "azertyuiop", "qsdfghjklm", "wxcvbn"), priority = "fjghdkslqvncmbxwrutyeizoap5849673210"),
 | 
				
			||||||
 | 
					  CANARY(arrayOf("1234567890", "wlypbzfou", "crstgmneia", "qjvdkxh"), priority = "tngmseracidxvhkjqpfbzyoluw5849673210"),
 | 
				
			||||||
 | 
					  ENGRAM(arrayOf("1234567890", "byouldwvz", "cieahtsnq", "gxjkrmfp"), priority = "ahetiscnkrjmodulywxfgpbvqz3847295610");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  internal val allChars = rows.joinToString("").toCharArray().apply(CharArray::sort).joinToString("")
 | 
					  internal val allChars = rows.joinToString("").toCharArray().apply(CharArray::sort).joinToString("")
 | 
				
			||||||
  internal val allPriorities = priority.mapIndexed { index, char -> char to index }.toMap()
 | 
					  internal val allPriorities = priority.mapIndexed { index, char -> char to index }.toMap()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
package org.acejump.search
 | 
					package org.acejump.search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class Pattern(val regex: String) {
 | 
					enum class Pattern(val regex: String) {
 | 
				
			||||||
  LINE_STARTS("^.|^\\n"),
 | 
					  LINE_STARTS("^.|^\\n|(?<!.)\\Z"),
 | 
				
			||||||
  LINE_ENDS("\\n|\\Z"),
 | 
					  LINE_ENDS("\\n|\\Z"),
 | 
				
			||||||
  LINE_INDENTS("[^\\s].*|^\\n"),
 | 
					  LINE_INDENTS("[^\\s].*|^\\n|(?<!.)\\Z"),
 | 
				
			||||||
  LINE_ALL_MARKS(LINE_ENDS.regex + "|" + LINE_STARTS.regex + "|" + LINE_INDENTS.regex),
 | 
					  LINE_ALL_MARKS(listOf(LINE_ENDS, LINE_STARTS, LINE_INDENTS).flatMap { it.regex.split("|") }.distinct().joinToString("|")),
 | 
				
			||||||
  ALL_WORDS("(?<=[^a-zA-Z0-9_]|\\A)[a-zA-Z0-9_]");
 | 
					  ALL_WORDS("(?<=[^a-zA-Z0-9_]|\\A)[a-zA-Z0-9_]");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ package org.acejump.search
 | 
				
			|||||||
import com.intellij.openapi.editor.Editor
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
import it.unimi.dsi.fastutil.ints.IntArrayList
 | 
					import it.unimi.dsi.fastutil.ints.IntArrayList
 | 
				
			||||||
import org.acejump.boundaries.Boundaries
 | 
					import org.acejump.boundaries.Boundaries
 | 
				
			||||||
 | 
					import org.acejump.boundaries.EditorOffsetCache
 | 
				
			||||||
import org.acejump.immutableText
 | 
					import org.acejump.immutableText
 | 
				
			||||||
import org.acejump.isWordPart
 | 
					import org.acejump.isWordPart
 | 
				
			||||||
import org.acejump.matchesAt
 | 
					import org.acejump.matchesAt
 | 
				
			||||||
@@ -12,7 +13,6 @@ import org.acejump.matchesAt
 | 
				
			|||||||
 * previous results when the user [type]s a character.
 | 
					 * previous results when the user [type]s a character.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
internal class SearchProcessor private constructor(
 | 
					internal class SearchProcessor private constructor(
 | 
				
			||||||
  private val editors: List<Editor>,
 | 
					 | 
				
			||||||
  query: SearchQuery,
 | 
					  query: SearchQuery,
 | 
				
			||||||
  results: MutableMap<Editor, IntArrayList>
 | 
					  results: MutableMap<Editor, IntArrayList>
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
@@ -24,14 +24,15 @@ internal class SearchProcessor private constructor(
 | 
				
			|||||||
      SearchProcessor(editors, SearchQuery.RegularExpression(pattern), boundaries)
 | 
					      SearchProcessor(editors, SearchQuery.RegularExpression(pattern), boundaries)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  private constructor(editors: List<Editor>, query: SearchQuery, boundaries: Boundaries) : this(editors, query, mutableMapOf()) {
 | 
					  private constructor(editors: List<Editor>, query: SearchQuery, boundaries: Boundaries) : this(query, mutableMapOf()) {
 | 
				
			||||||
    val regex = query.toRegex()
 | 
					    val regex = query.toRegex()
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (regex != null) {
 | 
					    if (regex != null) {
 | 
				
			||||||
      for (editor in editors) {
 | 
					      for (editor in editors) {
 | 
				
			||||||
 | 
					        val cache = EditorOffsetCache.new()
 | 
				
			||||||
        val offsets = IntArrayList()
 | 
					        val offsets = IntArrayList()
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        val offsetRange = boundaries.getOffsetRange(editor)
 | 
					        val offsetRange = boundaries.getOffsetRange(editor, cache)
 | 
				
			||||||
        var result = regex.find(editor.immutableText, offsetRange.first)
 | 
					        var result = regex.find(editor.immutableText, offsetRange.first)
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        while (result != null) {
 | 
					        while (result != null) {
 | 
				
			||||||
@@ -43,7 +44,7 @@ internal class SearchProcessor private constructor(
 | 
				
			|||||||
          if (highlightEnd > offsetRange.last) {
 | 
					          if (highlightEnd > offsetRange.last) {
 | 
				
			||||||
            break
 | 
					            break
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          else if (boundaries.isOffsetInside(editor, index)) {
 | 
					          else if (boundaries.isOffsetInside(editor, index, cache)) {
 | 
				
			||||||
            offsets.add(index)
 | 
					            offsets.add(index)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          
 | 
					          
 | 
				
			||||||
@@ -70,7 +71,7 @@ internal class SearchProcessor private constructor(
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  fun type(char: Char, tagger: Tagger): Boolean {
 | 
					  fun type(char: Char, tagger: Tagger): Boolean {
 | 
				
			||||||
    val newQuery = query.rawText + char
 | 
					    val newQuery = query.rawText + char
 | 
				
			||||||
    val canMatchTag = tagger.canQueryMatchAnyTag(newQuery)
 | 
					    val canMatchTag = tagger.canQueryMatchAnyVisibleTag(newQuery)
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // If the typed character is not compatible with any existing tag or as
 | 
					    // If the typed character is not compatible with any existing tag or as
 | 
				
			||||||
    // a continuation of any previous occurrence, reject the query change
 | 
					    // a continuation of any previous occurrence, reject the query change
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,7 +51,7 @@ internal sealed class SearchQuery {
 | 
				
			|||||||
  class RegularExpression(private var pattern: String): SearchQuery() {
 | 
					  class RegularExpression(private var pattern: String): SearchQuery() {
 | 
				
			||||||
    override val rawText = ""
 | 
					    override val rawText = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun getHighlightLength(text: CharSequence, offset: Int) = 1
 | 
					    override fun getHighlightLength(text: CharSequence, offset: Int) = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun toRegex(): Regex =
 | 
					    override fun toRegex(): Regex =
 | 
				
			||||||
      Regex(pattern, setOf(RegexOption.MULTILINE, RegexOption.IGNORE_CASE))
 | 
					      Regex(pattern, setOf(RegexOption.MULTILINE, RegexOption.IGNORE_CASE))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ import org.acejump.immutableText
 | 
				
			|||||||
import org.acejump.input.KeyLayoutCache
 | 
					import org.acejump.input.KeyLayoutCache
 | 
				
			||||||
import org.acejump.isWordPart
 | 
					import org.acejump.isWordPart
 | 
				
			||||||
import org.acejump.wordEndPlus
 | 
					import org.acejump.wordEndPlus
 | 
				
			||||||
import java.util.*
 | 
					import java.util.IdentityHashMap
 | 
				
			||||||
import kotlin.math.max
 | 
					import kotlin.math.max
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -89,6 +89,10 @@ internal class Solver private constructor(
 | 
				
			|||||||
      while (iter.hasNext()) {
 | 
					      while (iter.hasNext()) {
 | 
				
			||||||
        val site = iter.nextInt()
 | 
					        val site = iter.nextInt()
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        if (editor.foldingModel.isOffsetCollapsed(site)) {
 | 
				
			||||||
 | 
					          continue
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        for ((firstLetter, tags) in tagsByFirstLetter.entries) {
 | 
					        for ((firstLetter, tags) in tagsByFirstLetter.entries) {
 | 
				
			||||||
          if (canTagBeginWithChar(editor, site, firstLetter)) {
 | 
					          if (canTagBeginWithChar(editor, site, firstLetter)) {
 | 
				
			||||||
            for (tag in tags) {
 | 
					            for (tag in tags) {
 | 
				
			||||||
@@ -187,6 +191,9 @@ internal class Solver private constructor(
 | 
				
			|||||||
    val chars = editor.immutableText
 | 
					    val chars = editor.immutableText
 | 
				
			||||||
    val left = max(0, site + queryLength - 1)
 | 
					    val left = max(0, site + queryLength - 1)
 | 
				
			||||||
    val right = chars.wordEndPlus(site)
 | 
					    val right = chars.wordEndPlus(site)
 | 
				
			||||||
 | 
					    if (right >= chars.length) {
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
    val builder = StringBuilder(1 + right - left)
 | 
					    val builder = StringBuilder(1 + right - left)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,8 @@
 | 
				
			|||||||
package org.acejump.search
 | 
					package org.acejump.search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.intellij.openapi.editor.Editor
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
 | 
					import org.acejump.getView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
data class Tag(val editor: Editor, val offset: Int)
 | 
					data class Tag(val editor: Editor, val offset: Int) {
 | 
				
			||||||
 | 
					  fun isVisible() = offset in editor.getView() && !editor.foldingModel.isOffsetCollapsed(offset)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,13 +5,10 @@ import com.google.common.collect.HashBiMap
 | 
				
			|||||||
import com.intellij.openapi.editor.Editor
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
import it.unimi.dsi.fastutil.ints.IntArrayList
 | 
					import it.unimi.dsi.fastutil.ints.IntArrayList
 | 
				
			||||||
import it.unimi.dsi.fastutil.ints.IntList
 | 
					import it.unimi.dsi.fastutil.ints.IntList
 | 
				
			||||||
import org.acejump.ExternalUsage
 | 
					import org.acejump.*
 | 
				
			||||||
import org.acejump.boundaries.EditorOffsetCache
 | 
					import org.acejump.boundaries.EditorOffsetCache
 | 
				
			||||||
import org.acejump.boundaries.StandardBoundaries.VISIBLE_ON_SCREEN
 | 
					import org.acejump.boundaries.StandardBoundaries.VISIBLE_ON_SCREEN
 | 
				
			||||||
import org.acejump.immutableText
 | 
					 | 
				
			||||||
import org.acejump.input.KeyLayoutCache.allPossibleTags
 | 
					import org.acejump.input.KeyLayoutCache.allPossibleTags
 | 
				
			||||||
import org.acejump.isWordPart
 | 
					 | 
				
			||||||
import org.acejump.matchesAt
 | 
					 | 
				
			||||||
import org.acejump.view.TagMarker
 | 
					import org.acejump.view.TagMarker
 | 
				
			||||||
import java.util.AbstractMap.SimpleImmutableEntry
 | 
					import java.util.AbstractMap.SimpleImmutableEntry
 | 
				
			||||||
import kotlin.collections.component1
 | 
					import kotlin.collections.component1
 | 
				
			||||||
@@ -143,23 +140,22 @@ internal class Tagger(private val editors: List<Editor>) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  private infix fun Map.Entry<String, Tag>.solves(query: String): Boolean {
 | 
					  private infix fun Map.Entry<String, Tag>.solves(query: String): Boolean =
 | 
				
			||||||
    return query.endsWith(key, true) && isTagCompatibleWithQuery(key, value, query)
 | 
					    query.endsWith(key, true) && isTagCompatibleWithQuery(key, value, query)
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  private fun isTagCompatibleWithQuery(marker: String, tag: Tag, query: String): Boolean {
 | 
					  private fun isTagCompatibleWithQuery(marker: String, tag: Tag, query: String): Boolean =
 | 
				
			||||||
    return tag.editor.immutableText.matchesAt(tag.offset, getPlaintextPortion(query, marker), ignoreCase = true)
 | 
					    tag.editor.immutableText.matchesAt(tag.offset, getPlaintextPortion(query, marker), ignoreCase = true)
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  fun isQueryCompatibleWithTagAt(query: String, tag: Tag): Boolean {
 | 
					  fun isQueryCompatibleWithTagAt(query: String, tag: Tag): Boolean =
 | 
				
			||||||
    return tagMap.inverse()[tag].let { it != null && isTagCompatibleWithQuery(it, tag, query) }
 | 
					    tagMap.inverse()[tag].let { it != null && isTagCompatibleWithQuery(it, tag, query) }
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  fun canQueryMatchAnyTag(query: String): Boolean {
 | 
					  fun canQueryMatchAnyVisibleTag(query: String): Boolean =
 | 
				
			||||||
    return tagMap.any { (tag, offset) ->
 | 
					    tagMap.any { (label, tag) ->
 | 
				
			||||||
      val tagPortion = getTagPortion(query, tag)
 | 
					      val tagPortion = getTagPortion(query, label)
 | 
				
			||||||
      tagPortion.isNotEmpty() && tag.startsWith(tagPortion, ignoreCase = true) && isTagCompatibleWithQuery(tag, offset, query)
 | 
					      tagPortion.isNotEmpty()
 | 
				
			||||||
    }
 | 
					        && label.startsWith(tagPortion, ignoreCase = true)
 | 
				
			||||||
 | 
					        && isTagCompatibleWithQuery(label, tag, query)
 | 
				
			||||||
 | 
					        && tag.isVisible()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private fun removeResultsWithOverlappingTags(editor: Editor, offsets: IntList) {
 | 
					  private fun removeResultsWithOverlappingTags(editor: Editor, offsets: IntList) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,6 @@ import com.intellij.openapi.editor.Editor
 | 
				
			|||||||
internal data class EditorSettings(
 | 
					internal data class EditorSettings(
 | 
				
			||||||
  private val isBlockCursor: Boolean,
 | 
					  private val isBlockCursor: Boolean,
 | 
				
			||||||
  private val isBlinkCaret: Boolean,
 | 
					  private val isBlinkCaret: Boolean,
 | 
				
			||||||
  private val isReadOnly: Boolean
 | 
					 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
  companion object {
 | 
					  companion object {
 | 
				
			||||||
    fun setup(editor: Editor): EditorSettings {
 | 
					    fun setup(editor: Editor): EditorSettings {
 | 
				
			||||||
@@ -20,12 +19,10 @@ internal data class EditorSettings(
 | 
				
			|||||||
      val original = EditorSettings(
 | 
					      val original = EditorSettings(
 | 
				
			||||||
        isBlockCursor = settings.isBlockCursor,
 | 
					        isBlockCursor = settings.isBlockCursor,
 | 
				
			||||||
        isBlinkCaret = settings.isBlinkCaret,
 | 
					        isBlinkCaret = settings.isBlinkCaret,
 | 
				
			||||||
        isReadOnly = !document.isWritable
 | 
					 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      settings.isBlockCursor = true
 | 
					      settings.isBlockCursor = true
 | 
				
			||||||
      settings.isBlinkCaret = false
 | 
					      settings.isBlinkCaret = false
 | 
				
			||||||
      document.setReadOnly(true)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return original
 | 
					      return original
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -37,6 +34,5 @@ internal data class EditorSettings(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    settings.isBlockCursor = isBlockCursor
 | 
					    settings.isBlockCursor = isBlockCursor
 | 
				
			||||||
    settings.isBlinkCaret = isBlinkCaret
 | 
					    settings.isBlinkCaret = isBlinkCaret
 | 
				
			||||||
    document.setReadOnly(isReadOnly)
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ import com.intellij.openapi.editor.event.CaretEvent
 | 
				
			|||||||
import com.intellij.openapi.editor.event.CaretListener
 | 
					import com.intellij.openapi.editor.event.CaretListener
 | 
				
			||||||
import org.acejump.boundaries.EditorOffsetCache
 | 
					import org.acejump.boundaries.EditorOffsetCache
 | 
				
			||||||
import org.acejump.boundaries.StandardBoundaries.VISIBLE_ON_SCREEN
 | 
					import org.acejump.boundaries.StandardBoundaries.VISIBLE_ON_SCREEN
 | 
				
			||||||
 | 
					import org.acejump.read
 | 
				
			||||||
import java.awt.Graphics
 | 
					import java.awt.Graphics
 | 
				
			||||||
import java.awt.Graphics2D
 | 
					import java.awt.Graphics2D
 | 
				
			||||||
import java.awt.Rectangle
 | 
					import java.awt.Rectangle
 | 
				
			||||||
@@ -53,7 +54,7 @@ internal class TagCanvas(private val editor: Editor): JComponent(), CaretListene
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun paint(g: Graphics) =
 | 
					  override fun paint(g: Graphics) =
 | 
				
			||||||
    if (!markers.isNullOrEmpty()) super.paint(g) else Unit
 | 
					    read { if (!markers.isNullOrEmpty()) super.paint(g) else Unit }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun paintChildren(g: Graphics) {
 | 
					  override fun paintChildren(g: Graphics) {
 | 
				
			||||||
    super.paintChildren(g)
 | 
					    super.paintChildren(g)
 | 
				
			||||||
@@ -66,6 +67,7 @@ internal class TagCanvas(private val editor: Editor): JComponent(), CaretListene
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    val cache = EditorOffsetCache.new()
 | 
					    val cache = EditorOffsetCache.new()
 | 
				
			||||||
    val viewRange = VISIBLE_ON_SCREEN.getOffsetRange(editor, cache)
 | 
					    val viewRange = VISIBLE_ON_SCREEN.getOffsetRange(editor, cache)
 | 
				
			||||||
 | 
					    val foldingModel = editor.foldingModel
 | 
				
			||||||
    val occupied = mutableListOf<Rectangle>()
 | 
					    val occupied = mutableListOf<Rectangle>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // If there is a tag at the caret location, prioritize its rendering over
 | 
					    // If there is a tag at the caret location, prioritize its rendering over
 | 
				
			||||||
@@ -81,8 +83,9 @@ internal class TagCanvas(private val editor: Editor): JComponent(), CaretListene
 | 
				
			|||||||
    val caretMarker = markers.find { it.offsetL == caretOffset || it.offsetR == caretOffset }
 | 
					    val caretMarker = markers.find { it.offsetL == caretOffset || it.offsetR == caretOffset }
 | 
				
			||||||
    caretMarker?.paint(g, editor, cache, font, occupied)
 | 
					    caretMarker?.paint(g, editor, cache, font, occupied)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (marker in markers)
 | 
					    for (marker in markers) {
 | 
				
			||||||
      if (marker.isOffsetInRange(viewRange) && marker !== caretMarker)
 | 
					      if (marker.isOffsetInRange(viewRange) && !foldingModel.isOffsetCollapsed(marker.offsetL) && marker !== caretMarker)
 | 
				
			||||||
        marker.paint(g, editor, cache, font, occupied)
 | 
					        marker.paint(g, editor, cache, font, occupied)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -81,6 +81,10 @@ class TagMarker(
 | 
				
			|||||||
      g.color = AceConfig.tagForegroundColor
 | 
					      g.color = AceConfig.tagForegroundColor
 | 
				
			||||||
      g.drawString(text, x, y)
 | 
					      g.drawString(text, x, y)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private fun isLineEnding(char: Char): Boolean {
 | 
				
			||||||
 | 
					      return char == '\n' || char == '\r'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
@@ -106,7 +110,7 @@ class TagMarker(
 | 
				
			|||||||
  private fun alignTag(editor: Editor, cache: EditorOffsetCache, font: TagFont, occupied: List<Rectangle>): Rectangle? {
 | 
					  private fun alignTag(editor: Editor, cache: EditorOffsetCache, font: TagFont, occupied: List<Rectangle>): Rectangle? {
 | 
				
			||||||
    val boundaries = VISIBLE_ON_SCREEN
 | 
					    val boundaries = VISIBLE_ON_SCREEN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (hasSpaceRight || offsetL == 0 || editor.immutableText[offsetL - 1].let { it == '\n' || it == '\r' }) {
 | 
					    if (hasSpaceRight || offsetL !in 1 until editor.document.textLength || isLineEnding(editor.immutableText[offsetL - 1])) {
 | 
				
			||||||
      val rectR = createRightAlignedTagRect(editor, cache, font)
 | 
					      val rectR = createRightAlignedTagRect(editor, cache, font)
 | 
				
			||||||
      return rectR.takeIf { boundaries.isOffsetInside(editor, offsetR, cache) && occupied.none(rectR::intersects) }
 | 
					      return rectR.takeIf { boundaries.isOffsetInside(editor, offsetR, cache) && occupied.none(rectR::intersects) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -124,7 +128,15 @@ class TagMarker(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  private fun createRightAlignedTagRect(editor: Editor, cache: EditorOffsetCache, font: TagFont): Rectangle {
 | 
					  private fun createRightAlignedTagRect(editor: Editor, cache: EditorOffsetCache, font: TagFont): Rectangle {
 | 
				
			||||||
    val pos = cache.offsetToXY(editor, offsetR)
 | 
					    val pos = cache.offsetToXY(editor, offsetR)
 | 
				
			||||||
    val shift = font.editorFontMetrics.charWidth(editor.immutableText[offsetR]) + (font.tagCharWidth * shiftR)
 | 
					  
 | 
				
			||||||
 | 
					    val char = if (offsetR >= editor.document.textLength)
 | 
				
			||||||
 | 
					      ' ' // Use the width of a space on the last line.
 | 
				
			||||||
 | 
					    else editor.immutableText[offsetR].let {
 | 
				
			||||||
 | 
					      // Use the width of a space on empty lines.
 | 
				
			||||||
 | 
					      if (isLineEnding(it)) ' ' else it
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    val shift = font.editorFontMetrics.charWidth(char) + (font.tagCharWidth * shiftR)
 | 
				
			||||||
    return Rectangle(pos.x + shift, pos.y, (font.tagCharWidth * length) + 4, font.lineHeight)
 | 
					    return Rectangle(pos.x + shift, pos.y, (font.tagCharWidth * length) + 4, font.lineHeight)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,8 @@ import com.intellij.openapi.editor.colors.EditorFontType
 | 
				
			|||||||
import com.intellij.openapi.editor.markup.*
 | 
					import com.intellij.openapi.editor.markup.*
 | 
				
			||||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea.EXACT_RANGE
 | 
					import com.intellij.openapi.editor.markup.HighlighterTargetArea.EXACT_RANGE
 | 
				
			||||||
import com.intellij.ui.*
 | 
					import com.intellij.ui.*
 | 
				
			||||||
 | 
					import com.intellij.ui.util.preferredHeight
 | 
				
			||||||
 | 
					import com.intellij.util.DocumentUtil
 | 
				
			||||||
import com.intellij.util.ui.*
 | 
					import com.intellij.util.ui.*
 | 
				
			||||||
import it.unimi.dsi.fastutil.ints.IntList
 | 
					import it.unimi.dsi.fastutil.ints.IntList
 | 
				
			||||||
import org.acejump.*
 | 
					import org.acejump.*
 | 
				
			||||||
@@ -31,7 +33,7 @@ internal class TextHighlighter {
 | 
				
			|||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Label for the search notification.
 | 
					   * Label for the search notification.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  private class NotificationLabel constructor(text: String?): JLabel(text) {
 | 
					  private class NotificationLabel(text: String?): JLabel(text) {
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
      background = HintUtil.getInformationColor()
 | 
					      background = HintUtil.getInformationColor()
 | 
				
			||||||
      foreground = JBColor.foreground()
 | 
					      foreground = JBColor.foreground()
 | 
				
			||||||
@@ -61,9 +63,7 @@ internal class TextHighlighter {
 | 
				
			|||||||
      val modifications = (highlights?.size ?: 0) + offsets.size
 | 
					      val modifications = (highlights?.size ?: 0) + offsets.size
 | 
				
			||||||
      val enableBulkEditing = modifications > 1000
 | 
					      val enableBulkEditing = modifications > 1000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      try {
 | 
					      DocumentUtil.executeInBulk(document, enableBulkEditing) {
 | 
				
			||||||
        if (enableBulkEditing) document.isInBulkUpdate = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        highlights?.forEach(markup::removeHighlighter)
 | 
					        highlights?.forEach(markup::removeHighlighter)
 | 
				
			||||||
        previousHighlights[editor] = Array(offsets.size) { index ->
 | 
					        previousHighlights[editor] = Array(offsets.size) { index ->
 | 
				
			||||||
          val start = offsets.getInt(index)
 | 
					          val start = offsets.getInt(index)
 | 
				
			||||||
@@ -72,8 +72,6 @@ internal class TextHighlighter {
 | 
				
			|||||||
          markup.addRangeHighlighter(start, end, LAYER, null, EXACT_RANGE)
 | 
					          markup.addRangeHighlighter(start, end, LAYER, null, EXACT_RANGE)
 | 
				
			||||||
            .apply { customRenderer = renderer }
 | 
					            .apply { customRenderer = renderer }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } finally {
 | 
					 | 
				
			||||||
        if (enableBulkEditing) document.isInBulkUpdate = false
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -96,22 +94,21 @@ internal class TextHighlighter {
 | 
				
			|||||||
    previousHint?.hide()
 | 
					    previousHint?.hide()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // add notification hint to first editor
 | 
					    // add notification hint to first editor
 | 
				
			||||||
    results.keys.first().let {
 | 
					    val editor = results.keys.first()
 | 
				
			||||||
      val component: JComponent = it.component
 | 
					    val component: JComponent = editor.component
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      val label1: JLabel = NotificationLabel(" " +
 | 
					    val label1 = NotificationLabel(" $jumpMode Mode:")
 | 
				
			||||||
        CodeInsightBundle.message("incremental.search.tooltip.prefix"))
 | 
					      .apply { font = UIUtil.getLabelFont().deriveFont(Font.BOLD) }
 | 
				
			||||||
      label1.font = UIUtil.getLabelFont().deriveFont(Font.BOLD)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val queryText = " " +
 | 
					    val queryText = " " +
 | 
				
			||||||
        if (query is SearchQuery.RegularExpression) query.toRegex().toString()
 | 
					      (if (query is SearchQuery.RegularExpression) query.toRegex().toString()
 | 
				
			||||||
        else query.rawText[0] + query.rawText.drop(1).lowercase()
 | 
					      else query.rawText[0] + query.rawText.drop(1).lowercase()) + "   "
 | 
				
			||||||
    val label2 = NotificationLabel(queryText)
 | 
					    val label2 = NotificationLabel(queryText)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val label3 = NotificationLabel(
 | 
					    val label3 = NotificationLabel(
 | 
				
			||||||
      "Found ${results.values.flatMap { it.asIterable() }.size}" +
 | 
					      "Found ${results.values.flatMap { it.asIterable() }.size}" +
 | 
				
			||||||
        " results in ${results.keys.size}" +
 | 
					        " results in ${results.keys.size}" +
 | 
				
			||||||
        " editor" + if(1 != results.keys.size) "s" else "."
 | 
					        " editor" + if (1 != results.keys.size) "s" else ". "
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val panel = JPanel(BorderLayout()).apply {
 | 
					    val panel = JPanel(BorderLayout()).apply {
 | 
				
			||||||
@@ -119,35 +116,37 @@ internal class TextHighlighter {
 | 
				
			|||||||
      add(label2, BorderLayout.CENTER)
 | 
					      add(label2, BorderLayout.CENTER)
 | 
				
			||||||
      add(label3, BorderLayout.EAST)
 | 
					      add(label3, BorderLayout.EAST)
 | 
				
			||||||
      border = BorderFactory.createLineBorder(
 | 
					      border = BorderFactory.createLineBorder(
 | 
				
			||||||
          if (jumpMode == JumpMode.DISABLED) Color.BLACK else jumpMode.caretColor
 | 
					        if (jumpMode == JumpMode.DISABLED) JBColor.BLACK else jumpMode.caretColor
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        preferredSize = Dimension(it.contentComponent.width +
 | 
					      preferredHeight = label1.preferredSize.height + 10
 | 
				
			||||||
          label1.preferredSize.width, preferredSize.height)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val hint = LightweightHint(panel)
 | 
					    val hint = LightweightHint(panel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val x = SwingUtilities.convertPoint(component, 0, 0, component).x
 | 
					    val x = SwingUtilities.convertPoint(component, 0, 0, component).x
 | 
				
			||||||
    val y: Int = -hint.component.preferredSize.height
 | 
					    val y: Int = -hint.component.preferredSize.height
 | 
				
			||||||
      val p = SwingUtilities.convertPoint(component, x, y,
 | 
					    val p = SwingUtilities.convertPoint(
 | 
				
			||||||
        component.rootPane.layeredPane)
 | 
					      component, x, y,
 | 
				
			||||||
 | 
					      component.rootPane.layeredPane
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HintManagerImpl.getInstanceImpl().showEditorHint(
 | 
					    HintManagerImpl.getInstanceImpl().showEditorHint(
 | 
				
			||||||
      hint,
 | 
					      hint,
 | 
				
			||||||
        it,
 | 
					      editor,
 | 
				
			||||||
      p,
 | 
					      p,
 | 
				
			||||||
      HIDE_BY_ESCAPE or HIDE_BY_TEXT_CHANGE,
 | 
					      HIDE_BY_ESCAPE or HIDE_BY_TEXT_CHANGE,
 | 
				
			||||||
      0,
 | 
					      0,
 | 
				
			||||||
      false,
 | 
					      false,
 | 
				
			||||||
        HintHint(it, p).setAwtTooltip(false)
 | 
					      HintHint(editor, p).setAwtTooltip(false)
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    previousHint = hint
 | 
					    previousHint = hint
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun reset() {
 | 
					  fun reset() {
 | 
				
			||||||
    previousHighlights.keys.forEach { it.markupModel.removeAllHighlighters() }
 | 
					    previousHighlights.forEach { (editor, highlighters) ->
 | 
				
			||||||
 | 
					      highlighters.forEach(editor.markupModel::removeHighlighter)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    previousHighlights.clear()
 | 
					    previousHighlights.clear()
 | 
				
			||||||
    previousHint?.hide()
 | 
					    previousHint?.hide()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,27 +20,38 @@
 | 
				
			|||||||
                             id="preferences.AceConfigurable" dynamic="true"/>
 | 
					                             id="preferences.AceConfigurable" dynamic="true"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <editorActionHandler action="EditorEscape" order="first"
 | 
					    <editorActionHandler action="EditorEscape" order="first"
 | 
				
			||||||
                         implementationClass="org.acejump.action.AceEditorAction$Reset"/>
 | 
					                         implementationClass="org.acejump.action.AceEditorAction$Reset"
 | 
				
			||||||
 | 
					                         id="AceHandlerEscape"/>
 | 
				
			||||||
    <editorActionHandler action="EditorBackSpace" order="first"
 | 
					    <editorActionHandler action="EditorBackSpace" order="first"
 | 
				
			||||||
                         implementationClass="org.acejump.action.AceEditorAction$ClearSearch"/>
 | 
					                         implementationClass="org.acejump.action.AceEditorAction$ClearSearch"
 | 
				
			||||||
 | 
					                         id="AceHandlerBackSpace"/>
 | 
				
			||||||
    <editorActionHandler action="EditorStartNewLine" order="first"
 | 
					    <editorActionHandler action="EditorStartNewLine" order="first"
 | 
				
			||||||
                         implementationClass="org.acejump.action.AceEditorAction$SelectBackward"/>
 | 
					                         implementationClass="org.acejump.action.AceEditorAction$SelectBackward"
 | 
				
			||||||
 | 
					                         id="AceHandlerStartNewLine"/>
 | 
				
			||||||
    <editorActionHandler action="EditorEnter" order="first"
 | 
					    <editorActionHandler action="EditorEnter" order="first"
 | 
				
			||||||
                         implementationClass="org.acejump.action.AceEditorAction$SelectForward"/>
 | 
					                         implementationClass="org.acejump.action.AceEditorAction$SelectForward"
 | 
				
			||||||
 | 
					                         id="AceHandlerEnter"/>
 | 
				
			||||||
    <editorActionHandler action="EditorTab" order="first"
 | 
					    <editorActionHandler action="EditorTab" order="first"
 | 
				
			||||||
                         implementationClass="org.acejump.action.AceEditorAction$ScrollToNextScreenful"/>
 | 
					                         implementationClass="org.acejump.action.AceEditorAction$ScrollToNextScreenful"
 | 
				
			||||||
 | 
					                         id="AceHandlerTab"/>
 | 
				
			||||||
    <editorActionHandler action="EditorUnindentSelection" order="first"
 | 
					    <editorActionHandler action="EditorUnindentSelection" order="first"
 | 
				
			||||||
                         implementationClass="org.acejump.action.AceEditorAction$ScrollToPreviousScreenful"/>
 | 
					                         implementationClass="org.acejump.action.AceEditorAction$ScrollToPreviousScreenful"
 | 
				
			||||||
 | 
					                         id="AceHandlerUnindentSelection"/>
 | 
				
			||||||
    <editorActionHandler action="EditorUp" order="first"
 | 
					    <editorActionHandler action="EditorUp" order="first"
 | 
				
			||||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineStarts"/>
 | 
					                         implementationClass="org.acejump.action.AceEditorAction$SearchLineStarts"
 | 
				
			||||||
 | 
					                         id="AceHandlerUp"/>
 | 
				
			||||||
    <editorActionHandler action="EditorLeft" order="first"
 | 
					    <editorActionHandler action="EditorLeft" order="first"
 | 
				
			||||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineIndents"/>
 | 
					                         implementationClass="org.acejump.action.AceEditorAction$SearchLineIndents"
 | 
				
			||||||
 | 
					                         id="AceHandlerLeft"/>
 | 
				
			||||||
    <editorActionHandler action="EditorLineStart" order="first"
 | 
					    <editorActionHandler action="EditorLineStart" order="first"
 | 
				
			||||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineIndents"/>
 | 
					                         implementationClass="org.acejump.action.AceEditorAction$SearchLineIndents"
 | 
				
			||||||
 | 
					                         id="AceHandlerLineStart"/>
 | 
				
			||||||
    <editorActionHandler action="EditorRight" order="first"
 | 
					    <editorActionHandler action="EditorRight" order="first"
 | 
				
			||||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineEnds"/>
 | 
					                         implementationClass="org.acejump.action.AceEditorAction$SearchLineEnds"
 | 
				
			||||||
 | 
					                         id="AceHandlerRight"/>
 | 
				
			||||||
    <editorActionHandler action="EditorLineEnd" order="first"
 | 
					    <editorActionHandler action="EditorLineEnd" order="first"
 | 
				
			||||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineEnds"/>
 | 
					                         implementationClass="org.acejump.action.AceEditorAction$SearchLineEnds"
 | 
				
			||||||
 | 
					                         id="AceHandlerLineEnd"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  </extensions>
 | 
					  </extensions>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -55,6 +66,12 @@
 | 
				
			|||||||
    <action id="AceReverseAction"
 | 
					    <action id="AceReverseAction"
 | 
				
			||||||
            class="org.acejump.action.AceAction$ActivateOrReverseCycleMode"
 | 
					            class="org.acejump.action.AceAction$ActivateOrReverseCycleMode"
 | 
				
			||||||
            text="Activate / Reverse Cycle AceJump Mode"/>
 | 
					            text="Activate / Reverse Cycle AceJump Mode"/>
 | 
				
			||||||
 | 
					    <action id="AceForwardAction"
 | 
				
			||||||
 | 
					            class="org.acejump.action.AceAction$ToggleForwardJumpMode"
 | 
				
			||||||
 | 
					            text="Start AceJump in Jump After Caret Mode"/>
 | 
				
			||||||
 | 
					    <action id="AceBackwardAction"
 | 
				
			||||||
 | 
					            class="org.acejump.action.AceAction$ToggleBackwardJumpMode"
 | 
				
			||||||
 | 
					            text="Start AceJump in Jump Before Caret Mode"/>
 | 
				
			||||||
    <action id="AceWordStartAction"
 | 
					    <action id="AceWordStartAction"
 | 
				
			||||||
            class="org.acejump.action.AceAction$ToggleJumpMode"
 | 
					            class="org.acejump.action.AceAction$ToggleJumpMode"
 | 
				
			||||||
            text="Start AceJump in Jump Mode"/>
 | 
					            text="Start AceJump in Jump Mode"/>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
					<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
				
			||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 | 
					<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 | 
				
			||||||
<svg width="100%" height="100%" viewBox="0 0 40 41" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
 | 
					<svg width="100%" height="100%" viewBox="0 0 40 41" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
 | 
				
			||||||
    <g transform="matrix(1,0,0,1,0,-635)">
 | 
					    <g transform="matrix(1,0,0,1,0,-635)">
 | 
				
			||||||
        <g id="pluginIcon" transform="matrix(0.154082,0,0,0.154082,-39.7746,553.645)">
 | 
					        <g id="pluginIcon" transform="matrix(0.154082,0,0,0.154082,-39.7746,553.645)">
 | 
				
			||||||
            <rect x="258.139" y="529.264" width="259.602" height="259.602" style="fill:none;"/>
 | 
					            <rect x="258.139" y="529.264" width="259.602" height="259.602" style="fill:none;"/>
 | 
				
			||||||
 
 | 
				
			|||||||
| 
		 Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB  | 
@@ -121,11 +121,11 @@ class AceTest : BaseTest() {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun `test line mode`() {
 | 
					  fun `test line mode`() {
 | 
				
			||||||
    makeEditor("    test\n    three\n    lines\n")
 | 
					    makeEditor("    test\n    three\n    lines")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    takeAction(AceAction.StartAllLineMarksMode())
 | 
					    takeAction(AceAction.StartAllLineMarksMode())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assertEquals(8, session.tags.size) // last empty line does not count
 | 
					    assertEquals(9, session.tags.size)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun `test chinese selection`() {
 | 
					  fun `test chinese selection`() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
import com.intellij.mock.MockVirtualFile
 | 
					import com.intellij.mock.MockVirtualFile
 | 
				
			||||||
import com.intellij.openapi.editor.Editor
 | 
					import com.intellij.openapi.editor.Editor
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.markup.HighlighterLayer
 | 
				
			||||||
 | 
					import com.intellij.openapi.editor.markup.HighlighterTargetArea
 | 
				
			||||||
import com.intellij.openapi.fileEditor.TextEditor
 | 
					import com.intellij.openapi.fileEditor.TextEditor
 | 
				
			||||||
import com.intellij.util.ui.UIUtil
 | 
					import com.intellij.util.ui.UIUtil
 | 
				
			||||||
import it.unimi.dsi.fastutil.ints.IntArrayList
 | 
					import it.unimi.dsi.fastutil.ints.IntArrayList
 | 
				
			||||||
@@ -41,12 +43,12 @@ class ExternalUsageTest: BaseTest() {
 | 
				
			|||||||
  fun `test externally tagged results with multiple editors`() {
 | 
					  fun `test externally tagged results with multiple editors`() {
 | 
				
			||||||
    val fileA = MockVirtualFile("a.txt", "first file")
 | 
					    val fileA = MockVirtualFile("a.txt", "first file")
 | 
				
			||||||
    val fileB = MockVirtualFile("b.txt", "second file with more markers")
 | 
					    val fileB = MockVirtualFile("b.txt", "second file with more markers")
 | 
				
			||||||
    myManager.openFile(fileA, true)
 | 
					    manager?.openFile(fileA, true)
 | 
				
			||||||
    myManager.openFile(fileB, false)
 | 
					    manager?.openFile(fileB, false)
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    val mainEditor = (myManager.selectedEditor as TextEditor).editor
 | 
					    val mainEditor = (manager?.selectedEditor as TextEditor).editor
 | 
				
			||||||
    val editorA = (myManager.getEditors(fileA).single() as TextEditor).editor
 | 
					    val editorA = (manager?.getEditors(fileA)?.single() as TextEditor).editor
 | 
				
			||||||
    val editorB = (myManager.getEditors(fileB).single() as TextEditor).editor
 | 
					    val editorB = (manager?.getEditors(fileB)?.single() as TextEditor).editor
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    val session = SessionManager.start(mainEditor, listOf(editorA, editorB))
 | 
					    val session = SessionManager.start(mainEditor, listOf(editorA, editorB))
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
@@ -85,7 +87,7 @@ class ExternalUsageTest: BaseTest() {
 | 
				
			|||||||
    SessionManager.start(myFixture.editor)
 | 
					    SessionManager.start(myFixture.editor)
 | 
				
			||||||
      .startRegexSearch("[aeiou]+", WHOLE_FILE)
 | 
					      .startRegexSearch("[aeiou]+", WHOLE_FILE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TestCase.assertEquals(8, session.tags.size)
 | 
					    TestCase.assertEquals(9, session.tags.size)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun `test external jump with bounds`() {
 | 
					  fun `test external jump with bounds`() {
 | 
				
			||||||
@@ -166,4 +168,21 @@ class ExternalUsageTest: BaseTest() {
 | 
				
			|||||||
    TestCase.assertEquals(mark, detectedMark)
 | 
					    TestCase.assertEquals(mark, detectedMark)
 | 
				
			||||||
    TestCase.assertEquals("", detectedQuery)
 | 
					    TestCase.assertEquals("", detectedQuery)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fun `test do not remove other highlights when the session ends`() {
 | 
				
			||||||
 | 
					    makeEditor("test do not remove other highlights when the session ends")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val markupModel = myFixture.editor.markupModel
 | 
				
			||||||
 | 
					    val layer = HighlighterLayer.SELECTION - 1
 | 
				
			||||||
 | 
					    val existedHighlighter = markupModel.addRangeHighlighter(0, 1, layer, null, HighlighterTargetArea.EXACT_RANGE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    takeAction(AceAction.StartAllWordsMode())
 | 
				
			||||||
 | 
					    val mark = session.tags[0].key
 | 
				
			||||||
 | 
					    typeAndWaitForResults(mark)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TestCase.assertEquals("last session should be disposed", null, SessionManager[myFixture.editor])
 | 
				
			||||||
 | 
					    TestCase.assertTrue("existed highlighter should not be removed", existedHighlighter.isValid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    existedHighlighter.dispose()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,6 @@ import kotlin.system.measureTimeMillis
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@Ignore
 | 
					@Ignore
 | 
				
			||||||
class LatencyTest: BaseTest() {
 | 
					class LatencyTest: BaseTest() {
 | 
				
			||||||
 | 
					 | 
				
			||||||
  private fun `test tag latency`(editorText: String) {
 | 
					  private fun `test tag latency`(editorText: String) {
 | 
				
			||||||
    val chars = editorText.toCharArray().distinct().filter { !it.isWhitespace() }
 | 
					    val chars = editorText.toCharArray().distinct().filter { !it.isWhitespace() }
 | 
				
			||||||
    val avg = averageTimeWithWarmup(warmupRuns = 10, timedRuns = 10) {
 | 
					    val avg = averageTimeWithWarmup(warmupRuns = 10, timedRuns = 10) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,7 @@ abstract class BaseTest: FileEditorManagerTestCase() {
 | 
				
			|||||||
      UIUtil.dispatchAllInvocationEvents()
 | 
					      UIUtil.dispatchAllInvocationEvents()
 | 
				
			||||||
      assertEmpty(it.markupModel.allHighlighters)
 | 
					      assertEmpty(it.markupModel.allHighlighters)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    myManager.closeAllFiles()
 | 
					    manager?.closeAllFiles()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun typeAndWaitForResults(string: String) {
 | 
					  fun typeAndWaitForResults(string: String) {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user