ghelp icon indicating copy to clipboard operation
ghelp copied to clipboard

Emacs generic Help

#+TITLE: ghelp

This package provides a generic help system similar to Emacs Help. Unlike Emacs Help, ghelp works for more major-modes and is extensible with backends.

Features

  • Unified entry command
  • Unified UI
  • Documentation history, you can search in history, go back/forward.

Currently supported backends

  • builtin Help
  • [[https://github.com/Wilfred/helpful][helpful]]
  • [[https://github.com/joaotavora/eglot][eglot]]
  • [[https://www.nongnu.org/geiser/][geiser]]
  • [[https://github.com/joaotavora/sly][sly]]

[[https://github.com/casouri/ghelp#screencasts][☞ Screencasts]]

  • Install & load Download the files and add them to load path.

With ~use-package~: #+BEGIN_SRC emacs-lisp (use-package ghelp) #+END_SRC Without ~use-package~: #+BEGIN_SRC emacs-lisp (require 'ghelp) #+END_SRC

  • Usage

| ~ghelp-describe~ | Describe a symbol in current major mode | | ~gehlp-describe-at-point~ | Describe symbol at point (without prompt) | | ~ghelp-resume~ | Reopen last page |

| ~ghelp-describe-elisp~ | Describe a Emacs symbol (like apropos) | | ~ghelp-describe-function~ | Describe a Elisp function/macro/keyboard macro | | ~ghelp-describe-variable~ | Describe a Elisp variable | | ~ghelp-describe-key~ | Describe a key sequence |

Normally ~ghelp-describe~ shows documentation of the symbol at point, If you want to query for a symbol (e.g., with completion), type =C-u= then ~ghelp-describe~.

  • Enable backends

Each backend are loaded automatically when you enabled the corresponding package. For example, when you load =helpful.el=, ghelp automatically loads its helpful backend.

  • In ghelp buffer A ghelp buffer is called a page. Each page is made of several entries. Each entry is a self-contained documentation. (For example, you could have a entry for a symbol as a function and another one for it as a variable.)

Commands you can use:

| Key | Command | |---------+--------------------------------| | =?= | show help | | =f/b= | go forward/backward in history | | =TAB= | next button | | =S-TAB= | previous button | | =h= | collapse/expand entry | | =g= | refresh page | | =q= | close page | | =s= | search/switch to a page |

For more bindings, type =?= in a ghelp buffer, or type =M-x ghelp-describe ghelp-page-mode-map RET=.

  • Customization If you want several major modes to share the same set of history and backends (like ~lisp-interaction-mode~ and ~emacs-lisp-mode~), add an entry ~(mode1 . mode2)~ to ~ghelp-mode-share-alist~, and ~mode1~ will share everything of ~mode2~.

You can customize faces: ~ghelp-entry~, ~ghelp-folded-entry~, and ~ghelp-entry-title~.

Normally if you call ~ghelp-describe-function~ it selects the backends to use by the current major-mode. If you want to look up some symbol with a specific backend, try ~(ghelp-describe-with-mode ’prompt 'mode)~. For example, you can bind #+BEGIN_SRC emacs-lisp (define-key (kbd "C-h C-e") (lambda () (interactive) (ghelp-describe-with-mode ’force-prompt ’emacs-lisp-mode))) #+END_SRC to look up Emacs Lisp symbols regardless of which major mode you are currently in.

  • Write a backend A backend is a function that takes two arguments ~COMMAND~ and ~DATA~.

If ~COMMAND~ is ~symbol~, return a string representing the symbol that the user wants documentation for.

If ~COMMAND~ is ~doc~, return the documentation for ~SYMBOL~, where ~SYMBOL~ is from ~DATA~: #+BEGIN_SRC emacs-lisp (:symbol-name SYMBOL :marker MARKER) #+END_SRC And ~MARKER~ is the marker at the point where user invoked ~ghelp-describe~. Returned documentation should be a string ending with a newline. Return nil if no documentation is found.

Below is an example backend that gets the symbol and then the documentation and returns them. It only recognizes “woome”, “veemo”, “love” and “tank”. #+BEGIN_SRC emacs-lisp (defun ghelp-dummy-backend (command data) (pcase command ('symbol (completing-read "Symbol: " '("woome" "veemo" "love" "tank"))) ('doc (pcase (plist-get data :symbol-name) ("woome" "Woome!!\n") ("veemo" "Veemo!!\n") ("love" "Peace!!\n") ("tank" "TANK! THE! BEST!\n"))))) #+END_SRC You can try this out by typing ~M-x ghelp-dummy RET~.

Once you have a backend, register it by #+BEGIN_SRC emacs-lisp (ghelp-register-backend 'major-mode #'your-backend-function) #+END_SRC

  • Advanced backend

** Returned documentation Besides a string, the returned documentation could carry more information.

First, it can be a list of form ~(TITLE BODY)~ where ~TITLE~ is the title for your documentation, and ~BODY~ is the body of your documentation. This way you can use a title other than the symbol name.

Second, you can return multiple documentations by returning a list ~((TITLE BODY)...)~, where each element is a ~(TITLE BODY)~ form.

** Asynchronous backend Ghelp also supports asynchronous backends. Instead of returning the documentation immediately, a backend can return a callback function. This function should have a signature like ~(display-fn &rest _)~. ~display-fn~ is a function that takes a single argument ~doc~. ~&rest _~ allows ghelp to extend this interface in the future.

An example:

#+begin_src emacs-lisp (lambda (display-fn) (backend-async-call (lambda (doc) (funcall display-fn "(documentation)")))) #+end_src

** Use buttons in your documentation You can use buttons in your documentation as long they are text buttons made by text properties, rather than overlay buttons. After all your are returning a string, which doesn’t carry overlays.

However, one problem might arise if the command invoked by your button needs some information, like the symbol that this documentation page is describing. You can get that by ~(ghelp-get-page-data)~, which returns a plist of form #+begin_src emacs-lisp (:symbol-name SYMBOL :mode MODE :marker MARKER) #+end_src ~SYMBOL~ and ~MARKER~ are the same as before, ~MODE~ is the major mode.

** Use a phony major mode Normally each backend is tied to an actual major mode. But if you want to write a backend that doesn’t associate with any major mode, like a dictionary, you can use ~ghelp-describe-with-mode~, and use ~dictionary~ as your “major mode”.

** Backend that can support undetermined major modes

Backends like eglot can support a wide range of major modes that can’t be determined ahead of time. For this kinds of backends, use ~t~ for the ~MODE~ argument when registering them:

#+begin_src emacs-lisp (ghelp-register-backend t #'your-backend-function) #+end_src

Your backend function should support the ~available-p~ command, in addition to the ~symbol~ and ~doc~ command. It should return t/nil indication the backend’s availability in the current buffer.

  • Screencasts Eglot

[[./ghelp-eglot-800.gif]]

Helpful

[[./ghelp-helpful-800.gif]]

Sly

[[./ghelp-sly.png]]