2011-12-19 89 views
6

我喜欢Python的TwistedCmd。我想一起使用它们。Python与Cmd模块的扭曲集成

我得到了一些工作,但到目前为止我还没有想出如何使tab完成工作,因为我没有看到如何在Twisted的LineReceiver中立即接收tab keypres事件(无需按Enter键)。

这里是到目前为止我的代码:

#!/usr/bin/env python 

from cmd import Cmd 
from twisted.internet import reactor 
from twisted.internet.stdio import StandardIO 
from twisted.protocols.basic import LineReceiver 

class CommandProcessor(Cmd): 
    def do_EOF(self, line): 
     return True 

class LineProcessor(LineReceiver): 
    from os import linesep as delimiter # makes newline work 

    def __init__(self): 
     self.processor = CommandProcessor() 
     self.setRawMode() 

    def connectionMade(self): 
     self.transport.write('>>> ') 

    def rawDataReceived(self, data): 
     self.processor.onecmd(data) 
     self.transport.write('>>> ') 

StandardIO(LineProcessor()) 
reactor.run() 

除了tab完成,这个有点工作。我可以输入一个像“help”这样的命令,Cmd模块将打印结果。但是我失去了Cmd模块的漂亮选项卡完整功能,因为Twisted每次缓冲一行。我试图设置LineProcessor.delimiter空字符串,无济于事。也许我需要找到其他一些Twisted来代替LineReceiver吗?或者也许有一种更简单的方法可以避免我必须逐一处理每个角色?

我不能单独使用Cmd,因为我想使它成为一个网络应用程序,其中一些命令将导致发送数据,并且从网络接收数据将异步发生(并显示给用户)。

因此,无论我们从上面的代码开始还是完全不同的东西,我想用Python构建一个友好的终端应用程序,以响应网络事件以及制表符完成。我希望我可以使用已经存在的内容,而不必自己实施太多。

+0

看一看[扭曲人孔(http://twistedmatrix.com/trac/wiki/TwistedConch),[示例](http://twistedmatrix.com/documents/current/conch /examples/demo_manhole.tac) – jfs 2011-12-19 23:56:33

+0

我注意到了沙井和海螺,但他们对我所做的事情没有什么意义。该文档将Conch描述为一个SSHv2实现,包括客户端和服务器,并说明如何创建一个为其客户端着色的SSH服务器。我的需求既相似又不同。如果您对我如何使用沙井有更具体的建议,我全都是耳朵......其中一个问题就是明显缺乏文档。 – 2011-12-20 02:22:41

回答

9

你有一对夫妇的困难,这种方法:

  • Cmd.onecmd是不会做任何标签的处理。
  • 即使确实如此,您的终端也需要处于Cbreak模式,以便将单个按键发送给Python解释器(tty.setcbreak可以解决这个问题)。
  • 如您所知,Cmd.cmdloop不感知反应堆,将阻止等待输入。
  • 然而,要获得所有你想要的酷行编辑,Cmd(实际上是readline)需要直接访问标准输入和标准输出。

考虑到所有这些困难,您可能需要考虑让CommandProcessor在其自己的线程中运行。例如:

#!/usr/bin/env python 

from cmd import Cmd 
from twisted.internet import reactor 

class CommandProcessor(Cmd): 
    def do_EOF(self, line): 
     return True 

    def do_YEP(self, line): 
     reactor.callFromThread(on_main_thread, "YEP") 

    def do_NOPE(self, line): 
     reactor.callFromThread(on_main_thread, "NOPE") 

def on_main_thread(item): 
    print "doing", item 

def heartbeat(): 
    print "heartbeat" 
    reactor.callLater(1.0, heartbeat) 

reactor.callLater(1.0, heartbeat) 
reactor.callInThread(CommandProcessor().cmdloop) 
reactor.run() 
+0

我想在Tab键按钮上自己调用Cmd模块中的完成方法。感谢您指出cbreak - 我不知道这一点。我会尝试你的方法,感谢你写出来。 – 2011-12-20 02:25:11

+0

不客气。基本上,readline是一个迷你curses应用程序。我想如果你尝试调解对标准输入/标准输出的访问,你最终必须重新实现其大部分功能。这种线程方式让它直接管理stdin/stdout(包括cbreak模式),这应该使事情变得简单。 – 2011-12-20 02:34:45

+0

twisted.internet.threads.blockingCallFromThread是一个非常有用的扭曲函数,它允许CommandProcessor获取返回值。 – 2014-07-01 14:59:17