The script aims to provide a programmable interface, allowing to relatively simply integrate a custom word autocomplete function in a given script or project. Any Edit
/RICHEDIT50W
control should be able to be wrapped into an eAutocomplete
object. Practically, the script enables you, as you type, to quickly find and select from a dynamic set of data (i.e. complete strings and replacement strings) and get suggestion-based info tips - leveraging this way typing, definition lookups, searching, translation, filtering etc.
This readme provides an overview of the development version and, as such, may not necessarily present your current version. Consider checking out the html file (eAutocomplete.html) bundled in the release for an overview of the programmable interface.
Download the latest release
Notes:
- Unlike the latest release, the master branch is not considered as fully tested on each commit.
- Although I have been careful to ensure that the script is right and efficient, I should underlined that I am not a programmer: this code should only serve as a basis for your own development and it is more reasonable to assume that the script cannot be used in unmodified form in a production environment.
- AlphaBravo, jeeswg and just me.
- brutus_skywalker for his valuable suggestions on how to make more ergonomic and user-friendly the common features provided by the script via the use of keyboard shortcuts.
- G33kDude (GeekDude) and ManiacDC whose respective works - respectively CQT.AutoComplete.ahk and TypingAid - served as models for this one.
- Uberi for its score fuzzy search algorithm.
- A special thanks to FanaticGuru for its Sift_Regex function.
- Thanks to the AutoHotkey community.
The script enables, as typing in an Edit
/RICHEDIT50W
control, to quickly find and select from a dynamic pre-populated list of suggestions and, by this means, to expand/replace partially entered strings into/by complete strings. When you start to type in the target control and a brief rest occurred since the last keystroke, the script starts searching for entries that match and should automatically - by default at least - display complete strings to choose from, which are based:
- on earlier typed characters (letters, symbols etc.);
- on the content and settings of the current wordlist;
- on the recentness of use of the matching suggestions.
The script integrates the Sift_Regex function: fuzzy searching is available, assuming the given wordlist and its Query
's interface have been set up to allow it. By way of examples, and depending on the setting, ahkey
, AHKey
, a.+?key$
or auto
could match autohotkey
- and suggest it as an autocomplete string.
Known limitation: for efficiency reasons, and for want of anything better, the script preprocessed the user-defined wordlist, creating a list alphabetically splitted in subsections; a pending word is check against the subsection of the autocomplete source where all words start with the very first letter by which a given pending word starts so that the length of the input string whose content is searched is reduced. This means, for example, in 'regex mode', that
on$
will suggestobjection
because:
- 1° the word actually ends with 'on' (that is, actually observes the pattern to search for, represented by the regular expression used as query);
- 2° starts with 'o': the search has been conducted on the subsection where all words start with 'o'.
In other words, and by way of example,
on$
won't be able to suggestabandon
(in this case one should useaon$
instead).
Depending on the setting of the Menu
member's own positioning strategy, the list of choices is displayed in the vicinity of the host control's caret or beneath the control instead, in the manner of a combobox menu. Items can be clicked to complete words and the menu is designed in such way that it does not get focused while being able to interact with it. Also, you can display suggestion-based info tips (when applicable, they appear in a tooltip, near the selected suggestion).
The key features provided by the script are accessible using keyboard shortcuts, which are customizable. By default, hotkeys default to the following values:
- Press the Tab key to complete a pending word with the selected suggestion (the top most suggestion is selected by default either when the menu drops or is updated upon match or when you invoke it).
- Use both the Down and Up arrow keys to select from the list all other available suggestions. Hitting Up while the first item is selected will bring you to the last one while hitting Down on the last item will bring you to the first one.
- Long press Tab to replace the current partial string (should call the onReplacement callback, if any).
- The Enter hotkey is functionally equivalent to the Tab one except that it also moves the caret to the next line at the same time.
- Press and hold ⯈ (that is, the right arrow key) to look up the selected suggestion's associated info tip (should call the onSuggestionLookUp callback, if any).
- The menu can be hidden by pressing the combination Shift+Esc.
- If
autoSuggest
is disabled or if you previously hid the menu, Ctrl+Shift+Down displays the menu, assuming one or more suggestions are available and that the caret is positioned in such a way that completion is practicable.
An instance can optionally learn hapax legomena at their first onset (or simply collect them for use in a single session) by setting the respective value of the given wordlist's learnWords
and collectWords
properties.
On a side note, the graphics of the menu and of both the listbox and the infotip it owns are to some extent customizable via their respective interface.
- Download the latest release and extract the content of the zip file to a location of your choice, for example into your project's folder hierarchy.
- Load the library (
\eAutocomplete.ahk
) by means of the #Include directive. eAutocomplete
is at its root designed as a super global automatically initialized singleton; you don't need to create a new instance of the class (besides, any attempt to create a new instance will throw an exception).- You must call the wrap base method to endow with word completion feature an existing edit control (e.g. Notepad's one) or an existing rich edit control (e.g. Poor Man's Rich Edit GUI's one).
But first it might be necessary to load a wordlist, either from a file or a variable, preparing it beforehand, when appropriate. This is precisely the subject of the next section.
Autocompletion data are assumed to be described as a simple LF/CRLF-separated set of lines.
A given line may be commented out by prefixing it by one or more space (or tab) characters - while a given part of a line may be excluded from the string which is intended to be displayed in the autocomplete menu, as an actual suggestion, by prefixing it by one or more tab characters:
...
summer this is a comment
sun
sunday this is not a comment
this is a comment
this is a comment
...
You must first call either the WordList.buildFromFile
or the WordList.buildFromVar
eAutocomplete
's base method to prepare a new list for use as an autocomplete list.
wlo := eAutocomplete.WordList.buildFromFile(_sourceName, _fileFullPath, _exportPath:="", _caseSensitive:=false)
wlo := eAutocomplete.WordList.buildFromVar(_sourceName, _list:="", _exportPath:="", _caseSensitive:=false)
wlo := eAutocomplete.WordList.setFromFile(_sourceName, _fileFullPath:="", _exportPath:="", _caseSensitive:=false)
wlo := eAutocomplete.WordList.setFromVar(_sourceName, _list:="", _exportPath:="", _caseSensitive:=false)
[buildFrom...
] Load a list of suggestions from a file/a variable and prepare the given list for use as an autocompletion list.
[setFrom...
] Set an already formatted list of suggestion from a file/a variable for use as an autocompletion list.
parameter | description |
---|---|
_sourceName [STRING] |
The name of the wordlist, which may consist of alphanumeric characters, underscore and non-ASCII characters. |
_fileFullPath [FILE_FULL_PATH] |
[...FromFile ] The absolute path of the file to read and whose content will be used to build or set the autocomplete list. |
_list [STRING] |
[...FromVar ] A list, as string of characters, from which to build or set the autocomplete list. You can use FileRead or a continuation section to save a series of lines to a variable. |
_exportPath [FILE_FULL_PATH/INTEGER] |
The absolute path of the file to which export the formatted autocomplete list and any update of its content (see also: learnWords ). The file is created if need be and overwritten if it already exists. [...FromFile ]: Specify -1 to use _fileFullPath as export file. |
_caseSensitive [BOOLEAN] |
A boolean value which determines whether or not items in the autocomplete list which are distinguishable one from the other only by their case should be considered as identical (false ) or not (true ). |
return value: all four methods return an new WordList object upon success.
All four methods throw an exception on failure.
Object member | description |
---|---|
Query.Sift |
Description soon available. |
Query.Word |
Description soon available. |
The WordList
object provides an interface that allows you to set for a given wordlist:
- its learning behaviour.
- its own definition of what a 'word' consists in.
- its way of sifting or searching through data for items that match a given pending word.
You can find below all properties available for the WordList
object:
property | description | default value | |
---|---|---|---|
collectAt [UNSIGNED_INTEGER] |
Specify how many times a 'word' absent from the wordlist should be typed before being actually collected by the instance. Instance's concept of 'word' is affected by the setting of the query.word member. Once collected, words are valid during a single session (see also: learnWords ). Each time you set this value, all internal instance's counters are reset: a given non-yet collected 'word' must anew be typed collectAt time(s) to trigger the collecting mechanism (that is, regardless of how many times it has been typed so far). |
4 |
|
collectWords [BOOLEAN] |
Specify whether or not an instance should collect 'words' at their collectAt -nth onset. Once collected, words are valid during a single session (see also: learnWords ). |
true |
|
learnWords [BOOLEAN] |
If the value evaluates to true at the time the eAutocomplete's current wordlist is replaced by a new one or at the time the script exits, collected words and the ranking of all the entries of the given wordlist, based on their respective recentness will be stored into the instance's export file. |
false |
|
name [STRING] [READ_ONLY] |
The name of the wordlist. | runtime/user-defined | |
query.sift | |||
option [SIFT_REGEX_OPTION] |
One of the following Sift_Regex options:IN Needle anywhere IN Haystack itemLEFT Needle is to LEFT or beginning of Haystack itemRIGHT Needle is to RIGHT or end of Haystack itemEXACT Needle is an EXACT match to Haystack itemREGEX Needle is an REGEX expression to check against Haystack itemOC Needle is ORDERED CHARACTERS to be searched for even non-consecutively but in the given order in Haystack itemOW Needle is ORDERED WORDS to be searched for even non-consecutively but in the given order in Haystack itemUC Needle is UNORDERED CHARACTERS to be search for even non-consecutively and in any order in Haystack itemUW Needle is UNORDERED WORDS to be search for even non-consecutively and in any order in Haystack item(see also: Sift_Regex) |
"LEFT" |
|
query.word | |||
edgeKeys [STRING] |
A list of zero or more characters, considered as not being part of a 'word', that is, all characters that can work as outer edges of a word. Space characters - space, tab, and newlines - are always considered as edge keys. | "\/|?!,;.:(){}[]'""<>@=" |
|
minLength [UNSIGNED_INTEGER] |
Set the minimum number of characters a word must contain to be actually seen as a 'word'. | 2 |
Note: the collecting/learning mechanism is case (in)sensitive if the wordlist has been created as case (in)sensitive.
Known limitation: for now, the script is unable to make a distinction between 'edge chars' and symbols commonly used in the regex syntax: if you want to use a regex symbol as such (by setting
(this).query.sift.option
to"REGEX"
), it must not be listed inedgeKeys
.
Once you have created / loaded one or more wordlists, you can wrap one or more controls and use the eAutocomplete
interface to set up the autocomplete feature:
#NoEnv
#Warn
#Include %A_ScriptDir%\eAutocomplete.ahk
list =
(Join`r`n
Control , Cmd [, Value, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlClick [, Control-or-Pos, WinTitle, WinText, WhichButton, ClickCount, Options, ExcludeTitle, ExcludeText]
ControlFocus [, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlGet , OutputVar, Cmd [, Value, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlGetFocus , OutputVar [, WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlGetPos [, X, Y, Width, Height, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlGetText , OutputVar [, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlMove , Control, X, Y, Width, Height [, WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlSend [, Control, Keys, WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlSetText [, Control, NewText, WinTitle, WinText, ExcludeTitle, ExcludeText]
)
global params := Object(StrSplit(list, ["`r`n", "`t"])*)
source := eAutocomplete.WordList.buildFromVar("myList", list)
query := source.Query
query.Word.minLength := 1
query.Sift.option := "OC"
GUI, New
GUI, Font, s14, Segoe UI
GUI, Add, Edit, hwndhEdit w200 h200
GUI, Show, AutoSize, eAutocomplete
eAutocomplete.wrap(hEdit)
eAutocomplete.resource := source.name
Menu := eAutocomplete.Menu
Menu.positioningStrategy := "DropDownList"
Menu.InfoTip.font.setCharacteristics("Segoe UI", "s11")
Menu.itemsBox.maxVisibleItems := 5
eAutocomplete.onSuggestionLookUp("eA_onSuggestionLookUp")
eAutocomplete.onComplete("eA_onComplete")
return
eA_onComplete(_suggestion, ByRef _expandModeOverride:="") {
static EXPAND_NO_SPACE := 0
return _suggestion . params[_suggestion], _expandModeOverride:=EXPAND_NO_SPACE
}
eA_onSuggestionLookUp(_selectionText) {
return params[_selectionText]
}
!x::
ExitApp
property | description | default value |
---|---|---|
eAutocomplete.autoSuggest [BOOLEAN] |
If set to true the autocompletion feature automatically displays a menu as soon as suggestions are available. Otherwise, if set to false , the Ctrl+Shift+Down hotkey can display the menu, assuming one or more suggestions are available and that the caret is positioned in such a way that completion is practicable. |
true |
eAutocomplete.disabled [BOOLEAN] |
Disable (true ) or enable (false ), if need be, the autocomplete feature. Use the unwrap method instead to deprive a control of its eAutocomplete word completion feature and interface. |
false |
eAutocomplete.keypressThreshold [UNSIGNED_INTEGER] |
The number of milliseconds that must pass before eAutocomplete starts searching for entries that match in the autocomplete list. Keystroke events separated by a period of less than this value are considered as part of an influx and are discarded as such while a single call is buffered: in other words, when you start to type in the target control and a brief rest of this property's value (in milliseconds) occurred since the last keystroke, eAutocomplete actually starts searching for entries that match in the autocomplete list. Specifying a number less than 65 is the same as specifying 65. | 225 |
eAutocomplete.resource [SOURCE_NAME/WORDLIST_OBJECT] |
[setter] Specifies the autocomplete list to use. The value must be the name of a Wordlist instance. [getter] Returns the current Wordlist instance used for autocompletion. |
runtime/user-defined |
-
wrap
-
unwrap
-
OnComplete
-
OnReplacement
-
OnSuggestionLookUp
eAutocomplete.wrap(_hHost)
Endow an existing Edit
/RICHEDIT50W
control with the eAutocomplete word completion feature and interface.
parameter | description |
---|---|
_hHost [HWND] |
The HWND of the Edit /RICHEDIT50W control to be endowed with the eAutocomplete word completion feature and interface. |
You can wrap as many controls as you need. Once you have done with a control, you should call the unwrap method.
The method throws an exception on failure.
eAutocomplete.unwrap(_hHost)
Deprive an existing Edit
/RICHEDIT50W
control of its eAutocomplete word completion feature and interface, if applicable.
parameter | description |
---|---|
_hHost [HWND] |
The HWND of the Edit /RICHEDIT50W control whose the eAutocomplete word completion feature and interface should be removed. |
The method throws an exception on failure.
Other documented methods allows you to specify user-defined callbacks in order to implement a custom event handling. This is the subject of the next section.
The script is able to call a user-defined callback for the following events:
onComplete
onReplacement
onSuggestionLookUp
The value can be either the name of a function, a function reference or a boundFunc object.
eAutocomplete.onComplete("onCompleteEventHandler")
eAutocomplete.onComplete("") ; unregister the function object, if applicable
Associate a function with the complete
event. This would cause the function to be launched automatically whenever you are about to complete a word by pressing the Tab/Enter key (by default). The event fires before the complete string has been actually sent to the host control - the return value of the function being actually used as the actual complete string.
The function can optionally accept the following parameters:
completeString := onCompleteEventHandler(_suggestion, ByRef _expandModeOverride:="")
parameters | description |
---|---|
_suggestion |
The text of the selected suggestion, as visible in the autocomplete menu. |
_expandModeOverride |
If you give a value to this ByRef parameter, it can be that of an EXPAND_MODE - to locally and punctually override the eAutocomplete's Completor way to expand. The value can be -1 to complete and move the caret to the next line at the same time. |
eAutocomplete.onReplacement("onReplacementEventHandler")
eAutocomplete.onReplacement("") ; unregister the function object, if applicable
Associate a function with the replacement
event. This would cause the function to be launched automatically whenever you are about to replace a word by long pressing the Tab/Enter key (by default). The event fires before the replacement string has been actually sent to the host control - the return value of the function being actually used as the actual replacement string. This can be used to allow dynamic replacements, such as when replacement strings come from a translation API, for example.
The function can optionally accept the following parameters:
replacementString := onReplacementEventHandler(_suggestion, ByRef _expandModeOverride:="")
parameters | description |
---|---|
_suggestion |
The text of the selected suggestion, as visible in the autocomplete menu. |
_expandModeOverride |
If you give a value to this ByRef parameter, it can be that of an EXPAND_MODE - to locally and punctually override the eAutocomplete's Completor way to expand. The value can be -1 to replace and move the caret to the next line at the same time. |
eAutocomplete.onSuggestionLookUp("onSuggestionLookUpEventHandler")
eAutocomplete.onSuggestionLookUp("") ; unregister the function object, if applicable
Associate a function with the suggestionLookUp
event. This would cause the function to be launched automatically whenever you attempt to query an info tip from the selected suggestion by pressing and holding the ⯈ arrow key (by default). The return value of the callback will be used as the actual text displayed in the tooltip. This can be used to allow dynamic description lookups such as when description strings come from a dictionary API.
The function can optionally accept the following parameters:
infotTipText := onSuggestionLookUp(_selectionText)
parameters | description |
---|---|
_selectionText |
The text of the selected suggestion, as visible in the autocomplete menu. |
eAutocomplete ├── Resource (instance of eAutocomplete.WordList) ├── ├── Query ├── ├── ├── Sift ├── ├── ├── Word ├── Menu ├── ├── ItemsBox ├── ├── ├── Selection ├── ├── ├── Font ├── ├── Positioning ├── ├── InfoTip ├── ├── ├── Positioning ├── ├── ├── Font ├── Completor
Object member | description |
---|---|
WordList (resource) |
Description soon available. |
WordList.Query (resource.Query) |
Description soon available. |
WordList.Query.Sift (resource.Query.Sift) |
Description soon available. |
WordList.Query.Word (resource.Query.Word) |
Description soon available. |
Menu |
Description soon available. |
Menu.ItemsBox |
Description soon available. |
Menu.ItemsBox.selection |
Description soon available. |
Menu.ItemsBox.font |
Description soon available. |
Menu.Positioning |
Description soon available. |
Menu.InfoTip |
Description soon available. |
Menu.InfoTip.Positioning |
Description soon available. |
Menu.InfoTip.font |
Description soon available. |
Completor |
Description soon available. |
member | property | description | default value |
---|---|---|---|
menu | |||
bkColor [COLOR_VALUE/COLOR_NAME] (getter not implemented) |
Set the background color of the autocomplete menu by specifying one of the 16 primary HTML color names or a 6-digit RGB color value (in this latter case, the 0x prefix is optional). | 0xF0F0F0 |
|
positioningStrategy [POS_STRATEGY] |
Set or get the current strategy used to automatically place the autocomplete menu. The two following positioning strategies are available:Menu the list of choices is displayed in the vicinity of the host control's caretDropDownList the menu is displayed beneath the host control, in the manner of a combobox menu |
"Menu" |
|
transparency [UNSIGNED_INTEGER] |
Specify a number between 10 and 255 to indicate the autocomplete menu's degree of transparency. | 255 |
|
menu.itemsBox | |||
maxVisibleItems [UNSIGNED_INTEGER] |
The maximum number of suggestions that must be visible in the autocomplete menu without having to scrolling, if necesary. | 5 |
|
menu.itemsBox.selection | |||
index [UNSIGNED_INTEGER] |
- | runtime/user-defined | |
text [STRING] |
- | runtime/user-defined | |
menu.itemsBox.font | |||
color [COLOR_VALUE/COLOR_NAME] (getter not implemented) |
Set the font color for the autocomplete menu's list box by specifying one of the 16 primary HTML color names or a 6-digit RGB color value. | "000000" |
|
name [FONT_DENOMINATION] |
Set or get the font typeface for the autocomplete menu's list box. | "Segoe UI" |
|
size [UNSIGNED_INTEGER] (getter not implemented) |
Set the font size for the autocomplete menu's list box. | 12 |
|
menu.positioning | |||
offsetX [INTEGER] |
(The menu's positioning strategy must be "Menu") The offset from the current host control's caret position to which display the autocomplete menu, on the x-axis. The offset value can be negative. | 5 |
|
offsetY [INTEGER] |
(The menu's positioning strategy must be "Menu") The offset from the current host control's caret position to which display the autocomplete menu, on the y-axis. The offset value can be negative. | 25 |
|
menu.infotip.positioning | |||
offsetX [INTEGER] |
The offset from the abscissa of the selected suggestion's upper-left corner to which display the infotip. The offset value can be negative. | 5 |
|
completor | |||
correctCase [INTEGER] |
Determine whether the eAutocomplete's completor simply completes the pending word (that is, preserving this latter's case) or actually replaces it by the autocomplete menu's selected suggestion (or more precisely, by the return value of either the onComplete or the onReplacement callback, as appropriate). |
false |
|
expandMode [BOOLEAN] |
Determine whether or not the eAutocomplete's completor automatically expands or not the complete string with a space upon text expansion/replacement. | 1 |
CC BY-SA for the autocompletion list. Otherwise, Unlicence.