Use the GoTo Command to Traverse Long Subroutines (Part Four: Finishing AutoHotkey GUI Scripts)

Sometimes the GoTo Command Makes Life Easier without Creating Perverse Effects

This next portion of the InstantHotstring.ahk menubar implementation did not go as I had expected. I thought that I would break up the routine launched by the Save Hotstrings button into separate subroutines or functions, then call each as appropriate for the corresponding Save/Append Hotstrings menu items (as seen in the image). I didn’t look forward to it because I knew it could get a little confusing. Some items would require multiple subroutine calls while others would need to just run—depending upon the menu selections made by the user.

I didn’t want to write redundant subroutines, but separating the various features of the complete routine required more than merely adding Return commands to encapsulate the code. I finally ask myself, “Why not insert AutoHotkey Labels into the main Save routine and use the GoTo command to jump my way through the decision points?”

Library Benefits

GoTo Statements Gone Astray

The online AutoHotkey documentation advises scriptwriters to avoid the GoTo command and, as a rule, I agree. Historically, adventurous coders would build complex mazes of GoTo statements winding through a labyrinth of code making it difficult to follow or alter. The GoTo statement jumps off to a distant location never to return. By using the GoSub command (which always returns to the original calling point) or adapting the code to use ElseBlocksBreak and Continue (as advised but the online documentation), you can avoid many GoTo pitfalls.

In spite of the dangers (and after staring at the code for an indeterminable amount to time), I decided to add jump-to Labels to my code and use the GoTo command to drive through the routine for each menu item. It looked so simple…and it was!

Note: I reference the difference between GoSub and GoTo in a number of my books. I demonstrate a practical use for GoTo statements in the CheeseBurgerRecipe.ahk script discussed in the book Beginning Tips for Writing AutoHotkey Scripts.

Adding Labels to the SaveHotstrings Routine

Making the GoTo command work relies on the strategic placement of AutoHotkey Labels. Remember, AutoHotkey ignores Label names except when called by another command. Inserting multiple Labels into a script has no effect on the running of the code. When properly placed, the Label names provide a method for bypassing currently unneeded code with a GoTo command. You can even use the GoTo statement to create an artificial loop.

Four Steps to Saving Instant Hotstrings

In this blog, I address the three Save-type menu items found in the GUI menubar’s File menu in the InstantHotstringMenuBar.ahk script: Save for instant-save of Hotstring changes, Save as… for selecting or creating Hotstring filenames, and Append Hotstrings to File for adding Hotstrings to the end of any file. While Save as… requires running the entire SaveHotstrings routine, the other two only require select portions of the code.

The current version of the SaveHotstrings routine runs through the following steps:

  1. FileSelectFile for filename
    When saving Hotstrings to a new filename or adding Hotstrings to another file, the FileSelectFile command allows the user to select (or create) any file in a given folder. However, for an instant-save, skip it—this step offers no value.
  2. Replace file?
    The Replace File? step applies to the Save as… menu item, but for both the Save and Append Hotstrings menubar items, you’ll find this step unnecessary. Although, the No—Select New Filename! option requires a jump back to the FileSelectFile step.
  3. Overwrite or append?
    Again, this step only applies to Save as… since Save automatically overwrites the target file and Append Hotstrings merely adds the Hotstrings to the end of a file without overwriting anything.
  4. Write Hotstrings
    This step applies to all three of the GUI menubar Save options. The routine writes (FileAppend command) all active Instant Hotstrings to the selected (or default) file.

Note: I removed the Set Default File subroutine from the overall SaveHotstrings routine since the menubar allows a separate Set default file option—providing greater visibility and easier access. The SaveHotstrings routine should not force the user to deal with the default file decision whenever making a save.

GoTo Jumps

By placing additional AutoHotkey Labels inside the SaveHotstrings routine, I create signposts for jumping to particular spots in the code. The script continues running from that new location without regard to any previous code. Unlike the GoSub command, the GoTo command does not return to the calling point. The following Label names mark the starting (or continuation) points for the Save item (instant-save) and the Append Hotstrings item, respectively.

InstantHotstringSave:

Since the Save menu item (instant-save) only enables with a valid InstantHotstring file (.hsf) positioned in the GUI title bar and after detecting a change (see my last post), I inserted the new Label name InstantHotstringSave: just before the routine for overwriting the file—no file selection or other decisions—calling it in the auto-execute section of the script using the Menu command:

Menu, FileMenu, Add, &Save`tCtrl+S, InstantHotstringSave

By jumping directly to the new Label at the end of the master routine, the script immediately saves all of the current Hotstrings to the file without pausing for the various MsgBox queries.

If (A_ThisMenuItemPos = 3)
  {
    SaveFile := A_ScriptDir . "\Hotstrings\" . StrReplace(WindowTitle, "*")
    FileCopy, %SaveFile%, %SaveFile%.bak, 1
    FileDelete, %SaveFile%
  }

This conditional fires when launched by the third menu item (Save at A_ThisMenuItemPos = 3). It prepares the proper file for overwriting (backup and delete the old file).

Note: The default title bar file currently does not display its path. It took up too much space. In my setup, “\Hotstrings\” acts as part of the path. This needs to change to a more flexible solution. I plan to go back and store the complete path of the current default file. Plus, I plan to change the last MsgBox to a Progress bar. Any instant-save routine should not force the user to click-away a notification.

AppendFile:

The Append Hotstrings to File menu item launches the master SaveHotstrings routine for initial file selection:

Menu, FileMenu, Add, A&ppend Hotstrings to File`tCtrl+Shift+A
    , SaveHotstrings

(The above code uses line continuation techniques to wrap lines of code for display purposes.)

After file selection, the script uses a GoTo statement for routines launched from the Append Hotstrings menu item (A_ThisMenuItemPos = 5) to directly add Hotstrings to the end of the selected file—skipping everything in between:

If (A_ThisMenuItemPos = 5)
{
  Goto AppendFile
}

The script doesn’t actually require this Label name. I could have used the previously discussed InstantHotstringSave Label since the following conditional differentiates between overwriting a file and merely appending the records. I used the AppendFile Label name in the script for clarity:

If (A_ThisMenuItemPos != 5 and !FileExist(SaveFile))
  {
    SplitPath, SaveFile, CurrentFile
    WindowTitle := CurrentFile
    WinSetTitle, %WindowTitle%
    Menu, FileMenu, Disable, &Save`tCtrl+S
  }

This instant-save condition tests for a thread not launched by the menu item Append Hotstrings to File (A_ThisMenuItemPos != 5) and the old SaveFile does not exist (ready for overwriting), then parses the instant-save filename, resets the title bar (without the asterisk *), and disables the Save menu item.

GoTo Loop

In order to use a specialized MsgBox with the FileSelectFile command, I needed to create a method for looping back to the FileSelectFile command when rethinking the filename. While I know that you’ll find many techniques for inserting loops into your script, I love the simplicity of adding a jump-to point with a Label, then using GoTo to start over.

SaveFileSelect:

I inserted the SaveFileSelect Label just before the FileSelectFile command. Since the FileSelectFile command uses the value of SaveFile (if any), the last selected filename appears in the file selection box:

SaveFileSelect:

FileSelectFile, SaveFile , S, %A_ScriptDir%\Hotstrings\%SaveFile%, , Hotstrings(*.ahk;*.hsf)

The MsgBox conditional uses a GoTo statement to jump back to SaveFileSelect each time the user clicks the “No” MsgBox button:

MsgBox, 3, , Not an InstantHotstring Generated file
               !`rMay overwrite other code!Continue
               ?`rYes — Write HotString (.hsf) File
               !`rNo — Select New Filename!
IfMsgBox, Cancel
  Return
IfMsgBox, No
  GoTo SaveFileSelect

On Using GoTo Statements

I have spent most of my programming life avoiding Goto statements—and for good reason. But now I recognize that at times, as with any tool, it may offer the best solution for certain types of problems. At a minimum, I must consider it as an option. I will no longer look disparagingly upon people who do use GoTo statements—depending upon how they use them.

The Entire SaveHotstrings Routine

The SaveHotstrings routine follows with the internal Label name targets and the associated GoTo statements highlighted:

SaveHotstrings:

Gui, Hotstring:+OwnDialogs
If (InStr(FileExist("\Hotstrings"), "D") = 0)
    FileCreateDir, Hotstrings

SaveFileSelect:

FileSelectFile, SaveFile , S, %A_ScriptDir%\Hotstrings\%SaveFile%, , Hotstrings(*.ahk;*.hsf)

If ErrorLevel     ; "Cancel" button, close, or Escape
   Return

	If (A_ThisMenuItemPos = 5)
		{
		  Goto AppendFile
		}


;SaveFile := StrReplace(SaveFile, ".ahk", "")
If !InStr(SaveFile,".hsf")
  SaveFile .= ".hsf"
FileReadLine, FileHeader, %SaveFile%, 1
If FileExist(SaveFile) and !InStr(FileHeader,"InstantHotkey generated file")
  MsgBox, 3, , Not an InstantHotstring Generated file
					!`rMay overwrite other code!Continue
                    ?`rYes — Write HotString (.hsf) File
                    !`rNo — Select New Filename!
     IfMsgBox, Cancel
       Return
     IfMsgBox, No
       GoTo SaveFileSelect
If FileExist(SaveFile)   ; . ".ahk")
  MsgBox, 3, , Yes — Overwrite Old Hotstrings
                    !`rNo — Append New Hotstrings!
     IfMsgBox, Cancel
       Return
     IfMsgBox, Yes
       {
          FileCopy, %SaveFile%, %SaveFile%.bak, 1
          FileDelete, %SaveFile%
        }

InstantHotstringSave:

	If (A_ThisMenuItemPos = 3)
		{
		  SaveFile := A_ScriptDir . "\Hotstrings\" . StrReplace(WindowTitle, "*")
          FileCopy, %SaveFile%, %SaveFile%.bak, 1
          FileDelete, %SaveFile%
		}

AppendFile:

If (A_ThisMenuItemPos != 5 and !FileExist(SaveFile))
  {
    SplitPath, SaveFile, CurrentFile
    WindowTitle := CurrentFile
    WinSetTitle, %WindowTitle%
    Menu, FileMenu, Disable, &Save`tCtrl+S
  }


Head := "; InstantHotkey generated file https://tinyurl.com/ydcjgzuk"
FileAppend , %Head%`r`n, %SaveFile%, UTF-8

ControlGet, Items, List,, ComboBox1, A

Loop, Parse, Items, `n
{
  If (InStr(A_LoopField, "🛑 Stopped!") = 0)
  {
      FileAppend , %A_LoopField%`r`n, %SaveFile%, UTF-8
  }
}

MsgBox Hotstrings added to the %SaveFile% file!

Return

Note: While I view this script as work-in-progress, I provide the current version of the new code for the curious. You can find the most recent iteration of the InstantHotstringMenuBar.ahk script on the “ComputorEdge Free AutoHotkey Scripts” page—updated on July 12, 2020. Although only partially operational, you can find the discussed changes in context—and a few more additions subject to future inspection. While these blogs demonstrate the techniques I plan to implement, the script requires a great deal more work before it’s ready for general use.

Click the Follow button at the top of the sidebar on the right of this page for e-mail notification of new blogs. (If you’re reading this on a tablet or your phone, then you must scroll all the way to the end of the blog—pass any comments—to find the Follow button.)

jack

This post was proofread by Grammarly
(Any other mistakes are all mine.)

(Full disclosure: If you sign up for a free Grammarly account, I get 20¢. I use the spelling/grammar checking service all the time, but, then again, I write a lot more than most people. I recommend Grammarly because it works and it’s free.)

Find my AutoHotkey books at ComputorEdge E-Books!

Find quick-start AutoHotkey classes at “Robotic Desktop Automation with AutoHotkey“!

One thought on “Use the GoTo Command to Traverse Long Subroutines (Part Four: Finishing AutoHotkey GUI Scripts)

  1. Ha! What does it say about the current and recent coding community that has made me feel guilty even reading about using GOTO for any reason. Thanks for posting this.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s