Changed comments
[fileset-whole.git] / fileset-whole.el
bloba34ee1b18533bdaa8fa7b8946bfbfdb5aaa5feb7
1 ;;;_ fileset-whole.el --- Commands and data applying to filesets as a whole
3 ;;;_. Headers
4 ;;;_ , License
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)
13 ;; any later version.
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.
25 ;;;_ , Commentary:
27 ;;
30 ;;;_ , Requires
32 (require 'filesets)
34 ;;;_. Body
35 ;;;_ , Customizations
36 ;;;_ . fileset-whole-alist
37 (defcustom fileset-whole-alist
38 '()
39 "Alist associating fileset names to keyed data"
40 :group 'filesets
41 :type '(repeat
42 (cons :tag "Fileset"
43 (string :tag "Name" :value "")
44 (repeat :tag "Data"
45 (list
46 symbol
47 sexp)))))
48 (put 'fileset-whole-alist 'risky-local-variable t)
50 ;;;_ . fileset-whole-commands
51 (defcustom fileset-whole-commands
52 '(("gdb"
53 gdb ((gud-query-cmdline 'gdb)))
54 ("git"
55 magit-status (default-directory))
56 ("eshell"
57 eshell nil)
58 ("Build"
59 fileset-whole-apply-compile
60 ("make -C" default-directory))
61 ("test"
62 emt:fileset
63 (fileset-name)))
65 "List of commands that apply to whole filesets.
67 Before the command is applied, each arg is evalled with the
68 following bindings:
70 `fileset' - the fileset.
71 `fileset-name' - the name of the fileset
72 `fileset-whole' - other data associated with the fileset, if any.
73 `default-directory' the root directory of the project, if any.
75 Then the command is applied to the list of args."
76 :group 'filesets
77 ;;$$IMPROVE ME Add a hotkey and put it into some keymap
78 ;;$$IMPROVE ME Add a field saying how to find the buffers it
79 ;;creates, given its return value.
80 :type '(repeat :tag "Commands"
81 (list :tag "Definition" :value ("")
82 (string "Name")
83 (choice :tag "Command"
84 (function :tag "Function"))
85 (repeat :tag "Argument List"
86 (choice :tag "Arguments"
87 ;;$$IMPROVE ME List the bound symbols as options
88 (sexp :tag "Sexp"
89 :value nil))))))
91 (put 'fileset-whole-commands 'risky-local-variable t)
92 ;;;_ , Variables
93 ;;For now, we don't contemplate multiple filesets applying to one
94 ;;buffer. Could treat a list of them differently.
95 (defvar fileset-whole-name-here nil
96 "The fileset that contains this buffer, if any." )
97 (make-variable-buffer-local 'fileset-whole-name-here)
98 ;;;_ , Setting up fileset stuff
99 ;;;_ . fileset-whole-setup-menu
100 ;;;###autoload
101 (defun fileset-whole-setup-menu ()
102 "Add the commands in fileset-whole-commands to fileset menu."
103 ;;When is this triggered?
104 ;;And see `filesets-get-cmd-menu'. Either add to it or add another
105 ;;menu.
107 (easy-menu-add-item
108 nil ;;Should this be `filesets-menu-in-menu'?
109 (append filesets-menu-path (list filesets-menu-name "# Filesets"))
110 ["Edit Filesets' Data" fileset-whole-edit]
111 "Save Filesets"))
113 ;;;_ . fileset-whole-edit
114 (defun fileset-whole-edit ()
115 "Customize `fileset-whole-alist'."
116 (interactive)
117 ;;$$IMPROVE ME Populate it first from fileset-data
118 (customize-variable 'fileset-whole-alist))
120 ;;;_ . fileset-whole-add-buffer
122 ;;Add a "created" buffer such as gdb, eshell, or magit make to the
123 ;;menus about files.
125 ;;;_ . fileset-whole-setup-files
126 ;;;###autoload
127 (defun fileset-whole-setup-files ()
128 "Run a hook in each currently open buffer that any fileset applies to."
129 ;;$$WRITE ME
130 ;;$$FACTOR ME Several parts: Running something in all relevant
131 ;;buffers (parms: fileset-name). The hook. Running the hook this
132 ;;way.
133 ;;$$DESIGN ABOUT ME How and when to trigger this. There are no
134 ;;obvious hooks in fileset.
135 (interactive)
136 (let*
138 ;;For each fileset
139 ;;Get list of files
140 ;;For each one that's already open, with that buffer current,
141 ;;run hooks. Default hook will just set `fileset-whole-name-here'.
144 ;;;_ , Structuring
145 ;;;_ . fileset-whole-cmd->fn
146 (defun fileset-whole-cmd->fn (cmd)
147 "Return the function field of CMD"
148 (nth 1 cmd))
149 ;;;_ . fileset-whole-cmd->args
150 (defun fileset-whole-cmd->args (cmd)
151 "Return the args field of CMD"
152 (nth 2 cmd))
153 ;;;_ . fileset-whole-entry->alist
154 (defun fileset-whole-entry->alist (entry)
155 "Return the alist of ENTRY"
156 (cdr entry))
157 ;;;_ . filesets-whole-data-get
158 (defun filesets-whole-data-get (entry key &optional default carp)
159 "Extract the value for KEY in the data part of fileset ENTRY.
160 Return DEFAULT if not found. Return (car VALUE) if CARP is non-nil."
161 (filesets-alist-get
162 (fileset-whole-entry->alist entry) key default carp))
164 ;;;_ , Running commands
165 ;;;_ . fileset-whole-read-cmd
166 (defun fileset-whole-read-cmd ()
167 "Interactively get the name of a fileset command.
168 Either a whole command or a command on individual files."
170 (completing-read "Select command: "
171 (append filesets-commands fileset-whole-commands)
172 nil t))
173 ;;;_ . fileset-whole-read-fileset
174 (defun fileset-whole-read-fileset (&optional ask)
175 "Interactively get the name of a fileset"
177 (unless ask fileset-whole-name-here)
178 (let
179 ((name
180 (completing-read "Select fileset: "
181 filesets-data nil t
182 nil nil fileset-whole-name-here)))
183 ;;Record it so we won't have to ask again wrt this buffer
184 ;;(`fileset-whole-name-here' is buffer-local)
186 ;;$$IMPROVE ME Allow some way(s) to not set it:
187 ;;User preference, and a buffer-local variable.
188 (unless (eq name fileset-whole-name-here)
189 (setq fileset-whole-name-here name))
190 ;;$$IMPROVE ME If buffer is not associated with
191 ;;any file, ask to add it (consult user preference)
192 ;;`filesets-add-buffer'
193 name)))
194 ;;;_ . fileset-whole-get-dir
195 (defun fileset-whole-get-dir (fileset-whole fileset)
196 "Return the root dir of FILESET-WHOLE if it exists."
197 ;;$$IMPROVE ME Store a :root-dir property if we made one.
199 (filesets-whole-data-get fileset-whole :root-dir nil t)
200 (fileset-whole-root-dir fileset)))
203 ;;;_ . fileset-whole-run-cmd
204 ;;;###autoload
205 (defun fileset-whole-run-cmd (cmd-name fileset-name)
206 "Pick a command and run it."
207 (interactive
208 (list
209 (fileset-whole-read-cmd)
210 (fileset-whole-read-fileset)))
211 (let
212 ((cmd-on-whole (assoc cmd-name fileset-whole-commands)))
213 (cond
214 (cmd-on-whole
215 (let*
217 (fileset
218 (filesets-get-fileset-from-name fileset-name))
219 (fileset-whole
220 (assoc fileset-name fileset-whole-alist))
221 (default-directory
222 (fileset-whole-get-dir fileset-whole fileset))
224 (fileset-whole-cmd->fn cmd-on-whole))
225 (args-spec
226 (fileset-whole-cmd->args cmd-on-whole))
227 (args
228 (mapcar #'eval args-spec)))
230 ;;$$IMPROVE ME Maybe open the fileset first, as
231 ;;filesets-run-cmd does. Do this according to some
232 ;;property of the command. `filesets-open'.
234 ;;$$IMPROVE ME When command makes another buffer
235 ;;(if we can tell it did), associate that buffer
236 ;;with FILESET. Set `fileset-whole-name-here' in
237 ;;it. Add it as an associated buffer (Possibly
238 ;;in another menu area).
239 (apply fn args)))
241 ;;If not, call the filesets command (which presumably
242 ;;exists since we found it earlier)
244 (filesets-run-cmd cmd-name fileset-name)))))
246 ;;;_ , Fileset extras
247 ;;;_ . filesets-whole->fileset
248 (defun filesets-whole->fileset (fileset)
249 "Return a fileset object corresponding to FILESET.
250 If FILESET is a string, return the fileset of that name."
252 (cond
253 ((stringp fileset)
254 (filesets-get-fileset-from-name fileset))
255 ((listp fileset)
256 fileset)
258 (error "Can't convert to fileset: %s" fileset))))
259 ;;;_ . fileset-whole-pick-file
260 ;;This is suitable as a destination-file function for
261 ;;`org-remember-templates'
262 (defun fileset-whole-pick-file (&optional fileset-name filter)
263 "Interactively pick a single file name from a fileset.
264 If FILESET-NAME if not given, prompt for it.
266 If FILTER is given, it must be a function of 1 arg. Only present
267 files that satisfy it."
269 (interactive)
270 (let*
271 ((fileset-name
272 (or
273 fileset-name
274 (fileset-whole-read-fileset t)))
275 (fileset
276 (filesets-get-fileset-from-name fileset-name))
277 (files
278 (filesets-get-filelist fileset nil nil))
279 (files
280 ;;$$IMPROVE ME Support filtering by extension, by
281 ;;mode-symbol, or by regexp.
282 (if filter
283 (filesets-filter-list files filter)
284 files)))
286 (completing-read "File: " files nil t)))
288 ;;;_ . fileset-whole-root-dir
289 (defun fileset-whole-root-dir (fileset)
290 "Return a fileset's smallest enclosing directory."
292 (let*
293 ((fileset (filesets-whole->fileset fileset))
294 (files (filesets-get-filelist fileset nil nil)))
295 (reduce
296 #'fill-common-string-prefix
297 files)))
299 ;;;_ , Populating the alist
301 ;;;_ . fileset-whole-populate-alist
302 ;;YAGNI
303 ;;Populate `fileset-whole-alist' with fileset names and whatever data
304 ;;can be deduced about them, such as :root-dir
305 ;;;_ , Support
306 ;;;_ . fileset-whole-apply-compile
307 (defun fileset-whole-apply-compile (&rest args)
308 "Like `compile', but applied to the concatenation of ARGS"
309 (compile
310 (mapconcat #'identity args " ")))
311 ;;;_ , To set up bindings
312 ;;;###autoload (global-set-key "\C-cp" #'fileset-whole-run-cmd)
314 ;;;_. Footers
315 ;;;_ , Provides
317 (provide 'fileset-whole)
319 ;;;_ * Local emacs vars.
320 ;;;_ + Local variables:
321 ;;;_ + mode: allout
322 ;;;_ + End:
324 ;;;_ , End
325 ;;; fileset-whole.el ends here