Developing with the Helm Framework
- Creating a Helm buffer
- Helm attributes
- Customizing Action Lists
- Creating a Source
- Creating a Class
- Writing actions
- Writing persistent actions
That being said, we’ll try to go over some basic ideas in this Wiki.
Creating a Helm buffer
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 :sources 'my-source :buffer "*helm my command*"))
helm must be called with several keywords arguments, called attributes.
An attribute determines Helm behavior. There are a large number of attributes in Helm; some are mandatory, while others are optional.
NOTE: When creating sources you are using slots which are keywords describing how to build attributes, they have generally the same name as attributes but not always e.g the slot :data exists, but there is no such attribute.
Looking up Helm attributes
To learn about a single Helm attribute, use the documentation of the class you are using where all slots are documented.
You have to give at least a name to your source and a list of
The list of candidates is given with a variable containing candidates,
a function returning candidates or a list, the attribute depend on
which class you are using, e.g candidates for sync sources, for
in-buffer sources you have to build a buffer using
helm-init-candidates-in-buffer or for conveniency you can use the
:data slot which will build the candidate buffer for you. In async
sources the candidates-process attribute is used which is a function
with no arg that returns a process.
Optional, but important attributes
Expects a source of the form:
- Single source (alist)
- Symbol naming the source
- List of sources (alist or symbol)
Where alists are the resulting value of functions building sources,
that is all the
helm-build-* function or the
function, don’t use directly alists when writing sources.
See examples in next section.
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
Info*). This is not mandatory, but it is good practice. It will, among other
things, allow Helm to automatically hide the buffer.
The value for the
:input keyword is used to pre-fill the input of the helm window.
E.g. if the user is using helm to autocomplete and runs the autocomplete command, you could get the word at point and set
:input to that word. That word will then be pre-filled in the minibuffer.
(defun my-autocomplete-command () (interactive) (helm :sources 'my-source :input (word-at-point) :buffer "*helm my autocomplete command*"))
Customizing Action Lists
It’s possible to change the default list of actions for various
existing Helm commands. The actions are typically held in variables
helm-type-foo-actions, for instance
so search apropos for those. Each action in the list is the usual cons
of action label and action function.
Another higher-level approach is to use a pre-defined function such as
functions accept an action label, action function, the source to
modify (as a class symbol name, such as ‘helm-source-ffiles), and for
the latter, a predicate which determines if the action should be made
available for the candidate under point.
Creating a Source
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 the
helm-source-in-file, which gets candidates from the lines of a named file using
For consistency, prefix your source names with
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*")
(defun helm/test-default-action (candidate) (browse-url (format "http://www.google.com/search?q=%s" (url-hexify-string candidate)))) (helm :sources (helm-build-dummy-source "test" :action '(("Google" . helm/test-default-action))) :buffer "*helm test*")
(helm :sources (helm-build-in-file-source "test" "~/.emacs.d/init.el" :action (lambda (candidate) (let ((linum (with-helm-buffer (get-text-property 1 'helm-linum (helm-get-selection nil 'withprop))))) (find-file (with-helm-buffer (helm-attr 'candidates-file))) (goto-line linum)))) :buffer "*helm test*")
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 appear when you use
C-h m or
Pre-filtering lines in a buffer
Here’s an example of an in-buffer source that pre-filters lines to
those matching a certain regular expression. Then the pre-filtered
lines are narrowed as the user types. This uses hl-todo-mode which
hl-todo-regexp but you could use any regexp to do the same
:init function switches to the automatically created
buffer, which is returned by
(helm-candidate-buffer 'global), then
it deletes uninteresting lines, after which Helm presents the
remaining lines to the user. The
:get-line function is changed to
buffer-substring so that the properties are preserved in the
(defun helm-hl-todo-items () "Show `hl-todo'-keyword items in buffer." (helm :sources (helm-build-in-buffer-source "hl-todo items" :init (lambda () (with-current-buffer (helm-candidate-buffer 'global) (insert (with-helm-current-buffer (buffer-string))) (goto-char (point-min)) (delete-non-matching-lines hl-todo-regexp))) :get-line #'buffer-substring) :buffer "*helm hl-todo*"))
And it could be also written using the
(defun helm-hl-todo-items () "Show `hl-todo'-keyword items in buffer." (helm :sources (helm-build-in-buffer-source "hl-todo items" :data (current-buffer) :candidate-transformer (lambda (candidates) (cl-loop for c in candidates when (string-match hl-todo-regexp c) collect c)) :get-line #'buffer-substring) :buffer "*helm hl-todo*"))
Creating a Class
Create your own class inheriting from one of the main classes
(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*")
Create your own class and Inherit from one of helm-type classes
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*")
Creating a new class using as parent a class inheriting itself from a
Sometimes, you may want to inherit from a class using itself a
class but with one or more attributes of this class slightly modified
for your needs.
You may think that you only need to create your new class inheriting
from the class inheriting itself from the
helm-type-* class, but
this is not enough.
Here how to do, reusing the example above we modify the actions predefined by helm-type-file:
- Create a fake class:
(defclass helm-override-test-fav (helm-source) ())
- Create a method for this class
This method is used as a
:PRIMARY method, which mean that the similar
parent method, if some will not be used, in particular the
helm-source-in-file method which calls itself the
helm-source-in-buffer method, so to be sure these important methods
are used, use
call-next-method, see below.
(defmethod helm--setup-source ((source helm-override-test-fav)) (call-next-method) (let ((actions (slot-value source 'action))) (setf (slot-value source 'action) (helm-append-at-nth (symbol-value actions) '(("test" . ignore)) 1))))
- Create now your main class inheriting from your new overriding class
(defclass helm-test-fav (helm-source-in-file helm-type-file helm-override-test-fav) ((candidates-file :initform "~/.fav")))
Now when running helm with a source built from your new class you should see the new action you have added in second position to the other file action.
Create your source from your own class
Once your class is created, you have to use
helm-make-source to build your
(helm-make-source "test" 'my-class :action 'foo [...other slots])
Write your own helm-type class
You will find several examples in the helm-types.el file. The main thing to
remember is to create an empty class 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
defmethod. This allows you to
override different slots of the inheriting type class in your new class.
Actions are specified in the :action slot of your class, it is an alist composed of (ACTION_NAME . FUNCTION), it can be also a symbol defining a customizable action alist.
(defcustom helm-source-foo '(("Do this" . foo) ("Do that" . bar)) "A customizable action list." :group 'helm :type '(alist :key-type string :value-type function))
It is recommended however to use
helm-make-actions to define your
actions easily, it allow also to create actions with condition, e.g
(helm-make-actions "Do this" 'foo (lambda () (when (featurep 'something) "Do that")) 'bar)
Writing persistent actions
The way to specify persistent-action is to use the slot
:persistent-action to specify the function Helm will run when using
C-z. If you don’t specify this helm will run the first action of
You can also specify additional persistent actions, which must be bound to keys other than
(defun helm-foo-persistent-action () "Bind a new persistent action 'foo-action to foo function. foo function is an action function called with one arg candidate." (interactive) (with-helm-alive-p ;; never split means to not split the helm window when executing ;; this persistent action. If your source is using full frame you ;; will want your helm buffer to split to display a buffer for the ;; persistent action (if it needs one to display something). (helm-attrset 'foo-action '(foo . never-split)) (helm-execute-persistent-action 'foo-action)))
Then you bind your new persistent action to something else than
Class names are currently a mess. Need to come up with a better convention.