Skip to content

Commit

Permalink
feat: Switching/Creating git branches from Command Palette / Statusbar
Browse files Browse the repository at this point in the history
…#283 (nightly)

Updating/creating git branch from Command palette
  • Loading branch information
tomlin7 authored Apr 11, 2024
2 parents 1b68504 + 231ac61 commit 3b12721
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 15 deletions.
33 changes: 32 additions & 1 deletion biscuit/core/components/git/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
from __future__ import annotations

import os
import re
import typing
from tkinter import messagebox

from ..floating.palette.actionset import ActionSet

git_available = True
try:
import git
Expand All @@ -11,13 +16,27 @@
messagebox.showerror("Git not found", "Git is not installed on your PC. Install and add Git to the PATH to use Biscuit")
git_available = False


if typing.TYPE_CHECKING:
from biscuit import App

URL = re.compile(r'^(?:http)s?://')

class Git(git.Git):
def __init__(self, master, *args, **kwargs) -> None:
def __init__(self, master: App, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.base = master
self.repo = None
self.branches = {}

self.actionset = ActionSet(
"Manage git branches", "branch:",
self.branches,
pinned=[["Create new branch: {}", lambda branch=None: self.repo.create_branch(branch)]],
)

def late_setup(self) -> None:
self.base.palette.register_actionset(lambda: self.actionset)

def check_git(self) -> None:
if not (git_available and self.base.active_directory):
Expand All @@ -27,9 +46,21 @@ def check_git(self) -> None:
try:
self.repo = GitRepo(self, self.base.active_directory)
self.base.git_found = True
self.update_repo_info()
except git.exc.InvalidGitRepositoryError:
self.base.git_found = False

def update_repo_info(self) -> None:
self.branches = {}

for branch in self.repo.branches:
latest_commit = next(self.repo.iter_commits(branch))
self.branches[branch] = latest_commit.committed_datetime
self.branches = sorted(self.branches.items(), key=lambda x: x[1], reverse=True)

# TODO: make use of the commit_time in palette items
self.actionset.update([(str(branch), lambda e=None, b=branch: self.repo.switch_to_branch(b)) for branch, commit_time in self.branches])

def get_version(self) -> str:
if not git_available:
return
Expand Down
25 changes: 23 additions & 2 deletions biscuit/core/components/git/repo.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
from __future__ import annotations

import typing

import git

if typing.TYPE_CHECKING:
from . import Git

class GitRepo(git.Repo):
def __init__(self, master=None, path=None, *args, **kwargs) -> None:
def __init__(self, master: Git=None, path=None, *args, **kwargs) -> None:
super().__init__(path, *args, **kwargs)
self.master = master
self.base = master.base
self.path = path
self.config = self.config_reader()

self.author_name = self.config.get_value("user", "name")
self.author_email = self.config.get_value("user", "email")
self.author = git.Actor(self.author_name, self.author_email)

def switch_to_branch(self, branch: git.Head):
self.git.checkout(str(branch))
self.master.update_repo_info()
self.base.statusbar.update_git_info()
self.base.explorer.directory.refresh_root()

def create_branch(self, branch: str):
if not branch:
self.base.notifications.error("Branch name cannot be empty")
return

self.create_head(branch.strip())
self.switch_to_branch(branch)

def get_untracked_files(self) -> list:
return list(self.untracked_files)

Expand Down Expand Up @@ -41,7 +62,7 @@ def get_commit_filedata(self, filename) -> str:

def stage_files(self, *paths) -> None:
for path, change_type in paths:
# change type can be 0, 1, 2, 3
# change type can be 0, 1, 2, 3
# respectively represents Deleted, Added, Modified, Untracked
if change_type == 0:
self.do(self.index.remove, [path])
Expand Down
1 change: 1 addition & 0 deletions biscuit/core/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def late_setup(self) -> None:
self.editorsmanager.generate_actionsets()
self.settings.late_setup()
self.history.generate_actionsets()
self.git.late_setup()

# force set focus on this window
self.focus_set()
Expand Down
19 changes: 7 additions & 12 deletions biscuit/core/layout/statusbar/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,10 @@ def __init__(self, master: Root, *args, **kwargs) -> None:
super().__init__(master, *args, **kwargs)
self.config(bg=self.base.theme.layout.statusbar.background)

# TODO add a button for toggling panel, left side, "terminal-bash", color
self.branch = TerminalButton(self, icon="terminal-bash", function=self.toggle_terminal, description="Toggle terminal", padx=10)
self.branch.pack(side=tk.LEFT)

# git info
self.git_actionset = ActionSet(
"Manage git branches", "branch:", #TODO pinned `create new branch` item
[("main", lambda e=None: print("main", e)),
("rewrite", lambda e=None: print("rewrite", e))],
)
self.base.palette.register_actionset(lambda: self.git_actionset)
self.terminal_toggle = TerminalButton(self, icon="terminal-bash", function=self.toggle_terminal, description="Toggle terminal", padx=10)
self.terminal_toggle.pack(side=tk.LEFT)

# git branch info
self.branch = SButton(self, text="master", icon="source-control", function=self.base.events.change_git_branch, description="Checkout branch")
self.branch.set_pack_data(side=tk.LEFT, padx=(2, 0))

Expand Down Expand Up @@ -134,7 +127,9 @@ def update_git_info(self) -> None:
if self.base.git_found:
self.branch.show()
self.branch.change_text("{0}".format(self.base.git.active_branch))
self.git_actionset.update([(str(branch), lambda e=None: self.base.git.checkout(str(branch))) for branch in self.base.git.repo.branches])

# following has been moved to `git.update_repo_info`
# self.git_actionset.update([(str(branch), lambda e=None: self.base.git.checkout(str(branch))) for branch in self.base.git.repo.branches])
else:
self.branch.hide()

Expand Down

0 comments on commit 3b12721

Please sign in to comment.