diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..c29bf06 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,2 @@ +# Berry IDE +W.I.P \ No newline at end of file diff --git a/main.py b/main.py index 641226c..b8e38c6 100644 --- a/main.py +++ b/main.py @@ -10,10 +10,21 @@ from textual_fspicker import FileOpen, FileSave from plugin_loader import PluginLoader +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler + import subprocess import os +class Watcher(FileSystemEventHandler): + def __init__(self, app: App): + super().__init__() + self.app = app + + 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" @@ -26,6 +37,10 @@ class Berry(App): Binding("ctrl+f", "find", "Find", priority=True) ] + def __init__(self, path: str): + super().__init__() + self.path = path + def compose(self) -> ComposeResult: yield Header() with Vertical(id="sidebar"): @@ -36,7 +51,7 @@ class Berry(App): with ContentSwitcher(initial="files"): with Vertical(id="files"): yield Static("EXPLORER") - yield DirectoryTree("./", id="directory") + yield DirectoryTree(self.path, id="directory") with Vertical(id="editor"): first_tab = Tab("New File") @@ -46,7 +61,7 @@ class Berry(App): first_tab, id="file-tabs" ) - yield TextArea.code_editor(placeholder="This file is empty.", language="python", theme="css", id="code-editor", disabled=True) + yield TextArea.code_editor(placeholder="This file is empty.", theme="css", id="code-editor", disabled=True) #if os.name == "nt": with Vertical(id="console-container"): @@ -64,7 +79,7 @@ class Berry(App): self.run_command(event.input.value) event.input.clear() - + def run_command(self, command: str): console = self.query_one("#console") @@ -248,7 +263,11 @@ class Berry(App): with open(result, "wb") as f: f.write(self.query_one("#code-editor").text.encode()) + + 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) @@ -269,6 +288,11 @@ class Berry(App): 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 = {} @@ -277,12 +301,15 @@ class Berry(App): self.switching = False self.file_clicked = False + self.observer = Observer() + self.observer.schedule(Watcher(self), path=self.path) + self.observer.start() + #if os.name == "nt": self.query_one("#console").write("Run a command below.") #else: # self.query_one("#terminal").start() - if __name__ == "__main__": - app = Berry() + app = Berry("./") app.run() \ No newline at end of file diff --git a/plugin_loader.py b/plugin_loader.py index 27a020b..7420d3b 100644 --- a/plugin_loader.py +++ b/plugin_loader.py @@ -1,7 +1,8 @@ from textual_window import Window -from textual.widgets import RichLog +from textual.widgets import RichLog, Button from textual import work -from lupa import LuaRuntime, lua51 +from textual.binding import Binding +from lupa import lua51 import os, json, asyncio @@ -18,6 +19,30 @@ class PluginLoader(Window): allow_maximize=True ) + def fake_notify(self, message: str, title: str = None, severity: str = "information"): + self.app.notify(message=message, title=title, severity=severity) + + def create_sidebar_button(self, icon: str): + new_button = Button(icon) + self.app.query_one("#sidebar-buttons").mount(new_button) + + def set_theme(self, theme_name: str): + self.app.theme = theme_name + + def add_bind(self, action_name: str, key: str, description: str, show: bool = True): + # a bit of a sneaky way of doing things + self.app.bind(key, action_name, description=description, show=show) + self.app.refresh_bindings() + + def fake_run_action(self, action_name: str): + getattr(self.app, f"action_{action_name}")() + + def create_action(self, action_name: str, function): + def wrapper(): + function() + + setattr(self.app, f"action_{action_name}", wrapper) + @work async def find_plugins(self): log = self.query_one(RichLog) @@ -26,9 +51,15 @@ class PluginLoader(Window): log.write("[b]Setting up LUA runtime..[/]") self.lua_runtime = lua51.LuaRuntime() + lua_runtime_stuff = { "ui": { - "notify": self.notify + "notify": self.fake_notify, + "createSidebarButton": self.create_sidebar_button, + "setTheme": self.set_theme, + "runAction": self.fake_run_action, + "addBind": self.add_bind, + "createAction": self.create_action } } @@ -109,7 +140,7 @@ class PluginLoader(Window): executed_code = self.lua_runtime.execute(code) except lua51.LuaError as e: log.write(f"[b red]Error in {lua_file_path}: {e}[/]") - self.notify("There was Lua error while loading one your installed plugins. Check the Plugin Loader window for more details.", title="Lua Error", severity="error") + self.notify("There was Lua error while loading one your installed plugins. Check the Plugin Loader window for more details.", title="Lua Error", severity="error", timeout=10) no_errors = False continue @@ -120,8 +151,9 @@ class PluginLoader(Window): plugin_paths.append(plugin_folder) + log.write("\n[b]Done loading plugins![/]") if no_errors: - log.write("\n[d]Window will automatically close in 5 seconds.[/]") + log.write("[d]Window will automatically close in 5 seconds.[/]") await asyncio.sleep(5.0) self.close_window() diff --git a/plugins/test-plugin/lua/main.lua b/plugins/test-plugin/lua/main.lua index a3696c0..d45467f 100644 --- a/plugins/test-plugin/lua/main.lua +++ b/plugins/test-plugin/lua/main.lua @@ -1,7 +1,12 @@ local plugin = {} +function testAction() + berry.ui.notify("I just ran the test action!") +end + function plugin.init() - berry.ui.notify(tostring(math.random(1,10))) + berry.ui.createAction("test", testAction) + berry.ui.addBind("test", "ctrl+d", "Test") end return plugin \ No newline at end of file