Skip to content
This repository has been archived by the owner on Mar 14, 2021. It is now read-only.

Haddock experiment (WIP) #166

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

kostmo
Copy link

@kostmo kostmo commented Jul 17, 2016

I would like to implement support for showing Haddock docstrings in tooltips alongside "info" or "type" information.

I'm hoping for some guidance both overall in the design and specifics of using the API and interfacing with the existing code. I am totally new to Coffeescript and Atom package development.

One of the outputs of the stack haddock --no-haddock-deps command is a text file for each package that says the following at the top:

-- Hoogle documentation, generated by Haddock

The contents of the file are pretty straightforward to parse. I wrote a function in haddock.js that generates a dictionary with symbol names as keys and haddock docstrings as values. Actually it's a nested dictionary with module names as the outer key.

For starters, the plugin could request that the user manually run the stack haddock command before documentation can be shown. Having even this basic functionality would be valuable for users that just need to browse through a Haskell codebase. Perhaps later the plugin could automatically run stack in the background, but I've noticed that it takes a long time (~1:30 in my project, or ~30s with --fast option).

I was able to get the Haddock strings to print to the console when mousing over a symbol, but somehow I was not able to propagate the same string all the way to the tooltip display. I think a short chat on IRC or something could clear up a lot of details for me.

@@ -263,7 +279,7 @@ class UPIConsumer
else
throw new Error('Got neither type nor info')
text:
text: "#{if type?.text?.text then ':: '+type.text.text+'\n' else ''}#{info?.text?.text ? ''}"
text: (Object.keys(doc).join(", ") + "\nBLERG 0: " + doc[Object.keys(doc)[0]] + "\nBLERG 1: " + doc[Object.keys(doc)[1]] + "\nBLERG 1 keys: " + Object.keys(doc[Object.keys(doc)[1]]) + "\nBLERG 1[0]: " + doc[Object.keys(doc)[1]]["text"] + "--(Karl was here)\n") + "#{if type?.text?.text then ':: '+type.text.text+'\n' else ''}#{info?.text?.text ? ''}"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm piggybacking this experimental functionality on the Info+Type display, which is the default tooltip behavior in the package.

I've created a promise as docP which returns a value in doc. For some reason the value of doc.text.text displays as undefined in the tooltip.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're trying to debug it, you might consider using JSON.stringify(doc) instead of this long-winded construction.

That said, I have two thoughts on this whole thing. First, I would think that since this has virtually nothing to do with ghc-mod, this would be better-suited to be provided as a separate package, unless it eventually does (see below).

Second, there's some work wrt haddock happening on ghc-mod, which you might want to take a look at: DanielG/ghc-mod#810

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, that ghc-imported-from merge is exciting. I feel like I should put my effort on hold until that is finished.

Pardon the digression from Haddock, but it seems like that ghc-imported-from project could also improve the reliability of the "Go to Declaration" functionality. Would you agree? I saw your comment in atom-haskell/ide-haskell#137 that there are two ways to "Go to Declaration", provided by either the ide-haskell-hasktags package or haskell-ghc-mod package. However, for me neither seem to properly handle jumping to function definitions that are qualified imports. To me it's unfortunately ironic, as jumping to a declaration that is "far away" (i.e. in a differnt file) is the more valuable automation.

I saw your other comment in atom-haskell/ide-haskell#110 that indicated some limitations:

  • haskell-ghc-mod:

    more accurate, but doesn't work for symbols that are not exported

  • ide-haskell-hasktags:

    less accurate, but works for all top-level symbols

With regard to haskell-ghc-mod, were you referring to symbols that are not explicitly given in a module's export list? For me, symbols from a different module are rarely found regardless. Sometimes, when I mouseover a symbol, I see the following in the console:

EXCEPTION: info:     Not in scope: 'MyOtherModule.someFunction'

In that case, I of course cannot "Go to Declaration" with haskell-ghc-mod eitiher.

In other cases, I am able to mouseover a qualified-imported symbol and see the "info" tooltip, and it even says -- Defined in Foo.Bar.Blah, but "Go to Declaration" will not take me there. I believe that this happens when the symbol is in a different local package (which happens to be one of two listed in my stack.yaml file.

Regarding ide-haskell-hasktags, it is much faster than haskell-ghc-mod for jumping to declarations in the same module, but it also suffers from the inability to jump to symbols that are external to the current module when those symbols are qualified imports.

Would it be valuable for me to submit some test cases to demonstrate these exact problems? I'd also try my hand at fixing the problems.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not about qualified imports (if actual qualified imports fail, file a bug with a testcase -- those should work), but rather cross-package imports I believe? Horrible truth is, ghc is not aware of any cross-package source files -- packages are compiled. So jumping source files between packages is problematic.

Hasktags just parses all open Atom projects for Haskell sources and collects top-level declarations. So it stands to reason that it's faster. Besides, if you need to jump sources between two packages, you can just open both as Atom projects and that should work. There's a caveat with symbols sharing the same name: hasktags has no way to distinguish those, since it's not context-aware, unlike ghc-mod.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I have created minimal test cases that demonstrate various failure modes of "Jump to Declaration" for both haskell-ghc-mod and ide-haskell-hasktags in this demo project.

In summary:

  • Indeed, haskell-ghc-mod never works "across" packages
  • ide-haskell-hasktags works both within the same package and "across" packages when:
    • the symbol is not highlighted; one must place the cursor within the symbol without highlighting it
    • the symbol is not qualified by a namespace; it must be "bare"
  • haskell-ghc-mod does not work when a symbol is qualified by a renamed import, unless one manually highlights the symbol alone while excluding the leading namespace and period.

Are the latter two items known limitations?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kostmo, thank you for your work, but please file new issues against relevant packages or at least ide-haskell in the future. It's hard enough to maintain this mess as it is.

So second point is an oversight on my part, should be fixed by ide-haskell-hasktags-0.0.6.

Third point seems to be a problem with ghc-mod -- it seems it doesn't resolve import aliases to files. Can't tell from the top of my head if it's easy to fix, or even fixable in principle -- it's very probable that it's a limitation of GHC API.

@lierdakil
Copy link
Contributor

Thanks for your efforts, that's appreciated.

You can usually find me on #ghc-mod at freenode (irc.freenode.net) -- nick's Lierdakil. Ping me and if I'm near IRC client, I'll try to answer. Bear in mind I'm on UTC+3 and usually busy in the afternoon, so 16 to 19 UTC would probably be the best time to catch me.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants