saving and creating new files
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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):
|
||||
file_name = os.path.basename(path)
|
||||
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:
|
||||
return
|
||||
if self.last_saved_value != saved_value:
|
||||
self.changed = True
|
||||
self.last_saved_value = saved_value
|
||||
|
||||
self.refresh_name()
|
||||
|
||||
self.changed = True
|
||||
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}"
|
||||
|
||||
self._title = self.render_str(f"{icon} {self.file_name}")
|
||||
parent: TabbedContent = self.parent
|
||||
def update_language(self):
|
||||
try:
|
||||
text_editor: TextEditor = self.query_one(TextEditor)
|
||||
except:
|
||||
return
|
||||
|
||||
parent.recompose()
|
||||
extension = pathlib.Path(self.path).suffix
|
||||
|
||||
text_editor.language = FILE_EXTENSION_LANG.get(extension)
|
||||
|
||||
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,17 +158,9 @@ 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
|
||||
return
|
||||
opened_new_tab = await self.clean_up_tabs(path)
|
||||
if not opened_new_tab:
|
||||
return
|
||||
|
||||
new_pane = FileTab(path)
|
||||
|
||||
|
||||
@@ -62,12 +62,7 @@ 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()
|
||||
|
||||
Reference in New Issue
Block a user