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

时间:2015-09-12 08:18:01

标签: 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('')

在您键入行时会对行进行着色...

Syntax highlighting in interactive prompt

问题是;

  1. 这使用一个单独的线程来忙于检查行中的更改(认为这可能是使用整个核心)
  2. 如果您将光标向后移动一行,然后将其向右移动,则终端会重新绘制刚刚未选中的字符,并以白色显示
  3. 我真正想要的是当光标移动或行缓冲区改变时的回调/钩子 - 这些是否可能?我可以将stdin放入逐字节模式,然后以某种方式将字节传递给raw_input的内部缓冲版本,并触发回调吗?

    P.S目前它还没有处理多行字符串("""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('')
    

    我正在寻找的是PyOS_InputHook,它被称为

    1. 每次按键
    2. 每0.1秒
    3. 所以这意味着我可以放弃繁忙的监视线程并意味着我不会(几乎)使用任何CPU。

      最后一个问题是输入挂钩在按键时被称为立即;在从stdin读取输入之前和(对于可打印的字符)连接到行缓冲区。结果是,对最近的角色着色有0.1秒的延迟。

      我通过在0.001秒延迟的线程中进行绘图,以一种黑客的方式解决了这个问题。

0 个答案:

没有答案