606 lines
30 KiB
EmacsLisp
606 lines
30 KiB
EmacsLisp
;;; org-cliplink.el --- insert org-mode links from the clipboard -*- lexical-binding: t -*-
|
|
|
|
;; Copyright (C) 2014 Alexey Kutepov a.k.a rexim
|
|
|
|
;; Author: Alexey Kutepov <reximkut@gmail.com>
|
|
;; Maintainer: Alexey Kutepov <reximkut@gmail.com>
|
|
;; URL: http://github.com/rexim/org-cliplink
|
|
;; Package-Version: 20201126.1020
|
|
;; Package-Revision: 13e0940b65d2
|
|
;; Package-Requires: ((emacs "24.4"))
|
|
|
|
;; Permission is hereby granted, free of charge, to any person
|
|
;; obtaining a copy of this software and associated documentation
|
|
;; files (the "Software"), to deal in the Software without
|
|
;; restriction, including without limitation the rights to use, copy,
|
|
;; modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
;; of the Software, and to permit persons to whom the Software is
|
|
;; furnished to do so, subject to the following conditions:
|
|
|
|
;; The above copyright notice and this permission notice shall be
|
|
;; included in all copies or substantial portions of the Software.
|
|
|
|
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
;; SOFTWARE.
|
|
|
|
;;; Usage:
|
|
;;
|
|
;; Bind `org-cliplink` function to something. For example, put
|
|
;; this line in your init file:
|
|
;; (global-set-key (kbd "C-x p i") 'org-cliplink)
|
|
;;
|
|
;; Then copy any http/https URL to the clipboard, switch to
|
|
;; the Emacs window and hit `C-x p i`.
|
|
|
|
;;; Commentary:
|
|
;;
|
|
;; A simple command that takes a URL from the clipboard and inserts an
|
|
;; org-mode link with a title of a page found by the URL into the
|
|
;; current buffer
|
|
;;
|
|
;; This code was a part of my Emacs config almost a year. I decided to
|
|
;; publish it as a separate package in case someone needs this feature
|
|
;; too.
|
|
|
|
;;; Code:
|
|
|
|
(require 'em-glob)
|
|
(require 'subr-x) ; for string-trim
|
|
|
|
(require 'org-cliplink-string)
|
|
(require 'org-cliplink-transport)
|
|
|
|
(defconst org-cliplink-basic-escape-alist
|
|
'((""" . "\"") ;; " - double-quote
|
|
("&" . "&") ;; & - ampersand
|
|
("<" . "<") ;; < - less-than
|
|
(">" . ">"))) ;; > - greater-than
|
|
|
|
(defconst org-cliplink-iso8869-1-escape-alist
|
|
'((" " . "\u00A0") ;; non-breaking space
|
|
("¡" . "\u00A1") ;; inverted exclamation mark
|
|
("¢" . "\u00A2") ;; cent sign
|
|
("£" . "\u00A3") ;; pound sign
|
|
("¤" . "\u00A4") ;; currency sign
|
|
("¥" . "\u00A5") ;; yen sign = yuan sign
|
|
("¦" . "\u00A6") ;; broken bar = broken vertical bar
|
|
("§" . "\u00A7") ;; section sign
|
|
("¨" . "\u00A8") ;; diaeresis = spacing diaeresis
|
|
("©" . "\u00A9") ;; © - copyright sign
|
|
("ª" . "\u00AA") ;; feminine ordinal indicator
|
|
("«" . "\u00AB") ;; left-pointing double angle quotation mark = left pointing guillemet
|
|
("¬" . "\u00AC") ;; not sign
|
|
("­" . "\u00AD") ;; soft hyphen = discretionary hyphen
|
|
("®" . "\u00AE") ;; ® - registered trademark sign
|
|
("¯" . "\u00AF") ;; macron = spacing macron = overline = APL overbar
|
|
("°" . "\u00B0") ;; degree sign
|
|
("±" . "\u00B1") ;; plus-minus sign = plus-or-minus sign
|
|
("²" . "\u00B2") ;; superscript two = superscript digit two = squared
|
|
("³" . "\u00B3") ;; superscript three = superscript digit three = cubed
|
|
("´" . "\u00B4") ;; acute accent = spacing acute
|
|
("µ" . "\u00B5") ;; micro sign
|
|
("¶" . "\u00B6") ;; pilcrow sign = paragraph sign
|
|
("·" . "\u00B7") ;; middle dot = Georgian comma = Greek middle dot
|
|
("¸" . "\u00B8") ;; cedilla = spacing cedilla
|
|
("¹" . "\u00B9") ;; superscript one = superscript digit one
|
|
("º" . "\u00BA") ;; masculine ordinal indicator
|
|
("»" . "\u00BB") ;; right-pointing double angle quotation mark = right pointing guillemet
|
|
("¼" . "\u00BC") ;; vulgar fraction one quarter = fraction one quarter
|
|
("½" . "\u00BD") ;; vulgar fraction one half = fraction one half
|
|
("¾" . "\u00BE") ;; vulgar fraction three quarters = fraction three quarters
|
|
("¿" . "\u00BF") ;; inverted question mark = turned question mark
|
|
("À" . "\u00C0") ;; À - uppercase A, grave accent
|
|
("Á" . "\u00C1") ;; Á - uppercase A, acute accent
|
|
("Â" . "\u00C2") ;; Â - uppercase A, circumflex accent
|
|
("Ã" . "\u00C3") ;; Ã - uppercase A, tilde
|
|
("Ä" . "\u00C4") ;; Ä - uppercase A, umlaut
|
|
("Å" . "\u00C5") ;; Å - uppercase A, ring
|
|
("Æ" . "\u00C6") ;; Æ - uppercase AE
|
|
("Ç" . "\u00C7") ;; Ç - uppercase C, cedilla
|
|
("È" . "\u00C8") ;; È - uppercase E, grave accent
|
|
("É" . "\u00C9") ;; É - uppercase E, acute accent
|
|
("Ê" . "\u00CA") ;; Ê - uppercase E, circumflex accent
|
|
("Ë" . "\u00CB") ;; Ë - uppercase E, umlaut
|
|
("Ì" . "\u00CC") ;; Ì - uppercase I, grave accent
|
|
("Í" . "\u00CD") ;; Í - uppercase I, acute accent
|
|
("Î" . "\u00CE") ;; Î - uppercase I, circumflex accent
|
|
("Ï" . "\u00CF") ;; Ï - uppercase I, umlaut
|
|
("Ð" . "\u00D0") ;; Ð - uppercase Eth, Icelandic
|
|
("Ñ" . "\u00D1") ;; Ñ - uppercase N, tilde
|
|
("Ò" . "\u00D2") ;; Ò - uppercase O, grave accent
|
|
("Ó" . "\u00D3") ;; Ó - uppercase O, acute accent
|
|
("Ô" . "\u00D4") ;; Ô - uppercase O, circumflex accent
|
|
("Õ" . "\u00D5") ;; Õ - uppercase O, tilde
|
|
("Ö" . "\u00D6") ;; Ö - uppercase O, umlaut
|
|
("×" . "\u00D7") ;; multiplication sign
|
|
("Ø" . "\u00D8") ;; Ø - uppercase O, slash
|
|
("Ù" . "\u00D9") ;; Ù - uppercase U, grave accent
|
|
("Ú" . "\u00DA") ;; Ú - uppercase U, acute accent
|
|
("Û" . "\u00DB") ;; Û - uppercase U, circumflex accent
|
|
("Ü" . "\u00DC") ;; Ü - uppercase U, umlaut
|
|
("Ý" . "\u00DD") ;; Ý - uppercase Y, acute accent
|
|
("Þ" . "\u00DE") ;; Þ - uppercase THORN, Icelandic
|
|
("ß" . "\u00DF") ;; ß - lowercase sharps, German
|
|
("à" . "\u00E0") ;; à - lowercase a, grave accent
|
|
("á" . "\u00E1") ;; á - lowercase a, acute accent
|
|
("â" . "\u00E2") ;; â - lowercase a, circumflex accent
|
|
("ã" . "\u00E3") ;; ã - lowercase a, tilde
|
|
("ä" . "\u00E4") ;; ä - lowercase a, umlaut
|
|
("å" . "\u00E5") ;; å - lowercase a, ring
|
|
("æ" . "\u00E6") ;; æ - lowercase ae
|
|
("ç" . "\u00E7") ;; ç - lowercase c, cedilla
|
|
("è" . "\u00E8") ;; è - lowercase e, grave accent
|
|
("é" . "\u00E9") ;; é - lowercase e, acute accent
|
|
("ê" . "\u00EA") ;; ê - lowercase e, circumflex accent
|
|
("ë" . "\u00EB") ;; ë - lowercase e, umlaut
|
|
("ì" . "\u00EC") ;; ì - lowercase i, grave accent
|
|
("í" . "\u00ED") ;; í - lowercase i, acute accent
|
|
("î" . "\u00EE") ;; î - lowercase i, circumflex accent
|
|
("ï" . "\u00EF") ;; ï - lowercase i, umlaut
|
|
("ð" . "\u00F0") ;; ð - lowercase eth, Icelandic
|
|
("ñ" . "\u00F1") ;; ñ - lowercase n, tilde
|
|
("ò" . "\u00F2") ;; ò - lowercase o, grave accent
|
|
("ó" . "\u00F3") ;; ó - lowercase o, acute accent
|
|
("ô" . "\u00F4") ;; ô - lowercase o, circumflex accent
|
|
("õ" . "\u00F5") ;; õ - lowercase o, tilde
|
|
("ö" . "\u00F6") ;; ö - lowercase o, umlaut
|
|
("÷" . "\u00F7") ;; division sign
|
|
("ø" . "\u00F8") ;; ø - lowercase o, slash
|
|
("ù" . "\u00F9") ;; ù - lowercase u, grave accent
|
|
("ú" . "\u00FA") ;; ú - lowercase u, acute accent
|
|
("û" . "\u00FB") ;; û - lowercase u, circumflex accent
|
|
("ü" . "\u00FC") ;; ü - lowercase u, umlaut
|
|
("ý" . "\u00FD") ;; ý - lowercase y, acute accent
|
|
("þ" . "\u00FE") ;; þ - lowercase thorn, Icelandic
|
|
("ÿ" . "\u00FF"))) ;; ÿ - lowercase y, umlaut
|
|
|
|
(defconst org-cliplink-html40-extended-escape-alist
|
|
'( ;; <!-- Latin Extended-B -->
|
|
("ƒ" . "\u0192") ;; latin small f with hook = function= florin, U+0192 ISOtech -->
|
|
;; <!-- Greek -->
|
|
("Α" . "\u0391") ;; greek capital letter alpha, U+0391 -->
|
|
("Β" . "\u0392") ;; greek capital letter beta, U+0392 -->
|
|
("Γ" . "\u0393") ;; greek capital letter gamma,U+0393 ISOgrk3 -->
|
|
("Δ" . "\u0394") ;; greek capital letter delta,U+0394 ISOgrk3 -->
|
|
("Ε" . "\u0395") ;; greek capital letter epsilon, U+0395 -->
|
|
("Ζ" . "\u0396") ;; greek capital letter zeta, U+0396 -->
|
|
("Η" . "\u0397") ;; greek capital letter eta, U+0397 -->
|
|
("Θ" . "\u0398") ;; greek capital letter theta,U+0398 ISOgrk3 -->
|
|
("Ι" . "\u0399") ;; greek capital letter iota, U+0399 -->
|
|
("Κ" . "\u039A") ;; greek capital letter kappa, U+039A -->
|
|
("Λ" . "\u039B") ;; greek capital letter lambda,U+039B ISOgrk3 -->
|
|
("Μ" . "\u039C") ;; greek capital letter mu, U+039C -->
|
|
("Ν" . "\u039D") ;; greek capital letter nu, U+039D -->
|
|
("Ξ" . "\u039E") ;; greek capital letter xi, U+039E ISOgrk3 -->
|
|
("Ο" . "\u039F") ;; greek capital letter omicron, U+039F -->
|
|
("Π" . "\u03A0") ;; greek capital letter pi, U+03A0 ISOgrk3 -->
|
|
("Ρ" . "\u03A1") ;; greek capital letter rho, U+03A1 -->
|
|
;; <!-- there is no Sigmaf, and no U+03A2 character either -->
|
|
("Σ" . "\u03A3") ;; greek capital letter sigma,U+03A3 ISOgrk3 -->
|
|
("Τ" . "\u03A4") ;; greek capital letter tau, U+03A4 -->
|
|
("Υ" . "\u03A5") ;; greek capital letter upsilon,U+03A5 ISOgrk3 -->
|
|
("Φ" . "\u03A6") ;; greek capital letter phi,U+03A6 ISOgrk3 -->
|
|
("Χ" . "\u03A7") ;; greek capital letter chi, U+03A7 -->
|
|
("Ψ" . "\u03A8") ;; greek capital letter psi,U+03A8 ISOgrk3 -->
|
|
("Ω" . "\u03A9") ;; greek capital letter omega,U+03A9 ISOgrk3 -->
|
|
("α" . "\u03B1") ;; greek small letter alpha,U+03B1 ISOgrk3 -->
|
|
("β" . "\u03B2") ;; greek small letter beta, U+03B2 ISOgrk3 -->
|
|
("γ" . "\u03B3") ;; greek small letter gamma,U+03B3 ISOgrk3 -->
|
|
("δ" . "\u03B4") ;; greek small letter delta,U+03B4 ISOgrk3 -->
|
|
("ε" . "\u03B5") ;; greek small letter epsilon,U+03B5 ISOgrk3 -->
|
|
("ζ" . "\u03B6") ;; greek small letter zeta, U+03B6 ISOgrk3 -->
|
|
("η" . "\u03B7") ;; greek small letter eta, U+03B7 ISOgrk3 -->
|
|
("θ" . "\u03B8") ;; greek small letter theta,U+03B8 ISOgrk3 -->
|
|
("ι" . "\u03B9") ;; greek small letter iota, U+03B9 ISOgrk3 -->
|
|
("κ" . "\u03BA") ;; greek small letter kappa,U+03BA ISOgrk3 -->
|
|
("λ" . "\u03BB") ;; greek small letter lambda,U+03BB ISOgrk3 -->
|
|
("μ" . "\u03BC") ;; greek small letter mu, U+03BC ISOgrk3 -->
|
|
("ν" . "\u03BD") ;; greek small letter nu, U+03BD ISOgrk3 -->
|
|
("ξ" . "\u03BE") ;; greek small letter xi, U+03BE ISOgrk3 -->
|
|
("ο" . "\u03BF") ;; greek small letter omicron, U+03BF NEW -->
|
|
("π" . "\u03C0") ;; greek small letter pi, U+03C0 ISOgrk3 -->
|
|
("ρ" . "\u03C1") ;; greek small letter rho, U+03C1 ISOgrk3 -->
|
|
("ς" . "\u03C2") ;; greek small letter final sigma,U+03C2 ISOgrk3 -->
|
|
("σ" . "\u03C3") ;; greek small letter sigma,U+03C3 ISOgrk3 -->
|
|
("τ" . "\u03C4") ;; greek small letter tau, U+03C4 ISOgrk3 -->
|
|
("υ" . "\u03C5") ;; greek small letter upsilon,U+03C5 ISOgrk3 -->
|
|
("φ" . "\u03C6") ;; greek small letter phi, U+03C6 ISOgrk3 -->
|
|
("χ" . "\u03C7") ;; greek small letter chi, U+03C7 ISOgrk3 -->
|
|
("ψ" . "\u03C8") ;; greek small letter psi, U+03C8 ISOgrk3 -->
|
|
("ω" . "\u03C9") ;; greek small letter omega,U+03C9 ISOgrk3 -->
|
|
("ϑ" . "\u03D1") ;; greek small letter theta symbol,U+03D1 NEW -->
|
|
("ϒ" . "\u03D2") ;; greek upsilon with hook symbol,U+03D2 NEW -->
|
|
("ϖ" . "\u03D6") ;; greek pi symbol, U+03D6 ISOgrk3 -->
|
|
;; <!-- General Punctuation -->
|
|
("•" . "\u2022") ;; bullet = black small circle,U+2022 ISOpub -->
|
|
;; <!-- bullet is NOT the same as bullet operator, U+2219 -->
|
|
("…" . "\u2026") ;; horizontal ellipsis = three dot leader,U+2026 ISOpub -->
|
|
("′" . "\u2032") ;; prime = minutes = feet, U+2032 ISOtech -->
|
|
("″" . "\u2033") ;; double prime = seconds = inches,U+2033 ISOtech -->
|
|
("‾" . "\u203E") ;; overline = spacing overscore,U+203E NEW -->
|
|
("⁄" . "\u2044") ;; fraction slash, U+2044 NEW -->
|
|
;; <!-- Letterlike Symbols -->
|
|
("℘" . "\u2118") ;; script capital P = power set= Weierstrass p, U+2118 ISOamso -->
|
|
("ℑ" . "\u2111") ;; blackletter capital I = imaginary part,U+2111 ISOamso -->
|
|
("ℜ" . "\u211C") ;; blackletter capital R = real part symbol,U+211C ISOamso -->
|
|
("™" . "\u2122") ;; trade mark sign, U+2122 ISOnum -->
|
|
("ℵ" . "\u2135") ;; alef symbol = first transfinite cardinal,U+2135 NEW -->
|
|
;; <!-- alef symbol is NOT the same as hebrew letter alef,U+05D0 although the
|
|
;; same glyph could be used to depict both characters -->
|
|
;; <!-- Arrows -->
|
|
("←" . "\u2190") ;; leftwards arrow, U+2190 ISOnum -->
|
|
("↑" . "\u2191") ;; upwards arrow, U+2191 ISOnum-->
|
|
("→" . "\u2192") ;; rightwards arrow, U+2192 ISOnum -->
|
|
("↓" . "\u2193") ;; downwards arrow, U+2193 ISOnum -->
|
|
("↔" . "\u2194") ;; left right arrow, U+2194 ISOamsa -->
|
|
("↵" . "\u21B5") ;; downwards arrow with corner leftwards= carriage return, U+21B5 NEW -->
|
|
("⇐" . "\u21D0") ;; leftwards double arrow, U+21D0 ISOtech -->
|
|
;; <!-- ISO 10646 does not say that lArr is the same as the 'is implied by'
|
|
;; arrow but also does not have any other character for that function.
|
|
;; So ? lArr canbe used for 'is implied by' as ISOtech suggests -->
|
|
("⇑" . "\u21D1") ;; upwards double arrow, U+21D1 ISOamsa -->
|
|
("⇒" . "\u21D2") ;; rightwards double arrow,U+21D2 ISOtech -->
|
|
;; <!-- ISO 10646 does not say this is the 'implies' character but does not
|
|
;; have another character with this function so ?rArr can be used for
|
|
;; 'implies' as ISOtech suggests -->
|
|
("⇓" . "\u21D3") ;; downwards double arrow, U+21D3 ISOamsa -->
|
|
("⇔" . "\u21D4") ;; left right double arrow,U+21D4 ISOamsa -->
|
|
;; <!-- Mathematical Operators -->
|
|
("∀" . "\u2200") ;; for all, U+2200 ISOtech -->
|
|
("∂" . "\u2202") ;; partial differential, U+2202 ISOtech -->
|
|
("∃" . "\u2203") ;; there exists, U+2203 ISOtech -->
|
|
("∅" . "\u2205") ;; empty set = null set = diameter,U+2205 ISOamso -->
|
|
("∇" . "\u2207") ;; nabla = backward difference,U+2207 ISOtech -->
|
|
("∈" . "\u2208") ;; element of, U+2208 ISOtech -->
|
|
("∉" . "\u2209") ;; not an element of, U+2209 ISOtech -->
|
|
("∋" . "\u220B") ;; contains as member, U+220B ISOtech -->
|
|
;; <!-- should there be a more memorable name than 'ni'? -->
|
|
("∏" . "\u220F") ;; n-ary product = product sign,U+220F ISOamsb -->
|
|
;; <!-- prod is NOT the same character as U+03A0 'greek capital letter pi'
|
|
;; though the same glyph might be used for both -->
|
|
("∑" . "\u2211") ;; n-ary summation, U+2211 ISOamsb -->
|
|
;; <!-- sum is NOT the same character as U+03A3 'greek capital letter sigma'
|
|
;; though the same glyph might be used for both -->
|
|
("−" . "\u2212") ;; minus sign, U+2212 ISOtech -->
|
|
("∗" . "\u2217") ;; asterisk operator, U+2217 ISOtech -->
|
|
("√" . "\u221A") ;; square root = radical sign,U+221A ISOtech -->
|
|
("∝" . "\u221D") ;; proportional to, U+221D ISOtech -->
|
|
("∞" . "\u221E") ;; infinity, U+221E ISOtech -->
|
|
("∠" . "\u2220") ;; angle, U+2220 ISOamso -->
|
|
("∧" . "\u2227") ;; logical and = wedge, U+2227 ISOtech -->
|
|
("∨" . "\u2228") ;; logical or = vee, U+2228 ISOtech -->
|
|
("∩" . "\u2229") ;; intersection = cap, U+2229 ISOtech -->
|
|
("∪" . "\u222A") ;; union = cup, U+222A ISOtech -->
|
|
("∫" . "\u222B") ;; integral, U+222B ISOtech -->
|
|
("∴" . "\u2234") ;; therefore, U+2234 ISOtech -->
|
|
("∼" . "\u223C") ;; tilde operator = varies with = similar to,U+223C ISOtech -->
|
|
;; <!-- tilde operator is NOT the same character as the tilde, U+007E,although
|
|
;; the same glyph might be used to represent both -->
|
|
("≅" . "\u2245") ;; approximately equal to, U+2245 ISOtech -->
|
|
("≈" . "\u2248") ;; almost equal to = asymptotic to,U+2248 ISOamsr -->
|
|
("≠" . "\u2260") ;; not equal to, U+2260 ISOtech -->
|
|
("≡" . "\u2261") ;; identical to, U+2261 ISOtech -->
|
|
("≤" . "\u2264") ;; less-than or equal to, U+2264 ISOtech -->
|
|
("≥" . "\u2265") ;; greater-than or equal to,U+2265 ISOtech -->
|
|
("⊂" . "\u2282") ;; subset of, U+2282 ISOtech -->
|
|
("⊃" . "\u2283") ;; superset of, U+2283 ISOtech -->
|
|
;; <!-- note that nsup, 'not a superset of, U+2283' is not covered by the
|
|
;; Symbol font encoding and is not included. Should it be, for symmetry?
|
|
;; It is in ISOamsn --> <!ENTITY nsub", "8836"},
|
|
;; not a subset of, U+2284 ISOamsn -->
|
|
("⊆" . "\u2286") ;; subset of or equal to, U+2286 ISOtech -->
|
|
("⊇" . "\u2287") ;; superset of or equal to,U+2287 ISOtech -->
|
|
("⊕" . "\u2295") ;; circled plus = direct sum,U+2295 ISOamsb -->
|
|
("⊗" . "\u2297") ;; circled times = vector product,U+2297 ISOamsb -->
|
|
("⊥" . "\u22A5") ;; up tack = orthogonal to = perpendicular,U+22A5 ISOtech -->
|
|
("⋅" . "\u22C5") ;; dot operator, U+22C5 ISOamsb -->
|
|
;; <!-- dot operator is NOT the same character as U+00B7 middle dot -->
|
|
;; <!-- Miscellaneous Technical -->
|
|
("⌈" . "\u2308") ;; left ceiling = apl upstile,U+2308 ISOamsc -->
|
|
("⌉" . "\u2309") ;; right ceiling, U+2309 ISOamsc -->
|
|
("⌊" . "\u230A") ;; left floor = apl downstile,U+230A ISOamsc -->
|
|
("⌋" . "\u230B") ;; right floor, U+230B ISOamsc -->
|
|
("⟨" . "\u2329") ;; left-pointing angle bracket = bra,U+2329 ISOtech -->
|
|
;; <!-- lang is NOT the same character as U+003C 'less than' or U+2039 'single left-pointing angle quotation
|
|
;; mark' -->
|
|
("⟩" . "\u232A") ;; right-pointing angle bracket = ket,U+232A ISOtech -->
|
|
;; <!-- rang is NOT the same character as U+003E 'greater than' or U+203A
|
|
;; 'single right-pointing angle quotation mark' -->
|
|
;; <!-- Geometric Shapes -->
|
|
("◊" . "\u25CA") ;; lozenge, U+25CA ISOpub -->
|
|
;; <!-- Miscellaneous Symbols -->
|
|
("♠" . "\u2660") ;; black spade suit, U+2660 ISOpub -->
|
|
;; <!-- black here seems to mean filled as opposed to hollow -->
|
|
("♣" . "\u2663") ;; black club suit = shamrock,U+2663 ISOpub -->
|
|
("♥" . "\u2665") ;; black heart suit = valentine,U+2665 ISOpub -->
|
|
("♦" . "\u2666") ;; black diamond suit, U+2666 ISOpub -->
|
|
|
|
;; <!-- Latin Extended-A -->
|
|
("Œ" . "\u0152") ;; -- latin capital ligature OE,U+0152 ISOlat2 -->
|
|
("œ" . "\u0153") ;; -- latin small ligature oe, U+0153 ISOlat2 -->
|
|
;; <!-- ligature is a misnomer, this is a separate character in some languages -->
|
|
("Š" . "\u0160") ;; -- latin capital letter S with caron,U+0160 ISOlat2 -->
|
|
("š" . "\u0161") ;; -- latin small letter s with caron,U+0161 ISOlat2 -->
|
|
("Ÿ" . "\u0178") ;; -- latin capital letter Y with diaeresis,U+0178 ISOlat2 -->
|
|
;; <!-- Spacing Modifier Letters -->
|
|
("ˆ" . "\u02C6") ;; -- modifier letter circumflex accent,U+02C6 ISOpub -->
|
|
("˜" . "\u02DC") ;; small tilde, U+02DC ISOdia -->
|
|
;; <!-- General Punctuation -->
|
|
(" " . "\u2002") ;; en space, U+2002 ISOpub -->
|
|
(" " . "\u2003") ;; em space, U+2003 ISOpub -->
|
|
(" " . "\u2009") ;; thin space, U+2009 ISOpub -->
|
|
("‌" . "\u200C") ;; zero width non-joiner,U+200C NEW RFC 2070 -->
|
|
("‍" . "\u200D") ;; zero width joiner, U+200D NEW RFC 2070 -->
|
|
("‎" . "\u200E") ;; left-to-right mark, U+200E NEW RFC 2070 -->
|
|
("‏" . "\u200F") ;; right-to-left mark, U+200F NEW RFC 2070 -->
|
|
("–" . "\u2013") ;; en dash, U+2013 ISOpub -->
|
|
("—" . "\u2014") ;; em dash, U+2014 ISOpub -->
|
|
("‘" . "\u2018") ;; left single quotation mark,U+2018 ISOnum -->
|
|
("’" . "\u2019") ;; right single quotation mark,U+2019 ISOnum -->
|
|
("‚" . "\u201A") ;; single low-9 quotation mark, U+201A NEW -->
|
|
("“" . "\u201C") ;; left double quotation mark,U+201C ISOnum -->
|
|
("”" . "\u201D") ;; right double quotation mark,U+201D ISOnum -->
|
|
("„" . "\u201E") ;; double low-9 quotation mark, U+201E NEW -->
|
|
("†" . "\u2020") ;; dagger, U+2020 ISOpub -->
|
|
("‡" . "\u2021") ;; double dagger, U+2021 ISOpub -->
|
|
("‰" . "\u2030") ;; per mille sign, U+2030 ISOtech -->
|
|
("‹" . "\u2039") ;; single left-pointing angle quotation mark,U+2039 ISO proposed -->
|
|
;; <!-- lsaquo is proposed but not yet ISO standardized -->
|
|
("›" . "\u203A") ;; single right-pointing angle quotation mark,U+203A ISO proposed -->
|
|
;; <!-- rsaquo is proposed but not yet ISO standardized -->
|
|
("€" . "\u20AC"))) ;; -- euro sign, U+20AC NEW -->
|
|
|
|
(defun org-cliplink-escape-numeric-match (s)
|
|
(char-to-string
|
|
(string-to-number
|
|
(match-string 1 s))))
|
|
|
|
(defvar org-cliplink-escape-alist
|
|
(append org-cliplink-basic-escape-alist
|
|
org-cliplink-iso8869-1-escape-alist
|
|
org-cliplink-html40-extended-escape-alist
|
|
'(("\\[" . "{")
|
|
("\\]" . "}")
|
|
("&#\\([0-9]+\\);" . org-cliplink-escape-numeric-match))))
|
|
|
|
(defgroup org-cliplink nil
|
|
"A simple command that takes a URL from the clipboard and inserts an
|
|
org-mode link with a title of a page found by the URL into the current
|
|
buffer."
|
|
:prefix "org-cliplink-"
|
|
:group 'wp
|
|
:link '(url-link "https://github.com/rexim/org-cliplink"))
|
|
|
|
(defcustom org-cliplink-max-length 80
|
|
"Max length of the title.
|
|
Org-cliplink cuts any title that exceeds the limit. Minimum
|
|
possible value is 4."
|
|
:group 'org-cliplink
|
|
:type '(choice integer (const :tag "off" nil)))
|
|
|
|
(defcustom org-cliplink-ellipsis "..."
|
|
"String to mark the end of truncated titles"
|
|
:group 'org-cliplink
|
|
:type 'string)
|
|
|
|
(defcustom org-cliplink-secrets-path "~/.org-cliplink-secrets.el"
|
|
"Path to file that keeps your org-cliplink related secrets.
|
|
It can be any sensitive information like password to different
|
|
services."
|
|
:group 'org-cliplink
|
|
:type 'string)
|
|
|
|
(defcustom org-cliplink-title-replacements
|
|
'(("https://github.com/.+/?"
|
|
("\\(.*\\) · \\(?:Issue\\|Pull Request\\) #\\([0-9]+\\) · \\(.*\\) · GitHub"
|
|
"\\3#\\2 \\1"))
|
|
("https://twitter.com/.+/status/[[:digit:]]+/?"
|
|
(".+ on Twitter: \\(.+\\)" "\\1")))
|
|
"A list of rules for formatting titles.
|
|
|
|
Each entry has the form (URL-REGEXP . (TITLE-REGEXP . REPLACEMENT))."
|
|
:group 'org-cliplink
|
|
:type '(repeat (list string (list string string))))
|
|
|
|
(defcustom org-cliplink-transport-implementation 'url-el
|
|
"The transport implementation.
|
|
Supported transports are `url-el' and `curl'. `curl' is
|
|
experimental so use it on your own risk."
|
|
:group 'org-cliplink
|
|
:type 'symbol)
|
|
|
|
(defcustom org-cliplink-curl-transport-arguments '()
|
|
"Additional arguments for cURL.
|
|
Used when the current transport implementation is set to
|
|
`curl'."
|
|
:group 'org-cliplink
|
|
:type '(repeat string))
|
|
|
|
(defcustom org-cliplink-simpleclip-source nil
|
|
"Clipboard source.
|
|
Non-nil means use system clipboard as source.
|
|
The clipboard content will be provided by `simpleclip',
|
|
requiring simpleclip.el to be installed.
|
|
|
|
When nil, use the first element of kill-ring as source"
|
|
:group 'org-cliplink
|
|
:type 'boolean)
|
|
|
|
(defun org-cliplink-clipboard-content ()
|
|
(let ((content (if (and org-cliplink-simpleclip-source
|
|
(fboundp 'simpleclip-get-contents))
|
|
(simpleclip-get-contents)
|
|
(current-kill 0))))
|
|
(string-trim
|
|
(substring-no-properties content))))
|
|
|
|
(defun org-cliplink-parse-raw-header (raw-header)
|
|
(let ((start 0)
|
|
(result-header nil))
|
|
(while (string-match "^\\(.+?\\): \\(.+?\\)\r?$" raw-header start)
|
|
(let ((header-name (match-string 1 raw-header))
|
|
(header-value (match-string 2 raw-header)))
|
|
(setq result-header
|
|
(cons (cons header-name header-value) result-header))
|
|
(setq start (match-end 2))))
|
|
result-header))
|
|
|
|
(defun org-cliplink-parse-response ()
|
|
(goto-char (point-min))
|
|
(search-forward-regexp "^\r?$")
|
|
(let ((content (buffer-substring (+ (point) 1) (point-max)))
|
|
(raw-header (buffer-substring (point-min) (point))))
|
|
(cons (org-cliplink-parse-raw-header raw-header)
|
|
content)))
|
|
|
|
(defun org-cliplink-extract-title-from-html (html)
|
|
(let* ((case-fold-search t)
|
|
(start0 (string-match "<title" html))
|
|
(start (when start0 (string-match ">" html start0)))
|
|
(end (string-match "</title>" html))
|
|
(chars-to-skip (length ">")))
|
|
(if (and start end (< start end))
|
|
(substring html (+ start chars-to-skip) end)
|
|
nil)))
|
|
|
|
(defun org-cliplink-escape-html4 (s)
|
|
(when s
|
|
(let ((case-replace nil)
|
|
(case-fold-search nil)
|
|
(result s))
|
|
(dolist (x org-cliplink-escape-alist result)
|
|
(setq result (replace-regexp-in-string (car x) (cdr x) result))))))
|
|
|
|
(defun org-cliplink-title-for-url (url title)
|
|
"Replace title using configured rules.
|
|
|
|
Find the first entry (URL-REGEXP (TITLE-REGEXP REPLACEMENT)) in
|
|
`org-cliplink-title-replacements' where URL-REGEXP matches URL,
|
|
and return TITLE with any matches for TITLE-REGEXP replaced by
|
|
REPLACEMENT.
|
|
|
|
If no URL-REGEXP matches URL, or if the first matching entry's
|
|
TITLE-REGEXP does not match TITLE, return the original TITLE."
|
|
(save-match-data
|
|
(cl-loop for (url-re (title-re rep)) in org-cliplink-title-replacements
|
|
when (string-match url-re url)
|
|
return (replace-regexp-in-string title-re rep title)
|
|
finally return title)))
|
|
|
|
(defun org-cliplink-org-mode-link-transformer (url title)
|
|
(if title
|
|
(format "[[%s][%s]]" url (org-cliplink-elide-string
|
|
(org-cliplink-escape-html4
|
|
(org-cliplink-title-for-url url title))
|
|
org-cliplink-max-length))
|
|
(format "[[%s]]" url)))
|
|
|
|
(defun org-cliplink-insert-org-mode-link-callback (url title)
|
|
(insert (org-cliplink-org-mode-link-transformer url title)))
|
|
|
|
(defun org-cliplink-uncompress-gziped-text (text)
|
|
(let ((filename (make-temp-file "org-cliplink" nil ".gz")))
|
|
(write-region text nil filename)
|
|
(with-auto-compression-mode
|
|
(with-temp-buffer
|
|
(insert-file-contents filename)
|
|
(delete-file filename)
|
|
(buffer-string)))))
|
|
|
|
(defun org-cliplink-extract-and-prepare-title-from-current-buffer ()
|
|
(let* ((response (org-cliplink-parse-response))
|
|
(header (car response))
|
|
(content (if (and (string= "gzip" (cdr (assoc "Content-Encoding" header)))
|
|
(not (string= "gzip" url-mime-encoding-string)))
|
|
(org-cliplink-uncompress-gziped-text (cdr response))
|
|
(cdr response)))
|
|
(decoded-content (decode-coding-string content (quote utf-8))))
|
|
(org-cliplink-straight-string
|
|
(org-cliplink-extract-title-from-html
|
|
decoded-content))))
|
|
|
|
(defun org-cliplink-read-secrets ()
|
|
(when (file-exists-p org-cliplink-secrets-path)
|
|
(with-temp-buffer
|
|
(insert-file-contents org-cliplink-secrets-path)
|
|
(car (read-from-string (buffer-string))))))
|
|
|
|
(defun org-cliplink-check-basic-auth-for-url (url)
|
|
(let ((basic-auth-secrets (plist-get (org-cliplink-read-secrets)
|
|
:basic-auth))
|
|
(result nil))
|
|
(while (and (not result) basic-auth-secrets)
|
|
(let ((secret (car basic-auth-secrets)))
|
|
(when (string-match (eshell-glob-regexp
|
|
(plist-get secret :url-pattern)) url)
|
|
(setq result secret)))
|
|
(pop basic-auth-secrets))
|
|
result))
|
|
|
|
;;;###autoload
|
|
(defun org-cliplink-retrieve-title (url title-callback)
|
|
(let* ((dest-buffer (current-buffer))
|
|
(basic-auth (org-cliplink-check-basic-auth-for-url url))
|
|
(url-retrieve-callback
|
|
(lambda (status)
|
|
(ignore status)
|
|
(let ((title (org-cliplink-extract-and-prepare-title-from-current-buffer)))
|
|
(with-current-buffer dest-buffer
|
|
(funcall title-callback url title))))))
|
|
(if (equal 'curl org-cliplink-transport-implementation)
|
|
(org-cliplink-http-get-request--curl url url-retrieve-callback basic-auth
|
|
org-cliplink-curl-transport-arguments)
|
|
(org-cliplink-http-get-request--url-el url url-retrieve-callback basic-auth))))
|
|
|
|
;;;###autoload
|
|
(defun org-cliplink-insert-transformed-title (url transformer)
|
|
"Takes the URL, asynchronously retrieves the title and applies
|
|
a custom TRANSFORMER which transforms the url and title and insert
|
|
the required text to the current buffer."
|
|
(org-cliplink-retrieve-title
|
|
url
|
|
(lambda (url title)
|
|
(insert (funcall transformer url title)))))
|
|
|
|
;;;###autoload
|
|
(defun org-cliplink-retrieve-title-synchronously (url)
|
|
(when (member (url-type (url-generic-parse-url url))
|
|
'("http" "https"))
|
|
(let ((response-buffer (url-retrieve-synchronously url t)))
|
|
(when response-buffer
|
|
(with-current-buffer response-buffer
|
|
(org-cliplink-elide-string
|
|
(org-cliplink-escape-html4
|
|
(org-cliplink-extract-and-prepare-title-from-current-buffer))
|
|
org-cliplink-max-length))))))
|
|
|
|
;;;###autoload
|
|
(defun org-cliplink ()
|
|
"Takes a URL from the clipboard and inserts an org-mode link
|
|
with the title of a page found by the URL into the current
|
|
buffer"
|
|
(interactive)
|
|
(org-cliplink-insert-transformed-title (org-cliplink-clipboard-content)
|
|
'org-cliplink-org-mode-link-transformer))
|
|
|
|
;;;###autoload
|
|
(defun org-cliplink-capture ()
|
|
"org-cliplink version for org-capture templates.
|
|
Makes synchronous request. Returns the link instead of inserting
|
|
it to the current buffer. Doesn't support Basic Auth. Doesn't
|
|
support cURL transport."
|
|
(interactive)
|
|
(let ((url (org-cliplink-clipboard-content)))
|
|
(org-cliplink-org-mode-link-transformer url
|
|
(org-cliplink-retrieve-title-synchronously url))))
|
|
|
|
(provide 'org-cliplink)
|
|
|
|
;;; org-cliplink.el ends here
|