]> sipb.mit.edu Git - ikiwiki.git/blob - IkiWiki/Plugin/link.pm
Enhance the link plugin to handle external links.
[ikiwiki.git] / IkiWiki / Plugin / link.pm
1 #!/usr/bin/perl
2 package IkiWiki::Plugin::link;
3
4 use warnings;
5 use strict;
6 use IkiWiki 3.00;
7
8 my $link_regexp;
9
10 my $email_regexp = qr/^(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i; 
11 my $url_regexp = qr/^(?:[^:]+:\/\/|mailto:).*/i;
12
13 sub import {
14         hook(type => "getsetup", id => "link", call => \&getsetup);
15         hook(type => "checkconfig", id => "link", call => \&checkconfig);
16         hook(type => "linkify", id => "link", call => \&linkify);
17         hook(type => "scan", id => "link", call => \&scan);
18         hook(type => "renamepage", id => "link", call => \&renamepage);
19 }
20
21 sub getsetup () {
22         return
23                 plugin => {
24                         safe => 1,
25                         rebuild => 1,
26                         section => "core",
27                 },
28 }
29
30 sub checkconfig () {
31         if ($config{prefix_directives}) {
32                 $link_regexp = qr{
33                         \[\[(?=[^!])            # beginning of link
34                         (?:
35                                 ([^\]\|]+)      # 1: link text
36                                 \|              # followed by '|'
37                         )?                      # optional
38                         
39                         ([^\n\r\]#]+)           # 2: page to link to
40                         (?:
41                                 \#              # '#', beginning of anchor
42                                 ([^\s\]]+)      # 3: anchor text
43                         )?                      # optional
44                         
45                         \]\]                    # end of link
46                 }x;
47         }
48         else {
49                 $link_regexp = qr{
50                         \[\[                    # beginning of link
51                         (?:
52                                 ([^\]\|\n\s]+)  # 1: link text
53                                 \|              # followed by '|'
54                         )?                      # optional
55
56                         ([^\s\]#]+)             # 2: page to link to
57                         (?:
58                                 \#              # '#', beginning of anchor
59                                 ([^\s\]]+)      # 3: anchor text
60                         )?                      # optional
61
62                         \]\]                    # end of link
63                 }x;
64         }
65 }
66
67 sub is_externallink ($$) {
68         my $page = shift;
69         my $url = shift;
70         if ($url =~ /$email_regexp/) {
71                 # url looks like an email address, so we assume it
72                 # is supposed to be an external link if there is no
73                 # page with that name.
74                 $url =~ s/#.*//;
75                 return (! (bestlink($page, linkpage($url))))
76         }
77         return ($url =~ /$url_regexp/)
78 }
79
80 sub externallink ($;@) {
81         my $url = shift;
82         my $pagetitle = shift;
83
84         # build pagetitle
85         if (!($pagetitle)) {
86                 $pagetitle = $url;
87                 # use only the email address as title for mailto: urls
88                 if ($pagetitle =~ /^mailto:.*/) {
89                         $pagetitle =~ s/^mailto:([^?]+).*/$1/;
90                 }
91         }
92
93         # handle email-addresses (without mailto:):
94         if ($url =~ /$email_regexp/) {
95                 $url = "mailto:" . $url;
96         }
97
98         return "<a href=\"$url\">$pagetitle</a>";
99 }
100
101 sub linkify (@) {
102         my %params=@_;
103         my $page=$params{page};
104         my $destpage=$params{destpage};
105
106         $params{content} =~ s{(\\?)$link_regexp}{
107                 defined $2
108                         ? ( $1 
109                                 ? "[[$2|$3".($4 ? "#$4" : "")."]]" 
110                                 : is_externallink($page, $3 . ($4 ? "#$4" : ""))
111                                         ? externallink("$3" . ($4 ? "#$4" : ""), $2)
112                                         : htmllink($page, $destpage, linkpage($3),
113                                                 anchor => $4, linktext => pagetitle($2)))
114                         : ( $1 
115                                 ? "[[$3".($4 ? "#$4" : "")."]]"
116                                 : is_externallink($page, $3 . ($4 ? "#$4" : ""))
117                                         ? externallink("$3" . ($4 ? "#$4" : ""))
118                                         : htmllink($page, $destpage, linkpage($3),
119                                                 anchor => $4))
120         }eg;
121         
122         return $params{content};
123 }
124
125 sub scan (@) {
126         my %params=@_;
127         my $page=$params{page};
128         my $content=$params{content};
129
130         while ($content =~ /(?<!\\)$link_regexp/g) {
131                 if (! is_externallink($page, $2 . ($3 ? "#$3" : ""))) {
132                         add_link($page, linkpage($2));
133                 }
134         }
135 }
136
137 sub renamepage (@) {
138         my %params=@_;
139         my $page=$params{page};
140         my $old=$params{oldpage};
141         my $new=$params{newpage};
142
143         $params{content} =~ s{(?<!\\)$link_regexp}{
144                 if (! is_externallink($page, $2 . ($3 ? "#$3" : ""))) {
145                         my $linktext=$2;
146                         my $link=$linktext;
147                         if (bestlink($page, linkpage($linktext)) eq $old) {
148                                 $link=pagetitle($new, 1);
149                                 $link=~s/ /_/g;
150                                 if ($linktext =~ m/.*\/*?[A-Z]/) {
151                                         # preserve leading cap of last component
152                                         my @bits=split("/", $link);
153                                         $link=join("/", @bits[0..$#bits-1], ucfirst($bits[$#bits]));
154                                 }
155                                 if (index($linktext, "/") == 0) {
156                                         # absolute link
157                                         $link="/$link";
158                                 }
159                         }
160                         defined $1
161                                 ? ( "[[$1|$link".($3 ? "#$3" : "")."]]" )
162                                 : ( "[[$link".   ($3 ? "#$3" : "")."]]" )
163                 }
164         }eg;
165
166         return $params{content};
167 }
168
169 1