From 5c4d87ea6efde132c126ccd6b287571a96c99a31 Mon Sep 17 00:00:00 2001 From: billy Date: Mon, 16 Oct 2023 17:22:49 +0800 Subject: [PATCH] feat: Change language mode from statusbar --- .../editors/texteditor/highlighter.py | 54 ++++++++++++++----- .../components/floating/palette/__init__.py | 1 + biscuit/core/layout/statusbar/__init__.py | 26 +++++---- biscuit/core/layout/statusbar/utils/button.py | 3 ++ 4 files changed, 62 insertions(+), 22 deletions(-) diff --git a/biscuit/core/components/editors/texteditor/highlighter.py b/biscuit/core/components/editors/texteditor/highlighter.py index e1ca0f84..43c78734 100644 --- a/biscuit/core/components/editors/texteditor/highlighter.py +++ b/biscuit/core/components/editors/texteditor/highlighter.py @@ -1,17 +1,32 @@ +from __future__ import annotations + import os +import threading import tkinter as tk +import typing from pygments import lex from pygments.lexers import get_lexer_by_name, get_lexer_for_filename +if typing.TYPE_CHECKING: + from .text import Text class Highlighter: - def __init__(self, master, language=None, *args, **kwargs) -> None: - self.master = master - self.base = master.base + def __init__(self, text: Text, language: str=None, *args, **kwargs) -> None: + """Highlighter based on pygments lexers + If language is not given, it will try to detect the language from the file extension. + If the file extension is not recognized, it will default to plain text. + + Attributes + ---------- + text : Text + Text widget to highlight + language : str, optional + Language to highlight, by default None + """ - self.text = master - self.base = master.base + self.text: Text = text + self.base = text.base self.language = language if language: @@ -25,10 +40,10 @@ def __init__(self, master, language=None, *args, **kwargs) -> None: return else: try: - if os.path.basename(master.path).endswith("txt"): + if os.path.basename(text.path).endswith("txt"): raise Exception() - self.lexer = get_lexer_for_filename(os.path.basename(master.path), encoding=master.encoding) + self.lexer = get_lexer_for_filename(os.path.basename(text.path), encoding=text.encoding) self.text.language = self.lexer.name except: self.lexer = None @@ -39,7 +54,16 @@ def __init__(self, master, language=None, *args, **kwargs) -> None: self.tag_colors = self.base.theme.syntax self.setup_highlight_tags() - def change_language(self, language): + def change_language(self, language: str) -> None: + """Change the language of the highlighter + If language is not given, it will try to detect the language from the file extension. + If the file extension is not recognized, it will default to plain text. + + Parameters + ---------- + language : str + Language to highlight + """ if language: try: self.lexer = get_lexer_by_name(language) @@ -51,22 +75,26 @@ def change_language(self, language): return else: try: - if os.path.basename(self.master.path).endswith("txt"): + if os.path.basename(self.text.path).endswith("txt"): raise Exception() - self.lexer = get_lexer_for_filename(os.path.basename(self.master.path), encoding=self.master.encoding) + self.lexer = get_lexer_for_filename(os.path.basename(self.text.path), encoding=self.text.encoding) self.text.language = self.lexer.name except: self.lexer = None self.text.language = "Plain Text" self.base.notifications.info("No lexers are available for opened file type.") return - - def setup_highlight_tags(self): + + threading.Thread(target=self.text.refresh, daemon=True).start() + + def setup_highlight_tags(self) -> None: + "Setup the tags for highlighting" for token, color in self.tag_colors.items(): self.text.tag_configure(str(token), foreground=color) - def highlight(self): + def highlight(self) -> None: + "Highlights the text content of attached Editor instance" if not self.lexer: return diff --git a/biscuit/core/components/floating/palette/__init__.py b/biscuit/core/components/floating/palette/__init__.py index 489d7380..64d43637 100644 --- a/biscuit/core/components/floating/palette/__init__.py +++ b/biscuit/core/components/floating/palette/__init__.py @@ -57,6 +57,7 @@ def __init__(self, master, items=None, width=60, *args, **kwargs) -> None: self.configure_bindings() def register_actionset(self, actionset: ActionSet) -> None: + "Expects a lambda returning the actionset instead of the actionset itself" self.actionsets.append(actionset) def generate_help_actionset(self) -> None: diff --git a/biscuit/core/layout/statusbar/__init__.py b/biscuit/core/layout/statusbar/__init__.py index a2118002..d29b309d 100644 --- a/biscuit/core/layout/statusbar/__init__.py +++ b/biscuit/core/layout/statusbar/__init__.py @@ -13,6 +13,8 @@ import tkinter as tk import typing +from pygments.lexers._mapping import LEXERS + from biscuit.core.components import ActionSet from biscuit.core.components.utils import Frame @@ -28,7 +30,13 @@ class Statusbar(Frame): """ Status bar holds various widgets that are used to display information about the current file and the current state of the editor. + + Attributes + ---------- + base : Root + Root window """ + def __init__(self, master: Root, *args, **kwargs) -> None: super().__init__(master, *args, **kwargs) self.config(bg=self.base.theme.layout.statusbar.background) @@ -84,21 +92,21 @@ def __init__(self, master: Root, *args, **kwargs) -> None: self.eol = SButton(self, text="CRLF", function=lambda: self.base.palette.show_prompt('eol:'), description="Select End of Line sequence") self.eol.set_pack_data(side=tk.RIGHT) - # TODO use pygments to list out? - self.filetype_actionset = ActionSet( - "FILETYPE", "syntax:", - [("Plain Text", lambda e=None: print("filetype Plain Text", e)), - ("python", lambda e=None: print("filetype python", e)), - ("c++", lambda e=None: print("filetype c++", e))], + # language mode + items = [(aliases[0], lambda _, lang=aliases[0]: self.base.editorsmanager.active_editor.content.text.highlighter.change_language(lang)) for _, _, aliases, _, _ in LEXERS.values() if aliases] + self.language_actionset = ActionSet( + "Change Language Mode", "language:", items ) - self.base.palette.register_actionset(lambda: self.filetype_actionset) - self.file_type = SButton(self, text="Plain Text", function=lambda: self.base.palette.show_prompt('syntax:'), description="Select Language Mode") + self.base.palette.register_actionset(lambda: self.language_actionset) + self.file_type = SButton(self, text="Plain Text", function=lambda: self.base.palette.show_prompt('language:'), description="Select Language Mode") self.file_type.set_pack_data(side=tk.RIGHT) + # show/hide notifications self.notif = SButton(self, icon="bell", function=self.base.notifications.show, description="No notifications") self.notif.pack(side=tk.RIGHT, padx=(0, 10)) - self.filetype_actionset = ActionSet( + # clock + self.time_actionset = ActionSet( "Configure clock format", "time:", [("12 hours", lambda e=None: print("time 12 hours", e)), ("24 hours", lambda e=None: print("time 24 hours", e)),], diff --git a/biscuit/core/layout/statusbar/utils/button.py b/biscuit/core/layout/statusbar/utils/button.py index 5f463dc3..3ec5dc3c 100644 --- a/biscuit/core/layout/statusbar/utils/button.py +++ b/biscuit/core/layout/statusbar/utils/button.py @@ -78,6 +78,9 @@ def change_description(self, text: str) -> None: def change_icon(self, icon: str) -> None: self.icon_label.config(text=get_codicon(icon)) + + def change_function(self, function: typing.Callable) -> None: + self.function = function def set_pack_data(self, **kwargs) -> None: self.pack_data = kwargs