App-Notes

 view release on metacpan or  search on metacpan

bin/notes  view on Meta::CPAN

#!/usr/bin/env perl
use v5.10;
use strict;
use warnings;
use App::Rad;
use Capture::Tiny qw( capture );
use Git::Repository;
use List::MoreUtils qw( firstidx );
use Path::Class qw( file dir );

# ABSTRACT: Simple. Git-based. Notes.

sub setup {
    my ( $c ) = @_;
    $c->register_commands({
        add     => 'add a new note, and edit it',
        append  => 'append to a note',
        delete  => 'delete the note',
        edit    => 'edit a note',
        init    => 'Initiliazie notes (optionally from remote repo)',
        list    => 'lists id and subject of all notes',
        rename  => 'rename a note',
        replace => 'replace the contents of the note ( from STDIN )',
        show    => 'show the contents of the note',
        sync    => 'Sync notes with remote (pull + push)',
    });
    $c->register_command(mv => \&rename, 'alias for rename');
}

sub pre_process {
    my ( $c ) = @_;
    my $cmd = $c->cmd;

    # If we aren't initializing, check to make sure our notes directory exists
    if( $cmd ne 'init' ) {
        if( -d notes_repo() ) {
            $c->stash->{git} = Git::Repository->new( git_dir => notes_repo() );
        } else {
            # We are not initialized
            die "Notes Directory has not been initialized!\n" .
                "Run init [remote git repo] to initialize.\n";
        }
    }

    return if not $c->is_command($cmd) or $cmd ~~ [qw( help init sync )];
    sync( $c, pull_only => 1 ) if auto_sync();
}

sub post_process {
    my ( $c ) = @_;
    my $cmd = $c->cmd;
    if($c->is_command($cmd) and not $cmd ~~ [qw( help init list show sync )]) {
        sync( $c, push_only => 1 ) if auto_sync();
    }
    say $c->output if $c->output;
}

sub invalid {
    my ( $c ) = @_;
    my $cmd = $c->cmd;
    ($cmd) = grep { /^$cmd/ } $c->commands;
    $cmd ? $c->execute( $cmd ) : $c->execute( 'help' );
    return; # This makes the command name not be printed from the last line
}

App::Rad->run;

# helpers ---------------------------------------------------------------------

sub editor { $ENV{EDITOR} || 'vim' }
sub notes_dir { dir( $ENV{APP_NOTES_DIR} ) || dir( $ENV{HOME}, '.notes' ) }
sub notes_repo { file( notes_dir, '.git' ) }
sub auto_sync {  $ENV{APP_NOTES_AUTOSYNC} // 1 }

sub has_origin {
    grep { /^origin$/ } split ' ', $_[0]->stash->{git}->run( 'remote' )
}

sub find_notes {
    my ( $c, %args ) = @_;
    my $search = $args{search};
    my @notes = map file($_), sort {-M $a <=> -M $b} glob file(notes_dir, '*');

    # Filter results if requested
    if (defined $search) {
        @notes = grep { $_->basename =~ /$search/i } @notes;
        # If there is an exact match, make sure it is first
        my $idx = firstidx { $search eq $_->basename } @notes;
        unshift @notes, splice @notes, $idx, 1 if $idx > 0;
    }

    return \@notes;
}

sub read_stdin { local $/; <STDIN> }

sub check_stdin { ( -t STDIN ) ? 0 : read_stdin() }

sub get_title { join ' ', @ARGV; }

sub get_filename {
    return undef unless $_[0];
    ( my $r = $_[0] ) =~ s/ /-/g;
    return  $r;
}

sub is_yes { shift ~~ /^y(es)?$/i }

sub edit_file {
    my ( $c, $file, %args ) = @_;

    $args{check_stdin} //= 1; # Default to check stdin
    my $verb = ( -e $file->stringify ) ? "Updated " : "Created ";

    my $stdin = $args{check_stdin} ? check_stdin() : 0;

bin/notes  view on Meta::CPAN


    my $file = file( notes_dir(), get_filename( $title ) );
    die "File already exists!" if -e $file;

    edit_file( $c, $file );
}

sub append {
    my ( $c ) = @_;
    my $title = get_title();
    my $notes = find_notes( $c, search => get_filename( $title ) );

    die "No matching notes found" unless @$notes > 0;

    my $file = $notes->[0];
    edit_file( $c, $file, append => 1 );
}

sub delete {
    my ( $c ) = @_;
    my $title = get_title();
    my $notes = find_notes( $c, search => get_filename( $title ) );

    die "No matching note found!" unless @$notes > 0;
    my $to_rm = $notes->[0];

    print qq(Delete "@{[$to_rm->basename]}" ? );
    my $res = <STDIN>;

    if( is_yes($res) ) {
        my $output = capture {
            my $msg = qq(Removed "$to_rm");
            $c->stash->{git}->run( rm => "$to_rm" );
            $c->stash->{git}->run( commit => -m => $msg );
        };
    } else {
        return "Not Removed.";
    }
}

sub edit {
    my ( $c ) = @_;
    my $title = get_title();
    my $notes = find_notes( $c, search => get_filename( $title ) );

    die "No matching notes found!" unless @$notes > 0;
    my $to_edit = $notes->[0];

    edit_file( $c, $to_edit, check_stdin => 0 );
}

sub init {
    my ( $c ) = @_;

    die "Notes dir already exists!" if -d notes_dir();

    my $dir = notes_dir();
    my $repo = $ARGV[0];
    my $output = capture {
        if( $repo ) {
            say "Initializing notes from $repo...";
            Git::Repository->run( clone => $repo, $dir->stringify );
        } else {
            say "Initializing notes ($dir)...";
            print Git::Repository->run( init => $dir->stringify );
        }
    }
}

sub list {
    my ( $c ) = @_;
    my $search = @ARGV > 0 ? join ' ', @ARGV : undef;
    my $notes = find_notes( $c, search => get_filename( $search ) );
    say $_->basename for @$notes;
    return;
}

sub rename {
    my ( $c ) = @_;
    my $cmd = $c->cmd;
    die "usage: $0 $cmd <orig_name> <new_name>\n" unless @ARGV == 2;
    my ($orig_name, $new_name) = @ARGV;
    my $notes = find_notes( $c, search => get_filename( $orig_name ) );
    die "No such note [$orig_name]" unless @$notes;
    my ($orig_file, $new_file) = ($notes->[0], get_filename($new_name));
    print qq(Rename "@{[$orig_file->basename]}" to "$new_name" ? );
    my $res = <STDIN>;
    if( is_yes($res) ){
        $c->stash->{git}->run(mv => "$orig_file" => "$new_file");
        $c->stash->{git}->run(commit => '-m',
            "Rename " . $orig_file->basename . " => $new_file");
    }
    return;
}

sub replace {
    my ( $c ) = @_;
    my $title = get_title();
    my $notes = find_notes( $c, search => get_filename( $title ) );

    die "No matching notes found" unless @$notes > 0;

    my $file = $notes->[0];
    edit_file( $c, $file );
}

sub show {
    my ( $c ) = @_;
    my $title = get_title();
    my $notes = find_notes( $c, search => get_filename( $title ) );

    die "No matching notes found" unless @$notes > 0;

    system "cat $notes->[0]";
}

sub sync {
    my ( $c, %args ) = @_;
    return unless has_origin( $c );

    my $output = capture {
        $c->stash->{git}->run( 'pull' ) unless $args{push_only};
        $c->stash->{git}->run( 'push' ) unless $args{pull_only};
    };
    return;
}

# PODNAME: notes



__END__
=pod



( run in 0.842 second using v1.01-cache-2.11-cpan-9169edd2b0e )