Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emojis and some weird chars are broken #5

Closed
rdbende opened this issue Apr 7, 2023 · 4 comments · May be fixed by #35
Closed

Emojis and some weird chars are broken #5

rdbende opened this issue Apr 7, 2023 · 4 comments · May be fixed by #35
Assignees
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@rdbende
Copy link
Owner

rdbende commented Apr 7, 2023

@Moosems:

It works in normal Text pretty well (although with its own issues)but doesn't in chlorophyll

@rdbende:

Can you provide an example?
In general, Tkinter (Tk) doesn't support most emojis (any character that's beyond U+FFFF, to be precise), so I'm wondering what is what works with the normal text widget but not with Chlorophyll

@Moosems:

Tkinter recently made them not break widgets so example chars are:

😀 😃 😄 😁 😆 😅 😂 🤣 😊 😇 🙂 🙃 😉 😌

Instructions: Paste and then press backspace

@rdbende:

simplescreenrecorder-2022-08-01_21.49.24.mp4

@Moosems:

Very odd... honestly I wish tkinter could support it cause some people use emojis in code and if it doesn't work I'm sure I'm gonna hear about it a lot later on

@rdbende It happens in mantaray too though so it seems less like a pygments thing

Happens in Porcupine too, probably due to some Pygments coloring tag that confuses Tk

@Moosems
Copy link
Collaborator

Moosems commented Apr 7, 2023

When this is done on a normal Text widget it works fine so there's definitely something going on, I'll have to look into this more and make an MRE.

@Moosems Moosems added bug Something isn't working question Further information is requested labels Apr 10, 2023
@Moosems Moosems self-assigned this Apr 11, 2023
@Moosems
Copy link
Collaborator

Moosems commented Apr 11, 2023

Here's what we know: The issue appears in both Chlorophyll and Mantaray however the issues are different. In Mantaray, deleting the emojis crashes the window, in Chlorophyll, it simply makes the chars act really weird. That means that we can not cross-compare them. However, when I started working on making an MRE I first deleted all the highlighting code believing it was not the cause of the issue but found that it did, in fact, alleviate the issue, That means that this is either a misuse of pygments or an issue in pygments. (Using pygments version 2.15.0 and fresh install of Chlorophyll (not from any PR's))

Code without pygments that works fine:

from __future__ import annotations

from chlorophyll import CodeView
from tkinter import Tk, Text, Misc, TclError, BaseWidget, Frame, Event, Scrollbar
from contextlib import suppress
from tkinter.font import Font
from typing import Any
from pyperclip import copy

root = Tk()
cv = CodeView(root)
cv.pack()


class SpecialText(Text):
    _w: str

    def __init__(
        self,
        master: Misc | None = None,
        tab_width: int = 4,
        **kwargs,
    ) -> None:
        self._frame = Frame(master)
        self._frame.grid_rowconfigure(0, weight=1)
        self._frame.grid_columnconfigure(0, weight=1)

        kwargs.setdefault("wrap", "none")
        kwargs.setdefault("font", ("monospace", 11))

        super().__init__(self._frame, **kwargs)
        super().grid(row=0, column=1, sticky="nswe")

        self._hs = Scrollbar(self._frame, orient="horizontal", command=self.xview)
        self._vs = Scrollbar(self._frame, orient="vertical", command=self.yview)

        self._hs.grid(row=1, column=1, sticky="we")
        self._vs.grid(row=0, column=2, sticky="ns")

        super().configure(
            xscrollcommand=self._hs.set,
            yscrollcommand=self._vs.set,
            tabs=Font(font=kwargs["font"]).measure(" " * tab_width)
        )

        contmand = "Command" if self._windowingsystem == "aqua" else "Control"

        super().bind(f"<{contmand}-c>", self._copy, add=True)
        super().bind(f"<{contmand}-v>", self._paste, add=True)
        super().bind(f"<{contmand}-a>", self._select_all, add=True)
        super().bind(f"<{contmand}-Shift-Z>", self.redo, add=True)

        self._orig = f"{self._w}_widget"
        self.tk.call("rename", self._w, self._orig)
        self.tk.createcommand(self._w, self._cmd_proxy)


    def _select_all(self, *_) -> str:
        self.tag_add("sel", "1.0", "end")
        self.mark_set("insert", "end")
        return "break"

    def redo(self, event: Event | None = None) -> None:
        try:
            self.edit_redo()
        except TclError:
            pass

    def _paste(self, *_):
        insert = self.index(f"@0,0 + {self.cget('height') // 2} lines")

        with suppress(TclError):
            self.delete("sel.first", "sel.last")
            self.tag_remove("sel", "1.0", "end")
            self.insert("insert", self.clipboard_get())

        self.see(insert)

        return "break"

    def _copy(self, *_):
        text = self.get("sel.first", "sel.last")
        if not text:
            text = self.get("insert linestart", "insert lineend")

        copy(text)

        return "break"

    def _cmd_proxy(self, command: str, *args) -> Any:
        cmd = (self._orig, command) + args
        try:
            result = self.tk.call(cmd)
        except TclError as e:
            error = str(e)
            if 'tagged with "sel"' in error or "nothing to" in error:
                return ""
            raise e from None

        if command in {"insert", "replace", "delete"}:
            self.event_generate("<<ContentChanged>>")

        return result

    def __setitem__(self, key: str, value) -> None:
        self.configure(**{key: value})

    def __getitem__(self, key: str) -> Any:
        return self.cget(key)

    def configure(self, **kwargs) -> None:
        lexer = kwargs.pop("lexer", None)
        color_scheme = kwargs.pop("color_scheme", None)

        if lexer is not None:
            self._set_lexer(lexer)

        if color_scheme is not None:
            self._set_color_scheme(color_scheme)

        super().configure(**kwargs)

    config = configure

    def pack(self, *args, **kwargs) -> None:
        self._frame.pack(*args, **kwargs)

    def grid(self, *args, **kwargs) -> None:
        self._frame.grid(*args, **kwargs)

    def place(self, *args, **kwargs) -> None:
        self._frame.place(*args, **kwargs)

    def pack_forget(self) -> None:
        self._frame.pack_forget()

    def grid_forget(self) -> None:
        self._frame.grid_forget()

    def place_forget(self) -> None:
        self._frame.place_forget()

    def destroy(self) -> None:
        for widget in self._frame.winfo_children():
            BaseWidget.destroy(widget)
        BaseWidget.destroy(self._frame)

tt = SpecialText(root)
tt.pack()
root.mainloop()

@Moosems Moosems added help wanted Extra attention is needed and removed question Further information is requested labels Apr 11, 2023
@Moosems
Copy link
Collaborator

Moosems commented May 1, 2023

@rdbende we could check that chard getting tags don't include emojis and if they do include them we can remove the areas with them.

@Moosems
Copy link
Collaborator

Moosems commented Jul 11, 2023

If the char is an emoji don't highlight.

@Moosems Moosems closed this as not planned Won't fix, can't repro, duplicate, stale Jul 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants