packages feed

commonmark-extensions 0.2.0.4 → 0.2.1

raw patch · 14 files changed

+359/−29 lines, 14 filesdep +filepathdep +network-uridep +tasty-benchdep −QuickCheckdep −bytestringdep −criteriondep ~commonmarkPVP ok

version bump matches the API change (PVP)

Dependencies added: filepath, network-uri, tasty-bench

Dependencies removed: QuickCheck, bytestring, criterion, tasty-quickcheck

Dependency ranges changed: commonmark

API changes (from Hackage documentation)

+ Commonmark.Extensions.RebaseRelativePaths: rebaseRelativePathsSpec :: forall m bl il. (Monad m, IsInline il, IsBlock il bl) => SyntaxSpec m il bl
+ Commonmark.Extensions.Wikilinks: TitleAfterPipe :: TitlePosition
+ Commonmark.Extensions.Wikilinks: TitleBeforePipe :: TitlePosition
+ Commonmark.Extensions.Wikilinks: class HasWikilinks il
+ Commonmark.Extensions.Wikilinks: data TitlePosition
+ Commonmark.Extensions.Wikilinks: instance (Commonmark.Extensions.Wikilinks.HasWikilinks il, GHC.Base.Semigroup il, GHC.Base.Monoid il) => Commonmark.Extensions.Wikilinks.HasWikilinks (Commonmark.SourceMap.WithSourceMap il)
+ Commonmark.Extensions.Wikilinks: instance Commonmark.Types.Rangeable (Commonmark.Html.Html a) => Commonmark.Extensions.Wikilinks.HasWikilinks (Commonmark.Html.Html a)
+ Commonmark.Extensions.Wikilinks: instance GHC.Classes.Eq Commonmark.Extensions.Wikilinks.TitlePosition
+ Commonmark.Extensions.Wikilinks: instance GHC.Show.Show Commonmark.Extensions.Wikilinks.TitlePosition
+ Commonmark.Extensions.Wikilinks: wikilink :: HasWikilinks il => Text -> il -> il
+ Commonmark.Extensions.Wikilinks: wikilinksSpec :: (Monad m, IsInline il, HasWikilinks il) => TitlePosition -> SyntaxSpec m il bl

Files

README.md view
@@ -25,6 +25,8 @@ - [`auto_identifiers`] (automatic generation of identifiers for headings) - [`auto_identifiers_ascii`] (automatic generation of ASCII identifiers for headings) - [`implicit_heading_references`] (headings implicitly define link references)+- [`wikilinks_title_before_pipe`] and+  [`wikilinks_title_after_pipe`] (wikilink syntax)  [`pipe_tables`]: test/pipe_tables.md [`hard_line_breaks`]: test/hard_line_breaks.md@@ -46,4 +48,6 @@ [`auto_identifiers`]: test/auto_identifiers.md [`auto_identifiers_ascii`]: test/auto_identifiers_ascii.md [`implicit_heading_references`]: test/implicit_heading_references.md+[`wikilinks_title_before_pipe`]: test/wikilinks_title_before_pipe.md+[`wikilinks_title_after_pipe`]: test/wikilinks_title_before_pipe.md 
benchmark/benchmark.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE CPP                 #-} {-# LANGUAGE OverloadedStrings   #-} {-# LANGUAGE ScopedTypeVariables #-}-import Criterion.Main+import Test.Tasty.Bench import Data.Text (Text) import Data.Functor.Identity  -- base >= 4.8 import Commonmark@@ -15,7 +15,7 @@ main :: IO () main = do   sample <- T.replicate 10 <$> TIO.readFile "benchmark/sample.md"-  defaultMainWith defaultConfig+  defaultMain     [ benchCommonmark (smartPunctuationSpec <> defaultSyntaxSpec)         ("commonmark +smart", sample)     , benchCommonmark (autolinkSpec <> defaultSyntaxSpec)
changelog.md view
@@ -1,5 +1,13 @@ # Changelog for commonmark-extensions +## 0.2.1++- Add `rebase_relative_paths` extension.+  New exported module Commonmark.Extensions.RebaseRelativePaths [API change].+- Add `wikilinks_title_before_pipe` and `wikilinks_title_after_pipe`+  extensions (#69).+  New exported module Commonmark.Extensions.Wikilinks [API change].+ ## 0.2.0.4  - Add a test for autolinks (#66).
commonmark-extensions.cabal view
@@ -1,5 +1,5 @@ name:           commonmark-extensions-version:        0.2.0.4+version:        0.2.1 synopsis:       Pure Haskell commonmark parser. description:    This library provides some useful extensions to core commonmark@@ -11,7 +11,7 @@ bug-reports:    https://github.com/jgm/commonmark-hs/issues author:         John MacFarlane maintainer:     jgm@berkeley.edu-copyright:      2018-2020 John MacFarlane+copyright:      2018-2021 John MacFarlane license:        BSD3 license-file:   LICENSE build-type:     Simple@@ -28,6 +28,8 @@     test/implicit_heading_references.md     test/pipe_tables.md     test/attributes.md+    test/wikilinks_title_before_pipe.md+    test/wikilinks_title_after_pipe.md     test/raw_attribute.md     test/fenced_divs.md     test/bracketed_spans.md@@ -35,6 +37,7 @@     test/math.md     test/emoji.md     test/smart.md+    test/rebase_relative_paths.md     test/strikethrough.md     test/superscript.md     test/subscript.md@@ -51,11 +54,12 @@   build-depends:       base >= 4.9 && <5     , text-    , bytestring+    , parsec     , containers     , transformers-    , parsec-    , commonmark >= 0.1.1.2 && < 0.2+    , filepath+    , network-uri+    , commonmark >= 0.2 && < 0.3     -- for extensions:     , emojis >= 0.1 && < 0.2   exposed-modules:@@ -76,7 +80,11 @@       Commonmark.Extensions.FancyList       Commonmark.Extensions.TaskList       Commonmark.Extensions.ImplicitHeadingReferences+      Commonmark.Extensions.RebaseRelativePaths+      Commonmark.Extensions.Wikilinks   ghc-options: -Wall -fno-warn-unused-do-bind -funbox-small-strict-fields+  if impl(ghc >= 8.10)+    ghc-options:      -Wunused-packages   if impl(ghc >= 8.8)     ghc-options:  -fwrite-ide-info -hiedir=.hie   default-language: Haskell2010@@ -86,16 +94,16 @@   main-is: test-commonmark-extensions.hs   hs-source-dirs:       test+  if impl(ghc >= 8.10)+    ghc-options:      -Wunused-packages   ghc-options: -threaded -rtsopts -with-rtsopts=-K40K   build-depends:       base >= 4.9 && <5-    , commonmark+    , commonmark >= 0.2 && < 0.3     , commonmark-extensions     , text     , tasty-    , tasty-quickcheck     , tasty-hunit-    , QuickCheck     , parsec   default-language: Haskell2010 @@ -104,13 +112,12 @@   main-is:         benchmark.hs   hs-source-dirs:  benchmark   build-depends:-       commonmark >= 0.1.1.2 && < 0.2+       commonmark >= 0.2 && < 0.3      , commonmark-extensions      , base >= 4.9 && < 5      , text-     , transformers-     , containers-     , bytestring-     , criterion >= 1.0 && < 1.6+     , tasty-bench+  if impl(ghc >= 8.10)+    ghc-options:      -Wunused-packages   ghc-options: -threaded -rtsopts -with-rtsopts=-K10K   default-language: Haskell2010
src/Commonmark/Extensions.hs view
@@ -39,6 +39,8 @@     , module Commonmark.Extensions.FancyList     , module Commonmark.Extensions.TaskList     , module Commonmark.Extensions.ImplicitHeadingReferences+    , module Commonmark.Extensions.Wikilinks+    , module Commonmark.Extensions.RebaseRelativePaths     , gfmExtensions     ) where @@ -58,6 +60,8 @@ import           Commonmark.Extensions.FancyList import           Commonmark.Extensions.TaskList import           Commonmark.Extensions.ImplicitHeadingReferences+import           Commonmark.Extensions.Wikilinks+import           Commonmark.Extensions.RebaseRelativePaths import           Commonmark #if !MIN_VERSION_base(4,11,0) import           Data.Monoid ((<>))
src/Commonmark/Extensions/ImplicitHeadingReferences.hs view
@@ -51,6 +51,7 @@           referenceMap = insertReference lab             LinkInfo{ linkDestination = "#" <> ident                     , linkTitle = mempty-                    , linkAttributes = mempty }+                    , linkAttributes = mempty+                    , linkPos = Nothing }             (referenceMap s) }   | otherwise = return ()
+ src/Commonmark/Extensions/RebaseRelativePaths.hs view
@@ -0,0 +1,135 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+module Commonmark.Extensions.RebaseRelativePaths+  ( rebaseRelativePathsSpec )+where+import Commonmark.Types+import Commonmark.Syntax+import Commonmark.Inlines+import Data.Text (Text)+import qualified Data.Text as T+import Data.Maybe (fromMaybe)+import Text.Parsec (getPosition)+import Text.Parsec.Pos (sourceName)+import System.FilePath+import Network.URI (URI (uriScheme), parseURI)+import qualified Data.Set as Set+#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup (Semigroup(..))+#endif++rebaseRelativePathsSpec+  :: forall m bl il . (Monad m , IsInline il , IsBlock il bl)+  => SyntaxSpec m il bl+rebaseRelativePathsSpec =+  defaultSyntaxSpec {+     syntaxBracketedSpecs = [rebasedImageSpec, rebasedLinkSpec] }++ where++  rebasedImageSpec :: BracketedSpec il+  rebasedImageSpec =BracketedSpec+            { bracketedName = "Image"+            , bracketedNests = True+            , bracketedPrefix = Just '!'+            , bracketedSuffixEnd = Just ')'+            , bracketedSuffix = newImageSuffix+            }++  rebasedLinkSpec :: BracketedSpec il+  rebasedLinkSpec = BracketedSpec+           { bracketedName = "Link"+           , bracketedNests = False  -- links don't nest inside links+           , bracketedPrefix = Nothing+           , bracketedSuffixEnd = Just ')'+           , bracketedSuffix = newLinkSuffix+           }++  newImageSuffix rm key = do+    pos <- getPosition+    LinkInfo target title attrs mbpos <- pLink rm key+    let pos' = fromMaybe pos mbpos+    return $! addAttributes attrs . image (rebasePath pos' target) title++  newLinkSuffix rm key = do+    pos <- getPosition+    LinkInfo target title attrs mbpos <- pLink rm key+    let pos' = fromMaybe pos mbpos+    return $! addAttributes attrs . link (rebasePath pos' target) title++-- | Rebase a relative path, by adding the (relative) directory+-- of the containing source position.  Absolute links and URLs+-- are untouched.+rebasePath :: SourcePos -> Text -> Text+rebasePath pos path = do+  let fp = sourceName pos+      isFragment = T.take 1 path == "#"+   in if T.null path || isFragment || isAbsolute (T.unpack path) || isURI path+         then path+         else+           case takeDirectory fp of+             ""  -> path+             "." -> path+             d   -> T.pack d <> "/" <> path++-- | Schemes from http://www.iana.org/assignments/uri-schemes.html plus+-- the unofficial schemes doi, javascript, isbn, pmid.+schemes :: Set.Set T.Text+schemes = Set.fromList+  -- Official IANA schemes+  [ "aaa", "aaas", "about", "acap", "acct", "acr", "adiumxtra", "afp", "afs"+  , "aim", "appdata", "apt", "attachment", "aw", "barion", "beshare", "bitcoin"+  , "blob", "bolo", "browserext", "callto", "cap", "chrome", "chrome-extension"+  , "cid", "coap", "coaps", "com-eventbrite-attendee", "content", "crid", "cvs"+  , "data", "dav", "dict", "dis", "dlna-playcontainer", "dlna-playsingle"+  , "dns", "dntp", "dtn", "dvb", "ed2k", "example", "facetime", "fax", "feed"+  , "feedready", "file", "filesystem", "finger", "fish", "ftp", "geo", "gg"+  , "git", "gizmoproject", "go", "gopher", "graph", "gtalk", "h323", "ham"+  , "hcp", "http", "https", "hxxp", "hxxps", "hydrazone", "iax", "icap", "icon"+  , "im", "imap", "info", "iotdisco", "ipn", "ipp", "ipps", "irc", "irc6"+  , "ircs", "iris", "iris.beep", "iris.lwz", "iris.xpc", "iris.xpcs"+  , "isostore", "itms", "jabber", "jar", "jms", "keyparc", "lastfm", "ldap"+  , "ldaps", "lvlt", "magnet", "mailserver", "mailto", "maps", "market"+  , "message", "mid", "mms", "modem", "mongodb", "moz", "ms-access"+  , "ms-browser-extension", "ms-drive-to", "ms-enrollment", "ms-excel"+  , "ms-gamebarservices", "ms-getoffice", "ms-help", "ms-infopath"+  , "ms-media-stream-id", "ms-officeapp", "ms-project", "ms-powerpoint"+  , "ms-publisher", "ms-search-repair", "ms-secondary-screen-controller"+  , "ms-secondary-screen-setup", "ms-settings", "ms-settings-airplanemode"+  , "ms-settings-bluetooth", "ms-settings-camera", "ms-settings-cellular"+  , "ms-settings-cloudstorage", "ms-settings-connectabledevices"+  , "ms-settings-displays-topology", "ms-settings-emailandaccounts"+  , "ms-settings-language", "ms-settings-location", "ms-settings-lock"+  , "ms-settings-nfctransactions", "ms-settings-notifications"+  , "ms-settings-power", "ms-settings-privacy", "ms-settings-proximity"+  , "ms-settings-screenrotation", "ms-settings-wifi", "ms-settings-workplace"+  , "ms-spd", "ms-sttoverlay", "ms-transit-to", "ms-virtualtouchpad"+  , "ms-visio", "ms-walk-to", "ms-whiteboard", "ms-whiteboard-cmd", "ms-word"+  , "msnim", "msrp", "msrps", "mtqp", "mumble", "mupdate", "mvn", "news", "nfs"+  , "ni", "nih", "nntp", "notes", "ocf", "oid", "onenote", "onenote-cmd"+  , "opaquelocktoken", "pack", "palm", "paparazzi", "pkcs11", "platform", "pop"+  , "pres", "prospero", "proxy", "pwid", "psyc", "qb", "query", "redis"+  , "rediss", "reload", "res", "resource", "rmi", "rsync", "rtmfp", "rtmp"+  , "rtsp", "rtsps", "rtspu", "secondlife", "service", "session", "sftp", "sgn"+  , "shttp", "sieve", "sip", "sips", "skype", "smb", "sms", "smtp", "snews"+  , "snmp", "soap.beep", "soap.beeps", "soldat", "spotify", "ssh", "steam"+  , "stun", "stuns", "submit", "svn", "tag", "teamspeak", "tel", "teliaeid"+  , "telnet", "tftp", "things", "thismessage", "tip", "tn3270", "tool", "turn"+  , "turns", "tv", "udp", "unreal", "urn", "ut2004", "v-event", "vemmi"+  , "ventrilo", "videotex", "vnc", "view-source", "wais", "webcal", "wpid"+  , "ws", "wss", "wtai", "wyciwyg", "xcon", "xcon-userid", "xfire"+  , "xmlrpc.beep", "xmlrpc.beeps", "xmpp", "xri", "ymsgr", "z39.50", "z39.50r"+  , "z39.50s"+  -- Unofficial schemes+  , "doi", "isbn", "javascript", "pmid"+  ]++-- | Check if the string is a valid URL with a IANA or frequently used but+-- unofficial scheme (see @schemes@).+isURI :: T.Text -> Bool+isURI = maybe False hasKnownScheme . parseURI . T.unpack+  where+    hasKnownScheme = (`Set.member` schemes) . T.toLower .+                     T.filter (/= ':') . T.pack . uriScheme
+ src/Commonmark/Extensions/Wikilinks.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+module Commonmark.Extensions.Wikilinks+  ( wikilinksSpec+  , TitlePosition(..)+  , HasWikilinks(..)+  )+where+import Commonmark.Types+import Commonmark.Tokens+import Commonmark.Syntax+import Commonmark.SourceMap+import Commonmark.TokParsers+import Commonmark.Html+import Text.Parsec+#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup hiding (option)+#endif+import Data.Text (Text, strip)++class HasWikilinks il where+  wikilink :: Text -> il -> il++instance Rangeable (Html a) => HasWikilinks (Html a) where+  wikilink url il = link url "wikilink" il++instance (HasWikilinks il, Semigroup il, Monoid il)+        => HasWikilinks (WithSourceMap il) where+  wikilink url il = (wikilink url <$> il) <* addName "wikilink"++-- | Determines whether @[[foo|bar]]@ is a link to page @bar@+-- with title (description) @foo@ ('TitleBeforePipe'), as in+-- GitHub wikis, or a link to page @foo@ with title @bar@+-- ('TitleAfterPipe'), as in Obsidian and Foam.+data TitlePosition = TitleBeforePipe | TitleAfterPipe+  deriving (Show, Eq)++wikilinksSpec :: (Monad m, IsInline il, HasWikilinks il)+              => TitlePosition+              -> SyntaxSpec m il bl+wikilinksSpec titlepos = mempty+  { syntaxInlineParsers = [ pWikilink ]+  }+  where+   pWikilink = do+     symbol '['+     symbol '['+     notFollowedBy (symbol '[')+     toks <- many (satisfyTok (not . hasType (Symbol ']')))+     let isPipe (Tok (Symbol '|') _ _) = True+         isPipe _ = False+     let (title, url) =+           case break isPipe toks of+              (xs, [])   -> (untokenize xs, untokenize xs)+              (xs, _:ys) ->+                case titlepos of+                  TitleBeforePipe -> (untokenize xs, untokenize ys)+                  TitleAfterPipe  -> (untokenize ys, untokenize xs)+     symbol ']'+     symbol ']'+     return $ wikilink (strip url) (str (strip title))
test/attributes.md view
@@ -19,14 +19,14 @@ ```````````````````````````````` example # Heading {#ident .class key="value value" key2=value2} .-<h1 id="ident" class="class" key="value value" key2="value2">Heading</h1>+<h1 id="ident" class="class" data-key="value value" data-key2="value2">Heading</h1> ````````````````````````````````  ```````````````````````````````` example Heading {#ident .class key="value"} ===== .-<h1 id="ident" class="class" key="value">Heading</h1>+<h1 id="ident" class="class" data-key="value">Heading</h1> ````````````````````````````````  Whitespace is tolerated around the delimiters:@@ -34,7 +34,7 @@ ```````````````````````````````` example # Heading {  #ident  .class key="value" } .-<h1 id="ident" class="class" key="value">Heading</h1>+<h1 id="ident" class="class" data-key="value">Heading</h1> ````````````````````````````````  Multiple class attributes are combined:@@ -82,7 +82,7 @@ xyz ``` .-<pre id="ident" class="class" key="value value" key2="value2"><code>xyz+<pre id="ident" class="class" data-key="value value" data-key2="value2"><code>xyz </code></pre> ```````````````````````````````` @@ -127,13 +127,13 @@ ```````````````````````````````` example `hi`{#ident .class key=value} .-<p><code id="ident" class="class" key="value">hi</code></p>+<p><code id="ident" class="class" data-key="value">hi</code></p> ````````````````````````````````  ```````````````````````````````` example `hi` {#ident .class key=value} .-<p><code>hi</code><span id="ident" class="class" key="value"> </span></p>+<p><code>hi</code><span id="ident" class="class" data-key="value"> </span></p> ````````````````````````````````  The attributes can wrap:@@ -142,7 +142,7 @@ `hi`{#ident .class key=value} .-<p><code id="ident" class="class" key="value">hi</code></p>+<p><code id="ident" class="class" data-key="value">hi</code></p> ````````````````````````````````  **Attributes that occur immediately before a block@@ -195,7 +195,7 @@ {.class2 .class3 k=2} # Heading {.class4} .-<h1 class="class1 class2 class3 class4" k="2">Heading</h1>+<h1 class="class1 class2 class3 class4" data-k="2">Heading</h1> ````````````````````````````````  @@ -217,7 +217,7 @@ ```````````````````````````````` example [foo](bar){#ident .class key="value value" key2=value2} .-<p><a id="ident" class="class" key="value value" key2="value2" href="bar">foo</a></p>+<p><a id="ident" class="class" data-key="value value" data-key2="value2" href="bar">foo</a></p> ````````````````````````````````  ```````````````````````````````` example@@ -262,5 +262,5 @@ ```````````````````````````````` example # Heading {key="v&#97;lue" } .-<h1 key="value">Heading</h1>+<h1 data-key="value">Heading</h1> ````````````````````````````````
test/bracketed_spans.md view
@@ -4,7 +4,7 @@ ```````````````````````````````` example [foo]{#ident .class key="value value" key2=value2} .-<p><span id="ident" class="class" key="value value" key2="value2">foo</span></p>+<p><span id="ident" class="class" data-key="value value" data-key2="value2">foo</span></p> ````````````````````````````````  ```````````````````````````````` example
+ test/rebase_relative_paths.md view
@@ -0,0 +1,13 @@+## Rebase relative paths++This extension causes relative paths in images and links to be+rebased to the (relative) directory of the containing file.+For example, if the source file is `foo/test.md` and contains+an image `![image](img.jpg)`, the image path will be rewritten+to `foo/img.jpg`.  Absolute paths, absolute URLs, empty paths,+and paths that are purely fragments (i.e., start with `#`) are+left unchanged.++This feature facilitates converting documents that are split+into multiple files in different directories.+
test/test-commonmark-extensions.hs view
@@ -50,8 +50,10 @@              , ("test/auto_identifiers.md", autoIdentifiersSpec <> attributesSpec)              , ("test/implicit_heading_references.md",                  autoIdentifiersSpec <> attributesSpec <> implicitHeadingReferencesSpec)+             , ("test/wikilinks_title_before_pipe.md", wikilinksSpec TitleBeforePipe)+             , ("test/wikilinks_title_after_pipe.md", wikilinksSpec TitleAfterPipe)              ]-  defaultMain $ testGroup "Tests" tests+  defaultMain $ testGroup "Tests" (tests ++ [rebaseRelativePathTests])  getSpecTestTree :: FilePath                 -> SyntaxSpec Identity (Html ()) (Html ())@@ -144,4 +146,29 @@   when ("#" `T.isPrefixOf` t) $ updateState $ \(_secname, exampnum) ->            (T.strip $ T.dropWhile (=='#') t, exampnum) ----+rebaseRelativePathTests :: TestTree+rebaseRelativePathTests = do+  let parser = runIdentity . parseCommonmarkWith+                   (rebaseRelativePathsSpec <> defaultSyntaxSpec)+  let md = T.unlines+            [ "![image](foo.jpg)"+            , "[link](http://example.com/foo.jpg)"+            , "![image]()"+            , "[link](#foobar)"+            , "![image][ref]"+            , ""+            ]+  let mdref = "[ref]: baz.png"+  let toks = tokenize "chap1/text.md" md ++ tokenize "extra/refs.md" mdref+  let actual = normalizeHtml .  TL.toStrict . renderHtml .+                  fromRight mempty $ (parser toks+                       :: Either ParseError (Html ()))+  let expected = T.unlines+                 [ "<p><img src=\"chap1/foo.jpg\" alt=\"image\" />"+                 , "<a href=\"http://example.com/foo.jpg\">link</a>"+                 , "<img src=\"\" alt=\"image\" />"+                 , "<a href=\"#foobar\">link</a>"+                 , "<img src=\"extra/baz.png\" alt=\"image\" /></p>"+                 ]+  testCase "rebase_relative_paths" (actual @?= expected)+
@@ -0,0 +1,33 @@+Wikilinks can have one of the following forms:++    [[https://example.org]]+    [[https://example.org|title]]+    [[name of page]]+    [[name of page|title]]++With this version of wikilinks, the title comes after the pipe.++```````````````````````````````` example+[[https://example.org]]+.+<p><a href="https://example.org" title="wikilink">https://example.org</a></p>+````````````````````````````````++```````````````````````````````` example+[[https://example.org|title]]+.+<p><a href="https://example.org" title="wikilink">title</a></p>+````````````````````````````````++```````````````````````````````` example+[[Name of page]]+.+<p><a href="Name%20of%20page" title="wikilink">Name of page</a></p>+````````````````````````````````++```````````````````````````````` example+[[Name of page|Title]]+.+<p><a href="Name%20of%20page" title="wikilink">Title</a></p>+````````````````````````````````+
@@ -0,0 +1,33 @@+Wikilinks can have one of the following forms:++    [[https://example.org]]+    [[title|https://example.org]]+    [[name of page]]+    [[title|name of page]]++With this version of wikilinks, the title comes before the pipe.++```````````````````````````````` example+[[https://example.org]]+.+<p><a href="https://example.org" title="wikilink">https://example.org</a></p>+````````````````````````````````++```````````````````````````````` example+[[title|https://example.org]]+.+<p><a href="https://example.org" title="wikilink">title</a></p>+````````````````````````````````++```````````````````````````````` example+[[Name of page]]+.+<p><a href="Name%20of%20page" title="wikilink">Name of page</a></p>+````````````````````````````````++```````````````````````````````` example+[[Title|Name of page]]+.+<p><a href="Name%20of%20page" title="wikilink">Title</a></p>+````````````````````````````````+