A way to warn about duplicate or partially duplicate hotstrings

Propose new features and changes
User avatar
Ross
Posts: 100
Joined: 13 Mar 2016, 00:27

A way to warn about duplicate or partially duplicate hotstrings

Post by Ross » 25 May 2021, 00:24

Since 2007 I've been populating my hotstring database with over 28000 entries now. Of course I don't remember all of them and don't need to; the ones most needed for the time being are recalled either naturally or via lookup.

But AutoHotKey doesn't come with a built-in way to detect or prevent duplicates as it does with hotkeys. Say I have this:

Code: Select all

:*:tjs::Tribunais de Justiça
:*:tjspc::trânsito em julgado da sentença penal condenatória


As you can see, the 2nd hotstring will never trigger because the 1st will trigger first, necessarily.
AutoHotKey could have a warning message to be shown upon execution of a script containing conflicting hotstrings, along with a prompt to fix one of them. It could speed up the process of creating and "normalizing" our hotstrings.

On the same subject, I don't know whether this is already possible via script, but there could be a way to:
  • Display a tooltip reminder whenever the user types the expanded string when there is already a hotstring defined;
  • Detect whether the user is typing the same whole, long word repeatedly and offer to create a hotstring for that.

lexikos
Posts: 9621
Joined: 30 Sep 2013, 04:07
Contact:

Re: A way to warn about duplicate or partially duplicate hotstrings

Post by lexikos » 28 May 2021, 06:54

// v1.0.42: Unlike hotkeys, duplicate hotstrings are not detected. This is because
// hotstrings are less commonly used and also because it requires more code to find
// hotstring duplicates (and performs a lot worse if a script has thousands of
// hotstrings) because of all the hotstring options.
That's probably without even considering hotstrings which are not duplicates, but where one is a substring of the other (as in your example).

Some thoughts:
  • If some options differ, the longer hotstring may be possible to trigger in some situations and not others, and that may be intentional. Some options don't affect the hotstring's conditions for triggering at all.
  • It would probably be necessary to always permit overlapping hotstrings with different criteria (#If/#HotIf), even though the criteria might overlap.
  • I assume you created :*:tjspc:: first, because if you tried it in the other order, you'd probably end up with :*:Tribunais de Justiçapc::.
  • I think it's sufficient that you'll find the conflict when you type the hotstring. Until then (and especially if you forget hotstrings like I do), it doesn't really matter.

I do not feel that the other features you have suggested should be built-in. If they are implemented in script, there is a lot more room for customizing the behaviour, or adding nice-to-have features that might not be worth implementing in C++. Aside from that, it's not something I would want to personally use or develop.


You can detect typed words with an InputHook.

Enumerating the existing hotstrings currently requires parsing the script (but that might not always be the case). This should be fairly reliable for v1:

Code: Select all

FileRead code, % A_ScriptFullPath
hotstrings := "", p := 1
while (p := RegExMatch(code, "Omi)^[ `t]*:([a-z0-9\?\*\- ]*):(.*)(?<!``)::", hs, p))
    && A_Index < 25 ; Limit the MsgBox for this demo.
{
    hotstrings .= hs.1 "`t" hs.2 "`n"
    p += hs.Len()
}
MsgBox % hotstrings
Or for v2:

Code: Select all

code := FileRead(A_ScriptFullPath)
hotstrings := "", p := 1
while (p := RegExMatch(code, "mi)^[ `t]*:([a-z0-9\?\*\- ]*):(.*?)(?<!``)::", &hs, p))
    && A_Index < 25 ; Limit the MsgBox for this demo.
{
    hotstrings .= hs.1 "`t" hs.2 "`n"
    p += hs.Len()
}
MsgBox hotstrings
This will of course show nothing if you run it as-is, because there are no hotstrings. Replace A_ScriptFullPath with something else if you want to read hotstrings from another file.

There's a slight difference in which pair of colons (::) is used if there are multiple possibilities, and the v1 code above actually isn't correct, because the current v1 behaviour is just weird. Best not to use hotstring triggers ending with a colon.

Homework task #1 ;)
Implement a hotstring that detects when a new hotstring has been typed and scans the current file for any conflicting hotstrings.

User avatar
Ross
Posts: 100
Joined: 13 Mar 2016, 00:27

Re: A way to warn about duplicate or partially duplicate hotstrings

Post by Ross » 29 May 2021, 03:05

@lexikos

Hi Lexikos, thanks for your attentive reply!

Now I understand the engine would probably rely on regexes to parse the entire "database", making things slow.

About the thoughts:
  • The idea is having the hotstrings be regular :: or asterisked :*:, since I feel those two modes speed up my workflow. Hotstrings with options, like :R: or :o: are exceptions.
  • Use of directives to differentiate: could theoretically work, but not when you're already into a pile of already-defined hotstrings; also, they're meant to work everywhere except some specified games and — sadly — elevated programs.
  • You assumed right!
  • I think I'm satisfied. After all, the suggestion was just a... "there could be this functionality!"
About the two extras: I understand too.

I'll take a look at the InputHook.

About your two pieces of code: I tried the one you made for v1, since my experience porting my scripts to v2 has been a rocky road. It works nice: I set aside a subset of my hotstrings database and did this:

Code: Select all

#SingleInstance, force

FileRead code, % A_ScriptFullPath
hotstrings := "", p := 1
while (p := RegExMatch(code, "Omi)^[ `t]*:([a-z0-9\?\*\- ]*):(.*)(?<!``)::(.+)$", hs, p))
    && A_Index < 25 ; Limit the MsgBox for this demo.
{
    hotstrings .= hs.1 "`t" hs.2 "`t" hs.3 "`n"
    p += hs.Len()
}

;MsgBox % hotstrings
FileAppend, %hotstrings%, list_of_hotstrings.txt

:*:wmu::we move unseen
:*:vrani::void reanimator
:R:voris::void rifts
:?:agede::aggressive deployment
:?*:douge::double edged
:*:ndnr::não deu nenhum resultado
:*:lodu::Line of Duty
:*:sutlog::sublime.log_commands(True)
::vaot::vão ter
::vait::vai ter
:*:mnw::minesweeper
:*:snta::se não estiver aí


...to get this:

Code: Select all

*   wmu we move unseen
*   vrani   void reanimator
R   voris   void rifts
?   agede   aggressive deployment
?*  douge   double edged
*   ndnr    não deu nenhum resultado
*   lodu    Line of Duty
*   sutlog  sublime.log_commands(True)
    vaot    vão ter
    vait    vai ter
*   mnw minesweeper
*   snta    se não estiver aí


As you can see, I understood the while statement from my python lessons (I'm still a noob), as well as the regex, except I was unfamiliar (and still am) with the O option. Might have something to do with objects, "arrays" as they're called in AHK (I've known them as lists, dictionaries and tuples from Python). I figured it has something to do with the script slicing the hotstrings' options, abbreviations and expansions respectively <-- this one I added, like I extended the regex with the (.+)$ part.

However, I didn't grasp the value of p. By slipping in a MsgBox statement inside the loop, I got three-digit numbers like 423, etc until it was finished for the 12 hotstrings present in the file.

Now, the homework:
Implement a hotstring that detects when a new hotstring has been typed and scans the current file for any conflicting hotstrings.
Err, I swear I tried.
I tried inserting a count tool like

Code: Select all

Loop, Read, list_of_hotstrings.txt
{
   total_lines = %A_Index%
}

MsgBox, Total number of lines in the file "list_of_hotstrings.txt" :`n%total_lines%


...so I could compare to the number of `n stored in hotstrings in order to be able to tell if something changed, but from this point on, I don't know. Is it something like, pseudocodically, this?

Code: Select all

Loop, read, hotstrings
    {
    If hotstring = hs.1
    MsgBox, "Be creative. Chose a different abbreviation."
    }
    return

User avatar
Ross
Posts: 100
Joined: 13 Mar 2016, 00:27

Re: A way to warn about duplicate or partially duplicate hotstrings

Post by Ross » 04 Jul 2021, 13:57

Erm... @lexikos! Could you... if you can... grade my homework? I know I didn't get a straight A but still, I'm eager to learn! :D

lexikos
Posts: 9621
Joined: 30 Sep 2013, 04:07
Contact:

Re: A way to warn about duplicate or partially duplicate hotstrings

Post by lexikos » 05 Jul 2021, 03:50

It doesn't even begin to achieve either of the objectives.

1. Implement a hotstring that detects when a new hotstring has been typed.
As a starting point, :B0*:`:::: executes whenever you type ::. From there, you would need to read the current line of the script/text editor to extract the hotstring, or determine that it isn't one. For some editors there are ways to read the current line with SendMessage. If it's Notepad, you can use ControlGet CurrentLine. For others there is the more general approach of sending keystrokes to select and copy the current line.

It would also be possible to detect a fully typed hotstring with InputHook, but it would be more complex and less reliable (than reading the code directly from the editor, if that is possible).

2. Determine whether the new hotstring is a duplicate of one already present in the file.
I've already shown how to loop through all hotstrings in a file. From there, you can just add some logic to check whether the current hotstring is the same as the new one. There are also more efficient solutions that may require more experience. Even just calling FileRead and InStr can tell you whether the exact text exists within the file (and further checking what is before/after the position returned by InStr can rule out false positives).

I was unfamiliar (and still am) with the O option.
See RegExMatch "Mode 3".
However, I didn't grasp the value of p.
See RegExMatch "Return Value".

User avatar
kunkel321
Posts: 1101
Joined: 30 Nov 2015, 21:19

Re: A way to warn about duplicate or partially duplicate hotstrings

Post by kunkel321 » 10 Feb 2022, 16:56

This is just what I needed. Thanks Lexikos!
ste(phen|ve) kunkel

Post Reply

Return to “Wish List”