continued adding support for other text editors, added a home screen
This commit is contained in:
103
home_page.py
Normal file
103
home_page.py
Normal file
@@ -0,0 +1,103 @@
|
||||
from textual.containers import Center, Vertical, Horizontal
|
||||
from textual.widgets import Rule, Static
|
||||
from textual import on
|
||||
|
||||
from textualeffects.widgets import EffectLabel
|
||||
from textualeffects.effects import effects
|
||||
from terminaltexteffects.utils.graphics import Color
|
||||
|
||||
|
||||
class HomePage(Vertical):
|
||||
LOGO = r""" ______ ______ ______ ______ __ __
|
||||
/\ == \ /\ ___\ /\ == \ /\ == \ /\ \_\ \
|
||||
\ \ __< \ \ __\ \ \ __< \ \ __< \ \____ \
|
||||
\ \_____\ \ \_____\ \ \_\ \_\ \ \_\ \_\ \/\_____\
|
||||
\/_____/ \/_____/ \/_/ /_/ \/_/ /_/ \/_____/
|
||||
|
||||
"""
|
||||
|
||||
DEFAULT_CSS = """
|
||||
HomePage {
|
||||
content-align: center top;
|
||||
|
||||
Static {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#banner {
|
||||
height: 5; # probs will need to be updated
|
||||
margin-bottom: 1;
|
||||
|
||||
Rule {
|
||||
color: $surface-lighten-2;
|
||||
height: 100%;
|
||||
content-align: center middle;
|
||||
margin: 0 3;
|
||||
}
|
||||
|
||||
EffectLabel {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#bindings {
|
||||
Horizontal {
|
||||
max-width: 50;
|
||||
width: 50%;
|
||||
margin-top: 1;
|
||||
height: 1;
|
||||
|
||||
.bind-name {
|
||||
width: 85%;
|
||||
}
|
||||
.bind-keys {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
Static {
|
||||
text-align: left;
|
||||
link-background: transparent;
|
||||
link-color: $primary;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
@on(EffectLabel.EffectFinished)
|
||||
def restart_effect(self):
|
||||
self.banner_label.run_worker(self.banner_label.run_effect, exclusive=True)
|
||||
|
||||
def compose(self):
|
||||
with Horizontal(id="banner"):
|
||||
yield Rule()
|
||||
self.banner_label = EffectLabel(self.LOGO, effect="Highlight", config={
|
||||
"final_gradient_stops": [Color("#f263ff"), Color("#946ff2")],
|
||||
"cycles": 0
|
||||
})
|
||||
yield self.banner_label
|
||||
yield Rule()
|
||||
|
||||
yield Static("[dim]The text editor that no one asked for and didn't need.[/]")
|
||||
|
||||
# bindings
|
||||
with Center(id="bindings"):
|
||||
binds = self.app.bindings
|
||||
|
||||
with Horizontal():
|
||||
yield Static("[b] New file[/]", classes="bind-name")
|
||||
yield Static(f"[@click=app.new]{binds["new"]}[/]", classes="bind-keys")
|
||||
|
||||
with Horizontal():
|
||||
yield Static("[b] Open file[/]", classes="bind-name")
|
||||
yield Static(f"[@click=app.open]{binds["open"]}[/]", classes="bind-keys")
|
||||
|
||||
with Horizontal():
|
||||
yield Static("[b] Settings[/]", classes="bind-name")
|
||||
yield Static(f"[@click=app.settings]{binds["settings"]}[/]", classes="bind-keys")
|
||||
|
||||
64
main.py
64
main.py
@@ -8,6 +8,8 @@ from textual_fspicker import FileOpen, FileSave
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from home_page import HomePage
|
||||
|
||||
from assets.theme_mappings import theme_mappings
|
||||
from plugin_loader import PluginLoader
|
||||
from settings import SettingsScreen
|
||||
@@ -32,19 +34,32 @@ class Berry(App):
|
||||
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")
|
||||
]
|
||||
|
||||
|
||||
def __init__(self, path: str):
|
||||
self.config_handler = ConfigHandler(self)
|
||||
|
||||
self.bindings = eval(self.config_handler.get("editor", "bindings"))
|
||||
|
||||
super().__init__()
|
||||
self.path = path
|
||||
self.config_handler = ConfigHandler(self)
|
||||
|
||||
self.BINDINGS = (
|
||||
Binding(self.bindings["new"], "new", "New File"),
|
||||
Binding(self.bindings["open"], "open", "Open File"),
|
||||
Binding(self.bindings["save"], "save", "Save File"),
|
||||
Binding(self.bindings["save-as"], "save_as", "Save File As..."),
|
||||
Binding(self.bindings["find"], "find", "Find and Replace"),
|
||||
Binding(self.bindings["settings"], "settings", "Settings"),
|
||||
)
|
||||
|
||||
for binding in self.BINDINGS:
|
||||
self._bindings._add_binding(binding)
|
||||
|
||||
self.refresh_bindings()
|
||||
|
||||
self.current_editor = None
|
||||
self.file_tabs = {}
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Header()
|
||||
@@ -59,14 +74,18 @@ class Berry(App):
|
||||
yield CustomDirectoryTree(self.path, id="directory")
|
||||
|
||||
with Vertical(id="editor"):
|
||||
first_tab = Tab("New File")
|
||||
first_tab.file_path = None
|
||||
first_tab = Tab("Home")
|
||||
first_tab.file_path = "berry://home"
|
||||
self.file_tabs["berry://home"] = first_tab
|
||||
|
||||
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"))))
|
||||
|
||||
with Vertical() as editor:
|
||||
yield HomePage()
|
||||
self.current_editor = editor
|
||||
|
||||
#if os.name == "nt":
|
||||
#with Vertical(id="console-container"):
|
||||
@@ -201,7 +220,9 @@ class Berry(App):
|
||||
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 = TextArea.code_editor(placeholder="This file is empty.", theme="css", disabled=True, soft_wrap=bool(int(self.config_handler.get("editor", "word_wrap"))), show_line_numbers=bool(int(self.config_handler.get("editor", "line_numbers"))))
|
||||
|
||||
self.current_editor.mount(code_editor)
|
||||
|
||||
code_editor.language = theme_mappings.get(file_extension, None)
|
||||
|
||||
@@ -215,10 +236,12 @@ class Berry(App):
|
||||
|
||||
code_editor.focus()
|
||||
|
||||
def open_editor(self, file_extension: str, file_content: str):
|
||||
def open_editor(self, file_extension: str, file_content: bytes):
|
||||
default_editors: dict = eval(self.config_handler.get("editor", "default_editors"))
|
||||
editor_for_file = default_editors.get(file_extension, None)
|
||||
|
||||
self.current_editor.remove_children()
|
||||
|
||||
if not editor_for_file:
|
||||
self.open_text_editor(file_content, file_extension)
|
||||
|
||||
@@ -230,8 +253,12 @@ class Berry(App):
|
||||
else:
|
||||
self.open_file = getattr(event.tab, "file_path")
|
||||
|
||||
if self.open_file and self.open_file.startswith(r"berry://"):
|
||||
return
|
||||
|
||||
self.switching = True
|
||||
|
||||
|
||||
content = b""
|
||||
file_extension = ""
|
||||
|
||||
@@ -265,8 +292,6 @@ class Berry(App):
|
||||
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
|
||||
@@ -301,10 +326,9 @@ class Berry(App):
|
||||
|
||||
self.open_file = None
|
||||
self.switching = True
|
||||
code_editor: TextArea = self.query_one("#code-editor")
|
||||
|
||||
code_editor.disabled = False
|
||||
code_editor.text = ""
|
||||
# open empty editor
|
||||
self.open_editor("", b"")
|
||||
|
||||
def done_saving(self, result):
|
||||
if result is None: return
|
||||
@@ -342,8 +366,6 @@ class Berry(App):
|
||||
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
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
"name": "Markdown Reader",
|
||||
"author": "SpookyDervish",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"dependencies": []
|
||||
}
|
||||
10
settings.py
10
settings.py
@@ -1,5 +1,5 @@
|
||||
from textual.screen import ModalScreen
|
||||
from textual.widgets import Label, Select, TabbedContent, TabPane, Switch, Input, Rule, Static
|
||||
from textual.widgets import Label, Select, TextArea, TabbedContent, TabPane, Switch, Input, Rule, Static
|
||||
from textual.containers import Vertical, HorizontalGroup, VerticalGroup, VerticalScroll
|
||||
from textual.binding import Binding
|
||||
|
||||
@@ -70,11 +70,15 @@ class SettingsScreen(ModalScreen):
|
||||
self.dismiss()
|
||||
|
||||
def on_switch_changed(self, event: Switch.Changed):
|
||||
text_area = self.app.current_editor.query_one_optional(TextArea)
|
||||
|
||||
if event.switch.id == "word-wrap":
|
||||
self.app.query_one("#code-editor").soft_wrap = event.value
|
||||
if text_area:
|
||||
text_area.soft_wrap = event.value
|
||||
self.app.config_handler.set("editor", "word_wrap", str(int(event.value)))
|
||||
elif event.switch.id == "line-numbers":
|
||||
self.app.query_one("#code-editor").show_line_numbers = event.value
|
||||
if text_area:
|
||||
text_area.show_line_numbers = event.value
|
||||
self.app.config_handler.set("editor", "line_numbers", str(int(event.value)))
|
||||
elif event.switch.id == "plugins-enabled":
|
||||
self.app.config_handler.set("plugins", "enabled", str(int(event.value)))
|
||||
|
||||
@@ -76,7 +76,9 @@ class ConfigHandler:
|
||||
self.write_settings()
|
||||
|
||||
def apply_settings(self):
|
||||
self.app.query_one("#code-editor").soft_wrap = bool(int(self.get("editor", "word_wrap")))
|
||||
if self.app.current_editor and self.app.current_editor.id == "code-editor":
|
||||
self.app.current_editor.soft_wrap = bool(int(self.get("editor", "word_wrap")))
|
||||
|
||||
self.app.theme = self.get("appearance", "colour_theme")
|
||||
|
||||
def write_settings(self):
|
||||
@@ -94,7 +96,15 @@ class ConfigHandler:
|
||||
self.config["editor"] = {
|
||||
"word_wrap": "0",
|
||||
"line_numbers": "1",
|
||||
"default_editors": {}
|
||||
"default_editors": {},
|
||||
"bindings": {
|
||||
"open": "ctrl+o",
|
||||
"new": "ctrl+n",
|
||||
"save": "ctrl+s",
|
||||
"save-as": "ctrl+shift+s",
|
||||
"find": "ctrl+f",
|
||||
"settings": "ctrl+f1"
|
||||
}
|
||||
}
|
||||
self.config["plugins"] = {
|
||||
"enabled": "1",
|
||||
|
||||
Reference in New Issue
Block a user