diff --git a/.fedora/vendor/crystal-setup.sh b/.fedora/vendor/crystal-setup.sh new file mode 100755 index 00000000..d68379ce --- /dev/null +++ b/.fedora/vendor/crystal-setup.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +cat > /etc/yum.repos.d/crystal.repo < 'all'; + use strict; + use Encode; + + # Highlight by reversing foreground and background. You could do + # other things like bold or underline if you prefer. + our @OLD_HIGHLIGHT = ( + color_config('color.diff-highlight.oldnormal'), + color_config('color.diff-highlight.oldhighlight', "\x1b[7m"), + "\x1b[27m", + ); + our@NEW_HIGHLIGHT = ( + color_config('color.diff-highlight.newnormal', $OLD_HIGHLIGHT[0]), + color_config('color.diff-highlight.newhighlight', $OLD_HIGHLIGHT[1]), + $OLD_HIGHLIGHT[2], + ); + + my $RESET = "\x1b[m"; + my $COLOR = qr/\x1b\[[0-9;]*m/; + my $BORING = qr/$COLOR|\s/; + + # The patch portion of git log -p --graph should only ever have preceding | and + # not / or \ as merge history only shows up on the commit line. + my $GRAPH = qr/$COLOR?\|$COLOR?\s+/; + + my @removed; + my @added; + my $in_hunk; + + our $line_cb = sub { print @_ }; + our $flush_cb = sub { local $| = 1 }; + + sub handle_line { + local $_ = shift; + + if (!$in_hunk) { + $line_cb->($_); + $in_hunk = /^$GRAPH*$COLOR*\@\@ /; + } + elsif (/^$GRAPH*$COLOR*-/) { + push @removed, $_; + } + elsif (/^$GRAPH*$COLOR*\+/) { + push @added, $_; + } + else { + show_hunk(\@removed, \@added); + @removed = (); + @added = (); + + $line_cb->($_); + $in_hunk = /^$GRAPH*$COLOR*[\@ ]/; + } + + # Most of the time there is enough output to keep things streaming, + # but for something like "git log -Sfoo", you can get one early + # commit and then many seconds of nothing. We want to show + # that one commit as soon as possible. + # + # Since we can receive arbitrary input, there's no optimal + # place to flush. Flushing on a blank line is a heuristic that + # happens to match git-log output. + if (!length) { + $flush_cb->(); + } + } + + sub flush { + # Flush any queued hunk (this can happen when there is no trailing + # context in the final diff of the input). + show_hunk(\@removed, \@added); + } + + sub highlight_stdin { + while () { + handle_line($_); + } + flush(); + } + + # Ideally we would feed the default as a human-readable color to + # git-config as the fallback value. But diff-highlight does + # not otherwise depend on git at all, and there are reports + # of it being used in other settings. Let's handle our own + # fallback, which means we will work even if git can't be run. + sub color_config { + my ($key, $default) = @_; + my $s = `git config --get-color $key 2>/dev/null`; + return length($s) ? $s : $default; + } + + sub show_hunk { + my ($a, $b) = @_; + + # If one side is empty, then there is nothing to compare or highlight. + if (!@$a || !@$b) { + $line_cb->(@$a, @$b); + return; + } + + # If we have mismatched numbers of lines on each side, we could try to + # be clever and match up similar lines. But for now we are simple and + # stupid, and only handle multi-line hunks that remove and add the same + # number of lines. + if (@$a != @$b) { + $line_cb->(@$a, @$b); + return; + } + + my @queue; + for (my $i = 0; $i < @$a; $i++) { + my ($rm, $add) = highlight_pair($a->[$i], $b->[$i]); + $line_cb->($rm); + push @queue, $add; + } + $line_cb->(@queue); + } + + sub highlight_pair { + my @a = split_line(shift); + my @b = split_line(shift); + my $opts = shift(); + + # Find common prefix, taking care to skip any ansi + # color codes. + my $seen_plusminus; + my ($pa, $pb) = (0, 0); + while ($pa < @a && $pb < @b) { + if ($a[$pa] =~ /$COLOR/) { + $pa++; + } + elsif ($b[$pb] =~ /$COLOR/) { + $pb++; + } + elsif ($a[$pa] eq $b[$pb]) { + $pa++; + $pb++; + } + elsif (!$seen_plusminus && $a[$pa] eq '-' && $b[$pb] eq '+') { + $seen_plusminus = 1; + $pa++; + $pb++; + } + else { + last; + } + } + + # Find common suffix, ignoring colors. + my ($sa, $sb) = ($#a, $#b); + while ($sa >= $pa && $sb >= $pb) { + if ($a[$sa] =~ /$COLOR/) { + $sa--; + } + elsif ($b[$sb] =~ /$COLOR/) { + $sb--; + } + elsif ($a[$sa] eq $b[$sb]) { + $sa--; + $sb--; + } + else { + last; + } + } + + my @OLD_COLOR_SPEC = @OLD_HIGHLIGHT; + my @NEW_COLOR_SPEC = @NEW_HIGHLIGHT; + + # If we're only highlight the differences temp disable the old/new normal colors + if ($opts->{'only_diff'}) { + $OLD_COLOR_SPEC[0] = ''; + $NEW_COLOR_SPEC[0] = ''; + } + + if (is_pair_interesting(\@a, $pa, $sa, \@b, $pb, $sb)) { + return highlight_line(\@a, $pa, $sa, \@OLD_COLOR_SPEC), + highlight_line(\@b, $pb, $sb, \@NEW_COLOR_SPEC); + } + else { + return join('', @a), + join('', @b); + } + } + + # we split either by $COLOR or by character. This has the side effect of + # leaving in graph cruft. It works because the graph cruft does not contain "-" + # or "+" + sub split_line { + local $_ = shift; + return eval { $_ = Encode::decode('UTF-8', $_, 1); 1 } ? + map { Encode::encode('UTF-8', $_) } + map { /$COLOR/ ? $_ : (split //) } + split /($COLOR+)/ : + map { /$COLOR/ ? $_ : (split //) } + split /($COLOR+)/; + } + + sub highlight_line { + my ($line, $prefix, $suffix, $theme) = @_; + + my $start = join('', @{$line}[0..($prefix-1)]); + my $mid = join('', @{$line}[$prefix..$suffix]); + my $end = join('', @{$line}[($suffix+1)..$#$line]); + + # If we have a "normal" color specified, then take over the whole line. + # Otherwise, we try to just manipulate the highlighted bits. + if (defined $theme->[0]) { + s/$COLOR//g for ($start, $mid, $end); + chomp $end; + return join('', + $theme->[0], $start, $RESET, + $theme->[1], $mid, $RESET, + $theme->[0], $end, $RESET, + "\n" + ); + } else { + return join('', + $start, + $theme->[1], $mid, $theme->[2], + $end + ); + } + } + + # Pairs are interesting to highlight only if we are going to end up + # highlighting a subset (i.e., not the whole line). Otherwise, the highlighting + # is just useless noise. We can detect this by finding either a matching prefix + # or suffix (disregarding boring bits like whitespace and colorization). + sub is_pair_interesting { + my ($a, $pa, $sa, $b, $pb, $sb) = @_; + my $prefix_a = join('', @$a[0..($pa-1)]); + my $prefix_b = join('', @$b[0..($pb-1)]); + my $suffix_a = join('', @$a[($sa+1)..$#$a]); + my $suffix_b = join('', @$b[($sb+1)..$#$b]); + + return $prefix_a !~ /^$GRAPH*$COLOR*-$BORING*$/ || + $prefix_b !~ /^$GRAPH*$COLOR*\+$BORING*$/ || + $suffix_a !~ /^$BORING*$/ || + $suffix_b !~ /^$BORING*$/; + } +DIFFHIGHLIGHT + +s/^ //mg for values %fatpacked; + +my $class = 'FatPacked::'.(0+\%fatpacked); +no strict 'refs'; +*{"${class}::files"} = sub { keys %{$_[0]} }; + +if ($] < 5.008) { + *{"${class}::INC"} = sub { + if (my $fat = $_[0]{$_[1]}) { + my $pos = 0; + my $last = length $fat; + return (sub { + return 0 if $pos == $last; + my $next = (1 + index $fat, "\n", $pos) || $last; + $_ .= substr $fat, $pos, $next - $pos; + $pos = $next; + return 1; + }); + } + }; +} + +else { + *{"${class}::INC"} = sub { + if (my $fat = $_[0]{$_[1]}) { + open my $fh, '<', \$fat + or die "FatPacker error loading $_[1] (could be a perl installation issue?)"; + return $fh; + } + return; + }; +} + +unshift @INC, bless \%fatpacked, $class; + } # END OF FATPACK CODE + + +my $VERSION = "1.2.0"; + +################################################################################# + +use File::Spec; # For catdir +use File::Basename; # For dirname +use Encode; # For handling UTF8 stuff +use Cwd qw(abs_path); # For realpath() +use lib dirname(abs_path(File::Spec->catdir($0))) . "/lib"; # Add the local lib/ to @INC +use DiffHighlight; + +use strict; +use warnings FATAL => 'all'; + +my $remove_file_add_header = 1; +my $remove_file_delete_header = 1; +my $clean_permission_changes = 1; +my $change_hunk_indicators = git_config_boolean("diff-so-fancy.changeHunkIndicators","true"); +my $strip_leading_indicators = git_config_boolean("diff-so-fancy.stripLeadingSymbols","true"); +my $mark_empty_lines = git_config_boolean("diff-so-fancy.markEmptyLines","true"); +my $use_unicode_dash_for_ruler = git_config_boolean("diff-so-fancy.useUnicodeRuler","true"); +my $git_strip_prefix = git_config_boolean("diff.noprefix","false"); +my $has_stdin = has_stdin(); + +my $ansi_color_regex = qr/(\e\[([0-9]{1,3}(;[0-9]{1,3}){0,3})[mK])?/; +my $dim_magenta = "\e[38;5;146m"; +my $reset_color = "\e[0m"; +my $bold = "\e[1m"; +my $meta_color = ""; + +my ($file_1,$file_2); +my $last_file_seen = ""; +my $last_file_mode = ""; +my $i = 0; +my $in_hunk = 0; +my $columns_to_remove = 0; + +# We only process ARGV if we don't have STDIN +if (!$has_stdin) { + my $args = argv(); + + if ($args->{v} || $args->{version}) { + die(version()); + } elsif ($args->{'set-defaults'}) { + my $ok = set_defaults(); + } elsif ($args->{colors}) { + # We print this to STDOUT so we can redirect to bash to auto-set the colors + print get_default_colors(); + exit; + } elsif (!%$args || $args->{help} || $args->{h}) { + my $first = check_first_run(); + + if (!$first) { + die(usage()); + } + } else { + die("Missing input on STDIN\n"); + } +} else { + # Check to see if were using default settings + check_first_run(); + + my @lines; + local $DiffHighlight::line_cb = sub { + push(@lines,@_); + + my $last_line = $lines[-1]; + + # Buffer X lines before we try and output anything + # Also make sure we're sending enough data to d-s-f to do it's magic. + # Certain things require a look-ahead line or two to function so + # we make sure we don't break on those sections prematurely + if (@lines > 24 && ($last_line !~ /^${ansi_color_regex}(---|index|old mode|similarity index|rename (from|to))/)) { + do_dsf_stuff(\@lines); + @lines = (); + } + }; + + while (my $line = ) { + my $ok = DiffHighlight::handle_line($line); + } + + DiffHighlight::flush(); + do_dsf_stuff(\@lines); +} + +################################################################################# + +sub do_dsf_stuff { + my $input = shift(); + + #print STDERR "START -------------------------------------------------\n"; + #print STDERR join("",@$input); + #print STDERR "END ---------------------------------------------------\n"; + + while (my $line = shift(@$input)) { + ###################################################### + # Pre-process the line before we do any other markup # + ###################################################### + + # If the first line of the input is a blank line, skip that + if ($i == 0 && $line =~ /^\s*$/) { + next; + } + + ###################### + # End pre-processing # + ###################### + + ####################################################################### + + #################################################################### + # Look for git index and replace it horizontal line (header later) # + #################################################################### + if ($line =~ /^${ansi_color_regex}index /) { + # Print the line color and then the actual line + $meta_color = $1 || DiffHighlight::color_config('color.diff.meta',"\e[38;5;11m"); + print horizontal_rule($meta_color); + + # Get the next line without incrementing counter while loop + my $next = $input->[0] || ""; + my ($file_1,$file_2); + + # The line immediately after the "index" line should be the --- file line + # If it's not it's an empty file add/delete + if ($next !~ /^$ansi_color_regex(---|Binary files)/) { + + # We fake out the file names since it's a raw add/delete + if ($last_file_mode eq "add") { + $file_1 = "/dev/null"; + $file_2 = $last_file_seen; + } elsif ($last_file_mode eq "delete") { + $file_1 = $last_file_seen; + $file_2 = "/dev/null"; + } + } + + if ($file_1 && $file_2) { + print $meta_color . file_change_string($file_1,$file_2) . "\n"; + print horizontal_rule($meta_color); + } + ######################### + # Look for the filename # + ######################### + } elsif ($line =~ /^${ansi_color_regex}diff --(git|cc) (.*?)(\s|\e|$)/) { + $last_file_seen = $5; + $last_file_seen =~ s|^\w/||; # Remove a/ (and handle diff.mnemonicPrefix). + $in_hunk = 0; + ######################################## + # Find the first file: --- a/README.md # + ######################################## + } elsif (!$in_hunk && $line =~ /^$ansi_color_regex--- (\w\/)?(.+?)(\e|\t|$)/) { + if ($git_strip_prefix) { + my $file_dir = $4 || ""; + $file_1 = $file_dir . $5; + } else { + $file_1 = $5; + } + + # Find the second file on the next line: +++ b/README.md + my $next = shift(@$input); + $next =~ /^$ansi_color_regex\+\+\+ (\w\/)?(.+?)(\e|\t|$)/; + if ($1) { + print $1; # Print out whatever color we're using + } + if ($git_strip_prefix) { + my $file_dir = $4 || ""; + $file_2 = $file_dir . $5; + } else { + $file_2 = $5; + } + + if ($file_2 ne "/dev/null") { + $last_file_seen = $file_2; + } + + print file_change_string($file_1,$file_2) . "\n"; + + # Print out the bottom horizontal line of the header + print horizontal_rule($meta_color); + ######################################## + # Check for "@@ -3,41 +3,63 @@" syntax # + ######################################## + } elsif ($change_hunk_indicators && $line =~ /^${ansi_color_regex}(@@@* .+? @@@*)(.*)/) { + $in_hunk = 1; + my $hunk_header = $4; + my $remain = bleach_text($5); + + # The number of colums to remove (1 or 2) is based on how many commas in the hunk header + $columns_to_remove = (char_count(",",$hunk_header)) - 1; + # On single line removes there is NO comma in the hunk so we force one + if ($columns_to_remove <= 0) { + $columns_to_remove = 1; + } + + if ($1) { + print $1; # Print out whatever color we're using + } + + my ($orig_offset, $orig_count, $new_offset, $new_count) = parse_hunk_header($hunk_header); + $last_file_seen = basename($last_file_seen); + + # Figure out the start line + my $start_line = start_line_calc($new_offset,$new_count); + print "@ $last_file_seen:$start_line \@${bold}${dim_magenta}${remain}${reset_color}\n"; + ################################### + # Remove any new file permissions # + ################################### + } elsif ($remove_file_add_header && $line =~ /^${ansi_color_regex}.*new file mode/) { + # Don't print the line (i.e. remove it from the output); + $last_file_mode = "add"; + ###################################### + # Remove any delete file permissions # + ###################################### + } elsif ($remove_file_delete_header && $line =~ /^${ansi_color_regex}deleted file mode/) { + # Don't print the line (i.e. remove it from the output); + $last_file_mode = "delete"; + ################################ + # Look for binary file changes # + ################################ + } elsif ($line =~ /^Binary files (\w\/)?(.+?) and (\w\/)?(.+?) differ/) { + my $change = file_change_string($2,$4); + print "$meta_color$change (binary)\n"; + print horizontal_rule($meta_color); + ##################################################### + # Check if we're changing the permissions of a file # + ##################################################### + } elsif ($clean_permission_changes && $line =~ /^${ansi_color_regex}old mode (\d+)/) { + my ($old_mode) = $4; + my $next = shift(@$input); + + if ($1) { + print $1; # Print out whatever color we're using + } + + my ($new_mode) = $next =~ m/new mode (\d+)/; + print "$last_file_seen changed file mode from $old_mode to $new_mode\n"; + + ############### + # File rename # + ############### + } elsif ($line =~ /^${ansi_color_regex}similarity index (\d+)%/) { + my $simil = $4; + + # If it's a move with content change we ignore this and the next two lines + if ($simil != 100) { + shift(@$input); + shift(@$input); + next; + } + + my $next = shift(@$input); + my ($file1) = $next =~ /rename from (.+)/; + + $next = shift(@$input); + my ($file2) = $next =~ /rename to (.+)/; + + if ($file1 && $file2) { + # We may not have extracted this yet, so we pull from the config if not + $meta_color ||= DiffHighlight::color_config('color.diff.meta',"\e[38;5;11m"); + + my $change = file_change_string($file1,$file2); + + print horizontal_rule($meta_color); + print $meta_color . $change . "\n"; + print horizontal_rule($meta_color); + } + + $i += 3; # We've consumed three lines + next; + ##################################### + # Just a regular line, print it out # + ##################################### + } else { + # Mark empty line with a red/green box indicating addition/removal + if ($mark_empty_lines) { + $line = mark_empty_line($line); + } + + # Remove the correct number of leading " " or "+" or "-" + if ($strip_leading_indicators) { + $line = strip_leading_indicators($line,$columns_to_remove); + } + print $line; + } + + $i++; + } +} + +###################################################################################################### +# End regular code, begin functions +###################################################################################################### + +# Courtesy of github.com/git/git/blob/ab5d01a/git-add--interactive.perl#L798-L805 +sub parse_hunk_header { + my ($line) = @_; + my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) = $line =~ /^\@\@+(?: -(\d+)(?:,(\d+))?)+ \+(\d+)(?:,(\d+))? \@\@+/; + $o_cnt = 1 unless defined $o_cnt; + $n_cnt = 1 unless defined $n_cnt; + return ($o_ofs, $o_cnt, $n_ofs, $n_cnt); +} + +# Mark the first char of an empty line +sub mark_empty_line { + my $line = shift(); + + my $reset_color = "\e\\[0?m"; + my $reset_escape = "\e\[m"; + my $invert_color = "\e\[7m"; + + $line =~ s/^($ansi_color_regex)[+-]$reset_color\s*$/$invert_color$1 $reset_escape\n/; + + return $line; +} + +# String to boolean +sub boolean { + my $str = shift(); + $str = trim($str); + + if ($str eq "" || $str =~ /^(no|false|0)$/i) { + return 0; + } else { + return 1; + } +} + +# Memoize getting the git config +{ + my $static_config; + + sub git_config_raw { + if ($static_config) { + # If we already have the config return that + return $static_config; + } + + my $cmd = "git config --list"; + my @out = `$cmd`; + + $static_config = \@out; + + return \@out; + } +} + +# Fetch a textual item from the git config +sub git_config { + my $search_key = lc($_[0] || ""); + my $default_value = lc($_[1] || ""); + + my $out = git_config_raw(); + + # If we're in a unit test, use the default (don't read the users config) + if (in_unit_test()) { + return $default_value; + } + + my $raw = {}; + foreach my $line (@$out) { + if ($line =~ /=/) { + my ($key,$value) = split("=",$line,2); + $value =~ s/\s+$//; + $raw->{$key} = $value; + } + } + + # If we're given a search key return that, else return the hash + if ($search_key) { + return $raw->{$search_key} || $default_value; + } else { + return $raw; + } +} + +# Fetch a boolean item from the git config +sub git_config_boolean { + my $search_key = lc($_[0] || ""); + my $default_value = lc($_[1] || 0); # Default to false + + # If we're in a unit test, use the default (don't read the users config) + if (in_unit_test()) { + return boolean($default_value); + } + + my $result = git_config($search_key,$default_value); + my $ret = boolean($result); + + return $ret; +} + +# Check if we're inside of BATS +sub in_unit_test { + if ($ENV{BATS_CWD}) { + return 1; + } else { + return 0; + } +} + +sub get_less_charset { + my @less_char_vars = ("LESSCHARSET", "LESSCHARDEF", "LC_ALL", "LC_CTYPE", "LANG"); + foreach (@less_char_vars) { + return $ENV{$_} if defined $ENV{$_}; + } + + return ""; +} + +sub should_print_unicode { + if (-t STDOUT) { + # Always print unicode chars if we're not piping stuff, e.g. to less(1) + return 1; + } + + # Otherwise, assume we're piping to less(1) + my $less_charset = get_less_charset(); + if ($less_charset =~ /utf-?8/i) { + return 1; + } + + return 0; +} + +# Return git config as a hash +sub get_git_config_hash { + my $out = git_config_raw(); + + my %hash; + foreach my $line (@$out) { + my ($key,$value) = split("=",$line,2); + + if ($key && $value) { + $value =~ s/\s+$//; + my @path = split(/\./,$key); + my $last = pop @path; + my $p = \%hash; + + # Build the tree for each section + $p = $p->{$_} ||= {} for @path; + $p->{$last} = $value; + } + } + + return \%hash; +} + +# Try and be smart about what line the diff hunk starts on +sub start_line_calc { + my ($line_num,$diff_context) = @_; + my $ret; + + if ($line_num == 0 && $diff_context == 0) { + return 1; + } + + # Git defaults to three lines of context + my $default_context_lines = 3; + # Three lines on either side, and the line itself = 7 + my $expected_context = ($default_context_lines * 2 + 1); + + # The first three lines + if ($line_num == 1 && $diff_context < $expected_context) { + $ret = $diff_context - $default_context_lines; + } else { + $ret = $line_num + $default_context_lines; + } + + if ($ret < 1) { + $ret = 1; + } + + return $ret; +} + +# Remove + or - at the beginning of the lines +sub strip_leading_indicators { + my $line = shift(); # Array passed in by reference + my $columns_to_remove = shift(); # Don't remove any lines by default + + if ($columns_to_remove == 0) { + return $line; # Nothing to do + } + + $line =~ s/^(${ansi_color_regex})[ +-]{${columns_to_remove}}/$1/; + + return $line; +} + +# Count the number of a given char in a string +sub char_count { + my ($needle,$str) = @_; + my $len = length($str); + my $ret = 0; + + for (my $i = 0; $i < $len; $i++) { + my $found = substr($str,$i,1); + + if ($needle eq $found) { $ret++; } + } + + return $ret; +} + +# Remove all ANSI codes from a string +sub bleach_text { + my $str = shift(); + $str =~ s/\e\[\d*(;\d+)*m//mg; + + return $str; +} + +# Remove all trailing and leading spaces +sub trim { + my $s = shift(); + if (!$s) { return ""; } + $s =~ s/^\s*|\s*$//g; + + return $s; +} + +# Print a line of em-dash or line-drawing chars the full width of the screen +sub horizontal_rule { + my $color = $_[0] || ""; + my $width = `tput cols`; + + if (is_windows()) { + $width--; + } + + # em-dash http://www.fileformat.info/info/unicode/char/2014/index.htm + #my $dash = "\x{2014}"; + # BOX DRAWINGS LIGHT HORIZONTAL http://www.fileformat.info/info/unicode/char/2500/index.htm + my $dash; + if ($use_unicode_dash_for_ruler && should_print_unicode()) { + $dash = Encode::encode('UTF-8', "\x{2500}"); + } else { + $dash = "-"; + } + + # Draw the line + my $ret = $color . ($dash x $width) . "\n"; + + return $ret; +} + +sub file_change_string { + my $file_1 = shift(); + my $file_2 = shift(); + + # If they're the same it's a modify + if ($file_1 eq $file_2) { + return "modified: $file_1"; + # If the first is /dev/null it's a new file + } elsif ($file_1 eq "/dev/null") { + my $add_color = $DiffHighlight::NEW_HIGHLIGHT[1]; + return "added: $add_color$file_2$reset_color"; + # If the second is /dev/null it's a deletion + } elsif ($file_2 eq "/dev/null") { + my $del_color = $DiffHighlight::OLD_HIGHLIGHT[1]; + return "deleted: $del_color$file_1$reset_color"; + # If the files aren't the same it's a rename + } elsif ($file_1 ne $file_2) { + my ($old, $new) = DiffHighlight::highlight_pair($file_1,$file_2,{only_diff => 1}); + $old = trim($old); + $new = trim($new); + + # highlight_pair resets the colors, but we want it to be the meta color + $old =~ s/(\e0?\[m)/$1$meta_color/g; + $new =~ s/(\e0?\[m)/$1$meta_color/g; + + return "renamed: $old to $new"; + # Something we haven't thought of yet + } else { + return "$file_1 -> $file_2"; + } +} + +# Check to see if STDIN is connected to an interactive terminal +sub has_stdin { + my $i = -t STDIN; + my $ret = int(!$i); + + return $ret; +} + +# We use this instead of Getopt::Long because it's faster and we're not parsing any +# crazy arguments +# Borrowed from: https://www.perturb.org/display/1153_Perl_Quick_extract_variables_from_ARGV.html +sub argv { + my $ret = {}; + + for (my $i = 0; $i < scalar(@ARGV); $i++) { + # If the item starts with "-" it's a key + if ((my ($key) = $ARGV[$i] =~ /^--?([a-zA-Z_]\w*)/) && ($ARGV[$i] !~ /^-\w\w/)) { + # If the next item does not start with "--" it's the value for this item + if (defined($ARGV[$i + 1]) && ($ARGV[$i + 1] !~ /^--?\D/)) { + $ret->{$key} = $ARGV[$i + 1]; + # Bareword like --verbose with no options + } else { + $ret->{$key}++; + } + } + } + + # We're looking for a certain item + if ($_[0]) { return $ret->{$_[0]}; } + + return $ret; +} + +# Output the command line usage for d-s-f +sub usage { + my $out = color("white_bold") . version() . color("reset") . "\n"; + + $out .= "Usage: + +git diff --color | diff-so-fancy # Use d-s-f on one diff +diff-so-fancy --colors # View the commands to set the recommended colors +diff-so-fancy --set-defaults # Configure git-diff to use diff-so-fancy and suggested colors + +# Configure git to use d-s-f for *all* diff operations +git config --global core.pager \"diff-so-fancy | less --tabs=4 -RFX\"\n"; + + return $out; +} + +sub get_default_colors { + my $out = "# Recommended default colors for diff-so-fancy\n"; + $out .= "# --------------------------------------------\n"; + $out .= 'git config --global color.ui true + +git config --global color.diff-highlight.oldNormal "red bold" +git config --global color.diff-highlight.oldHighlight "red bold 52" +git config --global color.diff-highlight.newNormal "green bold" +git config --global color.diff-highlight.newHighlight "green bold 22" + +git config --global color.diff.meta "yellow" +git config --global color.diff.frag "magenta bold" +git config --global color.diff.commit "yellow bold" +git config --global color.diff.old "red bold" +git config --global color.diff.new "green bold" +git config --global color.diff.whitespace "red reverse" +'; + + return $out; +} + +# Output the current version string +sub version { + my $ret = "Diff-so-fancy: https://github.com/so-fancy/diff-so-fancy\n"; + $ret .= "Version : $VERSION\n"; + + return $ret; +} + +# Feed the raw git input through diff-highlight to get line level highlights +sub filter_stdin_through_diff_highlight { + my @dh_lines; + + # Have DH put the lines it's modified in an array + local $DiffHighlight::line_cb = sub { push(@dh_lines,@_) }; + + while (my $line = ) { + my $ok = DiffHighlight::handle_line($line); + } + + DiffHighlight::flush(); + + return @dh_lines; +} + +sub is_windows { + if ($^O eq 'MSWin32' or $^O eq 'dos' or $^O eq 'os2' or $^O eq 'cygwin' or $^O eq 'msys') { + return 1; + } else { + return 0; + } +} + +# Return value is whether this is the first time they've run d-s-f +sub check_first_run { + my $ret = 0; + + # If first-run is not set, or it's set to "true" + my $first_run = git_config_boolean('diff-so-fancy.first-run'); + # See if they're previously set SOME diff-highlight colors + my $has_dh_colors = git_config_boolean('color.diff-highlight.oldnormal') || git_config_boolean('color.diff-highlight.newnormal'); + + #$first_run = 1; $has_dh_colors = 0; + + if (!$first_run || $has_dh_colors) { + return 0; + } else { + print "This appears to be the first time you've run diff-so-fancy, please note\n"; + print "that the default git colors are not ideal. Diff-so-fancy recommends the\n"; + print "following colors.\n\n"; + + print get_default_colors(); + + # Set the first run flag to false + my $cmd = 'git config --global diff-so-fancy.first-run false'; + system($cmd); + + exit; + } + + return 1; +} + +sub set_defaults { + my $color_config = get_default_colors(); + my $git_config = 'git config --global core.pager "diff-so-fancy | less --tabs=4 -RFX"'; + my $first_cmd = 'git config --global diff-so-fancy.first-run false'; + + my @cmds = split(/\n/,$color_config); + push(@cmds,$git_config); + push(@cmds,$first_cmd); + + # Remove all comments from the commands + foreach my $x (@cmds) { + $x =~ s/#.*//g; + } + + # Remove any empty commands + @cmds = grep($_,@cmds); + + foreach my $cmd (@cmds) { + system($cmd); + my $exit = ($? >> 8); + + if ($exit != 0) { + die("Error running: '$cmd' (error #18941)\n"); + } + } + + return 1; +} + +# String format: '115', '165_bold', '10_on_140', 'reset', 'on_173', 'red_bold', 'red_on_blue', 'blink', 'italic' +sub color { + my $str = shift(); + + # No string sent in, so we just reset + if (!length($str) || $str eq 'reset') { return "\e[0m"; } + + # Some predefined colors + my %color_map = qw(red 160 blue 21 green 34 yellow 226 orange 214 purple 93 white 15 black 0); + $str =~ s/$_/$color_map{$_}/g for keys %color_map; + + # Get foreground/background and any commands + my ($fc,$cmd) = $str =~ /^(\d+)?_?(\w+)?/g; + my ($bc) = $str =~ /on_?(\d+)$/g; + + # Some predefined commands + my %cmd_map = qw(bold 1 italic 3 underline 4 blink 5 inverse 7); + my $cmd_num = $cmd_map{$cmd || 0}; + + my $ret = ''; + if ($cmd_num) { $ret .= "\e[${cmd_num}m"; } + if (defined($fc)) { $ret .= "\e[38;5;${fc}m"; } + if (defined($bc)) { $ret .= "\e[48;5;${bc}m"; } + + return $ret; +} + +# vim: tabstop=4 shiftwidth=4 noexpandtab autoindent softtabstop=4 diff --git a/.fedora/vendor/rustup-init.sh b/.fedora/vendor/rustup-init.sh new file mode 100755 index 00000000..20f1a59d --- /dev/null +++ b/.fedora/vendor/rustup-init.sh @@ -0,0 +1,387 @@ +#!/bin/bash +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +# This is just a little script that can be downloaded from the internet to +# install rustup. It just does platform detection, downloads the installer +# and runs it. + +set -u + +RUSTUP_UPDATE_ROOT="https://static.rust-lang.org/rustup/dist" + +#XXX: If you change anything here, please make the same changes in setup_mode.rs +usage() { + cat 1>&2 < Choose a default host triple + --default-toolchain Choose a default toolchain to install + --default-toolchain none Do not install any toolchains +EOF +} + +main() { + downloader --check + need_cmd uname + need_cmd mktemp + need_cmd chmod + need_cmd mkdir + need_cmd rm + need_cmd rmdir + + get_architecture || return 1 + local _arch="$RETVAL" + assert_nz "$_arch" "arch" + + local _ext="" + case "$_arch" in + *windows*) + _ext=".exe" + ;; + esac + + local _url="$RUSTUP_UPDATE_ROOT/$_arch/rustup-init$_ext" + + local _dir="$(mktemp -d 2>/dev/null || ensure mktemp -d -t rustup)" + local _file="$_dir/rustup-init$_ext" + + local _ansi_escapes_are_valid=false + if [ -t 2 ]; then + if [ "${TERM+set}" = 'set' ]; then + case "$TERM" in + xterm*|rxvt*|urxvt*|linux*|vt*) + _ansi_escapes_are_valid=true + ;; + esac + fi + fi + + # check if we have to use /dev/tty to prompt the user + local need_tty=yes + for arg in "$@"; do + case "$arg" in + -h|--help) + usage + exit 0 + ;; + -y) + # user wants to skip the prompt -- we don't need /dev/tty + need_tty=no + ;; + *) + ;; + esac + done + + if $_ansi_escapes_are_valid; then + printf "\33[1minfo:\33[0m downloading installer\n" 1>&2 + else + printf '%s\n' 'info: downloading installer' 1>&2 + fi + + ensure mkdir -p "$_dir" + ensure downloader "$_url" "$_file" + ensure chmod u+x "$_file" + if [ ! -x "$_file" ]; then + printf '%s\n' "Cannot execute $_file (likely because of mounting /tmp as noexec)." 1>&2 + printf '%s\n' "Please copy the file to a location where you can execute binaries and run ./rustup-init$_ext." 1>&2 + exit 1 + fi + + + + if [ "$need_tty" = "yes" ]; then + # The installer is going to want to ask for confirmation by + # reading stdin. This script was piped into `sh` though and + # doesn't have stdin to pass to its children. Instead we're going + # to explicitly connect /dev/tty to the installer's stdin. + if [ ! -t 1 ]; then + err "Unable to run interactively. Run with -y to accept defaults, --help for additional options" + fi + + ignore "$_file" "$@" < /dev/tty + else + ignore "$_file" "$@" + fi + + local _retval=$? + + ignore rm "$_file" + ignore rmdir "$_dir" + + return "$_retval" +} + +get_bitness() { + need_cmd head + # Architecture detection without dependencies beyond coreutils. + # ELF files start out "\x7fELF", and the following byte is + # 0x01 for 32-bit and + # 0x02 for 64-bit. + # The printf builtin on some shells like dash only supports octal + # escape sequences, so we use those. + local _current_exe_head=$(head -c 5 /proc/self/exe ) + if [ "$_current_exe_head" = "$(printf '\177ELF\001')" ]; then + echo 32 + elif [ "$_current_exe_head" = "$(printf '\177ELF\002')" ]; then + echo 64 + else + err "unknown platform bitness" + fi +} + +get_endianness() { + local cputype=$1 + local suffix_eb=$2 + local suffix_el=$3 + + # detect endianness without od/hexdump, like get_bitness() does. + need_cmd head + need_cmd tail + + local _current_exe_endianness="$(head -c 6 /proc/self/exe | tail -c 1)" + if [ "$_current_exe_endianness" = "$(printf '\001')" ]; then + echo "${cputype}${suffix_el}" + elif [ "$_current_exe_endianness" = "$(printf '\002')" ]; then + echo "${cputype}${suffix_eb}" + else + err "unknown platform endianness" + fi +} + +get_architecture() { + + local _ostype="$(uname -s)" + local _cputype="$(uname -m)" + + if [ "$_ostype" = Linux ]; then + if [ "$(uname -o)" = Android ]; then + local _ostype=Android + fi + fi + + if [ "$_ostype" = Darwin -a "$_cputype" = i386 ]; then + # Darwin `uname -s` lies + if sysctl hw.optional.x86_64 | grep -q ': 1'; then + local _cputype=x86_64 + fi + fi + + case "$_ostype" in + + Android) + local _ostype=linux-android + ;; + + Linux) + local _ostype=unknown-linux-gnu + ;; + + FreeBSD) + local _ostype=unknown-freebsd + ;; + + NetBSD) + local _ostype=unknown-netbsd + ;; + + DragonFly) + local _ostype=unknown-dragonfly + ;; + + Darwin) + local _ostype=apple-darwin + ;; + + MINGW* | MSYS* | CYGWIN*) + local _ostype=pc-windows-gnu + ;; + + *) + err "unrecognized OS type: $_ostype" + ;; + + esac + + case "$_cputype" in + + i386 | i486 | i686 | i786 | x86) + local _cputype=i686 + ;; + + xscale | arm) + local _cputype=arm + if [ "$_ostype" = "linux-android" ]; then + local _ostype=linux-androideabi + fi + ;; + + armv6l) + local _cputype=arm + if [ "$_ostype" = "linux-android" ]; then + local _ostype=linux-androideabi + else + local _ostype="${_ostype}eabihf" + fi + ;; + + armv7l | armv8l) + local _cputype=armv7 + if [ "$_ostype" = "linux-android" ]; then + local _ostype=linux-androideabi + else + local _ostype="${_ostype}eabihf" + fi + ;; + + aarch64) + local _cputype=aarch64 + ;; + + x86_64 | x86-64 | x64 | amd64) + local _cputype=x86_64 + ;; + + mips) + local _cputype="$(get_endianness $_cputype "" 'el')" + ;; + + mips64) + local _bitness="$(get_bitness)" + if [ $_bitness = "32" ]; then + if [ $_ostype = "unknown-linux-gnu" ]; then + # 64-bit kernel with 32-bit userland + # endianness suffix is appended later + local _cputype=mips + fi + else + # only n64 ABI is supported for now + local _ostype="${_ostype}abi64" + fi + + local _cputype="$(get_endianness $_cputype "" 'el')" + ;; + + ppc) + local _cputype=powerpc + ;; + + ppc64) + local _cputype=powerpc64 + ;; + + ppc64le) + local _cputype=powerpc64le + ;; + + *) + err "unknown CPU type: $_cputype" + + esac + + # Detect 64-bit linux with 32-bit userland + if [ $_ostype = unknown-linux-gnu -a $_cputype = x86_64 ]; then + if [ "$(get_bitness)" = "32" ]; then + local _cputype=i686 + fi + fi + + # Detect armv7 but without the CPU features Rust needs in that build, + # and fall back to arm. + # See https://github.com/rust-lang-nursery/rustup.rs/issues/587. + if [ $_ostype = "unknown-linux-gnueabihf" -a $_cputype = armv7 ]; then + if ensure grep '^Features' /proc/cpuinfo | grep -q -v neon; then + # At least one processor does not have NEON. + local _cputype=arm + fi + fi + + local _arch="$_cputype-$_ostype" + + RETVAL="$_arch" +} + +say() { + echo "rustup: $1" +} + +err() { + say "$1" >&2 + exit 1 +} + +need_cmd() { + if ! check_cmd "$1" + then err "need '$1' (command not found)" + fi +} + +check_cmd() { + command -v "$1" > /dev/null 2>&1 + return $? +} + +need_ok() { + if [ $? != 0 ]; then err "$1"; fi +} + +assert_nz() { + if [ -z "$1" ]; then err "assert_nz $2"; fi +} + +# Run a command that should never fail. If the command fails execution +# will immediately terminate with an error showing the failing +# command. +ensure() { + "$@" + need_ok "command failed: $*" +} + +# This is just for indicating that commands' results are being +# intentionally ignored. Usually, because it's being executed +# as part of error handling. +ignore() { + "$@" +} + +# This wraps curl or wget. Try curl first, if not installed, +# use wget instead. +downloader() { + if check_cmd curl + then _dld=curl + elif check_cmd wget + then _dld=wget + else _dld='curl or wget' # to be used in error message of need_cmd + fi + + if [ "$1" = --check ] + then need_cmd "$_dld" + elif [ "$_dld" = curl ] + then curl -sSfL "$1" -o "$2" + elif [ "$_dld" = wget ] + then wget "$1" -O "$2" + else err "Unknown downloader" # should not reach here + fi +} + +main "$@" || exit 1