1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; eproject.el --- project workspaces for emacs
5 ;; Copyright (C) 2008-2010 grischka
7 ;; Author: grischka -- grischka@users.sourceforge.net
8 ;; Created: 24 Jan 2008
11 ;; This program is free software, released under the GNU General
12 ;; Public License (GPL, version 2). For details see:
14 ;; http://www.fsf.org/licenses/gpl.html
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ;; General Public License for more details.
21 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
24 ;; User-configurable items:
26 (defvar prj-default-config
'(
28 ("Clean" "make clean" "C-f9")
29 ("Run" "echo run what" "f8")
30 ("Stop" "-e eproject-killtool" "C-f8")
32 ("Configure" "./configure")
34 ("Explore Project" "nautilus --browser `pwd` &")
35 ("XTerm In Project" "xterm &")
37 "*The default tools menu for new projects in eproject."
40 (defvar prj-set-default-directory nil
41 "*Should eproject set the project directory as default-directory
42 for all project files (nil/t).")
44 (defvar prj-set-framepos nil
45 "*Should eproject restore the last frame position/size (nil/t).")
47 (defvar prj-set-compilation-frame nil
48 "*Should eproject show compilation output in the other frame (nil/t).")
50 (defvar prj-set-multi-isearch nil
51 "*Should eproject setup multi-isearch in the project files (nil/t).")
53 ;; End of user-configurable items
54 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
56 ;; There is a global file (~/.emacs.d/eproject.lst)
57 (defun prj-globalfile ()
58 (expand-file-name "eproject.lst"
59 (if (boundp 'user-emacs-directory
) user-emacs-directory
63 ;; with the list of all projects
66 ;; and the project that was open in the last session (if any)
67 (defvar prj-last-open nil
)
69 ;; and the frame coords from last session
70 (defvar prj-frame-pos nil
)
72 ;; eproject version that created the config file
73 (defvar prj-version nil
)
75 ;; Here is a function to reset these
77 (setq prj-version nil
)
79 (setq prj-last-open nil
)
80 (setq prj-frame-pos nil
)
83 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
84 ;; Each project has a directory
86 (defvar prj-directory
)
88 ;; with a configuration files in it
89 (defvar prj-default-cfg
"eproject.cfg")
99 ;; an alist of settings
105 ;; a list of utility functions (feature incomplete)
106 (defvar prj-functions nil
)
108 ;; directory to run commands, default to prj-directory
109 (defvar prj-exec-directory
)
111 ;; The current project
114 ;; A list with generated functions for each tool
115 (defvar prj-tools-fns
)
117 ;; A list with files removed from the project
118 (defvar prj-removed-files
)
120 ;; Here is a function to reset/close the project
122 (setq prj-version nil
)
123 (setq prj-current nil
)
124 (setq prj-directory nil
)
125 (setq prj-exec-directory nil
)
127 (setq prj-removed-files nil
)
128 (setq prj-curfile nil
)
129 (setq prj-config nil
)
130 (setq prj-tools-fns nil
)
131 (setq prj-tools
(copy-tree prj-default-config
))
132 (prj-reset-functions)
135 (defun prj-reset-functions ()
136 (dolist (l prj-functions
)
137 (if (eq (car l
) 'setq
)
138 (makunbound (cadr l
))
139 (fmakunbound (cadr l
))
141 (setq prj-functions nil
)
144 (defun prj-set-functions (s)
145 (prj-reset-functions)
146 (setq prj-functions s
)
147 (dolist (l s
) (eval l
))
150 ;; Some more variables:
152 ;; the frame that exists on startup
153 (defvar prj-initial-frame nil
)
155 ;; this is put into minor-mode-alist
156 (defvar eproject-mode t
)
158 ;; where this file is in
159 (defvar eproject-directory
)
161 ;; eproject version that created the files
162 (defvar eproject-version
"0.4")
166 (defun eproject-setup-toggle () (interactive))
167 (defun eproject-setup-quit () (interactive))
168 (defun prj-config-get-result (s))
169 (defun prj-config-reset ())
170 (defun prj-config-print ())
171 (defun prj-config-parse ())
174 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
177 (defun caddr (l) (car (cddr l
)))
179 (defun prj-del-list (l e
)
180 (let ((a (assoc (car e
) l
)))
185 (defun prj-add-list (l e
)
186 (nconc (prj-del-list l e
) (list e
))
189 (defun prj-next-file (l e
)
190 (and (setq e
(assoc (car e
) l
))
194 (defun prj-prev-file (l e
)
195 (prj-next-file (reverse l
) e
)
198 ; replace a closed file, either by the previous or the next.
199 (defun prj-otherfile (l f
)
200 (or (prj-prev-file l f
)
204 ;; make relative path, but only up to the second level of ..
205 (defun prj-relative-path (f)
206 (let ((r (file-relative-name f prj-directory
)))
207 (if (string-match "^\\.\\.[/\\]\\.\\.[/\\]\\.\\.[/\\]" r
)
212 ;; friendly truncate filename
213 (defun prj-shortname (s)
214 (let ((l (length s
)) (x 30) n
)
218 (setq n
(length (file-name-nondirectory s
)))
219 (if (< n l
) (setq n
(1+ n
)))
222 (concat (substring s
0 (- x n
)) "..." (substring s
(- n
)))
225 (concat (substring s
0 x
) "...")
228 (concat "..." (substring s
(- n
) (- (- x
3) n
)) "...")
231 (defun prj-settitle ()
232 (modify-frame-parameters
236 (format "emacs - %s" (car prj-current
))
239 (defun eproject-addon (f)
240 (concat eproject-directory f
)
243 (defun prj-goto-line (n)
245 (beginning-of-line n
)
248 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
249 ;; Write configuration to file
251 (defun prj-print-list (s fp
)
253 (setq v
(list 'setq s
254 (if (and (atom v
) (null (and (symbolp v
) v
)))
259 (pp v fp
) (princ "\n" fp
)
262 (defun prj-create-file (filename)
263 (let ((fp (generate-new-buffer filename
)))
264 (princ ";; -*- mode: Lisp; -*-\n\n" fp
)
267 (defun prj-close-file (fp)
268 (with-current-buffer fp
270 (and t
(write-region nil nil
(buffer-name fp
) nil
0))
276 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
277 ;; Load/Save global project list and initial frame sizes
279 (defun prj-loadlist ()
281 (load (prj-globalfile) t t
)
282 (setq prj-version eproject-version
)
285 (defun prj-get-frame-pos (f)
287 (lambda (parm) (cons parm
(frame-parameter f parm
)))
288 '(top left width height
)
291 (defun prj-savelist ()
292 (let ((g (prj-globalfile)) fp
)
293 (unless (file-exists-p g
)
294 (make-directory (file-name-directory g
) t
)
296 (setq prj-last-open
(car prj-current
))
297 (when (frame-live-p prj-initial-frame
)
298 (setq prj-frame-pos
(prj-get-frame-pos prj-initial-frame
))
300 (setq fp
(prj-create-file g
))
302 (prj-print-list 'prj-version fp
)
303 (prj-print-list 'prj-list fp
)
304 (prj-print-list 'prj-last-open fp
)
305 (prj-print-list 'prj-frame-pos fp
)
309 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
310 ;; Load/Save local per-project configuration file
312 (defun prj-update-config ()
313 (let ((d (prj-get-directory prj-current
))
314 (e (prj-getconfig "exec-root"))
316 (if e
(setq d
(expand-file-name e d
)))
317 (setq prj-exec-directory
(file-name-as-directory d
))
320 (defun prj-get-directory (a)
321 (file-name-as-directory (expand-file-name (cadr a
)))
324 (defun prj-get-cfg ()
325 (expand-file-name (or (caddr prj-current
) prj-default-cfg
) prj-directory
)
328 (defun prj-loadconfig (a)
332 (setq prj-directory
(prj-get-directory a
))
333 (when (file-regular-p (setq lf
(prj-get-cfg)))
336 (or (assoc prj-curfile prj-files
)
340 (if (setq e
(prj-getconfig "project-name"))
342 (prj-setconfig "project-name" (car a
))
345 (prj-set-functions prj-functions
)
346 (setq prj-version eproject-version
)
349 (defun prj-saveconfig ()
353 (setq w
(selected-window))
354 (setq c
(window-buffer w
))
355 (dolist (f prj-files
)
356 (cond ((setq b
(get-buffer (car f
)))
357 (set-window-buffer w b t
)
358 (with-current-buffer b
359 (let ((s (line-number-at-pos (window-start w
)))
360 (p (line-number-at-pos (window-point w
)))
362 (push (list (car f
) s p
) files
)
367 (set-window-buffer w c t
)
369 (let ((fp (prj-create-file (prj-get-cfg)))
370 (prj-curfile (car prj-curfile
))
371 (prj-files (nreverse files
))
374 (prj-print-list 'prj-version fp
)
375 (prj-print-list 'prj-config fp
)
376 (prj-print-list 'prj-tools fp
)
377 (prj-print-list 'prj-files fp
)
378 (prj-print-list 'prj-curfile fp
)
379 (prj-print-list 'prj-functions fp
)
384 (defun prj-saveall ()
389 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
390 ;; The core functions: Open / Close / Add / Remove Project
392 (defun eproject-open (a)
393 "Open another project."
396 (or (prj-config-get-result 'p
)
397 (completing-read "Open Project: " (mapcar 'car prj-list
))
400 (let ((b (assoc a prj-list
)))
402 (error "No such project: %s" a
)
406 (setq a
(or (car (member a prj-list
)) a
))
407 (unless (eq a prj-current
)
408 (unless (file-directory-p (prj-get-directory a
))
409 (error "No such directory: %s" (cadr a
))
411 (setq prj-list
(cons a
(delq a prj-list
)))
418 (unless (prj-edit-file prj-curfile
)
422 (defun eproject-close ()
423 "Close the current project."
431 (save-some-buffers nil
)
432 (eproject-killbuffers t
)
435 (or f
(prj-addhooks))
443 (defun eproject-killbuffers (&optional from-project
)
444 "If called interactively kills all buffers that
445 do not belong to project files"
448 (dolist (f prj-files
)
449 (setq b
(get-buffer (car f
)))
451 (setq a
(cons (list b
) a
))
453 (dolist (b (buffer-list))
454 (when (eq (consp (assoc b a
)) from-project
)
458 (defun eproject-add (dir &optional name cfg
)
459 "Add a new or existing project to the list."
462 (setq d
(read-directory-name "Add project in directory: " prj-directory nil t
))
463 (setq n
(file-name-nondirectory (directory-file-name d
)))
464 (setq n
(read-string "Project name: " n
))
465 (setq f
(read-string "Project file: " prj-default-cfg
))
469 (setq dir
(directory-file-name dir
))
471 (setq name
(file-name-nondirectory dir
))
473 (when (and cfg
(string-equal cfg prj-default-cfg
))
476 (let ((a (if cfg
(list name dir cfg
) (list name dir
))))
481 (defun eproject-remove (a)
482 "Remove a project from the list."
485 (or (prj-config-get-result 'p
)
486 (completing-read "Remove project: " (mapcar 'car prj-list
))
489 (let ((b (assoc a prj-list
)))
491 (error "No such project: %s" a
)
497 (prog1 (y-or-n-p (format "Remove \"%s\"? " (car a
)))
500 (setq prj-list
(prj-del-list prj-list a
))
504 (defun eproject-save ()
505 "Save the project configuration to file."
512 (defun eproject-revert ()
513 "Reload the project configuration from file."
517 (prj-loadconfig prj-current
)
522 (defun eproject-addfile (f)
523 "Add a file to the current project."
527 (read-file-name "Add file to project: " nil nil t nil
)
529 (unless prj-current
(error "No project open"))
530 (let ((a (prj-insert-file f
(prj-config-get-result 'f
))))
532 (message "Added to project: %s" (car a
))
538 (defun eproject-removefile (a)
539 "Remove a file from the current project."
540 (interactive (prj-get-existing-file-1 "Remove file from project: "))
541 (setq a
(prj-get-existing-file-2 a
))
545 (defun eproject-visitfile (a)
546 "Visit a file from the current project."
547 (interactive (prj-get-existing-file-1 "Visit file: "))
548 (setq a
(prj-get-existing-file-2 a
))
552 (defun prj-get-existing-file-1 (msg)
555 (or (prj-config-get-result 'f
)
556 (completing-read msg
(mapcar 'car prj-files
))
559 (defun prj-get-existing-file-2 (a)
560 (unless prj-current
(error "No project open"))
563 (let ((b (assoc (prj-relative-path a
) prj-files
)))
564 (unless b
(error "No such file in project: %s" a
))
568 (defun eproject-help ()
569 "Show the eproject README."
571 (view-file (eproject-addon "eproject.txt"))
574 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
575 ;; Hook functions to track opening/closing files from emacs
577 (defun prj-addhooks ()
578 (add-hook 'kill-buffer-hook
'prj-kill-buffer-hook
)
579 (add-hook 'find-file-hook
'prj-find-file-hook
)
580 (add-hook 'window-configuration-change-hook
'prj-wcc-hook
)
583 (defun prj-removehooks ()
584 (remove-hook 'window-configuration-change-hook
'prj-wcc-hook
)
585 (remove-hook 'find-file-hook
'prj-find-file-hook
)
586 (remove-hook 'kill-buffer-hook
'prj-kill-buffer-hook
)
589 (defun prj-wcc-hook ()
590 (dolist (w (window-list))
591 (prj-register-buffer (window-buffer w
))
594 (defun prj-find-file-hook ()
595 (run-with-idle-timer 0.2 nil
'prj-wcc-hook
)
598 (defun prj-kill-buffer-hook ()
599 (let ((b (current-buffer)) a
)
600 (if (setq a
(rassq b prj-files
))
601 (prj-remove-file a t
)
602 (if (setq a
(rassq b prj-removed-files
))
603 (setq prj-removed-files
(delq a prj-removed-files
))
606 (defun prj-register-buffer (b)
608 (setq f
(buffer-file-name b
))
609 (when (and f t
) ;;(not (string-match "^\\." (file-name-nondirectory f))))
610 (setq a
(rassq b prj-files
))
612 (setq a
(prj-insert-file f nil t
))
615 (message "Added to project: %s" (car a
))
617 (prj-init-buffer a b
)
619 (when (and a
(null (eq a prj-curfile
)))
625 (defun prj-insert-file (f &optional after on-the-fly
)
626 (let ((r (prj-relative-path f
)) a m
)
627 (setq a
(assoc r prj-files
))
628 (unless (or a
(and on-the-fly
(assoc r prj-removed-files
)))
630 (setq m
(memq (or after prj-curfile
) prj-files
))
632 (setcdr m
(cons a
(cdr m
)))
633 (setq prj-files
(prj-add-list prj-files a
))
635 (setq prj-removed-files
(prj-del-list prj-removed-files a
))
639 (defun prj-remove-file (a &optional on-the-fly
)
640 (let ((n (prj-otherfile prj-files a
)) b
)
641 (setq prj-files
(prj-del-list prj-files a
))
642 (when (eq prj-curfile a
)
646 (setq prj-removed-files
(prj-add-list prj-removed-files a
))
648 (unless (prj-config-print)
649 (prj-edit-file prj-curfile
)
652 (message "Removed from project: %s" (car a
))
655 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
658 (defun prj-init-buffer (a b
)
659 (with-current-buffer b
660 (rename-buffer (car a
) t
)
661 (when prj-set-default-directory
667 (defun prj-find-file (a)
671 (setq f
(expand-file-name (car a
) prj-directory
))
672 (setq b
(get-file-buffer f
))
675 (setq b
(find-file-noselect f
))
677 (when (and b
(consp (cdr a
)))
681 (prj-init-buffer a b
)
685 (defun prj-edit-file (a)
686 (let ((f (prj-find-file a
)))
688 (eproject-setup-quit)
689 (switch-to-buffer (car f
))
690 (prj-restore-edit-pos (cdr f
) (selected-window))
692 ;;(message "dir: %s" default-directory)
697 (defun prj-restore-edit-pos (pos w
)
698 (let ((top (car pos
)) (line (cadr pos
)))
699 (when (and (numberp top
) (numberp line
))
701 (set-window-start w
(point))
705 (defun prj-select-window (w)
706 (let (focus-follows-mouse)
708 (select-frame-set-input-focus (window-frame w
))
711 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
712 ;; choose next/previous file
714 (defun eproject-nextfile ()
715 "Switch to the next file that belongs to the current project."
717 (prj-switch-file 'prj-next-file
'next-buffer
)
720 (defun eproject-prevfile ()
721 "Switch to the previous file that belongs to the current project."
723 (prj-switch-file 'prj-prev-file
'previous-buffer
)
726 (defun prj-switch-file (fn1 fn2
)
727 (let ((a (rassoc (current-buffer) prj-files
)))
729 (prj-edit-file (or (funcall fn1 prj-files a
) a
))
732 (prj-edit-file prj-curfile
)
738 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
741 (defun prj-setkeys ()
742 (let ((f (consp prj-current
))
743 (a (assoc 'eproject-mode minor-mode-map-alist
))
744 (map (make-sparse-keymap))
748 (push (cons 'eproject-mode map
) minor-mode-map-alist
)
751 (define-key map
[M-right
] 'eproject-nextfile
)
752 (define-key map
[M-left
] 'eproject-prevfile
)
753 (define-key map
[C-f5
] 'eproject-dired
)
755 (dolist (a prj-tools
)
756 (unless (setq fn
(nth n prj-tools-fns
))
757 (setq fn
(list 'lambda
))
758 (setq prj-tools-fns
(nconc prj-tools-fns
(list fn
)))
760 (setcdr fn
`(() (interactive) (prj-run-tool ',a
)))
762 (when (setq s
(caddr a
))
763 (define-key map
(prj-parse-key s
) (and f fn
))
765 (define-key map
[f5] 'eproject-setup-toggle)
768 (defun prj-parse-key (s)
770 (if (string-match "[a-z][a-z0-9]+$" s)
772 (concat "\"\\" s "\""))))
774 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
777 (defun prj-list-sorted ()
778 (sort (append prj-list nil)
779 '(lambda (a b) (string-lessp (car a) (car b)))
782 (defun prj-setmenu ()
783 (let ((f (consp prj-current)) m1 m2 m3)
786 `(("Open" open ,@(prj-menulist-maker prj-list prj-current 'prj-menu-open))
788 ("Add ..." "Add new or existing project to the list" . eproject-add)
789 ("Remove ..." "Remove project from the list" . eproject-remove)
790 ,@(and f '(("Close" "Close current project" . eproject-close)))
792 ("Setup" "Enter the project setup area." . eproject-setup-toggle)
793 ("Help" "View eproject.txt" . eproject-help)
797 (nconc m1 (cons '("--") (prj-menulist-maker prj-tools nil prj-tools-fns)))
799 `(("Dired" "Browse project directory in Dired - Use 'a' to add file(s) to the project" . eproject-dired)
801 ,@(prj-menulist-maker prj-files prj-curfile 'prj-menu-edit)
806 `((buffer "Project" project ,@m1)
807 (file "List" list ,@m2)
812 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
814 (defun prj-menu-edit ()
816 (let ((a (nth last-command-event prj-files)))
817 (if a (prj-edit-file a))
820 (defun prj-menu-open ()
822 (let ((a (nth last-command-event prj-list)))
823 (if a (eproject-open (car a)))
826 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
828 (defun prj-menu-maker (map l v)
829 (let ((e (list nil)))
830 (setq v (append v e))
831 (dolist (k (reverse l))
833 (when (symbolp (car k))
840 ((and (consp (cdr k)) (symbolp (cadr k)))
843 (setq k (and s (cons (car k) (make-sparse-keymap (car k)))))
846 (setcar e (intern (downcase (car k))))
849 (define-key-after map (vconcat v) k a)
850 (define-key map (vconcat v) k)
852 (if s (prj-menu-maker map s v))
855 (defun prj-copy-head (l n)
857 (while (and l (> n 0))
864 (defun prj-split-list (l n)
867 (push (prj-copy-head l n) r)
868 (setq l (nthcdr n l))
873 (defun prj-menulist-maker (l act fns)
874 (let (r (w 30) s (m 0) (n 0) k)
877 (prj-menulist-maker-1 (list l fns n) act)
880 ;; menu too long; split into submenus
881 (setq s (prj-split-list l w))
882 (setq k (prj-menulist-maker-1 (list (append (pop s) '(("--"))) fns n) act))
883 (setq r (nreverse k))
886 (setq fns (nthcdr w fns))
889 (setq k (prj-menulist-maker-1 (list l fns n) act))
890 (push (cons (concat (prj-shortname (caar l)) " ...")
891 (cons (intern (format "m_%d" (setq m (1+ m))))
897 (defun prj-menulist-maker-1 (l act)
903 (setcar (cddr l) (1+ n))
904 (setq f (if (consp (cadr l))
905 (prog1 (car (cadr l)) (setcar (cdr l) (cdr (cadr l))))
909 (unless (string-match "^ *#" i)
910 (setq s (if (and (consp (cdr a)) (stringp (cadr a))) (cadr a) i))
912 (setq e (cons s (cons (intern s) (prj-menulist-maker-1 l act))))
919 (setq i (prj-shortname i))
920 (setq e (cons n (if (eq a act)
921 `(menu-item ,i ,f :button (:toggle . t) :help ,s)
922 (cons i (cons s f)))))
929 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
930 ;; Run make and other commands
932 (defun prj-compilation-in-frame (cmd)
933 (let ((bn "*compilation*") w h b c f)
934 (unless (get-buffer-window bn t)
935 (setq b (get-buffer-create bn))
936 (setq f (frame-list))
938 (setq w (frame-first-window (car f)))
939 (delete-other-windows w)
942 (setq h (/ (* 70 (frame-height)) 100))
943 (delete-other-windows w)
944 (setq w (split-window w h))
946 (set-window-buffer w b)
948 (let ((display-buffer-reuse-frames t) (f (selected-frame)))
950 (select-frame-set-input-focus f)
954 (cond ((string-match "^-e +" cmd)
955 (setq cmd (read (substring cmd (match-end 0))))
956 (unless (commandp cmd)
957 (setq cmd `(lambda () (interactive) ,cmd))
959 (command-execute cmd)
961 ((let ((b (current-buffer))
962 (old-dir default-directory)
965 (when (string-match "^-in +\\([^[:space:]]+\\) +" cmd)
966 (setq new-dir (match-string-no-properties 1 cmd))
967 (setq cmd (substring cmd (match-end 0)))
969 (when prj-exec-directory
970 (setq new-dir (expand-file-name new-dir prj-exec-directory))
973 (cond ((string-match "\\(.+\\)& *$" cmd)
974 (start-process-shell-command
975 "eproject-async" nil (match-string 1 cmd))
976 (message (match-string 1 cmd))
978 (prj-set-compilation-frame
979 (prj-compilation-in-frame cmd)
984 (with-current-buffer b (cd old-dir))
987 (defun prj-run-tool (a)
988 (unless (string-match "^--+$" (car a))
989 (prj-run (or (cadr a) (car a)))
992 (defun eproject-killtool ()
994 (let ((bn "*compilation*") w0 w1)
995 (when (setq w1 (get-buffer-window bn t))
996 (when (fboundp 'kill-compilation)
997 (setq w0 (selected-window))
1003 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1004 ;; run grep on project files
1006 (defun eproject-grep (command-args)
1007 "Run the grep command on all the project files."
1011 (grep-compute-defaults)
1012 (let ((default (grep-default-command)))
1013 (list (read-from-minibuffer
1014 "Run grep on project files: "
1015 (if current-prefix-arg default grep-command)
1019 (if current-prefix-arg nil default)
1021 (let ((b (current-buffer)) (old-dir default-directory))
1022 (dolist (f (mapcar 'car prj-files))
1023 (setq command-args (concat command-args " " f))
1025 (when prj-directory (cd prj-directory))
1027 (with-current-buffer b (cd old-dir))
1030 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1031 ;; add files to the project with dired
1035 (defun prj-dired-addfiles ()
1039 (dolist (f (dired-get-marked-files))
1040 (setq a (prj-insert-file f))
1043 (setq prj-curfile a)
1045 (message "Added to project: %d file(s)" n)
1049 (defun prj-dired-run ()
1051 (let ((f (dired-get-marked-files)) c)
1052 (and (setq c (pop f))
1054 (let ((prj-directory (file-name-directory c)))
1057 (defun eproject-dired ()
1058 "Start a dired window with the project directory."
1061 (eproject-setup-quit)
1062 ;;(message "Use 'a' to add marked or single files to the project.")
1063 (dired prj-directory)
1064 (let ((map dired-mode-map))
1065 (define-key map [mouse-2] 'dired-find-file)
1066 (define-key map "a" 'prj-dired-addfiles)
1067 (define-key map "r" 'prj-dired-run)
1068 (define-key map [menu-bar operate command] '("Add to Project"
1069 "Add current or marked file(s) to project" . prj-dired-addfiles))
1072 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1074 (defun prj-setup-all ()
1081 (defun prj-getconfig (n)
1082 (let ((a (cdr (assoc n prj-config))))
1086 (defun prj-setconfig (n v)
1087 (let ((a (assoc n prj-config)))
1090 (setq prj-config (nconc prj-config (list a)))
1095 (defun prj-on-kill ()
1099 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1100 ;; isearch in all project files
1102 (defun prj-isearch-function (b wrap)
1104 (or b (setq b (current-buffer)))
1107 (setq a (car prj-files))
1108 (setq a (car (last prj-files)))
1110 ((setq a (rassoc b prj-files))
1112 (setq a (prj-next-file prj-files a))
1113 (setq a (prj-prev-file prj-files a))
1117 (if (buffer-live-p (cdr a))
1119 (setq d (car (prj-find-file a)))
1121 ;; (print `(prj-isearch (wrap . ,wrap) ,b ,d) (get-buffer "*Messages*"))
1125 (defun prj-isearch-setup ()
1126 (cond ((and prj-set-multi-isearch prj-current)
1127 (setq multi-isearch-next-buffer-function 'prj-isearch-function)
1128 (setq multi-isearch-pause 'initial)
1129 (add-hook 'isearch-mode-hook 'multi-isearch-setup)
1132 (remove-hook 'isearch-mode-hook 'multi-isearch-setup)
1135 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1138 (defun prj-startup-delayed ()
1140 (load (eproject-addon "eproject-config") nil t)
1142 ;; When no projects are specified yet, load the eproject project itself.
1144 (load (eproject-addon prj-default-cfg))
1147 ;; no project so far
1150 (add-hook 'kill-emacs-hook 'prj-on-kill)
1152 ;; inhibit open last project when a file was on the commandline
1153 (unless (buffer-file-name (window-buffer))
1156 ;; open last project
1157 (eproject-open prj-last-open)
1159 ;; restore frame position
1160 (when (and prj-set-framepos prj-frame-pos prj-initial-frame)
1161 (modify-frame-parameters prj-initial-frame prj-frame-pos)
1162 ;; emacs bug: when it's too busy it doesn't set frames correctly.
1166 (defun prj-command-line-switch (option)
1167 (setq prj-last-open (pop argv))
1168 (setq inhibit-startup-screen t)
1171 (defun eproject-startup ()
1172 ;; where is this file
1174 (setq eproject-directory (file-name-directory load-file-name)))
1175 (if (boundp 'prj-list)
1177 (load (eproject-addon "eproject-config"))
1181 (when prj-last-open (setq inhibit-startup-screen t))
1182 (when (display-graphic-p) (setq prj-initial-frame (selected-frame)))
1183 (push '("project" . prj-command-line-switch) command-switch-alist)
1184 (run-with-idle-timer 0.1 nil 'prj-startup-delayed)
1187 ;;;###autoload(require 'eproject)
1191 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1192 ;; eproject.el ends here