plugin defined settings!!!!
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
from textual_window import Window
|
from textual_window import Window
|
||||||
from textual.widgets import RichLog, Button
|
from textual.widgets import RichLog, Button
|
||||||
from textual import work, on
|
from textual import work
|
||||||
import textual.widgets
|
import textual.widgets
|
||||||
|
from typing import Any
|
||||||
from traceback import format_exception
|
from traceback import format_exception
|
||||||
|
|
||||||
from lupa import lua51
|
from lupa import lua51
|
||||||
@@ -68,6 +69,9 @@ class PluginLoader(Window):
|
|||||||
)
|
)
|
||||||
#self.app.mount(new_window)
|
#self.app.mount(new_window)
|
||||||
return new_window
|
return new_window
|
||||||
|
|
||||||
|
def create_setting(self, section_name: str, option_name: str, description: str, option_type: str, default_value: Any, on_changed_func = None):
|
||||||
|
self.app.config_handler.define_plugin_setting(section_name, option_name, description, option_type, default_value, on_changed_func)
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
@@ -83,8 +87,6 @@ class PluginLoader(Window):
|
|||||||
lua_runtime_stuff = {
|
lua_runtime_stuff = {
|
||||||
"ui": {
|
"ui": {
|
||||||
"notify": self.fake_notify,
|
"notify": self.fake_notify,
|
||||||
#"createSidebarButton": self.create_sidebar_button,
|
|
||||||
#"setTheme": self.set_theme,
|
|
||||||
"runAction": self.fake_run_action,
|
"runAction": self.fake_run_action,
|
||||||
"addBind": self.add_bind,
|
"addBind": self.add_bind,
|
||||||
"createAction": self.create_action,
|
"createAction": self.create_action,
|
||||||
@@ -93,7 +95,10 @@ class PluginLoader(Window):
|
|||||||
"app": self.app,
|
"app": self.app,
|
||||||
"onMessage": self.run_on_message
|
"onMessage": self.run_on_message
|
||||||
},
|
},
|
||||||
"config": self.app.config_handler
|
"config": {
|
||||||
|
"get": self.app.config_handler.get,
|
||||||
|
"defineSetting": self.create_setting
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.write("[b]Finding plugins...[/]")
|
log.write("[b]Finding plugins...[/]")
|
||||||
@@ -190,7 +195,7 @@ class PluginLoader(Window):
|
|||||||
|
|
||||||
log.write("\n[b]Done loading plugins![/]")
|
log.write("\n[b]Done loading plugins![/]")
|
||||||
if no_errors and int(self.app.config_handler.get("plugins", "log_timeout")) != -1:
|
if no_errors and int(self.app.config_handler.get("plugins", "log_timeout")) != -1:
|
||||||
log.write("[d]Window will automatically close in 10 seconds.[/]")
|
log.write(f'[d]Window will automatically close in {self.app.config_handler.get("plugins", "log_timeout")} seconds.[/]')
|
||||||
await asyncio.sleep(int(self.app.config_handler.get("plugins", "log_timeout")))
|
await asyncio.sleep(int(self.app.config_handler.get("plugins", "log_timeout")))
|
||||||
self.close_window()
|
self.close_window()
|
||||||
|
|
||||||
|
|||||||
14
plugins/test/lua/main.lua
Normal file
14
plugins/test/lua/main.lua
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
local plugin = {}
|
||||||
|
|
||||||
|
function test(newValue)
|
||||||
|
berry.ui.notify(tostring(newValue))
|
||||||
|
end
|
||||||
|
|
||||||
|
function plugin.run()
|
||||||
|
berry.config.defineSetting("Test Plugin", "test setting", "this is a description", "string", "hi, this is the default value", test)
|
||||||
|
berry.config.defineSetting("Test Plugin", "another setting!", "woah!", "boolean", "1", test)
|
||||||
|
berry.config.defineSetting("Test Plugin", "integer setting", "i love integers :O", "integer", "123", test)
|
||||||
|
berry.config.defineSetting("Test Plugin", "float setting", "i love floating point numbers :O", "float", "123.456", test)
|
||||||
|
end
|
||||||
|
|
||||||
|
return plugin
|
||||||
6
plugins/test/plugin.json
Normal file
6
plugins/test/plugin.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "Test Plugin",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": "SpookyDervish",
|
||||||
|
"dependencies": []
|
||||||
|
}
|
||||||
114
settings.py
114
settings.py
@@ -1,6 +1,6 @@
|
|||||||
from textual.screen import ModalScreen
|
from textual.screen import ModalScreen
|
||||||
from textual.widgets import Label, Select, TabbedContent, TabPane, Switch, Input
|
from textual.widgets import Label, Select, TabbedContent, TabPane, Switch, Input, Rule, Static
|
||||||
from textual.containers import Vertical, HorizontalGroup, VerticalGroup
|
from textual.containers import Vertical, HorizontalGroup, VerticalGroup, VerticalScroll
|
||||||
from textual.binding import Binding
|
from textual.binding import Binding
|
||||||
|
|
||||||
|
|
||||||
@@ -22,6 +22,15 @@ class SettingsScreen(ModalScreen):
|
|||||||
padding: 1;
|
padding: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rule {
|
||||||
|
color: $boost;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thingy {
|
||||||
|
margin-top: 2;
|
||||||
|
text-style: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.setting {
|
.setting {
|
||||||
padding: 0 2;
|
padding: 0 2;
|
||||||
content-align: center middle;
|
content-align: center middle;
|
||||||
@@ -69,6 +78,9 @@ class SettingsScreen(ModalScreen):
|
|||||||
self.notify("Restart for changes to apply.", title="Restart Required", severity="warning")
|
self.notify("Restart for changes to apply.", title="Restart Required", severity="warning")
|
||||||
elif event.switch.id == "plugins-log":
|
elif event.switch.id == "plugins-log":
|
||||||
self.app.config_handler.set("plugins", "log", str(int(event.value)))
|
self.app.config_handler.set("plugins", "log", str(int(event.value)))
|
||||||
|
elif event.switch.has_class("plugin-option"):
|
||||||
|
if event.switch.berry_changed_func != None:
|
||||||
|
event.switch.berry_changed_func(event.switch.value)
|
||||||
|
|
||||||
def on_select_changed(self, event: Select.Changed):
|
def on_select_changed(self, event: Select.Changed):
|
||||||
if event.select.id == "colour-theme":
|
if event.select.id == "colour-theme":
|
||||||
@@ -80,47 +92,83 @@ class SettingsScreen(ModalScreen):
|
|||||||
|
|
||||||
if event.input.id == "log-timeout":
|
if event.input.id == "log-timeout":
|
||||||
self.app.config_handler.set("plugins", "log_timeout", str(event.input.value))
|
self.app.config_handler.set("plugins", "log_timeout", str(event.input.value))
|
||||||
|
elif event.input.has_class("plugin-option"):
|
||||||
|
if event.input.berry_changed_func != None:
|
||||||
|
event.input.berry_changed_func(event.input.value)
|
||||||
|
|
||||||
def compose(self):
|
def compose(self):
|
||||||
with Vertical(id="window") as window:
|
with Vertical(id="window") as window:
|
||||||
window.border_title = "Settings"
|
window.border_title = "Settings"
|
||||||
with TabbedContent():
|
with TabbedContent():
|
||||||
with TabPane("Appearance"):
|
with TabPane("Appearance"):
|
||||||
with HorizontalGroup(classes="setting"):
|
with VerticalScroll():
|
||||||
with VerticalGroup():
|
with HorizontalGroup(classes="setting"):
|
||||||
yield Label("Colour Theme", classes="setting-name")
|
with VerticalGroup():
|
||||||
yield Label("Colour theme used for the entire Berry app. You can get more themes with plugins!", classes="setting-desc")
|
yield Label("Colour Theme", classes="setting-name")
|
||||||
|
yield Label("Colour theme used for the entire Berry app. You can get more themes with plugins!", classes="setting-desc")
|
||||||
|
|
||||||
yield Select.from_values(
|
yield Select.from_values(
|
||||||
(theme_name for theme_name in self.app._registered_themes.keys() if theme_name != "textual-ansi"),
|
(theme_name for theme_name in self.app._registered_themes.keys() if theme_name != "textual-ansi"),
|
||||||
allow_blank=False,
|
allow_blank=False,
|
||||||
id="colour-theme",
|
id="colour-theme",
|
||||||
value=self.app.theme
|
value=self.app.theme
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
with TabPane("Editor"):
|
with TabPane("Editor"):
|
||||||
with HorizontalGroup(classes="setting"):
|
with VerticalScroll():
|
||||||
with VerticalGroup():
|
with HorizontalGroup(classes="setting"):
|
||||||
yield Label("Word Wrap", classes="setting-name")
|
with VerticalGroup():
|
||||||
yield Label("Enable word wrap in the code editor.", classes="setting-desc")
|
yield Label("Word Wrap", classes="setting-name")
|
||||||
yield Switch(value=bool(int(self.app.config_handler.get("editor", "word_wrap"))), id="word-wrap")
|
yield Label("Enable word wrap in the code editor.", classes="setting-desc")
|
||||||
|
yield Switch(value=bool(int(self.app.config_handler.get("editor", "word_wrap"))), id="word-wrap")
|
||||||
with TabPane("Plugins"):
|
with TabPane("Plugins"):
|
||||||
|
with VerticalScroll():
|
||||||
|
|
||||||
|
with HorizontalGroup(classes="setting"):
|
||||||
|
with VerticalGroup():
|
||||||
|
yield Label("Plugins Enabled", classes="setting-name")
|
||||||
|
yield Label("Enable or disable Lua plugins. This requires a restart.", classes="setting-desc")
|
||||||
|
yield Switch(value=bool(int(self.app.config_handler.get("plugins", "enabled"))), id="plugins-enabled")
|
||||||
|
|
||||||
with HorizontalGroup(classes="setting"):
|
with HorizontalGroup(classes="setting"):
|
||||||
with VerticalGroup():
|
with VerticalGroup():
|
||||||
yield Label("Plugins Enabled", classes="setting-name")
|
yield Label("Plugins Log", classes="setting-name")
|
||||||
yield Label("Enable or disable Lua plugins. This requires a restart.", classes="setting-desc")
|
yield Label("Show the plugin loader log on startup.", classes="setting-desc")
|
||||||
yield Switch(value=bool(int(self.app.config_handler.get("plugins", "enabled"))), id="plugins-enabled")
|
yield Switch(value=bool(int(self.app.config_handler.get("plugins", "log"))), id="plugins-log")
|
||||||
|
|
||||||
|
with HorizontalGroup(classes="setting"):
|
||||||
|
with VerticalGroup():
|
||||||
|
yield Label("Log Timeout", classes="setting-name")
|
||||||
|
yield Label("How many seconds before the log automatically closes. This gets overriden by the [b]Plugins Log[/] option. The window doesn't automatically close if there was an error. If this is set to -1, the log will not close automatically.", classes="setting-desc")
|
||||||
|
yield Input(value=self.app.config_handler.get("plugins", "log_timeout"), id="log-timeout", type="integer")
|
||||||
|
|
||||||
|
yield Static("Plugin-defined Settings", classes="thingy")
|
||||||
|
yield Rule(line_style="thick")
|
||||||
|
|
||||||
with HorizontalGroup(classes="setting"):
|
for plugin_section, plugin_settings in self.app.config_handler.plugin_defined_settings.items():
|
||||||
with VerticalGroup():
|
yield Static(f"{plugin_section}", classes="thingy")
|
||||||
yield Label("Plugins Log", classes="setting-name")
|
yield Rule()
|
||||||
yield Label("Show the plugin loader log on startup.", classes="setting-desc")
|
|
||||||
yield Switch(value=bool(int(self.app.config_handler.get("plugins", "log"))), id="plugins-log")
|
for setting_name, setting in plugin_settings.items():
|
||||||
|
with HorizontalGroup(classes="setting"):
|
||||||
with HorizontalGroup(classes="setting"):
|
with VerticalGroup():
|
||||||
with VerticalGroup():
|
yield Label(setting_name, classes="setting-name")
|
||||||
yield Label("Log Timeout", classes="setting-name")
|
yield Label(setting["description"], classes="setting-desc")
|
||||||
yield Label("How many seconds before the log automatically closes. This gets overriden by the [b]Plugins Log[/] option. The window doesn't automatically close if there was an error. If this is set to -1, the log will not close automatically.", classes="setting-desc")
|
|
||||||
yield Input(value=self.app.config_handler.get("plugins", "log_timeout"), id="log-timeout", type="integer")
|
value = self.app.config_handler.get(f"plugin_{plugin_section}", setting["option_name"])
|
||||||
|
|
||||||
|
new_widget = None
|
||||||
|
if setting["type"] == bool:
|
||||||
|
value = bool(int(value))
|
||||||
|
new_widget = Switch(value=value)
|
||||||
|
elif setting["type"] == int:
|
||||||
|
new_widget = Input(value=value, type="integer", placeholder=setting["default_value"])
|
||||||
|
elif setting["type"] == float:
|
||||||
|
new_widget = Input(value=value, type="number", placeholder=setting["default_value"])
|
||||||
|
elif setting["type"] == str:
|
||||||
|
new_widget = Input(value=value, placeholder=setting["default_value"])
|
||||||
|
|
||||||
|
new_widget.add_class("plugin-option")
|
||||||
|
setattr(new_widget, "berry_changed_func", setting['on_changed_func'])
|
||||||
|
yield new_widget
|
||||||
@@ -2,6 +2,7 @@ from textual.app import App
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import os
|
import os
|
||||||
import configparser
|
import configparser
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
class ConfigHandler:
|
class ConfigHandler:
|
||||||
@@ -9,8 +10,43 @@ class ConfigHandler:
|
|||||||
self.app: App = app
|
self.app: App = app
|
||||||
self.config: configparser.ConfigParser = configparser.ConfigParser()
|
self.config: configparser.ConfigParser = configparser.ConfigParser()
|
||||||
|
|
||||||
|
self.plugin_defined_settings = {}
|
||||||
self.config_dir: str = self.ensure_hidden_config_dir()
|
self.config_dir: str = self.ensure_hidden_config_dir()
|
||||||
self.load_settings()
|
self.load_settings()
|
||||||
|
|
||||||
|
def define_plugin_setting(self, plugin_name: str, option_name: str, description: str, option_type: str, default_value: Any, on_changed_func = None):
|
||||||
|
actual_type = None
|
||||||
|
if option_type == "boolean":
|
||||||
|
actual_type = bool
|
||||||
|
elif option_type == "string":
|
||||||
|
actual_type = str
|
||||||
|
elif option_type == "float":
|
||||||
|
actual_type = float
|
||||||
|
elif option_type == "integer":
|
||||||
|
actual_type = int
|
||||||
|
else:
|
||||||
|
raise Exception(f"Invalid type name \"{option_type}\".")
|
||||||
|
|
||||||
|
if plugin_name in self.plugin_defined_settings:
|
||||||
|
self.plugin_defined_settings[plugin_name][option_name] = {
|
||||||
|
"option_name": option_name,
|
||||||
|
"description": description,
|
||||||
|
"type": actual_type,
|
||||||
|
"default_value": default_value,
|
||||||
|
"on_changed_func": on_changed_func
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
self.plugin_defined_settings[plugin_name] = {option_name: {
|
||||||
|
"option_name": option_name,
|
||||||
|
"description": description,
|
||||||
|
"type": actual_type,
|
||||||
|
"default_value": default_value,
|
||||||
|
"on_changed_func": on_changed_func
|
||||||
|
}}
|
||||||
|
|
||||||
|
# user hasnt used this plugin before
|
||||||
|
if self.get("plugin_" + plugin_name, option_name) == None:
|
||||||
|
self.set("plugin_" + plugin_name, option_name, default_value)
|
||||||
|
|
||||||
def ensure_hidden_config_dir(self):
|
def ensure_hidden_config_dir(self):
|
||||||
config_dir = Path.home() / ".berry"
|
config_dir = Path.home() / ".berry"
|
||||||
@@ -19,10 +55,18 @@ class ConfigHandler:
|
|||||||
return config_dir
|
return config_dir
|
||||||
|
|
||||||
def get(self, section: str, option: str):
|
def get(self, section: str, option: str):
|
||||||
return self.config.get(section, option)
|
return self.config.get(section, option, fallback=None)
|
||||||
|
|
||||||
def set(self, section: str, option: str, new_value: str):
|
def set(self, section: str, option: str, new_value: str):
|
||||||
|
if not self.config.has_section(section):
|
||||||
|
self.config.add_section(section)
|
||||||
self.config.set(section, option, new_value)
|
self.config.set(section, option, new_value)
|
||||||
|
|
||||||
|
if section.startswith("plugin_"):
|
||||||
|
section = section.removeprefix("plugin_")
|
||||||
|
if self.plugin_defined_settings[section].get("on_changed_func", None) != None:
|
||||||
|
self.plugin_defined_settings[section]["on_changed_func"](new_value)
|
||||||
|
|
||||||
self.write_settings()
|
self.write_settings()
|
||||||
|
|
||||||
def apply_settings(self):
|
def apply_settings(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user