packages feed

qm-interpolated-string (empty) → 0.1.0.0

raw patch · 6 files changed

+320/−0 lines, 6 filesdep +basedep +bytestringdep +haskell-src-metasetup-changed

Dependencies added: base, bytestring, haskell-src-meta, hspec, qm-interpolated-string, template-haskell, text

Files

+ LICENSE view
@@ -0,0 +1,24 @@+This is free and unencumbered software released into the public domain.++Anyone is free to copy, modify, publish, use, compile, sell, or+distribute this software, either in source code form or as a compiled+binary, for any purpose, commercial or non-commercial, and by any+means.++In jurisdictions that recognize copyright laws, the author or authors+of this software dedicate any and all copyright interest in the+software to the public domain. We make this dedication for the benefit+of the public at large and to the detriment of our heirs and+successors. We intend this dedication to be an overt act of+relinquishment in perpetuity of all present and future rights to this+software under copyright law.++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 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.++For more information, please refer to <http://unlicense.org>
+ README.md view
@@ -0,0 +1,72 @@+# [qm|interpolated-string|]++[![Hackage](https://img.shields.io/hackage/v/qm-interpolated-string.svg)](https://hackage.haskell.org/package/qm-interpolated-string)+[![Build Status](https://travis-ci.org/unclechu/haskell-qm-interpolated-string.svg?branch=master)](https://travis-ci.org/unclechu/haskell-qm-interpolated-string)++Implementation of interpolated multiline strings that ignores indentation+and trailing whitespaces.++It's [QuasiQuoter](https://wiki.haskell.org/Quasiquotation).++Actually it's modification of+[interpolatedstring-perl6](https://github.com/audreyt/interpolatedstring-perl6)+package. I used it to implemenent my own strings I really like.++This implementation looks just like `qc`+from **interpolatedstring-perl6** package but ignores any indentation,+line-breaks (except explicitly written using `\n` char)+and trailing whitespaces.++'m' in 'qm' means 'multiline'.++You could write a decoratively formatted string and your+decorative indentation and line-breaks wont go to the string,+but when you really need it, you could just escape it using backslash.++## Simple usage example++```haskell+{-# LANGUAGE QuasiQuotes #-}++import Text.InterpolatedString.QM (qm)++main :: IO ()+main = putStrLn [qm| hello+                   \ world |]+```++## More examples++```haskell+[qm|   hello world,+     \ what's going on here?  |]+-- Result: "hello world, what's going on here?"+```++```haskell+[qm|+      it's actual+      ly ignored+   |]+-- Result: "it's actually ignored"+```++```haskell+[qm|  \  You could explicitly escape indentation or\n+         line-breaks when you really need it!  \+   |]+-- Result: "  You could explicitly escape indentation or\nline-breaks when you really need it!  "+```++```haskell+[qm| {1+2} \{3+4} |]+-- Result: "3 {3+4}"+```++## Author++[Viacheslav Lotsmanov](https://github.com/unclechu)++## License++[The Unlicense](./LICENSE)
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ qm-interpolated-string.cabal view
@@ -0,0 +1,43 @@+name:               qm-interpolated-string+version:            0.1.0.0+synopsis:           Implementation of interpolated multiline strings+description:        Implementation of interpolated multiline strings+                    that ignores indentation and trailing whitespaces+homepage:           https://github.com/unclechu/haskell-qm-interpolated-string+license:            PublicDomain+license-file:       LICENSE+author:             Viacheslav Lotsmanov+copyright:          Viacheslav Lotsmanov+maintainer:         Viacheslav Lotsmanov <lotsmanov89@gmail.com>+category:           Data+build-type:         Simple+extra-source-files: README.md+cabal-version:      >=1.8+tested-with:        GHC == 7.6.3+                  , GHC == 7.8.4+                  , GHC == 7.10.1+                  , GHC == 7.10.2+                  , GHC == 8.0.2++source-repository head+  type:     git+  location: git://github.com/unclechu/haskell-qm-interpolated-string.git++library+  ghc-options:      -Wall+  hs-source-dirs:   src+  exposed-modules:  Text.InterpolatedString.QM+  build-depends:    base ==4.*+                  , template-haskell >=2.5 && <3+                  , haskell-src-meta >=0.3 && <0.8+                  , bytestring ==0.10.*+                  , text ==1.*++test-suite tests+  type:            exitcode-stdio-1.0+  ghc-options:     -Wall -fno-warn-type-defaults+  hs-source-dirs:  test+  main-is:         Spec.hs+  build-depends:   base ==4.*+                 , hspec ==2.*+                 , qm-interpolated-string
+ src/Text/InterpolatedString/QM.hs view
@@ -0,0 +1,138 @@+-- Fork of: https://github.com/audreyt/interpolatedstring-perl6/blob/63d91a83eb5e48740c87570a8c7fd4668afe6832/src/Text/InterpolatedString/Perl6.hs+-- Author of the 'interpolatedstring-perl6' package: Audrey Tang++{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE IncoherentInstances #-}++{-# LANGUAGE PackageImports #-}+{-# LANGUAGE ViewPatterns #-}++{-# LANGUAGE CPP #-}++module Text.InterpolatedString.QM (qm, ShowQ(..)) where++import "base" GHC.Exts (IsString(..))+import qualified "template-haskell" Language.Haskell.TH as TH+import "template-haskell" Language.Haskell.TH.Quote+import "haskell-src-meta" Language.Haskell.Meta.Parse+import "bytestring" Data.ByteString.Char8 as Strict (ByteString, unpack)+import "bytestring" Data.ByteString.Lazy.Char8 as Lazy (ByteString, unpack)+import "text" Data.Text as T (Text, unpack)+import "text" Data.Text.Lazy as LazyT (Text, unpack)++#if MIN_VERSION_base(4,8,0)+#else+import "base" Data.Monoid (mempty, mappend)+#endif+++class ShowQ a where+  showQ :: a -> String++instance ShowQ Char where+  showQ = (:[])++instance ShowQ String where+  showQ = id++instance ShowQ Strict.ByteString where+  showQ = Strict.unpack++instance ShowQ Lazy.ByteString where+  showQ = Lazy.unpack++instance ShowQ T.Text where+  showQ = T.unpack++instance ShowQ LazyT.Text where+  showQ = LazyT.unpack++instance Show a => ShowQ a where+  showQ = show++class QQ a string where+  toQQ :: a -> string++instance IsString s => QQ s s where+  toQQ = id++instance (ShowQ a, IsString s) => QQ a s where+  toQQ = fromString . showQ++data StringPart = Literal String | AntiQuote String deriving Show+++unQM :: String -> String -> [StringPart]+unQM a []          = [Literal (reverse a)]+unQM a ('\\':x:xs) = unQM (x:a) xs+unQM a ("\\")      = unQM ('\\':a) []+unQM a ('}':xs)    = AntiQuote (reverse a) : parseQM [] xs+unQM a (x:xs)      = unQM (x:a) xs++parseQM :: String -> String -> [StringPart]+parseQM a []             = [Literal (reverse a)]+parseQM a ('\\':'\\':xs) = parseQM ('\\':a) xs+parseQM a ('\\':'{':xs)  = parseQM ('{':a) xs+parseQM a ('\\':' ':xs)  = parseQM (' ':a) xs+parseQM a ('\\':'\n':xs) = parseQM a ('\n':xs)+parseQM a ('\\':'n':xs)  = parseQM ('\n':a) xs+parseQM a ("\\")         = parseQM ('\\':a) []+parseQM a ('{':xs)       = Literal (reverse a) : unQM [] xs+parseQM a (clearIndentAtSOF   -> Just clean) = parseQM a clean+parseQM a (clearIndentTillEOF -> Just clean) = parseQM a clean+parseQM a ('\n':xs)      = parseQM a xs -- cut off line breaks+parseQM a (x:xs)         = parseQM (x:a) xs++clearIndentTillEOF :: String -> Maybe String+clearIndentTillEOF str@((ifMaybe (`elem` "\t ") -> Just _) : _) = cutOff str+  where cutOff :: String -> Maybe String+        cutOff ""            = Just ""+        cutOff eof@('\n':_) = Just eof+        cutOff ((ifMaybe (`elem` "\t ") -> Just _) : xs) = cutOff xs+        cutOff _ = Nothing+clearIndentTillEOF _ = Nothing++clearIndentAtSOF :: String -> Maybe String+clearIndentAtSOF ('\n' : xs) = if result /= xs+                                  then Just $ '\n' : cutOff xs+                                  else Nothing+  where cutOff :: String -> String+        cutOff ((ifMaybe (`elem` "\t ") -> Just _) : ys) = cutOff ys+        cutOff s = s+        result = cutOff xs+clearIndentAtSOF _ = Nothing++clearIndentAtStart :: String -> String+clearIndentAtStart ((ifMaybe (`elem` "\t ") -> Just _) : xs) =+  clearIndentAtStart xs+clearIndentAtStart s = s+++makeExpr :: [StringPart] -> TH.ExpQ+makeExpr [] = [| mempty |]+makeExpr (Literal a : xs) =+  TH.appE [| mappend (fromString a) |]    $ makeExpr xs+makeExpr (AntiQuote a : xs) =+  TH.appE [| mappend (toQQ $(reify a)) |] $ makeExpr xs++reify :: String -> TH.Q TH.Exp+reify s =+  case parseExp s of+       Left  e -> TH.reportError e >> [| mempty |]+       Right e -> return e+++qm :: QuasiQuoter+qm = QuasiQuoter f+  (error "Cannot use qm as a pattern")+  (error "Cannot use qm as a type")+  (error "Cannot use qm as a dec")+  where f = makeExpr . parseQM [] . clearIndentAtStart . filter (/= '\r')+++ifMaybe :: (a -> Bool) -> a -> Maybe a+ifMaybe f x = if f x then Just x else Nothing
+ test/Spec.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE QuasiQuotes #-}++module Main (main) where++import "hspec" Test.Hspec (hspec, describe, it, shouldBe)+import "qm-interpolated-string" Text.InterpolatedString.QM (qm)+++main :: IO ()+main = hspec $ do++  describe "Examples from README" $ do++    it "First (decorative spacing and escaping space symbol)" $+      [qm|   hello world,+           \ what's going on here?  |]+        `shouldBe` "hello world, what's going on here?"++    it "Second (merging lines without spaces)" $+      [qm|+            it's actual+            ly ignored+         |]+            `shouldBe` "it's actually ignored"++    it "Third (explicit line-breaks symbols)" $+      [qm|  \  You could explicitly escape indentation or\n+               line-breaks when you really need it!  \+         |] `shouldBe` "  You could explicitly escape indentation or\n\+                       \line-breaks when you really need it!  "++    it "Fourth (escaping interpolation blocks to show them as text)" $+      [qm| {1+2} \{3+4} |] `shouldBe` "3 {3+4}"++  it "Type annotation in interpolation block" $+    [qm|{10 :: Float}|] `shouldBe` "10.0"++  it "Escaping interpolation symbols inside interpolation block" $ do+    [qm|foo {"b{a{r"} baz|] `shouldBe` "foo b{a{r baz"+    [qm|foo {"b\}a\}r"} baz|] `shouldBe` "foo b}a}r baz"