From 7df6ce10c7dbea783d82a594bfb5cafafe21a2d7 Mon Sep 17 00:00:00 2001 From: SpookyDervish Date: Sat, 16 May 2026 17:50:51 +1000 Subject: [PATCH] working on multiple editor types --- assets/theme_mappings.py | 1 + directory_tree_custom.py | 37 +- main.py | 585 ++++++++++--------- plugin_loader.py | 9 +- plugins/Git/lua/main.lua | 14 - plugins/Markdown Reader/lua/main.lua | 7 + plugins/{Git => Markdown Reader}/plugin.json | 2 +- prompt.py | 127 ++-- settings_store.py | 3 +- test.py | 1 + 10 files changed, 411 insertions(+), 375 deletions(-) delete mode 100644 plugins/Git/lua/main.lua create mode 100644 plugins/Markdown Reader/lua/main.lua rename plugins/{Git => Markdown Reader}/plugin.json (72%) create mode 100644 test.py diff --git a/assets/theme_mappings.py b/assets/theme_mappings.py index e5849d4..81f1d34 100644 --- a/assets/theme_mappings.py +++ b/assets/theme_mappings.py @@ -14,4 +14,5 @@ theme_mappings = { "yaml": "yaml", "md": "markdown", "gitignore": "markdown", + "lua": "lua" } \ No newline at end of file diff --git a/directory_tree_custom.py b/directory_tree_custom.py index 63248c8..02d5a76 100644 --- a/directory_tree_custom.py +++ b/directory_tree_custom.py @@ -9,13 +9,18 @@ import os, shutil class CustomDirectoryTree(DirectoryTree): + + ICON_NODE = " " + ICON_NODE_EXPANDED = " " + ICON_FILE = " " + def __init__(self, path, *, name = None, id = None, classes = None, disabled = False): super().__init__(path, name=name, id=id, classes=classes, disabled=disabled) self.right_clicked_node: TreeNode | None = None - def context_menu_chosen(self, result): + def context_menu_chosen(self, file_name: str, result: str): if result == "Delete": def delete_confirm(will_delete: bool | None): if will_delete == True: @@ -44,7 +49,7 @@ class CustomDirectoryTree(DirectoryTree): self.right_clicked_node = None self.app.push_screen(Prompt(f"Enter the new name for \"{self.right_clicked_node.label}\".", "string", "Rename"), rename_confirm) - elif result == "New Folder": + elif result == "New folder": def new_folder(folder_name: str | None): if folder_name == None: return if folder_name.strip() == "": @@ -60,7 +65,7 @@ class CustomDirectoryTree(DirectoryTree): return self.app.push_screen(Prompt("Enter the name of the new folder.", "string", "Create New Folder"), new_folder) - elif result == "New File": + elif result == "New file": def new_file(file_name: str | None): if file_name == None: return if file_name.strip() == "": @@ -82,6 +87,24 @@ class CustomDirectoryTree(DirectoryTree): return self.app.push_screen(Prompt("Enter the name of the new file", "string", "Create New File"), new_file) + elif result == "Open with...": + file_extension = file_name.rsplit(".")[1] + default_editors = eval(self.app.config_handler.get("editor", "default_editors")) + default_editor = default_editors.get(file_extension, "Text Editor") + + def open_with(chosen_editor): + self.notify(str(chosen_editor)) + + self.app.push_screen(Prompt( + "Editor for file:", + "list", + "Choose editor for file", + values=[ + default_editor + " (Default)", + "Text Editor" + ], + allow_blank=False + ), open_with) def on_mouse_down(self, event: MouseDown): if event.button != 3 or not "line" in event.style.meta: @@ -89,16 +112,18 @@ class CustomDirectoryTree(DirectoryTree): selected_node = self.get_node_at_line(event.style.meta["line"]) self.right_clicked_node = selected_node + spacer = NoSelectStatic(f'[d]{"-" * 17}[/]') + options = None if self._safe_is_dir(self.right_clicked_node.data.path): - options = ["New Folder", "New File", NoSelectStatic(f'[d]{"-" * 17}[/]'), "Delete", "Rename"] + options = ["New folder", "New file", spacer, "Delete", "Rename"] else: - options = ["Delete", "Rename"] + options = ["Delete", "Rename", spacer, "Open with..."] file_name = str(self.right_clicked_node.label) if len(self.right_clicked_node.label) <= 17 else self.right_clicked_node.label[:14] + "..." self.app.push_screen(ContextMenu( [NoSelectStatic(f"[b]{file_name}[/]"), NoSelectStatic(f'[d]{"-" * 17}[/]')] + options, event.screen_offset - ), self.context_menu_chosen) + ), lambda result: self.context_menu_chosen(file_name, result)) diff --git a/main.py b/main.py index 5c326c9..93b9481 100644 --- a/main.py +++ b/main.py @@ -21,341 +21,344 @@ import os, sys class Watcher(FileSystemEventHandler): - def __init__(self, app: App): - super().__init__() - self.app = app + def __init__(self, app: App): + super().__init__() + self.app = app - async def on_any_event(self, event): - await self.app.query_one(DirectoryTree).reload() + async def on_any_event(self, event): + await self.app.query_one(DirectoryTree).reload() class Berry(App): - CSS_PATH = "assets/style.tcss" - SUB_TITLE = "New File" + CSS_PATH = "assets/style.tcss" + SUB_TITLE = "New File" - BINDINGS = [ - Binding("ctrl+o", "open", "Open File"), - Binding("ctrl+n", "new", "New File"), - Binding("ctrl+s", "save", "Save"), - Binding("ctrl+shift+s", "save_as", "Save As...", priority=True), - Binding("ctrl+f", "find", "Find", priority=True), - Binding("ctrl+f1", "settings", "Settings") - ] + BINDINGS = [ + Binding("ctrl+o", "open", "Open File"), + Binding("ctrl+n", "new", "New File"), + Binding("ctrl+s", "save", "Save"), + Binding("ctrl+shift+s", "save_as", "Save As...", priority=True), + Binding("ctrl+f", "find", "Find", priority=True), + Binding("ctrl+f1", "settings", "Settings") + ] - def __init__(self, path: str): - super().__init__() - self.path = path - self.config_handler = ConfigHandler(self) + def __init__(self, path: str): + super().__init__() + self.path = path + self.config_handler = ConfigHandler(self) - def compose(self) -> ComposeResult: - yield Header() - with Vertical(id="sidebar"): - with HorizontalGroup(id="sidebar-buttons"): - yield Button("📂") - yield Button("🔍") - - with ContentSwitcher(initial="files", id="sidebar-switcher"): - with Vertical(id="files"): - yield Static("EXPLORER") - yield CustomDirectoryTree(self.path, id="directory") + def compose(self) -> ComposeResult: + yield Header() + with Vertical(id="sidebar"): + with HorizontalGroup(id="sidebar-buttons"): + yield Button("") + yield Button("") + + with ContentSwitcher(initial="files", id="sidebar-switcher"): + with Vertical(id="files"): + yield Static("EXPLORER") + yield CustomDirectoryTree(self.path, id="directory") - with Vertical(id="editor"): - first_tab = Tab("New File") - first_tab.file_path = None + with Vertical(id="editor"): + first_tab = Tab("New File") + first_tab.file_path = None - yield Tabs( - first_tab, - id="file-tabs" - ) - yield TextArea.code_editor(placeholder="This file is empty.", theme="css", id="code-editor", disabled=True, soft_wrap=True, show_line_numbers=bool(int(self.config_handler.get("editor", "line_numbers")))) + yield Tabs( + first_tab, + id="file-tabs" + ) + yield TextArea.code_editor(placeholder="This file is empty.", theme="css", id="code-editor", disabled=True, soft_wrap=True, show_line_numbers=bool(int(self.config_handler.get("editor", "line_numbers")))) - #if os.name == "nt": - #with Vertical(id="console-container"): - # yield RichLog(id="console") - # yield Input(placeholder="> ", id="console-input") - #else: - # yield Terminal(command="bash", id="terminal") + #if os.name == "nt": + #with Vertical(id="console-container"): + # yield RichLog(id="console") + # yield Input(placeholder="> ", id="console-input") + #else: + # yield Terminal(command="bash", id="terminal") - yield Footer() - if bool(int(self.config_handler.get("plugins", "enabled"))) == True: - yield PluginLoader() + yield Footer() + if bool(int(self.config_handler.get("plugins", "enabled"))) == True: + yield PluginLoader() - def action_settings(self): - self.push_screen(SettingsScreen()) + def action_settings(self): + self.push_screen(SettingsScreen()) - def get_system_commands(self, screen): - yield SystemCommand( - "Quit the application", - "Quit the application as soon as possible", - self.action_quit, - ) + def get_system_commands(self, screen): + yield SystemCommand( + "Quit the application", + "Quit the application as soon as possible", + self.action_quit, + ) - if screen.query("HelpPanel"): - yield SystemCommand( - "Hide keys and help panel", - "Hide the keys and widget help panel", - self.action_hide_help_panel, - ) - else: - yield SystemCommand( - "Show keys and help panel", - "Show help for the focused widget and a summary of available keys", - self.action_show_help_panel, - ) - - yield SystemCommand("Settings", "Open the settings menu", self.action_settings) + if screen.query("HelpPanel"): + yield SystemCommand( + "Hide keys and help panel", + "Hide the keys and widget help panel", + self.action_hide_help_panel, + ) + else: + yield SystemCommand( + "Show keys and help panel", + "Show help for the focused widget and a summary of available keys", + self.action_show_help_panel, + ) + + yield SystemCommand("Settings", "Open the settings menu", self.action_settings) - async def chose_file_to_open(self, result): - if result == None: return - result = str(result) - if self.open_file == result: - return - - def is_within_directory(file_path: str, directory: str) -> bool: - file_path = Path(file_path).resolve() - directory = Path(directory).resolve() - return directory in file_path.parents - - self.switching = True - - tabs: Tabs = self.query_one("#file-tabs") - - if self.open_file not in self.unsaved_files: - if self.open_file: - self.file_tabs.pop(self.open_file) - tabs.remove_tab(tabs.active_tab) - - self.open_file = result - inside_dir = is_within_directory(result, self.path) + async def chose_file_to_open(self, result): + if result == None: return + result = str(result) + if self.open_file == result: + return + + def is_within_directory(file_path: str, directory: str) -> bool: + file_path = Path(file_path).resolve() + directory = Path(directory).resolve() + return directory in file_path.parents + + self.switching = True + + tabs: Tabs = self.query_one("#file-tabs") + + if self.open_file not in self.unsaved_files: + if self.open_file: + self.file_tabs.pop(self.open_file) + tabs.remove_tab(tabs.active_tab) + + self.open_file = result + inside_dir = is_within_directory(result, self.path) - self.sub_title = os.path.basename(self.open_file) if inside_dir else self.open_file + self.sub_title = os.path.basename(self.open_file) if inside_dir else self.open_file - if result not in self.file_tabs: - new_tab = Tab(os.path.basename(result) if inside_dir else result) - new_tab.tooltip = str(new_tab.label) - setattr(new_tab, "file_path", result) - await tabs.add_tab(new_tab) - self.file_tabs[result] = new_tab - tabs.active = new_tab.id - else: - tabs.active = self.file_tabs[result].id + if result not in self.file_tabs: + new_tab = Tab(os.path.basename(result) if inside_dir else result) + new_tab.tooltip = str(new_tab.label) + setattr(new_tab, "file_path", result) + await tabs.add_tab(new_tab) + self.file_tabs[result] = new_tab + tabs.active = new_tab.id + else: + tabs.active = self.file_tabs[result].id - def action_open(self): - self.app.push_screen(FileOpen(), self.chose_file_to_open) + def action_open(self): + self.app.push_screen(FileOpen(), self.chose_file_to_open) - def action_find(self): - try: - self.query_one("#find-window") - return - except: + def action_find(self): + try: + self.query_one("#find-window") + return + except: - find_window = Window( + find_window = Window( - Vertical( - HorizontalGroup( - Input(placeholder="Find"), - Static("0 of 0", id="num-matches"), - Button("↑", flat=True), - Button("↓", flat=True), - ), - HorizontalGroup( - Input(placeholder="Replace"), - ), - ), - - icon="🔍", - start_open=True, - allow_resize=False, - allow_maximize=False, - id="find-window", - mode="temporary", - name="Find & Replace" - ) + Vertical( + HorizontalGroup( + Input(placeholder="Find"), + Static("0 of 0", id="num-matches"), + Button("↑", flat=True), + Button("↓", flat=True), + ), + HorizontalGroup( + Input(placeholder="Replace"), + ), + ), + + icon="🔍", + start_open=True, + allow_resize=False, + allow_maximize=False, + id="find-window", + mode="temporary", + name="Find & Replace" + ) - self.mount(find_window) + self.mount(find_window) - async def on_directory_tree_file_selected(self, event: DirectoryTree.FileSelected): - if self.open_file == str(event.path): - return + async def on_directory_tree_file_selected(self, event: DirectoryTree.FileSelected): + if self.open_file == str(event.path): + return - self.file_clicked = True - self.switching = True - - tabs: Tabs = self.query_one("#file-tabs") - - if self.open_file not in self.unsaved_files: - if self.open_file: - self.file_tabs.pop(self.open_file) - tabs.remove_tab(tabs.active_tab) - - self.open_file = str(event.path) - self.sub_title = os.path.basename(self.open_file) + self.file_clicked = True + self.switching = True + + tabs: Tabs = self.query_one("#file-tabs") + + if self.open_file not in self.unsaved_files: + if self.open_file: + self.file_tabs.pop(self.open_file) + tabs.remove_tab(tabs.active_tab) + + self.open_file = str(event.path) + self.sub_title = os.path.basename(self.open_file) - if str(event.path) not in self.file_tabs: - new_tab = Tab(os.path.basename(str(event.path))) - new_tab.tooltip = str(new_tab.label) - setattr(new_tab, "file_path", str(event.path)) - await tabs.add_tab(new_tab) - self.file_tabs[str(event.path)] = new_tab - tabs.active = new_tab.id - else: - tabs.active = self.file_tabs[str(event.path)].id + if str(event.path) not in self.file_tabs: + new_tab = Tab(os.path.basename(str(event.path))) + new_tab.tooltip = str(new_tab.label) + setattr(new_tab, "file_path", str(event.path)) + await tabs.add_tab(new_tab) + self.file_tabs[str(event.path)] = new_tab + tabs.active = new_tab.id + else: + tabs.active = self.file_tabs[str(event.path)].id - + def open_text_editor(self, file_content: bytes, file_extension: str): + code_editor: TextArea = self.query_one("#code-editor") + + code_editor.language = theme_mappings.get(file_extension, None) + + try: + code_editor.text = file_content.decode("utf-8") + code_editor.disabled = False + except UnicodeDecodeError: + code_editor.text = "This file is in binary, it can't be opened. Sorry." + code_editor.language = None + code_editor.disabled = True + + code_editor.focus() + + def open_editor(self, file_extension: str, file_content: str): + default_editors: dict = eval(self.config_handler.get("editor", "default_editors")) + editor_for_file = default_editors.get(file_extension, None) + + if not editor_for_file: + self.open_text_editor(file_content, file_extension) + + @on(Tabs.TabActivated) + def on_tab_shown(self, event: Tabs.TabActivated): + + if self.file_clicked: + self.file_clicked = False + else: + self.open_file = getattr(event.tab, "file_path") + + self.switching = True + + content = b"" + file_extension = "" + + if self.open_file: + try: + f = open(self.open_file, "rb") + except Exception as e: + self.notify(f"Failed to open the file: {e}") + return + + # if the file is unsaved, use the content we wrote into it + # otherwise, read the CURRENT state of the file + if self.open_file in self.unsaved_files: + content = self.unsaved_files[self.open_file]["current"] + else: + content = f.read() + + # get the file extension + file_extension = self.open_file.split(".")[-1] if "." in self.open_file else "" + + # close the file + f.close() + + self.open_editor(file_extension, content) + + - @on(Tabs.TabActivated) - def on_tab_shown(self, event: Tabs.TabActivated): + @on(Window.Minimized) + def window_minimized(self, event: Window.Minimized): + event.window.remove_window() + + def on_text_area_changed(self, event: TextArea.Changed): + if event.text_area.id != "code-editor": + return + if self.switching: + self.switching = False + return + + + + tabs: Tabs = self.query_one("#file-tabs") + if self.open_file: + if not self.open_file in self.unsaved_files: + with open(self.open_file, "r", encoding="utf-8") as f: + if f.read() == event.text_area.text: # TODO: figure out why im guetting what seems like a race conidition which is making this if statement needed + return + self.unsaved_files[self.open_file] = {"current": event.text_area.text, "original": f.read()} - if self.file_clicked: - self.file_clicked = False - else: - self.open_file = getattr(event.tab, "file_path") + + tabs.active_tab.tooltip = f"Unsaved changes in {tabs.active_tab.label}" + tabs.active_tab.label = "[d orange]●[/] " + str(tabs.active_tab.label) + + else: + self.unsaved_files[self.open_file]["current"] = event.text_area.text + if self.unsaved_files[self.open_file]["original"] == self.unsaved_files[self.open_file]["current"]: + tabs.active_tab.label = os.path.basename(self.open_file) + tabs.active_tab.tooltip = str(tabs.active_tab.label) + self.unsaved_files.pop(self.open_file) - self.switching = True + def action_new(self): + tabs: Tabs = self.query_one("#file-tabs") + new_tab = Tab("New File") + setattr(new_tab, "file_path", None) + tabs.add_tab(new_tab) + tabs.active = new_tab.id - code_editor: TextArea = self.query_one("#code-editor") - if self.open_file: - try: - f = open(self.open_file, "r", encoding="utf-8") - except Exception as e: - self.notify(f"Failed to open the file: {e}") - return + self.open_file = None + self.switching = True + code_editor: TextArea = self.query_one("#code-editor") - + code_editor.disabled = False + code_editor.text = "" - - try: - if self.open_file in self.unsaved_files: - code_editor.text = self.unsaved_files[self.open_file]["current"] - else: - code_editor.text = f.read() - - file_extension = self.open_file - dot_count = file_extension.count(".") - - if dot_count == 1: - if file_extension.startswith("."): - file_extension = file_extension.removeprefix(".") - else: - file_extension = file_extension.rsplit(".", 1)[1] - elif dot_count > 1: - file_extension = file_extension.rsplit(".", 1)[1] + def done_saving(self, result): + if result is None: return - code_editor.language = theme_mappings.get(file_extension, None) - code_editor.disabled = False - except UnicodeDecodeError: - code_editor.text = "This file is in binary, it can't be opened. Sorry." - code_editor.language = None - code_editor.disabled = True + with open(result, "w", encoding="utf-8") as f: + f.write(self.query_one("#code-editor").text) - f.close() - else: - code_editor.text = "" - code_editor.language = None - code_editor.disabled = False + tabs: Tabs = self.query_one("#file-tabs") + tabs.active_tab.label = os.path.basename(result) + self.notify(f"Saved to {result} successfully.", title="Done!", markup=False) + self.query_one(DirectoryTree).reload() - code_editor.focus() + def action_save_as(self): + self.push_screen(FileSave(), callback=self.done_saving) + def action_save(self): + if self.open_file == None and self.query_one("#code-editor").disabled == False: + self.action_save_as() - @on(Window.Minimized) - def window_minimized(self, event: Window.Minimized): - event.window.remove_window() - - def on_text_area_changed(self, event: TextArea.Changed): - if event.text_area.id != "code-editor": - return - if self.switching: - self.switching = False - return - - - - tabs: Tabs = self.query_one("#file-tabs") - if self.open_file: - if not self.open_file in self.unsaved_files: - with open(self.open_file, "r", encoding="utf-8") as f: - if f.read() == event.text_area.text: # TODO: figure out why im guetting what seems like a race conidition which is making this if statement needed - return - self.unsaved_files[self.open_file] = {"current": event.text_area.text, "original": f.read()} + # dont bother saving if there are no new changes + if not self.open_file in self.unsaved_files: return - - tabs.active_tab.tooltip = f"Unsaved changes in {tabs.active_tab.label}" - tabs.active_tab.label = "[d orange]●[/] " + str(tabs.active_tab.label) - - else: - self.unsaved_files[self.open_file]["current"] = event.text_area.text - if self.unsaved_files[self.open_file]["original"] == self.unsaved_files[self.open_file]["current"]: - tabs.active_tab.label = os.path.basename(self.open_file) - tabs.active_tab.tooltip = str(tabs.active_tab.label) - self.unsaved_files.pop(self.open_file) + with open(self.open_file, "w") as f: + f.write(self.unsaved_files[self.open_file]["current"]) - def action_new(self): - tabs: Tabs = self.query_one("#file-tabs") - new_tab = Tab("New File") - setattr(new_tab, "file_path", None) - tabs.add_tab(new_tab) - tabs.active = new_tab.id + tabs: Tabs = self.query_one("#file-tabs") + tabs.active_tab.label = os.path.basename(self.open_file) + tabs.active_tab.tooltip = str(tabs.active_tab.label) + self.unsaved_files.pop(self.open_file) + self.notify("Saved.") - self.open_file = None - self.switching = True - code_editor: TextArea = self.query_one("#code-editor") + def action_quit(self): + self.observer.stop() + self.observer.join() + return super().action_quit() + + def on_ready(self): + # src/main.py: Tab<> + self.file_tabs = {} + self.open_file = None + self.unsaved_files = {} # list of paths + self.switching = False + self.file_clicked = False - code_editor.disabled = False - code_editor.text = "" + self.observer = Observer() + self.observer.schedule(Watcher(self), path=self.path) + self.observer.start() - def done_saving(self, result): - if result is None: return - - with open(result, "w", encoding="utf-8") as f: - f.write(self.query_one("#code-editor").text) - - tabs: Tabs = self.query_one("#file-tabs") - tabs.active_tab.label = os.path.basename(result) - self.notify(f"Saved to {result} successfully.", title="Done!", markup=False) - self.query_one(DirectoryTree).reload() - - def action_save_as(self): - self.push_screen(FileSave(), callback=self.done_saving) - - def action_save(self): - if self.open_file == None and self.query_one("#code-editor").disabled == False: - self.action_save_as() - - # dont bother saving if there are no new changes - if not self.open_file in self.unsaved_files: return - - with open(self.open_file, "w") as f: - f.write(self.unsaved_files[self.open_file]["current"]) - - tabs: Tabs = self.query_one("#file-tabs") - tabs.active_tab.label = os.path.basename(self.open_file) - tabs.active_tab.tooltip = str(tabs.active_tab.label) - self.unsaved_files.pop(self.open_file) - self.notify("Saved.") - - def action_quit(self): - self.observer.stop() - self.observer.join() - return super().action_quit() - - def on_ready(self): - # src/main.py: Tab<> - self.file_tabs = {} - self.open_file = None - self.unsaved_files = {} # list of paths - self.switching = False - self.file_clicked = False - - self.observer = Observer() - self.observer.schedule(Watcher(self), path=self.path) - self.observer.start() - - self.config_handler.apply_settings() + self.config_handler.apply_settings() if __name__ == "__main__": - working_path = os.getcwd() if len(sys.argv) == 1 else sys.argv[1] - app = Berry(working_path) - app.run() \ No newline at end of file + working_path = os.getcwd() if len(sys.argv) == 1 else sys.argv[1] + app = Berry(working_path) + app.run() \ No newline at end of file diff --git a/plugin_loader.py b/plugin_loader.py index e6c57c6..3255041 100644 --- a/plugin_loader.py +++ b/plugin_loader.py @@ -71,7 +71,14 @@ class PluginLoader(Window): setattr(self.app, f"action_{action_name}", wrapper) def create_widget(self, widget_type: str, *args): - return getattr(textual.widgets, widget_type)(*args) + new_widget = getattr(textual.widgets, widget_type)(*args) + + def on_func(event_name: str, function): + self.event_handler.subscribe(new_widget, event_name, function) + new_widget.message_signal.subscribe(self, lambda e: self.event_handler.message_handler(new_widget, e)) + + setattr(new_widget, "on", on_func) + return new_widget def run_on_message(self, widget, event, function): self.event_handler.subscribe(widget, event, function) diff --git a/plugins/Git/lua/main.lua b/plugins/Git/lua/main.lua deleted file mode 100644 index bbf92be..0000000 --- a/plugins/Git/lua/main.lua +++ /dev/null @@ -1,14 +0,0 @@ - local plugin = {} - -function plugin.run() - --berry.config.defineSetting("my plugin", "test setting", "description", "boolean", "1") - - button = berry.ui.button("Click me!", "success") - berry.ui.mount(button) - - berry.ui.onMessage(button, "Pressed", function() - print("hi") - end) -end - -return plugin \ No newline at end of file diff --git a/plugins/Markdown Reader/lua/main.lua b/plugins/Markdown Reader/lua/main.lua new file mode 100644 index 0000000..e5fc983 --- /dev/null +++ b/plugins/Markdown Reader/lua/main.lua @@ -0,0 +1,7 @@ + local plugin = {} + +function plugin.run() + berry.ui.notify("hi lmao") +end + +return plugin \ No newline at end of file diff --git a/plugins/Git/plugin.json b/plugins/Markdown Reader/plugin.json similarity index 72% rename from plugins/Git/plugin.json rename to plugins/Markdown Reader/plugin.json index dd6f6e8..1d9be49 100644 --- a/plugins/Git/plugin.json +++ b/plugins/Markdown Reader/plugin.json @@ -1,5 +1,5 @@ { - "name": "Git", + "name": "Markdown Reader", "author": "SpookyDervish", "version": "1.0.0", "dependencies": [] diff --git a/prompt.py b/prompt.py index 17b2558..be841d9 100644 --- a/prompt.py +++ b/prompt.py @@ -1,80 +1,85 @@ from textual.screen import ModalScreen from textual.containers import Vertical -from textual.widgets import Static, Button, Input +from textual.widgets import Static, Button, Input, Select from textual.containers import HorizontalGroup, Center from textual.binding import Binding from typing import Literal class Prompt(ModalScreen): - DEFAULT_CSS = """ - Prompt { - align: center middle; + DEFAULT_CSS = """ + Prompt { + align: center middle; - #window { - max-width: 50; - height: auto; - border: panel $accent; + #window { + max-width: 50; + height: auto; + border: panel $accent; - #question { - width: 100%; - margin: 2; - margin-top: 1; - } + #question { + width: 100%; + margin: 2; + margin-top: 1; + } - #bottom { - dock: bottom; - margin-bottom: 1; - margin-left: 1; + #bottom { + dock: bottom; + margin-bottom: 1; + margin-left: 1; - #yes { - margin-left: 1; - margin-right: 2; - } + #yes { + margin-left: 1; + margin-right: 2; + } - #confirm-string { - margin-left: 1; - } + #confirm-string { + margin-left: 1; + } - Input { - max-width: 25; - } - } - } - } - """ + Input { + max-width: 25; + } + } + } + } + """ - BINDINGS = [ - Binding("escape", "close", "Close") - ] + BINDINGS = [ + Binding("escape", "close", "Close") + ] - def action_close(self): - self.dismiss(None) + def action_close(self): + self.dismiss(None) - def on_button_pressed(self, event: Button.Pressed): - if event.button.id == "yes": - self.dismiss(True) - elif event.button.id == "no": - self.dismiss(False) - elif event.button.id == "confirm-string": - self.dismiss(self.query_one("#input").value) + def on_button_pressed(self, event: Button.Pressed): + if event.button.id == "yes": + self.dismiss(True) + elif event.button.id == "no": + self.dismiss(False) + elif event.button.id == "confirm-string": + self.dismiss(self.query_one("#input").value) + elif event.button.id == "confirm-list": + self.dismiss(self.query_one("#select").value) - def __init__(self, question: str, prompt_type: Literal["confirm", "string"], title: str = "Confirm"): - super().__init__() - self.question = question - self.window_title = title - self.prompt_type = prompt_type + def __init__(self, question: str, prompt_type: Literal["confirm", "string"], title: str = "Confirm", **kwargs): + super().__init__() + self.question = question + self.window_title = title + self.prompt_type = prompt_type + self.kwargs = kwargs - def compose(self): - with Vertical(id="window") as window: - window.border_title = self.window_title - yield Static(self.question, id="question") - - if self.prompt_type == "confirm": - with HorizontalGroup(id="bottom"): - yield Button("Yes", variant="success", id="yes") - yield Button("No", variant="error", id="no") - elif self.prompt_type == "string": - with HorizontalGroup(id="bottom"): - yield Input(id="input", max_length=30) - yield Button("Confirm", variant="success", id="confirm-string") \ No newline at end of file + def compose(self): + with Vertical(id="window") as window: + window.border_title = self.window_title + yield Static(self.question, id="question") + + with HorizontalGroup(id="bottom"): + if self.prompt_type == "confirm": + yield Button("Yes", variant="success", id="yes") + yield Button("No", variant="error", id="no") + elif self.prompt_type == "string": + yield Input(id="input", **self.kwargs) + yield Button("Confirm", variant="success", id="confirm-string") + elif self.prompt_type == "list": + yield Select.from_values(**self.kwargs, id="select") + yield Button("Confirm", variant="success", id="confirm-list") \ No newline at end of file diff --git a/settings_store.py b/settings_store.py index 195daae..0266fe3 100644 --- a/settings_store.py +++ b/settings_store.py @@ -93,7 +93,8 @@ class ConfigHandler: } self.config["editor"] = { "word_wrap": "0", - "line_numbers": "1" + "line_numbers": "1", + "default_editors": {} } self.config["plugins"] = { "enabled": "1", diff --git a/test.py b/test.py new file mode 100644 index 0000000..4648e70 --- /dev/null +++ b/test.py @@ -0,0 +1 @@ +print("Hello, World!") \ No newline at end of file