1 ;;;_ fileset-whole.el --- Commands and data applying to filesets as a whole
5 ;; Copyright (C) 2011 Tom Breton (Tehom)
7 ;; Author: Tom Breton (Tehom) <tehom@panix.com>
8 ;; Keywords: convenience
10 ;; This file is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; This file is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to
22 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
36 ;;;_ . fileset-whole-alist
37 (defcustom fileset-whole-alist
39 "Alist associating fileset names to keyed data"
43 (string :tag
"Name" :value
"")
48 (put 'fileset-whole-alist
'risky-local-variable t
)
50 ;;;_ . fileset-whole-commands
51 (defcustom fileset-whole-commands
54 magit-status
(default-directory))
58 fileset-whole-apply-compile
59 ("make -C" default-directory
))
69 (fileset-whole-pick-file name
)))
72 "List of commands that apply to whole filesets.
74 Before the command is applied, each arg is evalled with the
77 `fileset' - the fileset.
78 `fileset-name' - the name of the fileset
79 `fileset-whole' - other data associated with the fileset, if any.
80 `default-directory' the root directory of the project, if any.
82 Then the command is applied to the list of args.
84 It is the user's resposibility to ensure that commands and
85 functions called in arguments are available; consider using
89 ;;$$IMPROVE ME Add a hotkey and put it into some keymap
90 ;;$$IMPROVE ME Add a field saying how to find the buffers it
91 ;;creates, given its return value.
92 :type
'(repeat :tag
"Commands"
93 (list :tag
"Definition" :value
("")
95 (choice :tag
"Command"
96 (function :tag
"Function"))
97 (repeat :tag
"Argument List"
98 (choice :tag
"Arguments"
99 ;;$$IMPROVE ME List the bound symbols as options
103 (put 'fileset-whole-commands
'risky-local-variable t
)
105 ;;For now, we don't contemplate multiple filesets applying to one
106 ;;buffer. Could treat a list of them differently.
107 (defvar fileset-whole-name-here nil
108 "The fileset that contains this buffer, if any." )
109 (make-variable-buffer-local 'fileset-whole-name-here
)
110 (put 'fileset-whole-name-here
'permanent-local t
)
111 ;;;_ , Setting up menus
112 ;;;_ . fileset-whole-setup-menu
113 (defun fileset-whole-setup-menu ()
114 "Add the commands in fileset-whole-commands to fileset menu."
115 ;;When is this triggered?
116 ;;And see `filesets-get-cmd-menu'. Either add to it or add another
120 nil
;;Should this be `filesets-menu-in-menu'?
121 (append filesets-menu-path
(list filesets-menu-name
"# Filesets"))
122 ["Edit Filesets' Data" fileset-whole-edit
]
125 ;;;_ . fileset-whole-cmds-to-menu
126 (defun fileset-whole-cmds-to-menu ()
127 "Add fileset-whole commands to filesets command menu."
133 nil
;;Should this be `filesets-menu-in-menu'?
134 (append filesets-menu-path
(list filesets-menu-name
"+ Commands"))
135 `[,name
(fileset-whole-run-cmd
137 (fileset-whole-read-fileset))])))
138 fileset-whole-commands
)
141 ;;;_ . fileset-whole-add-buffer
143 ;;Add a "created" buffer such as gdb, eshell, or magit make to the
144 ;;menus, in a section paralleling the list of files.
146 ;;;_ . fileset-whole-setup-files
148 (defun fileset-whole-setup-files ()
149 "Run a hook in each currently open buffer that any fileset applies to."
151 ;;$$FACTOR ME Several parts: Running something in all relevant
152 ;;buffers (parms: fileset-name). The hook. Running the hook this
154 ;;$$DESIGN ABOUT ME How and when to trigger this. There are no
155 ;;obvious hooks in fileset.
161 ;;For each one that's already open, with that buffer current,
162 ;;run hooks. Default hook will just set `fileset-whole-name-here'.
164 ;;;_ . fileset-whole-init
166 (defun fileset-whole-init ()
167 "Set up fileset-whole on top of filesets"
169 (fileset-whole-setup-menu)
170 (fileset-whole-cmds-to-menu))
172 ;;;_ . fileset-whole-cmd->fn
173 (defun fileset-whole-cmd->fn
(cmd)
174 "Return the function field of CMD"
176 ;;;_ . fileset-whole-cmd->args
177 (defun fileset-whole-cmd->args
(cmd)
178 "Return the args field of CMD"
180 ;;;_ . fileset-whole-entry->alist
181 (defun fileset-whole-entry->alist
(entry)
182 "Return the alist of ENTRY"
184 ;;;_ . fileset-whole-data-get
185 (defun fileset-whole-data-get (entry key
&optional default carp
)
186 "Extract the value for KEY in the data part of fileset ENTRY.
187 Return DEFAULT if not found. Return (car VALUE) if CARP is non-nil."
189 (fileset-whole-entry->alist entry
) key default carp
))
191 ;;;_ , Running commands
192 ;;;_ . fileset-whole-read-cmd
193 (defun fileset-whole-read-cmd ()
194 "Interactively get the name of a fileset command.
195 Either a whole command or a command on individual files."
197 (completing-read "Select command: "
198 (append filesets-commands fileset-whole-commands
)
200 ;;;_ . fileset-whole-read-fileset
201 (defun fileset-whole-read-fileset (&optional ask
)
202 "Interactively get the name of a fileset.
203 Called interactively, it's useful for changing a buffer's default
205 (interactive (list t
))
207 (unless ask fileset-whole-name-here
)
210 (completing-read "Select fileset: "
212 nil nil fileset-whole-name-here
)))
213 ;;Record it so we won't have to ask again wrt this buffer
214 ;;(`fileset-whole-name-here' is buffer-local)
216 ;;$$IMPROVE ME Allow some way(s) to not set it:
217 ;;User preference, and a buffer-local variable.
218 (unless (eq name fileset-whole-name-here
)
219 (setq fileset-whole-name-here name
))
220 ;;$$IMPROVE ME If buffer is not associated with
221 ;;any file, ask to add it (consult user preference)
222 ;;`filesets-add-buffer'
224 ;;;_ . fileset-whole-set-fileset
225 (defalias 'fileset-whole-set-fileset
'fileset-whole-read-fileset
)
226 ;;;_ . fileset-whole-get-dir
227 (defun fileset-whole-get-dir (fileset-whole fileset
)
228 "Return the root dir of FILESET-WHOLE if it exists."
229 ;;$$IMPROVE ME Store a :root-dir property if we made one.
231 (fileset-whole-data-get fileset-whole
:root-dir nil t
)
232 (fileset-whole-root-dir fileset
)))
235 ;;;_ . fileset-whole-run-cmd
237 (defun fileset-whole-run-cmd (cmd-name &optional fileset-name
)
238 "Run command CMD-NAME on whole fileset FILESET-NAME.
239 If prefix arg is given, don't use FILESET-NAME default."
242 (fileset-whole-read-cmd)
243 (fileset-whole-read-fileset current-prefix-arg
)))
245 ((cmd-on-whole (assoc cmd-name fileset-whole-commands
)))
251 (filesets-get-fileset-from-name fileset-name
))
253 (assoc fileset-name fileset-whole-alist
))
255 (fileset-whole-get-dir fileset-whole fileset
))
257 (fileset-whole-cmd->fn cmd-on-whole
))
259 (fileset-whole-cmd->args cmd-on-whole
))
261 (mapcar #'eval args-spec
)))
263 ;;$$IMPROVE ME Maybe open the fileset first, as
264 ;;filesets-run-cmd does. Do this according to some
265 ;;property of the command. `filesets-open'.
267 ;;$$IMPROVE ME When command makes another buffer
268 ;;(if we can tell it did), associate that buffer
269 ;;with FILESET. Set `fileset-whole-name-here' in
270 ;;it. Add it as an associated buffer (Possibly
271 ;;in another menu area).
274 ;;If not, call the filesets command (which presumably
275 ;;exists since we found it earlier)
277 (filesets-run-cmd cmd-name fileset-name
)))))
279 ;;;_ , Fileset extras
280 ;;;_ . fileset-whole->fileset
281 (defun fileset-whole->fileset
(fileset)
282 "Return a fileset object corresponding to FILESET.
283 If FILESET is a string, return the fileset of that name."
287 (filesets-get-fileset-from-name fileset
))
291 (error "Can't convert to fileset: %s" fileset
))))
292 ;;;_ . fileset-whole-get-filelist
294 ;;This may be a bugfix towards filesets, because
295 ;;`filesets-get-filelist' fails on :pattern or :tree. It's also an
296 ;;extension, to allow multiple :files-type clauses.
297 (defun fileset-whole-get-filelist (fileset)
298 "Return a list of all files in FILESET.
299 Use instead of `filesets-get-filelist'."
303 (entries (cdr fileset
))
311 ((:pattern
:tree
:ingroup
)
312 (filesets-get-filelist
313 (cdr entry
) (car entry
) nil
))
324 ;;;_ . fileset-whole-pick-file
325 ;;This is suitable as a destination-file function for
326 ;;`org-remember-templates'
327 (defun fileset-whole-pick-file (&optional fileset-name filter
)
328 "Interactively pick a single file name from a fileset.
329 If FILESET-NAME if not given, prompt for it.
331 If FILTER is given, it must be a function of 1 arg. Only present
332 files that satisfy it."
339 (fileset-whole-read-fileset t
)))
341 (filesets-get-fileset-from-name fileset-name
))
343 (fileset-whole-get-filelist fileset
))
345 ;;$$IMPROVE ME Support filtering by extension, by
346 ;;mode-symbol, or by regexp.
348 (filesets-filter-list files filter
)
351 (completing-read "File: " files nil t
352 (fileset-whole-root-dir fileset
))))
355 ;;;_ . fileset-whole-root-dir
356 (defun fileset-whole-root-dir (fileset)
357 "Return a fileset's smallest enclosing directory."
360 ((fileset (fileset-whole->fileset fileset
))
361 (files (fileset-whole-get-filelist fileset
))
365 #'fill-common-string-prefix
367 (error "No files found for %s" fileset
))))
368 (file-name-directory prefix
)))
372 ;;;_ , Maintaining fileset-whole data
373 ;;;_ . fileset-whole-edit
374 (defun fileset-whole-edit ()
375 "Customize `fileset-whole-alist'."
377 ;;$$IMPROVE ME Populate it first from fileset-data
378 (customize-variable 'fileset-whole-alist
))
380 ;;;_ . fileset-whole-populate-alist
382 ;;Populate `fileset-whole-alist' with fileset names and whatever data
383 ;;can be deduced about them, such as :root-dir
385 ;;;_ . fileset-whole-apply-compile
386 (defun fileset-whole-apply-compile (&rest args
)
387 "Like `compile', but applied to the concatenation of ARGS"
389 (mapconcat #'identity args
" ")))
390 ;;;_ , To set up bindings
391 ;;;###autoload (global-set-key "\C-cp" #'fileset-whole-run-cmd)
392 ;;;###autoload (fileset-whole-init)
396 (provide 'fileset-whole
)
398 ;;;_ * Local emacs vars.
399 ;;;_ + Local variables:
404 ;;; fileset-whole.el ends here