haskell / haddock

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

Re-export behavior #1563

Open parsonsmatt opened 1 year ago

parsonsmatt commented 1 year ago

Currently if you re export a module with an alias, it dumps all of the contents of that module directly.

module M 
  ( module X
  ) where

import ClassyPrelude as X hiding (...)
import FooBar as X
import BlahBaz as X

This can quite quickly cause performance issues, particularly if you re-export these things.

module M2 ( module X ) where

  import M as X
  import Neat as X

module M3 (module X) where
  import M2 as X
  import A as X

Even if you re-export with the original module name, if you hide anything or only import a specific list, you get a dump of everything:

module M (module Prelude, module Data.Text) where

import Prelude hiding (String)
import Data.Text (Text)

This is Bad both for performance reasons and legibility reasons. Tracking the provenance of re-exports is difficult, and exploding everything onto a page is bad. On the other hand, presenting only a link doesn't allow you to understand the "index" of that module - everything that is exported from it.

Related:

So - let's talk about possible designs for improving the situation.

Goals

Status Quo

We have essentially two status quo situations: Linking a module (if the module is exported intact and without a shared alias), and totally verbose and unorganized (dumping the docs for the module in whatever order makes sense).

Linking a module isn't great, because we can't know at-a-glance (or Ctrl-F) what a module contains and allows you to use.

Dumping the entire module contents isn't great, because it's totally disorganized (and also can be huge - one of our Prelude-ish modules exploded to 250MB of HTML, hundreds of pages printed as a PDF).

Options

Expand Alias and Link Complete Modules

One easy change that would require little modification would be to "expand" an alias and provide links where possible.

module M (module X) where

import Prelude as X
import Data.Text as X (Text)
import BigModule as X 
import LittleModule as X hiding (foo)

If this option were enabled, Hadock would do the same thing as if you wrote this:

module M
  ( module Prelude
  , module Data.Text
  , module BigModule
  , module LittleModule
  ) 

import Prelude
import Data.Text (Text)
import BigModule 
import LittleModule hiding (foo)

Instead of dumping Prelude and BigModule's contents directly, you'd get a link to those two modules.

Modified Modules are Grouped

If this option is enabled, then a modified module is "grouped" with a section. A module like this:

module M (module X) where

import Prelude as X hiding (String)
import Data.Maybe as X hiding (fromJust)

would be rendered as though the user wrote:

module M 
  ( -- * "Prelude"
    module Prelude
    -- * "Data.Maybe"
  , module Data.Maybe
  ) where

import Prelude hiding (String)
import Data.Maybe hiding (fromJust)

Searchable Indexes

With this option enabled, a module would contain an 'index' of everything the module exports, even if the module is linked. The index can take the form of the current "index pages" - just a list of items, paired with the module that brought it into scope (+ maybe the module that defined it?)

This would require more work than the prior two choices, since we'd be adding stuff to the page, rather than "reinterpreting" the export items.

Link with Changes

With this option enabled, a module re-export that alters the exports would show a link and report what was changed.

module M (module X) where

import Prelude hiding (String)
import Data.String (IsString(..))

The above module should generate documentation looking something like:

module M where

Seems reasonable to make this two options: link with explicit import, link with explicit hiding.