Python - Добавить ловушку / обратный вызов для того, когда курсор перемещается при вводе raw_input?

Я пытаюсь написать версию интерактивного переводчика, который имеет подсветку синтаксиса.

Вот то, что у меня есть, которое работает достаточно хорошо (использует модули благословений и фрагментов)...

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('')

Он окрашивает линии по мере их ввода...

Подсветка синтаксиса в интерактивном режиме

Проблемы есть;

  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('')

Я искал PyOS_InputHook, который называется

  1. На каждое нажатие клавиши
  2. Каждые 0,1 секунды

Таким образом, это означает, что я могу отказаться от занятого потока наблюдения, и означает, что я не использую (почти) любой процессор.

Последняя проблема заключалась в том, что входной хук вызывается сразу после нажатия клавиши; до того, как ввод был прочитан из stdin и (для печатаемых символов) присоединен к строковому буферу. Результатом было то, что для раскраски самого последнего персонажа была задержка 0,1 секунды.

Я решил это немного хакерским способом, выполняя рисование в потоке с задержкой 0,001 секунды.

0 ответов

Другие вопросы по тегам