packages feed

BlogLiterately 0.8.1.6 → 0.8.2

raw patch · 5 files changed

+230/−11 lines, 5 filesdep +HTTPdep +tagsoupdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: HTTP, tagsoup

Dependency ranges changed: base

API changes (from Hackage documentation)

+ Text.BlogLiterately.Post: findTitle :: Int -> String -> String -> String -> String -> IO (Maybe String)
+ Text.BlogLiterately.Post: getPostURL :: String -> String -> String -> String -> IO (Maybe String)
+ Text.BlogLiterately.Transform: luckyLink :: SpecialLink
+ Text.BlogLiterately.Transform: mkSpecialLinksXF :: [SpecialLink] -> Transform
+ Text.BlogLiterately.Transform: postLink :: SpecialLink
+ Text.BlogLiterately.Transform: specialLinksXF :: Transform
+ Text.BlogLiterately.Transform: standardSpecialLinks :: [SpecialLink]
+ Text.BlogLiterately.Transform: wikiLink :: SpecialLink

Files

BlogLiterately.cabal view
@@ -1,5 +1,5 @@ Name:           BlogLiterately-Version:        0.8.1.6+Version:        0.8.2 Synopsis:       A tool for posting Haskelly articles to blogs Description:    Write blog posts in Markdown format, then use BlogLiterately                 to do syntax highlighting, format ghci sessions, and upload@@ -26,7 +26,7 @@ Maintainer:     Brent Yorgey <byorgey@cis.upenn.edu> Stability:      experimental Build-Type:     Simple-Tested-With:    GHC ==7.6.3, GHC ==7.8.4, GHC ==7.10.1+Tested-With:    GHC ==7.6.3, GHC ==7.8.4, GHC ==7.10.3, GHC ==8.0.1 Extra-Source-Files: CHANGES.md                     README.markdown                     doc/BlogLiteratelyDoc.lhs@@ -39,7 +39,7 @@   location: git://github.com/byorgey/BlogLiterately.git  Library-  Build-Depends:   base >= 4.0 && < 4.9,+  Build-Depends:   base >= 4.0 && < 4.10,                    process,                    filepath,                    directory,@@ -62,7 +62,9 @@                    pandoc-citeproc >= 0.1.2 && < 0.10,                    highlighting-kate >= 0.5 && < 0.7,                    data-default >= 0.5 && < 0.6,-                   lens >= 3.8 && < 4.14+                   lens >= 3.8 && < 4.14,+                   tagsoup >= 0.13.4 && < 0.14,+                   HTTP >= 4000.3 && < 4000.4   Exposed-modules: Text.BlogLiterately                    Text.BlogLiterately.Block                    Text.BlogLiterately.Ghci
CHANGES.md view
@@ -1,3 +1,11 @@+0.8.2 (25 March 2016)+---------------------++  * New feature: support various types of "special links" which are+    automatically replaced with appropriate URLs.  Initial support for+    wikipedia links, Google "feeling lucky" search, and links to other+    posts on the same blog specified by ID or search term.+ 0.8.1.6 (22 March 2016) ----------------------- 
doc/BlogLiteratelyDoc.lhs view
@@ -224,6 +224,52 @@ Note that an extra `$latex...` won't be added to the beginning of LaTeX expressions which already appear to be in WordPress format. +Special links+-------------++Certain special link types can be replaced with appropriate URLs.  A+special link is one where the URL is of the form `<name>::<text>`+where `<name>` is used to identify the special link type, and `<text>`+is passed as a parameter to a function which can use it to generate a+URL. Currently, four types of special links are supported by default+(and you can easily add your own):++`lucky::<search>`++:   The first Google result for `<search>`.++`wiki::<title>`++:   The Wikipedia page for `<title>`.  (Note that the page is not+    checked for existence.)++`post::nnnn`++:   Link to the blog post on your blog with post ID `nnnn`.  Note that+    this form of special link is invoked when `nnnn` consists of all+    digits, so it only works on blogs which use numerical identifiers for+    post IDs (as Wordpress does).++`post::<search>`++:   Link to the most recent blog post (among the+    20 most recent posts) containing `<search>` in its title.++For example, a post written in Markdown format containing++```+    This is a post about the game of [Go](wiki::Go (game)).+```++will be formatted in HTML as++```+    <p>This is a post about the game of <a href="https://en.wikipedia.org/wiki/Go%20(game)">Go</a>.</p>+```++You can easily add your own new types of special links.  See the+`SpecialLink` type and the `mkSpecialLinksXF` function.+ Table of contents ----------------- 
src/Text/BlogLiterately/Post.hs view
@@ -9,17 +9,20 @@ -- License     :  GPL (see LICENSE) -- Maintainer  :  Brent Yorgey <byorgey@gmail.com> ----- Uploading posts to the server.+-- Uploading posts to the server and fetching posts from the server. -- -----------------------------------------------------------------------------  module Text.BlogLiterately.Post     (-      mkPost, mkArray, postIt+      mkPost, mkArray, postIt, getPostURL, findTitle     ) where  import           Control.Lens                (at, makePrisms, to, traverse,-                                              (^.), (^?))+                                              (^.), (^..), (^?), _Just, _head)+import           Data.Char                   (toLower)+import           Data.Function               (on)+import           Data.List                   (isInfixOf) import qualified Data.Map                    as M  import           Network.XmlRpc.Client       (remote)@@ -104,6 +107,17 @@ getPostURL url pid usr pwd = do   v <- remote url "metaWeblog.getPost" pid usr pwd   return (v ^? _ValueStruct . to M.fromList . at "link" . traverse . _ValueString)++-- | Look at the last n posts and find the most recent whose title+--   contains the search term (case insensitive); return its permalink+--   URL.+findTitle :: Int -> String -> String -> String -> String -> IO (Maybe String)+findTitle numPrev url search usr pwd = do+  res <- remote url "metaWeblog.getRecentPosts" (0::Int) usr pwd numPrev+  let matches s = (isInfixOf `on` map toLower) search s+      posts  = res ^.. _ValueArray . traverse . _ValueStruct . to M.fromList+      posts' = filter (\p -> maybe False matches (p ^? at "title" . _Just . _ValueString)) posts+  return (posts' ^? _head . at "link" . _Just . _ValueString)  -- | Given a configuration and a formatted post, upload it to the server. postIt :: BlogLiterately -> String -> IO ()
src/Text/BlogLiterately/Transform.hs view
@@ -1,6 +1,6 @@+ {-# LANGUAGE FlexibleContexts  #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards   #-} {-# LANGUAGE TypeOperators     #-} @@ -35,6 +35,14 @@     , centerImagesXF     , citationsXF +      -- * Link generation+    , specialLinksXF+    , mkSpecialLinksXF+    , standardSpecialLinks+    , luckyLink+    , wikiLink+    , postLink+       -- * Transforms     , Transform(..), pureTransform, ioTransform, runTransform, runTransforms @@ -51,12 +59,18 @@                                                     (.=), (.~), (^.), _1, _2,                                                     _Just) import           Control.Monad.State-import           Data.List                         (intercalate, isPrefixOf)+import           Data.Char                         (isDigit, toLower)+import           Data.List                         (intercalate, isInfixOf,+                                                    isPrefixOf)+import           Data.List.Split                   (splitOn) import qualified Data.Map                          as M+import           Data.Maybe                        (fromMaybe) import           Data.Monoid                       (mappend) import           Data.Monoid                       (mempty, (<>)) import qualified Data.Set                          as S import           Data.Traversable                  (traverse)+import           Network.HTTP                      (getRequest, getResponseBody,+                                                    simpleHTTP) import           System.Directory                  (doesFileExist,                                                     getAppUserDataDirectory) import           System.Exit                       (exitFailure)@@ -64,6 +78,7 @@ import           System.IO                         (hFlush, stdout) import           Text.Blaze.Html.Renderer.String   (renderHtml) import           Text.CSL.Pandoc                   (processCites')+import           Text.HTML.TagSoup import           Text.Pandoc import           Text.Pandoc.Error                 (PandocError) import           Text.Parsec                       (ParseError)@@ -78,6 +93,7 @@ import           Text.BlogLiterately.LaTeX         (wpTeXify) import           Text.BlogLiterately.Options import           Text.BlogLiterately.Options.Parse (readBLOptions)+import           Text.BlogLiterately.Post          (findTitle, getPostURL)  -- | A document transformation consists of two parts: an actual --   transformation, expressed as a function over Pandoc documents, and@@ -177,12 +193,142 @@   where     centerImage :: [Block] -> [Block]     centerImage (img@(Para [Image _attr _altText (_imgUrl, _imgTitle)]) : bs) =-        RawBlock "html" "<div style=\"text-align: center;\">"+        RawBlock (Format "html") "<div style=\"text-align: center;\">"       : img-      : RawBlock "html" "</div>"+      : RawBlock (Format "html") "</div>"       : bs     centerImage bs = bs +-- | Replace special links with appropriate URLs.  Currently, four+--   types of special links are supported:+--+--   [@lucky::<search>@] The first Google result for @<search>@.+--+--   [@wiki::<title>@] The Wikipedia page for @<title>@.  Note that+--   the page is not checked for existence.+--+--   [@post::nnnn@] Link to the blog post with post ID @nnnn@.  Note+--   that this form of special link is invoked when @nnnn@ consists of+--   all digits, so it only works on blogs which use numerical+--   identifiers for post IDs (as Wordpress does).+--+--   [@post::<search>@] Link to the most recent blog post (among the+--   20 most recent posts) containing @<search>@ in its title.+--+--   For example, a post written in Markdown format containing+--+--   @+--       This is a post about the game of [Go](wiki::Go (game)).+--   @+--+--   will be formatted in HTML as+--+--   @+--       <p>This is a post about the game of <a href="https://en.wikipedia.org/wiki/Go%20(game)">Go</a>.</p>+--   @+--+--   You can also create a Transform with your own special link types,+--   using 'mkSpecialLinksXF', and I am happy to receive pull requests+--   adding new types of standard special links.+specialLinksXF :: Transform+specialLinksXF = mkSpecialLinksXF standardSpecialLinks++-- | The standard special link types included in 'specialLinksXF':+--   'luckyLink', 'wikiLink', and 'postLink'.+standardSpecialLinks :: [SpecialLink]+standardSpecialLinks = [luckyLink, wikiLink, postLink]++-- | A special link consists of two parts:+--+--   * An identifier string.  If the identifier string is @<id>@, this+--   will trigger for links which are of the form @<id>::XXXX@.+--+--   * A URL generation function.  It takes as input the string+--   following the @::@ (the @XXXX@ in the example above), the+--   configuration record, and must output a URL.+--+--   For example,+--+--   @("twitter", \u _ -> return $ "https://twitter.com/" ++ u)@+--+--   is a simple 'SpecialLink' which causes links of the form+--   @twitter::user@ to be replaced by @https://twitter.com/user@.+type SpecialLink = (String, String -> BlogLiterately -> IO String)++-- | Create a transformation which looks for the given special links+--   and replaces them appropriately. You can use this function with+--   your own types of special links.+mkSpecialLinksXF :: [SpecialLink] -> Transform+mkSpecialLinksXF links = ioTransform (specialLinks links) (const True)++-- | Create a document transformation which looks for the given+--   special links and replaces them appropriately.+specialLinks :: [SpecialLink] -> BlogLiterately -> Pandoc -> IO Pandoc+specialLinks links bl = bottomUpM specialLink+  where+    specialLink :: Inline -> IO Inline+    specialLink i@(Link attrs alt (url, title))+      | Just (typ, target) <- getSpecial url+      = mkLink <$> case lookup (map toLower typ) links of+                     Just mkURL -> mkURL target bl+                     Nothing    -> return target+      where+        mkLink u = Link attrs alt (u, title)++    specialLink i = return i++    getSpecial url+      | "::" `isInfixOf` url =+          let (typ:rest) = splitOn "::" url+          in  Just (typ, intercalate "::" rest)+      | otherwise = Nothing++-- | Turn @lucky::<search>@ into a link to the first Google result for+-- @<search>@.+luckyLink :: SpecialLink+luckyLink = ("lucky", getLucky)+  where+    getLucky searchTerm _ = do+      results <- openURL $ "http://www.google.com/search?q=" ++ searchTerm+      let tags   = parseTags results+          anchor = take 1 . dropWhile (~/= "<a>") . dropWhile (~/= "<h3 class='r'>") $ tags+          url = case anchor of+            [t@(TagOpen{})] -> takeWhile (/='&') . dropWhile (/='h') . fromAttrib "href" $ t+            _ -> searchTerm+      return url++-- | Get the contents of the given URL in a simple way.+openURL :: String -> IO String+openURL x = getResponseBody =<< simpleHTTP (getRequest x)++-- | Given @wiki::<title>@, generate a link to the Wikipedia page for+--   @<title>@.  Note that the page is not checked for existence.+wikiLink :: SpecialLink+wikiLink = ("wiki", \target _ -> return $ "https://en.wikipedia.org/wiki/" ++ target)++-- | @postLink@ handles two types of special links.+--+-- [@post::nnnn@] Link to the blog post with post ID @nnnn@.  Note that+-- this form of special link is invoked when @nnnn@ consists of all+-- digits, so it only works on blogs which use numerical identifiers+-- for post IDs (as Wordpress does).+--+-- [@post::<search>@] Link to the most recent blog post (among the+-- 20 most recent posts) containing @<search>@ in its title.+postLink :: SpecialLink+postLink = ("post", getPostLink)+  where+    getPostLink target bl =+      fromMaybe target <$>+        case (all isDigit target, bl ^. blog) of+          (_    , Nothing ) -> return Nothing+          (True , Just url) -> getPostURL url target (user' bl) (password' bl)+          (False, Just url) -> findTitle 20 url target (user' bl) (password' bl)++          -- If all digits, replace with permalink for that postid+          -- Otherwise, search titles of 20 most recent posts.+          --   Choose most recent that matches.+ -- | Potentially extract a title from the metadata block, and set it --   in the options record. titleXF :: Transform@@ -295,6 +441,8 @@ -- --   * 'centerImagesXF': center images occurring in their own paragraph --+--   * 'specialLinksXF': replace special link types with URLs+-- --   * 'highlightOptsXF': load the requested highlighting style file -- --   * 'highlightXF': perform syntax highlighting@@ -318,6 +466,7 @@   , ghciXF   , uploadImagesXF   , centerImagesXF+  , specialLinksXF   , highlightOptsXF   , highlightXF   , citationsXF