-
-
Notifications
You must be signed in to change notification settings - Fork 392
Developing
The best way to learn how to create a custom Helm command is to read the source code and look at examples. A good place to start is the helm-info.el file, which is fairly short and straightforward.
That being said, we’ll try to go over some basic ideas in this Uncyclo.
The helm
function creates a Helm buffer with candidates to select and/or
take action on. The list of candidates is provided by one or more sources.
An example usage of helm
is below:
(defun my-first-helm-command ()
(interactive)
(helm :candidates 'my-source
:buffer "*helm my command*"))
helm
must be called with several keywords arguments, called attributes.
An attribute is a keyword that determines the behavior of the helm
function. There are a large number of attributes in Helm; some are mandatory,
while others are optional.
To learn about a single Helm attribute, use the
helm-describe-helm-attribute
command. This command allows you to select an
attribute and display its information in a Helm buffer.
To learn about several Helm attributes, use the helm-apropos
command. By
default, helm-apropos
includes Helm attributes as one of its
sources. Persistent action brings up the Help buffer for each Helm attribute.
The following are mandatory attributes; some attributes are conditionally mandatory; that is, they are mandatory if other attributes are not specified.
Attribute | Description |
---|---|
action | Mandatory if the type attribute is not provided. A list of (DISPLAY . FUNCTION) pairs or FUNCTION. FUNCTION is called with one parameter: the selected candidate. |
candidates | Mandatory if the candidates-in-buffer attribute is not provided. Specifies how to retrieve candidates from the source. It can either be a variable name, a function called with no parameters or the actual list of candidates. |
name | The name of the source. It is also the heading which appears above the list of matches from the source. Must be unique. |
Expects a source of the form:
- Single source (alist)
- Symbol naming the source
- List of sources (alist or symbol)
Examples are below:
;; alist
:candidates '((name . "test") (candidates . (a b c d)))
;; List of alists
:candidates '(((name . "test") (candidates . (a b c d)))
((name . "test2") (candidates . (e f g h))))
;; Symbol
:candidates 'helm-source-1
;; List of symbols
:candidates '(helm-source-1 helm-source-2 helm-source-3)
Optional but important.
The value for the :buffer
keyword helps the helm-resume
command retrieve
the Helm session.
The name of the buffer should be prefixed with helm
(e.g. *helm
Info*
). This is not mandatory, but it is good practice. It will, among other
things, allow Helm to automatically hide the buffer.
Even if you can still create source with alists, helm provides convenient basic classes to build sources, and allow you to create your own classes that inherit from these basics classes.
Here are the basic classes for creating a Helm source:
-
helm-source-sync
, which puts candidates in a list. -
helm-source-in-buffer
, which puts candidates in a buffer. -
helm-source-async
, which gets candidates asynchronously using the output of a process. -
helm-source-dummy
, which use thehelm-pattern
as candidate. -
helm-source-in-file
, which gets candidates from the lines of a named file usinghelm-source-in-buffer
.
For consistency, prefix your source names with helm-source-
(e.g. helm-source-info-emacs
).
For convenience, helm
provide macros prefixed by helm-build-
to build your
sources quickly, see examples below.
All the different slots are documented in docstring of each classes.
(helm-build-sync-source "test"
:candidates '(a b c d e))
(helm :sources (helm-build-sync-source "test"
:candidates '(a b c d e))
:buffer "*helm sync source*")
(helm-build-in-buffer-source "test1"
:data '(a b c d e))
(helm :sources (helm-build-in-buffer-source "test1"
:data '(a b c d e))
:buffer "*helm buffer source*")
(helm :sources (helm-build-async-source "test2"
:candidates-process
(lambda ()
(start-process "echo" nil "echo" "a\nb\nc\nd\ne")))
:buffer "*helm async source*")
To give a specific help to your Helm source, create a variable
helm-<my-source>-help-string
and bind it in your source with the
helm-message
slot. It will then will appear when you use C-h m
or C-c ?
.
(defclass my-helm-class (helm-source-sync)
((candidates :initform '("foo" "bar" "baz"))))
(helm :sources (helm-make-source "test" 'my-helm-class)
:buffer "*helm test*")
Is the same as creating your source with:
(helm :sources (helm-build-sync-source "test"
:candidates '("foo" "bar" "baz"))
:buffer "*helm test*")
Here an example from a helm user that store a list of favorite files in a file
~/.fav
to retrieve them quickly:
(defclass helm-test-fav (helm-source-in-file helm-type-file)
((candidates-file :initform "~/.fav")))
(helm :sources (helm-make-source "test" 'helm-test-fav)
:buffer "*helm test*")
Once your class is created, you have to use helm-make-source
to build your
source.
You will find several examples in the helm-types.el file. The main thing to
remember is to create an empty source and fill it using two defmethod’s, one
empty which should be a primary method and one which is a before method, use
for this the slots :primary
and :before
of defmethod
. This allows you to
override different slots of the inheriting type class in your new class.
Class names are currently a mess. Need to come up with a better convention.