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
53 gdb
((gud-query-cmdline 'gdb
)))
55 magit-status
(default-directory))
59 fileset-whole-apply-compile
60 ("make -C" default-directory
))
67 (fileset-whole-pick-file name
)))
70 "List of commands that apply to whole filesets.
72 Before the command is applied, each arg is evalled with the
75 `fileset' - the fileset.
76 `fileset-name' - the name of the fileset
77 `fileset-whole' - other data associated with the fileset, if any.
78 `default-directory' the root directory of the project, if any.
80 Then the command is applied to the list of args."
82 ;;$$IMPROVE ME Add a hotkey and put it into some keymap
83 ;;$$IMPROVE ME Add a field saying how to find the buffers it
84 ;;creates, given its return value.
85 :type
'(repeat :tag
"Commands"
86 (list :tag
"Definition" :value
("")
88 (choice :tag
"Command"
89 (function :tag
"Function"))
90 (repeat :tag
"Argument List"
91 (choice :tag
"Arguments"
92 ;;$$IMPROVE ME List the bound symbols as options
96 (put 'fileset-whole-commands
'risky-local-variable t
)
98 ;;For now, we don't contemplate multiple filesets applying to one
99 ;;buffer. Could treat a list of them differently.
100 (defvar fileset-whole-name-here nil
101 "The fileset that contains this buffer, if any." )
102 (make-variable-buffer-local 'fileset-whole-name-here
)
103 (put 'fileset-whole-name-here
'permanent-local t
)
104 ;;;_ , Setting up menus
105 ;;;_ . fileset-whole-setup-menu
106 (defun fileset-whole-setup-menu ()
107 "Add the commands in fileset-whole-commands to fileset menu."
108 ;;When is this triggered?
109 ;;And see `filesets-get-cmd-menu'. Either add to it or add another
113 nil
;;Should this be `filesets-menu-in-menu'?
114 (append filesets-menu-path
(list filesets-menu-name
"# Filesets"))
115 ["Edit Filesets' Data" fileset-whole-edit
]
118 ;;;_ . fileset-whole-cmds-to-menu
119 (defun fileset-whole-cmds-to-menu ()
120 "Add fileset-whole commands to filesets command menu."
126 nil
;;Should this be `filesets-menu-in-menu'?
127 (append filesets-menu-path
(list filesets-menu-name
"+ Commands"))
128 `[,name
(fileset-whole-run-cmd
130 (fileset-whole-read-fileset))])))
131 fileset-whole-commands
)
134 ;;;_ . fileset-whole-add-buffer
136 ;;Add a "created" buffer such as gdb, eshell, or magit make to the
137 ;;menus, in a section paralleling the list of files.
139 ;;;_ . fileset-whole-setup-files
141 (defun fileset-whole-setup-files ()
142 "Run a hook in each currently open buffer that any fileset applies to."
144 ;;$$FACTOR ME Several parts: Running something in all relevant
145 ;;buffers (parms: fileset-name). The hook. Running the hook this
147 ;;$$DESIGN ABOUT ME How and when to trigger this. There are no
148 ;;obvious hooks in fileset.
154 ;;For each one that's already open, with that buffer current,
155 ;;run hooks. Default hook will just set `fileset-whole-name-here'.
157 ;;;_ . fileset-whole-init
159 (defun fileset-whole-init ()
160 "Set up fileset-whole on top of filesets"
162 (fileset-whole-setup-menu)
163 (fileset-whole-cmds-to-menu))
165 ;;;_ . fileset-whole-cmd->fn
166 (defun fileset-whole-cmd->fn
(cmd)
167 "Return the function field of CMD"
169 ;;;_ . fileset-whole-cmd->args
170 (defun fileset-whole-cmd->args
(cmd)
171 "Return the args field of CMD"
173 ;;;_ . fileset-whole-entry->alist
174 (defun fileset-whole-entry->alist
(entry)
175 "Return the alist of ENTRY"
177 ;;;_ . filesets-whole-data-get
178 (defun filesets-whole-data-get (entry key
&optional default carp
)
179 "Extract the value for KEY in the data part of fileset ENTRY.
180 Return DEFAULT if not found. Return (car VALUE) if CARP is non-nil."
182 (fileset-whole-entry->alist entry
) key default carp
))
184 ;;;_ , Running commands
185 ;;;_ . fileset-whole-read-cmd
186 (defun fileset-whole-read-cmd ()
187 "Interactively get the name of a fileset command.
188 Either a whole command or a command on individual files."
190 (completing-read "Select command: "
191 (append filesets-commands fileset-whole-commands
)
193 ;;;_ . fileset-whole-read-fileset
194 (defun fileset-whole-read-fileset (&optional ask
)
195 "Interactively get the name of a fileset"
197 (unless ask fileset-whole-name-here
)
200 (completing-read "Select fileset: "
202 nil nil fileset-whole-name-here
)))
203 ;;Record it so we won't have to ask again wrt this buffer
204 ;;(`fileset-whole-name-here' is buffer-local)
206 ;;$$IMPROVE ME Allow some way(s) to not set it:
207 ;;User preference, and a buffer-local variable.
208 (unless (eq name fileset-whole-name-here
)
209 (setq fileset-whole-name-here name
))
210 ;;$$IMPROVE ME If buffer is not associated with
211 ;;any file, ask to add it (consult user preference)
212 ;;`filesets-add-buffer'
214 ;;;_ . fileset-whole-get-dir
215 (defun fileset-whole-get-dir (fileset-whole fileset
)
216 "Return the root dir of FILESET-WHOLE if it exists."
217 ;;$$IMPROVE ME Store a :root-dir property if we made one.
219 (filesets-whole-data-get fileset-whole
:root-dir nil t
)
220 (fileset-whole-root-dir fileset
)))
223 ;;;_ . fileset-whole-run-cmd
225 (defun fileset-whole-run-cmd (cmd-name &optional fileset-name
)
226 "Run command CMD-NAME on whole fileset FILESET-NAME."
229 (fileset-whole-read-cmd)
230 (fileset-whole-read-fileset)))
232 ((cmd-on-whole (assoc cmd-name fileset-whole-commands
)))
238 (filesets-get-fileset-from-name fileset-name
))
240 (assoc fileset-name fileset-whole-alist
))
242 (fileset-whole-get-dir fileset-whole fileset
))
244 (fileset-whole-cmd->fn cmd-on-whole
))
246 (fileset-whole-cmd->args cmd-on-whole
))
248 (mapcar #'eval args-spec
)))
250 ;;$$IMPROVE ME Maybe open the fileset first, as
251 ;;filesets-run-cmd does. Do this according to some
252 ;;property of the command. `filesets-open'.
254 ;;$$IMPROVE ME When command makes another buffer
255 ;;(if we can tell it did), associate that buffer
256 ;;with FILESET. Set `fileset-whole-name-here' in
257 ;;it. Add it as an associated buffer (Possibly
258 ;;in another menu area).
261 ;;If not, call the filesets command (which presumably
262 ;;exists since we found it earlier)
264 (filesets-run-cmd cmd-name fileset-name
)))))
266 ;;;_ , Fileset extras
267 ;;;_ . filesets-whole->fileset
268 (defun filesets-whole->fileset
(fileset)
269 "Return a fileset object corresponding to FILESET.
270 If FILESET is a string, return the fileset of that name."
274 (filesets-get-fileset-from-name fileset
))
278 (error "Can't convert to fileset: %s" fileset
))))
279 ;;;_ . fileset-whole-pick-file
280 ;;This is suitable as a destination-file function for
281 ;;`org-remember-templates'
282 (defun fileset-whole-pick-file (&optional fileset-name filter
)
283 "Interactively pick a single file name from a fileset.
284 If FILESET-NAME if not given, prompt for it.
286 If FILTER is given, it must be a function of 1 arg. Only present
287 files that satisfy it."
294 (fileset-whole-read-fileset t
)))
296 (filesets-get-fileset-from-name fileset-name
))
298 (filesets-get-filelist fileset nil nil
))
300 ;;$$IMPROVE ME Support filtering by extension, by
301 ;;mode-symbol, or by regexp.
303 (filesets-filter-list files filter
)
306 (completing-read "File: " files nil t
)))
308 ;;;_ . fileset-whole-root-dir
309 (defun fileset-whole-root-dir (fileset)
310 "Return a fileset's smallest enclosing directory."
313 ((fileset (filesets-whole->fileset fileset
))
314 (files (filesets-get-filelist fileset nil nil
)))
316 #'fill-common-string-prefix
320 ;;;_ , Maintaining fileset-whole data
321 ;;;_ . fileset-whole-edit
322 (defun fileset-whole-edit ()
323 "Customize `fileset-whole-alist'."
325 ;;$$IMPROVE ME Populate it first from fileset-data
326 (customize-variable 'fileset-whole-alist
))
328 ;;;_ . fileset-whole-populate-alist
330 ;;Populate `fileset-whole-alist' with fileset names and whatever data
331 ;;can be deduced about them, such as :root-dir
333 ;;;_ . fileset-whole-apply-compile
334 (defun fileset-whole-apply-compile (&rest args
)
335 "Like `compile', but applied to the concatenation of ARGS"
337 (mapconcat #'identity args
" ")))
338 ;;;_ , To set up bindings
339 ;;;###autoload (global-set-key "\C-cp" #'fileset-whole-run-cmd)
340 ;;;###autoload (fileset-whole-init)
344 (provide 'fileset-whole
)
346 ;;;_ * Local emacs vars.
347 ;;;_ + Local variables:
352 ;;; fileset-whole.el ends here