{-# LANGUAGE OverloadedStrings, DeriveFunctor, ViewPatterns #-} module ShortcutLinks.All ( Result(..), Shortcut, allShortcuts, -- * Encyclopedias wikipedia, tvtropes, -- * Social networks facebook, vk, googleplus, -- * Microblogs twitter, juick, -- * Major search engines google, duckduckgo, yandex, baidu, -- * Programming language libraries npm, jam, rubygems, pypi, metacpanPod, metacpanRelease, hackage, cargo, pub, hex, cran, swiprolog, dub, bpkg, pear, -- * Code hosting github, gitlab, bitbucket, -- * OS packages -- ** Mobile googleplay, -- ** Windows chocolatey, -- ** OS X braumeister, -- ** Linux debian, aur, mint, fedora, gentoo, opensuse, -- * Addons -- ** Text editors marmalade, melpa, elpa, packagecontrol, atomPackage, atomTheme, jedit, vim, -- ** Browsers operaExt, operaTheme, firefox, chrome, -- * Manuals ghcExt, -- * Standards and databases rfc, ecma, cve, ) where -- General import Data.Monoid import Control.Applicative import Control.Monad import Data.Maybe -- Text import qualified Data.Text as T import Data.Text (Text) import Data.Char -- shortcut-links import ShortcutLinks.Utils data Result a = Failure String | Warning [String] a | Success a deriving (Show, Functor) instance Applicative Result where pure = return (<*>) = ap instance Monad Result where fail = Failure return = Success Failure x >>= _ = Failure x Warning wa a >>= f = case f a of Success b -> Warning wa b Warning wb b -> Warning (wa ++ wb) b Failure x -> Failure x Success a >>= f = f a warn :: String -> Result () warn s = Warning [s] () type Shortcut = Maybe Text -> Text -> Result Text -- | A list of all functions included in this module, together with suggested -- names for them. allShortcuts :: [([Text], Shortcut)] allShortcuts = let (.=) names func = (T.words names, func) in [ -- encyclopedias "w wikipedia" .= wikipedia, "tvt tvtropes" .= tvtropes, -- social networks "fb facebook" .= facebook, "vk vkontakte" .= vk, "gp gplus googleplus" .= googleplus, -- microblogs "t twitter" .= twitter, "juick" .= juick, -- search engines "google" .= google, "ddg duckduckgo" .= duckduckgo, "yandex" .= yandex, "baidu" .= baidu, -- programming language libraries "npm" .= npm, "jam" .= jam, "gem" .= rubygems, "pypi" .= pypi, "cpan" .= metacpanPod, "cpan-r" .= metacpanRelease, "hackage" .= hackage, "cargo" .= cargo, "pub" .= pub, "hex" .= hex, "cran" .= cran, "swiprolog" .= swiprolog, "dub" .= dub, "bpkg" .= bpkg, "pear" .= pear, -- code hosting "gh github" .= github, "gitlab" .= gitlab, "bitbucket" .= bitbucket, -- OS "gplay googleplay" .= googleplay, "chocolatey" .= chocolatey, "brew" .= braumeister, -- OS – Linux "debian" .= debian, "aur" .= aur, "mint" .= mint, "fedora" .= fedora, "gentoo" .= gentoo, "opensuse" .= opensuse, -- text editors "marmalade" .= marmalade, "melpa" .= melpa, "elpa" .= elpa, "sublime" .= packagecontrol, "atom" .= atomPackage, "atom-theme" .= atomTheme, "jedit" .= jedit, "vim" .= vim, -- browsers "opera" .= operaExt, "opera-theme" .= operaTheme, "firefox" .= firefox, "chrome" .= chrome, -- manuals "ghc-ext" .= ghcExt, -- standards and databases "rfc" .= rfc, "ecma" .= ecma, "cve" .= cve ] -- | <https://facebook.com Facebook> -- -- Link example: -- @[green](\@fb)@ → -- <https://facebook.com/green> facebook :: Shortcut facebook _ q = return $ "https://facebook.com/" <> q -- | <https://vk.com Vkontakte> (Вконтакте) -- -- Link example (username): -- @[green](\@vk)@ → -- <https://vk.com/green> -- -- Link example (ID): -- -- @[1337](\@vk)@ → -- <https://vk.com/id1337> vk :: Shortcut vk _ q = return $ "https://vk.com/" <> q' where q' = if not (T.null q) && isDigit (T.head q) then "id" <> q else q -- | <https://plus.google.com Google+> -- -- Link example (username): -- @[SergeyBrin](\@gp)@ → -- <https://plus.google.com/+SergeyBrin SergeyBrin> -- -- Link example (username with @+@): -- @[+SergeyBrin](\@gp)@ → -- <https://plus.google.com/+SergeyBrin +SergeyBrin> -- -- Link example (full name – will just be concatenated): -- @[Sergey Brin](\@gp)@ → -- <https://plus.google.com/+SergeyBrin Sergey Brin> -- -- Link example (ID): -- @[Sergey Brin](\@gp:109813896768294978296)@ → -- <https://plus.google.com/109813896768294978296 Sergey Brin> -- -- Link example (hashtag): -- @[#Australia](\@gp)@ → -- <https://plus.google.com/explore/Australia #Australia> googleplus :: Shortcut googleplus _ q | T.null q = return $ url | T.head q == '#' = return $ format "{}/explore/{}" url (T.tail q) | T.head q == '+' = return $ format "{}/{}" url q | T.all isDigit q = return $ format "{}/{}" url q | otherwise = return $ format "{}/+{}" url (T.concat (T.words q)) where url = "https://plus.google.com" -- | <https://twitter.com Twitter> -- -- Link example (username): -- @[kmett](\@t)@ → -- <https://twitter.com/kmett kmett> -- -- Link example (username with @\@@): -- @[\@kmett](\@t)@ → -- <https://twitter.com/kmett \@kmett> -- -- Link example (hashtag): -- @[#haskell](\@t)@ → -- <https://twitter.com/hashtag/haskell #haskell> twitter :: Shortcut twitter _ q | T.null q = return $ url | T.head q == '#' = return $ format "{}/hashtag/{}" url (T.tail q) | T.head q == '@' = return $ format "{}/{}" url (T.tail q) | otherwise = return $ format "{}/{}" url q where url = "https://twitter.com" -- | <https://juick.com Juick> -- -- Link example (username): -- @[thefish](\@juick)@ → -- <https://juick.com/thefish/ thefish> -- -- Link example (username with @\@@): -- @[\@thefish](\@juick)@ → -- <https://juick.com/thefish/ \@thefish> -- -- Link example (tag): -- @[*Haskell](\@juick)@ → -- <https://juick.com/tag/Haskell *Haskell> juick :: Shortcut juick _ q | T.null q = return $ url | T.head q == '*' = return $ format "{}/tag/{}" url (T.tail q) | T.head q == '@' = return $ format "{}/{}" url (T.tail q) | otherwise = return $ format "{}/{}" url q where url = "https://juick.com" -- | <https://google.com Google> -- -- Link example: -- @[random query](\@google)@ → -- <https://www.google.com/search?nfpr=1&q=random+query random query> google :: Shortcut google _ q = return $ "https://google.com/search?nfpr=1&q=" <> replaceSpaces '+' q -- | <https://duckduckgo.com Duckduckgo> -- -- Link example: -- @[random query](\@ddg)@ → -- <https://duckduckgo.com/?q=random+query random query> duckduckgo :: Shortcut duckduckgo _ q = return $ "https://duckduckgo.com/?q=" <> replaceSpaces '+' q -- | <http://yandex.ru Yandex> (Russian search engine) -- -- Link example: -- @[random query](\@yandex)@ → -- <http://yandex.ru/search/?noreask=1&text=random+query random query> yandex :: Shortcut yandex _ q = return $ "http://yandex.ru/search/?noreask=1&text=" <> replaceSpaces '+' q -- | <http://baidu.com Baidu> (Chinese search engine) -- -- Link example: -- @[random query](\@baidu)@ → -- <http://baidu.com/s?nojc=1&wd=random+query random query> baidu :: Shortcut baidu _ q = return $ "http://baidu.com/s?nojc=1&wd=" <> replaceSpaces '+' q -- | __Node.js__ – <https://npmjs.com NPM> -- -- Link example: -- @[markdown](\@npm)@ → -- <https://www.npmjs.com/package/markdown markdown> npm :: Shortcut npm _ q = return $ "https://npmjs.com/package/" <> q -- | __Javascript__ – <http://jamjs.org/packages/#/ Jam> -- -- Link example: -- @[pagedown](\@jam)@ → -- <http://jamjs.org/packages/#/details/pagedown pagedown> jam :: Shortcut jam _ q = return $ "http://jamjs.org/packages/#/details/" <> q -- | __Ruby__ – <https://rubygems.org RubyGems.org> -- -- Link example: -- @[github-markdown](\@gem)@ → -- <https://rubygems.org/gems/github-markdown github-markdown> rubygems :: Shortcut rubygems _ q = return $ "https://rubygems.org/gems/" <> q -- | __Python__ – <https://pypi.python.org/pypi PyPI> -- -- Link example: -- @[Markdown](\@pypi)@ → -- <https://pypi.python.org/pypi/Markdown Markdown> pypi :: Shortcut pypi _ q = return $ "https://pypi.python.org/pypi/" <> q -- | __Perl__ – <https://metacpan.org MetaCPAN> (by module) -- -- Link example: -- @[Text::Markdown](\@cpan)@ → -- <https://metacpan.org/pod/Text::Markdown Text::Markdown> metacpanPod :: Shortcut metacpanPod _ q = return $ "https://metacpan.org/pod/" <> q -- | __Perl__ – <https://metacpan.org MetaCPAN> (by release) -- -- Link example: -- @[Text-Markdown](\@cpan-r)@ → -- <https://metacpan.org/release/Text-Markdown Text-Markdown> metacpanRelease :: Shortcut metacpanRelease _ q = return $ "https://metacpan.org/release/" <> q -- | __Haskell__ – <https://hackage.haskell.org Hackage> -- -- Link example: -- @[cmark](\@hackage)@ → -- <https://hackage.haskell.org/package/cmark cmark> hackage :: Shortcut hackage _ q = return $ "https://hackage.haskell.org/package/" <> q -- | __Rust__ – <https://crates.io Cargo> -- -- Link example: -- @[hoedown](\@cargo)@ → -- <https://crates.io/crates/hoedown hoedown> cargo :: Shortcut cargo _ q = return $ "https://crates.io/crates/" <> q -- | __PHP__ – <http://pear.php.net PEAR> -- -- Link example: -- @[Text_Wiki_Doku](\@pear)@ → -- <http://pear.php.net/package/Text_Wiki_Doku Text_Wiki_Doku> pear :: Shortcut pear _ q = return $ "http://pear.php.net/package/" <> q -- | __Dart__ – <https://pub.dartlang.org pub> -- -- Link example: -- @[md_proc](\@pub)@ → -- <https://pub.dartlang.org/packages/md_proc md_proc> pub :: Shortcut pub _ q = return $ "https://pub.dartlang.org/packages/" <> q -- | __R__ – <http://cran.r-project.org/web/packages/ CRAN> -- -- Link example: -- @[markdown](\@cran)@ → -- <http://cran.r-project.org/web/packages/markdown markdown> cran :: Shortcut cran _ q = return $ "http://cran.r-project.org/web/packages/" <> q -- | __Erlang__ – <https://hex.pm Hex> -- -- Link example: -- @[earmark](\@hex)@ → -- <https://hex.pm/packages/earmark earmark> hex :: Shortcut hex _ q = return $ "https://hex.pm/packages/" <> q -- | __SWI-Prolog__ – <http://www.swi-prolog.org/pack/list packages> -- -- Link example: -- @[markdown](\@swiprolog)@ → -- <http://www.swi-prolog.org/pack/list?p=markdown markdown> swiprolog :: Shortcut swiprolog _ q = return $ "http://www.swi-prolog.org/pack/list?p=" <> q -- | __D__ – <http://code.dlang.org DUB> -- -- Link example: -- @[dmarkdown](\@dub)@ → -- <http://code.dlang.org/packages/dmarkdown dmarkdown> dub :: Shortcut dub _ q = return $ "http://code.dlang.org/packages/" <> q -- | __Bash__ – <http://bpkg.io bpkg> -- -- Link example: -- @[markdown](\@bpkg)@ → -- <http://www.bpkg.io/pkg/markdown markdown> bpkg :: Shortcut bpkg _ q = return $ "http://bpkg.io/pkg/" <> q -- | <https://github.com Github> -- -- Link example: -- @[aelve/shortcut-links](\@gh)@ → -- <https://github.com/aelve/shortcut-links aelve/shortcut-links> -- -- The repository owner can also be given as an option: -- -- @[shortcut-links](\@gh(aelve))@ → -- <https://github.com/aelve/shortcut-links shortcut-links> github :: Shortcut github mbOwner q = case mbOwner of Nothing -> return $ format "https://github.com/{}" q Just owner -> return $ format "https://github.com/{}/{}" owner q -- | <https://bitbucket.org Bitbucket> -- -- Link example: -- @[bos/text](\@bitbucket)@ → -- <https://bitbucket.org/bos/text bos/text> -- -- The repository owner can also be given as an option: -- -- @[text](\@bitbucket(bos))@ → -- <https://bitbucket.org/bos/text text> bitbucket :: Shortcut bitbucket mbOwner q = case mbOwner of Nothing -> return $ format "https://bitbucket.org/{}" q Just owner -> return $ format "https://bitbucket.org/{}/{}" owner q -- | <https://gitlab.com Gitlab> -- -- Link example: -- @[learnyou/lysa](\@gitlab)@ → -- <https://gitlab.com/learnyou/lysa learnyou/lysa> -- -- The repository owner can also be given as an option: -- -- @[lysa](\@gitlab(learnyou))@ → -- <https://gitlab.com/learnyou/lysa lysa> -- -- Note that links like <https://gitlab.com/owner> work but are going to be -- automatically redirected to either <https://gitlab.com/u/owner> or -- <https://gitlab.com/groups/owner>, depending on whether it's a user or a -- team. So, it's a case when the “links have to look as authentic as -- possible” principle is violated (but c'mon, this “u” thing looks ugly -- anyway). gitlab :: Shortcut gitlab mbOwner q = case mbOwner of Nothing -> return $ format "https://gitlab.com/{}" q Just owner -> return $ format "https://gitlab.com/{}/{}" owner q -- | __Android__ – <https://play.google.com Google Play> (formerly Play Market) -- -- Link example: -- @[Opera Mini](\@gplay:com.opera.mini.native)@ → -- <https://play.google.com/store/apps/details?id=com.opera.mini.native Opera Mini> googleplay :: Shortcut googleplay _ q = return $ "https://play.google.com/store/apps/details?id=" <> q -- | <http://braumeister.org Braumeister> (Homebrew formulas) -- -- Link example: -- @[multimarkdown](\@brew)@ → -- <http://braumeister.org/formula/multimarkdown multimarkdown> braumeister :: Shortcut braumeister _ q = return $ "http://braumeister.org/formula/" <> q -- | <https://chocolatey.org Chocolatey> -- -- Link example: -- @[Opera](\@chocolatey)@ → -- <https://chocolatey.org/packages/Opera Opera> chocolatey :: Shortcut chocolatey _ q = return $ "https://chocolatey.org/packages/" <> q -- | __Debian__ – <https://debian.org/distrib/packages packages> -- -- Link example (stable distribution): -- @[ghc](\@debian)@ → -- <https://packages.debian.org/stable/ghc ghc> -- -- Link example (experimental distribution, but could be any other): -- @[ghc](\@debian(experimental))@ → -- <https://packages.debian.org/experimental/ghc ghc> debian :: Shortcut debian mbDist q = return $ format "https://packages.debian.org/{}/{}" dist q where dist = fromMaybe "stable" mbDist -- | __Arch Linux__ – <https://aur.archlinux.org AUR> (“user repository”) -- -- Link example: -- @[ghc-git](\@aur)@ → -- <https://aur.archlinux.org/packages/ghc-git ghc-git> aur :: Shortcut aur _ q = return $ "https://aur.archlinux.org/packages/" <> q -- | __Gentoo__ – <https://packages.gentoo.org packages> -- -- Link example: -- @[dev-lang/ghc](\@gentoo)@ → -- <https://packages.gentoo.org/package/dev-lang/ghc dev-lang/ghc> -- -- Link example (category as an option): -- @[ghc](\@gentoo(dev-lang))@ → -- <https://packages.gentoo.org/package/dev-lang/ghc ghc> -- -- Note that if you don't specify any category, the link would still work – -- but there are a lot of packages with overlapping names (like “ace”, “csv”, -- “http”), and such links would lead to search pages listing several -- packages. So, it's better to include categories. gentoo :: Shortcut gentoo mbCat q = return $ "https://packages.gentoo.org/package/" <> pkg where pkg = case mbCat of Nothing -> q Just cat -> cat <> "/" <> q -- | __openSUSE__ – <http://software.opensuse.org packages> -- -- Link example: -- @[ghc](\@opensuse)@ → -- <http://software.opensuse.org/package/ghc ghc> opensuse :: Shortcut opensuse _ q = return $ "http://software.opensuse.org/package/" <> q -- | __Linux Mint__ – <http://community.linuxmint.com/software/browse packages> -- -- Link example: -- @[ghc](\@mint)@ → -- <http://community.linuxmint.com/software/view/ghc ghc> mint :: Shortcut mint _ q = return $ "http://community.linuxmint.com/software/view/" <> q -- | __Fedora__ – <https://admin.fedoraproject.org/pkgdb packages> -- -- Link example: -- @[ghc](\@fedora)@ → -- <https://admin.fedoraproject.org/pkgdb/package/ghc ghc> fedora :: Shortcut fedora _ q = return $ "https://admin.fedoraproject.org/pkgdb/package/" <> q -- | __Emacs__ – <https://marmalade-repo.org Marmalade> -- -- Link example: -- @[markdown-mode](\@marmalade)@ → -- <https://marmalade-repo.org/packages/markdown-mode markdown-mode> marmalade :: Shortcut marmalade _ q = return $ "https://marmalade-repo.org/packages/" <> q -- | __Emacs__ – <http://melpa.org MELPA> -- -- Link example: -- @[markdown-mode](\@melpa)@ → -- <http://melpa.org/#/markdown-mode markdown-mode> melpa :: Shortcut melpa _ q = return $ "http://melpa.org/#/" <> q -- | __Emacs__ – <https://elpa.gnu.org ELPA> -- -- Link example: -- @[undo-tree](\@elpa)@ → -- <https://elpa.gnu.org/packages/undo-tree.html undo-tree> elpa :: Shortcut elpa _ q = return $ format "https://elpa.gnu.org/packages/{}.html" q -- | __Sublime Text__ – <https://packagecontrol.io Package Control> -- -- Link example: -- @[MarkdownEditing](\@sublime)@ → -- <https://packagecontrol.io/packages/MarkdownEditing MarkdownEditing> packagecontrol :: Shortcut packagecontrol _ q = return $ "https://packagecontrol.io/packages/" <> q -- | __Atom__ – <https://atom.io/packages packages> -- -- Link example: -- @[tidy-markdown](\@atom)@ → -- <https://atom.io/packages/tidy-markdown tidy-markdown> atomPackage :: Shortcut atomPackage _ q = return $ "https://atom.io/packages/" <> q -- | __Atom__ – <https://atom.io/themes themes> -- -- Link example: -- @[atom-material-ui](\@atom-theme)@ → -- <https://atom.io/themes/atom-material-ui atom-material-ui> atomTheme :: Shortcut atomTheme _ q = return $ "https://atom.io/themes/" <> q -- | __jEdit__ – <http://plugins.jedit.org packages> -- -- Link example: -- @[MarkdownPlugin](\@jedit)@ → -- <http://plugins.jedit.org/plugins/?MarkdownPlugin MarkdownPlugin> jedit :: Shortcut jedit _ q = return $ "http://plugins.jedit.org/plugins/?" <> q -- | __Vim__ – <http://www.vim.org/scripts/ scripts> -- -- Link example (ID): -- @[haskell.vim](\@vim:2062)@ → -- <http://www.vim.org/scripts/script.php?script_id=2062 haskell.vim> vim :: Shortcut vim _ q = return $ "http://www.vim.org/scripts/script.php?script_id=" <> q -- | __Opera__ – <https://addons.opera.com/extensions/ extensions> -- -- Link example: -- @[Amazon](\@opera:amazon-for-opera)@ → -- <https://addons.opera.com/extensions/details/amazon-for-opera Amazon> operaExt :: Shortcut operaExt _ q = return $ "https://addons.opera.com/extensions/details/" <> q -- | __Opera__ – <https://addons.opera.com/themes/ themes> -- -- Link example: -- @[Space theme](\@opera-theme:space-15)@ → -- <https://addons.opera.com/en/themes/details/space-15 Space theme> operaTheme :: Shortcut operaTheme _ q = return $ "https://addons.opera.com/themes/details/" <> q -- | __Firefox__ – <https://addons.mozilla.org/firefox Add-ons> (extensions, themes) -- -- Link example: -- @[tree-style-tab]@ → -- <https://addons.mozilla.org/firefox/addon/tree-style-tab Tree Style Tab> firefox :: Shortcut firefox _ q = return $ "https://addons.mozilla.org/firefox/addon/" <> q -- | __Chrome__ – <https://chrome.google.com/webstore Chrome Web Store> (extensions, apps, themes) -- -- Link example: -- @[hdokiejnpimakedhajhdlcegeplioahd]@ → -- <https://chrome.google.com/webstore/detail/hdokiejnpimakedhajhdlcegeplioahd LastPass> chrome :: Shortcut chrome _ q = return $ "https://chrome.google.com/webstore/detail/" <> q -- | <https://www.haskell.org/ghc/ GHC> (Glasgow Haskell Compiler) extensions -- -- Link example: -- @[ViewPatterns](\@ghc-ext)@ → -- <https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/syntax-extns.html#view-patterns ViewPatterns> ghcExt :: Shortcut ghcExt _ ext = case lookup ext ghcExtsList of Nothing -> fail (format "unknown GHC extension '{}'" ext) Just link -> return link -- | <https://www.ietf.org/rfc.html RFCs> -- -- Link example: -- @[RFC 2026](\@rfc)@ → -- <https://tools.ietf.org/html/rfc2026 RFC 2026> -- -- Precise format of recognised text: optional “rfc” (case-insensitive), then -- arbitrary amount of spaces and punctuation (or nothing), then the -- number. Examples: “RFC 2026”, “RFC-2026”, “rfc2026”, “rfc #2026”, “2026”, -- “#2026”. rfc :: Shortcut rfc _ x = do let n = T.dropWhile (not . isAlphaNum) (tryStripPrefixCI "rfc" x) -- We don't use 'readMaybe' here because 'readMaybe' isn't available in GHC -- 7.4, which Pandoc has to be compatible with. unless (T.all isDigit n) $ warn "non-digits in RFC number" when (T.null n) $ warn "no RFC number" let n' = T.dropWhile (== '0') n `orElse` "0" return ("https://tools.ietf.org/html/rfc" <> n') -- | <http://ecma-international.org/publications/index.html Ecma standards and technical reports> -- -- Link example (standard): -- @[ECMA-262](\@ecma)@ → -- <http://www.ecma-international.org/publications/standards/Ecma-262.htm ECMA-262> -- -- Link example (technical report): -- @[TR/71](\@ecma)@ → -- <http://ecma-international.org/publications/techreports/E-TR-071.htm TR/71> -- -- Precise format of recognised text for standards: optional “ECMA” -- (case-insensitive), then arbitrary amount of spaces and punctuation (or -- nothing), then the number. Examples: “ECMA-262”, “ECMA 262”, “ecma262”, -- “ECMA #262”, “262”, “#262”. -- -- Format for technical reports is the same, except that “TR” (instead of -- “ECMA”) is not optional (so, if there's only a number given, it's -- considered a standard and not a technical report). ecma :: Shortcut ecma _ q = do -- TODO: move dropSeparators to Utils and use it in 'rfc' and 'cve' let dropSeparators = T.dropWhile (not . isAlphaNum) let (dropSeparators -> mbNum, isTR) = case stripPrefixCI "tr" q of Nothing -> (tryStripPrefixCI "ecma" q, False) Just q' -> (q', True) -- We don't use 'readMaybe' here because 'readMaybe' isn't available in GHC -- 7.4, which Pandoc has to be compatible with. unless (T.all isDigit mbNum) $ warn "non-digits in ECMA standard number" when (T.null mbNum) $ warn "no ECMA standard number" -- The number has to have at least 3 digits. let num = T.justifyRight 3 '0' mbNum url = "http://ecma-international.org/publications" :: Text return $ if isTR then format "{}/techreports/E-TR-{}.htm" url num else format "{}/standards/Ecma-{}.htm" url num -- | <http://cve.mitre.org CVEs> (Common Vulnerabilities and Exposures) -- -- Link example: -- @[CVE-2014-10001](\@cve)@ → -- <http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-10001> -- -- Precise format of recognised text: optional “cve” (case-insensitive), then -- arbitrary amount of spaces and punctuation (or nothing), then the year, -- ‘-’, and a number. Examples: “CVE-2014-10001”, “cve 2014-10001”, -- “2014-10001”. cve :: Shortcut cve _ x = do let n = T.dropWhile (not . isAlphaNum) (tryStripPrefixCI "cve" x) unless (T.length n >= 9) $ warn "CVE-ID is too short" let isValid = and [ T.length n >= 9, T.all isDigit (T.take 4 n), T.index n 4 == '-', T.all isDigit (T.drop 5 n) ] unless isValid $ warn "CVE-ID doesn't follow the <year>-<digits> format" return ("http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-" <> n) -- | <https://wikipedia.org/ Wikipedia> -- -- Link example (English Wikipedia): -- @[grey-headed flying fox](\@w)@ → -- <https://en.wikipedia.org/wiki/Grey-headed_flying_fox> -- -- Link example (Russian Wikipedia, but any language code can be used): -- @[Haskell](\@w(ru))@ → -- <https://ru.wikipedia.org/wiki/Haskell> wikipedia :: Shortcut wikipedia mbLang q = return $ format "https://{}.wikipedia.org/wiki/{}" lang q' where lang = fromMaybe "en" mbLang q' = titleFirst (replaceSpaces '_' q) -- | <http://tvtropes.org TV Tropes> -- -- Link example (trope): -- @[so bad, it's good](\@tvtropes)@ → -- <http://tvtropes.org/pmwiki/pmwiki.php/Main/SoBadItsGood> -- -- Link example (series): -- @[Elementary](\@tvtropes(series))@ → -- <http://tvtropes.org/pmwiki/pmwiki.php/Series/Elementary> -- -- You can give anything as a category instead of “series”, it'll be -- capitalised but nothing else. tvtropes :: Shortcut tvtropes mbCat q = return $ format "http://tvtropes.org/pmwiki/pmwiki.php/{}/{}" cat q' where cat = maybe "Main" titleFirst mbCat isSep c = (isSpace c || isPunctuation c) && c /= '\'' -- Break into words, transform each word like “it's” → “Its”, and concat. -- Note that e.g. “man-made” is considered 2 separate words. q' = T.concat $ map (titleFirst . T.filter isAlphaNum) (T.split isSep q) ghcExtsList :: [(Text, Text)] ghcExtsList = do let (.=) = (,) base = "https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/" prefix x = map (\(a, b) -> (a, x <> b)) prefix base $ concat [ prefix "syntax-extns.html" [ "DisambiguateRecordFields" .= "#disambiguate-fields", "EmptyCase" .= "#empty-case", "NoImplicitPrelude" .= "#rebindable-syntax", "NegativeLiterals" .= "#negative-literals", "RebindableSyntax" .= "#rebindable-syntax", "PatternGuards" .= "#pattern-guards", "ViewPatterns" .= "#view-patterns", "UnicodeSyntax" .= "#unicode-syntax", "MagicHash" .= "#magic-hash", "ParallelListComp" .= "#parallel-list-comprehensions", "TransformListComp" .= "#generalised-list-comprehensions", "MonadComprehensions" .= "#monad-comprehensions", "ExplicitNamespaces" .= "#explicit-namespaces", "RecursiveDo" .= "#recursive-do-notation", "RecordWildCards" .= "#record-wildcards", "NamedFieldPuns" .= "#record-puns", "PackageImports" .= "#package-imports", "LambdaCase" .= "#lambda-case", "MultiWayIf" .= "#multi-way-if", "NumDecimals" .= "#num-decimals", "BinaryLiterals" .= "#binary-literals", "PostfixOperators" .= "#postfix-operators", "TupleSections" .= "#tuple-sections", "PatternSynonyms" .= "#pattern-synonyms" ], prefix "data-type-extensions.html" [ "GADTs" .= "#gadt", "GADTSyntax" .= "#gadt-style", "ExistentialQuantification" .= "#existential-quantification", "LiberalTypeSynonyms" .= "#type-synonyms", "EmptyDataDecls" .= "#nullary-types", "DatatypeContexts" .= "#datatype-contexts", "TypeOperators" .= "#type-operators" ], prefix "other-type-extensions.html" [ "AllowAmbiguousTypes" .= "#ambiguity", "ImplicitParams" .= "#implicit-parameters", "NoMonomorphismRestriction" .= "#monomorphism", "RelaxedPolyRec" .= "#typing-binds", "MonoLocalBinds" .= "#mono-local-binds", "ScopedTypeVariables" .= "#scoped-type-variables", "ExplicitForAll" .= "#explicit-foralls", "PolymorphicComponents" .= "#universal-quantification", "Rank2Types" .= "#universal-quantification", "RankNTypes" .= "#universal-quantification", "ImpredicativeTypes" .= "#impredicative-polymorphism", "KindSignatures" .= "#kinding", "FlexibleContexts" .= "#flexible-contexts" ], prefix "type-class-extensions.html" [ "IncoherentInstances" .= "#instance-overlap", "OverlappingInstances" .= "#instance-overlap", "OverloadedLists" .= "#overloaded-lists", "OverloadedStrings" .= "#overloaded-strings", "UndecidableInstances" .= "#undecidable-instances", "TypeSynonymInstances" .= "#flexible-instance-head", "FlexibleInstances" .= "#instance-rules", "ConstrainedClassMethods" .= "#class-method-types", "DefaultSignatures" .= "#class-default-signatures", "MultiParamTypeClasses" .= "#multi-param-type-classes", "NullaryTypeClasses" .= "#nullary-type-classes", "InstanceSigs" .= "#instance-sigs", "FunctionalDependencies" .= "#functional-dependencies" ], prefix "deriving.html" [ "AutoDeriveTypeable" .= "#auto-derive-typeable", "DeriveDataTypeable" .= "#deriving-typeable", "DeriveGeneric" .= "#deriving-typeable", "DeriveFunctor" .= "#deriving-extra", "DeriveTraversable" .= "#deriving-extra", "DeriveFoldable" .= "#deriving-extra", "GeneralizedNewtypeDeriving" .= "#newtype-deriving", "DeriveAnyClass" .= "#derive-any-class", "StandaloneDeriving" .= "#stand-alone-deriving" ], prefix "template-haskell.html" [ "TemplateHaskell" .= "", "QuasiQuotes" .= "#th-quasiquotation" ], prefix "ffi.html" [ "ForeignFunctionInterface" .= "", "InterruptibleFFI" .= "#ffi-interruptible", "CApiFFI" .= "#ffi-capi" ], prefix "partial-type-signatures.html" [ "PartialTypeSignatures" .= "", "NamedWildCards" .= "#named-wildcards" ], map (.= "safe-haskell.html") [ "Safe", "Trustworthy", "Unsafe" ], [ "Arrows" .= "arrow-notation.html", "ConstraintKinds" .= "constraint-kind.html", "DataKinds" .= "promotion.html", "ExtendedDefaultRules" .= "interactive-evaluation.html#extended-default-rules", "TypeFamilies" .= "type-families.html", "PolyKinds" .= "kind-polymorphism.html", "BangPatterns" .= "bang-patterns.html", "CPP" .= "options-phases.html#c-pre-processor", "RoleAnnotations" .= "roles.html#role-annotations", "UnboxedTuples" .= "primitives.html#unboxed-tuples" ] ]