Skip to content
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
38 changes: 22 additions & 16 deletions config/settings.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
theme="default"
font="firacode"
font_size=13

theme = "dark"
font = "Fira Code"
font_size = 13
cursor_style = "line"
auto_save = false
tab_size = 4
show_minimap = false
render_indent_guides = false
show_breadcrumbs = false
show_line_numbers = false

[testing]
font_size=14
tab_size=4
theme="light"
auto_save=false
auto_closing_pairs=true
auto_closing_delete=true
auto_indent=true
auto_surround=true
cursor_style="line"
word_wrap=false
exclude_dirs=[".git"]
exclude_types=["__pycache__"]
font_size = 14
tab_size = 4
theme = "light"
auto_save = false
auto_closing_pairs = true
auto_closing_delete = true
auto_indent = true
auto_surround = true
cursor_style = "line"
word_wrap = false
exclude_dirs = [ ".git",]
exclude_types = [ "__pycache__",]
27 changes: 6 additions & 21 deletions src/biscuit/common/fixedstack.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import annotations

import os
import sqlite3


class FixedSizeStack:
Expand Down Expand Up @@ -45,27 +44,13 @@ def __len__(self):
def clear(self):
self.stack.clear()

def dump_sqlite(self, cursor: sqlite3.Cursor) -> None:
"""Dump the stack to the database.
def dump(self) -> None:
"""Dump the stack to the file."""
return self.stack

Args:
cursor (sqlite3.Cursor): the cursor to the database"""

# print(self.name, self.stack)
cursor.execute(f"DELETE FROM {self.name};")
cursor.executemany(
f"INSERT INTO {self.name} (path) VALUES (?);",
[(item,) for item in self.stack],
)

def load_sqlite(self, cursor: sqlite3.Cursor) -> FixedSizeStack:
"""Load the stack from the database.

Args:
cursor (sqlite3.Cursor): the cursor to the database"""

cursor.execute(f"SELECT path FROM {self.name};")
self.stack = [item[0] for item in cursor.fetchall()]
def load(self, data) -> FixedSizeStack:
"""Load the stack from the file."""
self.stack = data
return self

def open_item(self, item):
Expand Down
6 changes: 6 additions & 0 deletions src/biscuit/common/ui/scrollableframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ def _configure_canvas(self, event) -> None:
def _on_mousewheel(self, event) -> None:
self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")

def bind_scroll(self, widget):
widget.bind("<MouseWheel>", self._on_mousewheel)
for child in widget.winfo_children():
self.bind_scroll(child)

def add(self, content, *args, **kwargs) -> None:
content.pack(in_=self.content, *args, **kwargs)
self.items.append(content)
self.bind_scroll(content)
43 changes: 43 additions & 0 deletions src/biscuit/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os
import sys
import typing
import tkinter as tk
from pathlib import Path

from biscuit.layout.statusbar.statusbar import Statusbar
Expand Down Expand Up @@ -154,7 +155,49 @@ 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)

def refresh_editors(self) -> None:
self.tab_spaces = self.config.tab_size
self.wrap_words = self.config.word_wrap
self.block_cursor = self.config.cursor_style == "block"
self.relative_line_numbers = self.config.relative_line_numbers
self.show_minimap = self.config.show_minimap
self.show_linenumbers = self.config.show_linenumbers
self.theme = self.config.theme

for editor in self.editorsmanager.active_editors:
if editor.content and editor.content.editable:
editor.content.text.configure(
tabs=(self.settings.font.measure(" " * self.tab_spaces),),
blockcursor=self.block_cursor,
wrap=tk.WORD if self.wrap_words else tk.NONE,
**self.theme.editors.text
)
editor.content.text.relative_line_numbers = self.relative_line_numbers
editor.content.linenumbers.redraw()

if self.show_minimap:
editor.content.minimap.grid()
else:
editor.content.minimap.grid_remove()

if self.show_linenumbers:
editor.content.linenumbers.grid()
else:
editor.content.linenumbers.grid_remove()

if self.config.show_breadcrumbs:
self.editorsmanager.editorsbar.show_breadcrumbs()
else:
self.editorsmanager.editorsbar.hide_breadcrumbs()

# Update indent guides for all active text editors
# This requires manually triggering an update/refresh in the text widget
# providing the render_indent_guides flag is used in update_indent_guides
for editor in self.editorsmanager.active_editors:
if editor.content and editor.content.editable:
editor.content.text.refresh()

@property
def active_workspace(self):
return self.workspaces.workspace
2 changes: 1 addition & 1 deletion src/biscuit/editor/text/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ def diagnostic_hover(self, severity: int) -> str:
self.base.diagnostic.show(self, start, message, severity)

def update_indent_guides(self) -> None:
if self.minimalist:
if self.minimalist or not self.base.config.render_indent_guides:
return

self.tag_remove("indent_guide", "1.0", "end")
Expand Down
1 change: 0 additions & 1 deletion src/biscuit/gui.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import platform
import sqlite3

from tkinterDnD import Tk

Expand Down
43 changes: 20 additions & 23 deletions src/biscuit/history.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,34 @@
from __future__ import annotations

import os
import sqlite3
import toml
import typing

from .common import ActionSet, FixedSizeStack

if typing.TYPE_CHECKING:
from . import App


class HistoryManager:
"""Manages the history of opened files and folders.

Manages the history of opened files and folders.
Uses an sqlite3 database to store the history.
Uses a TOML file to store the history.
"""

def __init__(self, base: App) -> None:
self.base = base
self.path = self.base.datadir / "history.db"

self.db = sqlite3.connect(self.path)
self.cursor = self.db.cursor()
self.path = self.base.datadir / "history.toml"
self.history = {}

self.cursor.executescript(
"""
CREATE TABLE IF NOT EXISTS file_history (path TEXT NOT NULL);
CREATE TABLE IF NOT EXISTS folder_history (path TEXT NOT NULL);
"""
)
if self.path.exists():
try:
self.history = toml.load(self.path)
except Exception as e:
self.base.logger.error(f"History load failed: {e}")
self.history = {}

self.file_history = FixedSizeStack(self, "file_history").load_sqlite(
self.cursor
)
self.folder_history = FixedSizeStack(self, "folder_history").load_sqlite(
self.cursor
)
self.file_history = FixedSizeStack(self, "file_history").load(self.history.get("file_history", []))
self.folder_history = FixedSizeStack(self, "folder_history").load(self.history.get("folder_history", []))

def generate_actionsets(self) -> None:
self.base.palette.register_actionset(
Expand All @@ -53,9 +45,14 @@ def register_folder_history(self, path: str) -> None:
self.folder_history.push(path)

def dump(self) -> None:
self.file_history.dump_sqlite(self.cursor)
self.folder_history.dump_sqlite(self.cursor)
self.db.commit()
try:
with open(self.path, 'w') as f:
toml.dump({
"file_history": self.file_history.dump(),
"folder_history": self.folder_history.dump(),
}, f)
except Exception as e:
self.base.logger.error(f"History save failed: {e}")

def clear_history(self) -> None:
self.file_history.clear()
Expand Down
81 changes: 35 additions & 46 deletions src/biscuit/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,54 @@

from __future__ import annotations

import sqlite3 as sq
import typing

if typing.TYPE_CHECKING:
from biscuit import App

import toml

class SessionManager:
def __init__(self, base: App):
self.base = base
self.session_path = self.base.datadir / "session.toml"
self.session = {}

# Initialize the session database connection
self.base_dir = self.base.datadir
self.session_db_path = self.base.datadir / "session.db"
self.db = sq.connect(self.session_db_path)
self.cursor = self.db.cursor()

# Ensure the session table is created
self._create_session_table()

def _create_session_table(self):
self.cursor.executescript(
"""
CREATE TABLE IF NOT EXISTS session (
id INTEGER PRIMARY KEY AUTOINCREMENT,
file_path TEXT,
folder_path TEXT
);
"""
)
if self.session_path.exists():
try:
self.session = toml.load(self.session_path)
except Exception as e:
self.base.notifications.error(f"Failed to load session: {e}")
self.session = {}

def restore_session(self):
opened_files = []
active_directory = ""
if not self.session:
return

self.cursor.execute("SELECT * FROM session")
for row in self.cursor.fetchall():
if row[1]:
opened_files.append(row[1])
elif row[2]:
active_directory = row[2]
active_directory = self.session.get("active_directory")
opened_files = self.session.get("opened_files", [])

self.base.open_directory(active_directory)
if active_directory:
self.base.open_directory(active_directory)

self.base.open_files(opened_files)

def clear_session(self):
self.cursor.execute("DELETE FROM session")
self.session = {}
if self.session_path.exists():
try:
# Create empty file or just empty dict
with open(self.session_path, 'w') as f:
toml.dump({}, f)
except Exception as e:
self.base.logger.error(f"Failed to clear session: {e}")

def save_session(self, opened_files, active_directory):
for file_path in opened_files:
self.cursor.execute(
"INSERT INTO session (file_path) VALUES (?)", (file_path,)
)

self.cursor.execute(
"INSERT INTO session (folder_path) VALUES (?)", (active_directory,)
)

self.db.commit()
self.session = {
"active_directory": active_directory,
"opened_files": opened_files
}
try:
with open(self.session_path, 'w') as f:
toml.dump(self.session, f)
except Exception as e:
self.base.logger.error(f"Failed to save session: {e}")

def close(self):
self.db.close()
pass
Loading
Loading