Download as pdf
Download as pdf
You are on page 1of 46

public domain image from NOAA's Historic Fisheries Collection

Mark Lentczner
Haddock Revamp Haskell Implementors
Workshop - 2010
Why Bother?

photo curtesy of Cornell University Library


Utility

Pages are difficult to navigate

Information density is low

Page area is poorly utilized

Typography is far from lovely


Aesthetic

We’d like a more modern look

Baseline browsers are better today

Keep up with the Joneses


The Competition
Haskell
… with Haddock Revamp
Semantic Markup

Much easier to re-style with just CSS

Possible to parse

Usable in wider variety of browsing situations


A Hypothesis

If generated documentation is more


appealing to read…

…then more developers will write it.


Refactoring

public domain photo, NASA


The original HTML backend call graph
ppHtml copyHtmlBits dcolon empty emptyTable hsep isRecCon parenList parens quote spacedTable5 tda tupleParens ubxParenList ubxparens vanillaTable

<+> braces brackets char collapsed comma vanillaTable2 keyword

ppHtmlHelpFiles ppHtmlContents ppHtmlModule copyFile

ppHtmlIndex ppHtmlContentsFrame footer ppHtmlModuleMiniSynopsis ifaceToHtml

simpleHeader flatModuleTree styleSheet documentCharacterEncoding renderToString pageHeader miniSynopsis processExport

srcButton contentsButton indexButton wikiButton moduleInfo numberSectionHeadings groupTag ppDecl'

linkId ppModuleTree ppDecl

ppClassDecl ppFor ppDataInst

methHdr ppShortClassDecl s8 abovesSep atHdr

lookupAnySubdoc ppAssocType ppFunSig

ppTyFam ppTySyn ppDataDecl

ppTyInst collapseId instHdr ppTypeOrFunSig ppDocInstance ppSideBySideConstr spacedTable1 constrHdr

ppPrologue ppTyInstHeader bodyBox declWithDoc ndocBox ppInstHead ppLFunLhType ppLContextNoArrow ppShortDataDecl ppSideBySideField

mkNode processForMiniSynopsis docBox ppAppNameTypes topDeclBox equals argBox maybeRDocBox ppDataHeader ppModuleContents

spliceURL rdrDocToHtml origDocToHtml <++> collapsebutton ppTyFamHeader docToHtml ppParendType declBox ppFunLhType rdocBox

htmlRdrMarkup htmlCleanup htmlOrigMarkup onclick htmlMarkup ppr_mono_ty ppClassHdr ppTyClBinderWithVars ppShortConstr

unParagraph parHtmlMarkup ppTyClBinderWithVarsMini ppKind pREC_CON pREC_OP pabrackets ppBang ppr_fun_ty ppTypeSig ppFds ppAppDocNameNames ppForAll ppShortField ppConstrHdr
ppLParendType

ppModule markupDef ppNameMini ppTypeApp maybeParen ppr_mono_lty pREC_FUN arrow punctuate ppContextNoArrow dot ppTyVars ppBinder ppLContext forallSymbol

ppBinder' ppTyName tyvarNames linkTarget ppContext linkedAnchor

namedAnchor ppName ppContextNoLocs

ppLDocName pp_hs_context darrow

ppRdrName ppPred

ppDocName ppLType

linkIdOcc ppOccName ppType

pREC_TOP

The original HTML backend call graph - thinned and hand laid out
Approach

Split into “logical” files


Layout
DocMarkup
Names
Decls

Narrow imports

Refactor out common functions & types


Experience

Haskell really supports refactoring much more


than other systems.

Really hard nut to crack:


Haskell’s abstract syntax is pretty recursive

GHC internal form loses some textual form

What is up with all those Name classes?


Language Representation

ppDecl :: … -> LHsDecl DocName -> DocForDecl DocName -> [DocInstance DocName]
-> [(DocName, DocForDecl DocName)] -> … -> Html

ppDecl … (L loc decl) (mbDoc, fnArgsDoc) instances subdocs … = case decl of

TyClD d@(TyFamily {}) -> ppTyFam … loc mbDoc d …


TyClD d@(TyData {})
| Nothing <- tcdTyPats d -> ppDataDecl … instances subdocs loc mbDoc d …
| Just _ <- tcdTyPats d -> ppDataInst … loc mbDoc d
TyClD d@(TySynonym {})
| Nothing <- tcdTyPats d -> ppTySyn … loc (mbDoc, fnArgsDoc) d …
| Just _ <- tcdTyPats d -> ppTyInst … loc mbDoc d …
TyClD d@(ClassDecl {}) -> ppClassDecl … instances loc mbDoc subdocs d …
SigD (TypeSig (L _ n) (L _ t)) -> ppFunSig … loc (mbDoc, fnArgsDoc) n t …
ForD d -> ppFor … loc (mbDoc, fnArgsDoc) d …
InstD _ -> noHtml
_ -> error "declaration not supported by ppDecl"
Language Representation

ppDecl :: … -> LHsDecl DocName -> DocForDecl DocName -> [DocInstance DocName]
-> [(DocName, DocForDecl DocName)] -> … -> Html

ppDecl … (L loc decl) (mbDoc, fnArgsDoc) instances subdocs … = case decl of

TyClD d@(TyFamily {}) -> ppTyFam … loc mbDoc d …


TyClD d@(TyData {})
| Nothing <- tcdTyPats d -> ppDataDecl … instances subdocs loc mbDoc d …
| Just _ <- tcdTyPats d -> ppDataInst … loc mbDoc d
TyClD d@(TySynonym {})
| Nothing <- tcdTyPats d -> ppTySyn … loc (mbDoc, fnArgsDoc) d …
| Just _ <- tcdTyPats d -> ppTyInst … loc mbDoc d …
TyClD d@(ClassDecl {}) -> ppClassDecl … instances loc mbDoc subdocs d …
SigD (TypeSig (L _ n) (L _ t)) -> ppFunSig … loc (mbDoc, fnArgsDoc) n t …
ForD d -> ppFor … loc (mbDoc, fnArgsDoc) d …
InstD _ -> noHtml
_ -> error "declaration not supported by ppDecl"
Name Madness

ppOccName :: OccName -> Html


ppOccName = toHtml . occNameString

ppRdrName :: RdrName -> Html


ppRdrName = ppOccName . rdrNameOcc

ppLDocName :: Located DocName -> Html


ppLDocName (L _ d) = ppDocName d

ppDocName :: DocName -> Html


ppDocName (Documented name mdl) =
linkIdOcc mdl (Just occName) << ppOccName occName
where occName = nameOccName name
ppDocName (Undocumented name) = toHtml (getOccString name)

ppName :: Name -> Html


ppName name = toHtml (getOccString name)
When Syntaxes
Collide

photo by Ethan Hein


A DSL for HTML

> let ppht x = putStrLn $ showHtmlFragment x


> ppht $ p << "Hello"

<p>Hello</p>

> ppht $ p ! [ theclass "big" ] << "Hello"

<p class="big">Hello</p>
Looks like a combinator…

> let bigp = p ! [ theclass "big" ]

> ppht $ bigp << "Hello"

<p class="big">Hello</p>

> ppht $ bigp ! [ identifier "greeting" ] << "Hello"

<p class="big" id="greeting">Hello</p>


…But fail?

> ppht $ bigp ! [ theclass "quote" ] << "Hello"

<p class="big" class="quote">Hello</p>


Truth & Consequences

Problem stems from not modeling the structure


of HTML completely

Library hides implementation

Library’s type classes don’t seem to help


Actual Code

-- a box for displaying code


declElem :: Html -> Html
declElem = paragraph ! [theclass "src"]

-- | Attributes for an area that can be collapsed


collapseSection :: String -> Bool -> String -> [HtmlAttr]
collapseSection id_ state classes
= [ identifier sid, theclass cs ]
where cs = unwords (csh : words classes)
csh = if state then "show" else "hide"
sid = "section." ++ id_
Haskell Workflow &
Haddock

National Archives
Local Workflow

.cabal

cabal
ghc
haddock
hscolour
Large Project Workflow

.cabal

.sh

.cabal

bash
haddock

.cabal
Using a Library Workflow

user
&/or

cabal

system
Hackage Workflow

magic
GHC Boot Library Workflow

time

dph

containers

array
bytestring

ghc-prim

haskell98 base
Multiple Deployments

Files

Contained web site

Embedded web site

Served

Packaged
Future Work

Library of Congress Archives


The Rendering

Endless Tweaking

New Themes

Better Frames (or Frame-like) Mode

JavaScript: More? Less? Better?


The Features

Source Code
Better integration with Hscolour
In-line source

Search
In-line search
Integration w/Hoogle & Hayoo

Integration with ghci, vim/emacs, IDEs


The Process

Workflows

Cabal Integration and Regeneration

Hackage Project Page Integration

Publication of GHC Base Libraries & Haskell


Platform
Credits

David Waern - Project Maintainer

Johan Tibell

Mark Lentczner

Ross Paterson

Simon Marlow

Thomas Shilling
public domain image from NOAA's Historic Fisheries Collection

Mark Lentczner
Fin markl@glyphic.com

You might also like