wxPython: how to create a bash shell window?

后端 未结 4 833
渐次进展
渐次进展 2020-12-01 15:11

I want to create a popup window using wxPython that acts like a bash shell. I don\'t want a terminal emulator, I don\'t need job control, I just want a REPL (Read, Eval, Pr

相关标签:
4条回答
  • 2020-12-01 15:36

    i searched but there doesn't seem to be any exiting bash shell for wxPython though wx.py module has Shell module which is for python interpretor good thing is you can pass your own interpretor to it,so I have come with very simple bash interpreter. example currently reads only one line from bash stdout, otherwise it will get stuck, in real code you must read output in thread or use select

    import wx
    import wx.py
    from subprocess import Popen, PIPE
    
    class MyInterpretor(object):
        def __init__(self, locals, rawin, stdin, stdout, stderr):
            self.introText = "Welcome to stackoverflow bash shell"
            self.locals = locals
            self.revision = 1.0
            self.rawin = rawin
            self.stdin = stdin
            self.stdout = stdout
            self.stderr = stderr
    
            #
            self.more = False
    
            # bash process
            self.bp = Popen('bash', shell=False, stdout=PIPE, stdin=PIPE, stderr=PIPE)
    
    
        def getAutoCompleteKeys(self):
            return [ord('\t')]
    
        def getAutoCompleteList(self, *args, **kwargs):
            return []
    
        def getCallTip(self, command):
            return ""
    
        def push(self, command):
            command = command.strip()
            if not command: return
    
            self.bp.stdin.write(command+"\n")
            self.stdout.write(self.bp.stdout.readline())
    
    app = wx.PySimpleApp()
    frame = wx.py.shell.ShellFrame(InterpClass=MyInterpretor)
    frame.Show()
    app.SetTopWindow(frame)
    app.MainLoop()
    
    0 讨论(0)
  • 2020-12-01 15:45

    I found the solution for my problem. Funny how it never turned up in google searches before now. It's not production ready code, but it ultimately what I was looking for -- a way to run a bash shell in a wxPython window.

    http://sivachandran.blogspot.com/2008/04/termemulator-10-released.html

    0 讨论(0)
  • 2020-12-01 15:51

    ok here is another try, which reads all output and errors too, in a separate thread and communicates via Queue. I know it is not perfect(e.g. command with delayed output will not work and there output will get into next commnd for example tryr sleep 1; date) and replicating whole bash not trivial but for few commands i tested it seems to work fine

    Regarding API of wx.py.shell I just implemented those method which Shell class was calling for Interpreter, if you go thru source code of Shell you will understand. basically

    • push is where user entered command is sent to interpreter
    • getAutoCompleteKeys returns keys which user can user for auto completing commands e.g. tab key
    • getAutoCompleteList return list of command matching given text

    • getCallTip "Display argument spec and docstring in a popup window. so for bash we may show man page :)

    here is the source code

    import threading
    import Queue
    import time
    
    import wx
    import wx.py
    from subprocess import Popen, PIPE
    
    class BashProcessThread(threading.Thread):
        def __init__(self, readlineFunc):
            threading.Thread.__init__(self)
    
            self.readlineFunc = readlineFunc
            self.outputQueue = Queue.Queue()
            self.setDaemon(True)
    
        def run(self):
            while True:
                line = self.readlineFunc()
                self.outputQueue.put(line)
    
        def getOutput(self):
            """ called from other thread """
            lines = []
            while True:
                try:
                    line = self.outputQueue.get_nowait()
                    lines.append(line)
                except Queue.Empty:
                    break
            return ''.join(lines)
    
    class MyInterpretor(object):
        def __init__(self, locals, rawin, stdin, stdout, stderr):
            self.introText = "Welcome to stackoverflow bash shell"
            self.locals = locals
            self.revision = 1.0
            self.rawin = rawin
            self.stdin = stdin
            self.stdout = stdout
            self.stderr = stderr
    
            self.more = False
    
            # bash process
            self.bp = Popen('bash', shell=False, stdout=PIPE, stdin=PIPE, stderr=PIPE)
    
            # start output grab thread
            self.outputThread = BashProcessThread(self.bp.stdout.readline)
            self.outputThread.start()
    
            # start err grab thread
            self.errorThread = BashProcessThread(self.bp.stderr.readline)
            self.errorThread.start()
    
        def getAutoCompleteKeys(self):
            return [ord('\t')]
    
        def getAutoCompleteList(self, *args, **kwargs):
            return []
    
        def getCallTip(self, command):
            return ""
    
        def push(self, command):
            command = command.strip()
            if not command: return
    
            self.bp.stdin.write(command+"\n")
            # wait a bit
            time.sleep(.1)
    
            # print output
            self.stdout.write(self.outputThread.getOutput())
    
            # print error
            self.stderr.write(self.errorThread.getOutput())
    
    app = wx.PySimpleApp()
    frame = wx.py.shell.ShellFrame(InterpClass=MyInterpretor)
    frame.Show()
    app.SetTopWindow(frame)
    app.MainLoop()
    
    0 讨论(0)
  • 2020-12-01 15:53

    Going to see what i can come up with.

    But if you change your mind and decide to use pygtk instead, here it is:

    enjoy!!

    EDIT

    I started making a poor man's version of a terminal using the text control widget. I stopped because there are flaws that can't be fixed, such as when you use the sudo command.

    import wx
    import subprocess
    
    class MyFrame(wx.Frame):
        def __init__(self, *args, **kwds):
            # begin wxGlade: MyFrame.__init__
            kwds["style"] = wx.DEFAULT_FRAME_STYLE
            wx.Frame.__init__(self, *args, **kwds)
    
            self.prompt = "user@stackOvervlow:~ "
            self.textctrl = wx.TextCtrl(self, -1, '', style=wx.TE_PROCESS_ENTER|wx.TE_MULTILINE)
            self.default_txt = self.textctrl.GetDefaultStyle()
            self.textctrl.AppendText(self.prompt)
    
            self.__set_properties()
            self.__do_layout()
            self.__bind_events()
    
    
        def __bind_events(self):
            self.Bind(wx.EVT_TEXT_ENTER, self.__enter)
    
    
        def __enter(self, e):
            self.value = (self.textctrl.GetValue())
            self.eval_last_line()
            e.Skip()
    
    
        def __set_properties(self):
            self.SetTitle("Poor Man's Terminal")
            self.SetSize((800, 600))
            self.textctrl.SetFocus()
    
        def __do_layout(self):
            sizer_1 = wx.BoxSizer(wx.VERTICAL)
            sizer_1.Add(self.textctrl, 1, wx.EXPAND, 0)
            self.SetSizer(sizer_1)
            self.Layout()
    
        def eval_last_line(self):
            nl = self.textctrl.GetNumberOfLines()
            ln =  self.textctrl.GetLineText(nl-1)
            ln = ln[len(self.prompt):]
            args = ln.split(" ")
    
            proc = subprocess.Popen(args, stdout=subprocess.PIPE)
            retvalue = proc.communicate()[0]
    
            c = wx.Colour(239, 177, 177)
            tc = wx.TextAttr(c)
            self.textctrl.SetDefaultStyle(tc)
            self.textctrl.AppendText(retvalue)
            self.textctrl.SetDefaultStyle(self.default_txt)
            self.textctrl.AppendText(self.prompt)
            self.textctrl.SetInsertionPoint(GetLastPosition() - 1)
    
    if __name__ == "__main__":
        app = wx.PySimpleApp(0)
        wx.InitAllImageHandlers()
        frame_1 = MyFrame(None, -1, "")
        app.SetTopWindow(frame_1)
        frame_1.Show()
        app.MainLoop()
    

    If really wanted, this could be worked upon.

    0 讨论(0)
提交回复
热议问题