Dotfiles, utilities, and other apparatus.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

201 lines
4.2 KiB

  1. #!/usr/bin/env perl
  2. =pod
  3. =head1 NAME
  4. notes-links - work with links within my notes
  5. =head1 SYNOPSIS
  6. Currently this is vimwiki-dependent.
  7. # List pages linking to foo:
  8. notes links --target foo
  9. # Pages linking to foo.wiki:
  10. notes links --file ./foo.wiki
  11. # Pages with a date (i.e. logs and diaries) linking to foo:
  12. notes links --with-date --target foo
  13. # Links in foo (experimental, probably broken):
  14. notes links --source foo
  15. =head1 AUTHOR
  16. Brennen Bearnes
  17. =cut
  18. use warnings;
  19. use strict;
  20. use 5.10.0;
  21. use Cwd;
  22. use Data::Dumper;
  23. use DBI;
  24. use File::Basename;
  25. use File::Spec;
  26. use Getopt::Long;
  27. use Pod::Usage;
  28. use SQL::Abstract;
  29. use Sys::Hostname;
  30. # Display formats:
  31. my %FORMATS = (
  32. vimwiki => sub {
  33. my ($data) = @_;
  34. my $timestamp = '';
  35. if (defined $data->{timestamp}) {
  36. $timestamp = $data->{timestamp} . " ";
  37. }
  38. return ' - '
  39. . $timestamp
  40. . '[[/' . $data->{page} . '|'
  41. . $data->{title}
  42. . "]]\n";
  43. },
  44. tsv => sub {
  45. my ($data) = @_;
  46. my $timestamp = '(null)';
  47. if (defined $data->{timestamp}) {
  48. $timestamp = $data->{timestamp};
  49. }
  50. return (join "\t", ($timestamp, $data->{page}, $data->{title})) . "\n";
  51. },
  52. # vim location list
  53. #
  54. # TODO: Note that the "1" here is, theoretically, a line number.
  55. # Unfortunately, there's no obvious way to extract that from Pandoc's parsing
  56. # of the original file, and thus no non-hacky way for notes-collect-metadata to
  57. # store an approximate value in the database. We _could_ read the file
  58. # line-by-line, or run grep, looking for the file's basename, but this is
  59. # tricky to get right.
  60. #
  61. # If I keep using this long-term, I should solve this problem.
  62. location => sub {
  63. my ($data) = @_;
  64. my $result = "$ENV{HOME}/notes/vimwiki/$data->{page}.wiki";
  65. if ($data->{title}) {
  66. $result .= ":1:$data->{title}";
  67. } else {
  68. $result .= print ":1:$data->{page}"
  69. }
  70. return $result . "\n";
  71. },
  72. # Fulltext of vimwiki pages:
  73. full => sub {
  74. my ($data) = @_;
  75. my $result = '';
  76. my $pagepath = "$ENV{HOME}/notes/vimwiki/$data->{page}.wiki";
  77. $result .= "%% $pagepath {{{\n\n";
  78. $result .= file_get_contents($pagepath);
  79. $result .= "\n%% }}}\n\n";
  80. return $result;
  81. },
  82. # Bare names of wiki pages (no extension):
  83. name => sub {
  84. my ($data) = @_;
  85. return $data->{page} . "\n";
  86. },
  87. );
  88. # Handle options, including help generated from the POD above.
  89. my $debug = 0;
  90. my $with_date = 0;
  91. my $target;
  92. my $source;
  93. my $file;
  94. my $format = 'location';
  95. GetOptions(
  96. 'debug' => \$debug,
  97. 'target=s' => \$target,
  98. 'file=s' => \$file,
  99. 'format=s' => \$format,
  100. 'with-date' => \$with_date,
  101. 'help' => sub { pod2usage(0) },
  102. ) or pod2usage(2);
  103. if (defined $file)
  104. {
  105. my ($name, $path, $suffix) = fileparse($file, '.wiki');
  106. # XXX: This is a dirty fucking hack - get rid of the leading path stuff, but
  107. # keep subdirs within the vimwiki directory:
  108. $path =~ s{^.*?notes/vimwiki/}{};
  109. $target = $path . $name;
  110. }
  111. my %where = ();
  112. # Require that the link point to a given page:
  113. if (defined $target) {
  114. $where{target} = $target;
  115. }
  116. # Get only links from pages that have a datetime:
  117. if ($with_date) {
  118. # NOT NULL:
  119. $where{'pages.datetime'} = { '!=', undef };
  120. }
  121. my $dbfile = $ENV{HOME} . "/notes/metadata.db";
  122. my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile", "", "");
  123. my $sql = SQL::Abstract->new;
  124. my ($query, @bind) = $sql->select(
  125. 'links JOIN pages ON links.page = pages.page',
  126. # timestamp will be null if datetime is
  127. "*, DATETIME(datetime, 'localtime') AS timestamp",
  128. \%where,
  129. {-desc => [ 'datetime', 'page' ] }
  130. );
  131. if ($debug) {
  132. say STDERR $query;
  133. say STDERR Dumper(%where);
  134. }
  135. my $sth = $dbh->prepare($query);
  136. $sth->execute(@bind);
  137. while (my $data = $sth->fetchrow_hashref())
  138. {
  139. if ($debug) {
  140. print STDERR Dumper($data);
  141. }
  142. print $FORMATS{$format}->($data);
  143. }
  144. $sth->execute();
  145. # PHP-style file-content grabbing:
  146. sub file_get_contents {
  147. my ($file) = @_;
  148. open my $fh, '<', $file
  149. or die "Couldn't open $file: $!\n";
  150. my $contents;
  151. {
  152. # line separator:
  153. local $/ = undef;
  154. $contents = <$fh>;
  155. }
  156. close $fh or die "Couldn't close $file: $!";
  157. return $contents;
  158. }
  159. 1;