diff --git a/README.md b/README.md index 5b34de2..d592783 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ AHK_X11 can be used completely without a terminal. You can however if you want u
*Click here* to see which commands are implemented and which are missing. Note however that this is not very representative. For example, no `Gui` sub command is included in the listing. For a better overview on what is already done, skim through the full documentation here. Generally speaking, everything important is done. ```diff -DONE 57% (126/221): +DONE 57% (126/222): + Else, { ... }, Break, Continue, Return, Exit, GoSub, GoTo, IfEqual, Loop, SetEnv, Sleep, FileCopy, + SetTimer, WinActivate, MsgBox, Gui, SendRaw, #Persistent, ExitApp, + EnvAdd, EnvSub, EnvMult, EnvDiv, ControlSendRaw, IfWinExist/IfWinNotExist, SetWorkingDir, @@ -155,11 +155,12 @@ DONE 57% (126/221): + WinWaitClose, WinWaitActive, WinWaitNotActive, DriveSpaceFree, FileGetSize, FileRecycle, + FileRecycleEmpty, SplitPath, StringSplit -NEW 4% (10/221): (not part of spec or from a more recent version) +NEW 4% (11/222): (not part of spec or from a more recent version) @@ Echo, ahk_x11_print_vars, FileRead, RegExGetPos, RegExReplace, EnvGet, Click @@ @@ Eval, ahk_x11_track_performance_start, ahk_x11_track_performance_stop @@ +@@ #DefineCommand @@ -REMOVED 5% (11/221): +REMOVED 5% (11/222): # ### Those that simply make no sense in Linux: # EnvUpdate, PostMessage, RegDelete, RegRead, RegWrite, SendMessage, #InstallKeybdHook, # #InstallMouseHook, #UseHook, Loop (registry) @@ -168,7 +169,7 @@ REMOVED 5% (11/221): # AutoTrim: It's always Off. It would not differentiate between %a_space% and %some_var%. # It's possible but needs significant work. -TO DO 32% (71/221): alphabetically +TO DO 32% (71/222): alphabetically - BlockInput, Control, ControlFocus, ControlGet, ControlGetFocus, ControlMove, DetectHiddenText, - DetectHiddenWindows, Drive, DriveGet, FileCopyDir, FileCreateShortcut, FileInstall, FileGetAttrib, - FileGetShortcut, FileGetTime, FileGetVersion, FileMove, FileMoveDir, FileRemoveDir, FormatTime, @@ -277,6 +278,7 @@ Like covered above, AHK_X11 is vastly different to modern Windows-AutoHotkey bec - `#NoEnv` is the default, this means, to access environment variables, you'll have to use `EnvGet`. - All arguments are always evaluated only at runtime, even if they are static. This can lead to slightly different behavior or error messages at runtime vs. build time. - Several more small subtle differences highlighted in green throughout the docs page +- There are a few commands present which are missing from Windows AHK, i.e. prominently [`#DefineCommand`](https://phil294.github.io/AHK_X11#h_DefineCommand.htm), [`Echo`](https://phil294.github.io/AHK_X11#Echo.htm) and [`Eval`](https://phil294.github.io/AHK_X11#Eval.htm). Besides, it should be noted that un[documented](https://phil294.github.io/AHK_X11) == undefined. @@ -328,6 +330,19 @@ Besides the [Legacy Syntax](https://www.autohotkey.com/docs/v1/Language.htm#lega result += %add_second% Return ``` + **or** you can use the special built-in command (AHK_X11-only) [`#DefineCommand`](https://phil294.github.io/AHK_X11#h_DefineCommand.htm) to reduce code repetition: + ```ahk + #DefineCommand Add, LblAdd + + Add, result, 7, 8 + Send, %result% + Return + + LblAdd: + %A_Param1% = %A_Param2% + %A_Param1% += %A_Param3% + Return + ``` - `my_array := ["one", "two", "three"]` -> ```ahk my_array1 = one diff --git a/docs/index.html b/docs/index.html index bc3c113..8bf913a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -443,6 +443,9 @@

Table of contents

  • Eval
  • +
  • + #DefineCommand +
  • ListLines
  • @@ -802,6 +805,9 @@

    Table of contents

  • #CommentFlag
  • +
  • + #DefineCommand +
  • #ErrorStdOut
  • @@ -2173,6 +2179,10 @@

    The "Last Found" Window

    ExitApp Terminates the script unconditionally. + + DefineCommand + Registers a new command. + FileAppend Appends text to a text file. @@ -9652,6 +9662,76 @@

    The "Last Found" Window

    ; Run a dynamic command:
    cmd = MsgBox
    Eval, %cmd% Hello

    +
    +
    + #

    #DefineCommand

    +
    +

    Registers a new command. Comparable but inferior to "function"s in modern Windows AHK.

    + + + + + + +
    #DefineCommand, Name, Label
    +

     

    +

    Parameters

    + + + + + + + + + + + +
    Name + The name of the new command which you can then invoke in subsequent lines. +
    Label + The name of the label or hotkey label to which to jump when the newly registered command is invoked. Internally this behaves like GoSub, check there for details. +
    +

     

    +

    Remarks

    +

    You should use this directive if you need to encapsulate logic that you use multiple times in your script, to prevent repeating yourself. Only do this if you can't find another built-in command that already does what you need.

    +

    This directive can be used multiple times to register multiple commands. It will only affect code in subsequent lines. This means that you will likely want to put it at the top of your script. The labels, however, can be placed anywhere in your script.

    +

    Inside the respective label, you can access the passed parameters using the pseudo-built-in vars A_Param1, A_Param2 and so on. Check the example below.

    +

    This feature hasn't been optimized a lot. It may not be super fast and it's possible to shadow variable names with a custom command (not built-in commands though). Generally however, it should work great for most use cases.

    +

     

    +

    Example

    +

    +; Registering a new custom command: GetMaximumValue, OutputVar [, Value1, Value2, ...]
    +#DefineCommand GetMaximumValue, LblGetMaximumValue
    +
    +GetMaximumValue, var1, 7, 8, 26, 12, 15
    +GetMaximumValue, var2, 4, %var1%
    +
    +; Prints: 26
    +MsgBox, Maximum: %var2%
    +Return
    +
    +LblGetMaximumValue:
    +max = 0
    +; Iterating A_Param1, A_Param2 and so on until no more params are found:
    +Loop
    +{
    +    param_index = %A_Index%
    +    ; We skip the first param as it's the OutputVar
    +    param_index += 1
    +    StringTrimLeft, value, A_Param%param_index%, 0
    +    If value =
    +        Break
    +    If value > %max%
    +        max = %value%
    +}
    +; We have defined OutputVar as our first parameter. This will set the out value:
    +%A_Param1% = %max%
    +max =
    +Return
    +          

    +
    +
    #

    ListLines

    diff --git a/src/build/parser.cr b/src/build/parser.cr index d9ed80c..303bac8 100644 --- a/src/build/parser.cr +++ b/src/build/parser.cr @@ -23,6 +23,7 @@ module Build @block_comment = false @hotstring_default_options = "" @already_included = [] of Path + @user_defined_command_label_by_name = {} of String => String def parse_into_cmds!(lines : Indexable(String)) @cmds.clear @@ -64,8 +65,7 @@ module Build raise "Unexpected */" if ! @block_comment @block_comment = false elsif @block_comment - # - # This is the "normal" case where 90% of all commands fall into. All other if-clauses + # Below is the "normal" case where 90% of all commands fall into. All other if-clauses # are special cases. elsif cmd_class csv_args = split_args(args, cmd_class.multi_command ? cmd_class.max_args + 1 : cmd_class.max_args) @@ -116,6 +116,10 @@ module Build @runner_settings.x11_grab_from_root = true elsif line.starts_with?("#!") && line_no == 0 # hashbang elsif first_word == "#noenv" + elsif first_word == "#definecommand" + split = split_args(args) + raise "#DefineCommand requires two arguments" if split.size < 2 + @user_defined_command_label_by_name[split[0].downcase] = split[1].downcase elsif first_word == "if" split = args.split(/ |\n/, 3, remove_empty: true) var_name = split[0] @@ -206,6 +210,14 @@ module Build comma = rest_args.empty? ? "" : "," add_line "Gui#{sub_cmd}, #{gui_id}#{comma} #{rest_args}", line_no @runner_settings.persistent = true + elsif label = @user_defined_command_label_by_name[first_word]? + split_args(args).each_with_index do |arg, i| + add_line "SetEnv, A_Param#{i+1}, #{arg}", line_no + end + add_line "GoSub, #{label}", line_no + split_args(args).each_with_index do |arg, i| + add_line "SetEnv, A_Param#{i+1}", line_no + end elsif first_word.ends_with?(':') @cmds << Cmd::ControlFlow::Label.new line_no, [first_word[...-1]] elsif first_word.ends_with?("++")