ryuta46 / vscode-multi-command

Visual Studio Code Plugin named multi-command
MIT License
229 stars 14 forks source link

Conditioned (logical) commands #43

Closed seahindeniz closed 2 years ago

seahindeniz commented 3 years ago

Hi,

Is it possible to have a feature that gives the ability to use some sort of conditional expressions over commands, like ternary operations etc.?

Ok, here is the keybindings.json

[
  {
    "key": "shift+alt+f",
    "command": "extension.multiCommand.execute",
    "args": {
      "sequence": [
        "editor.action.formatDocument",
        "eslint.executeAutofix"
      ]
    },
    "when": "editorTextFocus && !editorReadonly"
  }
]

As you see, I have two commands which are kind of the same when you have proper configurations in your workspace.

My intention was here to use these commands anywhere that is possible, and the above keybinding is actually works. However, the following error occurs when ESLint extension isn't enabled on the workspace. image

So my idea is to solve this problem is to have a special expression/syntax to make conditions possible.

    "args": {
      "sequence": [
        "eslint.executeAutofix || editor.action.formatDocument" // JS syntax looking
      ]
    },

I'm also not sure about the possibility to catch command * not found error after invoking the vscode.commands.executeCommand API. If it is possible, then I think the extension can try to invoke the first command and when it fails, can invoke the second command from the conditional command expression (eslint.executeAutofix || editor.action.formatDocument).

The condition expression can also be like:

seahindeniz commented 3 years ago

An additional solution is to pass some sort of error suppressor expression to suppress the command * not found error from being popped out.

      "sequence": [
        "editor.action.formatDocument",
        "?eslint.executeAutofix" // Use the ? - question mark to let the extension know the following command is
                                 // optional and suppress the not found error...
      ]

Or

I'm not so sure if it's possible to pass a JSON object like this:

      "sequence": [
        "editor.action.formatDocument",
        {
          "optional": true,
          "command": "eslint.executeAutofix"
        }
      ]
ryuta46 commented 3 years ago

@seahindeniz I checked codes and what happens when unregistered command is called.

This extension catch errors when the command in the sequence is executed and show the error message (ex. command * not found). If an error occurred in the sequence, the extension breaks the sequence and the latter commands are not executed.

So suppressing the error message like command * not found is possible with the options like you mentioned.

I think the first style "eslint.executeAutofix || editor.action.formatDocument" is simple and good. To treat a command with arguments, json style is also needed.

I'll implement this feature in next version.

For extensibility, the json style might look like this:

"sequence": [
     { 
         "command": "eslint.executeAutofix",
         "onFail": [
              "editor.action.formatDocument"
         ]
     }
]

If the command "A" is succeeded, command "B" is executed with arguments.

"sequence": [
     { 
         "command": "A",
         "onSuccess": [
              { 
                  "command" : "B",
                  "args": { "arg0": "foo" }
              }
         ]
     }
]
seahindeniz commented 3 years ago

Hmm, I like it. What do you think about placing onFail and onSuccess properties in nested commands? In this case, letting command "B" be able to use the suggested event handlers. + with this way, the user will have an infinite possibility to define nested exceptional commands. Well, I'm not sure this can be more than 5 nested layers however, thinking about it makes it feel like it has a stable structure.

A Typescript definition for this feature can be like:

interface CommandType {
  command: string;
  onSuccess?: CommandType[];
  onFail?: CommandType[];
}
ryuta46 commented 3 years ago

I'll implement the feature as the interface you mentioned. I checked the codes and I think this kind of structure is easiest to implement.

I don't know how many nested layers users can define, so I'll test that after implementation.

ryuta46 commented 2 years ago

Implemented in 1.6.0. See Conditioned commands in README.

Please reopen this issue or create new issue if you have any problem about this feature. Thanks.