haskellyesodshakespeare-text

Ignoring leading whitespace in the "lazy-text" quasiquoter in Haskell Text.Shakespeare.Text


I am writing a Haskell command line program and using the lt quasiquoter ("lazy-text") from Text.Shakespeare.Text. In the Yesod book, it says that the hamlet quasiquoter ignores leading whitespace if the first non-whitespace character is a backslash (\).

Does this work in the lt quasiquoter?

My code looks like this:

[lt|Usage: #{programName} [OPTION ...]
   \Version #{showVersion version}|]

but the output is

Usage: MyProg [OPTION ...]
    \Version 0.1.0.0

with the Version string indented too far (and still containing the backslash). I also tried it with a space between the backslash and V.

Is this possible with shakespeare-text?


Solution

  • It doesn't appear to, however it isn't hard to add the feature yourself. lt is just a QuasiQuoter, which is the data type:

    QuasiQuoter {
       quoteExp :: String -> Q Exp
     , quotePat :: String -> Q Pat
     , quoteType :: String -> Q Type
     , quoteDec :: String -> Q [Dec]
    }
    

    They take a String, and return the appropriate template haskell type (depending on the context it is used in.

    It is a simple matter to transform a string so it works as you described with a regex:

    stripWhiteSpaceBeforeBackslash :: String -> String
    stripWhiteSpaceBeforeBackslash str = subRegex (mkRegex "^[[:space:]]*\\\\") str ""
    

    Also, a function that transforms a QuasiQuoter with a string transform function is simple:

    transformQuasiQuoter :: (String -> String) -> QuasiQuoter -> QuasiQuoter
    transformQuasiQuoter transform quasi = QuasiQuoter {
        quoteExp = (quoteExp quasi) . transform
      , quotePat = (quotePat quasi) . transform
      , quoteType = (quoteType quasi) . transform
      , quoteDec =  (quoteDec quasi) . transform
      }
    

    Now you can make a version of lt that does what you need:

    lt_ = transformQuasiQuoter stripWhiteSpaceBeforeBackslash lt
    

    Using it works as expected:

    programName = "SomeProgram"
    showVersion _ = "42.42.42"
    version = 34
    
    x = [lt_|Usage: #{programName} [OPTIONS...]
            \Version #{showVersion version}|]
    

    x evaluates to "Usage: SomeProgram [OPTIONS...]\nVersion 42.42.42" in ghci.