Add missing bins
60c495f03f8bca4cb2c35e69de23fde3a63db580
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 |