Best Way of redirecting output to a VTE terminal

1.4k Views Asked by At

Which is the best way of redirect the output of a command to a VTE terminal?

i came with this idea:

On the VTE execute:

tty > /usr/tmp/terminal_number    

then read the file from the python program:

with open('/usr/tmp/terminal_number', 'r') as f:
    self.VTE_redirect_path=f.readline()

then execute the bash commands, for exemple:

os.system('''echo "foo" >  {0}'''.format(self.VTE_redirect_path))

The problem of this method is that the file terminal_number containing /dev/pts/# needs to be refreshed. Also i don't really like the idea of having to create files to communicate. Is there any direct solution?

2

There are 2 best solutions below

7
On BEST ANSWER

In VTE you use terminal.feed("string")

See vte_terminal_feed.

With python Popen is the suggested method to execute commands. If you are wanting to use commands then you should do this.

#Uncomment the next line to get the print() function of python 3
#from __future__ import print_function
import os
import subprocess
from subprocess import Popen
command = "echo \"something\""
env = os.environ.copy()
try:
    po = Popen(command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
        universal_newlines=True, env=env)
    po.wait()
    output, error_output = po.communicate()

    if po.returncode:
        print(error_output)
    else:
        print(output)

except OSError as e:
    print('Execution failed:', e, file=sys.stderr)

If you want to use gtk with gtk vte then do this instead.

#place the following in a method of a vte instance
env = os.environ.copy()
try:
    po = Popen(command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
        universal_newlines=True, env=env)
    po.wait()
    output, error_output = po.communicate()

    if po.returncode:
        print(error_output)
    else:
        self.feed(output) #here you're printing to your terminal.

except OSError as e:
    print('Execution failed:', e, file=sys.stderr)

For the finest control in a regular terminal you can try the cmd module. This will require that you produce your own prompt so it is a more specific option to get what you want.

3
On

@Quentin The solution that you gave me prints the console output really bad (it doesn't indents) so i had to use my solution. Here is a clear example:

from gi.repository import Gtk, GObject, Vte, GLib
import os, time, threading

def command_on_VTE(self,command):
    length=len(command)
    self.terminal.feed_child(command, length)


class TheWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="inherited cell renderer")
        self.set_default_size(600, 300)
        self.terminal=Vte.Terminal()
        self.terminal.fork_command_full(
                Vte.PtyFlags.DEFAULT, #default is fine
                os.environ['HOME'], #where to start the command?
                ["/bin/bash"], #where is the emulator?
                [], #it's ok to leave this list empty
                GLib.SpawnFlags.DO_NOT_REAP_CHILD,
                None, #at least None is required
                None,
                )

        #set up the interface
        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        #a scroll window is required for the terminal
        scroller = Gtk.ScrolledWindow()
        scroller.set_hexpand(True)
        scroller.set_vexpand(True)
        scroller.add(self.terminal)
        box.pack_start(scroller, False, True, 2)
        self.add(box)

        #To get the command to automatically run
        #a newline(\n) character is used at the end of the
        #command string.
        command_on_VTE(self,'''tty > /tmp/terminal_number\n''') # Get the terminal ID

        # read the terminal ID
        while not os.path.exists("/tmp/terminal_number"):
            time.sleep(0.1) 
        with open('/tmp/terminal_number', 'r') as f:
            self.VTE_redirect_path=f.readline()
            os.remove('/tmp/terminal_number')

        # this cleans the vte
        os.system('''printf "\\033c" > {0}'''.format(self.VTE_redirect_path)) 


        # this calls the exemple
        threading.Thread(target=self.make_a_test).start()   

    def make_a_test(self):
        os.system('''ls -laR /home/ > {rdc}
echo "-------- The listing ended -------

Note that the input of the commands are not printed
" > {rdc}'''.format(rdc=self.VTE_redirect_path))

win = TheWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

I haven't found a way of getting the Terminal ID with out passing for the creation of a temporary file. This could be skipped if there is some way to pass a variable from the VTE to the python script. Any help on this would be great!