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 +24/−0
- README.md +72/−0
- Setup.hs +2/−0
- qm-interpolated-string.cabal +43/−0
- src/Text/InterpolatedString/QM.hs +138/−0
- test/Spec.hs +41/−0
+ 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|]++[](https://hackage.haskell.org/package/qm-interpolated-string)+[](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"