How can I make it so that when I change a tagged word in tkinter, the color changes back?

Issue

I am making a text editor, and I am using Pygments to help with syntax highlighting. When I type a keyword, say for, it changes yellow, good. Well, when I either, type a letter after, say fore, for is still yellow, OR if I backspace, fo or f is yellow.

Why doesn’t it change back to black/clear the color? Is there an efficient way to do this? My code, just incase needed, is as follows, there is no bug, so I am going to just include the highlighting function, even though that itself is probably unneeded.

I’ll include more if needed

import sys #imports
from pygments import highlight
from pygments.lexers import PythonLexer #python syntax highlighter
from pygments import lex
major_version = sys.version_info.major
if major_version == 2: #check python version for importing tkinter
    from Tkinter import *
    import tkFileDialog
elif major_version == 3:
    from tkinter import *
    import tkinter.filedialog as tkFileDialog
else:
    raise RuntimeError('Unexpected python major version: %d' % major_version)

def highlight(t, previousContent):
    content = t.get("1.0", END)
    lines = content.split("\n")

    if(content != previousContent):
        t.mark_set("range_start", "1.0")
        data = t.get("1.0", "end-1c")

        for token, content in lex(data, PythonLexer()):
            t.mark_set("range_end", "range_start + %dc" % len(content))
            t.tag_add(str(token), "range_start", "range_end")

            t.mark_set("range_start", "range_end")

def highlightLine(t, previousContent):
    content = t.get("1.0", END)
    lines = content.split("\n")
    currentCursorPosition = t.index(INSERT)
    currentCursorPositionSplit = currentCursorPosition.split(".")
    currentLine = currentCursorPositionSplit[0]
    currentColumn = currentCursorPositionSplit[1]

    if(content != previousContent):
        t.mark_set("range_start", str(currentLine) + ".0")
        data = t.get(str(currentLine) + ".0", str(currentLine) + "." + str(currentColumn))

        for token, content in lex(data, PythonLexer()):
            t.mark_set("range_end", "range_start + %dc" % len(content))
            t.tag_add(str(token), "range_start", "range_end")

            t.mark_set("range_start", "range_end")

def initHighlight(t):
    t.tag_configure("Token.Keyword", foreground="#CC7A00")
    t.tag_configure("Token.Keyword.Constant", foreground="#CC7A00")
    t.tag_configure("Token.Keyword.Declaration", foreground="#CC7A00")
    t.tag_configure("Token.Keyword.Namespace", foreground="#CC7A00")
    t.tag_configure("Token.Keyword.Pseudo", foreground="#CC7A00")
    t.tag_configure("Token.Keyword.Reserved", foreground="#CC7A00")
    t.tag_configure("Token.Keyword.Type", foreground="#CC7A00")

    t.tag_configure("Token.Name.Class", foreground="#003D99")
    t.tag_configure("Token.Name.Exception", foreground="#003D99")
    t.tag_configure("Token.Name.Function", foreground="#003D99")

    t.tag_configure("Token.Operator.Word", foreground="#CC7A00")

    t.tag_configure("Token.Comment", foreground="#B80000")

    t.tag_configure("Token.Literal.String", foreground="#248F24")

This question is NOT asking how to remove all tags from the text, it’s asking how do I check if a word that was tagged isn’t the desirable word anymore, then get rid of the tag on that word. If I were to remove all tags then retag everything, it would be way too laggy.

Solution

Before tagging, in the same function, I added

for tag in t.tag_names():
    t.tag_remove(tag, str(currentLine) + ".0", str(currentLine) + "." + str(currentColumn))

It checks all tags, then remove tags in the current line, then, afterwards, it will add them back, the full function goes as follows:

def highlightLine(t, previousContent):
    content = t.get("1.0", END)
    lines = content.split("\n")
    currentCursorPosition = t.index(INSERT)
    currentCursorPositionSplit = currentCursorPosition.split(".")
    currentLine = currentCursorPositionSplit[0]
    currentColumn = currentCursorPositionSplit[1]

    if(content != previousContent):
        t.mark_set("range_start", str(currentLine) + ".0")
        data = t.get(str(currentLine) + ".0", str(currentLine) + "." + str(currentColumn))

        for tag in t.tag_names():
            t.tag_remove(tag, str(currentLine) + ".0", str(currentLine) + "." + str(currentColumn))

        for token, content in lex(data, PythonLexer()):
            t.mark_set("range_end", "range_start + %dc" % len(content))
            t.tag_add(str(token), "range_start", "range_end")

            t.mark_set("range_start", "range_end")

Works perfectly now!

Answered By – Hunter Kepley

Answer Checked By – Terry (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.