saving and creating new files
This commit is contained in:
@@ -64,6 +64,12 @@ class Berry(App):
|
|||||||
|
|
||||||
yield Footer()
|
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):
|
async def open_file(self, path: str):
|
||||||
self.path = pathlib.Path(path)
|
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.reactive import reactive
|
||||||
|
|
||||||
|
from textual_fspicker import FileOpen, FileSave, SelectDirectory
|
||||||
|
|
||||||
from widgets.text_editor import TextEditor
|
from widgets.text_editor import TextEditor
|
||||||
from widgets.home_page import HomePage
|
from widgets.home_page import HomePage
|
||||||
|
|
||||||
@@ -8,7 +12,9 @@ import os, pathlib
|
|||||||
|
|
||||||
|
|
||||||
FILE_EXTENSION_LANG = {
|
FILE_EXTENSION_LANG = {
|
||||||
".py": "python"
|
".py": "python",
|
||||||
|
".json": "json",
|
||||||
|
".md": "markdown"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -17,23 +23,44 @@ class FileTab(TabPane):
|
|||||||
changed = reactive(False)
|
changed = reactive(False)
|
||||||
|
|
||||||
def __init__(self, path: str):
|
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}")
|
super().__init__(f"[ansi_bright_green][/] {file_name}")
|
||||||
self.file_name = file_name
|
self.file_name = file_name
|
||||||
self.path = path
|
self.path = path
|
||||||
|
self.last_saved_value = True
|
||||||
|
|
||||||
def watch_saved(self, saved_value: bool):
|
def watch_saved(self, saved_value: bool):
|
||||||
if self.saved == saved_value:
|
if self.last_saved_value != saved_value:
|
||||||
return
|
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][/]"
|
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}")
|
def update_language(self):
|
||||||
parent: TabbedContent = self.parent
|
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):
|
def on_text_area_changed(self, event: TextEditor.Changed):
|
||||||
self.saved = False
|
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:
|
if self.tab_count == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -65,6 +120,35 @@ class FileTabs(TabbedContent):
|
|||||||
if text_editor.read_only:
|
if text_editor.read_only:
|
||||||
return
|
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:
|
with open(file_tab.path, "w") as f:
|
||||||
f.write(text_editor.text)
|
f.write(text_editor.text)
|
||||||
|
|
||||||
@@ -74,17 +158,9 @@ class FileTabs(TabbedContent):
|
|||||||
await self.add_pane(HomeTab())
|
await self.add_pane(HomeTab())
|
||||||
|
|
||||||
async def open_file(self, path: str) -> None:
|
async def open_file(self, path: str) -> None:
|
||||||
if self.tab_count > 0:
|
opened_new_tab = await self.clean_up_tabs(path)
|
||||||
if isinstance(self.active_pane, HomeTab):
|
if not opened_new_tab:
|
||||||
self.remove_pane(self.active)
|
return
|
||||||
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
|
|
||||||
|
|
||||||
new_pane = FileTab(path)
|
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):
|
def compose(self):
|
||||||
with Horizontal(id="banner"):
|
with Horizontal(id="banner"):
|
||||||
yield Rule()
|
yield Rule()
|
||||||
|
|||||||
Reference in New Issue
Block a user