-
Notifications
You must be signed in to change notification settings - Fork 4
/
create-link.el
288 lines (246 loc) · 9.53 KB
/
create-link.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
;;; create-link.el --- Smart format link generator
;; Copyright (C) 2021 Kijima Daigo
;; Created date 2021-05-07 00:30 +0900
;; Author: Kijima Daigo <[email protected]>
;; Version: 1.0.0
;; Package-Requires: ((emacs "25.1"))
;; Keywords: link format browser convenience
;; URL: https://github.com/kijimaD/create-link
;; This file is NOT part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;; Create formatted url depending on the context.
;; M-x create-link
;; M-x create-link-manual
;;; Code:
(require 'cl-lib)
(require 'eww)
(require 'thingatpt)
(declare-function forge-current-issue "ext:forge-issue")
(declare-function forge-current-pullreq "ext:forge-pullreq")
(declare-function forge-get-url "ext:forge-repo")
(eval-when-compile (cl-pushnew 'title eieio--known-slot-names))
(defgroup create-link nil
"Generate a formatted current page link."
:group 'convenience
:prefix "create-link-")
(defcustom create-link-default-format 'create-link-format-html
"Default link format."
:group 'create-link
:type '(choice (const :tag "HTML" create-link-format-html)
(const :tag "Markdown" create-link-format-markdown)
(const :tag "Org" create-link-format-org)
(const :tag "DokuWiki" create-link-format-doku-wiki)
(const :tag "MediaWiki" create-link-format-media-wiki)
(const :tag "LaTeX" create-link-format-latex)))
;; Format keywords:
;; %url% - (e.g. https://www.google.com/)
;; %title% - (e.g. Google)
(defcustom create-link-format-html "<a href='%url%'>%title%</a>"
"HTML link format."
:group 'create-link
:type 'string)
(defcustom create-link-format-markdown "[%title%](%url%)"
"Markdown link format."
:group 'create-link
:type 'string)
(defcustom create-link-format-org "[[%url%][%title%]]"
"Org-mode link format."
:group 'create-link
:type 'string)
(defcustom create-link-format-doku-wiki "[[%url%|%title%]]"
"DokuWiki link format."
:group 'create-link
:type 'string)
(defcustom create-link-format-media-wiki "[%url% %title%]"
"MediaWiki link format."
:group 'create-link
:type 'string)
(defcustom create-link-format-latex "\\href{%url%}{%title%}"
"Latex link format."
:group 'create-link
:type 'string)
(defconst create-link-formats
'((create-link-format-html)
(create-link-format-markdown)
(create-link-format-org)
(create-link-format-doku-wiki)
(create-link-format-media-wiki)
(create-link-format-latex))
"All format list. Use for completion.")
(defconst create-link-html-title-regexp
"<title>\\(.*\\)</title>"
"Regular expression to scrape a page title.")
(defconst create-link-html-regexp
"<a.*?href=[\\'\\\"]\\(?1:.+\\)[\\'\\\"].*?>\\(?2:.+\\)</a>"
"Regular expression for HTML link.
Group 1 matches the link.
Group 2 matches the title.")
(defconst create-link-markdown-regexp
"\\[\\(?1:.*\\)\\](\\(?2:.*\\))"
"Regular expression for Markdown link.
Group 1 matches the title.
Group 2 matches the link.")
(defconst create-link-org-regexp
"\\[\\[\\(?1:.*?\\)\\]\\[\\(?2:.*?\\)\\]"
"Regular expression for Org link.
Group 1 matches the link.
Group 2 matches the title.")
(defconst create-link-doku-wiki-regexp
"\\[\\[\\(?1:.*?\\)\s?|\s?\\(?2:.*?\\)\\]\\]"
"Regular expression for DokuWiki external link.
Group 1 matches the link.
Group 2 matches the title.")
(defconst create-link-media-wiki-regexp
"\\[\\(?1:.*?\\)\s\s?\\(?2:.*?\\)\\]"
"Regular expression for MediaWiki external link.
Group 1 matches the link.
Group 2 matches the title.
It is problematic.")
(defconst create-link-latex-regexp
"\\\\href{\\(run:\\)?\\(?1:.*?\\)}{\\(?2:.*?\\)}"
"Regular expression for LaTeX link.
Group 1 matches the link.
Group 2 matches the title.")
(defun create-link-absolute-linkp (url)
"Return t if URL is absolute url."
(string-match-p "^http[s]?://" url))
(defun create-link-relative-linkp (url)
"Return t if URL is relative url."
(not (create-link-absolute-linkp url)))
(defun create-link-format-html-rule (dict)
"HTML specific rule (Unimplemented).
DICT is alist with url and title."
dict)
(defun create-link-format-markdown-rule (dict)
"Markdown specific rule (Unimplemented).
DICT is alist with url and title."
dict)
(defun create-link-format-org-rule (dict)
"Org specific rule (Unimplemented).
DICT is alist with url and title."
dict)
(defun create-link-format-doku-wiki-rule (dict)
"DokuWiki specific rule (Unimplemented).
DICT is alist with url and title."
dict)
(defun create-link-format-media-wiki-rule (dict)
"MediaWiki specific rule (Unimplemented).
DICT is alist with url and title."
dict)
(defun create-link-format-latex-rule (dict)
"LaTeX specific rule.
DICT is alist with url and title."
(cond ((create-link-relative-linkp (cdr (assoc 'url dict)))
`((url . ,(concat "run:" (cdr (assoc 'url dict))))
(title . ,(cdr (assoc 'title dict)))))
(t
dict)))
(defun create-link-replace-dictionary ()
"Convert format keyword to corresponding one.
If there is a selected region, fill title with the region.
If point is on URL, fill title with scraped one."
(cond ((region-active-p)
(deactivate-mark t)
`((url . ,(cdr (assoc 'url (create-link-get-from-buffer))))
(title . ,(buffer-substring (region-beginning) (region-end)))))
((thing-at-point-looking-at create-link-html-regexp)
`((url . ,(match-string 1))
(title . ,(match-string 2))))
((thing-at-point-looking-at create-link-markdown-regexp)
`((url . ,(match-string 2))
(title . ,(match-string 1))))
((thing-at-point-looking-at create-link-org-regexp)
`((url . ,(match-string 1))
(title . ,(match-string 2))))
((thing-at-point-looking-at create-link-doku-wiki-regexp)
`((url . ,(match-string 1))
(title . ,(match-string 2))))
((thing-at-point-looking-at create-link-media-wiki-regexp)
`((url . ,(match-string 1))
(title . ,(match-string 2))))
((thing-at-point-looking-at create-link-latex-regexp)
`((url . ,(match-string 1))
(title . ,(match-string 2))))
((thing-at-point-url-at-point)
`((url . ,(thing-at-point-url-at-point))
(title . ,(create-link-scrape-title (thing-at-point-url-at-point)))))
(t
(create-link-get-from-buffer))))
(defun create-link-get-from-buffer ()
"Get keyword information on each buffer."
(cond ((eq major-mode 'eww-mode)
`((title . ,(plist-get eww-data :title))
(url . ,(eww-current-url))))
((and (eq major-mode 'magit-status-mode) (forge-current-issue))
`((url . ,(forge-get-url (forge-current-issue)))
(title . ,(concat (oref (forge-current-issue) title)))))
((and (eq major-mode 'magit-status-mode) (forge-current-pullreq))
`((url . ,(forge-get-url (forge-current-pullreq)))
(title . ,(concat (oref (forge-current-pullreq) title)))))
((buffer-file-name)
`((title . ,(buffer-name))
(url . ,(buffer-file-name))))
(t
(error "Can't create link!"))))
(defun create-link-scrape-title (url)
"Scraping page title from URL."
(let* ((buffer (url-retrieve-synchronously url))
(contents (with-current-buffer buffer
(buffer-substring (point-min) (point-max))))
(title))
(string-match create-link-html-title-regexp contents)
(setq title (match-string 1 contents))
(kill-buffer buffer)
title))
(defun create-link-format-rule (format)
"Get the symbol for an format rule function for a FORMAT."
(intern (concat (symbol-name format) "-rule")))
(defun create-link-exec-replace (dict format)
"Fill FORMAT string with DICT elements."
(seq-reduce
(lambda (string regexp-replacement-pair)
(replace-regexp-in-string
(concat "%" (symbol-name (car regexp-replacement-pair)) "%")
(cdr regexp-replacement-pair)
string))
dict
(symbol-value format)))
(defun create-link-make-format (&optional format)
"Make format link with FORMAT(optional).
If FORMAT is not specified, use `create-link-default-format'"
(let ((format (if format format create-link-default-format)))
(create-link-exec-replace (funcall (create-link-format-rule format)
(create-link-replace-dictionary))
format)))
;;;###autoload
(defun create-link-manual ()
"Manually select a format and generate a link.
Selecting format version of function `create-link'."
(interactive)
(create-link
(intern
(completing-read "Format: " create-link-formats nil t nil))))
;;;###autoload
(defun create-link (&optional format)
"Create format link.
If an optional FORMAT is specified,
it will be generated in that format."
(interactive)
(message "Copied! %s" (create-link-make-format format))
(kill-new (create-link-make-format format)))
(provide 'create-link)
;;; create-link.el ends here