Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Biscuit Workspaces #426

Merged
merged 5 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .biscuit/workspace.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# workspace I use for biscuit development (@tomlin7)

dirs = ["D:/biscuit", "D:/biscuit-extensions"]
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "biscuit-editor"
version = "2.99.85"
version = "2.99.95"
description = "A lightweight, fast, and extensible code editor with a growing community"
authors = ["Billy <[email protected]>"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion src/biscuit/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "2.99.85"
__version__ = "2.99.95"
__version_info__ = tuple([int(num) for num in __version__.split(".")])

from .main import *
23 changes: 23 additions & 0 deletions src/biscuit/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,29 @@ def save_all(self, *_) -> None:
if editor.content.editable:
editor.save()

def save_workspace_as(self, *_) -> None:
if path := asksaveasfilename(
title="Save Workspace As...",
initialfile="workspace.toml",
filetypes=[(".toml")],
):
self.base.workspaces.save(path)

def add_folder_to_workspace(self, *_) -> None:
path = filedialog.askdirectory()
if not path or not os.path.isdir(path):
return
self.base.workspaces.add_dir(path)

def open_workspace(self, *_) -> None:
path = filedialog.askopenfilename()
if not path or not os.path.isfile(path):
return
self.base.workspaces.load(path)

def close_workspace(self, *_) -> None:
self.base.workspaces.close()

def open_settings(self, *_) -> None:
self.base.open_settings()

Expand Down
6 changes: 6 additions & 0 deletions src/biscuit/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .history import HistoryManager
from .language import LanguageServerManager
from .settings import Settings
from .workspaces import WorkspaceManager


class ConfigManager:
Expand Down Expand Up @@ -58,6 +59,7 @@ def setup_configs(self) -> None:
self.system = SysInfo(self)
self.settings = Settings(self)
self.history = HistoryManager(self)
self.workspaces = WorkspaceManager(self)

self.resources = self.settings.resources
self.bindings = self.settings.bindings
Expand Down Expand Up @@ -120,3 +122,7 @@ def set_tab_spaces(self, spaces: int) -> None:
if e.content and e.content.editable:
e.content.text.set_tab_size(spaces)
self.statusbar.set_spaces(spaces)

@property
def active_workspace(self):
return self.workspaces.workspace
23 changes: 23 additions & 0 deletions src/biscuit/events.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import multiprocessing
import os
import subprocess
import sys
Expand Down Expand Up @@ -239,6 +240,28 @@ def open_in_new_window(self, dir: str) -> None:
def open_new_window(self) -> None:
subprocess.Popen([sys.executable, sys.argv[0]])

# from .main import get_app_instance
# app = get_app_instance()
# multiprocessing.freeze_support()
# multiprocessing.Process(target=app.run).start()

def workspace_opened(self) -> None:
workspace = self.active_workspace
try:
self.open_directory(workspace.dirs[0])
for dir in workspace.dirs[1:]:
self.open_in_new_window(dir)
except Exception as e:
self.logger.error(f"Opening workspace failed: {e}")
self.notifications.error("Opening workspace failed: see logs")

def workspace_changed(self, dir: str) -> None:
self.open_in_new_window(dir)

def workspace_closed(self) -> None:
self.close_active_directory()
# TODO add cli args to flag new windows opened by workspace and close them

def toggle_terminal(self) -> None:
self.panel.switch_to_terminal()
self.contentpane.toggle_panel()
Expand Down
11 changes: 10 additions & 1 deletion src/biscuit/layout/menubar/menubar.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ def add_file_menu(self) -> None:
self.file_menu.add_command("Open Recent File...", events.open_recent_file)
self.file_menu.add_command("Open Recent Folder...", events.open_recent_dir)
self.file_menu.add_separator()
self.file_menu.add_command("Open workspace...", events.open_workspace)
self.file_menu.add_command(
"Add Folder to Workspace...", events.add_folder_to_workspace
)
self.file_menu.add_command("Save Workspace As...", events.save_workspace_as)
self.file_menu.add_command("Close Workspace", events.close_workspace)
self.file_menu.add_separator()
self.file_menu.add_command("Save", events.save_file)
self.file_menu.add_command("Save As...", events.save_file_as)
self.file_menu.add_command("Save All", events.save_all)
Expand Down Expand Up @@ -165,7 +172,9 @@ def add_edit_menu(self) -> None:
self.edit_menu.add_command("Change Language Mode", events.change_language_mode)
self.edit_menu.add_checkable("Word Wrap", events.toggle_wordwrap)
self.edit_menu.add_checkable("Block Cursor", events.toggle_block_cursor)
self.edit_menu.add_checkable("Toggle Relative Line Numbering", events.toggle_relative_line_numbering)
self.edit_menu.add_checkable(
"Toggle Relative Line Numbering", events.toggle_relative_line_numbering
)

def add_view_menu(self) -> None:
events = self.events
Expand Down
15 changes: 9 additions & 6 deletions src/biscuit/settings/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,15 @@ def generate_actionset(self) -> None:
)

def setup_icon(self) -> None:
self.base.call(
"wm",
"iconphoto",
self.base._w,
tk.PhotoImage(file=self.resources.get_res_path_platform("icon.png")),
)
try:
self.base.call(
"wm",
"iconphoto",
self.base._w,
tk.PhotoImage(file=self.resources.get_res_path_platform("icon.png")),
)
except tk.TclError:
pass

def setup_font(self) -> None:
try:
Expand Down
3 changes: 3 additions & 0 deletions src/biscuit/workspaces/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .loader import WorkspaceLoader
from .manager import WorkspaceManager
from .workspace import Workspace
32 changes: 32 additions & 0 deletions src/biscuit/workspaces/loader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from __future__ import annotations

import typing

import toml

from .workspace import Workspace

if typing.TYPE_CHECKING:
from .manager import WorkspaceManager


class WorkspaceLoader:
def __init__(self, manager: WorkspaceManager):
self.manager = manager
self.base = manager.base

def load(self, path):
with open(path) as f:
data = toml.load(f)
self.open_workspace(Workspace(self, path, data["dirs"]))

def dump_modified(self, path: str, dirs: list[str]):
with open(path, "w") as f:
toml.dump({"dirs": dirs}, f)

def open_workspace(self, workspace: Workspace):
self.manager.set_workspace(workspace)

def save(self, active_workspace: Workspace, path: str):
with open(path, "w") as f:
toml.dump(active_workspace.export(), f)
40 changes: 40 additions & 0 deletions src/biscuit/workspaces/manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from __future__ import annotations

import typing

from .loader import WorkspaceLoader
from .workspace import Workspace

if typing.TYPE_CHECKING:
from biscuit.app import App


class WorkspaceManager:
def __init__(self, base: App):
self.base = base
self.workspace = None

self.loader = WorkspaceLoader(self)

def set_workspace(self, workspace: Workspace):
self.workspace = workspace
self.base.workspace_opened()

def add_dir(self, dir: str):
if not self.workspace:
self.set_workspace(Workspace(self, "workspace.toml", [dir]))
self.set_workspace(Workspace(self, "workspace.toml", [dir]))
return

self.workspace.add_dir(dir)
self.base.workspace_changed(dir)

def load(self, path: str):
self.loader.load(path)

def save(self, path: str):
self.loader.save(path)

def close(self):
self.workspace = None
self.base.workspace_closed()
21 changes: 21 additions & 0 deletions src/biscuit/workspaces/workspace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from __future__ import annotations

import typing
from typing import List

if typing.TYPE_CHECKING:
from .loader import WorkspaceLoader


class Workspace:
def __init__(self, loader: WorkspaceLoader, path: str, dirs: List[str]):
self.loader = loader
self.path = path
self.dirs = dirs

def add_dir(self, dir: str):
self.dirs.append(dir)
self.loader.dump_modified(self.path, self.dirs)

def export(self):
return {"dirs": self.dirs}
Loading