Editor Variable to ExecuteCommandLineOperation return

Post here questions and problems related to oXygen frameworks/document types.
kirkilj
Posts: 110
Joined: Fri May 14, 2010 12:14 am

Editor Variable to ExecuteCommandLineOperation return

Post by kirkilj »

The ExecuteCommandLineOperation has an option to show the results in an Oxygen console table. It would be useful if there was another parameter that would signal that the result should instead be returned as a string that could be used elsewhere.

One way to leverage this capability would be for Oxygen to provide an analog to the xpath_eval editor variable, such as os_eval. We would define other custom editor variables that would gets its value using the os_eval variable.

A hypothetical example would be to define a custom editor variable, called "currentBranch" that would get its value from

Code: Select all

${os_eval ('git rev-parse --abbrev-ref HEAD')}
As it stands today, our writers have to enter it literally whenever they create a new branch of their documentation.

Consideration would need to be made as to whether only the first line of output should be returned and what to do if the command results in an error.

Thoughts?
sorin_carbunaru
Posts: 402
Joined: Mon May 09, 2016 9:37 am

Re: Editor Variable to ExecuteCommandLineOperation return

Post by sorin_carbunaru »

Hello John,

I created a feature request for an editor variable that is capable of executing command lines (EXM-45656 - for reference purposes).

What I don't understand is the relationship between ExecuteCommandLineOperation and os_eval. Could you please explain this a little bit more? Or did you mean that users could use the result of the operation in some other ways?

All the best wishes,
Sorin Carbunaru
oXygen XML
kirkilj
Posts: 110
Joined: Fri May 14, 2010 12:14 am

Re: Editor Variable to ExecuteCommandLineOperation return

Post by kirkilj »

Hi Sorin,

Apologies. My feature request evolved while I was typing it, and I forgot to delete the first paragraph! My initial though was to add a parameter to the ExecuteCommandLineOperation, before the idea of os_eval came along. However, as long as we're talking about OS shell integration points... ;)

One thing my colleagues mentioned is what would be ideal is if we could indicate which shell to use in a number of customization opportunities in Oxygen. On Windows, the options for us are the legacy cmd shell, PowerShell, and GitBash, although we only care about CMD and Bash. GitBash does have the ability to invoke it with a command line parameter to provide the Bash command to execute.

For an os_eval implementation, perhaps there could be a preference for the default command shell, but also supporting an optional parameter to indicate the shell to use.

A bit more ambitious feature would be something I've mentioned in another forum post or perhaps a support email. It would be wonderful if we could:
  1. pick which shell to use in the External Tools dialog. The console display would show the output from a given shell.
  2. provide a true console that supports interactive input as well as output. Many text editors and IDEs provide that feature, and it precludes a user having to leave the OxygenXML UX to get something done in a separate terminal application.
There appear to be a few related terminal open source Java plugins for Eclipse, such as: which support multiple shell types.

Best Regards,

John
sorin_carbunaru
Posts: 402
Joined: Mon May 09, 2016 9:37 am

Re: Editor Variable to ExecuteCommandLineOperation return

Post by sorin_carbunaru »

Hello John,

Could you please give us some more details about how your colleagues would use os_eval? We would like to better/fully understand their use-cases and their workflows. This would help us with the development, the testing, and so on.

One specific thing that we would like to know is where exactly would they use it...

All the best,
Sorin C.
kirkilj
Posts: 110
Joined: Fri May 14, 2010 12:14 am

Re: Editor Variable to ExecuteCommandLineOperation return

Post by kirkilj »

Hi Sorin,

Sorry for not getting back to you on this request. Besides the example of getting the name of the current Git branch or Git repo, we were also trying to retrieve the latest modification date and creation date of the current file, so we could apply some conditional exposure of custom Oxygen Actions.

Certain Information Architecture policies define a deprecation date wherein the writer might receive a warning if the file was created before the policy was put into place, but after that date a failure would result and invalidate the file. Since xpath_eval will expand any editor variables, if there was an os_eval editor variable included in the xpath expression, it would allow for XPath activation and other date-sensitive triggering mechanisms to be possible.

This is easy with the Linux command line which can return the result of a command as a value that could be stored it in a variable or be used in an expression, which is why this goes hand-in-hand with my request to support other shells besides CMD on Windows 10 boxes. There are bash shells for Windows, and the one we use mostly is Git BASH, included in Git for Windows. If we could specify in general which shell Oxygen should use as well as what shell should used to evaluate an os_eval function, then we wouldn't have to jump through hoops. Likewise a javascript_eval might be useful in other contexts and allow us to get at certain file system attributes without resorting to Java every time. I don't see any existing built-in editor variables/functions that would return these categories of information. We have many more writers who know bash shell and Javascript than know Java, and it could open up possibilities for them.

One thing I haven't tried is to see what would happen if we tried executing an ExecuteCommandLineOperation whose command line invoked gitbash.exe and passed in a Bash expression on the command line. ExecuteCommandLineOperation can't return a value and store it in an Oxygen custom editor variable, correct? But perhaps the bash command line could simply redirect stdout to a file that could be examined by a follow-up task. I know this could be a complicated feature set, but I want to let you know, in general, whenever we hit a speed-bump so you can determine if it resonates with other customers' requests.

If you have any guidance for which parts of the SDK might be of service in implementing this on our own, that would be the fastest thing to do.

Best Regards,

John
alex_jitianu
Posts: 1008
Joined: Wed Nov 16, 2005 11:11 am

Re: Editor Variable to ExecuteCommandLineOperation return

Post by alex_jitianu »

Hi John,

Thank you for all of these details!
One thing I haven't tried is to see what would happen if we tried executing an ExecuteCommandLineOperation whose command line invoked gitbash.exe and passed in a Bash expression on the command line. ExecuteCommandLineOperation can't return a value and store it in an Oxygen custom editor variable, correct? But perhaps the bash command line could simply redirect stdout to a file that could be examined by a follow-up task.
You are correct. I did a bit of testing myself and it works as you anticipated. You can invoke directly git bash: bash.exe -c command. You can redirect it to a file, as well bash.exe -c "ls >> test.txt", to make its output available to other operations, probably chained after the current one.
If you have any guidance for which parts of the SDK might be of service in implementing this on our own, that would be the fastest thing to do.
An Workspace Access plugin can contribute custom variables. We have one such sample plugin available on Github. One thing to consider though, is that when expanding an expression, we pass through these SDK custom resolvers first and afterwards we expand the built-in/option-configured variables. So you can't have an xpath_eval generating a custom variable that should be handled by these SDK resolvers.

Here is an unpolished, but functional, example about how you could contribute an os_eval custom variable:

Code: Select all

  /**
   * @see ro.sync.exml.plugin.workspace.WorkspaceAccessPluginExtension#applicationStarted(ro.sync.exml.workspace.api.standalone.StandalonePluginWorkspace)
   */
  public void applicationStarted(final StandalonePluginWorkspace pluginWorkspaceAccess) {
    EditorVariablesResolver resolver = new EditorVariablesResolver() {
      @Override
      public List<EditorVariableDescription> getCustomResolverEditorVariableDescriptions() {
        List<EditorVariableDescription> descriptions = new ArrayList<EditorVariableDescription>();
        descriptions.add(new EditorVariableDescription("os_eval", "${os_eval(cmd)}"));
        return descriptions;
      }
      
      @Override
      public String resolveEditorVariables(String contentWithEditorVariables, String currentEditedFileURL) {
        int indexOf = contentWithEditorVariables.indexOf("${os_eval(");
        while (indexOf != -1) {
          int end = contentWithEditorVariables.indexOf(")}", indexOf);
          
          if (end != -1) {
            String value = evaluate(contentWithEditorVariables.substring(indexOf + "${os_eval(".length(), end));

            contentWithEditorVariables = "";
            if (indexOf > 0) {
              // We have something before the variable.
              contentWithEditorVariables += contentWithEditorVariables.substring(0, indexOf);
            }
            // Replace the variable with its resolved content.
            contentWithEditorVariables += value;

            if (end + 2 < contentWithEditorVariables.length()) {
              // We have something after the variable.
              contentWithEditorVariables += contentWithEditorVariables.substring(end + 2, contentWithEditorVariables.length());
            }
            // Check if we have another variable.
            indexOf = contentWithEditorVariables.indexOf("${os_eval(", end);
          } else {
            indexOf = -1;
          }
        }
        
        return contentWithEditorVariables;
      }

      private String evaluate(String command) {
        String value = "";
        try {
          Process exec = Runtime.getRuntime().exec(command);
          exec.waitFor();
          BufferedInputStream bis = new BufferedInputStream(exec.getInputStream());
          value = IOUtil.read(new InputStreamReader(bis)).toString();
          
        } catch (IOException | InterruptedException e) {
          e.printStackTrace();
        }
        return value;
      }
    };
    
    pluginWorkspaceAccess.getUtilAccess().addCustomEditorVariablesResolver(resolver);
  }
If you manage to implement such a plugin and you are interested in sharing it with the Oxygen users community, we can publish it in our Community addons update site. I am sure that others could benefit from it.

Best regards,
Alex
Post Reply