haskell / haddock

Haskell Documentation Tool
www.haskell.org/haddock/
BSD 2-Clause "Simplified" License
361 stars 241 forks source link

Output of an example is interpreted as a named chunk #1057

Open aztek opened 5 years ago

aztek commented 5 years ago

I would like to show an example of a function that prints a string that starts with the dollar sign.

-- | Foo
--
-- >>> foo
-- $foo
foo :: IO ()
foo = putStrLn "$foo"

Haddock (2.22.0) interprets $foo in the comment as the name of a chunk and removes the entire example from the documentation. Escaping the $ with the backslash does not help - the backslash remains in the documentation like this.

>>> foo
\$foo

And it also fails the doctest.

Is there a way to convince Haddock that $foo is not a named chunk? If not, I think Haddock should parse examples and their output before it parses named chunks.

harpocrates commented 5 years ago

Haddock uses GHC to do the heavy lifting of parsing docstrings and code. In your case, take

$ cat Foo.hs
module Foo where

-- | Foo
--
-- >>> foo
-- $foo
foo :: IO ()
foo = putStrLn "$foo"
$ ghc-8.6.3 -haddock -ddump-parsed-ast -fforce-recomp Foo.hs
[1 of 1] Compiling Foo              ( Foo.hs, Foo.o )

==================== Parser AST ====================

({ Foo.hs:1:1 }
 (HsModule
  (Just
   ({ Foo.hs:1:8-10 }
    {ModuleName: Foo}))
  (Nothing)
  []
  [({ Foo.hs:(3,1)-(5,10) }
    (DocD
     (NoExt)
     (DocCommentNext
      (HsDocString
       " Foo\n\n >>> foo"))))
  ,({ Foo.hs:6:1-7 }
    (DocD
     (NoExt)
     (DocCommentNamed
      "foo"
      (HsDocString
       ""))))
  ,({ Foo.hs:7:1-12 }
    (SigD
     (NoExt)
     (TypeSig
      (NoExt)
      [({ Foo.hs:7:1-3 }
        (Unqual
         {OccName: foo}))]
      (HsWC
       (NoExt)
       (HsIB
        (NoExt)
        ({ Foo.hs:7:8-12 }
         (HsAppTy
          (NoExt)    
        ....

Notice how GHC is responsible for producing two DocD's! This is perhaps something to fix upstream. In the meantime, a semi-workaround is to add an extra space:

-- | Foo
--
-- >>> foo
--  $foo
foo :: IO ()
foo = putStrLn "$foo"

I'm not sure what doctest will make of that though...

aztek commented 5 years ago

I see. I will report the issue to GHC.

The extra space character makes doctest fail too, unfortunately.

For now I ended up using the following.

-- > >>> foo
-- > $foo

It looks close enough to an actual example and does not trigger doctest.