mirror of https://github.com/Chizi123/.emacs.d.git

Chizi123
2018-11-18 76bbd07de7add0f9d13c6914f158d19630fe2f62
commit | author | age
5cb5f7 1 ;;; helm-source.el --- Helm source creation. -*- lexical-binding: t -*-
C 2
3 ;; Copyright (C) 2015 ~ 2018  Thierry Volpiatto <thierry.volpiatto@gmail.com>
4
5 ;; Author: Thierry Volpiatto <thierry.volpiatto@gmail.com>
6 ;; URL: http://github.com/emacs-helm/helm
7
8 ;; This program is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation, either version 3 of the License, or
11 ;; (at your option) any later version.
12
13 ;; This program is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ;; GNU General Public License for more details.
17
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21 ;;; Commentary:
22
23 ;; Interface to create helm sources easily.
24 ;; Actually the eieo objects are transformed in alist for compatibility.
25 ;; In the future this package should allow creating source as eieo objects
26 ;; without conversion to alist, teaching helm to read such a structure.
27 ;; The compatibility with alists would be kept.
28
29 ;;; Code:
30
31 (require 'cl-lib)
32 (require 'eieio)
33 (require 'helm-lib)
34
35 (defvar helm-fuzzy-sort-fn)
36 (defvar helm-fuzzy-match-fn)
37 (defvar helm-fuzzy-search-fn)
38
39 (declare-function helm-init-candidates-in-buffer "helm.el")
40 (declare-function helm-interpret-value "helm.el")
41 (declare-function helm-fuzzy-highlight-matches "helm.el")
42
43
44 (defgeneric helm--setup-source (source)
45   "Prepare slots and handle slot errors before creating a helm source.")
46
47 (defgeneric helm-setup-user-source (source)
48   "Allow users modifying slots in SOURCE just before creation.")
49
50
51 ;;; Classes for sources
52 ;;
53 ;;
54 (defclass helm-source ()
55   ((name
56     :initarg :name
57     :initform nil
58     :custom string
59     :documentation
60     "  The name of the source.
61   A string which is also the heading which appears
62   above the list of matches from the source. Must be unique.")
63
64    (header-name
65     :initarg :header-name
66     :initform nil
67     :custom function
68     :documentation
69     "  A function returning the display string of the header.
70   Its argument is the name of the source. This attribute is useful to
71   add an additional information with the source name.
72   It doesn't modify the name of the source.")
73
74    (init
75     :initarg :init
76     :initform nil
77     :custom function
78     :documentation
79     "  Function called with no parameters when helm is started.
80   It is useful for collecting current state information which can be
81   used to create the list of candidates later.
82   Initialization of `candidates-in-buffer' is done here
83   with `helm-init-candidates-in-buffer'.")
84
85    (candidates
86     :initarg :candidates
87     :initform nil
88     :custom (choice function list)
89     :documentation
90     "  Specifies how to retrieve candidates from the source.
91   It can either be a variable name, a function called with no parameters
92   or the actual list of candidates.
93
94   The list must be a list whose members are strings, symbols
95   or (DISPLAY . REAL) pairs.
96
97   In case of (DISPLAY . REAL) pairs, the DISPLAY string is shown
98   in the Helm buffer, but the REAL one is used as action
99   argument when the candidate is selected. This allows a more
100   readable presentation for candidates which would otherwise be,
101   for example, too long or have a common part shared with other
102   candidates which can be safely replaced with an abbreviated
103   string for display purposes.
104
105   Note that if the (DISPLAY . REAL) form is used then pattern
106   matching is done on the displayed string, not on the real
107   value.")
108
109    (update
110     :initarg :update
111     :initform nil
112     :custom function
113     :documentation
114     "  Function called with no parameters at before \"init\" function
115   when `helm-force-update' is called.")
116
117    (cleanup
118     :initarg :cleanup
119     :initform nil
120     :custom function
121     :documentation
122     "  Function called with no parameters when *helm* buffer is
123   closed. It is useful for killing unneeded candidates buffer.
124
125   Note that the function is executed BEFORE performing action.")
126
127    (keymap
128     :initarg :keymap
129     :initform helm-map
130     :custom sexp
131     :documentation
132     "  Specific keymap for this source.
133   default value is `helm-map'.")
134
135    (action
136     :initarg :action
137     :initform 'identity
138     :custom (alist :key-type string
139                    :value-type function)
140     :documentation
141     "  An alist of (DISPLAY . FUNCTION) pairs, a variable name  or a function.
142   FUNCTION is called with one parameter: the selected candidate.
143
144   An action other than the default can be chosen from this list
145   of actions for the currently selected candidate (by default
146   with TAB). The DISPLAY string is shown in the completions
147   buffer and the FUNCTION is invoked when an action is
148   selected. The first action of the list is the default.
149
150   You should use `helm-make-actions' to build this alist easily.")
151
152    (persistent-action
153     :initarg :persistent-action
154     :initform nil
155     :custom function
156     :documentation
157     "  Can be a either a Function called with one parameter (the
158   selected candidate) or a cons cell where first element is this
159   same function and second element a symbol (e.g never-split)
160   that inform `helm-execute-persistent-action' to not split his
161   window to execute this persistent action.
162   Example:
163
164     (defun foo-persistent-action (candidate)
165        (do-something candidate))
166
167     :persistent-action '(foo-persistent-action . never-split) ; Don't split
168   or
169     :persistent-action 'foo-persistent-action ; Split
170
171   When specifying :persistent-action by slot directly, foo-persistent-action
172   will be executed without quitting helm when hitting `C-j'.
173
174   Note that other persistent actions can be defined using other
175   bindings than `C-j' by simply defining an interactive function bound
176   to a key in the keymap source.
177   The function should create a new attribute in source before calling
178   `helm-execute-persistent-action' on this attribute.
179   Example:
180
181      (defun helm-ff-persistent-delete ()
182        \"Delete current candidate without quitting.\"
183        (interactive)
184        (with-helm-alive-p
185          (helm-attrset 'quick-delete '(helm-ff-quick-delete . never-split))
186          (helm-execute-persistent-action 'quick-delete)))
187
188   This function is then bound in `helm-find-files-map'.")
189
190    (persistent-action-if
191     :initarg :persistent-action-if
192     :initform nil
193     :custom function
194     :documentation
195     "  Similar from persistent action but it is a function that should
196   return an object suitable for persistent action when called , i.e. a
197   function or a cons cell.
198   Example:
199
200      (defun foo-persistent-action (candidate)
201        (cond (something
202               ;; Don't split helm-window.
203               (cons (lambda (_ignore)
204                       (do-something candidate))
205                     'no-split))
206              ;; Split helm-window.
207              (something-else
208               (lambda (_ignore)
209                 (do-something-else candidate)))))
210
211      :persistent-action-if 'foo-persistent-action
212
213   Here when hitting `C-j' one of the lambda's will be executed
214   depending on something or something-else condition, splitting or not
215   splitting as needed.
216   See `helm-find-files-persistent-action-if' definition as another example.")
217
218    (persistent-help
219     :initarg :persistent-help
220     :initform nil
221     :custom string
222     :documentation
223     "  A string to explain persistent-action of this source. It also
224   accepts a function or a variable name.
225   It will be displayed in `header-line' or in `minibuffer' depending
226   of value of `helm-echo-input-in-header-line' and `helm-display-header-line'.")
227
228    (help-message
229     :initarg :help-message
230     :initform nil
231     :custom (choice string function)
232     :documentation
233     "  Help message for this source.
234   If not present, `helm-help-message' value will be used.")
235
236    (multiline
237     :initarg :multiline
238     :initform nil
239     :custom (choice boolean integer)
240     :documentation
241     "  Allow multiline candidates.
242   When non-nil candidates will be separated by `helm-candidate-separator'.
243   You can customize the color of this separator with `helm-separator' face.
244   Value of multiline can be an integer which specify the maximum size of the
245   multiline string to display, if multiline string is longer than this value
246   it will be truncated.")
247
248    (requires-pattern
249     :initarg :requires-pattern
250     :initform nil
251     :custom integer
252     :documentation
253     "  If present matches from the source are shown only if the
254   pattern is not empty. Optionally, it can have an integer
255   parameter specifying the required length of input which is
256   useful in case of sources with lots of candidates.")
257
258    (candidate-transformer
259     :initarg :candidate-transformer
260     :initform nil
261     :custom (choice function list)
262     :documentation
263     "  It's a function or a list of functions called with one argument
264   when the completion list from the source is built. The argument
265   is the list of candidates retrieved from the source. The
266   function should return a transformed list of candidates which
267   will be used for the actual completion.  If it is a list of
268   functions, it calls each function sequentially.
269
270   This can be used to transform or remove items from the list of
271   candidates.
272
273   Note that `candidates' is run already, so the given transformer
274   function should also be able to handle candidates with (DISPLAY
275   . REAL) format.")
276
277    (filtered-candidate-transformer
278     :initarg :filtered-candidate-transformer
279     :initform nil
280     :custom (choice function list)
281     :documentation
282     "  It has the same format as `candidate-transformer', except the
283   function is called with two parameters: the candidate list and
284   the source.
285
286   This transformer is run on the candidate list which is already
287   filtered by the current pattern. While `candidate-transformer'
288   is run only once, it is run every time the input pattern is
289   changed.
290
291   It can be used to transform the candidate list dynamically, for
292   example, based on the current pattern.
293
294   In some cases it may also be more efficent to perform candidate
295   transformation here, instead of with `candidate-transformer'
296   even if this transformation is done every time the pattern is
297   changed.  For example, if a candidate set is very large then
298   `candidate-transformer' transforms every candidate while only
299   some of them will actually be displayed due to the limit
300   imposed by `helm-candidate-number-limit'.
301
302   Note that `candidates' and `candidate-transformer' is run
303   already, so the given transformer function should also be able
304   to handle candidates with (DISPLAY . REAL) format.")
305
306    (filter-one-by-one
307     :initarg :filter-one-by-one
308     :initform nil
309     :custom (choice function list)
310     :documentation
311     "  A transformer function that treat candidates one by one.
312   It is called with one arg the candidate.
313   It is faster than `filtered-candidate-transformer' or
314   `candidate-transformer', but should be used only in sources
315   that recompute constantly their candidates, e.g `helm-source-find-files'.
316   Filtering happen early and candidates are treated
317   one by one instead of re-looping on the whole list.
318   If used with `filtered-candidate-transformer' or `candidate-transformer'
319   these functions should treat the candidates transformed by the
320   `filter-one-by-one' function in consequence.")
321
322    (display-to-real
323     :initarg :display-to-real
324     :initform nil
325     :custom function
326     :documentation
327     "  Transform the selected candidate when passing it to action.
328
329   Function called with one parameter, the selected candidate.
330
331   Avoid recomputing all candidates with candidate-transformer
332   or filtered-candidate-transformer to give a new value to REAL,
333   instead the selected candidate is transformed only when passing it
334   to action.
335
336   Note that this is NOT a transformer,
337   so the display will not be modified by this function.")
338
339    (real-to-display
340     :initarg :real-to-display
341     :initform nil
342     :custom function
343     :documentation
344     "  Recompute all candidates computed previously with other transformers.
345
346   Function called with one parameter, the selected candidate.
347
348   The real value of candidates will be shown in display.
349   Note: This have nothing to do with display-to-real.
350   It is unuseful as the same can be performed by using more than
351   one function in transformers, it is kept only for backward compatibility.")
352
353    (marked-with-props
354     :initarg :marked-with-props
355     :initform nil
356     :custom (choice boolean symbol)
357     :documentation
358     "  Get candidates with their properties in `helm-marked-candidates'.
359   Allow using the FORCE-DISPLAY-PART of `helm-get-selection' in marked
360   candidates, use t or 'withprop to pass it to `helm-get-selection'.")
361
362    (action-transformer
363     :initarg :action-transformer
364     :initform nil
365     :custom (choice function list)
366     :documentation
367     "  It's a function or a list of functions called with two
368   arguments when the action list from the source is
369   assembled. The first argument is the list of actions, the
370   second is the current selection.  If it is a list of functions,
371   it calls each function sequentially.
372
373   The function should return a transformed action list.
374
375   This can be used to customize the list of actions based on the
376   currently selected candidate.")
377
378    (pattern-transformer
379     :initarg :pattern-transformer
380     :initform nil
381     :custom (choice function list)
382     :documentation
383     "  It's a function or a list of functions called with one argument
384   before computing matches. Its argument is `helm-pattern'.
385   Functions should return transformed `helm-pattern'.
386
387   It is useful to change interpretation of `helm-pattern'.")
388
389    (candidate-number-limit
390     :initarg :candidate-number-limit
391     :initform nil
392     :custom integer
393     :documentation
394     "  Override `helm-candidate-number-limit' only for this source.")
395
396    (volatile
397     :initarg :volatile
398     :initform nil
399     :custom boolean
400     :documentation
401     "  Indicates the source assembles the candidate list dynamically,
402   so it shouldn't be cached within a single Helm
403   invocation. It is only applicable to synchronous sources,
404   because asynchronous sources are not cached.")
405
406    (match
407     :initarg :match
408     :initform nil
409     :custom (choice function list)
410     :documentation
411     "  List of functions called with one parameter: a candidate. The
412   function should return non-nil if the candidate matches the
413   current pattern (see variable `helm-pattern').
414
415   When using `candidates-in-buffer' its default value is `identity' and
416   don't have to be changed, use the `search' slot instead.
417
418   This attribute allows the source to override the default
419   pattern matching based on `string-match'. It can be used, for
420   example, to implement a source for file names and do the
421   pattern matching on the basename of files, since it's more
422   likely one is typing part of the basename when searching for a
423   file, instead of some string anywhere else in its path.
424
425   If the list contains more than one function then the list of
426   matching candidates from the source is constructed by appending
427   the results after invoking the first function on all the
428   potential candidates, then the next function, and so on. The
429   matching candidates supplied by the first function appear first
430   in the list of results and then results from the other
431   functions, respectively.
432
433   This attribute has no effect for asynchronous sources (see
434   attribute `candidates'), since they perform pattern matching
435   themselves.
436
437   Note that FUZZY-MATCH slot will overhide value of this slot.")
438
439    (fuzzy-match
440     :initarg :fuzzy-match
441     :initform nil
442     :custom boolean
443     :documentation
444     "  Enable fuzzy matching in this source.
445   This will overwrite settings in MATCH slot, and for
446   sources built with child class `helm-source-in-buffer' the SEARCH slot.
447   This is an easy way of enabling fuzzy matching, but you can use the MATCH
448   or SEARCH slots yourself if you want something more elaborated, mixing
449   different type of match (See `helm-source-buffers' class for example).
450
451   This attribute is not supported for asynchronous sources
452   since they perform pattern matching themselves.")
453
454    (redisplay
455     :initarg :redisplay
456     :initform 'identity
457     :custom (choice list function)
458     :documentation
459     "  A function or a list of functions to apply to current list
460   of candidates when redisplaying buffer with `helm-redisplay-buffer'.
461   This is only interesting for modifying and redisplaying the whole list
462   of candidates in async sources.
463   It uses `identity' by default for when async sources are mixed with
464   normal sources, in this case these normal sources are not modified and
465   redisplayed as they are.")
466
467    (nomark
468     :initarg :nomark
469     :initform nil
470     :custom boolean
471     :documentation
472     "  Don't allow marking candidates when this attribute is present.")
473
474    (nohighlight
475     :initarg :nohighlight
476     :initform nil
477     :custom boolean
478     :documentation
479     "  Disable highlighting matches in this source.
480   This will disable generic highlighting of matches,
481   but some specialized highlighting can be done from elsewhere,
482   i.e from `filtered-candidate-transformer' or `filter-one-by-one' slots.
483   So use this to either disable completely highlighting in your source,
484   or to disable highlighting and use a specialized highlighting matches
485   function for this source.
486   Remember that this function should run AFTER all filter functions if those
487   filter functions are modifying face properties, though it is possible to
488   avoid this by using new `add-face-text-property' in your filter functions.")
489
490    (allow-dups
491     :initarg :allow-dups
492     :initform nil
493     :custom boolean
494     :documentation
495     "  Allow helm collecting duplicates candidates.")
496
497    (history
498     :initarg :history
499     :initform nil
500     :custom symbol
501     :documentation
502     "  Allow passing history variable to helm from source.
503   It should be a quoted symbol.
504   Passing the history variable here have no effect
505   so add it also in the `helm' call with the :history keyword.
506   The main point of adding the variable here
507   is to make it available when resuming.")
508
509    (coerce
510     :initarg :coerce
511     :initform nil
512     :custom function
513     :documentation
514     "  It's a function called with one argument: the selected candidate.
515   This function is intended for type convertion. In normal case,
516   the selected candidate (string) is passed to action
517   function. If coerce function is specified, it is called just
518   before action function.
519
520   Example: converting string to symbol
521     (coerce . intern)")
522
523    (mode-line
524     :initarg :mode-line
525     :initform nil
526     :custom (choice string sexp)
527     :documentation
528     "  Source local `helm-mode-line-string' (included in
529   `mode-line-format'). It accepts also variable/function name.")
530
531    (header-line
532     :initarg :header-line
533     :initform nil
534     :custom (choice string function)
535     :documentation
536     "  Source local `header-line-format'.
537   It will be displayed in `header-line' or in `minibuffer' depending
538   of value of `helm-echo-input-in-header-line' and `helm-display-header-line'.
539   It accepts also variable/function name.")
540
541    (resume
542     :initarg :resume
543     :initform nil
544     :custom function
545     :documentation
546     "  Function called with no parameters at end of initialization
547   when `helm-resume' is started.
548   If this function try to do something against `helm-buffer', \(e.g updating,
549   searching etc...\) probably you should run it in a timer to ensure
550   `helm-buffer' is ready.")
551
552    (follow
553     :initarg :follow
554     :initform nil
555     :custom integer
556     :documentation
557     "  Enable `helm-follow-mode' for this source only.
558 With a value of 1 enable, a value of -1 or nil disable the mode.
559   See `helm-follow-mode' for more infos.")
560
561    (follow-delay
562     :initarg :follow-delay
563     :initform nil
564     :custom integer
565     :documentation
566     "  `helm-follow-mode' will execute persistent-action after this delay.
567   Otherwise value of `helm-follow-input-idle-delay' is used if non--nil,
568   If none of these are found fallback to `helm-input-idle-delay'.")
569
570    (multimatch
571     :initarg :multimatch
572     :initform t
573     :custom boolean
574     :documentation
575     "  Use the multi-match algorithm when non-nil.
576   I.e Allow specifying multiple patterns separated by spaces.
577   When a pattern is prefixed by \"!\" the negation of this pattern is used,
578   i.e match anything but this pattern.
579   It is the standard way of matching in helm and is enabled by default.
580   It can be used with fuzzy-matching enabled, but as soon helm detect a space,
581   each pattern will match by regexp and will not be fuzzy.")
582
583    (match-part
584     :initarg :match-part
585     :initform nil
586     :custom function
587     :documentation
588     "  Allow matching only one part of candidate.
589   If source contain match-part attribute, match is computed only
590   on part of candidate returned by the call of function provided
591   by this attribute. The function should have one arg, candidate,
592   and return only a specific part of candidate.
593   On async sources, as matching is done by the backend, this have
594   no effect apart for highlighting matches.")
595
596    (before-init-hook
597     :initarg :before-init-hook
598     :initform nil
599     :custom symbol
600     :documentation
601     "  A local hook that run at beginning of initilization of this source.
602   i.e Before the creation of `helm-buffer'.
603
604   Should be a variable (defined with defvar).
605   Can be also an anonymous function or a list of functions
606   directly added to slot, this is not recommended though.")
607
608    (after-init-hook
609     :initarg :after-init-hook
610     :initform nil
611     :custom symbol
612     :documentation
613     "  A local hook that run at end of initilization of this source.
614   i.e After the creation of `helm-buffer'.
615
616   Should be a variable.
617   Can be also an anonymous function or a list of functions
618   directly added to slot, this is not recommended though.")
619
620    (delayed
621     :initarg :delayed
622     :initform nil
623     :custom (choice null integer)
624     :documentation
625     "  This slot have no more effect and is just kept for backward compatibility.
626   Please don't use it.")
627
628    (group
629     :initarg :group
630     :initform helm
631     :custom symbol
632     :documentation
633     "  The current source group, default to `helm' when not specified."))
634
635   "Main interface to define helm sources."
636   :abstract t)
637
638 (defclass helm-source-sync (helm-source)
639   ((candidates
640     :initform '("ERROR: You must specify the `candidates' slot, either with a list or a function"))
641
642    (migemo
643     :initarg :migemo
644     :initform nil
645     :custom boolean
646     :documentation
647     "  Enable migemo.
648   When multimatch is disabled, you can give the symbol 'nomultimatch as value
649   to force not using generic migemo matching function.
650   In this case you have to provide your own migemo matching funtion
651   that kick in when `helm-migemo-mode' is enabled.
652   Otherwise it will be available for this source once `helm-migemo-mode'
653   is enabled when non-nil.")
654
655    (match-strict
656     :initarg :match-strict
657     :initform nil
658     :custom function
659     :documentation
660     "  When specifying a match function within a source and
661   helm-multi-match is enabled, the result of all matching
662   functions will be concatened, which in some cases is not what
663   is wanted. When using `match-strict' only this or these
664   functions will be used. You can specify those functions as a
665   list of functions or a single symbol function.
666
667   NOTE: This have the same effect as using :MULTIMATCH nil."))
668
669   "Use this class to make helm sources using a list of candidates.
670 This list should be given as a normal list, a variable handling a list
671 or a function returning a list.
672 Matching is done basically with `string-match' against each candidate.")
673
674 (defclass helm-source-async (helm-source)
675   ((candidates-process
676     :initarg :candidates-process
677     :initform nil
678     :custom function
679     :documentation
680     "  This attribute is used to define a process as candidate.
681   The value must be a process.
682
683   NOTE:
684   When building the source at runtime you can give directly a process
685   as value, otherwise wrap the process call into a function.
686   The process buffer should be nil, otherwise, if you use
687   `helm-buffer' give to the process a sentinel.")
688
689    (multimatch :initform nil))
690
691   "Use this class to define a helm source calling an external process.
692 The :candidates slot is not allowed even if described because this class
693 inherit from `helm-source'.")
694
695 (defclass helm-source-in-buffer (helm-source)
696   ((init
697     :initform 'helm-default-init-source-in-buffer-function)
698
699    (data
700     :initarg :data
701     :initform nil
702     :custom (choice list string)
703     :documentation
704     "  A string, a list or a buffer that will be used to feed the `helm-candidates-buffer'.
705   This data will be passed in a function added to the init slot and
706   the buffer will be build with `helm-init-candidates-in-buffer' or directly
707   with `helm-candidates-buffer' if data is a buffer.
708   This is an easy and fast method to build a `candidates-in-buffer' source.")
709
710    (migemo
711     :initarg :migemo
712     :initform nil
713     :custom boolean
714     :documentation
715     "  Enable migemo.
716   When multimatch is disabled, you can give the symbol 'nomultimatch as value
717   to force not using generic migemo matching function.
718   In this case you have to provide your own migemo matching funtion
719   that kick in when `helm-migemo-mode' is enabled.
720   Otherwise it will be available for this source once `helm-migemo-mode'
721   is enabled when non-nil.")
722
723    (candidates
724     :initform 'helm-candidates-in-buffer)
725
726    (volatile
727     :initform t)
728
729    (match
730     :initform '(identity))
731
732    (get-line
733     :initarg :get-line
734     :initform 'buffer-substring-no-properties
735     :custom function
736     :documentation
737     "  A function like `buffer-substring-no-properties' or `buffer-substring'.
738   This function converts region from point at line-beginning and point
739   at line-end in the `helm-candidate-buffer' to a string which will be displayed
740   in the `helm-buffer', it takes two args BEG and END.
741   By default, `helm-candidates-in-buffer' uses
742   `buffer-substring-no-properties' which does no conversion and doesn't carry
743   text properties.")
744
745    (search
746     :initarg :search
747     :initform '(helm-candidates-in-buffer-search-default-fn)
748     :custom (choice function list)
749     :documentation
750     "  List of functions like `re-search-forward' or `search-forward'.
751   Buffer search function used by `helm-candidates-in-buffer'.
752   By default, `helm-candidates-in-buffer' uses `re-search-forward'.
753   The function should take one arg PATTERN.
754   If your search function needs to handle negation like multimatch,
755   this function should returns in such case a cons cell of two integers defining
756   the beg and end positions to match in the line previously matched by
757   `re-search-forward' or similar, and move point to next line
758   (See how the `helm-mm-3-search-base' and `helm-fuzzy-search' functions are working).
759
760   NOTE: FUZZY-MATCH slot will overhide value of this slot.")
761
762    (search-strict
763     :initarg :search-strict
764     :initform nil
765     :custom function
766     :documentation
767     "  When specifying a search function within a source and
768   helm-multi-match is enabled, the result of all searching
769   functions will be concatened, which in some cases is not what
770   is wanted. When using `search-strict' only this or these
771   functions will be used. You can specify those functions as a
772   list of functions or a single symbol function.
773
774   NOTE: This have the same effect as using a nil value for
775         :MULTIMATCH slot."))
776
777   "Use this source to make helm sources storing candidates inside a buffer.
778
779 The buffer storing candidates is generated by `helm-candidate-buffer' function
780 and all search are done in this buffer, results are transfered to the `helm-buffer'
781 when done.
782 Contrarily to `helm-source-sync' candidates are matched using a function
783 like `re-search-forward' (see below documentation of `:search' slot) which makes
784 the search much faster than matching candidates one by one.
785 If you want to add search functions to your sources, don't use `:match' which
786 will raise an error, but `:search'.
787 See `helm-candidates-in-buffer' for more infos.")
788
789 (defclass helm-source-dummy (helm-source)
790   ((candidates
791     :initform '("dummy"))
792
793    (filtered-candidate-transformer
794     :initform (lambda (_candidates _source) (list helm-pattern)))
795
796    (multimatch
797     :initform nil)
798
799    (accept-empty
800     :initarg :accept-empty
801     :initform t
802     :custom boolean
803     :documentation
804     "  Allow exiting with an empty string.
805   You should keep the default value.")
806
807    (match
808     :initform 'identity)
809
810    (volatile
811     :initform t)))
812
813 (defclass helm-source-in-file (helm-source-in-buffer)
814   ((init :initform (lambda ()
815                      (let ((file (helm-attr 'candidates-file))
816                            (count 1))
817                        (with-current-buffer (helm-candidate-buffer 'global)
818                          (insert-file-contents file)
819                          (goto-char (point-min))
820                          (while (not (eobp))
821                            (add-text-properties
822                             (point-at-bol) (point-at-eol)
823                             `(helm-linum ,count))
824                            (cl-incf count)
825                            (forward-line 1))))))
826    (get-line :initform #'buffer-substring)
827    (candidates-file
828     :initarg :candidates-file
829     :initform nil
830     :custom string
831     :documentation
832     "  A filename.
833   Each line number of FILE is accessible with helm-linum property
834   from candidate display part."))
835
836   "The contents of the FILE will be used as candidates in buffer.")
837
838
839 ;;; Error functions
840 ;;
841 ;;
842 (defun helm-default-init-source-in-buffer-function ()
843   (helm-init-candidates-in-buffer 'global
844     '("ERROR: No buffer handling your data, use either the `init' slot or the `data' slot.")))
845
846
847 ;;; Internal Builder functions.
848 ;;
849 ;;
850 (defun helm--create-source (object)
851   "[INTERNAL] Build a helm source from OBJECT.
852 Where OBJECT is an instance of an eieio class."
853   (cl-loop for s in (object-slots object)
854            for slot-val = (slot-value object s)
855            when slot-val
856            collect (cons s (unless (eq t slot-val) slot-val))))
857
858 (defun helm-make-source (name class &rest args)
859   "Build a `helm' source named NAME with ARGS for CLASS.
860 Argument NAME is a string which define the source name, so no need to use
861 the keyword :name in your source, NAME will be used instead.
862 Argument CLASS is an eieio class object.
863 Arguments ARGS are keyword value pairs as defined in CLASS."
864   (declare (indent 2))
865   (let ((source (apply #'make-instance class name args)))
866     (setf (slot-value source 'name) name)
867     (helm--setup-source source)
868     (helm-setup-user-source source)
869     (helm--create-source source)))
870
871 (defun helm-make-type (class &rest args)
872   (let ((source (apply #'make-instance class args)))
873     (setf (slot-value source 'name) nil)
874     (helm--setup-source source)
875     (helm--create-source source)))
876
877 (defvar helm-mm-default-search-functions)
878 (defvar helm-mm-default-match-functions)
879
880 (defun helm-source-mm-get-search-or-match-fns (source method)
881   (let ((defmatch         (helm-aif (slot-value source 'match)
882                               (helm-mklist it)))
883         (defmatch-strict  (helm-aif (and (eq method 'match)
884                                          (slot-value source 'match-strict))
885                               (helm-mklist it)))
886         (defsearch        (helm-aif (and (eq method 'search)
887                                          (slot-value source 'search))
888                               (helm-mklist it)))
889         (defsearch-strict (helm-aif (and (eq method 'search-strict)
890                                          (slot-value source 'search-strict))
891                               (helm-mklist it)))
892         (migemo           (slot-value source 'migemo)))
893     (cl-case method
894       (match (cond (defmatch-strict)
895                    (migemo
896                     (append helm-mm-default-match-functions
897                             defmatch '(helm-mm-3-migemo-match)))
898                    (defmatch
899                     (append helm-mm-default-match-functions defmatch))
900                    (t helm-mm-default-match-functions)))
901       (search (cond (defsearch-strict)
902                     (migemo
903                      (append helm-mm-default-search-functions
904                              defsearch '(helm-mm-3-migemo-search)))
905                     (defsearch
906                      (append helm-mm-default-search-functions defsearch))
907                     (t helm-mm-default-search-functions))))))
908
909
910 ;;; Modifiers
911 ;;
912 (cl-defun helm-source-add-action-to-source-if (name fn source predicate
913                                                     &optional (index 4))
914   "Same as `helm-add-action-to-source-if' but for SOURCE defined as eieio object.
915 You can use this inside a `helm--setup-source' method for a SOURCE defined as
916 an eieio class."
917   (let* ((actions     (slot-value source 'action))
918          (action-transformers (slot-value source 'action-transformer))
919          (new-action  (list (cons name fn)))
920          (transformer (lambda (actions candidate)
921                         (cond ((funcall predicate candidate)
922                                (helm-append-at-nth
923                                 actions new-action index))
924                               (t actions)))))
925     (cond ((functionp actions)
926            (setf (slot-value source 'action) (list (cons "Default action" actions))))
927           ((listp actions)
928            (setf (slot-value source 'action) (helm-interpret-value actions source))))
929     (when (or (symbolp action-transformers) (functionp action-transformers))
930       (setq action-transformers (list action-transformers)))
931     (setf (slot-value source 'action-transformer)
932           (delq nil (append (list transformer) action-transformers)))))
933
934
935 ;;; Methods to build sources.
936 ;;
937 ;;
938 (defun helm-source--persistent-help-string (string source)
939   (substitute-command-keys
940    (concat "\\<helm-map>\\[helm-execute-persistent-action]: "
941            (or (format "%s (keeping session)" string)
942                (slot-value source 'header-line)))))
943
944 (defun helm-source--header-line (source)
945   (substitute-command-keys
946    (concat "\\<helm-map>\\[helm-execute-persistent-action]: "
947            (helm-aif (or (slot-value source 'persistent-action)
948                          (slot-value source 'action))
949                (cond ((and (symbolp it)
950                            (functionp it)
951                            (eq it 'identity))
952                       "Do Nothing")
953                      ((and (symbolp it)
954                            (boundp it)
955                            (listp (symbol-value it))
956                            (stringp (caar (symbol-value it))))
957                       (caar (symbol-value it)))
958                      ((or (symbolp it) (functionp it))
959                       (helm-symbol-name it))
960                      ((listp it)
961                       (let ((action (car it)))
962                         ;; It comes from :action ("foo" . function).
963                         (if (stringp (car action))
964                             (car action)
965                             ;; It comes from :persistent-action
966                             ;; (function . 'nosplit) Fix Issue #788.
967                             (if (or (symbolp action)
968                                     (functionp action))
969                                 (helm-symbol-name action)))))
970                      (t ""))
971              "")
972            " (keeping session)")))
973
974 (defmethod helm--setup-source :primary ((_source helm-source)))
975
976 (defmethod helm--setup-source :before ((source helm-source))
977   (when (slot-value source 'delayed)
978     (warn "Deprecated usage of helm `delayed' slot in `%s'"
979           (slot-value source 'name)))
980   (helm-aif (slot-value source 'keymap)
981       (and (symbolp it) (setf (slot-value source 'keymap) (symbol-value it))))
982   (helm-aif (slot-value source 'persistent-help)
983       (setf (slot-value source 'header-line)
984             (helm-source--persistent-help-string it source))
985     (setf (slot-value source 'header-line) (helm-source--header-line source)))
986   (when (and (slot-value source 'fuzzy-match) helm-fuzzy-sort-fn)
987     (setf (slot-value source 'filtered-candidate-transformer)
988           (helm-aif (slot-value source 'filtered-candidate-transformer)
989               (append (helm-mklist it)
990                       (list helm-fuzzy-sort-fn))
991             (list helm-fuzzy-sort-fn))))
992   (unless (slot-value source 'nohighlight)
993     (setf (slot-value source 'filtered-candidate-transformer)
994           (helm-aif (slot-value source 'filtered-candidate-transformer)
995               (append (helm-mklist it)
996                       (list #'helm-fuzzy-highlight-matches))
997             (list #'helm-fuzzy-highlight-matches))))
998   (when (numberp (helm-interpret-value (slot-value source 'multiline)))
999     (setf (slot-value source 'filtered-candidate-transformer)
1000           (helm-aif (slot-value source 'filtered-candidate-transformer)
1001               (append (helm-mklist it)
1002                       (list #'helm-multiline-transformer))
1003             (list #'helm-multiline-transformer)))))
1004
1005 (defmethod helm-setup-user-source ((_source helm-source)))
1006
1007 (defmethod helm--setup-source ((source helm-source-sync))
1008   (when (slot-value source 'fuzzy-match)
1009     (helm-aif (slot-value source 'match)
1010         (setf (slot-value source 'match)
1011               (append (helm-mklist it)
1012                       (list helm-fuzzy-match-fn)))
1013       (setf (slot-value source 'match) helm-fuzzy-match-fn)))
1014   (when (slot-value source 'multimatch)
1015     (setf (slot-value source 'match)
1016           (helm-source-mm-get-search-or-match-fns source 'match)))
1017   (helm-aif (and (null (slot-value source 'multimatch))
1018                  (slot-value source 'migemo))
1019       (unless (eq it 'nomultimatch) ; Use own migemo fn.
1020         (setf (slot-value source 'match)
1021               (append (helm-mklist (slot-value source 'match))
1022                       '(helm-mm-3-migemo-match))))))
1023
1024 (defmethod helm--setup-source ((source helm-source-in-buffer))
1025   (let ((cur-init (slot-value source 'init)))
1026     (helm-aif (slot-value source 'data)
1027         (setf (slot-value source 'init)
1028               (delq
1029                nil
1030                (list
1031                 (and (null (eq 'helm-default-init-source-in-buffer-function
1032                                cur-init))
1033                      cur-init)
1034                 (lambda ()
1035                   (helm-init-candidates-in-buffer
1036                       'global
1037                     (cond ((functionp it) (funcall it))
1038                           ((and (bufferp it) (buffer-live-p it))
1039                            (with-current-buffer it (buffer-string)))
1040                           (t it)))))))))
1041   (when (slot-value source 'fuzzy-match)
1042     (helm-aif (slot-value source 'search)
1043         (setf (slot-value source 'search)
1044               (append (helm-mklist it)
1045                       (list helm-fuzzy-search-fn)))
1046       (setf (slot-value source 'search) (list helm-fuzzy-search-fn))))
1047   (when (slot-value source 'multimatch)
1048     (setf (slot-value source 'search)
1049           (helm-source-mm-get-search-or-match-fns source 'search)))
1050   (helm-aif (and (null (slot-value source 'multimatch))
1051                  (slot-value source 'migemo))
1052       (unless (eq it 'nomultimatch)
1053         (setf (slot-value source 'search)
1054               (append (helm-mklist (slot-value source 'search))
1055                       '(helm-mm-3-migemo-search)))))
1056   (let ((mtc (slot-value source 'match)))
1057     (cl-assert (or (equal '(identity) mtc)
1058                    (eq 'identity mtc))
1059                nil "Invalid slot value for `match'")
1060     (cl-assert (eq (slot-value source 'volatile) t)
1061                nil "Invalid slot value for `volatile'")))
1062
1063 (defmethod helm--setup-source ((source helm-source-async))
1064   (cl-assert (null (slot-value source 'candidates))
1065              nil "Incorrect use of `candidates' use `candidates-process' instead")
1066   (cl-assert (null (slot-value source 'multimatch))
1067              nil "`multimatch' not allowed in async sources.")
1068   (cl-assert (null (slot-value source 'fuzzy-match))
1069              nil "`fuzzy-match' not supported in async sources."))
1070
1071 (defmethod helm--setup-source ((source helm-source-dummy))
1072   (let ((mtc (slot-value source 'match)))
1073     (cl-assert (or (equal '(identity) mtc)
1074                    (eq 'identity mtc))
1075                nil "Invalid slot value for `match'")
1076     (cl-assert (eq (slot-value source 'volatile) t)
1077                nil "Invalid slot value for `volatile'")
1078     (cl-assert (equal (slot-value source 'candidates) '("dummy"))
1079                nil "Invalid slot value for `candidates'")
1080     (cl-assert (eq (slot-value source 'accept-empty) t)
1081                nil "Invalid slot value for `accept-empty'")))
1082
1083
1084 ;;; User functions
1085 ;;
1086 ;;  Sources
1087 (defmacro helm-build-sync-source (name &rest args)
1088   "Build a synchronous helm source with name NAME.
1089 Args ARGS are keywords provided by `helm-source-sync'."
1090   (declare (indent 1))
1091   `(helm-make-source ,name 'helm-source-sync ,@args))
1092
1093 (defmacro helm-build-async-source (name &rest args)
1094   "Build a asynchronous helm source with name NAME.
1095 Args ARGS are keywords provided by `helm-source-async'."
1096   (declare (indent 1))
1097   `(helm-make-source ,name 'helm-source-async ,@args))
1098
1099 (defmacro helm-build-in-buffer-source (name &rest args)
1100   "Build a helm source with name NAME using `candidates-in-buffer' method.
1101 Args ARGS are keywords provided by `helm-source-in-buffer'."
1102   (declare (indent 1))
1103   `(helm-make-source ,name 'helm-source-in-buffer ,@args))
1104
1105 (defmacro helm-build-dummy-source (name &rest args)
1106   "Build a helm source with name NAME using `dummy' method.
1107 Args ARGS are keywords provided by `helm-source-dummy'."
1108   (declare (indent 1))
1109   `(helm-make-source ,name 'helm-source-dummy ,@args))
1110
1111 (defmacro helm-build-in-file-source (name file &rest args)
1112   "Build a helm source with NAME name using `candidates-in-files' method.
1113 Arg FILE is a filename, the contents of this file will be
1114 used as candidates in buffer.
1115 Args ARGS are keywords provided by `helm-source-in-file'."
1116   (declare (indent 1))
1117   `(helm-make-source ,name 'helm-source-in-file
1118      :candidates-file ,file ,@args))
1119
1120
1121 (provide 'helm-source)
1122
1123 ;; Local Variables:
1124 ;; byte-compile-warnings: (not obsolete)
1125 ;; coding: utf-8
1126 ;; indent-tabs-mode: nil
1127 ;; End:
1128
1129 ;;; helm-source ends here