Thursday, July 16, 2015

Tilting at Windmills: Accessing Erlang man pages from Iex, Part 2:

Digging into the source code of iex, you find that the helpers are macros that pull apart the code and do introspection on the Elixir module to find the documentation. To get the documentation for a specific function in a module the code that eventually gets run is this:

iex> Code.get_docs(Atom, :docs)

[{{:to_char_list, 1}, 22, :def, [{:atom, [], nil}],
  "Converts an atom to a char list.\n\nInlined by the compiler.\n"},
 {{:to_string, 1}, 12, :def, [{:atom, [], nil}],
  "Converts an atom to string.\n\nInlined by the compiler.\n"}]

Where module is a Atom. All module names are Atoms. Code.get_docs returns a list of tuples describing the attributes of each of the functions exported by the module.

 {{function, arity }, line, kind, signature, text}

The initial tuple is the function name and arity. line is the line of the source file on which the function. kind is an atom that describes whether the exported function is a macro or a function.
signature is a list of tuples that define the arguments that the function takes, and lastly text is
the markdown documentation for the function.

If you're willing to fudge things a bit you can duplicate the parts of this function that the iex h command uses by parsing erlang man pages. Every erlang module supports the function module_info.

iex> Atom.module_info(:exports)

[__info__: 1, to_string: 1, to_char_list: 1, module_info: 0, module_info: 1]

iex> :et.module_info(:exports) 

[trace_me: 4, trace_me: 5, phone_home: 4, phone_home: 5, report_event: 4,
 report_event: 5, module_info: 0, module_info: 1]

Since the erlang man pages are created by a standard xml -> nroff process, it's relatively straightforward to split the nroff man page into documentation sections and to identify the function
documented by that section. So creating an ErlangCode.get_docs is possible by mapping the text
from the man page to the appropriate tuple in the export list. You can find code that does this in
the Erlman project on github.


Unfortunately, this is kind of a dead end since it's not general enough to be included in the main elixir source code. It requires that the erlang man pages be installed and that is simply something that can not be counted on. It's also unclear if the current version will even work on Windows with the man pages installed.

My next thought is "Is there a hook into iex commands that I can use to make this an optional addon?"