Python-在输入raw_input时光标移动时添加钩子/回调?

Leo*_*son 5 python terminal syntax-highlighting readline raw-input

我正在尝试编写具有语法突出显示功能的交互式解释器的版本。

到目前为止,这是我工作得相当不错的内容(使用祝福pygments模块)...

import code
import readline
import threading
import blessings
from pygments import highlight
from pygments.formatters import TerminalFormatter
from pygments.lexers import PythonLexer

def check_line():
    global current_line
    try:
        while True:
            line = readline.get_line_buffer()
            if line != current_line:
                current_line = line
                do_colour()
    except:
        pass

def do_colour():
    global terminal

    raw_line = readline.get_line_buffer()
    line = highlight(raw_line, lexer, formatter)[:-1]

    with terminal.location(x = 4):
        print line,

    readline.redisplay()

current_line = ''
terminal = blessings.Terminal()
lexer = PythonLexer()
formatter = TerminalFormatter()
console = code.InteractiveConsole()

colour_thread = threading.Thread(target=check_line)
colour_thread.setDaemon(True)
colour_thread.start()

console.interact('')
Run Code Online (Sandbox Code Playgroud)

键入时确实会为线条着色...

交互式提示中的语法突出显示

问题是;

  1. 这使用一个单独的线程来忙于检查行中的更改(认为这可能是使用整个核心)
  2. 如果将光标向后移动一行,然后将其向右移动,终端将重新绘制刚刚未选中的字符,并以白色显示

我真正想要的是当光标移动或行缓冲区更改时的回调/钩子-这些可能吗?我可以将stdin置于逐字节模式下,然后以某种方式将字节传递给raw_input的内部缓冲版本,并触发回调吗?

PS它目前还不能处理多行字符串("""like this"""),但这并不是一个非常困难的解决方案。


编辑:

好的,我已经到了那里,这是最新的代码...

import code, ctypes, readline, blessings, signal, threading
from pygments import highlight
from pygments.formatters import TerminalFormatter
from pygments.lexers import PythonLexer

def slight_delay():
    threading.Timer(0.001, draw).start()
    return 0

def draw():  
    raw_line = readline.get_line_buffer()
    line = highlight(raw_line, lexer, formatter)[:-1]

    with lock:
        with terminal.location(x = 4):
            print line,
        readline.redisplay()

def keyboard_interrupt(c, frame):   # Ctrl-C throws in C code otherwise
    pass

callback = ctypes.PYFUNCTYPE(ctypes.c_int)(slight_delay)
hook_ptr = ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
hook_ptr.value = ctypes.cast(callback, ctypes.c_void_p).value
signal.signal(signal.SIGINT, keyboard_interrupt)

terminal = blessings.Terminal()
lexer = PythonLexer()
formatter = TerminalFormatter()
console = code.InteractiveConsole()
lock = threading.Lock()

console.interact('')
Run Code Online (Sandbox Code Playgroud)

我一直在寻找的东西是PyOS_InputHook被称为

  1. 每次按键
  2. 每0.1秒

因此,这意味着我可以放弃繁忙的监视线程,并且意味着(几乎)不使用任何CPU。

最终的问题是,在按下按键时会立即调用输入挂钩。从stdin读取输入之前(对于可打印字符),将其附加到行缓冲区。结果是对最新字符的着色延迟了0.1秒。

我通过在0.001秒的延迟下在线程中绘制来解决问题。