6

Python のTwistedCmdが好きです。合わせて使いたいです。

いくつかのことが機能しましたが、Twisted の LineReceiver で (Enter を押さずに) タブの keypres イベントをすぐに受け取る方法がわからないため、これまでのところ、タブ補完を機能させる方法がわかりませんでした。

これまでの私のコードは次のとおりです。

#!/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()

タブ補完とは別に、これはある程度機能します。「help」などのコマンドを入力すると、Cmd モジュールが結果を出力します。しかし、Twisted は一度に 1 行ずつバッファリングするため、Cmd モジュールの気の利いたタブ補完機能を失いました。LineProcessor.delimiter空の文字列に設定しようとしましたが、役に立ちませんでした。たぶん、LineReceiver の代わりに使用する Twisted の他の部分を見つける必要がありますか? または、すべての文字を 1 つずつ処理する必要がないようにする、より単純なアプローチがあるのでしょうか。

これをネットワーク アプリケーションにしたいので、Cmd だけを使用することはできません。一部のコマンドはデータを送信し、ネットワークからのデータの受信は非同期で行われます (ユーザーに表示されます)。

上記のコードから始めるか、まったく別のコードから始めるかに関係なく、ネットワーク イベントとタブ補完に応答する、素晴らしく使いやすいターミナル アプリケーションを Python で作成したいと思います。すでにあるものを使用でき、自分で実装しすぎる必要がないことを願っています。

4

1 に答える 1

9

このアプローチにはいくつかの問題があります。

  • Cmd.onecmdタブ処理は行いません。
  • たとえそうであったとしても、個々のキーストロークが Python インタープリターに届くようにするには、端末を cbreak モードにする必要があります (それをtty.setcbreak処理できます)。
  • ご存じのとおり、Cmd.cmdloopはリアクターに対応しておらず、入力待ちをブロックします。
  • それでも、必要なすべてのクールな行編集を取得するには、Cmd (実際には readline) が stdin と stdout に直接アクセスできる必要があります。

これらすべての問題を考慮すると、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()
于 2011-12-20T02:13:16.773 に答える