Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Way to use %errorlevel% in Lua scripts? #91

Closed
rashil2000 opened this issue Mar 19, 2021 · 7 comments
Closed

Way to use %errorlevel% in Lua scripts? #91

rashil2000 opened this issue Mar 19, 2021 · 7 comments
Labels
enhancement New feature or request question Question about something

Comments

@rashil2000
Copy link
Contributor

I know ERRORLEVEL is not an environment variable, but an automatic variable. os.getenv('ERRORLEVEL') doesn't work for this reason.

Is there a way to use it in Lua scripts, specifically for prompt? I'm trying to do something like this:

local custom_prompt = clink.promptfilter(5)
function custom_prompt:filter(prompt)
  return os.date().." | "..os.getcwd().." | Last error: "..somefunction().." > "
end

I couldn't find anything in the docs.

@chrisant996
Copy link
Owner

Nope. It's impossible. I did a lot of research into that already. It is exclusively an internal variable in CMD that is not exposed in any way at all, other than in the parser.

@chrisant996
Copy link
Owner

Ok, I don't know how reliably this will work in practice, but I've hooked up an approach that's able to retrieve the value. But it's a bit invasive, so it's off by default.

A new cmd.get_errorlevel setting can make Clink run a hidden echo %errorlevel% command before every interactive prompt and retrieve the last exit code value for use by Lua scripts via a new os.geterrorlevel() function (and os.getenv("errorlevel") also returns it). It will be included in Clink v1.2.14 which will be released sometime in the next week or two.

@chrisant996 chrisant996 added the enhancement New feature or request label Jun 19, 2021
@rashil2000
Copy link
Contributor Author

What do we mean by invasive here? Does that also mean that the prompt will become slower because of the hidden echo command?

@chrisant996
Copy link
Owner

chrisant996 commented Jun 19, 2021

What do we mean by invasive here? Does that also mean that the prompt will become slower because of the hidden echo command?

It's not about speed, it's about altering the actual stream of commands being issued to CMD.

User enters three commands:

  1. abc
  2. def
  3. ghi

Clink actually runs:

  1. abc (typed by the user)
  2. echo %errorlevel% with redirection to a local temp file -- Clink fakes out CMD, and tells CMD the user actually typed the echo command, and returns it back to CMD. CMD literally runs a whole separate input line command here.
  3. def (typed by the user)
  4. echo %errorlevel% with redirection to a local temp file -- same fake-out.
  5. ghi (typed by the user)
  6. echo %errorlevel% with redirection to a local temp file -- same fake-out.

It's two very different series of commands. To be clear -- Clink is not "running a command" like you'd expect io.popen or etc would do -- no, Clink is pretending the user typed these additional commands. From CMD's perspective, the user has typed 6 separate commands at 6 separate input prompts. Even though the user only saw 3 of the input prompts and only typed at 3 of the input prompts.

Who knows what weird quirks it could run into.

It's tempting to say nothing could go wrong because it's just a few echo commands. But that might be underestimating the complexity of what really happens at lower levels.

For example, what if you press ^C during the def command and the CMD prompt regains control but the def command is still running (yes that can happen; def is a placeholder here and could be a series of piped processes that are all sharing the same terminal console as CMD). And now during the concurrent input/output overlapping, Clink will run twice as many actual commands through CMD as the user thinks they're running. Who knows under what circumstances that might have observably different behavior than before. And who knows whether "observably different behavior" might be benign or troublesome.

I'm not saying there will be problems. I'm saying there is certainly potential for weird problems, and there's no way to predict.

Invasive.

@rashil2000
Copy link
Contributor Author

rashil2000 commented Jun 19, 2021

Ah, understood. Thanks for taking the time to explain all this!

Keeping in mind the potential for weird behaviour, does this also mean that in the future clink might provide a way to run any arbitrary command (just like echo %errorlevel%) in Lua scripts in the present session itself (as currently any external commands just get executed in a new process)? Of course this behaviour would be turned off by default as you initially mentioned.

@chrisant996
Copy link
Owner

Keeping in mind the potential for weird behaviour, does this also mean that in the future clink might provide a way to run any arbitrary command (just like echo %errorlevel%) in Lua scripts in the present session itself (as currently any external commands just get executed in a new process)?

First:

It sounds like the question is "can Lua code call a function to run a command in the current session".
That's not what I described.

There's no way to "call into CMD to run a command".
There is only a way to "return control back to CMD, telling it what command to run".

That's all that Clink ever does! CMD calls into Clink code to "show a prompt and get input from the user". Clink returns a string to CMD, and CMD runs the string as a command. Repeat over and over until CMD exits.

Second:

It's possible to run any command in the current session by returning from Clink. But that's very messy.

It would have to:

  1. suspend the Lua code (which is only possible if the Lua code is running in a coroutine)
  2. erase the prompt and input text
  3. save the input text
  4. tell Readline the user pressed enter
  5. skip adding the command to history
  6. replace what the user typed with what the Lua code wants to run
  7. return from the input prompt back to CMD
  8. let CMD run the overridden input command line
  9. wait for CMD to show another prompt
  10. show the prompt
  11. restore the saved input text from step 3
  12. resume the Lua code

Notice that during steps 2 through 9 the prompt and input text are erased and are not visible. And if the command that effectively gets run during step 8 produces any stdout or stderr output then it won't just "flicker", there will be additional output visible.

It's already possible to run anything in the current session ever since clink.onendedit() was added in v1.1.20.

The only things missing from being to already do that today are (1) the ability to save/restore what the user had typed, (2) the ability to erase the prompt and input text, (3) the ability for the coroutine to get resumed, (4) the ability to prevent all Lua events from being sent during the procedure (mustn't let onbeginedit or onendedit event handlers run, and mustn't let any other Lua code run or a whole bunch of complicated nasty problems become easy to happen).

So is it technically possible? Sure, I guess so. It seems like a very fragile and dangerous thing to do, and due to the coroutine requirement it's also going to be hard for a Lua programmer to get their code written correctly to be able to successfully do this.

I think this should not be implemented.

@rashil2000
Copy link
Contributor Author

That's fair. Thanks again for all the details!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Question about something
Projects
None yet
Development

No branches or pull requests

2 participants