saving and creating new files

This commit is contained in:
2026-07-28 15:46:23 +10:00
parent 44aa152295
commit 2e80aa7553
3 changed files with 103 additions and 26 deletions

View File

@@ -64,6 +64,12 @@ class Berry(App):
yield Footer()
async def action_save(self):
await self.file_tabs.save()
async def action_new(self):
await self.file_tabs.new_file()
async def open_file(self, path: str):
self.path = pathlib.Path(path)

View File

@@ -1,6 +1,10 @@
from textual.widgets import TabbedContent, TabPane
from textual.widgets import TabbedContent, Tab, TabPane
from textual.widget import Widget
from textual.widgets._tabbed_content import ContentTabs
from textual.reactive import reactive
from textual_fspicker import FileOpen, FileSave, SelectDirectory
from widgets.text_editor import TextEditor
from widgets.home_page import HomePage
@@ -8,7 +12,9 @@ import os, pathlib
FILE_EXTENSION_LANG = {
".py": "python"
".py": "python",
".json": "json",
".md": "markdown"
}
@@ -17,23 +23,44 @@ class FileTab(TabPane):
changed = reactive(False)
def __init__(self, path: str):
if path != None:
file_name = os.path.basename(path)
else:
file_name = "New File"
super().__init__(f"[ansi_bright_green][/] {file_name}")
self.file_name = file_name
self.path = path
self.last_saved_value = True
def watch_saved(self, saved_value: bool):
if self.saved == saved_value:
if self.last_saved_value != saved_value:
self.changed = True
self.last_saved_value = saved_value
self.refresh_name()
def refresh_name(self):
icon = "[ansi_bright_green][/]" if self.saved else "[ansi_yellow][/]"
self.parent.parent.get_tab(self.id).label = f"{icon} {self.file_name}"
def update_language(self):
try:
text_editor: TextEditor = self.query_one(TextEditor)
except:
return
self.changed = True
icon = "[ansi_bright_green][/]" if self.saved else "[ansi_yellow][/]"
extension = pathlib.Path(self.path).suffix
self._title = self.render_str(f"{icon} {self.file_name}")
parent: TabbedContent = self.parent
text_editor.language = FILE_EXTENSION_LANG.get(extension)
parent.recompose()
def update_path(self, new_path: str):
self.path = new_path
self.file_name = os.path.basename(new_path)
self.saved = True
self.refresh_name()
self.update_language()
def on_text_area_changed(self, event: TextEditor.Changed):
self.saved = False
@@ -52,7 +79,35 @@ class FileTabs(TabbedContent):
}
"""
async def save(self) -> None:
async def clean_up_tabs(self, new_path: str):
if self.tab_count > 0:
if isinstance(self.active_pane, HomeTab):
self.remove_pane(self.active)
else:
if not self.active_pane.changed:
await self.remove_pane(self.active)
for tab in self.query(TabPane):
if isinstance(self.active_pane, HomeTab):
continue
if tab.path == new_path:
self.active = tab.id
return False
return True
async def new_file(self):
new_tab = FileTab(None)
await self.add_pane(new_tab)
text_editor = TextEditor()
await new_tab.mount(text_editor)
self.active = new_tab.id
text_editor.focus()
async def save_as(self):
if self.tab_count == 0:
return
@@ -65,6 +120,35 @@ class FileTabs(TabbedContent):
if text_editor.read_only:
return
def callback(path: str | None):
if path == None:
return
with open(path, "w") as f:
f.write(text_editor.text)
file_tab.update_path(path)
await self.app.push_screen(FileSave(), callback=callback)
async def save(self):
if self.tab_count == 0:
return
if not isinstance(self.active_pane, FileTab):
return
file_tab: FileTab = self.active_pane
text_editor: TextEditor = file_tab.query_one(TextEditor)
if text_editor.read_only:
return
if file_tab.path == None: # new file
await self.save_as()
return
with open(file_tab.path, "w") as f:
f.write(text_editor.text)
@@ -74,16 +158,8 @@ class FileTabs(TabbedContent):
await self.add_pane(HomeTab())
async def open_file(self, path: str) -> None:
if self.tab_count > 0:
if isinstance(self.active_pane, HomeTab):
self.remove_pane(self.active)
else:
if not self.active_pane.changed:
self.remove_pane(self.active)
for tab in self.query(TabPane):
if tab.path == path:
self.active = tab.id
opened_new_tab = await self.clean_up_tabs(path)
if not opened_new_tab:
return
new_pane = FileTab(path)

View File

@@ -63,11 +63,6 @@ class HomePage(Vertical):
}
"""
@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()