#!/usr/bin/env perl =pod =head1 NAME notes-links - work with links within my notes =head1 SYNOPSIS Currently this is vimwiki-dependent. # List pages linking to foo: notes links --target foo # Pages linking to foo.wiki: notes links --file ./foo.wiki # Pages with a date (i.e. logs and diaries) linking to foo: notes links --with-date --target foo # Links in foo (experimental, probably broken): notes links --source foo =head1 AUTHOR Brennen Bearnes =cut use warnings; use strict; use 5.10.0; use Cwd; use Data::Dumper; use DBI; use File::Basename; use File::Spec; use Getopt::Long; use Pod::Usage; use SQL::Abstract; use Sys::Hostname; # Display formats: my %FORMATS = ( vimwiki => sub { my ($data) = @_; my $timestamp = ''; if (defined $data->{timestamp}) { $timestamp = $data->{timestamp} . " "; } return ' - ' . $timestamp . '[[/' . $data->{page} . '|' . $data->{title} . "]]\n"; }, tsv => sub { my ($data) = @_; my $timestamp = '(null)'; if (defined $data->{timestamp}) { $timestamp = $data->{timestamp}; } return (join "\t", ($timestamp, $data->{page}, $data->{title})) . "\n"; }, # vim location list # # TODO: Note that the "1" here is, theoretically, a line number. # Unfortunately, there's no obvious way to extract that from Pandoc's parsing # of the original file, and thus no non-hacky way for notes-collect-metadata to # store an approximate value in the database. We _could_ read the file # line-by-line, or run grep, looking for the file's basename, but this is # tricky to get right. # # If I keep using this long-term, I should solve this problem. location => sub { my ($data) = @_; my $result = "$ENV{HOME}/notes/vimwiki/$data->{page}.wiki"; if ($data->{title}) { $result .= ":1:$data->{title}"; } else { $result .= print ":1:$data->{page}" } return $result . "\n"; }, # Fulltext of vimwiki pages: full => sub { my ($data) = @_; my $result = ''; my $pagepath = "$ENV{HOME}/notes/vimwiki/$data->{page}.wiki"; $result .= "%% $pagepath {{{\n\n"; $result .= file_get_contents($pagepath); $result .= "\n%% }}}\n\n"; return $result; }, # Bare names of wiki pages (no extension): name => sub { my ($data) = @_; return $data->{page} . "\n"; }, ); # Handle options, including help generated from the POD above. my $debug = 0; my $with_date = 0; my $target; my $source; my $file; my $format = 'location'; GetOptions( 'debug' => \$debug, 'target=s' => \$target, 'file=s' => \$file, 'format=s' => \$format, 'with-date' => \$with_date, 'help' => sub { pod2usage(0) }, ) or pod2usage(2); if (defined $file) { my ($name, $path, $suffix) = fileparse($file, '.wiki'); # XXX: This is a dirty fucking hack - get rid of the leading path stuff, but # keep subdirs within the vimwiki directory: $path =~ s{^.*?notes/vimwiki/}{}; $target = $path . $name; } my %where = (); # Require that the link point to a given page: if (defined $target) { $where{target} = $target; } # Get only links from pages that have a datetime: if ($with_date) { # NOT NULL: $where{'pages.datetime'} = { '!=', undef }; } my $dbfile = $ENV{HOME} . "/notes/metadata.db"; my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile", "", ""); my $sql = SQL::Abstract->new; my ($query, @bind) = $sql->select( 'links JOIN pages ON links.page = pages.page', # timestamp will be null if datetime is "*, DATETIME(datetime, 'localtime') AS timestamp", \%where, {-desc => [ 'datetime', 'page' ] } ); if ($debug) { say STDERR $query; say STDERR Dumper(%where); } my $sth = $dbh->prepare($query); $sth->execute(@bind); while (my $data = $sth->fetchrow_hashref()) { if ($debug) { print STDERR Dumper($data); } print $FORMATS{$format}->($data); } $sth->execute(); # PHP-style file-content grabbing: sub file_get_contents { my ($file) = @_; open my $fh, '<', $file or die "Couldn't open $file: $!\n"; my $contents; { # line separator: local $/ = undef; $contents = <$fh>; } close $fh or die "Couldn't close $file: $!"; return $contents; } 1;