Linux - Open terminal for input/output - linux

I'm coding a Rust app and since it's fairly small and there don't appear to be any stable UI frameworks, I've made it run in the console using println! and whatnot for input/output. However since this program is intended to be used by people directly after downloading from the internet (due to its use case), they're likely to just double click on it instead of navigating to their downloads directory in a terminal and running it from there.
This is a problem because on Linux, it runs in the background waiting for input and looks like it's not working. On Windows, Rust programs do open in CMD by default. (and in fact many of the search results for my question were about disabling this behavior - the exact opposite of what I want!).
So is it possible to somehow make my application open in the system's default terminal? My preferred way would be to somehow embed in the executable to open in terminal (similar to the -mconsole compiler flag on MinGW). Otherwise would it be possible to detect it's in the background and fork it into a terminal? If that's not possible then is it at least possible to detect that the app is not running in a terminal and throw up a message box telling the user to run in a terminal?
My app is cross-platform but I'm OK with writing code conditionally compiled on one OS.

One typical way would be to distribute a program.sh along with your executable. If .sh extension is bound to opening a terminal in their window manager of choice, it would open automatically. If not - it is enough of a hint for running it from the shell.
Without this file you could:
Detect if the program is already running inside a terminal can be done with isatty(). There's a crate for it.
If not, spawn the terminal app process (see process::Command) and relaunch the program with it by passing its path to the terminal command line options. As #Caesar mentioned there's a bunch of popular terminals that you might want to check for presence on Linux. If nothing is found, xterm could sometimes be a fallback.

Related

How do I start a terminal instance from a compiled rust executable?

I am making a small-scale project which reads from a file of 101 items, creates a vector of strings, and then randomly accesses one of the items and prints it to the standard output. The program works exactly as intended when run from the terminal, whether through cargo run
or by running the executable from the terminal with ./executable_name. The problem is, if I double click on the executable without a terminal open there is nowhere for the information to be printed and the program is essentially useless. I know how to check if a terminal is open using
if atty::is(Stream::Stdout) {
println!("Already in terminal");
} else {
// this is where I get confused
}
but from there I don't know where to go. I have experimented with things like Command::new("sh"); but am struggling with the documentation. Eventually, the idea is that I can compile this on my partners Mac without losing its functionality as I am writing it on Linux, and create an easy to use application to run it on her machine.
Programs generally do not open their own terminal windows. The way you arrange for one to exist varies by platform:
On macOS, you actually don't have to do anything; the default behavior of double-clicking an executable is to open a terminal to run it in. (GUI applications have their executables inside of .app packages, so that this behavior does not apply to them.)
On Windows, whether a terminal is opened is a property of the executable, which you can set in Rust with the windows_subsystem attribute. However, the default value is console so you don't need to do anything. (I've heard it is also possible to open a console window after startup, but I am not a Windows developer and can't advise you on the proper system calls to do that.)
On Linux, you'd create a .desktop file that specifies Terminal=true, to ask the desktop environment to launch your program in a terminal, and double-click that file rather than the executable. Or, you could make your program launch a terminal emulator and instruct it to start your program again within itself, but how you do that will depend on what terminal emulator programs are installed.
The one thing you'll have to do for all these cases is add a “Press Enter to exit” prompt to your program. Otherwise, the terminal will close immediately after your program exits, and so your output won't be visible.
eprintln!("Press Enter to exit.");
std::io::stdin().read_line(&mut String::new()).unwrap();

Launching Programs (example: Vim) from Haskell

Using the Turtle shell scripting library I am trying to launch a program, i.e:
shell "vim" empty
The problem is that this yields the warning Warning: Input is not from a terminal and causes Vim to lag for a few seconds before finally launching.
Questions:
Is shell the best Turtle function to launch an external program from haskell?
If so, is there any way to get around errors like the above?
You want to use functions from the process library, specifically createProcess or runProcess.
Relevant turtle thread on the issue here.
Example usage.
You could try manually setting up I/O to the vty. E.g. in bash: vim < $TTY > $TTY. I guess turtle is doing that with its own file descriptors under the hood, based on the warning, so you should be able to manually set up those redirects (or just use the command I gave via shell). You just need to make sure you've got a TTY environment var around.

Temporarily quitting Gvim starts over the shell

I am on windows machine, when I temporarily change to console using :sh then back to vim with exit command and then again back to console and it starts over. this causes me to lose my previous directory. Is there other way returning back to vim won't start the shell over?
Not really
https://stackoverflow.com/a/12089631/1427295
GVIM does not retain a "handle" to the shell that launched it in a way
that allows it to send commands back to it. Because of they
synchronous execution, you also cannot launch a shell from GVIM, keep
feeding it commands while also continue working in GVIM.
I'm afraid you have to use the functionality of your window manager to
launch (and then later re-activate) a shell window, and send the
commands as keystrokes to it. On Windows, this can be done (e.g. in
VBScript) via WshShell's Run(), AppActivate() and SendKeys() methods;
there are probably similar mechanisms for window control on Linux,
too.
If you don't mind having that shell inside your GVIM (emulated, with
all its drawbacks), though, there are plugins that enable that.
https://serverfault.com/a/95405
The Windows command interpreter ("cmd.exe") doesn't provide any
support for saving/exporting/keeping history, of, if it does,
Microsoft didn't document it and nobody was ever able to find it. You
can of course try to work around that, like Sean suggested, but
there's (or does appear to be) no built-in support for this
You may be able to output your command history using echo %cd% > prev_dir.txt then create a script that cds to the directory in prev_dir.txt, but you'd still have to remember to save your directory to the file before you exit the shell each time.

starting program in new terminal window

I have a program that needs to start another program. On my mac I did this using system("open path"), but on linux that doesn't work. and using system(./path) is not what I want since than it overtakes the running program.
So is there any way to get the same behaviour as the mac 'open path' command on linux?
(linux noob btw:p)
If you're running the application in a GUI environment, this should be possible but the approach is different. You need to start a new terminal instance explicitly.
Determine the path to your terminal application. This depends on the linux distribution.
Next, check the documentation of that particular terminal application and find out how it can be started to run an application (your application) instead of a shell. This probably involves using some application-specific command line options. Test that in a terminal window, until you have a command line that gives you the desired result. Things could get a little tricky if your application needs command line arguments as well. Use the -- option where necessary.
Then, all you need to do is run that command line from your "parent" application. I would advise however to not use system(). The exec... family functions (using fork and wait) provide better control.

Duplicate keyboard typing to another terminal

I have laptop-desktop setup at home and I have successfully cloned my Archlinux installation from one to another. However, I would like to avoid having to {install all new software, edit settings, update} twice, so I was wondering if it'd be possible to log over ssh from laptop to desktop, do something in terminal and have linux copy everything I type into second terminal with ssh logged in?
Thanks for ideas!
You could type the commands into one terminal then edit ~/.bash_history and save the commands into a script. Copy the script onto the machine with the second terminal and execute it. The advantage of this is now you have a script that saved your setup so you can reuse it whenever you need to.
You can use clusterssh, which duplicates your typed input across multiple systems. It is designed for situations in which the exact same tasks, such as software installation or configuration commands, are needed to be performed exactly the same on multiple systems. See http://sourceforge.net/projects/clusterssh/. Also, the KDE Konsole terminal has similar functionality.

Resources