git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Store more information in RenderedCode / refactoring

* Changes the RenderedCodeElement type to preserve more information for creating links in RenderedCode values. In particular, the namespace of a symbol is now stored. * Refactor Docs.RenderedCode.Types so that the functions for creating RenderedCode values are easier to use and more type-safe. * Include information about the module that kinds are contained in in the RenderedCode renderer. * Split Docs.RenderedCode.Render into two modules: Docs.RenderedCode.RenderType and Docs.RenderedCode.RenderKind. The JSON format has changed but in a backwards-compatible way, so the Pursuit database will not need to be regenerated.

commit04d7668434fa0fe9e47f4ce9f27779a6dc3dfaab authorHarry Garrood <harry@garrood.me> dateSat 7 Jan 2017, 02:54 (10 years ago) parent62a30ad
9 files changed+400−153
purescript.cabal+3−1 src/Language/PureScript/Docs.hs+1−2 src/Language/PureScript/Docs/AsMarkdown.hs+4−6 src/Language/PureScript/Docs/Render.hs+17−27 src/Language/PureScript/Docs/RenderedCode.hs+9−8 src/Language/PureScript/Docs/RenderedCode/RenderKind.hs+57 src/Language/PureScript/Docs/RenderedCode/Render.hs → src/Language/PureScript/Docs/RenderedCode/RenderType.hs+25−32 src/Language/PureScript/Docs/RenderedCode/Types.hs+251−74 src/Language/PureScript/Docs/Types.hs+33−3
purescript.cabal+3−1
@@ -123,6 +123,7 @@ library
123123 containers -any,
124124 clock -any,
125125 data-ordlist >= 0.4.7.0,
126+ deepseq -any,
126127 directory >= 1.2,
127128 dlist -any,
128129 edit-distance -any,
@@ -266,7 +267,8 @@ library
266267 Language.PureScript.Docs.Types
267268 Language.PureScript.Docs.RenderedCode
268269 Language.PureScript.Docs.RenderedCode.Types
269− Language.PureScript.Docs.RenderedCode.Render
270+ Language.PureScript.Docs.RenderedCode.RenderType
271+ Language.PureScript.Docs.RenderedCode.RenderKind
270272 Language.PureScript.Docs.AsMarkdown
271273 Language.PureScript.Docs.ParseInPackage
272274 Language.PureScript.Docs.Utils.MonoidExtras
src/Language/PureScript/Docs.hs+1−2
@@ -10,6 +10,5 @@ import Language.PureScript.Docs.Convert as Docs
1010import Language.PureScript.Docs.Prim as Docs
1111import Language.PureScript.Docs.ParseInPackage as Docs
1212import Language.PureScript.Docs.Render as Docs
13−import Language.PureScript.Docs.RenderedCode.Render as Docs
14−import Language.PureScript.Docs.RenderedCode.Types as Docs
13+import Language.PureScript.Docs.RenderedCode as Docs
1514import Language.PureScript.Docs.Types as Docs
src/Language/PureScript/Docs/AsMarkdown.hs+4−6
@@ -77,12 +77,10 @@ declAsMarkdown mn decl@Declaration{..} = do
7777codeToString :: RenderedCode -> Text
7878codeToString = outputWith elemAsMarkdown
7979 where
80− elemAsMarkdown (Syntax x) = x
81− elemAsMarkdown (Ident x _) = x
82− elemAsMarkdown (Ctor x _) = x
83− elemAsMarkdown (Kind x) = x
84− elemAsMarkdown (Keyword x) = x
85− elemAsMarkdown Space = " "
80+ elemAsMarkdown (Syntax x) = x
81+ elemAsMarkdown (Keyword x) = x
82+ elemAsMarkdown Space = " "
83+ elemAsMarkdown (Symbol _ x _) = x
8684
8785-- fixityAsMarkdown :: P.Fixity -> Docs
8886-- fixityAsMarkdown (P.Fixity associativity precedence) =
src/Language/PureScript/Docs/Render.hs+17−27
@@ -28,7 +28,7 @@ renderDeclarationWithOptions :: RenderTypeOptions -> Declaration -> RenderedCode
2828renderDeclarationWithOptions opts Declaration{..} =
2929 mintersperse sp $ case declInfo of
3030 ValueDeclaration ty ->
31− [ ident declTitle
31+ [ ident' declTitle
3232 , syntax "::"
3333 , renderType' ty
3434 ]
@@ -70,40 +70,25 @@ renderDeclarationWithOptions opts Declaration{..} =
7070 [idents from <> sp <> syntax "->" <> sp <> idents to | (from, to) <- fundeps ]
7171 ]
7272 where
73− idents = mintersperse sp . map ident
73+ idents = mintersperse sp . map ident'
7474
75− AliasDeclaration (P.Fixity associativity precedence) for@(P.Qualified _ alias) ->
75+ AliasDeclaration (P.Fixity associativity precedence) for ->
7676 [ keywordFixity associativity
7777 , syntax $ T.pack $ show precedence
78− , ident $ renderQualAlias for
79− , keyword "as"
80− , ident $ adjustAliasName alias declTitle
78+ , alias for
79+ , keywordAs
80+ , aliasName for declTitle
8181 ]
8282
8383 ExternKindDeclaration ->
8484 [ keywordKind
85− , renderKind (P.NamedKind (notQualified declTitle))
85+ , kind (notQualified declTitle)
8686 ]
8787
8888 where
8989 renderType' :: P.Type -> RenderedCode
9090 renderType' = renderTypeWithOptions opts
9191
92− renderQualAlias :: FixityAlias -> Text
93− renderQualAlias (P.Qualified mn alias)
94− | mn == currentModule opts = renderAlias id alias
95− | otherwise = renderAlias (\f -> P.showQualified f . P.Qualified mn) alias
96−
97− renderAlias
98− :: (forall a. (a -> Text) -> a -> Text)
99− -> Either (P.ProperName 'P.TypeName) (Either P.Ident (P.ProperName 'P.ConstructorName))
100− -> Text
101− renderAlias f
102− = either (("type " <>) . f P.runProperName)
103− $ either (f P.runIdent) (f P.runProperName)
104−
105− adjustAliasName _ title = T.tail (T.init title)
106−
10792renderChildDeclaration :: ChildDeclaration -> RenderedCode
10893renderChildDeclaration = renderChildDeclarationWithOptions defaultRenderTypeOptions
10994
@@ -113,18 +98,17 @@ renderChildDeclarationWithOptions opts ChildDeclaration{..} =
11398 ChildInstance constraints ty ->
11499 maybeToList (renderConstraints constraints) ++ [ renderType' ty ]
115100 ChildDataConstructor args ->
116− [ renderType' typeApp' ]
117− where
118− typeApp' = foldl P.TypeApp ctor' args
119− ctor' = P.TypeConstructor (notQualified cdeclTitle)
101+ [ dataCtor' cdeclTitle ]
102+ ++ map renderTypeAtom' args
120103
121104 ChildTypeClassMember ty ->
122− [ ident cdeclTitle
105+ [ ident' cdeclTitle
123106 , syntax "::"
124107 , renderType' ty
125108 ]
126109 where
127110 renderType' = renderTypeWithOptions opts
111+ renderTypeAtom' = renderTypeAtomWithOptions opts
128112
129113renderConstraint :: P.Constraint -> RenderedCode
130114renderConstraint = renderConstraintWithOptions defaultRenderTypeOptions
@@ -151,6 +135,12 @@ renderConstraintsWithOptions opts constraints
151135notQualified :: Text -> P.Qualified (P.ProperName a)
152136notQualified = P.Qualified Nothing . P.ProperName
153137
138+ident' :: Text -> RenderedCode
139+ident' = ident . P.Qualified Nothing . P.Ident
140+
141+dataCtor' :: Text -> RenderedCode
142+dataCtor' = dataCtor . notQualified
143+
154144typeApp :: Text -> [(Text, Maybe P.Kind)] -> P.Type
155145typeApp title typeArgs =
156146 foldl P.TypeApp
src/Language/PureScript/Docs/RenderedCode.hs+9−8
@@ -1,8 +1,9 @@
1−
2−-- | Data types and functions for representing a simplified form of PureScript
3−-- code, intended for use in e.g. HTML documentation.
4−
5−module Language.PureScript.Docs.RenderedCode (module RenderedCode) where
6−
7−import Language.PureScript.Docs.RenderedCode.Types as RenderedCode
8−import Language.PureScript.Docs.RenderedCode.Render as RenderedCode
1+
2+-- | Data types and functions for representing a simplified form of PureScript
3+-- code, intended for use in e.g. HTML documentation.
4+
5+module Language.PureScript.Docs.RenderedCode (module RenderedCode) where
6+
7+import Language.PureScript.Docs.RenderedCode.Types as RenderedCode
8+import Language.PureScript.Docs.RenderedCode.RenderType as RenderedCode
9+import Language.PureScript.Docs.RenderedCode.RenderKind as RenderedCode
src/Language/PureScript/Docs/RenderedCode/RenderKind.hsnew file+57
@@ -0,0 +1,57 @@
1+-- | Functions for producing RenderedCode values from PureScript Kind values.
2+--
3+module Language.PureScript.Docs.RenderedCode.RenderKind
4+ ( renderKind
5+ ) where
6+
7+-- TODO: This is pretty much copied from Language.PureScript.Pretty.Kinds.
8+-- Ideally we would unify the two.
9+
10+import Prelude.Compat
11+
12+import Control.Arrow (ArrowPlus(..))
13+import Control.PatternArrows as PA
14+
15+import Data.Monoid ((<>))
16+import Data.Maybe (fromMaybe)
17+import qualified Data.Text as T
18+
19+import Language.PureScript.Crash
20+import Language.PureScript.Kinds
21+
22+import Language.PureScript.Docs.RenderedCode.Types
23+
24+typeLiterals :: Pattern () Kind RenderedCode
25+typeLiterals = mkPattern match
26+ where
27+ match (KUnknown u) =
28+ Just $ typeVar $ T.cons 'k' (T.pack (show u))
29+ match (NamedKind n) =
30+ Just $ kind n
31+ match _ = Nothing
32+
33+matchRow :: Pattern () Kind ((), Kind)
34+matchRow = mkPattern match
35+ where
36+ match (Row k) = Just ((), k)
37+ match _ = Nothing
38+
39+funKind :: Pattern () Kind (Kind, Kind)
40+funKind = mkPattern match
41+ where
42+ match (FunKind arg ret) = Just (arg, ret)
43+ match _ = Nothing
44+
45+-- | Generate RenderedCode value representing a Kind
46+renderKind :: Kind -> RenderedCode
47+renderKind
48+ = fromMaybe (internalError "Incomplete pattern")
49+ . PA.pattern matchKind ()
50+ where
51+ matchKind :: Pattern () Kind RenderedCode
52+ matchKind = buildPrettyPrinter operators (typeLiterals <+> fmap parens matchKind)
53+
54+ operators :: OperatorTable () Kind RenderedCode
55+ operators =
56+ OperatorTable [ [ Wrap matchRow $ \_ k -> syntax "#" <> sp <> k]
57+ , [ AssocR funKind $ \arg ret -> arg <> sp <> syntax "->" <> sp <> ret ] ]
src/Language/PureScript/Docs/RenderedCode/Render.hs → src/Language/PureScript/Docs/RenderedCode/RenderType.hsrenamed+25−32
@@ -1,13 +1,13 @@
11-- | Functions for producing RenderedCode values from PureScript Type values.
22
3−module Language.PureScript.Docs.RenderedCode.Render
3+module Language.PureScript.Docs.RenderedCode.RenderType
44 ( renderType
55 , renderTypeAtom
66 , renderRow
7− , renderKind
87 , RenderTypeOptions(..)
98 , defaultRenderTypeOptions
109 , renderTypeWithOptions
10+ , renderTypeAtomWithOptions
1111 ) where
1212
1313import Prelude.Compat
@@ -20,39 +20,40 @@ import Control.Arrow ((<+>))
2020import Control.PatternArrows as PA
2121
2222import Language.PureScript.Crash
23−import Language.PureScript.Docs.RenderedCode.Types
24−import Language.PureScript.Docs.Utils.MonoidExtras
2523import Language.PureScript.Environment
2624import Language.PureScript.Kinds
2725import Language.PureScript.Names
28−import Language.PureScript.Pretty.Kinds
2926import Language.PureScript.Pretty.Types
3027import Language.PureScript.Types
3128import Language.PureScript.Label (Label)
3229
30+import Language.PureScript.Docs.RenderedCode.Types
31+import Language.PureScript.Docs.Utils.MonoidExtras
32+import Language.PureScript.Docs.RenderedCode.RenderKind (renderKind)
33+
3334typeLiterals :: Pattern () Type RenderedCode
3435typeLiterals = mkPattern match
3536 where
3637 match TypeWildcard{} =
3738 Just (syntax "_")
3839 match (TypeVar var) =
39− Just (ident var)
40+ Just (typeVar var)
4041 match (PrettyPrintObject row) =
4142 Just $ mintersperse sp
4243 [ syntax "{"
4344 , renderRow row
4445 , syntax "}"
4546 ]
46− match (TypeConstructor (Qualified mn name)) =
47− Just (ctor (runProperName name) (maybeToContainingModule mn))
47+ match (TypeConstructor n) =
48+ Just (typeCtor n)
4849 match REmpty =
4950 Just (syntax "()")
5051 match row@RCons{} =
5152 Just (syntax "(" <> renderRow row <> syntax ")")
5253 match (BinaryNoParensType op l r) =
5354 Just $ renderTypeAtom l <> sp <> renderTypeAtom op <> sp <> renderTypeAtom r
54− match (TypeOp (Qualified mn op)) =
55− Just (ident' (runOpName op) (maybeToContainingModule mn))
55+ match (TypeOp n) =
56+ Just (typeOp n)
5657 match _ =
5758 Nothing
5859
@@ -87,7 +88,7 @@ renderHead = mintersperse (syntax "," <> sp) . map renderLabel
8788renderLabel :: (Label, Type) -> RenderedCode
8889renderLabel (label, ty) =
8990 mintersperse sp
90− [ syntax $ prettyPrintLabel label
91+ [ typeVar $ prettyPrintLabel label
9192 , syntax "::"
9293 , renderType ty
9394 ]
@@ -139,7 +140,7 @@ matchType = buildPrettyPrinter operators matchTypeAtom
139140 OperatorTable [ [ AssocL typeApp $ \f x -> f <> sp <> x ]
140141 , [ AssocR appliedFunction $ \arg ret -> mintersperse sp [arg, syntax "->", ret] ]
141142 , [ Wrap constrained $ \deps ty -> renderConstraints deps ty ]
142− , [ Wrap forall_ $ \idents ty -> mconcat [syntax "forall", sp, mintersperse sp (map ident idents), syntax ".", sp, ty] ]
143+ , [ Wrap forall_ $ \tyVars ty -> mconcat [keywordForall, sp, mintersperse sp (map typeVar tyVars), syntax ".", sp, ty] ]
143144 , [ Wrap kinded $ \k ty -> mintersperse sp [ty, syntax "::", renderKind k] ]
144145 , [ Wrap explicitParens $ \_ ty -> ty ]
145146 ]
@@ -154,12 +155,6 @@ insertPlaceholders :: RenderTypeOptions -> Type -> Type
154155insertPlaceholders opts =
155156 everywhereOnTypesTopDown convertForAlls . everywhereOnTypes (convert opts)
156157
157−dePrim :: Type -> Type
158−dePrim ty@(TypeConstructor (Qualified _ name))
159− | ty == tyBoolean || ty == tyNumber || ty == tyString =
160− TypeConstructor $ Qualified Nothing name
161−dePrim other = other
162−
163158convert :: RenderTypeOptions -> Type -> Type
164159convert _ (TypeApp (TypeApp f arg) ret) | f == tyFunction = PrettyPrintFunction arg ret
165160convert opts (TypeApp o r) | o == tyRecord && prettyPrintObjects opts = PrettyPrintObject r
@@ -173,28 +168,20 @@ convertForAlls (ForAll i ty _) = go [i] ty
173168convertForAlls other = other
174169
175170preprocessType :: RenderTypeOptions -> Type -> Type
176−preprocessType opts = dePrim . insertPlaceholders opts
171+preprocessType opts = insertPlaceholders opts
172+
177173
178174-- |
179−-- Render code representing a Kind
175+-- Render code representing a Type
180176--
181−renderKind :: Kind -> RenderedCode
182−renderKind = kind . prettyPrintKind
177+renderType :: Type -> RenderedCode
178+renderType = renderTypeWithOptions defaultRenderTypeOptions
183179
184180-- |
185181-- Render code representing a Type, as it should appear inside parentheses
186182--
187183renderTypeAtom :: Type -> RenderedCode
188−renderTypeAtom
189− = fromMaybe (internalError "Incomplete pattern")
190− . PA.pattern matchTypeAtom ()
191− . preprocessType defaultRenderTypeOptions
192−
193−-- |
194−-- Render code representing a Type
195−--
196−renderType :: Type -> RenderedCode
197−renderType = renderTypeWithOptions defaultRenderTypeOptions
184+renderTypeAtom = renderTypeAtomWithOptions defaultRenderTypeOptions
198185
199186data RenderTypeOptions = RenderTypeOptions
200187 { prettyPrintObjects :: Bool
@@ -213,3 +200,9 @@ renderTypeWithOptions opts
213200 = fromMaybe (internalError "Incomplete pattern")
214201 . PA.pattern matchType ()
215202 . preprocessType opts
203+
204+renderTypeAtomWithOptions :: RenderTypeOptions -> Type -> RenderedCode
205+renderTypeAtomWithOptions opts
206+ = fromMaybe (internalError "Incomplete pattern")
207+ . PA.pattern matchTypeAtom ()
208+ . preprocessType opts
src/Language/PureScript/Docs/RenderedCode/Types.hs+251−74
@@ -1,4 +1,5 @@
11{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2+{-# LANGUAGE DeriveGeneric #-}
23
34-- | Data types and functions for representing a simplified form of PureScript
45-- code, intended for use in e.g. HTML documentation.
@@ -11,15 +12,16 @@ module Language.PureScript.Docs.RenderedCode.Types
1112 , containingModuleToMaybe
1213 , maybeToContainingModule
1314 , fromContainingModule
15+ , fromQualified
16+ , Namespace(..)
17+ , Link(..)
18+ , FixityAlias
1419 , RenderedCode
1520 , asRenderedCode
1621 , outputWith
1722 , sp
23+ , parens
1824 , syntax
19− , ident
20− , ident'
21− , ctor
22− , kind
2325 , keyword
2426 , keywordForall
2527 , keywordData
@@ -30,105 +32,216 @@ module Language.PureScript.Docs.RenderedCode.Types
3032 , keywordWhere
3133 , keywordFixity
3234 , keywordKind
35+ , keywordAs
36+ , ident
37+ , dataCtor
38+ , typeCtor
39+ , typeOp
40+ , typeVar
41+ , kind
42+ , alias
43+ , aliasName
3344 ) where
3445
3546import Prelude.Compat
47+import GHC.Generics (Generic)
3648
49+import Control.DeepSeq (NFData)
3750import Control.Monad.Error.Class (MonadError(..))
3851
52+import Data.Monoid ((<>))
3953import Data.Aeson.BetterErrors
4054import qualified Data.Aeson as A
4155import Data.Text (Text)
56+import qualified Data.Text as T
57+import qualified Data.ByteString.Lazy as BS
58+import qualified Data.Text.Encoding as TE
4259
43−import qualified Language.PureScript as P
60+import Language.PureScript.Names
61+import Language.PureScript.AST (Associativity(..))
62+import Language.PureScript.Crash (internalError)
4463
45−-- |
46−-- A single element in a rendered code fragment. The intention is to support
47−-- multiple output formats. For example, plain text, or highlighted HTML.
48−--
49−data RenderedCodeElement
50− = Syntax Text
51− | Ident Text ContainingModule
52− | Ctor Text ContainingModule
53− | Kind Text
54− | Keyword Text
55− | Space
56− deriving (Show, Eq, Ord)
64+-- | Given a list of actions, attempt them all, returning the first success.
65+-- If all the actions fail, 'tryAll' returns the first argument.
66+tryAll :: MonadError e m => m a -> [m a] -> m a
67+tryAll = foldr $ \x y -> catchError x (const y)
5768
58−instance A.ToJSON RenderedCodeElement where
59− toJSON (Syntax str) =
60− A.toJSON ["syntax", str]
61− toJSON (Ident str mn) =
62− A.toJSON ["ident", A.toJSON str, A.toJSON mn]
63− toJSON (Ctor str mn) =
64− A.toJSON ["ctor", A.toJSON str, A.toJSON mn ]
65− toJSON (Kind str) =
66− A.toJSON ["kind", str]
67− toJSON (Keyword str) =
68− A.toJSON ["keyword", str]
69− toJSON Space =
70− A.toJSON ["space" :: Text]
71−
72−asRenderedCodeElement :: Parse Text RenderedCodeElement
73−asRenderedCodeElement =
74− a Syntax "syntax" <|>
75− asIdent <|>
76− asCtor <|>
77− a Kind "kind" <|>
78− a Keyword "keyword" <|>
79− asSpace <|>
80− unableToParse
69+firstEq :: Text -> Parse Text a -> Parse Text a
70+firstEq str p = nth 0 (withText (eq str)) *> p
8171 where
82− p <|> q = catchError p (const q)
72+ eq s s' = if s == s' then Right () else Left ""
8373
84− a ctor' ctorStr = ctor' <$> (nth 0 (withText (eq ctorStr)) *> nth 1 asText)
85− asIdent = nth 0 (withText (eq "ident")) *> (Ident <$> nth 1 asText <*> nth 2 asContainingModule)
86− asCtor = nth 0 (withText (eq "ctor")) *> (Ctor <$> nth 1 asText <*> nth 2 asContainingModule)
87− asSpace = nth 0 (withText (eq "space")) *> pure Space
74+-- |
75+-- Try the given parsers in sequence. If all fail, fail with the given message,
76+-- and include the JSON in the error.
77+--
78+tryParse :: Text -> [Parse Text a] -> Parse Text a
79+tryParse msg =
80+ tryAll (withValue (Left . (fullMsg <>) . showJSON))
8881
89− eq s s' = if s == s' then Right () else Left ""
82+ where
83+ fullMsg = "Invalid " <> msg <> ": "
9084
91− unableToParse = withText Left
85+ showJSON :: A.Value -> Text
86+ showJSON = TE.decodeUtf8 . BS.toStrict . A.encode
9287
9388-- |
94−-- This type is isomorphic to 'Maybe' 'P.ModuleName'. It makes code a bit easier
95−-- to read, as the meaning is more explicit.
89+-- This type is isomorphic to 'Maybe' 'ModuleName'. It makes code a bit
90+-- easier to read, as the meaning is more explicit.
9691--
9792data ContainingModule
9893 = ThisModule
99− | OtherModule P.ModuleName
94+ | OtherModule ModuleName
10095 deriving (Show, Eq, Ord)
10196
10297instance A.ToJSON ContainingModule where
103− toJSON mn = A.toJSON (P.runModuleName <$> containingModuleToMaybe mn)
98+ toJSON = A.toJSON . go
99+ where
100+ go = \case
101+ ThisModule -> ["ThisModule"]
102+ OtherModule mn -> ["OtherModule", runModuleName mn]
104103
105−asContainingModule :: Parse e ContainingModule
104+instance A.FromJSON ContainingModule where
105+ parseJSON = toAesonParser id asContainingModule
106+
107+asContainingModule :: Parse Text ContainingModule
106108asContainingModule =
107− maybeToContainingModule <$> perhaps (P.moduleNameFromString <$> asText)
109+ tryParse "containing module" $
110+ current ++ backwardsCompat
111+ where
112+ current =
113+ [ firstEq "ThisModule" (pure ThisModule)
114+ , firstEq "OtherModule" (OtherModule <$> nth 1 asModuleName)
115+ ]
116+
117+ -- For JSON produced by compilers up to 0.10.5.
118+ backwardsCompat =
119+ [ maybeToContainingModule <$> perhaps asModuleName
120+ ]
121+
122+ asModuleName = moduleNameFromString <$> asText
108123
109124-- |
110−-- Convert a 'Maybe' 'P.ModuleName' to a 'ContainingModule', using the obvious
125+-- Convert a 'Maybe' 'ModuleName' to a 'ContainingModule', using the obvious
111126-- isomorphism.
112127--
113−maybeToContainingModule :: Maybe P.ModuleName -> ContainingModule
128+maybeToContainingModule :: Maybe ModuleName -> ContainingModule
114129maybeToContainingModule Nothing = ThisModule
115130maybeToContainingModule (Just mn) = OtherModule mn
116131
117132-- |
118−-- Convert a 'ContainingModule' to a 'Maybe' 'P.ModuleName', using the obvious
133+-- Convert a 'ContainingModule' to a 'Maybe' 'ModuleName', using the obvious
119134-- isomorphism.
120135--
121−containingModuleToMaybe :: ContainingModule -> Maybe P.ModuleName
136+containingModuleToMaybe :: ContainingModule -> Maybe ModuleName
122137containingModuleToMaybe ThisModule = Nothing
123138containingModuleToMaybe (OtherModule mn) = Just mn
124139
125140-- |
126141-- A version of 'fromMaybe' for 'ContainingModule' values.
127142--
128−fromContainingModule :: P.ModuleName -> ContainingModule -> P.ModuleName
143+fromContainingModule :: ModuleName -> ContainingModule -> ModuleName
129144fromContainingModule def ThisModule = def
130145fromContainingModule _ (OtherModule mn) = mn
131146
147+fromQualified :: Qualified a -> (ContainingModule, a)
148+fromQualified (Qualified mn x) =
149+ (maybeToContainingModule mn, x)
150+
151+data Link
152+ = NoLink
153+ | Link ContainingModule
154+ deriving (Show, Eq, Ord)
155+
156+instance A.ToJSON Link where
157+ toJSON = \case
158+ NoLink -> A.toJSON ["NoLink" :: Text]
159+ Link mn -> A.toJSON ["Link", A.toJSON mn]
160+
161+asLink :: Parse Text Link
162+asLink =
163+ tryParse "link"
164+ [ firstEq "NoLink" (pure NoLink)
165+ , firstEq "Link" (Link <$> nth 1 asContainingModule)
166+ ]
167+
168+instance A.FromJSON Link where
169+ parseJSON = toAesonParser id asLink
170+
171+data Namespace
172+ = ValueLevel
173+ | TypeLevel
174+ | KindLevel
175+ deriving (Show, Eq, Ord, Generic)
176+
177+instance NFData Namespace
178+
179+instance A.ToJSON Namespace where
180+ toJSON = A.toJSON . show
181+
182+asNamespace :: Parse Text Namespace
183+asNamespace =
184+ tryParse "namespace"
185+ [ withText $ \case
186+ "ValueLevel" -> Right ValueLevel
187+ "TypeLevel" -> Right TypeLevel
188+ "KindLevel" -> Right KindLevel
189+ _ -> Left ""
190+ ]
191+
192+instance A.FromJSON Namespace where
193+ parseJSON = toAesonParser id asNamespace
194+
195+-- |
196+-- A single element in a rendered code fragment. The intention is to support
197+-- multiple output formats. For example, plain text, or highlighted HTML.
198+--
199+data RenderedCodeElement
200+ = Syntax Text
201+ | Keyword Text
202+ | Space
203+ -- | Any symbol which you might or might not want to link to, in any
204+ -- namespace (value, type, or kind). Note that this is not related to the
205+ -- kind called Symbol for type-level strings.
206+ | Symbol Namespace Text Link
207+ deriving (Show, Eq, Ord)
208+
209+instance A.ToJSON RenderedCodeElement where
210+ toJSON (Syntax str) =
211+ A.toJSON ["syntax", str]
212+ toJSON (Keyword str) =
213+ A.toJSON ["keyword", str]
214+ toJSON Space =
215+ A.toJSON ["space" :: Text]
216+ toJSON (Symbol ns str link) =
217+ A.toJSON ["symbol", A.toJSON ns, A.toJSON str, A.toJSON link]
218+
219+asRenderedCodeElement :: Parse Text RenderedCodeElement
220+asRenderedCodeElement =
221+ tryParse "RenderedCodeElement" $
222+ [ a Syntax "syntax"
223+ , a Keyword "keyword"
224+ , asSpace
225+ , asSymbol
226+ ] ++ backwardsCompat
227+ where
228+ a ctor' ctorStr = firstEq ctorStr (ctor' <$> nth 1 asText)
229+ asSymbol = firstEq "symbol" (Symbol <$> nth 1 asNamespace <*> nth 2 asText <*> nth 3 asLink)
230+ asSpace = firstEq "space" (pure Space)
231+
232+ -- These will make some mistakes e.g. treating data constructors as types,
233+ -- because the old code did not save information which is necessary to
234+ -- distinguish these cases. This is the best we can do.
235+ backwardsCompat =
236+ [ oldAsIdent
237+ , oldAsCtor
238+ , oldAsKind
239+ ]
240+
241+ oldAsIdent = firstEq "ident" (Symbol ValueLevel <$> nth 1 asText <*> nth 2 (Link <$> asContainingModule))
242+ oldAsCtor = firstEq "ctor" (Symbol TypeLevel <$> nth 1 asText <*> nth 2 (Link <$> asContainingModule))
243+ oldAsKind = firstEq "kind" (Symbol KindLevel <$> nth 1 asText <*> pure (Link ThisModule))
244+
132245-- |
133246-- A type representing a highly simplified version of PureScript code, intended
134247-- for use in output formats like plain text or HTML.
@@ -158,21 +271,17 @@ outputWith f = foldMap f . unRC
158271sp :: RenderedCode
159272sp = RC [Space]
160273
274+-- |
275+-- Wrap a RenderedCode value in parens.
276+parens :: RenderedCode -> RenderedCode
277+parens x = syntax "(" <> x <> syntax ")"
278+
279+-- possible TODO: instead of this function, export RenderedCode values for
280+-- each syntax element, eg syntaxArr (== syntax "->"), syntaxLBrace,
281+-- syntaxRBrace, etc.
161282syntax :: Text -> RenderedCode
162283syntax x = RC [Syntax x]
163284
164−ident :: Text -> RenderedCode
165−ident x = RC [Ident x ThisModule]
166−
167−ident' :: Text -> ContainingModule -> RenderedCode
168−ident' x m = RC [Ident x m]
169−
170−ctor :: Text -> ContainingModule -> RenderedCode
171−ctor x m = RC [Ctor x m]
172−
173−kind :: Text -> RenderedCode
174−kind x = RC [Kind x]
175−
176285keyword :: Text -> RenderedCode
177286keyword kw = RC [Keyword kw]
178287
@@ -197,10 +306,78 @@ keywordInstance = keyword "instance"
197306keywordWhere :: RenderedCode
198307keywordWhere = keyword "where"
199308
200−keywordFixity :: P.Associativity -> RenderedCode
201−keywordFixity P.Infixl = keyword "infixl"
202−keywordFixity P.Infixr = keyword "infixr"
203−keywordFixity P.Infix = keyword "infix"
309+keywordFixity :: Associativity -> RenderedCode
310+keywordFixity Infixl = keyword "infixl"
311+keywordFixity Infixr = keyword "infixr"
312+keywordFixity Infix = keyword "infix"
204313
205314keywordKind :: RenderedCode
206315keywordKind = keyword "kind"
316+
317+keywordAs :: RenderedCode
318+keywordAs = keyword "as"
319+
320+ident :: Qualified Ident -> RenderedCode
321+ident (fromQualified -> (mn, name)) =
322+ RC [Symbol ValueLevel (runIdent name) (Link mn)]
323+
324+dataCtor :: Qualified (ProperName 'ConstructorName) -> RenderedCode
325+dataCtor (fromQualified -> (mn, name)) =
326+ RC [Symbol ValueLevel (runProperName name) (Link mn)]
327+
328+typeCtor :: Qualified (ProperName 'TypeName) -> RenderedCode
329+typeCtor (fromQualified -> (mn, name)) =
330+ RC [Symbol TypeLevel (runProperName name) (Link mn)]
331+
332+typeOp :: Qualified (OpName 'TypeOpName) -> RenderedCode
333+typeOp (fromQualified -> (mn, name)) =
334+ RC [Symbol TypeLevel (runOpName name) (Link mn)]
335+
336+typeVar :: Text -> RenderedCode
337+typeVar x = RC [Symbol TypeLevel x NoLink]
338+
339+kind :: Qualified (ProperName 'KindName) -> RenderedCode
340+kind (fromQualified -> (mn, name)) =
341+ RC [Symbol KindLevel (runProperName name) (Link mn)]
342+
343+type FixityAlias = Qualified (Either (ProperName 'TypeName) (Either Ident (ProperName 'ConstructorName)))
344+
345+alias :: FixityAlias -> RenderedCode
346+alias for =
347+ prefix <> RC [Symbol ns name (Link mn)]
348+ where
349+ (ns, name, mn) = unpackFixityAlias for
350+ prefix = case ns of
351+ TypeLevel ->
352+ keywordType <> sp
353+ _ ->
354+ mempty
355+
356+aliasName :: FixityAlias -> Text -> RenderedCode
357+aliasName for name' =
358+ let
359+ (ns, _, _) = unpackFixityAlias for
360+ unParen = T.tail . T.init
361+ name = unParen name'
362+ in
363+ case ns of
364+ ValueLevel ->
365+ ident (Qualified Nothing (Ident name))
366+ TypeLevel ->
367+ typeCtor (Qualified Nothing (ProperName name))
368+ KindLevel ->
369+ internalError "Kind aliases are not supported"
370+
371+-- | Converts a FixityAlias into a different representation which is more
372+-- useful to other functions in this module.
373+unpackFixityAlias :: FixityAlias -> (Namespace, Text, ContainingModule)
374+unpackFixityAlias (fromQualified -> (mn, x)) =
375+ case x of
376+ -- We add some seemingly superfluous type signatures here just to be extra
377+ -- sure we are not mixing up our namespaces.
378+ Left (n :: ProperName 'TypeName) ->
379+ (TypeLevel, runProperName n, mn)
380+ Right (Left n) ->
381+ (ValueLevel, runIdent n, mn)
382+ Right (Right (n :: ProperName 'ConstructorName)) ->
383+ (ValueLevel, runProperName n, mn)
src/Language/PureScript/Docs/Types.hs+33−3
@@ -28,7 +28,8 @@ import Web.Bower.PackageMeta hiding (Version, displayError)
2828import Language.PureScript.Docs.RenderedCode as ReExports
2929 (RenderedCode, asRenderedCode,
3030 ContainingModule(..), asContainingModule,
31− RenderedCodeElement(..), asRenderedCodeElement)
31+ RenderedCodeElement(..), asRenderedCodeElement,
32+ Namespace(..), FixityAlias)
3233
3334--------------------
3435-- Types
@@ -183,8 +184,6 @@ convertFundepsToStrings args fundeps =
183184 ) $ argsVec V.!? i
184185 toArgs from to = (map getArg from, map getArg to)
185186
186−type FixityAlias = P.Qualified (Either (P.ProperName 'P.TypeName) (Either P.Ident (P.ProperName 'P.ConstructorName)))
187−
188187declInfoToString :: DeclarationInfo -> Text
189188declInfoToString (ValueDeclaration _) = "value"
190189declInfoToString (DataDeclaration _ _) = "data"
@@ -194,6 +193,23 @@ declInfoToString (TypeClassDeclaration _ _ _) = "typeClass"
194193declInfoToString (AliasDeclaration _ _) = "alias"
195194declInfoToString ExternKindDeclaration = "kind"
196195
196+declInfoNamespace :: DeclarationInfo -> Namespace
197+declInfoNamespace = \case
198+ ValueDeclaration{} ->
199+ ValueLevel
200+ DataDeclaration{} ->
201+ TypeLevel
202+ ExternDataDeclaration{} ->
203+ TypeLevel
204+ TypeSynonymDeclaration{} ->
205+ TypeLevel
206+ TypeClassDeclaration{} ->
207+ TypeLevel
208+ AliasDeclaration _ alias ->
209+ either (const TypeLevel) (const ValueLevel) (P.disqualify alias)
210+ ExternKindDeclaration{} ->
211+ KindLevel
212+
197213isTypeClass :: Declaration -> Bool
198214isTypeClass Declaration{..} =
199215 case declInfo of
@@ -269,6 +285,20 @@ childDeclInfoToString (ChildInstance _ _) = "instance"
269285childDeclInfoToString (ChildDataConstructor _) = "dataConstructor"
270286childDeclInfoToString (ChildTypeClassMember _) = "typeClassMember"
271287
288+childDeclInfoNamespace :: ChildDeclarationInfo -> Namespace
289+childDeclInfoNamespace =
290+ -- We could just write this as `const ValueLevel` but by doing it this way,
291+ -- if another constructor is added, we get a warning which acts as a prompt
292+ -- to update this, instead of having this function (possibly incorrectly)
293+ -- just return ValueLevel for the new constructor.
294+ \case
295+ ChildInstance{} ->
296+ ValueLevel
297+ ChildDataConstructor{} ->
298+ ValueLevel
299+ ChildTypeClassMember{} ->
300+ ValueLevel
301+
272302isTypeClassMember :: ChildDeclaration -> Bool
273303isTypeClassMember ChildDeclaration{..} =
274304 case cdeclInfo of