2011-12-19 112 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