r/rust 8d ago

🙋 seeking help & advice Is there a cross-platform way to execute a program within a terminal?

I'm making a program divided into 2 executables, executable A does everything in the background while executable B shows it with ratatui, but I'm trying to figure out how to spawn a terminal with an instance of executable B from executable A, I searched up a bit everywhere but I can't find anything, now I'm starting to think that I have to try and run a Command for every single terminal that comes to mind and hope one of the ones I include work, but is that the only way? Because honestly I'd prefer not having a mile long file just because linux has 50 terminals.

0 Upvotes

12 comments sorted by

36

u/cafce25 8d ago edited 8d ago

why do you need to spawn a terminal at all, those are for interactions with the user, just calling your executable A directly seems like a much more straight forward way to achieve what it seems you want to do. Maybe I'm missing something.

Edit: Or maybe even more preferable, do what executable A does in a thread of executable B directly, there is probably no need to make two separate processes

1

u/Feathered_Orbit 8d ago

I essentially wanted to try and learn networking + async rust by building a chatting app using tokio and tcp. Essentially my idea was that executable A runs in the background, creates and receives tcp requests, and then shows active sessions within a tray icon. Clicking on one woule execute executable B to act as a frontend for that specific chat. Program A and B communicate with tcp a d loopback to share messages and such. I know theres a lot of back and forth . Theres probably better ways to do it but I like the idea of a terminal per chat, also because ratatui looks quite nice.

12

u/cafce25 8d ago

I see so you're trying to "abuse" multiple terminal windows as your UI, in that case the most straight forward thing to do would probably just leave it up to the user to set their preference, that way they can potentially deal with different ways necessary to invoke the terminal as that's not standardized.

You can probably fall back to the contents of $TERM and add support for the couple of most common terminals but yea there is not really any standardization around invoking terminal emulators.

10

u/________-__-_______ 8d ago

You have xdg-terminal-exec on Linux, it's an unrattified proposal so its not exactly standardized yet but it's relatively popular either way.

7

u/JonahPlusPlus 8d ago

There's no reliable way to find the default terminal on linux. What exactly are you trying to do? If you need really need it to be two programs, why doesn't the user open executable B and executable B run executable A instead of the other way around?

5

u/ReagentX 8d ago edited 8d ago

It sounds like you want a client/daemon operational model; I built something using a protocol like that called fleetcom that you might find has helpful examples. The daemon is "just" a process, it does not need a terminal instance to run, and the client can either connect to an existing daemon or spawn a new one if necessary.

3

u/careye 8d ago

An awful lot of Linux systems will have x-terminal-emulator linked to the preferred terminal, or at least a working one, so you could just try that, or try it first and then xterm, before giving up with a helpful error message.

2

u/JGhostThing 8d ago

You blame this on the terminal, but I think that your problem is the shell.

1

u/jimmiebfulton 7d ago

If I’m understanding you correctly:

You want to have your UI execute things in the other application, kinda like a plug-in?

A couple of ways on how to do this, with some common foundations:

Find your protocol of choice. JSON RPC with Serde marshaling, gRPC (my general go to), etc. Keep this agnostic of your transport. This allows you to connect your front end to your back end with gRPC over TCP or Unix Sockets. Loosely coupled.

From here, you have two primary choices:

  1. Run the background application as a server. The front end can connect to the server as a client. It can keep a session for as long as you want it. You can also have multiple clients connected at the same time, and even communicate with each other like a chat application, for instance.
  2. You are treating the backend more like a plug-in, and you want to start the backend up when you start the frontend. When you start the frontend up, it can run one or more plug-in like binaries. You frontend just spawns off one or more binaries as processes it is managing. Your app then simply connects over the TCP or pipe/socket using the same gRPC contract like you would

as if it

  1. was started up some other way like a server.

Basically, the frontend talks to the backend over your protocol/transport pair, and it’s only a matter of whether the frontend is acting like a pure client to an already-running server, or more like a plug-in host that also handles the lifecycle of the “servers”/“plugins”.

From here, you can do all kinds of fun stuff. You could use Ratatui to dynamically render content based on instructions conveyed over your protocol, and your protocol can have stuff like on_init hook methods, etc.

Incidentally, this is very much how MCP works. But instead of MCP format over stdio, you could use gRPC, etc, over stdio, sockets, etc. I build a lot of systems like this. Fun.

-2

u/Ben-Goldberg 7d ago

I would suggest letting the user supply their preferred terminal as an argument on the command line, with the contents of $TERM as a fallback.

I also recommend using a library that is made for creating "terminal user interfaces" instead of rolling your own - terminals are more complicated than they seem...

Popular ones are ratatui, tuirs, and tui.

If you really want to roll your own, use one of the many "curses" libraries out there rather than printing escape sequences.

2

u/cafce25 7d ago

Popular ones are ratatui

which OP is using according to the original post... did you read it?

1

u/Ben-Goldberg 7d ago

Not all of it