Re: A new way to get a sha1?

2 messages, 2 authors, 2016-06-15 · open the first message on its own page

Re: A new way to get a sha1?

From: Thomas Rast <hidden>
Date: 2016-06-15 22:54:23

Thomas Badie [off-list ref] writes:
The idea is to have a perl module which run through
the log history and print 10 shortlog associated with a number
from 0 to 9, and a message below "Select commit [| 0, 9 |] or
next row ?" or this kind of message with several options.

So I ask to the community if this module is interesting for git.
It can be integrated everywhere a sha1 is requested (git rebase,
git reset, ...). IMHO, it can be an enhancement.
I think this is too specific.  If you want full interactivity, use a
real interactive tool like tig.

However, your post and some quick searching gave me another idea.  Bash
actually has features to let you edit the current command line from
within key bindings.  So if only we had some clever utility, let's call
it lineselect for lack of a better name, that let us do

  git log --oneline <args> | lineselect

then we could paste the selected SHA1 into the command line.  That would
be really neat, wouldn't it?

I haven't found such a utility, so below is my first shot at making
something useful.  It has:

* a few keybinds that should make most people happy
* color rendering (yay), but because of issues with the default
  rendering, it sets white-on-black by default
* an optional regex arg to select only parts of the lines

Things that notably _don't_ work yet:

* cursor keys (I have no idea why it doesn't match KEY_UP etc.)
* ANSI attributes (colors work, of sorts)
* Searching the next occurrence of a search string

But you can probably guess that those aren't a huge problem for me.

I made a little repo too, for all your forking needs:

  https://github.com/trast/lineselect.git
  git://github.com/trast/lineselect.git

Thanks for the idea :-)


------ 8< ------
#!/usr/bin/perl

use warnings;
use strict;
use Curses;

my @lines;

open my $input, "<&STDIN" or die "Can't dup STDIN: $!";
open my $output, ">&STDOUT" or die "Can't dup STDOUT: $!";
open STDIN, "<", "/dev/tty" or die "Can't open TTY (in): $!";
open STDOUT, ">", "/dev/tty" or die "Can't open TTY (out): $!";

my $eof = -1;

sub read_more {
	my $n = $_[0];
	if ($eof > 0) {
		return;
	}
	while ($n >= scalar @lines) {
		my $read = <$input>;
		if (!defined $read) {
			$eof = scalar @lines;
			return;
		}
		push @lines, $read;
	}
}

my $pat;
my ($rows, $cols);
my $sel = 0;

my $top = 0;

my $cmdline = ":";

my $fg = 7;
my $bg = 0;
sub set_color {
	attron(COLOR_PAIR(1+$fg+8*$bg));
}

sub print_color_line {
	my $line = $_[0];
	my $remain = $cols;
	$fg = 7;
	$bg = 0;
	set_color;
	while ($line =~ m{^([^\e]*)\e\[([^m]*)m(.*)}) {
		printw($1);
		$remain -= length $1;
		$line = $3;
		if ($2 eq "") {
			$fg = 7;
			$bg = 0;
			set_color;
		} else {
			for my $c (split /;/, $2) {
				if (30 <= $c and $c < 38) {
					$fg = $c - 30;
				} elsif (40 <= $c and $c < 48) {
					$bg = $c - 30;
				}
			}
			set_color;
		}
	}
	printw($line);
	$remain -= length $line;
	if ($remain > 0) {
		printw(" "x$remain);
	}
}

sub redraw {
	read_more $top+$rows-1;
	clear;
	attron(COLOR_PAIR(8));
	for my $i (0..$rows-2) {
		if ($top+$i == $sel) {
			attron(A_STANDOUT);
		} else {
			attroff(A_STANDOUT);
		}
		move($i, 0);
		print_color_line($lines[$top+$i]);
	}
	move($rows-1, 0);
	attron(COLOR_PAIR(8));
	attron(A_STANDOUT);
	printw($cmdline);
	attroff(A_STANDOUT);
	refresh();
}

sub adjust_view {
	if ($sel < 0) {
		return;
	} elsif ($sel >= $top+$rows-1) {
		$top = $sel-$rows+2;
	} elsif ($sel < $top) {
		$top = $sel;
	}
}

sub forward;
sub backward {
	my $n = $_[0];
	$sel -= $n;
	while (defined $pat and $lines[$sel] !~ m{$pat}) {
		$sel--;
		read_more $sel;
		if ($sel < 0) {
			$sel = 0;
			forward 0;
			return;
		}
	}
	if ($sel < 0) {
		$sel = 0;
	}
	adjust_view;
}

sub forward {
	my $n = $_[0];
	$sel += $n;
	while (defined $pat and $lines[$sel] !~ m{$pat}) {
		$sel++;
		read_more $sel;
		if ($eof > 0 and $sel >= $eof) {
			$sel = $eof-1;
			backward 0;
			return;
		}
	}
	adjust_view;
}

sub search {
	my $start = $sel;
	my $search_str = "";
	while (1) {
		$sel = $start;
		my $case_sens = ($search_str ne lc $search_str);
		while (1) {
			if ($eof > 0 and $sel >= $eof) {
				$sel = -1;
				last;
			}
			if (defined $pat and $lines[$sel] !~ m{$pat}) {
				$sel++;
				read_more $sel;
				next;
			}
			if ($case_sens and $lines[$sel] =~ m{$search_str}) {
				last;
			}
			if (!$case_sens and $lines[$sel] =~ m{$search_str}i) {
				last;
			}
			$sel++;
			read_more $sel;
		}
		adjust_view;
		$cmdline = "/" . $search_str;
		$cmdline = "NO MATCH -- " . $cmdline if $sel < 0;
		redraw;
		my $c = getch();
		if ($c eq "\b" or $c eq "\x7f") {
			$search_str = substr $search_str, 0, length($search_str)-1;
		} elsif ($c eq "\n") {
			$sel = $start if $sel < 0;
			return;
		} elsif ($c eq "\033") {
			$sel = $start;
			return;
		} else {
			$search_str .= $c;
		}
	}
}

sub mainloop {
	while (1) {
		getmaxyx($rows, $cols);
		$cmdline = ":";
		redraw;
		my $c = getch();
		if ($c eq " ") {
			$sel += $rows-1;
			read_more $sel;
			$sel = $eof-1 if $eof > 0 and $sel > $eof;
			adjust_view;
		} elsif ($c eq "q") {
			return;
		} elsif ($c eq KEY_ENTER or $c eq "\n") {
			return $lines[$sel];
		} elsif ($c eq "n" or $c eq "j" or $c eq KEY_DOWN) {
			forward 1;
		} elsif ($c eq "p" or $c eq "k" or $c eq KEY_UP) {
			backward 1;
		} elsif ($c eq "/" or $c eq "f") {
			search;
		} elsif ($c eq "<" or $c eq KEY_HOME) {
			$sel = 0;
			adjust_view;
		} elsif ($c eq ">" or $c eq KEY_END) {
			while ($eof < 0) {
				$sel++;
				read_more $sel;
			}
			$sel = $eof-1;
			adjust_view;
		}
	}
}

if (0 < scalar @ARGV) {
	$pat = $ARGV[0];
}

initscr;
start_color;
for my $f (0..7) {
	for my $b (0..7) {
		init_pair(1+$f+8*$b,$f,$b);
	}
}
my $r = mainloop;
endwin;
if (defined $r) {
	$r =~ s{\e\[([^m]*)m}{}g;
	if (defined $pat) {
		$r =~ m/$pat/;
		$r = $1;
		die "BUG: should never get here" if (!defined $r);
	}
	print $output "$r";
} else {
	exit 1;
}

Re: A new way to get a sha1?

From: Thomas Badie <hidden>
Date: 2016-06-15 22:54:23

2012/7/30 Thomas Rast [off-list ref]:
Thomas Badie [off-list ref] writes:
quoted
The idea is to have a perl module which run through
the log history and print 10 shortlog associated with a number
from 0 to 9, and a message below "Select commit [| 0, 9 |] or
next row ?" or this kind of message with several options.

So I ask to the community if this module is interesting for git.
It can be integrated everywhere a sha1 is requested (git rebase,
git reset, ...). IMHO, it can be an enhancement.
I think this is too specific.  If you want full interactivity, use a
real interactive tool like tig.
Second suggestion for tig. I must definitely try it.
However, your post and some quick searching gave me another idea.  Bash
actually has features to let you edit the current command line from
within key bindings.  So if only we had some clever utility, let's call
it lineselect for lack of a better name, that let us do

  git log --oneline <args> | lineselect

then we could paste the selected SHA1 into the command line.  That would
be really neat, wouldn't it?

I haven't found such a utility, so below is my first shot at making
something useful.  It has:

* a few keybinds that should make most people happy
* color rendering (yay), but because of issues with the default
  rendering, it sets white-on-black by default
* an optional regex arg to select only parts of the lines
Very interesting. I tried it and it is nice. I fix a little bug ("Use of
uninitialized...") on my fork. I will take a look on the things that
don't work yet ;) I'm pretty sure that there is a lot of possible
usage of this script.
Things that notably _don't_ work yet:

* cursor keys (I have no idea why it doesn't match KEY_UP etc.)
* ANSI attributes (colors work, of sorts)
* Searching the next occurrence of a search string

But you can probably guess that those aren't a huge problem for me.

I made a little repo too, for all your forking needs:

  https://github.com/trast/lineselect.git
  git://github.com/trast/lineselect.git
Thanks for sharing it!
Thanks for the idea :-)
You're very welcome!

-- 
Thomas "Enki" Badie
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help