1 ;; Miscellaneous local functions
3 ;; $Id: misc-local.el,v 1.20 2003/08/04 13:27:17 admin Exp $
7 ;; $Log: misc-local.el,v $
8 ;; Revision 1.20 2003/08/04 13:27:17 admin
9 ;; Import der neuen Version
11 ;; Revision 1.19 2000/02/08 20:27:36 bund
12 ;; Besseres *scratch*-Buffer handling in kill-most-buffers
13 ;; setf in put-hashq/put-hash
15 ;; Revision 1.18 2000/02/04 13:16:45 bund
16 ;; *scratch*-Buffer verwaltung in kill-most-buffers verbessert
18 ;; Revision 1.17 2000/02/03 09:10:53 bund
21 ;; Revision 1.16 2000/02/01 11:21:18 bund
22 ;; Added emi-split-string
25 ;; Revision 1.15 2000/01/26 15:26:58 bund
26 ;; better prefix-arg handling in kill-most-buffers
28 ;; Revision 1.14 2000/01/12 14:38:42 bund
29 ;; Neue funktion: kill-most-buffers
31 ;; Revision 1.13 1999/06/03 15:46:17 bund
32 ;; Added template-document-name function
34 ;; Revision 1.12 1999/02/02 12:48:45 bund
35 ;; Neue implementiereung von date-time-fielname-string et. al.
37 ;; Revision 1.11 1998/10/10 09:35:20 admin
38 ;; BUGFIX: fixed hook dependencies
40 ;; Revision 1.10 1998/10/07 14:33:28 bund
41 ;; Implemented window-size-change-functions hook for dedicated windows
43 ;; Revision 1.9 1998/10/07 13:44:46 bund
44 ;; Implemeted open-dedicated-window and it's friends
46 ;; Revision 1.8 1998/06/17 15:58:30 bund
47 ;; added query-filename-and-check
49 ;; Revision 1.7 1998/06/05 16:22:45 bund
50 ;; added load-add-hook-or-run
52 ;; Revision 1.7 1998/05/17 15:51:38 bund
53 ;; moved adabas-convert-char-byte to dataface.el
55 ;; Revision 1.6 1998/04/23 17:09:52 bund
56 ;; implemented hsxstring conversion functions
58 ;; Revision 1.5 1998/04/16 11:52:48 bund
59 ;; fixed (args-out-of-range) bug in string-replace
61 ;; Revision 1.4 1998/04/14 09:42:45 bund
62 ;; Implemented grep-list and grep-map-list[*]
64 ;; Revision 1.3 1998/03/31 12:47:28 bund
67 ;; Revision 1.2 1998/03/30 08:39:34 bund
73 (defvar kill-most-buffers-nokill-list
74 '("*desktop*" " *Adabas*"))
80 (defun emi-mapcar* (f &rest args)
81 "Apply FUNCTION to successive cars of all ARGS.
82 Return the list of results."
83 (if (not (memq 'nil args))
84 (cons (apply f (mapcar 'car args))
86 (mapcar 'cdr args)))))
88 (defun string-noempty (str)
89 "Return STR if (length STR) > 0, nil otherwise"
90 (if (> (length str) 0)
94 (defun date-time-filename-string (date &optional num)
95 "Return the string YYYYMMDDHHMMSS[nn] for the date DATE.
96 Append nn if NUM is non-nil."
97 (concat (format "%04d%02d%02d%02d%02d%02d"
98 (nth 5 date) (nth 4 date) (nth 3 date)
99 (nth 2 date) (nth 1 date) (nth 0 date))
100 (if num (format "%02d" num) "")))
102 (defun date-time-string (date)
103 "Return DD.MM.YYYY HH:MM for the date DATE."
104 (format "%2d.%02d.%04d %2d:%02d"
105 (nth 3 date) (nth 4 date) (nth 5 date)
106 (nth 2 date) (nth 1 date)))
108 (defun current-date-time-filename-string (&optional num)
109 "Return the string YYYYMMDDHHMMSS[nn] for the current date-and-time.
110 If called interactively insert string at POINT"
113 (insert (date-time-filename-string (decode-time (current-time))))
114 (date-time-filename-string (decode-time (current-time)))))
116 (defun current-date-time-string ()
117 "Return the string DD.MM.YYYY HH:MM for the current date-and-time."
120 (insert (date-time-string (decode-time (current-time))))
121 (date-time-string (decode-time (current-time)))))
123 (defun template-document-name (template)
124 (if (string-match "\\.tmpl$" template)
125 (substring template 0 (match-beginning 0))
128 (defun template-document-extension (template)
129 "Return the extension of TEMPLATE without the trailing .tmpl.
130 That is, if TEMPLATE is 'filename.ext.tmpl', return '.ext'. If
131 TEMPLATE does not have the '.tmpl' extension or the '.ext' part is
133 (if (string-match "\\.tmpl$" template)
135 (setq template (replace-match "" t t template))
136 (if (string-match "^.*\\." template)
137 (replace-match "" t t template)
141 (defun read-file-name-with-default (prompt default &optional existing)
142 "Read file name from user prompting with PROMPT. The user
143 will get DEFAULT provided as default choice"
146 (if (string-match "^.*/" default)
148 (setq dir (match-string 0 default)
149 name (substring default (match-end 0))))
152 (read-file-name prompt
158 (defun string-replace (from to string &optional n start fixedcase literal subexp)
159 "Replate first N occurences, all if T, one if NIL of FROM in STRING
160 with TO. Returns the new string. FIXEDCASE, LITERAL and SUBEXP have
161 the same meaning as in replace-match."
162 (if (not (or (numberp n) n))
164 (while (and (if (numberp n) (> n 0) t)
165 (or (not start) (< start (length string)))
166 (string-match from string start))
167 (setq start (- (match-end 0) (length string))
168 string (replace-match to fixedcase literal string subexp)
169 start (+ start (length string)))
174 (defun emi-split-string (string separator &optional N)
175 "Split STRING at SEPARATOR (a regex). Return list of strings. If N
176 is given, split at most that many times. The last string return will
177 contain the remaining string."
180 (while (and (or (not N) (> N 0))
181 (string-match separator string start))
182 (setq strings (cons (substring string start (match-beginning 0))
186 (nreverse (cons (substring string start) strings))))
188 (defun grep-list (func list)
189 "Create a new list from LIST keeping only elements, for which
190 FUNC returns non-nil."
192 (if (funcall func (car list))
194 (grep-list func (cdr list)))
195 (grep-list func (cdr list)))))
197 (defun grep-map-list (func list)
198 "Apply FUNC to all elements of LIST and build a new list from the
199 return values of FUNC (like mapcar) excluding all nil elements."
201 (let ((elem (funcall func (car list))))
204 (grep-map-list func (cdr list)))
205 (grep-map-list func (cdr list))))))
207 (defun grep-map-list* (func &rest args)
208 "grep-map-list* is to grep-map-list, what emi-mapcar* is to mapcar."
209 (if (not (memq nil args))
210 (let ((elem (apply func (mapcar 'car args))))
213 (apply 'grep-map-list* func (mapcar 'cdr args)))
214 (apply 'grep-map-list* func (mapcar 'cdr args))))))
216 (defun hex-to-nibble (d)
217 (if (and (not (string< d "0"))
220 (- (string-to-char d) ?0)
221 (+ (- (string-to-char (upcase d)) ?A) 10)))
223 (defun hex-to-byte (string)
224 (+ (if (> (length string) 0) (* (hex-to-nibble (substring string 0 1)) 16) 0)
225 (if (> (length string) 1) (hex-to-nibble (substring string 1 2)) 0)))
227 (defun nibble-to-hex (n)
229 (char-to-string (+ ?0 n))
230 (char-to-string (+ ?A (- n 10)))))
232 (defun byte-to-hex (n)
233 (concat (nibble-to-hex (% (/ n 16) 16))
234 (nibble-to-hex (% n 16))))
236 (defun string-to-hexstring (value)
238 (while (> (length value) 0)
239 (setq v (concat v (byte-to-hex (string-to-char value)))
240 value (substring value 1)))
243 (defun hexstring-to-string (value)
245 (while (> (length value) 1)
246 (setq v (concat v (char-to-string (hex-to-byte value)))
247 value (substring value 2)))
250 (defun load-hook-add-or-run (feature hook-symbol hook)
251 "If FEATURE is present, immediately execute HOOK, otherwise add it to
252 HOOK-SYMBOL (preferably a load hook symbol)"
253 (if (featurep feature)
255 (add-hook hook-symbol hook)))
257 (defun query-filename-and-check (prompt &optional directory default initial)
258 "Query the user for the name of a new file. If FILENAME allready exists,
259 query wether to overwrite it and delete the file in the affirmative case.
260 Returns the filename entered. If the user terminates the request, a quit
261 condition is generated."
262 (let* ((filename (read-file-name prompt directory default nil initial))
263 (filebuffer (find-buffer-visiting filename))
264 (fileexists (file-readable-p filename)))
265 (if (not (if (or filebuffer fileexists)
266 (yes-or-no-p (concat "Overwrite " filename "? "))
269 (if fileexists (delete-file filename))
270 (if filebuffer (kill-buffer filebuffer)))
273 (defvar assign-window-buffer-window nil)
274 (defvar assign-window-buffer-buffers nil)
275 (put 'assign-window-buffer-window 'permanent-local t)
276 (put 'assign-window-buffer-buffers 'permanent-local t)
277 (make-variable-buffer-local 'assign-window-buffer-window)
278 (make-variable-buffer-local 'assign-window-buffer-buffers)
279 (put 'kill-buffer-hook 'permanent-local t)
280 (defvar assign-window-windows nil)
281 (defvar assign-window-hook-running nil)
283 (defun assign-window-to-buffer (buffer window &optional window-conf other-buffers)
284 "Assigns WINDOW to be fixed on displaying BUFFER. If BUFFER is
285 killed, the WINDOW is killed to. If WINDOW-CONF is given, instead of
286 killing the buffer, the WINDOW-CONFiguration is restored. If
287 OTHER-BUFFERS is given, theese buffers are killed together with
288 BUFFER, if BUFFER is killed."
289 (select-window window)
290 (switch-to-buffer buffer)
291 (setq buffer (get-buffer buffer))
292 (make-local-hook 'kill-buffer-hook)
293 (setq assign-window-buffer-window (cons window window-conf)
294 assign-window-buffer-buffers
295 (delq buffer (mapcar (function
297 (get-buffer buffer)))
299 (add-hook 'kill-buffer-hook 'assign-window-to-buffer-hook t t)
300 (setq assign-window-windows (cons (cons window buffer) assign-window-windows))
301 (set-window-dedicated-p window t))
303 ;;;FIXME: There's an emacs bug: If the dedicated window is the
304 ;;; right/top one of a split, killing the dedicated window will
305 ;;; result in the combined window having the dedicated flag
306 ;;; set. Workaround ???
307 (defun assign-window-change-hook (frame)
308 (let ((p assign-window-windows)
309 (assign-window-hook-running t)
312 (if (not (window-live-p (car (car p))))
314 (if (buffer-live-p (cdr (car p)))
315 (kill-buffer (cdr (car p))))
317 (setcdr last (cdr p))
318 (setq assign-window-windows (cdr p)))
323 (if (not (memq 'assign-window-change-hook window-size-change-functions))
324 (setq window-size-change-functions
325 (cons 'assign-window-change-hook window-size-change-functions)))
327 (defun assign-window-to-buffer-hook ()
328 (if (and (boundp 'assign-window-buffer-window)
329 (boundp 'assign-window-buffer-buffers))
330 (let ((window assign-window-buffer-window)
331 (buffers assign-window-buffer-buffers)
332 (old-assign-window-hook-running (and (boundp 'assign-window-hook-running)
333 assign-window-hook-running))
334 (assign-window-hook-running t))
335 (setq assign-window-windows
337 (lambda (x) (eq (cdr x) (current-buffer))))
338 assign-window-windows))
339 (if (window-live-p (car window))
340 (set-window-dedicated-p (car window) nil))
342 (if (not old-assign-window-hook-running)
343 (set-window-configuration (cdr window)))
344 (if (window-live-p (car window))
345 (delete-window (car window))))
347 (mapcar (function (lambda (buffer)
348 (if (buffer-live-p buffer) (kill-buffer buffer))))
351 (defun save-split-window (&optional size horizontal)
352 "Split the current window vertically, horizontally if HORIZONTAL is
353 non-nil, if the size of the current frame permits.
355 size is passed to split-window-[horizontally|vertically] but adjusted
356 using window-min-width or window-min-height respectively.
358 The selected window will be the old one, i.e. the left/top one. The
359 return value will be the new window, or nil if the window was not
362 (> (window-width) (+ (* 2 window-min-width) 2))
363 (> (window-height) (+ (* 2 window-min-height) 1)))
368 (setq size (- (max window-min-width (- size))))
369 (setq size (- (max window-min-height (- size)))))
371 (setq size (max window-min-width size))
372 (setq size (max window-min-height size)))))
374 (split-window-horizontally size)
375 (split-window-vertically size)))))
377 (defun open-dedicated-window (buffer &optional size horizontal)
378 "Open a new window visiting BUFFER. This new window will be assign
379 to BUFFER using assign-window-to-buffer. If SIZE is given, it gives
380 the size of the new window to open. By default the current window is
381 split vertically. If HORIZONTAL is non-nil, the window is split
384 If SIZE is positive, the left/top window after splitting will be the
385 new window, if SIZE is negative, the right/bottom window will be
386 used. if SIZE is not nil and not a number, the right/bottom window
387 will be used, but no explicit SIZE is requested.
389 The selected buffer and window will be the newly opened window with
390 it's bufer. The return value will be the window showing the buffer
391 active before calling this function. If the window could not be split,
392 because the frame is to small, BUFFER will be the selected buffer in
393 the current window and the return value is nil."
394 (let ((size (and (numberp size) size))
395 (which (if (numberp size) (< size 0) size))
396 (wc (current-window-configuration))
398 (if (setq other (save-split-window size horizontal))
402 other (selected-window))
403 (select-window this))
404 (setq this (selected-window))))
405 (assign-window-to-buffer buffer (selected-window) wc)
408 (defun kill-most-buffers (arg)
409 "Kill all Buffers exept those in kill-most-buffers-nokill-list.
411 If called with a negative prefix- argument, the current buffer will
412 not be killed. If called with a positive prefix argument only
413 non-displayed buffers are killed.
415 Additionally will make all windows in all frames schow the `*scratch*'
418 (loop for buffer being the buffers
420 (if (> (prefix-numeric-value arg) 0)
421 (get-buffer-window buffer t)
422 (eq buffer (current-buffer))))
423 (member (buffer-name buffer)
424 kill-most-buffers-nokill-list)))
425 do (kill-buffer buffer))
426 (if (get-buffer "*scratch*")
427 (kill-buffer "*scratch*"))
428 (get-buffer-create "*scratch*")
429 (if (not (and arg (> (prefix-numeric-value arg) 0)))
430 (loop for window being the windows
431 if (not (and arg (eq window (selected-window))))
432 do (set-window-buffer window "*scratch*"))))
434 (defmacro put-hashq (element hash)
435 "Place ELEMENT into HASH."
436 (let ((x (make-symbol "x"))
437 (y (make-symbol "y")))
438 `(let* ((,x ,element)
439 (,y (assq (car ,x) ,hash)))
441 (progn (setcdr ,y (cdr ,x)) ,y)
442 (progn (setf ,hash (cons ,x ,hash)) ,x)))))
444 (defmacro put-hash (element hash)
445 "Place ELEMENT into HASH."
446 (let ((x (make-symbol "x"))
447 (y (make-symbol "y")))
448 `(let* ((,x ,element)
449 (,y (assoc (car ,x) ,hash)))
451 (progn (setcdr ,y (cdr ,x)) ,y)
452 (progn (setf ,hash (cons ,x ,hash)) ,x)))))
454 (provide 'misc-local)