Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Options string framework


  • Please log in to reply
7 replies to this topic
berban
  • Members
  • 202 posts
  • Last active: Feb 21 2019 06:14 PM
  • Joined: 30 Dec 2009
See this update for an improved and more advanced version of the framework.

First, why?.

If you are familiar with the GUI command, you will know that there is an "Options" parameter. This lets you add a lot of information to the command, for instance an x-coordinate or a particular style. These do not have to be in any particular order. Instead, you indicate which of the multiple options you are referring to by preceding them with a character/characters that serve as a label.
I think this format is vastly superior in many cases for two reasons:[*:3jcsj9km]Lets you specify an uncommon option without having to fill several other parameters first[*:3jcsj9km]Options are easier to remember - you can remember x or y, for instance, instead of parameter #5I often add a parameter like this to my functions.

Posted Image

Now, how?.

Below is a simple framework. (The part in violet is included for demonstrational purposes only).

[color=violet]MyFunc(Options="")
{
	Global[/color]
	Local @ := 0, @O, @V, Literal := """", Commands := "Name|x|y|w|h|c"
	;---------------------------------OPTIONS:-----------------------------------------------------------
	; INITIAL                 DEFAULT                 NAME                    ABOUT
	, Name := "",             Name_def := "My Gui"    ;Name                   The title to give your new gui
	, x := "",                x_def := "Center"       ;X-coord                X-coordinate of upper left corner of gui
	, y := "",                y_def := "Center"       ;Y-coord                Y-coordinate of upper left corner of gui
	, w := 100,               w_def := 200            ;Width                  Width of gui
	, h := 100,               h_def := 200            ;Height                 Height of gui
	, c := "Black",           c_def := "Red"          ;Color                  Color of gui
	;----------------------------------------------------------------------------------------------------
	While (@ := RegExMatch(Options, "i)\s*\K(?P<O>" Commands ")(?P<V>" Literal "(?:[^" Literal "]|" Literal Literal ")*" Literal "(?= |$)|[^ ]*)", @, @ + StrLen(@O @V) + 1))
		If (@V <> "") {
			If (SubStr(@V, 1, 1) = Literal) and (StrLen(@V) > 1) and (SubStr(@V, 0, 1) = Literal) and (@V := SubStr(@V, 2, -1))
				StringReplace, @V, @V, %Literal%%Literal%, %Literal%, All
			%@O% := @V
		} Else
			%@O% := %@O%_def
	[color=violet]ListVars
	Pause
}[/color]

Posted Image

Finally, what? happens.

To enter options, use the following format: <Option Name><Option Value>
Separate each different option with a space.
For instance, x20 y100 would indicate that you want x to be 20 and y to be 100, just as it would with the Gui options parameter.


Additionally, leave the value out and only indicate the option name to specify a custom default option as is set in the option_def assignments.
For instance, x y100 would indicate that you want x to be Center and y to be 100


If you want to pass a value that contains spaces, surround the value with the literal indication characters, as assigned Literal := Character Here. To pass a literal version of this character, repeat it (just like two quotes in an AutoHotkey string means a literal quotation.)
For instance, Name"I'll name it ""Hank""" c"" would pass I'll name it "Hank" to Name and an empty string to c
Using "" is how you can indicate an empty string to a parameter with a non-blank default value. For instance, just c would have resulted in Red, rather than a blank string, since Red is the default for c. However, I'd generally say that it is best practice to leave either the initial or default value as a blank string so this doesn't have to be done.)


The script will store the values captured in variables with the same name as the option. For instance, MyFunc("NameHello cGreen x y") would reveal the following on a local ListVars:
Name[5 of 7]: Hello
x[6 of 7]: Center
y[6 of 7]: Center
w[3 of 3]: 100
h[3 of 3]: 100
c[5 of 7]: Green
Note that this means your option names must be valid variable names.


If the option is not indicated at all (such as with w and h in the above example), then it will take the value issued under the INITIAL column in the code.

Posted Image

A few other notes:[*:3jcsj9km]To define new commands, you must (or should) initialize that value (the INITIAL column), initialize that value_def (the DEFAULT column), and add that command to the Commands variable. This is a RegEx expression, the | ("or") separating each command. This last step is mandatory and is easy to forget :p[*:3jcsj9km]If you have multiple-character options (such as Name), you must put them BEFORE other shorter options that begin with the same character(s) in the Commands variable. For instance, Commands := "Name|NA|n"[*:3jcsj9km]You can change the literal chararacter if you want. Personally, I like using ' because a double-quote is the AutoHotkey literal symbol, which means you always will be doubling it up and it looks ugly. Another way around this is to set your Options param with a traditional assignment, on a different line.[*:3jcsj9km]The options are case-insensitive but you can easily change that by removing the i)[*:3jcsj9km]In addition to two variables per option (option and option_def), a literal symbol, and a list of commands, the code needs 3 temporary variables, for which I use @, @O, and @V - although you can change these names easily enough.Posted Image

You may also be interested in: (thanks for the links Tuncay)[*:3jcsj9km]Tuncay's argp v3.0 Argument Options Parser (+mod for AHK_L)[*:3jcsj9km]Yook's Parameters and switches parser[*:3jcsj9km]majkinetor's Parse[*:3jcsj9km]ahklerner's options.ahkl - an options object for AutoHotkey_L

nimda
  • Members
  • 4368 posts
  • Last active: Aug 09 2015 02:36 AM
  • Joined: 26 Dec 2010
I'd remove the 'must be valid variable name' requirement by using an object.

Tuncay
  • Members
  • 1945 posts
  • Last active: Feb 08 2015 03:49 PM
  • Joined: 07 Nov 2006
I have not read your post fully yet (just saw it before going to bed). I assume you are working with AutoHotkey Basic. With the objects (associated arrays) in AHK_L such a function is not really needed.

My function with options like the command line: argp - Argument Options Parser (A single RegEx call)

And here from majkinetor like your options in Ahk Gui command style: Parse

No signature.


berban_
  • Members
  • 202 posts
  • Last active: Aug 05 2014 11:52 PM
  • Joined: 16 Mar 2011

I'd remove the 'must be valid variable name' requirement by using an object.

I'm assuming you're referring to usage like this?
Options["x"] := 200
Options["Window Title"] := "My Title"
:?:
...in which case I believe Tuncay is probably correct:

With the objects (associated arrays) in AHK_L such a function is not really needed.

However, I wouldn't exactly say that objects make this kind of thing obsolete - at least from my point of view. Objects are great for computers but they're not exactly super human-friendly. For instance, you can't really ask a user to "input an object" the same way you can ask for a string, number, or boolean. (Instead the user would be inputting a series of strings, numbers, or booleans.) One effect that this has on scripts would be that you could not enter options parameters in a single expression like this:
Function("x100 y200")
or
Function("x" xcor " y" ycor)
Instead you'd have something like this (once more correct me if I'm wrong here)
Options["x"] := 100, Options["y"] := 200
Function(Options)
That being said, options in this format DO have a huge number of advantages. But, personally, I don't really like _L arrays :( sorry!


Posted Image


(paraphrasing) Check out these other cool scripts.

Woah! :shock: these are quite impressive (I'm referring to yours, majkinetor's, and the other one you linked in your argp post), and all do far more than the little snippet of code I have up here.

I guess the remaining reason to use the format that I laid out is that it is small & light. No external libraries needed, and the actual code itself really only takes 7 lines (which could be shortened to two were RegExReplace() substituted for the StringReplace, which I opted not to do for performance.) The settings and variable declarations could likewise be shortened to one line at the cost of readability.

Personally, when I make code I usually end up with a single stand-alone function. I can slide this framework into the top of the function and it's still stand-alone and still one function. However, if you are thinking about libraries, and would have many functions needing an Options parameter, then I guess one of Tucany's links would probably be the better way to go. This way you could include the options parsing library along with your library, and then use the functionality multiple times.

nimda
  • Members
  • 4368 posts
  • Last active: Aug 09 2015 02:36 AM
  • Joined: 26 Dec 2010

Instead you'd have something like this (once more correct me if I'm wrong here)

Options["x"] := 100, Options["y"] := 200
Function(Options)

Entirely incorrect. In fact, I think objects are even more friendly than your example:
MyFunc({x: 100, y: 200, "cool option": "no"})

MyFunc(Options){
   MsgBox % "Position: " Options.X ", " Options.Y "`nCool Option? " Options["Cool Option"]
}


Tuncay
  • Members
  • 1945 posts
  • Last active: Feb 08 2015 03:49 PM
  • Joined: 07 Nov 2006
Sorry, but I made another function similiar to yours for AHK_L, because I was bored again. :D optparse.

No signature.


  • Guests
  • Last active:
  • Joined: --

I was bored again

Why not have a stab at

Wish: Robust Time and Date function (Page: 4)
No solution yet
Source: http://www.autohotke...topic63028.html



berban
  • Members
  • 202 posts
  • Last active: Feb 21 2019 06:14 PM
  • Joined: 30 Dec 2009
Update 8/28/2012

Local @, @1, @2, @3, @4, @5 := 1, Literal := """", Commands := "x|y|w|h|a|c"
	;---------------------------------OPTIONS:-----------------------------------------------------------
	; INITIAL                 DEFAULT                 NAME                    ABOUT
	, x := "",                x_def := "Center"       ;x = X-coord            X-coordinate of upper left corner of gui
	, y := "",                y_def := "Center"       ;y = Y-coord            Y-coordinate of upper left corner of gui
	, w := "",                w_def := 100            ;w = Width              Width of gui
	, h := "",                h_def := 100            ;h = Height             Height of gui
	, a := True,              a_def := False          ;a = Activate           Whether or not the gui will activate when it shows
	, c := "Black",           c_def := "Red"          ;c = Color              Color of gui in hex format
	;---------------------------------USER CONFIGURATIONS:-----------------------------------------------
	, UserConfig_Foo := "x12 y34"
	, UserConfig_Bar := "cWhite -a"
	;----------------------------------------------------------------------------------------------------
	While (@5 := RegExMatch(Options, "i)(?:^|\s)(?:!(\w+)|(\+|-)?(" Commands ")(" Literal "(?:[^" Literal "]|" Literal Literal ")*" Literal "(?= |$)|[^ ]*))", @, @5 + StrLen(@)))
		If (@1 <> "")
			Options := SubStr(Options, 1, @5 + StrLen(@)) UserConfig_%@1% SubStr(Options, @5 + StrLen(@))
		Else If (@4 <> "") {
			If (InStr(@4, Literal) = 1) and (@4 <> Literal) and (SubStr(@4, 0, 1) = Literal) and (@4 := SubStr(@4, 2, -1))
				StringReplace, @4, @4, %Literal%%Literal%, %Literal%, All
			%@3% := @4
		} Else
			%@3% := @2 = "+" ? True : @2 = "-" ? False : %@3%_def

New Features:[*:fjakypw4]Ability to do + or - like in AutoHotkey GUI settings (for instance, -Wrap). -Option will set that option to False, and +Option will set that option to True.[*:fjakypw4]Ability to configure custom combinations of options. To do this, look at the USER CONFIGURATIONS: portion of the code. Using the given example configurations, putting !foo anywhere in the options string is equivalent to indicating x12 y34. So passing cBlack !foo w100 is the same thing as passing cBlack x12 y34 w100. Add as many user configurations as you like and give them whatever names and values. (The name, in this case, "Foo", is the title of the variable after "UserConfig_"). You can easily change the flag character to something other than an exclamation mark if you like.[*:fjakypw4]Fixed a small bug where the code could give unintuitive behavior.
I don't really feel like giving a full explanation here so just post any questions you've got!