Giter VIP home page Giter VIP logo

Comments (17)

rashil2000 avatar rashil2000 commented on May 18, 2024 1

I was looking for something like this: Currently I have a script in my home directory called init.cmd, which auto sets some aliases and variables at each shell startup. The location of this script has to be added to the Autorun variable of Command Processor in the Windows Registry. The script looks like this:

@echo OFF
set WTSettings="C:\Users\RashilGandhi\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json"
set ClinkReadlineHistory="C:\Users\RashilGandhi\AppData\Local\clink\clink_history"

doskey arch=wsl -d arch-linux genie -s
doskey admin=sudo
doskey ls=dir
'
'
'

and now this basically acts as a .bashrc for Windows CMD.

I was basically asking if there was a way to do this through Clink at each injection. I'm not aware if doskeys and variables (that can be accessed in the shell itself) can be set through Lua scripts, if yes, could you tell me how?

from clink.

rashil2000 avatar rashil2000 commented on May 18, 2024 1

There is a lot of Lua API documentation in clink.html, and a lot of public Lua documentation. What have you found so far from those?

I found the function os.setenv there, which can be used to set the variables. For settings aliases, I'm still looking as there is no built-in function.

Update:
I initially knew about io.popen function of Lua, but I thought it opened a separate process and didn't affect the current shell. Similar for os.execute.
But after some testing, it seems both these do affect the current shell, so either one of these should be fine, I guess? And I think os.execute should be a little faster since it doesn't have to open a file handle. Am I correct?

from clink.

rashil2000 avatar rashil2000 commented on May 18, 2024 1

If that's the case, I can safely assume that neither io.popen and os.execute would work in a scenario like this: Let's say I run a Java program that sets the JAVA_HOME variable for the current shell. If this program is run through either of the above two commands, then I won't be able to access JAVA_HOME, because it has been set in a different process. Right?

Thanks for the info though; I learnt a cool thing about doskey.exe today!

from clink.

chrisant996 avatar chrisant996 commented on May 18, 2024 1

Correct!

from clink.

rashil2000 avatar rashil2000 commented on May 18, 2024 1

If I'm understanding it correctly, the new clink_start.cmd script feature does exactly what the original issue requested, right? (and since it runs in the current session it can modify environment variables etc., as opposed to io.popen and os.execute)

from clink.

chrisant996 avatar chrisant996 commented on May 18, 2024 1

bool host_cmd::is_interactive() const

from clink.

chrisant996 avatar chrisant996 commented on May 18, 2024

I'm not sure what you're getting at:

Are you trying to avoid writing Lua scripts? Are you asking for a second language to be added to Clink?

from clink.

chrisant996 avatar chrisant996 commented on May 18, 2024

I think what you're asking about is really more of a shell feature, but Clink isn't a shell and isn't trying to be a shell. .bashrc is part of the Bash shell itself. CMD's equivalent is the AutoRun regkey.

Clink runs Lua scripts, and you can do via Lua all of the things that .bashrc can do, you'd just go about it a little differently. Clink uses Readline, and so it already has a .inputrc file whose format is defined by Readline and shouldn't be extended because it would break compatibility with existing .inputrc files, etc. You can currently share them between Bash and Clink, because inputrc files are only about Readline, not about the shell. But you're asking for new shell features in CMD, and that heads into murky territory. Try using Lua first.

There is a lot of Lua API documentation in clink.html, and a lot of public Lua documentation. What have you found so far from those?

Something to know about me: I don't tend to just hand out answers when the questions are easy to answer without my help. In those cases I try to ask questions to spark critical thought. "Give a man a fish, feed him for a day; teach a man to fish, feed him for life."

So, think about what it is you're trying to do, and what would be needed. Try searching for those things. If you've done that already, share what's been tried so far so that the respondent (me, in this case) doesn't have to guess at what's being done and try to predict what might have been missed. Try to make it inexpensive and easy for someone to respond. 🙂

One suggestion, though -- launching processes is expensive. Maybe instead of launching doskey once per alias, make use of its input file mechanism to load a bunch of aliases at once.

P.S. This is also a good exercise to help ensure Clink has what it needs; if you run into problems that can't be solved or that have messy solutions, then that may reveal some spots where Clink can be enhanced (e.g. adding an os.setalias() function, except I'm pretty sure that launching doskey from Lua will have the desired effect and if so then that would be preferable since it would use existing well-known things instead of inventing a new wheel).

from clink.

chrisant996 avatar chrisant996 commented on May 18, 2024

It's about how Doskey works, rather than about how popen works (and execute, etc).

doskey isn't a CMD command, it's a separate program. It's a separate process, but it affects the CMD process, so we can deduce there is some mechanism they use to communicate. So launching a doskey.exe process via popen or execute will behave the same (I agree execute is a better fit here).

(The details of how they communicate is public knowledge, but the point is we don't need to know that. We only need to know whether they do, and we can deduce that from observing that doskey.exe is a program rather than a command.)

from clink.

rashil2000 avatar rashil2000 commented on May 18, 2024

Thanks, I'll close this.

from clink.

rashil2000 avatar rashil2000 commented on May 18, 2024

I should mention that the reason I have come back to this 6 month old issue is because there are things that absolutely can't be done by Lua scripts (in the shell's context). I have a couple of examples to illustrate this:

  1. FNM is a popular NodeJS version manager. It generates commands depending on the shell at runtime (which means they can't be hardcoded in a Lua script). The commands include setting a few environment variables, a function, and a doskey, all of which should be injected in the current shell session. The homepage of FNM recommends adding a startup script to AutoRun registry key and putting this in that script:
FOR /f "tokens=*" %i IN ('fnm env --use-on-cd') DO CALL %i

As you can see, this won't be possible to do in a Lua script.

  1. Perhaps this is a very rare use case. A more common use case would be Visual Studio Developer Command Prompt. VS provides some scripts that take architectures as arguments and inject the appropriate environment variables/compiler and linker paths etc. in the current session. The scripts are fairly complex and a lot of effort would be needed to translate all of them to Lua (even if it's possible).

The solution to both of these was just prepending the startup script name in the AutoRun registry key as follows:

%USERPROFILE%\init.cmd & clink.bat inject --autorun --quiet

This method isn't very reliable; I have found many instances where CMD shell just freezes in the presence of certain commands in the init.cmd (regardless of whether the clink inject part is there in the key or not).

I just wanted to say thanks for the clink_start.cmd feature; it provides a much more cleaner UX, without those freezing issue and without needing to mess with registry manually (and is technically equivalent to a startup shell script much like bash's .bashrc, zsh's .zshrc or pwsh's profile.ps1 :))

from clink.

chrisant996 avatar chrisant996 commented on May 18, 2024

If I'm understanding it correctly, the new clink_start.cmd script feature does exactly what the original issue requested, right? (and since it runs in the current session it can modify environment variables etc., as opposed to io.popen and os.execute)

More or less. I didn't originally explain the technical reasons why it's difficult/problematic to fulfill the request (I later explained them in #91). The only way Clink can "run" a command line in the current session is to give control back to CMD. So the only way Clink can "run a startup script" is to notice the first time CMD asks Clink to prompt the user, and instead don't prompt, return a hidden command as though the user had typed in the startup script/program/command name. When CMD eventually asks Clink to prompt for the next time, then Clink has to figure out whether the previous command it returned resulted in any output and reset the cursor position accordingly, then show a prompt. So what the user experiences as "the first prompt" is in reality the second prompt.

I got tired of needing to explicitly specify a startup script, and decided to try an experiment to see how well the above might work in practice.

I should mention that the reason I have come back to this 6 month old issue is because there are things that absolutely can't be done by Lua scripts (in the shell's context).

The issue wasn't about "why" it was desired (I expect the desire is nearly universal), the issue was about "how" to even accomplish it. Injection into a process with Detours has many limitations as far as what is possible to do.

%USERPROFILE%\init.cmd & clink.bat inject --autorun --quiet

This method isn't very reliable; I have found many instances where CMD shell just freezes in the presence of certain commands in the init.cmd (regardless of whether the clink inject part is there in the key or not).

Can you share an example of a script that causes CMD to freeze when it's included in the AutoRun regkey? The only reason I know of for that to happen is if the script waits on something (such as input another process, etc). If there are other things that can cause a freeze then it would be useful to know -- there might be other side effects that can affect Clink as well.

from clink.

rashil2000 avatar rashil2000 commented on May 18, 2024

The only way Clink can "run" a command line in the current session is to give control back to CMD... So what the user experiences as "the first prompt" is in reality the second prompt.

Yes, I understood that from the discussion in #91.

Can you share an example of a script that causes CMD to freeze when it's included in the AutoRun regkey?

So the way I can reproduce this is like this:

  • Run clink autorun uninstall to clear the registry key.
  • Manually set the key value to %USERPROFILE%\init.cmd
  • In init.cmd, I have put these lines:
@echo OFF
bfetch

where bfetch is a bat script I have in my path, the contents of which are here.

  • This freezes the CMD window.
  • Now if I reinstall clink autorun through clink autorun install -- --quiet, and put the contents of init.cmd into clink_start.cmd, the script runs fine and shows the output.
  • Even the FNM script (shown below) hangs CMD, whereas in clink_start it works fine.
@echo OFF
for /f "tokens=*" %%i in ('fnm env') do call %%i

from clink.

chrisant996 avatar chrisant996 commented on May 18, 2024

What is fnm and what does fnm env normally do? Looks like it's a separate process, and that process is probably hanging, thus causing CMD to "freeze". Because CMD must wait for fnm to finish executing.

from clink.

chrisant996 avatar chrisant996 commented on May 18, 2024

It's a bug in your script -- or rather, your script is causing an extremely expensive infinite loop and creating thousands of new cmd.exe processes as quickly as possible, when the script is invoked as part of launching cmd.exe. (Use TaskMgr or Process Explorer to see the processes.)

Your script launches cmd.exe...

So:

  1. You launch cmd.exe.
  2. Cmd runs the autorun command, which launches cmd.exe.
  3. The new cmd runs the autorun command, which launches cmd.exe.
  4. Infinite loop.

This type of syntax launches a new cmd.exe in order to run the command that the for command will process (the wmic os get ... part):

for /f "tokens=* usebackq" %%f in (`wmic os get Caption^,Version^,FreePhysicalMemory^,TotalVisibleMemorySize /format:list`) do (

Just like io.popen() and spawn() and system() and so on do.

The reason it doesn't go into an infinite loop when used in clink_start.cmd is purely because Clink refuses to inject itself into a non-interactive cmd.exe, and the cmd.exe spawned by the script are non-interactive.

from clink.

rashil2000 avatar rashil2000 commented on May 18, 2024

What is fnm and what does fnm env normally do?

fnm env just prints 4-5 shell commands to stdout, like these:

set FNM_ENVIRONMENT=some\temp\path
set FNM_CONTEXT=some\other\path\
set FNM_SESSION_ID=somerandomnumber
set FNM_HOME=some\persistent\path
doskey cd=somefunctiontochangeversionondirectorychange

These commands need to be run in order to set up the FNM environment. The paths here depend on session ID, which are different for each CMD session.

from clink.

rashil2000 avatar rashil2000 commented on May 18, 2024

The new cmd runs the autorun command, which launches cmd.exe.

Oohhhh, now it makes sense!!!

This means that we should think twice before putting arbitrary shell commands in AutoRun batch scripts 😅

The reason it doesn't go into an infinite loop when used in clink_start.cmd is purely because Clink refuses to inject itself into a non-interactive cmd.exe, and the cmd.exe spawned by the script are non-interactive.

How do you detect interactive sessions? (In bash there is an automatic variable $- which contains the characer i when the session is interactive). Is the %CMDCMDLINE% variable being used?

from clink.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.