Next: Introduction [Contents]
• Introduction | ||
• Creating a Helm buffer | ||
• Helm attributes | ||
• Customizing Action Lists | ||
• Creating a Source | ||
• Creating a Class | ||
• Writing actions | ||
• Writing persistent actions | ||
— The Detailed Node Listing — Helm attributes | ||
---|---|---|
• Looking up Helm attributes | ||
• Mandatory attributes | ||
• Optional, but important attributes | ||
• helm keywords | ||
| ||
• sources | ||
• buffer | ||
• input | ||
Creating a Source | ||
• helm-source-sync | ||
• helm-source-in-buffer | ||
• helm-source-async | ||
• helm-source-dummy | ||
• helm-source-in-file | ||
• Help | ||
• Pre-filtering lines in a buffer | ||
Creating a Class | ||
• Create your own class inheriting from one of the main classes | ||
• Create your own class and Inherit from one of helm-type classes | ||
• Create your source from your own class | ||
• Write your own helm-type class | ||
Create your own class and Inherit from one of helm-type classes | ||
• Creating a new class using as parent a class inheriting itself from a helm-type-* class | ||
Next: Creating a Helm buffer, Previous: Top, Up: Top [Contents]
The best way to learn how to create a custom Helm command is to read the source code1 and look at examples.
A good place to start is the source file ‘helm-info.el’2. This source file is fairly short and straightforward.
That being said, we’ll try to go over some basic ideas in this manual.
Next: Helm attributes, Previous: Introduction, Up: Top [Contents]
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 :sources 'my-source :buffer "*helm my command*"))
helm
must be called with several keywords arguments, called
attributes.
Next: Customizing Action Lists, Previous: Creating a Helm buffer, Up: Top [Contents]
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 | ||
• Mandatory attributes | ||
• Optional, but important attributes | ||
• helm keywords |
Next: Mandatory attributes, Up: Helm attributes [Contents]
To learn about a single Helm attribute, use the documentation of the class you are using where all slots are documented.
Next: Optional but important attributes, Previous: Looking up Helm attributes, Up: Helm attributes [Contents]
You have to give at least a name to your source and a list of
candidates. 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.
Next: helm
keywords, Previous: Mandatory attributes, Up: Helm attributes [Contents]
Previous: Optional but important attributes, Up: Helm attributes [Contents]
helm
keywords• sources | ||
• buffer | ||
• input |
Next: buffer
, Up: helm
keywords [Contents]
:sources
Expects a source of the form:
Where alists are the resulting value of functions building sources,
that is all the helm-build-*
function or the helm-make-source
function, don’t use directly alists when writing sources. See
examples in next section.
Next: input
, Previous: sources
, Up: helm
keywords [Contents]
:buffer
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.
Previous: buffer
, Up: helm
keywords [Contents]
:input
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*"))
Next: Creating a Source, Previous: Helm attributes, Up: Top [Contents]
It’s possible to change the default list of actions for various
existing Helm commands. The actions are typically held in variables
called helm-type-foo-actions
, for instance helm-type-file-actions
,
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
helm-add-action-to-source
or helm-add-action-to-source-if
. These
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.
Also see helm-delete-action-from-source
, and
helm-source-add-action-to-source-if
.
Next: Creating a Class, Previous: Customizing Action Lists, Up: Top [Contents]
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
Put candidates in a list
helm-source-in-buffer
Put candidates in a buffer
helm-source-async
Get candidates asynchronously using the output of a process.
helm-source-dummy
Use helm-pattern
as candidate.
helm-source-in-file
Get candidates from the lines of a named
file using helm-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-source-sync | ||
• helm-source-in-buffer | ||
• helm-source-async | ||
• helm-source-dummy | ||
• helm-source-in-file | ||
• Help | ||
• Pre-filtering lines in a buffer |
Next: helm-source-in-buffer
, Up: Creating a Source [Contents]
helm-source-sync
Put candidates in a list
(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*")
Next: helm-source-async
, Previous: helm-source-sync
, Up: Creating a Source [Contents]
helm-source-in-buffer
Put candidates in a buffer
(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*")
Next: helm-source-dummy
, Previous: helm-source-in-buffer
, Up: Creating a Source [Contents]
helm-source-async
Get candidates asynchronously using the output of a process.
(helm :sources (helm-build-async-source "test2" :candidates-process (lambda () (start-process "echo" nil "echo" "a\nb\nc\nd\ne"))) :buffer "*helm async source*")
Next: helm-source-in-file
, Previous: helm-source-async
, Up: Creating a Source [Contents]
helm-source-dummy
Use helm-pattern
as candidate
(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*")
Next: Help, Previous: helm-source-dummy
, Up: Creating a Source [Contents]
helm-source-in-file
Get candidates from the lines of a named file using
helm-source-in-buffer
.
(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*")
Next: Pre-filtering lines in a buffer, Previous: helm-source-in-file
, Up: Creating a Source [Contents]
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
C-c ?=.
Previous: Help, Up: Creating a Source [Contents]
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 provide
‘hl-todo-regexp’ but you could use any regexp to do the same thing.
The ‘: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
‘helm-buffer’.
(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 ‘:data’ slot:
(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*"))
Next: Writing actions, Previous: Creating a Source, Up: Top [Contents]
Next: Create your own class and Inherit from one of helm-type classes, Up: Creating a Class [Contents]
(defclass my-helm-class (helm-source-sync) ((candidates :initform '("foo" "bar" "baz")))) (helm :sources (helm-make-source "test" 'my-helm-class) :buffer "*helm test*")
This is same as creating your source with:
(helm :sources (helm-build-sync-source "test" :candidates '("foo" "bar" "baz")) :buffer "*helm test*")
Next: Create your source from your own class, Previous: Create your own class inheriting from one of the main classes, Up: Creating a Class [Contents]
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 helm-type-* class |
helm-type-*
classSometimes, you may want to inherit from a class using itself a
helm-type-*
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:
(defclass helm-override-test-fav (helm-source) ())
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))))
(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.
Next: Write your own helm-type class, Previous: Create your own class and Inherit from one of helm-type classes, Up: Creating a Class [Contents]
Once your class is created, you have to use helm-make-source
to
build your source.
(helm-make-source "test" 'my-class :action 'foo [...other slots])
Previous: Create your source from your own class, Up: Creating a Class [Contents]
You will find several examples in the ‘helm-types.el’3 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 :primary
and
:before
of defmethod
. This allows you to override different slots
of the inheriting type class in your new class.
Next: Writing persistent actions, Previous: Creating a Class, Up: Top [Contents]
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)
Previous: Writing actions, Up: Top [Contents]
The way to specify persistent-action is to use the slot
:persistent-action
to specify the function Helm will run when using
C-j or C-z. If you don’t specify this helm will
run the first action of the action.
You can also specify additional persistent actions, which must be bound to keys other than C-j or C-z.
(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 C-j or C-z.
http://blog.codinghorror.com/learn-to-read-the-source-luke/
https://github.com/emacs-helm/helm/blob/master/helm-info.el
https://github.com/emacs-helm/helm/blob/master/helm-types.el