mirror of
				https://github.com/chylex/IntelliJ-AceJump.git
				synced 2025-11-04 00:40:12 +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
 | 
			
		||||
 | 
			
		||||
## 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
 | 
			
		||||
 | 
			
		||||
- 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)
 | 
			
		||||
- 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
 | 
			
		||||
 | 
			
		||||
- Fixes Declaration Mode in Rider, [#379](https://github.com/acejump/AceJump/issues/379), thanks to @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 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](https://github.com/chylex) for [the PR](https://github.com/acejump/AceJump/pull/384)!
 | 
			
		||||
 | 
			
		||||
## 3.8.3
 | 
			
		||||
 | 
			
		||||
@@ -20,7 +85,7 @@
 | 
			
		||||
 | 
			
		||||
- 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)
 | 
			
		||||
- Thanks to @SaiKai for the PRs!
 | 
			
		||||
- Thanks to [@SaiKai](https://github.com/SaiKai) for the PRs!
 | 
			
		||||
 | 
			
		||||
## 3.8.1
 | 
			
		||||
 | 
			
		||||
@@ -35,7 +100,7 @@
 | 
			
		||||
- 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)
 | 
			
		||||
- 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
 | 
			
		||||
- Improvements to tag latency
 | 
			
		||||
@@ -49,7 +114,7 @@
 | 
			
		||||
- Increase limit for what is considered a large file
 | 
			
		||||
- 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)
 | 
			
		||||
- 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
 | 
			
		||||
 | 
			
		||||
@@ -59,12 +124,12 @@
 | 
			
		||||
 | 
			
		||||
## 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.
 | 
			
		||||
 | 
			
		||||
## 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 Pinyin support.
 | 
			
		||||
 | 
			
		||||
@@ -72,7 +137,7 @@
 | 
			
		||||
 | 
			
		||||
- 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).
 | 
			
		||||
- 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).
 | 
			
		||||
 | 
			
		||||
## 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://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://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>
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
- 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 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.
 | 
			
		||||
 | 
			
		||||
  - 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"**.
 | 
			
		||||
 | 
			
		||||
[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
 | 
			
		||||
 | 
			
		||||
[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 '
 | 
			
		||||
 | 
			
		||||
" Press `f` to activate AceJump
 | 
			
		||||
map f :action AceAction<CR>
 | 
			
		||||
map f <Action>(AceAction)
 | 
			
		||||
" Press `F` to activate Target Mode
 | 
			
		||||
map F :action AceTargetAction<CR>
 | 
			
		||||
map F <Action>(AceTargetAction)
 | 
			
		||||
" Press `g` to activate Line Mode
 | 
			
		||||
map g :action AceLineAction<CR>
 | 
			
		||||
map g <Action>(AceLineAction)
 | 
			
		||||
 | 
			
		||||
' >> ~/.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>.
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
@@ -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:
 | 
			
		||||
 | 
			
		||||
| 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/)                     |
 | 
			
		||||
| [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:  |                       [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)                       |
 | 
			
		||||
| [TraceJump](https://github.com/acejump/tracejump)                     |                          [⬇](https://github.com/acejump/tracejump)                          |                                          Desktop                                       | :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:  |                     [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)                                            |         :x:         |                       [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                                                             |         :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)    |
 | 
			
		||||
| [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/)        |
 | 
			
		||||
| [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/)                        |
 | 
			
		||||
| [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/)                     |
 | 
			
		||||
| [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/)                     |
 | 
			
		||||
| [Jumpy](https://github.com/DavidLGoldberg/jumpy)                      |                             [⬇](https://atom.io/packages/jumpy)                             |                                [Atom](https://atom.io/)                                | :heavy_check_mark:  |                 [CoffeeScript](http://coffeescript.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:  |              [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/)               |
 | 
			
		||||
| [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/)               |
 | 
			
		||||
| [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/) |
 | 
			
		||||
| [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/)                 |
 | 
			
		||||
| [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/)                 |
 | 
			
		||||
| [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-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/)                    |
 | 
			
		||||
| [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/)                    |
 | 
			
		||||
| [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/)                 |
 | 
			
		||||
| [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/)                 |
 | 
			
		||||
@@ -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/)                 |
 | 
			
		||||
| [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/)               |
 | 
			
		||||
| [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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										103
									
								
								build.gradle.kts
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								build.gradle.kts
									
									
									
									
									
								
							@@ -1,73 +1,100 @@
 | 
			
		||||
import org.jetbrains.changelog.*
 | 
			
		||||
import org.jetbrains.intellij.tasks.*
 | 
			
		||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 | 
			
		||||
import org.jetbrains.changelog.Changelog.OutputType.HTML
 | 
			
		||||
import org.jetbrains.changelog.date
 | 
			
		||||
import org.jetbrains.intellij.platform.gradle.TestFrameworkType
 | 
			
		||||
 | 
			
		||||
plugins {
 | 
			
		||||
  idea apply true
 | 
			
		||||
  kotlin("jvm") version "1.6.0-RC2"
 | 
			
		||||
  id("org.jetbrains.intellij") version "1.2.1"
 | 
			
		||||
  id("org.jetbrains.changelog") version "1.3.1"
 | 
			
		||||
  id("com.github.ben-manes.versions") version "0.39.0"
 | 
			
		||||
  idea
 | 
			
		||||
  alias(libs.plugins.kotlin) // Kotlin support
 | 
			
		||||
  alias(libs.plugins.intelliJPlatform) // IntelliJ Platform Gradle Plugin
 | 
			
		||||
  alias(libs.plugins.changelog) // Gradle Changelog Plugin
 | 
			
		||||
  alias(libs.plugins.kover) // Gradle Kover Plugin
 | 
			
		||||
  id("com.github.ben-manes.versions") version "0.51.0"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tasks {
 | 
			
		||||
  withType<KotlinCompile> {
 | 
			
		||||
    kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  named<Zip>("buildPlugin") {
 | 
			
		||||
    dependsOn("test")
 | 
			
		||||
    archiveFileName.set("AceJump.zip")
 | 
			
		||||
    archiveFileName = "AceJump.zip"
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  withType<RunIdeTask> {
 | 
			
		||||
    dependsOn("test")
 | 
			
		||||
  runIde {
 | 
			
		||||
    findProperty("luginDev")?.let { args = listOf(projectDir.absolutePath) }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  publishPlugin {
 | 
			
		||||
    val intellijPublishToken: String? by project
 | 
			
		||||
    token.set(intellijPublishToken)
 | 
			
		||||
    token = intellijPublishToken
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  patchPluginXml {
 | 
			
		||||
    sinceBuild.set("203.7717.56")
 | 
			
		||||
    changeNotes.set(provider {
 | 
			
		||||
      changelog.getAll().values.take(2).last().toHTML()
 | 
			
		||||
    })
 | 
			
		||||
    sinceBuild = "223.7571.182"
 | 
			
		||||
    changeNotes = provider {
 | 
			
		||||
      changelog.renderItem(changelog.getAll().values.take(2).last(), HTML)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  runPluginVerifier {
 | 
			
		||||
    ideVersions.set(listOf("2021.2.1"))
 | 
			
		||||
  // Remove pending: https://youtrack.jetbrains.com/issue/IDEA-278926
 | 
			
		||||
  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 {
 | 
			
		||||
  version.set("3.8.5")
 | 
			
		||||
  path.set("${project.projectDir}/CHANGES.md")
 | 
			
		||||
  header.set(provider { "[${project.version}] - ${date()}" })
 | 
			
		||||
  itemPrefix.set("-")
 | 
			
		||||
  unreleasedTerm.set("Unreleased")
 | 
			
		||||
  version = acejumpVersion
 | 
			
		||||
  path = "${project.projectDir}/CHANGES.md"
 | 
			
		||||
  header = provider { "[${project.version}] - ${date()}" }
 | 
			
		||||
  itemPrefix = "-"
 | 
			
		||||
  unreleasedTerm = "Unreleased"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
repositories {
 | 
			
		||||
  mavenCentral()
 | 
			
		||||
  maven("https://jitpack.io")
 | 
			
		||||
  intellijPlatform.defaultRepositories()
 | 
			
		||||
//  intellijPlatform.localPlatformArtifacts()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
  // gradle-intellij-plugin doesn't attach sources properly for Kotlin :(
 | 
			
		||||
  implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
 | 
			
		||||
  compileOnly(kotlin("stdlib-jdk8"))
 | 
			
		||||
  implementation("com.anyascii:anyascii:0.3.0")
 | 
			
		||||
  // https://github.com/anyascii/anyascii
 | 
			
		||||
  implementation("com.anyascii:anyascii:0.3.2")
 | 
			
		||||
  intellijPlatform{
 | 
			
		||||
    testImplementation(libs.junit)
 | 
			
		||||
 | 
			
		||||
    bundledPlugins("com.intellij.java")
 | 
			
		||||
    create("IC", "2024.1.4")
 | 
			
		||||
    pluginVerifier()
 | 
			
		||||
    instrumentationTools()
 | 
			
		||||
    testFramework(TestFrameworkType.Platform)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
intellij {
 | 
			
		||||
  version.set("2021.2.1")
 | 
			
		||||
  pluginName.set("AceJump")
 | 
			
		||||
  updateSinceUntilBuild.set(false)
 | 
			
		||||
  plugins.set(listOf("java"))
 | 
			
		||||
intellijPlatform {
 | 
			
		||||
  pluginConfiguration {
 | 
			
		||||
    version = acejumpVersion
 | 
			
		||||
    name = "AceJump"
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pluginVerification.ides.recommended()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
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
 | 
			
		||||
zipStorePath=wrapper/dists
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,12 @@ package org.acejump
 | 
			
		||||
 | 
			
		||||
import com.anyascii.AnyAscii
 | 
			
		||||
import com.intellij.diff.util.DiffUtil.getLineCount
 | 
			
		||||
import com.intellij.openapi.application.ApplicationManager
 | 
			
		||||
import com.intellij.openapi.editor.*
 | 
			
		||||
import com.intellij.openapi.util.Computable
 | 
			
		||||
import it.unimi.dsi.fastutil.ints.IntArrayList
 | 
			
		||||
import org.acejump.config.AceConfig
 | 
			
		||||
import java.awt.Point
 | 
			
		||||
import kotlin.math.*
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -38,7 +41,7 @@ object EditorsCache {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
@@ -127,18 +130,15 @@ fun Editor.offsetCenter(first: Int, second: Int): LogicalPosition {
 | 
			
		||||
  return offsetToLogicalPosition(getLineStartOffset(center))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Borrowed from Editor.calculateVisibleRange() but only available after 232.6095.10
 | 
			
		||||
fun Editor.getView(): IntRange {
 | 
			
		||||
  val firstVisibleLine = max(0, getVisualLineAtTopOfScreen() - 1)
 | 
			
		||||
  val firstLine = visualLineToLogicalLine(firstVisibleLine)
 | 
			
		||||
  val startOffset = getLineStartOffset(firstLine)
 | 
			
		||||
 | 
			
		||||
  val height = getScreenHeight() + 2
 | 
			
		||||
  val lastLine = visualLineToLogicalLine(firstVisibleLine + height)
 | 
			
		||||
  var endOffset = getLineEndOffset(lastLine, true)
 | 
			
		||||
  endOffset = normalizeOffset(lastLine, endOffset)
 | 
			
		||||
  endOffset = min(max(0, document.textLength - 1), endOffset + 1)
 | 
			
		||||
 | 
			
		||||
  return startOffset..endOffset
 | 
			
		||||
  ApplicationManager.getApplication().assertIsDispatchThread()
 | 
			
		||||
  val rect = scrollingModel.visibleArea
 | 
			
		||||
  val startPosition = xyToLogicalPosition(Point(rect.x, rect.y))
 | 
			
		||||
  val visibleStart = logicalPositionToOffset(startPosition)
 | 
			
		||||
  val endPosition = xyToLogicalPosition(Point(rect.x + rect.width, rect.y + rect.height))
 | 
			
		||||
  val visibleEnd = logicalPositionToOffset(LogicalPosition(endPosition.line + 1, 0))
 | 
			
		||||
  return visibleStart..visibleEnd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -253,3 +253,9 @@ fun Editor.normalizeOffset(line: Int, offset: Int, allowEnd: Boolean = true) =
 | 
			
		||||
  if (getFileSize(allowEnd) == 0) 0 else
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
 | 
			
		||||
import com.intellij.openapi.actionSystem.AnActionEvent
 | 
			
		||||
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.ex.FileEditorManagerEx
 | 
			
		||||
import com.intellij.openapi.project.DumbAwareAction
 | 
			
		||||
import com.intellij.util.IncorrectOperationException
 | 
			
		||||
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.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.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.SessionManager
 | 
			
		||||
 | 
			
		||||
@@ -19,25 +32,28 @@ import org.acejump.session.SessionManager
 | 
			
		||||
 * Base class for keyboard-activated actions that create or update an AceJump [Session].
 | 
			
		||||
 */
 | 
			
		||||
sealed class AceAction: DumbAwareAction() {
 | 
			
		||||
  override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
 | 
			
		||||
 | 
			
		||||
  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) {
 | 
			
		||||
    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
 | 
			
		||||
  
 | 
			
		||||
    if (project != null) {
 | 
			
		||||
      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 }
 | 
			
		||||
          .sortedBy { if (it === editor) 0 else 1 }
 | 
			
		||||
        invoke(SessionManager.start(editor, openEditors))
 | 
			
		||||
      } catch (e: IncorrectOperationException) {
 | 
			
		||||
        invoke(SessionManager.start(editor))
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
    } else {
 | 
			
		||||
      invoke(SessionManager.start(editor))
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -51,6 +67,13 @@ sealed class AceAction: DumbAwareAction() {
 | 
			
		||||
    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.
 | 
			
		||||
   */
 | 
			
		||||
@@ -74,12 +97,17 @@ sealed class AceAction: DumbAwareAction() {
 | 
			
		||||
 | 
			
		||||
  // @formatter:off
 | 
			
		||||
 | 
			
		||||
  // Unbounded Toggle Modes
 | 
			
		||||
  class ToggleJumpMode        : BaseToggleJumpModeAction(JUMP)
 | 
			
		||||
  class ToggleJumpEndMode     : BaseToggleJumpModeAction(JUMP_END)
 | 
			
		||||
  class ToggleTargetMode      : BaseToggleJumpModeAction(TARGET)
 | 
			
		||||
  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 StartAllWordsBackwardsMode : BaseRegexSearchAction(ALL_WORDS, BEFORE_CARET)
 | 
			
		||||
  class StartAllWordsForwardMode   : BaseRegexSearchAction(ALL_WORDS, AFTER_CARET)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,31 @@
 | 
			
		||||
package org.acejump.action
 | 
			
		||||
 | 
			
		||||
import com.intellij.openapi.actionSystem.*
 | 
			
		||||
import com.intellij.openapi.actionSystem.IdeActions.*
 | 
			
		||||
import com.intellij.openapi.actionSystem.ActionManager
 | 
			
		||||
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.UndoConfirmationPolicy
 | 
			
		||||
import com.intellij.openapi.editor.Document
 | 
			
		||||
import com.intellij.openapi.editor.Editor
 | 
			
		||||
import com.intellij.openapi.editor.actionSystem.DocCommandGroupId
 | 
			
		||||
import com.intellij.openapi.fileEditor.FileEditorManager
 | 
			
		||||
import com.intellij.openapi.fileEditor.TextEditor
 | 
			
		||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
 | 
			
		||||
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory
 | 
			
		||||
import com.intellij.openapi.project.Project
 | 
			
		||||
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.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.Tag
 | 
			
		||||
import org.acejump.wordEnd
 | 
			
		||||
import org.acejump.wordStart
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Performs [JumpMode] navigation and actions.
 | 
			
		||||
@@ -98,9 +107,9 @@ internal class TagJumper(private val mode: JumpMode, private val searchProcessor
 | 
			
		||||
 | 
			
		||||
    private fun ensureEditorFocused(editor: Editor) {
 | 
			
		||||
      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) {
 | 
			
		||||
        fem.currentWindow = window
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,10 +5,10 @@ import org.acejump.*
 | 
			
		||||
import org.acejump.search.SearchProcessor
 | 
			
		||||
 | 
			
		||||
internal class TagScroller(private val editor: Editor, private val searchProcessor: SearchProcessor) {
 | 
			
		||||
  fun scroll(forward: Boolean = true): Boolean {
 | 
			
		||||
    val position = if (forward) findNextPosition() else findPreviousPosition()
 | 
			
		||||
    return if (position != null) true.also { scrollTo(position) } else false
 | 
			
		||||
  }
 | 
			
		||||
  fun scroll(
 | 
			
		||||
    forward: Boolean = true,
 | 
			
		||||
    position: LogicalPosition? = if (forward) findNextPosition() else findPreviousPosition()
 | 
			
		||||
  ) = if (position != null) true.also { scrollTo(position) } else false
 | 
			
		||||
 | 
			
		||||
  private fun scrollTo(position: LogicalPosition) = editor.run {
 | 
			
		||||
    scrollingModel.disableAnimation()
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@ package org.acejump.action
 | 
			
		||||
 | 
			
		||||
import com.intellij.openapi.editor.*
 | 
			
		||||
import com.intellij.openapi.editor.ScrollType.*
 | 
			
		||||
import org.acejump.*
 | 
			
		||||
import org.acejump.search.SearchProcessor
 | 
			
		||||
import org.acejump.search.Tag
 | 
			
		||||
import kotlin.math.abs
 | 
			
		||||
 
 | 
			
		||||
@@ -16,12 +16,14 @@ interface Boundaries {
 | 
			
		||||
   * offsets outside the boundary, for ex. when the boundary is rectangular
 | 
			
		||||
   * 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.
 | 
			
		||||
   */
 | 
			
		||||
  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
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ package org.acejump.boundaries
 | 
			
		||||
import com.intellij.openapi.editor.Editor
 | 
			
		||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
 | 
			
		||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
 | 
			
		||||
import org.acejump.read
 | 
			
		||||
import java.awt.Point
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -20,6 +21,11 @@ sealed class EditorOffsetCache {
 | 
			
		||||
   */
 | 
			
		||||
  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.
 | 
			
		||||
   */
 | 
			
		||||
@@ -30,32 +36,46 @@ sealed class EditorOffsetCache {
 | 
			
		||||
   */
 | 
			
		||||
  abstract fun offsetToXY(editor: Editor, offset: Int): Point
 | 
			
		||||
 | 
			
		||||
  companion object {
 | 
			
		||||
    fun new(): EditorOffsetCache = Cache()
 | 
			
		||||
  }
 | 
			
		||||
  companion object { fun new(): EditorOffsetCache = Cache() }
 | 
			
		||||
 | 
			
		||||
  private class Cache: EditorOffsetCache() {
 | 
			
		||||
    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>()
 | 
			
		||||
 | 
			
		||||
    override fun visibleArea(editor: Editor): Pair<Point, Point> =
 | 
			
		||||
      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 =
 | 
			
		||||
      pointToOffset.getInt(pos).let { offset ->
 | 
			
		||||
        if (offset != -1) offset
 | 
			
		||||
        else Uncached.xyToOffset(editor, pos).also {
 | 
			
		||||
          @Suppress("ReplacePutWithAssignment")
 | 
			
		||||
          pointToOffset.put(pos, it)
 | 
			
		||||
        }
 | 
			
		||||
        else Uncached.xyToOffset(editor, pos)
 | 
			
		||||
          .also { pointToOffset.put(pos, it) }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    override fun offsetToXY(editor: Editor, offset: Int) =
 | 
			
		||||
      offsetToPoint.get(offset) ?: Uncached.offsetToXY(editor, offset).also {
 | 
			
		||||
        @Suppress("ReplacePutWithAssignment")
 | 
			
		||||
        offsetToPoint.put(offset, it)
 | 
			
		||||
      }
 | 
			
		||||
      offsetToPoint.get(offset) ?: Uncached.offsetToXY(editor, offset)
 | 
			
		||||
        .also { offsetToPoint.put(offset, it) }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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 =
 | 
			
		||||
      editor.logicalPositionToOffset(editor.xyToLogicalPosition(pos))
 | 
			
		||||
      read { editor.logicalPositionToOffset(editor.xyToLogicalPosition(pos)) }
 | 
			
		||||
 | 
			
		||||
    override fun offsetToXY(editor: Editor, offset: Int): Point =
 | 
			
		||||
      editor.offsetToXY(offset, true, false)
 | 
			
		||||
 
 | 
			
		||||
@@ -5,10 +5,10 @@ import com.intellij.openapi.editor.Editor
 | 
			
		||||
enum class StandardBoundaries : Boundaries {
 | 
			
		||||
  WHOLE_FILE {
 | 
			
		||||
    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) =
 | 
			
		||||
      offset in (0 until editor.document.textLength)
 | 
			
		||||
      offset in (0..editor.document.textLength)
 | 
			
		||||
  },
 | 
			
		||||
  
 | 
			
		||||
  VISIBLE_ON_SCREEN {
 | 
			
		||||
@@ -21,22 +21,7 @@ enum class StandardBoundaries : Boundaries {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    override fun isOffsetInside(editor: Editor, offset: Int, cache: EditorOffsetCache): Boolean {
 | 
			
		||||
      // If we are not using a cache, calling getOffsetRange will cause
 | 
			
		||||
      // 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
 | 
			
		||||
      return cache.isVisible(editor, offset)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
package org.acejump.config
 | 
			
		||||
 | 
			
		||||
import com.intellij.openapi.components.PersistentStateComponent
 | 
			
		||||
import com.intellij.openapi.components.ServiceManager
 | 
			
		||||
import com.intellij.openapi.components.State
 | 
			
		||||
import com.intellij.openapi.components.Storage
 | 
			
		||||
import com.intellij.util.application
 | 
			
		||||
import org.acejump.input.KeyLayoutCache
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -16,19 +16,19 @@ class AceConfig: PersistentStateComponent<AceSettings> {
 | 
			
		||||
  private var aceSettings = AceSettings()
 | 
			
		||||
 | 
			
		||||
  companion object {
 | 
			
		||||
    val settings get() = ServiceManager.getService(AceConfig::class.java).aceSettings
 | 
			
		||||
    val settings get() = application.getService(AceConfig::class.java).aceSettings
 | 
			
		||||
 | 
			
		||||
    // @formatter:off
 | 
			
		||||
    val layout get()              = settings.layout
 | 
			
		||||
    val cycleModes get()          = settings.let { arrayOf(it.cycleMode1, it.cycleMode2, it.cycleMode3, it.cycleMode4) }
 | 
			
		||||
    val minQueryLength get()      = settings.minQueryLength
 | 
			
		||||
    val jumpModeColor get()       = settings.jumpModeColor
 | 
			
		||||
    val jumpEndModeColor get()    = settings.jumpEndModeColor
 | 
			
		||||
    val targetModeColor get()     = settings.targetModeColor
 | 
			
		||||
    val definitionModeColor get() = settings.definitionModeColor
 | 
			
		||||
    val textHighlightColor get()  = settings.textHighlightColor
 | 
			
		||||
    val tagForegroundColor get()  = settings.tagForegroundColor
 | 
			
		||||
    val tagBackgroundColor get()  = settings.tagBackgroundColor
 | 
			
		||||
    val jumpModeColor get()       = settings.getJumpModeJBC()
 | 
			
		||||
    val jumpEndModeColor get()    = settings.getJumpEndModeJBC()
 | 
			
		||||
    val targetModeColor get()     = settings.getTargetModeJBC()
 | 
			
		||||
    val definitionModeColor get() = settings.getDefinitionModeJBC()
 | 
			
		||||
    val textHighlightColor get()  = settings.getTextHighlightJBC()
 | 
			
		||||
    val tagForegroundColor get()  = settings.getTagForegroundJBC()
 | 
			
		||||
    val tagBackgroundColor get()  = settings.getTagBackgroundJBC()
 | 
			
		||||
    val searchWholeFile get()     = settings.searchWholeFile
 | 
			
		||||
    val mapToASCII get()        = settings.mapToASCII
 | 
			
		||||
    val showSearchNotification get()          = settings.showSearchNotification
 | 
			
		||||
 
 | 
			
		||||
@@ -19,13 +19,13 @@ class AceConfigurable: Configurable {
 | 
			
		||||
      panel.cycleMode3 != settings.cycleMode3 ||
 | 
			
		||||
      panel.cycleMode4 != settings.cycleMode4 ||
 | 
			
		||||
      panel.minQueryLengthInt != settings.minQueryLength ||
 | 
			
		||||
      panel.jumpModeColor != settings.jumpModeColor ||
 | 
			
		||||
      panel.jumpEndModeColor != settings.jumpEndModeColor ||
 | 
			
		||||
      panel.targetModeColor != settings.targetModeColor ||
 | 
			
		||||
      panel.definitionModeColor != settings.definitionModeColor ||
 | 
			
		||||
      panel.textHighlightColor != settings.textHighlightColor ||
 | 
			
		||||
      panel.tagForegroundColor != settings.tagForegroundColor ||
 | 
			
		||||
      panel.tagBackgroundColor != settings.tagBackgroundColor ||
 | 
			
		||||
      panel.jumpModeColor?.rgb != settings.jumpModeColor ||
 | 
			
		||||
      panel.jumpEndModeColor?.rgb != settings.jumpEndModeColor ||
 | 
			
		||||
      panel.targetModeColor?.rgb != settings.targetModeColor ||
 | 
			
		||||
      panel.definitionModeColor?.rgb != settings.definitionModeColor ||
 | 
			
		||||
      panel.textHighlightColor?.rgb != settings.textHighlightColor ||
 | 
			
		||||
      panel.tagForegroundColor?.rgb != settings.tagForegroundColor ||
 | 
			
		||||
      panel.tagBackgroundColor?.rgb != settings.tagBackgroundColor ||
 | 
			
		||||
      panel.searchWholeFile != settings.searchWholeFile ||
 | 
			
		||||
      panel.mapToASCII != settings.mapToASCII ||
 | 
			
		||||
      panel.showSearchNotification != settings.showSearchNotification
 | 
			
		||||
@@ -38,13 +38,13 @@ class AceConfigurable: Configurable {
 | 
			
		||||
    settings.cycleMode3 = panel.cycleMode3
 | 
			
		||||
    settings.cycleMode4 = panel.cycleMode4
 | 
			
		||||
    settings.minQueryLength = panel.minQueryLengthInt ?: settings.minQueryLength
 | 
			
		||||
    panel.jumpModeColor?.let { settings.jumpModeColor = it }
 | 
			
		||||
    panel.jumpEndModeColor?.let { settings.jumpEndModeColor = it }
 | 
			
		||||
    panel.targetModeColor?.let { settings.targetModeColor = it }
 | 
			
		||||
    panel.definitionModeColor?.let { settings.definitionModeColor = it }
 | 
			
		||||
    panel.textHighlightColor?.let { settings.textHighlightColor = it }
 | 
			
		||||
    panel.tagForegroundColor?.let { settings.tagForegroundColor = it }
 | 
			
		||||
    panel.tagBackgroundColor?.let { settings.tagBackgroundColor = it }
 | 
			
		||||
    panel.jumpModeColor?.let { settings.jumpModeColor = it.rgb }
 | 
			
		||||
    panel.jumpEndModeColor?.let { settings.jumpEndModeColor = it.rgb }
 | 
			
		||||
    panel.targetModeColor?.let { settings.targetModeColor = it.rgb }
 | 
			
		||||
    panel.definitionModeColor?.let { settings.definitionModeColor = it.rgb }
 | 
			
		||||
    panel.textHighlightColor?.let { settings.textHighlightColor = it.rgb }
 | 
			
		||||
    panel.tagForegroundColor?.let { settings.tagForegroundColor = it.rgb }
 | 
			
		||||
    panel.tagBackgroundColor?.let { settings.tagBackgroundColor = it.rgb }
 | 
			
		||||
    settings.searchWholeFile = panel.searchWholeFile
 | 
			
		||||
    settings.mapToASCII = panel.mapToASCII
 | 
			
		||||
    settings.showSearchNotification = panel.showSearchNotification
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,8 @@
 | 
			
		||||
package org.acejump.config
 | 
			
		||||
 | 
			
		||||
import com.intellij.util.xmlb.Converter
 | 
			
		||||
import com.intellij.util.xmlb.annotations.OptionTag
 | 
			
		||||
import org.acejump.input.JumpMode
 | 
			
		||||
import org.acejump.input.KeyLayout
 | 
			
		||||
import com.intellij.ui.JBColor
 | 
			
		||||
import org.acejump.input.*
 | 
			
		||||
import org.acejump.input.KeyLayout.QWERTY
 | 
			
		||||
import java.awt.Color
 | 
			
		||||
 | 
			
		||||
data class AceSettings(
 | 
			
		||||
  var layout: KeyLayout = QWERTY,
 | 
			
		||||
@@ -16,35 +13,31 @@ data class AceSettings(
 | 
			
		||||
  var cycleMode4: JumpMode = JumpMode.JUMP_END,
 | 
			
		||||
  var minQueryLength: Int = 1,
 | 
			
		||||
 | 
			
		||||
  @OptionTag("jumpModeRGB", converter = ColorConverter::class)
 | 
			
		||||
  var jumpModeColor: Color = Color(0xFFFFFF),
 | 
			
		||||
  var jumpModeColor: Int = 0xFFFFFF,
 | 
			
		||||
 | 
			
		||||
  @OptionTag("jumpEndModeRGB", converter = ColorConverter::class)
 | 
			
		||||
  var jumpEndModeColor: Color = Color(0x33E78A),
 | 
			
		||||
  var jumpEndModeColor: Int = 0x33E78A,
 | 
			
		||||
 | 
			
		||||
  @OptionTag("targetModeRGB", converter = ColorConverter::class)
 | 
			
		||||
  var targetModeColor: Color = Color(0xFFB700),
 | 
			
		||||
  var targetModeColor: Int = 0xFFB700,
 | 
			
		||||
 | 
			
		||||
  @OptionTag("definitionModeRGB", converter = ColorConverter::class)
 | 
			
		||||
  var definitionModeColor: Color = Color(0x6FC5FF),
 | 
			
		||||
  var definitionModeColor: Int = 0x6FC5FF,
 | 
			
		||||
 | 
			
		||||
  @OptionTag("textHighlightRGB", converter = ColorConverter::class)
 | 
			
		||||
  var textHighlightColor: Color = Color(0x394B58),
 | 
			
		||||
  var textHighlightColor: Int = 0x394B58,
 | 
			
		||||
 | 
			
		||||
  @OptionTag("tagForegroundRGB", converter = ColorConverter::class)
 | 
			
		||||
  var tagForegroundColor: Color = Color(0xFFFFFF),
 | 
			
		||||
  var tagForegroundColor: Int = 0xFFFFFF,
 | 
			
		||||
 | 
			
		||||
  @OptionTag("tagBackgroundRGB", converter = ColorConverter::class)
 | 
			
		||||
  var tagBackgroundColor: Color = Color(0x008299),
 | 
			
		||||
  var tagBackgroundColor: Int = 0x008299,
 | 
			
		||||
 | 
			
		||||
  var searchWholeFile: Boolean = true,
 | 
			
		||||
 | 
			
		||||
  var mapToASCII : Boolean = false,
 | 
			
		||||
  var mapToASCII: Boolean = false,
 | 
			
		||||
 | 
			
		||||
  var showSearchNotification : Boolean = false
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
internal class ColorConverter: Converter<Color>() {
 | 
			
		||||
  override fun toString(value: Color) = value.rgb.toString()
 | 
			
		||||
  override fun fromString(value: String) = value.toIntOrNull()?.let(::Color)
 | 
			
		||||
  var showSearchNotification: Boolean = false
 | 
			
		||||
) {
 | 
			
		||||
  fun getJumpModeJBC() = JBColor.namedColor("jumpModeRGB", jumpModeColor)
 | 
			
		||||
  fun getJumpEndModeJBC() = JBColor.namedColor("jumpEndModeRGB", jumpEndModeColor)
 | 
			
		||||
  fun getTargetModeJBC() = JBColor.namedColor("targetModeRGB", targetModeColor)
 | 
			
		||||
  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
 | 
			
		||||
 | 
			
		||||
import com.intellij.openapi.ui.ComboBox
 | 
			
		||||
import com.intellij.ui.ColorPanel
 | 
			
		||||
import com.intellij.ui.components.JBCheckBox
 | 
			
		||||
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 com.intellij.ui.components.*
 | 
			
		||||
import com.intellij.ui.dsl.builder.*
 | 
			
		||||
import org.acejump.input.JumpMode
 | 
			
		||||
import org.acejump.input.KeyLayout
 | 
			
		||||
import java.awt.Color
 | 
			
		||||
import java.awt.Font
 | 
			
		||||
import javax.swing.JCheckBox
 | 
			
		||||
import javax.swing.JComponent
 | 
			
		||||
import javax.swing.JPanel
 | 
			
		||||
import java.awt.*
 | 
			
		||||
import javax.swing.*
 | 
			
		||||
import javax.swing.text.JTextComponent
 | 
			
		||||
import kotlin.reflect.KProperty
 | 
			
		||||
 | 
			
		||||
@@ -24,6 +15,8 @@ import kotlin.reflect.KProperty
 | 
			
		||||
 */
 | 
			
		||||
@Suppress("UsePropertyAccessSyntax")
 | 
			
		||||
internal class AceSettingsPanel {
 | 
			
		||||
  private val defaults = AceSettings()
 | 
			
		||||
  
 | 
			
		||||
  private val tagCharsField = JBTextField()
 | 
			
		||||
  private val keyboardLayoutCombo = ComboBox<KeyLayout>()
 | 
			
		||||
  private val keyboardLayoutArea = JBTextArea().apply { isEditable = false }
 | 
			
		||||
@@ -32,13 +25,13 @@ internal class AceSettingsPanel {
 | 
			
		||||
  private val cycleModeCombo3 = ComboBox<JumpMode>()
 | 
			
		||||
  private val cycleModeCombo4 = ComboBox<JumpMode>()
 | 
			
		||||
  private val minQueryLengthField = JBTextField()
 | 
			
		||||
  private val jumpModeColorWheel = ColorPanel()
 | 
			
		||||
  private val jumpEndModeColorWheel = ColorPanel()
 | 
			
		||||
  private val targetModeColorWheel = ColorPanel()
 | 
			
		||||
  private val definitionModeColorWheel = ColorPanel()
 | 
			
		||||
  private val textHighlightColorWheel = ColorPanel()
 | 
			
		||||
  private val tagForegroundColorWheel = ColorPanel()
 | 
			
		||||
  private val tagBackgroundColorWheel = ColorPanel()
 | 
			
		||||
  private val jumpModeColorWheel = ResettableColorPicker(defaults.getJumpModeJBC())
 | 
			
		||||
  private val jumpEndModeColorWheel = ResettableColorPicker(defaults.getJumpEndModeJBC())
 | 
			
		||||
  private val targetModeColorWheel = ResettableColorPicker(defaults.getTargetModeJBC())
 | 
			
		||||
  private val definitionModeColorWheel = ResettableColorPicker(defaults.getDefinitionModeJBC())
 | 
			
		||||
  private val textHighlightColorWheel = ResettableColorPicker(defaults.getTextHighlightJBC())
 | 
			
		||||
  private val tagForegroundColorWheel = ResettableColorPicker(defaults.getTagForegroundJBC())
 | 
			
		||||
  private val tagBackgroundColorWheel = ResettableColorPicker(defaults.getTagBackgroundJBC())
 | 
			
		||||
  private val searchWholeFileCheckBox = JBCheckBox()
 | 
			
		||||
  private val mapToASCIICheckBox = JBCheckBox()
 | 
			
		||||
  private val showSearchNotificationCheckBox = JBCheckBox()
 | 
			
		||||
@@ -54,45 +47,40 @@ internal class AceSettingsPanel {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  internal val rootPanel: JPanel = panel {
 | 
			
		||||
    fun Cell.short(component: JComponent) = component(growPolicy = SHORT_TEXT)
 | 
			
		||||
    fun Cell.medium(component: JComponent) = component(growPolicy = MEDIUM_TEXT)
 | 
			
		||||
 | 
			
		||||
    titledRow("Characters and Layout") {
 | 
			
		||||
      row("Allowed characters in tags:") { medium(tagCharsField) }
 | 
			
		||||
      row("Keyboard layout:") { short(keyboardLayoutCombo) }
 | 
			
		||||
      row("Keyboard design:") { short(keyboardLayoutArea) }
 | 
			
		||||
    group("Characters and Layout") {
 | 
			
		||||
      row("Allowed characters in tags:") { cell(tagCharsField).columns(COLUMNS_LARGE) }
 | 
			
		||||
      row("Keyboard layout:") { cell(keyboardLayoutCombo).columns(COLUMNS_SHORT) }
 | 
			
		||||
      row("Keyboard design:") { cell(keyboardLayoutArea).columns(COLUMNS_SHORT) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    titledRow("Modes") {
 | 
			
		||||
      row("Cycle order:") { cell { cycleModeCombo1() } }
 | 
			
		||||
      row("") {
 | 
			
		||||
        cell(isVerticalFlow = true) {
 | 
			
		||||
          cycleModeCombo2()
 | 
			
		||||
          cycleModeCombo3()
 | 
			
		||||
          cycleModeCombo4()
 | 
			
		||||
        }
 | 
			
		||||
    group("Modes") {
 | 
			
		||||
      row("Cycle order:") {
 | 
			
		||||
        cell(cycleModeCombo1).columns(10)
 | 
			
		||||
        cell(cycleModeCombo2).columns(10)
 | 
			
		||||
        cell(cycleModeCombo3).columns(10)
 | 
			
		||||
        cell(cycleModeCombo4).columns(10)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    titledRow("Colors") {
 | 
			
		||||
      row("Jump mode caret background:") { short(jumpModeColorWheel) }
 | 
			
		||||
      row("Jump to End mode caret background:") { short(jumpEndModeColorWheel) }
 | 
			
		||||
      row("Target mode caret background:") { short(targetModeColorWheel) }
 | 
			
		||||
      row("Definition mode caret background:") { short(definitionModeColorWheel) }
 | 
			
		||||
      row("Searched text background:") { short(textHighlightColorWheel) }
 | 
			
		||||
      row("Tag foreground:") { short(tagForegroundColorWheel) }
 | 
			
		||||
      row("Tag background:") { short(tagBackgroundColorWheel) }
 | 
			
		||||
    group("Colors") {
 | 
			
		||||
      row("Jump mode caret background:") { cell(jumpModeColorWheel) }
 | 
			
		||||
      row("Jump to End mode caret background:") { cell(jumpEndModeColorWheel) }
 | 
			
		||||
      row("Target mode caret background:") { cell(targetModeColorWheel) }
 | 
			
		||||
      row("Definition mode caret background:") { cell(definitionModeColorWheel) }
 | 
			
		||||
      row("Searched text background:") { cell(textHighlightColorWheel) }
 | 
			
		||||
      row("Tag foreground:") { cell(tagForegroundColorWheel) }
 | 
			
		||||
      row("Tag background:") { cell(tagBackgroundColorWheel) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    titledRow("Behavior") {
 | 
			
		||||
      row { short(searchWholeFileCheckBox.apply { text = "Search whole file" }) }
 | 
			
		||||
      row("Minimum typed characters (1-10):") { short(minQueryLengthField) }
 | 
			
		||||
    group("Behavior") {
 | 
			
		||||
      row { cell(searchWholeFileCheckBox.apply { text = "Search whole file" }) }
 | 
			
		||||
      row("Minimum typed characters (1-10):") { cell(minQueryLengthField) }
 | 
			
		||||
    }
 | 
			
		||||
    titledRow("Language Settings") {
 | 
			
		||||
      row { short(mapToASCIICheckBox.apply { text = "Map unicode to ASCII" }) }
 | 
			
		||||
    group("Language Settings") {
 | 
			
		||||
      row { cell(mapToASCIICheckBox.apply { text = "Map unicode to ASCII" }) }
 | 
			
		||||
    }
 | 
			
		||||
    titledRow("Visual") {
 | 
			
		||||
      row { short(showSearchNotificationCheckBox.apply { text = "Show hint with search text" }) }
 | 
			
		||||
    group("Visual") {
 | 
			
		||||
      row { cell(showSearchNotificationCheckBox.apply { text = "Show hint with search text" }) }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -130,13 +118,13 @@ internal class AceSettingsPanel {
 | 
			
		||||
    cycleMode3 = settings.cycleMode3
 | 
			
		||||
    cycleMode4 = settings.cycleMode4
 | 
			
		||||
    minQueryLength = settings.minQueryLength.toString()
 | 
			
		||||
    jumpModeColor = settings.jumpModeColor
 | 
			
		||||
    jumpEndModeColor = settings.jumpEndModeColor
 | 
			
		||||
    targetModeColor = settings.targetModeColor
 | 
			
		||||
    definitionModeColor = settings.definitionModeColor
 | 
			
		||||
    textHighlightColor = settings.textHighlightColor
 | 
			
		||||
    tagForegroundColor = settings.tagForegroundColor
 | 
			
		||||
    tagBackgroundColor = settings.tagBackgroundColor
 | 
			
		||||
    jumpModeColor = settings.getJumpModeJBC()
 | 
			
		||||
    jumpEndModeColor = settings.getJumpEndModeJBC()
 | 
			
		||||
    targetModeColor = settings.getTargetModeJBC()
 | 
			
		||||
    definitionModeColor = settings.getDefinitionModeJBC()
 | 
			
		||||
    textHighlightColor = settings.getTextHighlightJBC()
 | 
			
		||||
    tagForegroundColor = settings.getTagForegroundJBC()
 | 
			
		||||
    tagBackgroundColor = settings.getTagBackgroundJBC()
 | 
			
		||||
    searchWholeFile = settings.searchWholeFile
 | 
			
		||||
    mapToASCII = settings.mapToASCII
 | 
			
		||||
    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.setValue(a: AceSettingsPanel, p: KProperty<*>, s: String) = setText(s)
 | 
			
		||||
 | 
			
		||||
  private operator fun ColorPanel.getValue(a: AceSettingsPanel, p: KProperty<*>) = selectedColor
 | 
			
		||||
  private operator fun ColorPanel.setValue(a: AceSettingsPanel, p: KProperty<*>, c: Color?) = setSelectedColor(c)
 | 
			
		||||
  private operator fun ResettableColorPicker.getValue(a: AceSettingsPanel, p: KProperty<*>) = getSelectedColor()
 | 
			
		||||
  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.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;
 | 
			
		||||
  
 | 
			
		||||
  val caretColor: Color
 | 
			
		||||
    get() = when (this) {
 | 
			
		||||
  val caretColor: Color get() = when (this) {
 | 
			
		||||
    DISABLED    -> AbstractColorsScheme.INHERITED_COLOR_MARKER
 | 
			
		||||
    JUMP        -> AceConfig.jumpModeColor
 | 
			
		||||
    JUMP_END    -> AceConfig.jumpEndModeColor
 | 
			
		||||
      DECLARATION -> AceConfig.definitionModeColor
 | 
			
		||||
    TARGET      -> AceConfig.targetModeColor
 | 
			
		||||
      DISABLED    -> AbstractColorsScheme.INHERITED_COLOR_MARKER
 | 
			
		||||
    DECLARATION -> AceConfig.definitionModeColor
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  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"),
 | 
			
		||||
  QGMLWY(arrayOf("1234567890", "qgmlwyfub", "dstnriaeoh", "zxcvjkp"), priority = "naterisodhvkcpjxzlfmuwygbq5849673210"),
 | 
			
		||||
  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 allPriorities = priority.mapIndexed { index, char -> char to index }.toMap()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
package org.acejump.search
 | 
			
		||||
 | 
			
		||||
enum class Pattern(val regex: String) {
 | 
			
		||||
  LINE_STARTS("^.|^\\n"),
 | 
			
		||||
  LINE_STARTS("^.|^\\n|(?<!.)\\Z"),
 | 
			
		||||
  LINE_ENDS("\\n|\\Z"),
 | 
			
		||||
  LINE_INDENTS("[^\\s].*|^\\n"),
 | 
			
		||||
  LINE_ALL_MARKS(LINE_ENDS.regex + "|" + LINE_STARTS.regex + "|" + LINE_INDENTS.regex),
 | 
			
		||||
  LINE_INDENTS("[^\\s].*|^\\n|(?<!.)\\Z"),
 | 
			
		||||
  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_]");
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ package org.acejump.search
 | 
			
		||||
import com.intellij.openapi.editor.Editor
 | 
			
		||||
import it.unimi.dsi.fastutil.ints.IntArrayList
 | 
			
		||||
import org.acejump.boundaries.Boundaries
 | 
			
		||||
import org.acejump.boundaries.EditorOffsetCache
 | 
			
		||||
import org.acejump.immutableText
 | 
			
		||||
import org.acejump.isWordPart
 | 
			
		||||
import org.acejump.matchesAt
 | 
			
		||||
@@ -12,7 +13,6 @@ import org.acejump.matchesAt
 | 
			
		||||
 * previous results when the user [type]s a character.
 | 
			
		||||
 */
 | 
			
		||||
internal class SearchProcessor private constructor(
 | 
			
		||||
  private val editors: List<Editor>,
 | 
			
		||||
  query: SearchQuery,
 | 
			
		||||
  results: MutableMap<Editor, IntArrayList>
 | 
			
		||||
) {
 | 
			
		||||
@@ -24,14 +24,15 @@ internal class SearchProcessor private constructor(
 | 
			
		||||
      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()
 | 
			
		||||
    
 | 
			
		||||
    if (regex != null) {
 | 
			
		||||
      for (editor in editors) {
 | 
			
		||||
        val cache = EditorOffsetCache.new()
 | 
			
		||||
        val offsets = IntArrayList()
 | 
			
		||||
        
 | 
			
		||||
        val offsetRange = boundaries.getOffsetRange(editor)
 | 
			
		||||
        val offsetRange = boundaries.getOffsetRange(editor, cache)
 | 
			
		||||
        var result = regex.find(editor.immutableText, offsetRange.first)
 | 
			
		||||
        
 | 
			
		||||
        while (result != null) {
 | 
			
		||||
@@ -43,7 +44,7 @@ internal class SearchProcessor private constructor(
 | 
			
		||||
          if (highlightEnd > offsetRange.last) {
 | 
			
		||||
            break
 | 
			
		||||
          }
 | 
			
		||||
          else if (boundaries.isOffsetInside(editor, index)) {
 | 
			
		||||
          else if (boundaries.isOffsetInside(editor, index, cache)) {
 | 
			
		||||
            offsets.add(index)
 | 
			
		||||
          }
 | 
			
		||||
          
 | 
			
		||||
@@ -70,7 +71,7 @@ internal class SearchProcessor private constructor(
 | 
			
		||||
   */
 | 
			
		||||
  fun type(char: Char, tagger: Tagger): Boolean {
 | 
			
		||||
    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
 | 
			
		||||
    // 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() {
 | 
			
		||||
    override val rawText = ""
 | 
			
		||||
 | 
			
		||||
    override fun getHighlightLength(text: CharSequence, offset: Int) = 1
 | 
			
		||||
    override fun getHighlightLength(text: CharSequence, offset: Int) = 0
 | 
			
		||||
 | 
			
		||||
    override fun toRegex(): Regex =
 | 
			
		||||
      Regex(pattern, setOf(RegexOption.MULTILINE, RegexOption.IGNORE_CASE))
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ import org.acejump.immutableText
 | 
			
		||||
import org.acejump.input.KeyLayoutCache
 | 
			
		||||
import org.acejump.isWordPart
 | 
			
		||||
import org.acejump.wordEndPlus
 | 
			
		||||
import java.util.*
 | 
			
		||||
import java.util.IdentityHashMap
 | 
			
		||||
import kotlin.math.max
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -89,6 +89,10 @@ internal class Solver private constructor(
 | 
			
		||||
      while (iter.hasNext()) {
 | 
			
		||||
        val site = iter.nextInt()
 | 
			
		||||
        
 | 
			
		||||
        if (editor.foldingModel.isOffsetCollapsed(site)) {
 | 
			
		||||
          continue
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for ((firstLetter, tags) in tagsByFirstLetter.entries) {
 | 
			
		||||
          if (canTagBeginWithChar(editor, site, firstLetter)) {
 | 
			
		||||
            for (tag in tags) {
 | 
			
		||||
@@ -187,6 +191,9 @@ internal class Solver private constructor(
 | 
			
		||||
    val chars = editor.immutableText
 | 
			
		||||
    val left = max(0, site + queryLength - 1)
 | 
			
		||||
    val right = chars.wordEndPlus(site)
 | 
			
		||||
    if (right >= chars.length) {
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    val builder = StringBuilder(1 + right - left)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,8 @@
 | 
			
		||||
package org.acejump.search
 | 
			
		||||
 | 
			
		||||
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 it.unimi.dsi.fastutil.ints.IntArrayList
 | 
			
		||||
import it.unimi.dsi.fastutil.ints.IntList
 | 
			
		||||
import org.acejump.ExternalUsage
 | 
			
		||||
import org.acejump.*
 | 
			
		||||
import org.acejump.boundaries.EditorOffsetCache
 | 
			
		||||
import org.acejump.boundaries.StandardBoundaries.VISIBLE_ON_SCREEN
 | 
			
		||||
import org.acejump.immutableText
 | 
			
		||||
import org.acejump.input.KeyLayoutCache.allPossibleTags
 | 
			
		||||
import org.acejump.isWordPart
 | 
			
		||||
import org.acejump.matchesAt
 | 
			
		||||
import org.acejump.view.TagMarker
 | 
			
		||||
import java.util.AbstractMap.SimpleImmutableEntry
 | 
			
		||||
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 {
 | 
			
		||||
    return query.endsWith(key, true) && isTagCompatibleWithQuery(key, value, query)
 | 
			
		||||
  }
 | 
			
		||||
  private infix fun Map.Entry<String, Tag>.solves(query: String): Boolean =
 | 
			
		||||
    query.endsWith(key, true) && isTagCompatibleWithQuery(key, value, query)
 | 
			
		||||
  
 | 
			
		||||
  private fun isTagCompatibleWithQuery(marker: String, tag: Tag, query: String): Boolean {
 | 
			
		||||
    return tag.editor.immutableText.matchesAt(tag.offset, getPlaintextPortion(query, marker), ignoreCase = true)
 | 
			
		||||
  }
 | 
			
		||||
  private fun isTagCompatibleWithQuery(marker: String, tag: Tag, query: String): Boolean =
 | 
			
		||||
    tag.editor.immutableText.matchesAt(tag.offset, getPlaintextPortion(query, marker), ignoreCase = true)
 | 
			
		||||
  
 | 
			
		||||
  fun isQueryCompatibleWithTagAt(query: String, tag: Tag): Boolean {
 | 
			
		||||
    return tagMap.inverse()[tag].let { it != null && isTagCompatibleWithQuery(it, tag, query) }
 | 
			
		||||
  }
 | 
			
		||||
  fun isQueryCompatibleWithTagAt(query: String, tag: Tag): Boolean =
 | 
			
		||||
    tagMap.inverse()[tag].let { it != null && isTagCompatibleWithQuery(it, tag, query) }
 | 
			
		||||
  
 | 
			
		||||
  fun canQueryMatchAnyTag(query: String): Boolean {
 | 
			
		||||
    return tagMap.any { (tag, offset) ->
 | 
			
		||||
      val tagPortion = getTagPortion(query, tag)
 | 
			
		||||
      tagPortion.isNotEmpty() && tag.startsWith(tagPortion, ignoreCase = true) && isTagCompatibleWithQuery(tag, offset, query)
 | 
			
		||||
    }
 | 
			
		||||
  fun canQueryMatchAnyVisibleTag(query: String): Boolean =
 | 
			
		||||
    tagMap.any { (label, tag) ->
 | 
			
		||||
      val tagPortion = getTagPortion(query, label)
 | 
			
		||||
      tagPortion.isNotEmpty()
 | 
			
		||||
        && label.startsWith(tagPortion, ignoreCase = true)
 | 
			
		||||
        && isTagCompatibleWithQuery(label, tag, query)
 | 
			
		||||
        && tag.isVisible()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  private fun removeResultsWithOverlappingTags(editor: Editor, offsets: IntList) {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,6 @@ import com.intellij.openapi.editor.Editor
 | 
			
		||||
internal data class EditorSettings(
 | 
			
		||||
  private val isBlockCursor: Boolean,
 | 
			
		||||
  private val isBlinkCaret: Boolean,
 | 
			
		||||
  private val isReadOnly: Boolean
 | 
			
		||||
) {
 | 
			
		||||
  companion object {
 | 
			
		||||
    fun setup(editor: Editor): EditorSettings {
 | 
			
		||||
@@ -20,12 +19,10 @@ internal data class EditorSettings(
 | 
			
		||||
      val original = EditorSettings(
 | 
			
		||||
        isBlockCursor = settings.isBlockCursor,
 | 
			
		||||
        isBlinkCaret = settings.isBlinkCaret,
 | 
			
		||||
        isReadOnly = !document.isWritable
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      settings.isBlockCursor = true
 | 
			
		||||
      settings.isBlinkCaret = false
 | 
			
		||||
      document.setReadOnly(true)
 | 
			
		||||
 | 
			
		||||
      return original
 | 
			
		||||
    }
 | 
			
		||||
@@ -37,6 +34,5 @@ internal data class EditorSettings(
 | 
			
		||||
 | 
			
		||||
    settings.isBlockCursor = isBlockCursor
 | 
			
		||||
    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 org.acejump.boundaries.EditorOffsetCache
 | 
			
		||||
import org.acejump.boundaries.StandardBoundaries.VISIBLE_ON_SCREEN
 | 
			
		||||
import org.acejump.read
 | 
			
		||||
import java.awt.Graphics
 | 
			
		||||
import java.awt.Graphics2D
 | 
			
		||||
import java.awt.Rectangle
 | 
			
		||||
@@ -53,7 +54,7 @@ internal class TagCanvas(private val editor: Editor): JComponent(), CaretListene
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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) {
 | 
			
		||||
    super.paintChildren(g)
 | 
			
		||||
@@ -66,6 +67,7 @@ internal class TagCanvas(private val editor: Editor): JComponent(), CaretListene
 | 
			
		||||
 | 
			
		||||
    val cache = EditorOffsetCache.new()
 | 
			
		||||
    val viewRange = VISIBLE_ON_SCREEN.getOffsetRange(editor, cache)
 | 
			
		||||
    val foldingModel = editor.foldingModel
 | 
			
		||||
    val occupied = mutableListOf<Rectangle>()
 | 
			
		||||
 | 
			
		||||
    // 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 }
 | 
			
		||||
    caretMarker?.paint(g, editor, cache, font, occupied)
 | 
			
		||||
 | 
			
		||||
    for (marker in markers)
 | 
			
		||||
      if (marker.isOffsetInRange(viewRange) && marker !== caretMarker)
 | 
			
		||||
    for (marker in markers) {
 | 
			
		||||
      if (marker.isOffsetInRange(viewRange) && !foldingModel.isOffsetCollapsed(marker.offsetL) && marker !== caretMarker)
 | 
			
		||||
        marker.paint(g, editor, cache, font, occupied)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -81,6 +81,10 @@ class TagMarker(
 | 
			
		||||
      g.color = AceConfig.tagForegroundColor
 | 
			
		||||
      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? {
 | 
			
		||||
    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)
 | 
			
		||||
      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 {
 | 
			
		||||
    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)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,8 @@ import com.intellij.openapi.editor.colors.EditorFontType
 | 
			
		||||
import com.intellij.openapi.editor.markup.*
 | 
			
		||||
import com.intellij.openapi.editor.markup.HighlighterTargetArea.EXACT_RANGE
 | 
			
		||||
import com.intellij.ui.*
 | 
			
		||||
import com.intellij.ui.util.preferredHeight
 | 
			
		||||
import com.intellij.util.DocumentUtil
 | 
			
		||||
import com.intellij.util.ui.*
 | 
			
		||||
import it.unimi.dsi.fastutil.ints.IntList
 | 
			
		||||
import org.acejump.*
 | 
			
		||||
@@ -31,7 +33,7 @@ internal class TextHighlighter {
 | 
			
		||||
  /**
 | 
			
		||||
   * Label for the search notification.
 | 
			
		||||
   */
 | 
			
		||||
  private class NotificationLabel constructor(text: String?): JLabel(text) {
 | 
			
		||||
  private class NotificationLabel(text: String?): JLabel(text) {
 | 
			
		||||
    init {
 | 
			
		||||
      background = HintUtil.getInformationColor()
 | 
			
		||||
      foreground = JBColor.foreground()
 | 
			
		||||
@@ -61,9 +63,7 @@ internal class TextHighlighter {
 | 
			
		||||
      val modifications = (highlights?.size ?: 0) + offsets.size
 | 
			
		||||
      val enableBulkEditing = modifications > 1000
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        if (enableBulkEditing) document.isInBulkUpdate = true
 | 
			
		||||
 | 
			
		||||
      DocumentUtil.executeInBulk(document, enableBulkEditing) {
 | 
			
		||||
        highlights?.forEach(markup::removeHighlighter)
 | 
			
		||||
        previousHighlights[editor] = Array(offsets.size) { index ->
 | 
			
		||||
          val start = offsets.getInt(index)
 | 
			
		||||
@@ -72,8 +72,6 @@ internal class TextHighlighter {
 | 
			
		||||
          markup.addRangeHighlighter(start, end, LAYER, null, EXACT_RANGE)
 | 
			
		||||
            .apply { customRenderer = renderer }
 | 
			
		||||
        }
 | 
			
		||||
      } finally {
 | 
			
		||||
        if (enableBulkEditing) document.isInBulkUpdate = false
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -96,22 +94,21 @@ internal class TextHighlighter {
 | 
			
		||||
    previousHint?.hide()
 | 
			
		||||
 | 
			
		||||
    // add notification hint to first editor
 | 
			
		||||
    results.keys.first().let {
 | 
			
		||||
      val component: JComponent = it.component
 | 
			
		||||
    val editor = results.keys.first()
 | 
			
		||||
    val component: JComponent = editor.component
 | 
			
		||||
 | 
			
		||||
      val label1: JLabel = NotificationLabel(" " +
 | 
			
		||||
        CodeInsightBundle.message("incremental.search.tooltip.prefix"))
 | 
			
		||||
      label1.font = UIUtil.getLabelFont().deriveFont(Font.BOLD)
 | 
			
		||||
    val label1 = NotificationLabel(" $jumpMode Mode:")
 | 
			
		||||
      .apply { font = UIUtil.getLabelFont().deriveFont(Font.BOLD) }
 | 
			
		||||
 | 
			
		||||
    val queryText = " " +
 | 
			
		||||
        if (query is SearchQuery.RegularExpression) query.toRegex().toString()
 | 
			
		||||
        else query.rawText[0] + query.rawText.drop(1).lowercase()
 | 
			
		||||
      (if (query is SearchQuery.RegularExpression) query.toRegex().toString()
 | 
			
		||||
      else query.rawText[0] + query.rawText.drop(1).lowercase()) + "   "
 | 
			
		||||
    val label2 = NotificationLabel(queryText)
 | 
			
		||||
 | 
			
		||||
    val label3 = NotificationLabel(
 | 
			
		||||
      "Found ${results.values.flatMap { it.asIterable() }.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 {
 | 
			
		||||
@@ -119,35 +116,37 @@ internal class TextHighlighter {
 | 
			
		||||
      add(label2, BorderLayout.CENTER)
 | 
			
		||||
      add(label3, BorderLayout.EAST)
 | 
			
		||||
      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 +
 | 
			
		||||
          label1.preferredSize.width, preferredSize.height)
 | 
			
		||||
      preferredHeight = label1.preferredSize.height + 10
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val hint = LightweightHint(panel)
 | 
			
		||||
 | 
			
		||||
    val x = SwingUtilities.convertPoint(component, 0, 0, component).x
 | 
			
		||||
    val y: Int = -hint.component.preferredSize.height
 | 
			
		||||
      val p = SwingUtilities.convertPoint(component, x, y,
 | 
			
		||||
        component.rootPane.layeredPane)
 | 
			
		||||
    val p = SwingUtilities.convertPoint(
 | 
			
		||||
      component, x, y,
 | 
			
		||||
      component.rootPane.layeredPane
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    HintManagerImpl.getInstanceImpl().showEditorHint(
 | 
			
		||||
      hint,
 | 
			
		||||
        it,
 | 
			
		||||
      editor,
 | 
			
		||||
      p,
 | 
			
		||||
      HIDE_BY_ESCAPE or HIDE_BY_TEXT_CHANGE,
 | 
			
		||||
      0,
 | 
			
		||||
      false,
 | 
			
		||||
        HintHint(it, p).setAwtTooltip(false)
 | 
			
		||||
      HintHint(editor, p).setAwtTooltip(false)
 | 
			
		||||
    )
 | 
			
		||||
    previousHint = hint
 | 
			
		||||
  }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fun reset() {
 | 
			
		||||
    previousHighlights.keys.forEach { it.markupModel.removeAllHighlighters() }
 | 
			
		||||
    previousHighlights.forEach { (editor, highlighters) ->
 | 
			
		||||
      highlighters.forEach(editor.markupModel::removeHighlighter)
 | 
			
		||||
    }
 | 
			
		||||
    previousHighlights.clear()
 | 
			
		||||
    previousHint?.hide()
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -20,27 +20,38 @@
 | 
			
		||||
                             id="preferences.AceConfigurable" dynamic="true"/>
 | 
			
		||||
 | 
			
		||||
    <editorActionHandler action="EditorEscape" order="first"
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$Reset"/>
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$Reset"
 | 
			
		||||
                         id="AceHandlerEscape"/>
 | 
			
		||||
    <editorActionHandler action="EditorBackSpace" order="first"
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$ClearSearch"/>
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$ClearSearch"
 | 
			
		||||
                         id="AceHandlerBackSpace"/>
 | 
			
		||||
    <editorActionHandler action="EditorStartNewLine" order="first"
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SelectBackward"/>
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SelectBackward"
 | 
			
		||||
                         id="AceHandlerStartNewLine"/>
 | 
			
		||||
    <editorActionHandler action="EditorEnter" order="first"
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SelectForward"/>
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SelectForward"
 | 
			
		||||
                         id="AceHandlerEnter"/>
 | 
			
		||||
    <editorActionHandler action="EditorTab" order="first"
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$ScrollToNextScreenful"/>
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$ScrollToNextScreenful"
 | 
			
		||||
                         id="AceHandlerTab"/>
 | 
			
		||||
    <editorActionHandler action="EditorUnindentSelection" order="first"
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$ScrollToPreviousScreenful"/>
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$ScrollToPreviousScreenful"
 | 
			
		||||
                         id="AceHandlerUnindentSelection"/>
 | 
			
		||||
    <editorActionHandler action="EditorUp" order="first"
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineStarts"/>
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineStarts"
 | 
			
		||||
                         id="AceHandlerUp"/>
 | 
			
		||||
    <editorActionHandler action="EditorLeft" order="first"
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineIndents"/>
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineIndents"
 | 
			
		||||
                         id="AceHandlerLeft"/>
 | 
			
		||||
    <editorActionHandler action="EditorLineStart" order="first"
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineIndents"/>
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineIndents"
 | 
			
		||||
                         id="AceHandlerLineStart"/>
 | 
			
		||||
    <editorActionHandler action="EditorRight" order="first"
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineEnds"/>
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineEnds"
 | 
			
		||||
                         id="AceHandlerRight"/>
 | 
			
		||||
    <editorActionHandler action="EditorLineEnd" order="first"
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineEnds"/>
 | 
			
		||||
                         implementationClass="org.acejump.action.AceEditorAction$SearchLineEnds"
 | 
			
		||||
                         id="AceHandlerLineEnd"/>
 | 
			
		||||
 | 
			
		||||
  </extensions>
 | 
			
		||||
 | 
			
		||||
@@ -55,6 +66,12 @@
 | 
			
		||||
    <action id="AceReverseAction"
 | 
			
		||||
            class="org.acejump.action.AceAction$ActivateOrReverseCycleMode"
 | 
			
		||||
            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"
 | 
			
		||||
            class="org.acejump.action.AceAction$ToggleJumpMode"
 | 
			
		||||
            text="Start AceJump in Jump Mode"/>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
<?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">
 | 
			
		||||
<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 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;"/>
 | 
			
		||||
 
 | 
			
		||||
| 
		 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`() {
 | 
			
		||||
    makeEditor("    test\n    three\n    lines\n")
 | 
			
		||||
    makeEditor("    test\n    three\n    lines")
 | 
			
		||||
 | 
			
		||||
    takeAction(AceAction.StartAllLineMarksMode())
 | 
			
		||||
 | 
			
		||||
    assertEquals(8, session.tags.size) // last empty line does not count
 | 
			
		||||
    assertEquals(9, session.tags.size)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fun `test chinese selection`() {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
import com.intellij.mock.MockVirtualFile
 | 
			
		||||
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.util.ui.UIUtil
 | 
			
		||||
import it.unimi.dsi.fastutil.ints.IntArrayList
 | 
			
		||||
@@ -41,12 +43,12 @@ class ExternalUsageTest: BaseTest() {
 | 
			
		||||
  fun `test externally tagged results with multiple editors`() {
 | 
			
		||||
    val fileA = MockVirtualFile("a.txt", "first file")
 | 
			
		||||
    val fileB = MockVirtualFile("b.txt", "second file with more markers")
 | 
			
		||||
    myManager.openFile(fileA, true)
 | 
			
		||||
    myManager.openFile(fileB, false)
 | 
			
		||||
    manager?.openFile(fileA, true)
 | 
			
		||||
    manager?.openFile(fileB, false)
 | 
			
		||||
    
 | 
			
		||||
    val mainEditor = (myManager.selectedEditor as TextEditor).editor
 | 
			
		||||
    val editorA = (myManager.getEditors(fileA).single() as TextEditor).editor
 | 
			
		||||
    val editorB = (myManager.getEditors(fileB).single() as TextEditor).editor
 | 
			
		||||
    val mainEditor = (manager?.selectedEditor as TextEditor).editor
 | 
			
		||||
    val editorA = (manager?.getEditors(fileA)?.single() as TextEditor).editor
 | 
			
		||||
    val editorB = (manager?.getEditors(fileB)?.single() as TextEditor).editor
 | 
			
		||||
    
 | 
			
		||||
    val session = SessionManager.start(mainEditor, listOf(editorA, editorB))
 | 
			
		||||
    
 | 
			
		||||
@@ -85,7 +87,7 @@ class ExternalUsageTest: BaseTest() {
 | 
			
		||||
    SessionManager.start(myFixture.editor)
 | 
			
		||||
      .startRegexSearch("[aeiou]+", WHOLE_FILE)
 | 
			
		||||
 | 
			
		||||
    TestCase.assertEquals(8, session.tags.size)
 | 
			
		||||
    TestCase.assertEquals(9, session.tags.size)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fun `test external jump with bounds`() {
 | 
			
		||||
@@ -166,4 +168,21 @@ class ExternalUsageTest: BaseTest() {
 | 
			
		||||
    TestCase.assertEquals(mark, detectedMark)
 | 
			
		||||
    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
 | 
			
		||||
class LatencyTest: BaseTest() {
 | 
			
		||||
 | 
			
		||||
  private fun `test tag latency`(editorText: String) {
 | 
			
		||||
    val chars = editorText.toCharArray().distinct().filter { !it.isWhitespace() }
 | 
			
		||||
    val avg = averageTimeWithWarmup(warmupRuns = 10, timedRuns = 10) {
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ abstract class BaseTest: FileEditorManagerTestCase() {
 | 
			
		||||
      UIUtil.dispatchAllInvocationEvents()
 | 
			
		||||
      assertEmpty(it.markupModel.allHighlighters)
 | 
			
		||||
    }
 | 
			
		||||
    myManager.closeAllFiles()
 | 
			
		||||
    manager?.closeAllFiles()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fun typeAndWaitForResults(string: String) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user