Add missing bins

60c495f03f8bca4cb2c35e69de23fde3a63db580
Alexis Sellier committed ago 1 parent bb61b1bc
bin/git-delete-merged added +2 -0
1 +
#!/bin/sh
2 +
git branch --merged master | grep -E -v "(^\*|master|main)" | xargs git branch -d
bin/git-forest added +641 -0
1 +
#!/usr/bin/perl
2 +
#
3 +
#	git-森林
4 +
#	text-based tree visualisation
5 +
#	Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2008
6 +
#
7 +
#	This program is free software; you can redistribute it and/or modify
8 +
#	it under the terms of the GNU General Public License as published by
9 +
#	the Free Software Foundation; either version 2 or 3 of the license.
10 +
#
11 +
use Getopt::Long;
12 +
use Git;
13 +
use strict;
14 +
use utf8;
15 +
use Encode qw(encode);
16 +
my $Repo          = Git->repository($ENV{"GIT_DIR"} || ".");
17 +
my $Pretty_fmt    = "format:%s";
18 +
my $Reverse_order = 0;
19 +
my $Show_all      = 0;
20 +
my $Show_rebase   = 1;
21 +
my $Style         = 1;
22 +
my $Subvine_depth = 2;
23 +
my $With_sha      = 0;
24 +
my %Color         = (
25 +
	"default" => "\e[0m", # ]
26 +
	"at"      => "\e[1;30m", # ]
27 +
	"hhead"   => "\e[1;31m", # ]
28 +
	"head"    => "\e[1;32m", # ]
29 +
	"ref"     => "\e[1;34m", # ]
30 +
	"remote"  => "\e[1;35m", # ]
31 +
	"sha"     => "\e[0;31m", # ]
32 +
	"tag"     => "\e[1;33m", # ]
33 +
	"tree"    => "\e[0;33m", # ]
34 +
);
35 +
36 +
&main();
37 +
38 +
sub main
39 +
{
40 +
	&Getopt::Long::Configure(qw(bundling pass_through));
41 +
	&GetOptions(
42 +
		"all"       => \$Show_all,
43 +
		"no-color"  => sub { %Color = (); },
44 +
		"no-rebase" => sub { $Show_rebase = 0; },
45 +
		"a"         => sub { $Pretty_fmt = "format:\e[1;30m(\e[0;32m%an\e[1;30m)\e[0m %s"; }, # ]]]]
46 +
		"pretty=s"  => \$Pretty_fmt,
47 +
		"reverse"   => \$Reverse_order,
48 +
		"svdepth=i" => \$Subvine_depth,
49 +
		"style=i"   => \$Style,
50 +
		"sha"       => \$With_sha,
51 +
	);
52 +
	++$Subvine_depth;
53 +
	if (substr($Pretty_fmt, 0, 7) ne "format:") {
54 +
		die "If you use --pretty, it must be in the form of --pretty=format:";
55 +
	}
56 +
	$Pretty_fmt = substr($Pretty_fmt, 7);
57 +
	while ($Pretty_fmt =~ /\%./g) {
58 +
		if ($& eq "\%b" || $& eq "\%n" || ($&.$') =~ /^\%x0a/i) {
59 +
			die "Cannot use \%b, \%n or \%x0a in --pretty=format:";
60 +
		}
61 +
	}
62 +
	if ($Show_all) {
63 +
		#
64 +
		# Give --all back. And add HEAD to include commits
65 +
		# in the rev list that belong to a detached HEAD.
66 +
		#
67 +
		unshift(@ARGV, "--all", "HEAD");
68 +
	}
69 +
	if ($Reverse_order) {
70 +
		tie(*STDOUT, "ReverseOutput");
71 +
	}
72 +
	&process();
73 +
	if ($Reverse_order) {
74 +
		untie *STDOUT;
75 +
	}
76 +
}
77 +
78 +
sub get_line_block
79 +
{
80 +
	my($fh, $max) = @_;
81 +
82 +
	while (scalar(@h::ist) < $max) {
83 +
		my $x;
84 +
85 +
		$x = <$fh>;
86 +
		if (!defined($x)) {
87 +
			last;
88 +
		}
89 +
		push(@h::ist, $x);
90 +
	}
91 +
92 +
	my @ret = (shift @h::ist);
93 +
	foreach (2..$max) {
94 +
		push(@ret, $h::ist[$_-2]);
95 +
	}
96 +
	return @ret;
97 +
}
98 +
99 +
sub process
100 +
{
101 +
	my(@vine);
102 +
	my $refs = &get_refs();
103 +
	my($fh, $fhc) = $Repo->command_output_pipe("log", "--date-order",
104 +
	                "--pretty=format:<%H><%h><%P>$Pretty_fmt", @ARGV);
105 +
106 +
	while (my($line, @next_sha) = get_line_block($fh, $Subvine_depth)) {
107 +
		if (!defined($line)) {
108 +
			last;
109 +
		}
110 +
		chomp $line;
111 +
		my($sha, $mini_sha, $parents, $msg) =
112 +
			($line =~ /^<(.*?)><(.*?)><(.*?)>(.*)/s);
113 +
		my @next_sha = map { ($_) = /^<(.*?)>/ } @next_sha;
114 +
		my @parents = split(" ", $parents);
115 +
116 +
		&vine_branch(\@vine, $sha);
117 +
		my $ra = &vine_commit(\@vine, $sha, \@parents);
118 +
119 +
		if (exists($refs->{$sha})) {
120 +
			print &vis_post(&vis_commit($ra),
121 +
			      $Color{at}."m".$Color{default});
122 +
			&ref_print($refs->{$sha});
123 +
		} else {
124 +
			print &vis_post(&vis_commit($ra, " "));
125 +
		}
126 +
		if ($With_sha) {
127 +
			print $msg, $Color{at}, encode('UTF-8', "──("), $Color{sha}, $mini_sha,
128 +
			      $Color{at}, ")", $Color{default}, "\n";
129 +
		} else {
130 +
			print $msg, "\n";
131 +
		}
132 +
133 +
		&vine_merge(\@vine, $sha, \@next_sha, \@parents);
134 +
	}
135 +
	$Repo->command_close_pipe($fh, $fhc);
136 +
}
137 +
138 +
sub get_refs
139 +
{
140 +
	my($fh, $c) = $Repo->command_output_pipe("show-ref");
141 +
	my $ret = {};
142 +
143 +
	while (defined(my $ln = <$fh>)) {
144 +
		chomp $ln;
145 +
		if (length($ln) == 0) {
146 +
			next;
147 +
		}
148 +
149 +
		my($sha, $name) = ($ln =~ /^(\S+)\s+(.*)/s);
150 +
		if (!exists($ret->{$sha})) {
151 +
			$ret->{$sha} = [];
152 +
		}
153 +
		push(@{$ret->{$sha}}, $name);
154 +
		if ($name =~ m{^refs/tags/}) {
155 +
			my $sub_sha = $Repo->command("log", "-1",
156 +
			              "--pretty=format:%H", $name);
157 +
			chomp $sub_sha;
158 +
			if ($sha ne $sub_sha) {
159 +
				push(@{$ret->{$sub_sha}}, $name);
160 +
			}
161 +
		}
162 +
	}
163 +
164 +
	$Repo->command_close_pipe($fh, $c);
165 +
166 +
	my $rebase = -e $Repo->repo_path()."/.dotest-merge/git-rebase-todo" &&
167 +
	             $Show_rebase;
168 +
	if ($rebase) {
169 +
		if (open(my $act_fh, $Repo->repo_path().
170 +
		    "/.dotest-merge/git-rebase-todo")) {
171 +
			my($curr) = (<$act_fh> =~ /^\S+\s+(\S+)/);
172 +
			$curr = $Repo->command("rev-parse", $curr);
173 +
			chomp $curr;
174 +
			unshift(@{$ret->{$curr}}, "rebase/cn");
175 +
			close $act_fh;
176 +
		}
177 +
178 +
		chomp(my $up   = $Repo->command("rev-parse", ".dotest-merge/upstream"));
179 +
		chomp(my $onto = $Repo->command("rev-parse", ".dotest-merge/onto"));
180 +
		chomp(my $old  = $Repo->command("rev-parse", ".dotest-merge/head"));
181 +
		unshift(@{$ret->{$up}}, "rebase/upstream");
182 +
		unshift(@{$ret->{$onto}}, "rebase/onto");
183 +
		unshift(@{$ret->{$old}}, "rebase/saved-HEAD");
184 +
	}
185 +
186 +
	my $head = $Repo->command("rev-parse", "HEAD");
187 +
	chomp $head;
188 +
	if ($rebase) {
189 +
		unshift(@{$ret->{$head}}, "rebase/new");
190 +
	}
191 +
	unshift(@{$ret->{$head}}, "HEAD");
192 +
193 +
	return $ret;
194 +
}
195 +
196 +
#
197 +
# ref_print - print a ref with color
198 +
# @s:	ref name
199 +
#
200 +
sub ref_print
201 +
{
202 +
	foreach my $symbol (@{shift @_}) {
203 +
		print $Color{at}, "[";
204 +
		if ($symbol eq "HEAD" || $symbol =~ m{^rebase/}) {
205 +
			print $Color{hhead}, $symbol;
206 +
		} elsif ($symbol =~ m{^refs/(remotes/[^/]+)/(.*)}s) {
207 +
			print $Color{remote}, $1, $Color{head}, "/$2";
208 +
		} elsif ($symbol =~ m{^refs/heads/(.*)}s) {
209 +
			print $Color{head}, $1;
210 +
		} elsif ($symbol =~ m{^refs/tags/(.*)}s) {
211 +
			print $Color{tag}, $1;
212 +
		} elsif ($symbol =~ m{^refs/(.*)}s) {
213 +
			print $Color{ref}, $1;
214 +
		}
215 +
		print $Color{at}, encode('UTF-8', "]──"), $Color{default};
216 +
	}
217 +
}
218 +
219 +
#
220 +
# vine_branch -
221 +
# @vine:	column array containing the expected parent IDs
222 +
# @rev:		commit ID
223 +
#
224 +
# Draws the branching vine matrix between a commit K and K^ (@rev).
225 +
#
226 +
sub vine_branch
227 +
{
228 +
	my($vine, $rev) = @_;
229 +
	my $idx;
230 +
231 +
	my($matched, $master) = (0, 0);
232 +
	my $ret;
233 +
234 +
	# Transform array into string
235 +
	for ($idx = 0; $idx <= $#$vine; ++$idx) {
236 +
		if (!defined($vine->[$idx])) {
237 +
			$ret .= " ";
238 +
			next;
239 +
		} elsif ($vine->[$idx] ne $rev) {
240 +
			$ret .= "I";
241 +
			next;
242 +
		}
243 +
		if (!$master && $idx % 2 == 0) {
244 +
			$ret .= "S";
245 +
			$master = 1;
246 +
		} else {
247 +
			$ret .= "s";
248 +
			$vine->[$idx] = undef;
249 +
		}
250 +
		++$matched;
251 +
	}
252 +
253 +
	if ($matched < 2) {
254 +
		return;
255 +
	}
256 +
257 +
	&remove_trailing_blanks($vine);
258 +
	print &vis_post(&vis_fan($ret, "branch")), "\n";
259 +
}
260 +
261 +
#
262 +
# vine_commit -
263 +
# @vine:	column array containing the expected IDs
264 +
# @rev:		commit ID
265 +
# @parents:	array of parent IDs
266 +
#
267 +
sub vine_commit
268 +
{
269 +
	my($vine, $rev, $parents) = @_;
270 +
	my $ret;
271 +
272 +
	for (my $i = 0; $i <= $#$vine; ++$i) {
273 +
		if (!defined($vine->[$i])) {
274 +
			$ret .= " ";
275 +
		} elsif ($vine->[$i] eq $rev) {
276 +
			$ret .= "C";
277 +
		} else {
278 +
			$ret .= "I";
279 +
		}
280 +
	}
281 +
282 +
	if ($ret !~ /C/) {
283 +
		# Not having produced a C before means this is a tip
284 +
		my $i;
285 +
		for ($i = &round_down2($#$vine); $i >= 0; $i -= 2) {
286 +
			if (substr($ret, $i, 1) eq " ") {
287 +
				substr($ret, $i, 1) = "t";
288 +
				$vine->[$i] = $rev;
289 +
				last;
290 +
			}
291 +
		}
292 +
		if ($i < 0) {
293 +
			if (scalar(@$vine) % 2 != 0) {
294 +
				push(@$vine, undef);
295 +
				$ret .= " ";
296 +
			}
297 +
			$ret .= "t";
298 +
			push(@$vine, $rev);
299 +
		}
300 +
	}
301 +
302 +
	&remove_trailing_blanks($vine);
303 +
304 +
	if (scalar(@$parents) == 0) {
305 +
		# tree root
306 +
		$ret =~ tr/C/r/;
307 +
	}
308 +
309 +
	return $ret;
310 +
}
311 +
312 +
#
313 +
# vine_merge -
314 +
# @vine:	column array containing the expected parent IDs
315 +
# @rev:		commit ID
316 +
# @next_rev:	next commit ID in the revision list
317 +
# @parents:	parent IDs of @rev
318 +
#
319 +
# Draws the merging vine matrix between a commit K (@rev) and K^ (@parents).
320 +
#
321 +
sub vine_merge
322 +
{
323 +
	my($vine, $rev, $next_rev, $parents) = @_;
324 +
	my $orig_vine = -1;
325 +
	my @slot;
326 +
	my($ret, $max);
327 +
328 +
	for (my $i = 0; $i <= $#$vine; ++$i) {
329 +
		if ($vine->[$i] eq $rev) {
330 +
			$orig_vine = $i;
331 +
			last;
332 +
		}
333 +
	}
334 +
335 +
	if ($orig_vine == -1) {
336 +
		die "vine_commit() did not add this vine.";
337 +
	}
338 +
339 +
	if (scalar(@$parents) <= 1) {
340 +
		#
341 +
		# A single parent does not need a visual. Update and return.
342 +
		#
343 +
		$vine->[$orig_vine] = $parents->[0];
344 +
		&remove_trailing_blanks($vine);
345 +
		return;
346 +
	}
347 +
348 +
	#
349 +
	# Put previously seen branches in the vine subcolumns
350 +
	# Need to keep at least one parent for the slot algorithm below.
351 +
	#
352 +
	for (my $j = 0; $j <= $#$parents && $#$parents > 0; ++$j) {
353 +
		for (my $idx = 0; $idx <= $#$vine; ++$idx) {
354 +
			if ($vine->[$idx] ne $parents->[$j] ||
355 +
			    !grep { my $z = $vine->[$idx]; /^\Q$z\E$/ }
356 +
			    @$next_rev) {
357 +
				next;
358 +
			}
359 +
			if ($idx == $orig_vine) {
360 +
				die "Should not really happen";
361 +
			}
362 +
			if ($idx < $orig_vine) {
363 +
				my $p = $idx + 1;
364 +
				if (defined($vine->[$p])) {
365 +
					$p = $idx - 1;
366 +
				}
367 +
				if (defined($vine->[$p])) {
368 +
					last;
369 +
				}
370 +
				$vine->[$p] = $parents->[$j];
371 +
				str_expand(\$ret, $p + 1);
372 +
				substr($ret, $p, 1) = "s";
373 +
			} else {
374 +
				my $p = $idx - 1;
375 +
				if (defined($vine->[$p]) || $p < 0) {
376 +
					$p = $idx + 1;
377 +
				}
378 +
				if (defined($vine->[$p])) {
379 +
					last;
380 +
				}
381 +
				$vine->[$p] = $parents->[$j];
382 +
				str_expand(\$ret, $p + 1);
383 +
				substr($ret, $p, 1) = "s";
384 +
			}
385 +
			splice(@$parents, $j, 1);
386 +
			--$j; # outer loop
387 +
			last; # inner loop
388 +
		}
389 +
	}
390 +
391 +
	#
392 +
	# Find some good spots to split out into and record columns
393 +
	# that will be used soon in the @slot list.
394 +
	#
395 +
	push(@slot, $orig_vine);
396 +
	my $parent = 0;
397 +
398 +
	for (my $seeker = 2; $parent < $#$parents &&
399 +
	    $seeker < 2 + $#$vine; ++$seeker)
400 +
	{
401 +
		my $idx = ($seeker % 2 == 0) ? -1 : 1;
402 +
		$idx   *= int($seeker / 2);
403 +
		$idx   *= 2;
404 +
		$idx   += $orig_vine;
405 +
406 +
		if ($idx >= 0 && $idx <= $#$vine && !defined($vine->[$idx])) {
407 +
			push(@slot, $idx);
408 +
			$vine->[$idx] = "0" x 40;
409 +
			++$parent;
410 +
		}
411 +
	}
412 +
	for (my $idx = $orig_vine + 2; $parent < $#$parents; $idx += 2) {
413 +
		if (!defined($vine->[$idx])) {
414 +
			push(@slot, $idx);
415 +
			++$parent;
416 +
		}
417 +
	}
418 +
419 +
	if (scalar(@slot) != scalar(@$parents)) {
420 +
		die "Serious internal problem";
421 +
	}
422 +
423 +
	@slot = sort { $a <=> $b } @slot;
424 +
	$max  = scalar(@$vine) + 2 * scalar(@slot);
425 +
426 +
	for (my $i = 0; $i < $max; ++$i) {
427 +
		str_expand(\$ret, $i + 1);
428 +
		if ($#slot >= 0 && $i == $slot[0]) {
429 +
			shift @slot;
430 +
			$vine->[$i] = shift @$parents;
431 +
			substr($ret, $i, 1) = ($i == $orig_vine) ? "S" : "s";
432 +
		} elsif (substr($ret, $i, 1) eq "s") {
433 +
			; # keep existing fanouts
434 +
		} elsif (defined($vine->[$i])) {
435 +
			substr($ret, $i, 1) = "I";
436 +
		} else {
437 +
			substr($ret, $i, 1) = " ";
438 +
		}
439 +
	}
440 +
441 +
	print &vis_post(&vis_fan($ret, "merge")), "\n";
442 +
}
443 +
444 +
#
445 +
# vis_* - transform control string into usable graphic
446 +
#
447 +
# To cut down on code, the three vine_* functions produce only a dumb,
448 +
# but already unambiguous, control string which needs some processing
449 +
# before it is ready for public display.
450 +
#
451 +
452 +
sub vis_commit
453 +
{
454 +
	my $s = shift @_;
455 +
	my $f = shift @_;
456 +
	$s =~ s/ +$//gs;
457 +
	if (defined $f) {
458 +
		$s .= $f;
459 +
	}
460 +
	return $s;
461 +
}
462 +
463 +
sub vis_fan
464 +
{
465 +
	my $s = shift @_;
466 +
	my $b = shift(@_) eq "branch";
467 +
468 +
	$s =~ s{s.*s}{
469 +
		$_ = $&;
470 +
		$_ =~ tr/ I/DO/;
471 +
		$_;
472 +
	}ei;
473 +
474 +
	# Transform an ODODO.. sequence into a contiguous overpass.
475 +
	$s =~ s{O[DO]+O}{"O" x length($&)}eg;
476 +
477 +
	# Do left/right edge transformation
478 +
	$s =~ s{(s.*)S(.*s)}{&vis_fan3($1, $2)}es ||
479 +
	$s =~ s{(s.*)S}{&vis_fan2L($1)."B"}es ||
480 +
	$s =~ s{S(.*s)}{"A".&vis_fan2R($1)}es ||
481 +
	die "Should not come here";
482 +
483 +
	if ($b) {
484 +
		$s =~ tr/efg/xyz/;
485 +
	}
486 +
487 +
	return $s;
488 +
}
489 +
490 +
sub vis_fan2L
491 +
{
492 +
	my $l = shift @_;
493 +
	$l =~ s/^s/e/;
494 +
	$l =~ s/s/f/g;
495 +
	return $l;
496 +
}
497 +
498 +
sub vis_fan2R
499 +
{
500 +
	my $r = shift @_;
501 +
	$r =~ s/s$/g/;
502 +
	$r =~ s/s/f/g;
503 +
	return $r;
504 +
}
505 +
506 +
sub vis_fan3
507 +
{
508 +
	my($l, $r) = @_;
509 +
	$l =~ s/^s/e/;
510 +
	$l =~ s/s/f/g;
511 +
	$r =~ s/s$/g/;
512 +
	$r =~ s/s/f/g;
513 +
	return "${l}K$r";
514 +
}
515 +
516 +
sub vis_xfrm
517 +
{
518 +
	# A: branch to right
519 +
	# B: branch to right
520 +
	# C: commit
521 +
	# D:
522 +
	# e: merge visual left (╔)
523 +
	# f: merge visual center (╦)
524 +
	# g: merge visual right (╗)
525 +
	# I: straight line (║)
526 +
	# K: branch visual split (╬)
527 +
	# m: single line (─)
528 +
	# O: overpass (≡)
529 +
	# r: root (╙)
530 +
	# t: tip (╓)
531 +
	# x: branch visual left (╚)
532 +
	# y: branch visual center (╩)
533 +
	# z: branch visual right (╝)
534 +
	# *: filler
535 +
536 +
	my $s = shift @_;
537 +
	my $spc = shift @_;
538 +
	if ($spc) {
539 +
		$s =~ s{[Ctr].*}{
540 +
			$_ = $&;
541 +
			$_ =~ s{ }{\*}g;
542 +
			$_;
543 +
		}esg;
544 +
	}
545 +
546 +
	if ($Reverse_order) {
547 +
		$s =~ tr/efg.rt.xyz/xyz.tr.efg/;
548 +
	}
549 +
550 +
	if ($Style == 1) {
551 +
		$s =~ tr/ABCD.efg.IKO.mrt.xyz/├┤├─.┌┬┐.│┼≡.─└┌.└┴┘/;
552 +
	} elsif ($Style == 2) {
553 +
		$s =~ tr/ABCD.efg.IKO.mrt.xyz/╠╣╟═.╔╦╗.║╬═.─╙╓.╚╩╝/;
554 +
	} elsif ($Style == 10) {
555 +
		$s =~ tr/ABCD.efg.IKO.mrt.xyz/├┤├─.╭┬╮.│┼≡.─└┌.╰┴╯/;
556 +
	} elsif ($Style == 15) {
557 +
		$s =~ tr/ABCD.efg.IKO.mrt.xyz/┣┫┣━.┏┳┓.┃╋☰.━┗┏.┗┻┛/;
558 +
	}
559 +
	return $s;
560 +
}
561 +
562 +
#
563 +
# vis_post - post-process/transform vine graphic
564 +
# Apply user-specific style transformation.
565 +
#
566 +
sub vis_post
567 +
{
568 +
	my $s = shift @_;
569 +
	my $f = shift @_;
570 +
571 +
	$s = vis_xfrm($s, defined $f);
572 +
	$f =~ s/^([^\x1b]+)/vis_xfrm($1)/e;
573 +
	$f =~ s/(\x1b.*?m)([^\x1b]+)/$1.vis_xfrm($2)/eg;
574 +
	if (defined $f) {
575 +
		$s =~ s/\*/$f/g;
576 +
		$s =~ s{\Q$Color{default}\E}{$&.$Color{tree}}egs;
577 +
		$s .= $f;
578 +
	}
579 +
580 +
	return $Color{tree}, encode('UTF-8', $s), $Color{default};
581 +
}
582 +
583 +
sub remove_trailing_blanks
584 +
{
585 +
	my $a = shift @_;
586 +
587 +
	while (scalar(@$a) > 0 && !defined($a->[$#$a])) {
588 +
		pop(@$a);
589 +
	}
590 +
}
591 +
592 +
sub round_down2
593 +
{
594 +
	my $i = shift @_;
595 +
	if ($i < 0) {
596 +
		return $i;
597 +
	}
598 +
	return $i & ~1;
599 +
}
600 +
601 +
sub str_expand
602 +
{
603 +
	my $r = shift @_;
604 +
	my $l = shift @_;
605 +
606 +
	if (length($$r) < $l) {
607 +
		$$r .= " " x ($l - length($$r));
608 +
	}
609 +
}
610 +
611 +
package ReverseOutput;
612 +
require Tie::Handle;
613 +
@ReverseOutput::ISA = qw(Tie::Handle);
614 +
615 +
sub TIEHANDLE
616 +
{
617 +
	my $class = shift @_;
618 +
	my $self  = {};
619 +
620 +
	open($self->{fh}, ">&STDOUT");
621 +
622 +
	return bless $self, $class;
623 +
}
624 +
625 +
sub PRINT
626 +
{
627 +
	my $self = shift @_;
628 +
	my $fh   = $self->{fh};
629 +
630 +
	$self->{saved} .= join($\, @_);
631 +
}
632 +
633 +
sub UNTIE
634 +
{
635 +
	my $self = shift @_;
636 +
	my $fh   = $self->{fh};
637 +
638 +
	print $fh join($/, reverse split(/\n/s, $self->{saved}));
639 +
	print $fh "\n";
640 +
	undef $self->{saved};
641 +
}
bin/kitty-reload added +2 -0
1 +
#!/bin/sh
2 +
killall -s SIGUSR1 kitty
bin/kitty-switch-theme added +12 -0
1 +
#!/bin/sh
2 +
3 +
LINK="$(readlink -f ~/.config/kitty/kitty.conf)"
4 +
DARK="$(readlink -f ~/.config/kitty/dark.conf)"
5 +
6 +
if [ $LINK = $DARK ]; then
7 +
  ln -sf ~/.config/kitty/light.conf ~/.config/kitty/kitty.conf
8 +
else
9 +
  ln -sf ~/.config/kitty/dark.conf ~/.config/kitty/kitty.conf
10 +
fi
11 +
12 +
kitty-reload
bin/mount-tank added +2 -0
1 +
#!/bin/sh
2 +
sudo mount -t ext4 -o umask=0022,gid=1000,uid=1000 /dev/sdb1 ~/tank