Tkinter/Pygments: странные результаты при подсветке

Я стараюсь выделять тексты по токенам. Токены могут быть выделены приведенными ниже кодами, но есть некоторые нежелательные результаты. Некоторые примеры:

Предположим, я набрал:

a = "a"

Обе буквы выделены одним цветом, несмотря на то, что первая буква «а» — это Token.Name, а вторая — Token.Literal.String.Double.

Другой нежелательный случай: когда я набрал «если», слово выделяется, и если я продолжу добавлять несколько букв к слову «если», цвет слова изменится, как и ожидалось. Однако, когда я удаляю некоторые буквы этого слова, пока слово снова не станет «если», это слово не выделяется, как раньше.

Можете ли вы помочь мне понять эту проблему здесь?

Коды:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from pygments import lex
from pygments.token import Token
from pygments.lexers import Python3Lexer
try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk

ROOT = tk.Tk()
TEXT = tk.Text(master=ROOT, fg="white", bg="black", font="TkDefaultFont 10")
TEXT.pack(fill="both", expand=True)


def tag(event):

    def colorize(word, color):
        index = []
        index1 = TEXT.search(word, "1.0", "end")
        while index1:
            index2 = ".".join([index1.split(".")[0], str(int(index1.split(".")[1]) + len(word))])
            index.append((index1, index2))
            index1 = TEXT.search(word, index2, "end")
        for i, j in index:
            TEXT.tag_add(word, i, j)
            TEXT.tag_configure(word, foreground=color)

    for token, content in lex(TEXT.get("1.0", "end"), Python3Lexer()):
        if token == Token.Literal.Number.Integer:
            colorize(content, color="purple")
        elif token == Token.Keyword:
            colorize(content, color="orange")
        elif token == Token.Operator.Word:
            colorize(content, color="red")
        elif token == Token.Name.Builtin:
            colorize(content, color="blue")
        elif token == Token.Comment.Hashbang or token == Token.Comment.Single:
            colorize(content, color="grey")
        elif token == Token.Keyword.Namespace:
            colorize(content, color="yellow")
        elif token == Token.Namespace:
            colorize(content, color="green")
        elif token == Token.Punctuation:
            colorize(content, color="brown")
        elif token == Token.Literal.String.Double:
            colorize(content, color="cyan")
        elif token == Token.Name:
            colorize(content, color="white")


TEXT.bind("<KeyRelease>", tag)
ROOT.mainloop()

`


person dildeolupbiten    schedule 10.06.2018    source источник
comment
Что вы сделали, чтобы отладить это? Например, распечатали ли вы значения переменных во время выполнения цикла, чтобы убедиться, что они такие, какими, по вашему мнению, должны быть?   -  person Bryan Oakley    schedule 11.06.2018
comment
Я помещаю оператор печати в цикл for, который печатает содержимое и токен.   -  person dildeolupbiten    schedule 11.06.2018
comment
Итак, вы утверждаете, что весь контент и токены верны, а индексы верны, но раскрашиваете не то?   -  person Bryan Oakley    schedule 11.06.2018
comment
Я просто хочу сказать, что как только слово было распознано как токен, это слово выделяется в другом слове. Например, если программа может распознать "a" как Token.Literal.String.Double, то эти символы будут выделены. Но не только этот строковый литерал, но и все символы a в текстовом виджете. Здесь вы можете увидеть на скриншотах. forum.yazbel.com/uploads/default/original/1X/ forum.yazbel.com/uploads/default/original/1X/   -  person dildeolupbiten    schedule 11.06.2018
comment
Так что я предполагаю, что есть проблема в разборе.   -  person dildeolupbiten    schedule 11.06.2018


Ответы (1)


Проблема была решена с помощью приведенных ниже кодов.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
if sys.version_info.major == 2:
    exit()
elif sys.version_info.major == 3:
    import builtins as builtins
    import tkinter as tk
import io
import tokenize
import keyword


root = tk.Tk()
text = tk.Text(master=root, fg="white", bg="black", font="TkDefaultFont 10")
text.pack(fill="both", expand=True)

count = 0


def colorize(*args):
    global count
    row1, col1 = args[0].startz
    row1, col1 = str(row1), str(col1)
    row2, col2 = args[0].end
    row2, col2 = str(row2), str(col2)
    start = ".".join((row1, col1))
    end = ".".join((row2, col2))
    text.tag_add(str(count), start, end)
    try:
        text.tag_config(str(count), foreground=args[1], font=args[2])
    except IndexError:
        text.tag_config(str(count), foreground=args[1])
    count += 1


def search(event):
    try:
        for i in tokenize.tokenize(io.BytesIO(text.get("1.0", "end").encode("utf-8")).readline):
            if i.type == 1:
                if i.string in keyword.kwlist:
                    colorize(i, "orange")
                elif i.string in dir(builtins):
                    colorize(i, "blue")
                else:
                    colorize(i, "white")
            elif i.type == 2:
                colorize(i, "cyan")
            elif i.type == 3:
                colorize(i, "purple")
            elif i.type == 53:
                if i.string == "," or i.string == "." or i.string == ":":
                    colorize(i, "orange")
                elif i.string == "(" or i.string == ")" or i.string == "[" \
                        or i.string == "]" or i.string == "{" or i.string == "}":
                    colorize(i, "darkred")
                else:
                    colorize(i, "green")
            elif i.type == 57:
                colorize(i, "grey", "TkDefaultFont 10 italic")
    except tokenize.TokenError:
        pass


text.bind("<KeyRelease>", search)
root.mainloop()
person dildeolupbiten    schedule 12.06.2018