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('')
Он окрашивает линии по мере их ввода...
Проблемы есть;
- При этом используется отдельный поток для проверки занятости на наличие изменений в строке (возможно, для этого используется целое ядро)
- Если вы переместите курсор назад через строку, а затем переместите его обратно вправо, терминал перерисовывает только что выбранный символ и делает это белым цветом.
Что мне действительно нужно, так это обратный вызов / ловушка для перемещения курсора или изменения буфера строки - возможны ли эти вещи? Могу ли я перевести 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, который называется
- На каждое нажатие клавиши
- Каждые 0,1 секунды
Таким образом, это означает, что я могу отказаться от занятого потока наблюдения, и означает, что я не использую (почти) любой процессор.
Последняя проблема заключалась в том, что входной хук вызывается сразу после нажатия клавиши; до того, как ввод был прочитан из stdin и (для печатаемых символов) присоединен к строковому буферу. Результатом было то, что для раскраски самого последнего персонажа была задержка 0,1 секунды.
Я решил это немного хакерским способом, выполняя рисование в потоке с задержкой 0,001 секунды.