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

Code folding #92

Merged
merged 5 commits into from
Jul 26, 2023
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
5 changes: 4 additions & 1 deletion biscuit/core/components/editors/editor.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from biscuit.core.components.utils import Frame
from biscuit.core.components.utils import Frame, IconButton


class BaseEditor(Frame):
Expand All @@ -20,5 +20,8 @@ def __init__(self, master, path=None, exists=None, editable=True, *args, **kwarg

self.__buttons__ = ()

def create_buttons(self, editorbar):
self.__buttons__ = [IconButton(editorbar, *button) for button in self.__buttons__]

def save(self, *_):
...
122 changes: 122 additions & 0 deletions biscuit/core/components/editors/texteditor/codefolding_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import tkinter as tk
from tkinter import INSERT, NE, Canvas, Menubutton
from tkinter.font import Font


class LineNumbers(Canvas):
def __init__(self, master, text=None, *args, **kwargs):
super().__init__(master, *args, **kwargs)
self.config(width=50, bd=0, highlightthickness=0)
self.text = text
self.text.config(bd=0, highlightthickness=0)
self.text.tag_config("sel", background="#48484f", foreground="#e1e1e6")
self.text.bind("<Configure>", self.redraw)
self.text.bind("<<Change>>", self.redraw)

def attach(self, text):
self.text = text

def set_bar_width(self, width):
self.configure(width=width)

def get_indentation_level(self, line):
"""Get the indentation level of a given line."""
return len(line) - len(line.lstrip())

def redraw(self, *_):
self.delete(tk.ALL)

prev_indent = 0
i = self.text.index("@0,0")
while True:
dline = self.text.dlineinfo(i)
if dline is None:
break

y = dline[1]
linenum = str(i).split(".")[0]

# Get the text content of the current line
line_content = self.text.get(f"{linenum}.0", f"{linenum}.end")
current_indent = self.get_indentation_level(line_content)

# Determine if the current line has more indentation than the previous line
if current_indent > prev_indent:
line_num_with_indent = f"+ {linenum}"
elif current_indent < prev_indent:
line_num_with_indent = f"- {linenum}"
else:
line_num_with_indent = linenum

# to highlight the current line
curline = self.text.dlineinfo(tk.INSERT)
cur_y = curline[1] if curline else None

if not cur_y:
i = self.text.index(f"{i}+1line")
continue

if y == cur_y:
self.create_text(40, y, anchor=tk.NE, text=line_num_with_indent, font=("Consolas", 14), fill="#83838f", tag=i)
else:
self.create_text(40, y, anchor=tk.NE, text=line_num_with_indent, font=("Consolas", 14), fill="#525259", tag=i)


# Update the previous indentation level
prev_indent = current_indent
i = self.text.index(f"{i}+1line")

class Text(tk.Text):
def __init__(self, master=None, **kw):
super().__init__(master, **kw)
self.mark_set('input', 'insert')
self.mark_gravity('input', 'left')

self._orig = self._w + "_orig"
self.tk.call("rename", self._w, self._orig)
self.tk.createcommand(self._w, self._proxy)

def _proxy(self, *args):
if args[0] == 'get' and (args[1] == tk.SEL_FIRST and args[2] == tk.SEL_LAST) and not self.tag_ranges(tk.SEL):
return
if args[0] == 'delete' and (args[1] == tk.SEL_FIRST and args[2] == tk.SEL_LAST) and not self.tag_ranges(tk.SEL):
return

cmd = (self._orig,) + args
result = self.tk.call(cmd)

if (args[0] in ("insert", "replace", "delete") or args[0:3] == ("mark", "set", "insert")
or args[0:2] == ("xview", "moveto") or args[0:2] == ("yview", "moveto")
or args[0:2] == ("xview", "scroll") or args[0:2] == ("yview", "scroll")):
self.event_generate("<<Change>>", when="tail")

return result


class ExampleApp:
def __init__(self, root):
self.font = ("Consolas", 14)

self.text_widget = Text(root, wrap=tk.NONE, font=self.font, bg="#2e2e32", fg="#e1e1e6")
self.line_numbers = LineNumbers(root, text=self.text_widget, bg="#2e2e32")

self.line_numbers.pack(side=tk.LEFT, fill=tk.Y)
self.text_widget.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

# Sample text with indentation for testing code folding
sample_code = """\
def foo():
print("Hello,")
print("World!")
if True:
print("This is a nested block.")
print("Indented lines are foldable.")
print("Code folding based on indentation.")
"""
self.text_widget.insert(tk.END, sample_code)
self.line_numbers.redraw()

if __name__ == "__main__":
root = tk.Tk()
app = ExampleApp(root)
root.mainloop()
9 changes: 4 additions & 5 deletions biscuit/core/components/games/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def register_game(game):

class Game(Frame):
"""
responsible for picking the right game
Responsible for picking the right game

name - name of game to opened
"""
Expand All @@ -46,12 +46,11 @@ def __init__(self, master, name, *args, **kwargs):
self.exists = False
self.diff = False
self.showpath = False
self.content = None

self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
self.game = get_game(name=name)(self)
self.game.grid(row=0, column=0, sticky=tk.NSEW)
self.content = get_game(name=name)(self)
self.content.grid(row=0, column=0, sticky=tk.NSEW)

def focus(self):
self.game.focus_get()
self.content.focus_get()
8 changes: 5 additions & 3 deletions biscuit/core/components/games/game.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import tkinter as tk

from biscuit.core.components.utils import Frame
from biscuit.core.components.utils import Frame, IconButton


class BaseGame(Frame):
Expand All @@ -15,11 +15,13 @@ def __init__(self, master, path=None, *args, **kwargs):

self.exists = False
self.showpath = False
self.content = None
self.diff = False
self.editable = False

self.__buttons__ = ()
self.__buttons__ = (('refresh', self.reload), )

def create_buttons(self, editorbar):
self.__buttons__ = [IconButton(editorbar, *button) for button in self.__buttons__]

def reload(self, *_):
...
Expand Down
9 changes: 5 additions & 4 deletions biscuit/core/layout/base/content/editors/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import tkinter as tk


from .editorsbar import Editorsbar
from .empty import Empty

from biscuit.core.components.editors import Editor
from biscuit.core.components.games import Game
from biscuit.core.components.utils import Frame

from .editorsbar import Editorsbar
from .empty import Empty


class EditorsPane(Frame):
"""
Expand Down Expand Up @@ -54,6 +53,8 @@ def add_editors(self, editors):
def add_editor(self, editor):
"Appends a editor to list. Create a tab."
self.editors.append(editor)
if editor.content:
editor.content.create_buttons(self.editorsbar.container)
self.tabs.add_tab(editor)

def delete_all_editors(self):
Expand Down
10 changes: 5 additions & 5 deletions biscuit/core/layout/base/content/editors/editorsbar.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import tkinter as tk
from tkinter.constants import *

from biscuit.core.components.utils import Frame, IconButton

from .tabs import Tabs
from biscuit.core.components.utils import IconButton, Frame


class Editorsbar(Frame):
Expand All @@ -16,12 +17,11 @@ def __init__(self, master, *args, **kwargs):
self.buttons = []
self.default_buttons = (('ellipsis',),)

# TODO like panelbar, add __buttons__ to BaseEditor
self.buttonframe = Frame(self)
self.buttonframe.pack(fill=BOTH, side=RIGHT, pady=5, padx=10)
self.container = Frame(self, **self.base.theme.layout.base.content.editors.bar)
self.container.pack(fill=BOTH, side=RIGHT, padx=(0, 10))

for button in self.default_buttons:
IconButton(self.buttonframe, *button).pack(side=RIGHT)
IconButton(self.container, *button).pack(side=RIGHT)

def add_buttons(self, buttons):
for button in buttons:
Expand Down