class AssistantConfigPage(ConfigurationPage): def __init__(self, master): super().__init__(master) ui_utils.create_url_label( self, "https://github.com/thonny/thonny/wiki/Friendly-traceback", text=_("Friendly traceback level"), ).grid(row=1, column=0, sticky="w") self.add_combobox( "assistance.friendly_traceback_level", values=[0, 1, 2, 3, 4, 5, 6, 7, 9], row=1, column=1, width=3, padx=5, ) self.add_checkbox( "assistance.open_assistant_on_errors", _("Open Assistant automatically when program crashes with an exception" ), row=2, columnspan=2, ) self.add_checkbox( "assistance.open_assistant_on_warnings", _("Open Assistant automatically when it has warnings for your code" ), row=3, columnspan=2, ) if get_workbench().get_option("assistance.use_pylint", "missing") != "missing": self.add_checkbox("assistance.use_pylint", _("Perform selected Pylint checks"), row=4, columnspan=2) if get_workbench().get_option("assistance.use_mypy", "missing") != "missing": self.add_checkbox("assistance.use_mypy", _("Perform MyPy checks"), row=5, columnspan=2) disabled_checks_label = ttk.Label( self, text=_("Disabled checks (one id per line)")) disabled_checks_label.grid(row=8, sticky="nw", pady=(10, 0), columnspan=2) self.disabled_checks_box = TextFrame( self, vertical_scrollbar_style=scrollbar_style("Vertical"), horizontal_scrollbar_style=scrollbar_style("Horizontal"), horizontal_scrollbar_class=ui_utils.AutoScrollbar, wrap="word", font="TkDefaultFont", # cursor="arrow", padx=5, pady=5, height=4, borderwidth=1, relief="groove", ) self.disabled_checks_box.grid(row=9, sticky="nsew", pady=(0, 10), columnspan=2) self.disabled_checks_box.text.insert( "1.0", "\n".join( get_workbench().get_option("assistance.disabled_checks"))) self.columnconfigure(1, weight=1) self.rowconfigure(9, weight=1) def apply(self): disabled_checks_str = (self.disabled_checks_box.text.get( "1.0", "end").replace("\r", "").replace('"', "").replace("'", "").strip()) get_workbench().set_option("assistance.disabled_checks", disabled_checks_str.splitlines())
class AssistantConfigPage(ConfigurationPage): def __init__(self, master): super().__init__(master) self.add_checkbox( "assistance.open_assistant_on_errors", "Open Assistant automatically when program crashes with an exception", row=1, ) self.add_checkbox( "assistance.open_assistant_on_warnings", "Open Assistant automatically when it has warnings for your code", row=2, ) if get_workbench().get_option("assistance.use_pylint", "missing") != "missing": self.add_checkbox( "assistance.use_pylint", "Perform selected Pylint checks", row=3, ) if get_workbench().get_option("assistance.use_mypy", "missing") != "missing": self.add_checkbox( "assistance.use_mypy", "Perform MyPy checks", row=4, ) disabled_checks_label = ttk.Label( self, text="Disabled checks (one id per line)") disabled_checks_label.grid(row=8, sticky="nw", pady=(10, 0)) self.disabled_checks_box = TextFrame( self, vertical_scrollbar_style=scrollbar_style("Vertical"), horizontal_scrollbar_style=scrollbar_style("Horizontal"), horizontal_scrollbar_class=ui_utils.AutoScrollbar, wrap="word", font="TkDefaultFont", # cursor="arrow", padx=5, pady=5, height=4, borderwidth=1, relief="groove", ) self.disabled_checks_box.grid(row=9, sticky="nsew", pady=(0, 10)) self.disabled_checks_box.text.insert( "1.0", "\n".join( get_workbench().get_option("assistance.disabled_checks"))) self.columnconfigure(0, weight=1) self.rowconfigure(9, weight=1) def apply(self): disabled_checks_str = (self.disabled_checks_box.text.get( "1.0", "end").replace("\r", "").replace('"', "").replace("'", "").strip()) get_workbench().set_option("assistance.disabled_checks", disabled_checks_str.splitlines())
import tkinter as tk from thonny.tktextext import TextFrame, TweakableText root = tk.Tk() frame = TextFrame(root, read_only=False, wrap=tk.NONE, line_numbers=True, line_length_margin=13, text_class=TweakableText) frame.grid() text = frame.text text.direct_insert("1.0", "Essa\n 'tessa\nkossa\nx=34+(45*89*(a+45)") text.tag_configure('string', background='yellow') text.tag_add("string", "2.0", "3.0") text.tag_configure('paren', underline=True) text.tag_add("paren", "4.6", "5.0") root.mainloop()
class SqueezedTextDialog(tk.Toplevel): def __init__(self, master, button): super().__init__(master) self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) self.button = button self.content = button.contained_text self.shell_text = master padding = 20 mainframe = ttk.Frame(self) mainframe.grid(row=0, column=0, sticky="nsew") mainframe.columnconfigure(0, weight=1) mainframe.rowconfigure(2, weight=1) explanation_label = ttk.Label( mainframe, text="For performance reasons, Shell avoids showing " + "very long lines in full (see Tools => Options => Shell).\n" + "Here you can interact with the original text fragment.") explanation_label.grid(row=0, column=0, sticky="nsew", padx=padding, pady=padding) self._wrap_var = tk.BooleanVar(False) self.wrap_checkbox = ttk.Checkbutton(mainframe, text="Wrap text (may be slow)", variable=self._wrap_var, onvalue=True, offvalue=False, command=self._on_wrap_changed) self.wrap_checkbox.grid(row=1, padx=padding, pady=(0, padding // 2), sticky="w") self.text_frame = TextFrame(mainframe, text_class=TweakableText, height=10, width=80, relief="sunken", borderwidth=1, wrap="none") self.text_frame.grid(row=2, column=0, padx=padding) self.text_frame.text.insert("1.0", button.contained_text) self.text_frame.text.set_read_only(True) button_frame = ttk.Frame(mainframe) button_frame.grid(row=3, column=0, padx=padding, pady=padding, sticky="nswe") button_frame.columnconfigure(2, weight=1) copy_caption = "Copy to clipboard" copy_button = ttk.Button(button_frame, text=copy_caption, width=len(copy_caption), command=self._on_copy) copy_button.grid(row=0, column=1, sticky="w", padx=(0, padding)) expand_caption = "Expand in Shell" expand_button = ttk.Button(button_frame, text=expand_caption, width=len(expand_caption), command=self._on_expand) expand_button.grid(row=0, column=2, sticky="e", padx=padding) close_button = ttk.Button(button_frame, text="Close", command=self._on_close) close_button.grid(row=0, column=3, sticky="e") self.bind("<Escape>", self._on_close, True) self.protocol("WM_DELETE_WINDOW", self._on_close) self.title("Squeezed text (%d characters)" % len(self.content)) def _on_wrap_changed(self): if self._wrap_var.get(): self.text_frame.text.configure(wrap="word") else: self.text_frame.text.configure(wrap="none") def _on_expand(self): index = self.shell_text.index(self.button) self.shell_text.direct_delete(index, index + " +1 chars") self.shell_text.direct_insert(index, self.content, tuple(self.button.tags)) self.destroy() # looks like the widgets are not fully GC-d. # At least avoid leaking big chunks of texts self.button.contained_text = None self.button.destroy() def _on_copy(self): self.clipboard_clear() self.clipboard_append(self.content) def _on_close(self, event=None): self.destroy()
class DocuBoxBase(EditorInfoBox): def __init__(self, show_vertical_scrollbar: bool): super().__init__() self.text_frame = TextFrame( master=self, horizontal_scrollbar=False, vertical_scrollbar=show_vertical_scrollbar, read_only=True, height=7, width=40, font="TkDefaultFont", wrap="word", ) self.text_frame.grid() self.text = self.text_frame.text self._update_theme() def _update_theme(self, event=None): super()._update_theme(event) comment_opts = get_syntax_options_for_tag("comment") gutter_opts = get_syntax_options_for_tag("GUTTER") text_opts = get_syntax_options_for_tag("TEXT") self.text["background"] = gutter_opts["background"] self.text["foreground"] = text_opts["foreground"] self.text.tag_configure("prose", font="TkDefaultFont") self.text.tag_configure("active", font="BoldTkDefaultFont") self.text.tag_configure("annotation", **comment_opts) self.text.tag_configure("default", **comment_opts) self.text.tag_configure("marker", **comment_opts) def _append_chars(self, chars, tags=()): self.text.direct_insert("end", chars, tags=tuple(tags)) def render_signatures(self, signatures: List[SignatureInfo], only_params=False) -> None: for i, sig in enumerate(signatures): if i > 0: self._append_chars("\n") self.render_signature(sig, only_params) def render_signature(self, sig: SignatureInfo, only_params) -> None: if not only_params: self._append_chars(sig.name) self._append_chars("(") is_positional = False is_kw_only = False for i, param in enumerate(sig.params): if i > 0: self._append_chars(", ") if len(sig.params) > 20: self._append_chars("\n ") is_positional |= param.kind == "POSITIONAL_ONLY" if is_positional and param.kind != "POSITIONAL_ONLY": self._append_chars("/, ", ["marker"]) is_positional = False if param.kind == "VAR_POSITIONAL": is_kw_only = True elif param.kind == "KEYWORD_ONLY" and not is_kw_only: self._append_chars("*, ", ["marker"]) is_kw_only = True is_active_parameter = sig.current_param_index == i self.render_parameter(param, is_active_parameter) if is_positional: self._append_chars(", /", ["marker"]) self._append_chars(")") if sig.return_type and not only_params: self._append_chars(" -> ", ["marker"]) self._append_chars(sig.return_type, ["annotation"]) def render_parameter(self, param: SignatureParameter, active: bool) -> None: if active: base_tags = ["active"] else: base_tags = [] if param.kind == "VAR_POSITIONAL": self._append_chars("*", base_tags) elif param.kind == "VAR_KEYWORD": self._append_chars("**", base_tags) self._append_chars(param.name, base_tags) if param.annotation: self._append_chars(":\u00A0" + param.annotation, base_tags + ["annotation"]) if param.default: self._append_chars("=" + param.default, base_tags + ["default"]) def format_signature(self, s: str) -> str: s = s.replace(": ", ":\u00A0") if len(s) > self.text["width"] * 1.8 and s.count("(") and s.count(")"): args_index = s.index("(") + 1 suffix_index = s.rindex(")") prefix = s[:args_index] args = s[args_index:suffix_index].split(", ") suffix = s[suffix_index:] s = prefix + "\n " + ",\n ".join(args) + "\n" + suffix # don't keep / and * alone on a line s = (s.replace("\n /,", " /,").replace("\n *,", " *,").replace( "\n /\n)", " /\n)").replace("\n *\n)", " *\n)")) return s else: return s