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 (put 'fileset-whole-alist
'risky-local-variable nil
)
112 ;;;_ , Setting up menus
113 ;;;_ . fileset-whole-setup-menu
114 (defun fileset-whole-setup-menu ()
115 "Add the commands in fileset-whole-commands to fileset menu."
116 ;;When is this triggered?
117 ;;And see `filesets-get-cmd-menu'. Either add to it or add another
121 nil
;;Should this be `filesets-menu-in-menu'?
122 (append filesets-menu-path
(list filesets-menu-name
"# Filesets"))
123 ["Edit Filesets' Data" fileset-whole-edit
]
126 ;;;_ . fileset-whole-cmds-to-menu
127 (defun fileset-whole-cmds-to-menu ()
128 "Add fileset-whole commands to filesets command menu."
134 nil
;;Should this be `filesets-menu-in-menu'?
135 (append filesets-menu-path
(list filesets-menu-name
"+ Commands"))
136 `[,name
(fileset-whole-run-cmd
138 (fileset-whole-read-fileset))])))
139 fileset-whole-commands
)
142 ;;;_ . fileset-whole-add-buffer
144 ;;Add a "created" buffer such as gdb, eshell, or magit make to the
145 ;;menus, in a section paralleling the list of files.
147 ;;;_ . fileset-whole-setup-files
149 (defun fileset-whole-setup-files ()
150 "Run a hook in each currently open buffer that any fileset applies to."
152 ;;$$FACTOR ME Several parts: Running something in all relevant
153 ;;buffers (parms: fileset-name). The hook. Running the hook this
155 ;;$$DESIGN ABOUT ME How and when to trigger this. There are no
156 ;;obvious hooks in fileset.
162 ;;For each one that's already open, with that buffer current,
163 ;;run hooks. Default hook will just set `fileset-whole-name-here'.
165 ;;;_ . fileset-whole-init
167 (defun fileset-whole-init ()
168 "Set up fileset-whole on top of filesets"
170 (fileset-whole-setup-menu)
171 (fileset-whole-cmds-to-menu))
173 ;;;_ . fileset-whole-cmd->fn
174 (defun fileset-whole-cmd->fn
(cmd)
175 "Return the function field of CMD"
177 ;;;_ . fileset-whole-cmd->args
178 (defun fileset-whole-cmd->args
(cmd)
179 "Return the args field of CMD"
181 ;;;_ . fileset-whole-entry->alist
182 (defun fileset-whole-entry->alist
(entry)
183 "Return the alist of ENTRY"
185 ;;;_ . fileset-whole-data-get
186 (defun fileset-whole-data-get (entry key
&optional default carp
)
187 "Extract the value for KEY in the data part of fileset ENTRY.
188 Return DEFAULT if not found. Return (car VALUE) if CARP is non-nil."
190 (fileset-whole-entry->alist entry
) key default carp
))
192 ;;;_ , Running commands
193 ;;;_ . fileset-whole-read-cmd
194 (defun fileset-whole-read-cmd ()
195 "Interactively get the name of a fileset command.
196 Either a whole command or a command on individual files."
198 (completing-read "Select command: "
199 (append filesets-commands fileset-whole-commands
)
201 ;;;_ . fileset-whole-read-fileset
202 (defun fileset-whole-read-fileset (&optional ask
)
203 "Interactively get the name of a fileset.
204 Called interactively, it's useful for changing a buffer's default
206 (interactive (list t
))
208 (unless ask fileset-whole-name-here
)
211 (completing-read "Select fileset: "
213 nil nil fileset-whole-name-here
)))
214 ;;Record it so we won't have to ask again wrt this buffer
215 ;;(`fileset-whole-name-here' is buffer-local)
217 ;;$$IMPROVE ME Allow some way(s) to not set it:
218 ;;User preference, and a buffer-local variable.
219 (unless (eq name fileset-whole-name-here
)
220 (setq fileset-whole-name-here name
))
221 ;;$$IMPROVE ME If buffer is not associated with
222 ;;any file, ask to add it (consult user preference)
223 ;;`filesets-add-buffer'
225 ;;;_ . fileset-whole-set-fileset
226 (defalias 'fileset-whole-set-fileset
'fileset-whole-read-fileset
)
227 ;;;_ . fileset-whole-get-dir
228 (defun fileset-whole-get-dir (fileset-whole fileset
)
229 "Return the root dir of FILESET-WHOLE if it exists."
230 ;;$$IMPROVE ME Store a :root-dir property if we made one.
232 (fileset-whole-data-get fileset-whole
:root-dir nil t
)
233 (fileset-whole-root-dir fileset
)))
236 ;;;_ . fileset-whole-run-cmd
238 (defun fileset-whole-run-cmd (cmd-name &optional fileset-name
)
239 "Run command CMD-NAME on whole fileset FILESET-NAME.
240 If prefix arg is given, don't use FILESET-NAME default."
243 (fileset-whole-read-cmd)
244 (fileset-whole-read-fileset current-prefix-arg
)))
246 ((cmd-on-whole (assoc cmd-name fileset-whole-commands
)))
252 (filesets-get-fileset-from-name fileset-name
))
254 (assoc fileset-name fileset-whole-alist
))
256 (fileset-whole-get-dir fileset-whole fileset
))
258 (fileset-whole-cmd->fn cmd-on-whole
))
260 (fileset-whole-cmd->args cmd-on-whole
))
262 (mapcar #'eval args-spec
)))
264 ;;$$IMPROVE ME Maybe open the fileset first, as
265 ;;filesets-run-cmd does. Do this according to some
266 ;;property of the command. `filesets-open'.
268 ;;$$IMPROVE ME When command makes another buffer
269 ;;(if we can tell it did), associate that buffer
270 ;;with FILESET. Set `fileset-whole-name-here' in
271 ;;it. Add it as an associated buffer (Possibly
272 ;;in another menu area).
275 ;;If not, call the filesets command (which presumably
276 ;;exists since we found it earlier)
278 (filesets-run-cmd cmd-name fileset-name
)))))
280 ;;;_ , Fileset extras
281 ;;;_ . fileset-whole->fileset
282 (defun fileset-whole->fileset
(fileset)
283 "Return a fileset object corresponding to FILESET.
284 If FILESET is a string, return the fileset of that name."
288 (filesets-get-fileset-from-name fileset
))
292 (error "Can't convert to fileset: %s" fileset
))))
293 ;;;_ . fileset-whole-get-filelist
295 ;;This may be a bugfix towards filesets, because
296 ;;`filesets-get-filelist' fails on :pattern or :tree. It's also an
297 ;;extension, to allow multiple :files-type clauses.
298 (defun fileset-whole-get-filelist (fileset)
299 "Return a list of all files in FILESET.
300 Use instead of `filesets-get-filelist'."
304 (entries (cdr fileset
))
312 ((:pattern
:tree
:ingroup
)
313 (filesets-get-filelist
314 (cdr entry
) (car entry
) nil
))
325 ;;;_ . fileset-whole-pick-file
326 ;;This is suitable as a destination-file function for
327 ;;`org-remember-templates'
328 (defun fileset-whole-pick-file (&optional fileset-name filter
)
329 "Interactively pick a single file name from a fileset.
330 If FILESET-NAME if not given, prompt for it.
332 If FILTER is given, it must be a function of 1 arg. Only present
333 files that satisfy it."
340 (fileset-whole-read-fileset t
)))
342 (filesets-get-fileset-from-name fileset-name
))
344 (fileset-whole-get-filelist fileset
))
346 ;;$$IMPROVE ME Support filtering by extension, by
347 ;;mode-symbol, or by regexp.
349 (filesets-filter-list files filter
)
352 (completing-read "File: " files nil t
353 (fileset-whole-root-dir fileset
))))
356 ;;;_ . fileset-whole-root-dir
357 (defun fileset-whole-root-dir (fileset)
358 "Return a fileset's smallest enclosing directory."
361 ((fileset (fileset-whole->fileset fileset
))
362 (files (fileset-whole-get-filelist fileset
))
366 #'fill-common-string-prefix
368 (error "No files found for %s" fileset
))))
369 (file-name-directory prefix
)))
373 ;;;_ , Maintaining fileset-whole data
374 ;;;_ . fileset-whole-edit
375 (defun fileset-whole-edit ()
376 "Customize `fileset-whole-alist'."
378 ;;$$IMPROVE ME Populate it first from fileset-data
379 (customize-variable 'fileset-whole-alist
))
381 ;;;_ . fileset-whole-populate-alist
383 ;;Populate `fileset-whole-alist' with fileset names and whatever data
384 ;;can be deduced about them, such as :root-dir
386 ;;;_ . fileset-whole-apply-compile
387 (defun fileset-whole-apply-compile (&rest args
)
388 "Like `compile', but applied to the concatenation of ARGS"
390 (mapconcat #'identity args
" ")))
391 ;;;_ , To set up bindings
392 ;;;###autoload (global-set-key "\C-cp" #'fileset-whole-run-cmd)
394 ;;;_ , To set up menus
400 (provide 'fileset-whole
)
402 ;;;_ * Local emacs vars.
403 ;;;_ + Local variables:
408 ;;; fileset-whole.el ends here