VSCode Extension that Executes terminal command - terminal

Trying to write an extension that executes the terminal command.
For example:
if I execute the sensors command in the terminal, it will show the CPU temperature. I want to create a command that prints this information into the terminal upon activation.
I have tried by placing it with registercommand like following.
let d = vscode.commands.registerCommand(sensors);
context.subscriptions.push(d);
Does anyone know where to put these type of terminal commands?
Environment:
Ubuntu 22.04.1 LTS
AMD Ryzen 3

One possible approach is to use Node.js' child_process module, run the sensor command in a separate process with this, read the output and print that in an output channel in VS Code.

Used child_process to execute the terminal command from extension (One click output)
exec('sensors', (error, stdout, stderr) => {
if(error){
console.log(`error: ${error.message}`);
return;
}
if(stderr){
console.log(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});

Related

Node.js: Is there a way to detect whether I'm using bash or cmd?

So, I'm messing around with an open source node application and I'm getting errors when I ask it to run a "command line" command. The original programmer wrote it in such a way that it only detects the os. If it's Windows it appends cmd, else it appends bash to run the command.
The problem is that I'm using Bash, on Windows, and the original author must not have thought of this..
Is there a way to get Node to detect where it's being run from, as opposed to detecting the os?
Check if "Windows" of "System32" are in your PATH env variables:
Updated Gist
It's not a perfect solution but I personally check if ls gives (stderr) an error. I use spawn to run that in a child process to avoid outputting anything in the current process.
You should know that for some reason, even though ls is a valid command in PowerShell, it will also output an error when run via child_process execution methods within a PowerShell CLI. This strange behavior is useful to detect both CMD and PowerShell.
Lastly, it allows the end-user to use a bash-like CLI since in that case, ls will work just fine. Here is the function:
const { spawnSync } = require('child_process')
const os = require('os')
function isCmd() {
if (os.platform() !== 'win32') {
return false
}
try {
const result = spawnSync(`ls`, {
stdio: 'pipe',
})
return result.error !== undefined
} catch (err) {
return true
}
}

Swift and NSTask hangs

i am new to the Mac World. I'm using Swift and i am trying to run external processes one at a time.
Now everything works fine, as long, as it is debugged, by which I mean: Run in Xcode with Debugger attached.
I do not change anything and try to run it in the terminal window, from it's place in the "Debug" folder. Now the external process starts but hangs.There is some STDERR output, which I already switched off. And there is DiskIO by the external Task.
let video : NSTask = NSTask()
video.launchPath = "./ffmpeg"
video.arguments = ["-i", "\(item)", "-c:v","copy", "-bsf:v", "h264_mp4toannexb", "-an", "-y", "-loglevel", "quiet", "\(path).h264"]
//also tried without the following two lines
video.standardError = NSFileHandle.fileHandleWithStandardError()
video.standardOutput = NSFileHandle.fileHandleWithStandardOutput()
video.launch()
video.waitUntilExit()
Yes: I copied everything to the current path, so that execution works. It starts but hangs when run from terminal.
Now the Question arises: WHY?! What am I doing wrong here? The easy solution would be to always run it in Xcode, but as you might imagine, that is quite inconvenient with a command line tool.
You need to redirect stdin from /dev/null. ffmpeg has an open stdin and is waiting for more data on that pipe.
video.standardInput = NSFileHandle.fileHandleWithNullDevice()
Note that you don't need your assignments to standardError and standardOutput. Those are the default settings.
This works in Xcode because the debugger closes stdin for you.

process.exit(0): output disappears?

Emacs lisp command calling node hello.js:
(call-process "node" nil t nil "hello.js")
Two variants of hello.js:
hello_1.js:
console.log('Hello world!');
Output:
Hello world!
0
hello_2.js:
console.log('Hello world!');
process.exit(5);
Output (no output from log statement!):
5
What is the reason that process.exit(5) causes output to be suppressed?
Notes:
I experienced the problem in GNU Emacs 24.3.1 (i386-mingw-nt5.1.2600) of
2013-03-17 on MARVIN in combination with Node.js v0.10.18, running on
Windows XP/SP3/32.
I tried EShell to execute the node command line: no output
process.exit() calls low level process.reallyExit(), which causes the problem:
no output
process.reallyExit() is implemented in C++:
void Exit(const FunctionCallbackInfo<Value>& args) {
HandleScope scope(node_isolate);
exit(args[0]->IntegerValue());
}
[...]
NODE_SET_METHOD(process, "reallyExit", Exit);
Phew, I figured it out myself. First of all, I discovered that a delay causes
the output to appear:
hello_3.js:
console.log('Hello world!');
setTimeout(function () {
process.exit(5);
}, 1000);
Output:
Hello world!
5
So I double checked Node.js documentation for console, and found:
The console functions are synchronous when the destination is a terminal or a
file (to avoid lost messages in case of premature exit) and asynchronous when
it's a pipe (to avoid blocking for long periods of time).
Then I decided to make sure that no pipe is used and wrote a batch script
hello_2.bat:
#ECHO OFF
node hello_2.js >test
TYPE test
Output when calling the script with (call-process "cmd.exe" nil t nil "/C"
"hello_2.bat"):
Hello world!
0
(return value is 0 instead of 5, but I don't care about that)
To answer my question:
It looks like call-process in Emacs on Windows uses a pipe for retrieving
output from programs.
As I also mentioned EShell: It does not seem to be recognized as a
terminal by Node.js on Windows, and possibly EShell internally uses call-process or
similar to run programs.
Detection of a pipe as destination for standard output causes console.log
to be run asynchronously.
process.exit(5) in Node.js on Windows seems to discard all scheduled
asynchronous tasks, and thus no output is generated.
This assumption is supported by the outcome of desperately directing output to a
pipe inside the Windows command prompt:
C:\Temp> node hello_2.js | MORE
C:\Temp>
Finally, I found out that the issue is known since about a year ago (as of September 2013).

Running shell commands in GVim without echoing the Vim command

When I use :! to run shell commands, like:
!echo hi
It prints both the VimScript command and it's output, so I get:
:!echo hi
hi
This is OK when I do it in command line mode, but when I run it via a .vim file I don't want to see it - I just want to see the result of the command.
Is there a way to disable the echoing of the VimScript command?
I know I can use
echo system('echo hi')
But that would prevent me from using it with interactive shell programs...
BTW, I'm using Linux - in windows this is not really a problem since shell commands run on a new console window anyways...
edit:
This is my small working example:
function! RunShellTask(cmd)
execute '!'.a:cmd
return v:shell_error
endfunction
call RunShellTask('echo hi')
I run it with :source %
You could try the :redir command:
*:redi* *:redir*
:redi[r][!] > {file} Redirect messages to file {file}. The messages which
are the output of commands are written to that file,
until redirection ends. The messages are also still
shown on the screen. When [!] is included, an
:
:
To stop the messages and commands from being echoed to
the screen, put the commands in a function and call it
with ":silent call Function()".
An alternative is to use the 'verbosefile' option,
this can be used in combination with ":redir".
I haven't tested, but you could try :redir #b, execute the shell commands from a function called with :silent call, read the output (from register b), filter out the vimscript commands, display it on the screen and then :redir end.
Another option is to try some plugins that provide similar functionality:
shellasync.vim : shellasync.vim plugin for asynchronously executing shell commands in vim
Conque Shell : Run interactive commands inside a Vim buffer
Screen (vim + gnu screen/tmux) : Simulate a split shell, using gnu screen or tmux, that you can send commands to.
Vicle : Vim - Interpreter Command Line Editor. Like Chimp or Slimv.

How to detect on waiting for user input from bash script?

My bash script looks like:
read -p "Do you wish to continue?" yn
# further actions ...
And I just want to interact with this script using nodejs / child_process.
How can I detect that it's waiting for the user input?
var spawn = require('child_process').spawn;
var proc = spawn('./script.sh');
proc.stdout.on("data", function(data) {
console.log("Data from bash");
}
proc.stdin.on("data", function(data) {
console.log("Data from bash"); // doesn't work :/
}
Thank you!
From the bash man page:
read -p prompt
Display prompt on standard error, without a trailing newline, before
attempting to read any input. The prompt is displayed only if input is
coming from a terminal.
And I don't think there a any way in node.js to detect that the script is waiting for input. The problems is actually that bash detects a non-terminal and disables the output to standard error. And even then you would have to read from stderr and not stdin to detect any waiting states.
In the end, as Antoine pointed out, you might have to use tools like empty or Expect to wrap your shell-scripts and trick Bash to think it is in a terminal.
Btw.: proc.stdin.write("yes\n") works fine. Thus you could work with the script, but won't get any prompts on proc.stderr and will not know when the script actually reads the input. You can also immediately proc.stdin.write the input even if the script is not yet at the read -p statement. The input is buffered until the scripts eats it up.
Have you try to use "expect" http://en.wikipedia.org/wiki/Expect ?
It's a tool that "expect" some text (it use regular expression) and the bash script can automatically answers.

Resources