Skip to content

Commit 5dfedf1

Browse files
Allow diverse branching structures in log subcommand
Signed-off-by: Jacob Stopak <jacob@initialcommit.io>
1 parent 08530c3 commit 5dfedf1

File tree

1 file changed

+143
-2
lines changed

1 file changed

+143
-2
lines changed

git_sim/log.py

Lines changed: 143 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from git_sim.animations import handle_animations
44
from git_sim.git_sim_base_command import GitSimBaseCommand
55
from git_sim.settings import settings
6+
import numpy
7+
import manim as m
68

79

810
class Log(GitSimBaseCommand):
@@ -14,25 +16,164 @@ def __init__(self, commits: int):
1416
self.selected_branches.append(self.repo.active_branch.name)
1517
except TypeError:
1618
pass
19+
self.arrow_map = []
1720

1821
def construct(self):
1922
if not settings.stdout:
2023
print(f"{settings.INFO_STRING} {type(self).__name__.lower()}")
2124
self.show_intro()
2225
self.get_commits()
23-
self.parse_commits(self.commits[0])
26+
self.parse_commits(self.commits[0], 0)
2427
self.recenter_frame()
2528
self.scale_frame()
2629
self.fadeout()
2730
self.show_outro()
2831

32+
def parse_commits(
33+
self, commit, i, prevCircle=None, shift=numpy.array([0.0, 0.0, 0.0]), dots=False
34+
):
35+
isNewCommit = commit.hexsha not in self.drawnCommits
36+
37+
if i < self.numCommits and commit in self.commits:
38+
commitId, circle, arrow, hide_refs = self.draw_commit(
39+
commit, prevCircle, shift, dots
40+
)
41+
42+
if commit != "dark":
43+
if not hide_refs and isNewCommit:
44+
self.draw_head(commit, commitId)
45+
self.draw_branch(commit)
46+
self.draw_tag(commit)
47+
if [arrow.start.tolist(), arrow.end.tolist()] not in self.arrow_map:
48+
self.draw_arrow(prevCircle, arrow)
49+
self.arrow_map.append([arrow.start.tolist(), arrow.end.tolist()])
50+
if i == 0 and len(self.drawnRefs) < 2:
51+
self.draw_dark_ref()
52+
53+
if i < len(self.commits) - 1:
54+
i += 1
55+
commitParents = list(commit.parents)
56+
if len(commitParents) > 0:
57+
# if ( self.args.invert_branches ):
58+
# commitParents.reverse()
59+
60+
# if ( self.args.hide_merged_chains ):
61+
# self.parseCommits(commitParents[0], i+1, prevCircle, toFadeOut)
62+
# else:
63+
for p in range(len(commitParents)):
64+
self.parse_commits(commitParents[p], i, circle, dots=True)
65+
else:
66+
self.i = 0
67+
68+
def draw_commit(
69+
self, commit, prevCircle, shift=numpy.array([0.0, 0.0, 0.0]), dots=False
70+
):
71+
if commit == "dark":
72+
commitFill = m.WHITE if settings.light_mode else m.BLACK
73+
elif len(commit.parents) <= 1:
74+
commitFill = m.RED
75+
else:
76+
commitFill = m.GRAY
77+
78+
circle = m.Circle(
79+
stroke_color=commitFill, fill_color=commitFill, fill_opacity=0.25
80+
)
81+
circle.height = 1
82+
83+
if shift.any():
84+
circle.shift(shift)
85+
86+
if prevCircle:
87+
circle.next_to(
88+
prevCircle, m.RIGHT if settings.reverse else m.LEFT, buff=1.5
89+
)
90+
91+
while any((circle.get_center() == c).all() for c in self.get_centers()):
92+
circle.next_to(circle, m.DOWN, buff=3.5)
93+
94+
isNewCommit = commit.hexsha not in self.drawnCommits
95+
96+
if isNewCommit:
97+
start = (
98+
prevCircle.get_center()
99+
if prevCircle
100+
else (m.LEFT if settings.reverse else m.RIGHT)
101+
)
102+
end = circle.get_center()
103+
else:
104+
circle.move_to(self.drawnCommits[commit.hexsha].get_center())
105+
start = prevCircle.get_center()
106+
end = self.drawnCommits[commit.hexsha].get_center()
107+
108+
arrow = m.Arrow(start, end, color=self.fontColor)
109+
110+
if commit == "dark":
111+
arrow = m.Arrow(
112+
start, end, color=m.WHITE if settings.light_mode else m.BLACK
113+
)
114+
115+
length = numpy.linalg.norm(start - end) - (1.5 if start[1] == end[1] else 3)
116+
arrow.set_length(length)
117+
angle = arrow.get_angle()
118+
lineRect = (
119+
m.Rectangle(height=0.1, width=length, color="#123456")
120+
.move_to(arrow.get_center())
121+
.rotate(angle)
122+
)
123+
124+
for commitCircle in self.drawnCommits.values():
125+
inter = m.Intersection(lineRect, commitCircle)
126+
if inter.has_points():
127+
arrow = m.CurvedArrow(start, end)
128+
if start[1] == end[1]:
129+
arrow.shift(UP * 1.25)
130+
if start[0] < end[0] and start[1] == end[1]:
131+
arrow.flip(RIGHT).shift(UP)
132+
133+
commitId, commitMessage, commit, hide_refs = self.build_commit_id_and_message(
134+
commit, dots
135+
)
136+
commitId.next_to(circle, m.UP)
137+
138+
if commit != "dark":
139+
self.drawnCommitIds[commit.hexsha] = commitId
140+
141+
message = m.Text(
142+
"\n".join(
143+
commitMessage[j : j + 20] for j in range(0, len(commitMessage), 20)
144+
)[:100],
145+
font="Monospace",
146+
font_size=14,
147+
color=self.fontColor,
148+
).next_to(circle, m.DOWN)
149+
150+
if settings.animate and commit != "dark" and isNewCommit:
151+
self.play(
152+
self.camera.frame.animate.move_to(circle.get_center()),
153+
m.Create(circle),
154+
m.AddTextLetterByLetter(commitId),
155+
m.AddTextLetterByLetter(message),
156+
run_time=1 / settings.speed,
157+
)
158+
elif isNewCommit:
159+
self.add(circle, commitId, message)
160+
else:
161+
return commitId, circle, arrow, hide_refs
162+
163+
if commit != "dark":
164+
self.drawnCommits[commit.hexsha] = circle
165+
166+
self.toFadeOut.add(circle, commitId, message)
167+
self.prevRef = commitId
168+
169+
return commitId, circle, arrow, hide_refs
170+
29171

30172
def log(
31173
commits: int = typer.Option(
32174
default=settings.commits,
33175
help="The number of commits to display in the simulated log output",
34176
min=1,
35-
max=12,
36177
),
37178
):
38179
scene = Log(commits=commits)

0 commit comments

Comments
 (0)