Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

'h' - a Win32 command-line history

by osfameron (Hermit)
on Nov 11, 2001 at 17:53 UTC ( [id://124663]=sourcecode: print w/replies, xml ) Need Help??
Category: Win32 Stuff
Author/Contact Info hakim@earthling.net
Description:

A command line history recall for Win32. Tries to emulate some of the functionality of Unix versions. I'm quite pleased with the use of Win32::Console to emulate Term::Readline's (non-functional) addhistory method. (but happy to get suggestions of better ways to do this!!)

Note: If this can be done better, safer etc. please let me know - I will welcome review, criticism etc.!

Update: Replaced the batch wrapper (which is redundant since I'm just writing to STDIN...). On the other hand, this also means that we lose the ability to recall a numbered item. hmmm.

=head1 NAME

C<h> - a command line historian...

=head1 DESCRIPTION

A 'history' script for the Windows command line.  While Unix shells al
+low
quite flexible history calling: grepping for patterns etc., Windows on
+ly
allows you to either tab up and down using the arrow cursors, or use F
+7 and
F9 to select (and execute) an entry from a list or recall a numbered e
+ntry
(and edit/execute).

C<h> offers this additional facility of being able to grep for command
+s fitting 
a particular pattern.  

It is basically a wrapper around the standard C<doskey> command in Win
+32, using
Aldo Calpini's Win32::Console to generate the selective command histor
+y.

=head1 SYNOPSIS

 h             shows history of commands
 h dir         shows history of all commands matching 'dir'
 h /jpe?g/     regular expression on history

The list of all matching commands will be returned: you are prompted w
+ith
the most recent command, for example:

 Re-run (ESC to cancel)> perldoc h.pl

The last of the matching commands will be automatically
placed into your command prompt and you can edit and run
as normal.  Using the UP and DOWN arrow keys will tab 
through the selected list.

=cut

use strict; use warnings;
use Win32::Console;
my $cons=Win32::Console->new(STD_INPUT_HANDLE);

# Help: currently invoked using Perldoc - could change to Pod::Usage I
+ suppose
if (defined $ARGV[0] && $ARGV[0]=~/^[\/-][hH?]/) {
    close BAT;
    system "perldoc $0";
    exit;
}

my $OPT=$ENV{HIST_OPT} || '';
# I'm being lazy (and probably inefficient) by
# just parsing the options when needed using a regexp. 
# (and by not accepting switches on the command line)

=head1 OPTIONS

The environment variable HIST_OPT can be set
to a string containing various options.

 OPTIONS
     /v         Verbose
     /limit=10  Show only 10 most recent options
     /nodup     Ignore duplicates.  (Alternatively you may prefer to
                set this on a Shell basis 
                (Alt-Space - Properties - Options - "Discard Old Dupli
+cates"

for example (from the commandline)

     set hist_opt=/verbose /nodup

=cut

my @hist=split /\n/, `doskey /history`; # latest last.

@hist=grep (!/^h\b/i, @hist); # remove any references to hist itself
                              # I used to have an option to do this
                              # but reckon it's a sensible default!

if ($OPT=~/[\/-]nodup/i) {
    my %seen;
    @hist = reverse grep (! $seen{$_}++ , reverse @hist);
    # I'm reversing the list so that if there are duplicates, we see t
+he
    # most recent time only
}

if ($OPT=~/[\/-]limit=(\d+)/i) {
    @hist=@hist[-$1..-1];
}

if (! @ARGV) {
    show_hist('ALL', @hist);
} else {
    my $grep='';
    if ($ARGV[0]=~m{^/(.*?)/?$}) {
        $grep=qr{$1};
    } else {
        $grep=$ARGV[0];
    }
    my @grep = grep (/$grep/, @hist);
    show_hist($grep, @grep);
}

close BAT;

###############

sub show_hist {
    my ($what, @hist)=@_;
    print "Options: $OPT\nHistory: $what\n==============\n" if $OPT=~/
+[-\/][vV]/;
    my $line=0; my $dummy;
    if (@hist) {
        for (@hist) {
        # write each line of the history to STDIN, followed by
        # a NEWLINE chr(13) (except for the last one).
        # The $dummy variable reads what we've written... but
        # the option is still preserved in doskeys's command
        # history so you can tab up and down the list with UP
        # and DOWN arrows
            if ($line) {
                write_input(chr(13));
                $dummy=<STDIN>;
            }
            print ++$line.": ";
            write_input($_); 
        }
        print $hist[-1];
    } else {
        print "-- no commands --\n";
    }
    print "\n";
}



sub write_input {
    my $string=shift;
    for (split //, $string) {
        # This doesn't quite seem to be the format listed in Win32::Co
+nsole
        # documentation at all: it is supposed to take the same format
        # as the return value of Input, which doesn't work!
        # 1 = Keyboard input
        # 1 = keydown, 0 = keyup (if we miss the second event, we won'
+t
        #                         push multiples of the same character
+...)
        # 1 = Repeat count
        # Virtual Key code  } Doesn't appear to matter what 
        # Virtual Scan code } goes in these !
        # Char              } 
        # Control Key State - this is the parameter that I am passing
        #                     the ASCII code for the character with.
        
        $cons->WriteInput(1,1,1,1,1,1,ord($_));
        $cons->WriteInput(1,0,1,1,1,1,ord($_));
    }
}

=head1 AUTHOR, VERSION, COPYRIGHT, WARNING

 hakim@earthling.net
 version 0.04
 This is TEST CODE.  No warranty is implied.  Use at your own risk.

Please contact me for any comments or questions, I will try to help, h
+owever I cannot guarantee any particular support.

=head1 BUGS and CHANGES

=over 4

=item 1

(2001-11-10) FIXED:  
No means of editing the command line (apart from copying and pasting i
+t).
My copy of Term::ReadLine doesn't support the 'addhistory' option whic
+h
would have been ideal... (2001-11-11) used Win32::Console's WriteInput
method.  Maybe Term::Readline could be patched to use a similar method
+ to
implement this for Windows?

=item 2

(2001-11-11) FIXED: (see item 5)
If the command history is edited it isn't itself propagated to doskey 
+/history
(because it's run from a batch file...) so it won't be visible to late
+r
hist calls.  This also means that rerunning a command will not make it
appear later in the history list.

=item 3

(2001-11-11) CHANGED:
Renamed from C<hist> to C<h> as hist is too much typing...

=item 4

(2001-11-11) OPEN:
Has only been tested on Win2K so far.

=item 5

(2001-11-11) CHANGED:
Got rid of the whole batch wrapper concept: realised that as the histo
+ry is
passed back into STDIN, I no longer need to input the command myself!

=item 6
(2001-11-11) OPEN:
Because I'm adding things into STDIN, the order of the history appears
+ to be
messed up.  Fine if you're grepping for specifics but annoying if you 
+wanted
a chronological view.

=back

=cut
Replies are listed 'Best First'.
Re: 'h' - a Win32 command-line history
by Rex(Wrecks) (Curate) on Nov 13, 2001 at 05:58 UTC
    You cover everything but the native Win32 hotkey I use most in your doc. I use F8 for a lot, you type the begining of a command and F8 through any of the previous commands in the history buffer.

    "Nothing is sure but death and taxes" I say combine the two and its death to all taxes!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://124663]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2024-04-18 07:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found