| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 |
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 |
|
|---|
| 32 |
|
|---|
| 33 |
(require 'wid-edit) |
|---|
| 34 |
|
|---|
| 35 |
(defgroup gmm nil |
|---|
| 36 |
"Utility functions for Gnus, Message and MML" |
|---|
| 37 |
:prefix "gmm-" |
|---|
| 38 |
:version "22.1" |
|---|
| 39 |
:group 'lisp) |
|---|
| 40 |
|
|---|
| 41 |
|
|---|
| 42 |
|
|---|
| 43 |
(defcustom gmm-verbose 7 |
|---|
| 44 |
"Integer that says how verbose gmm should be. |
|---|
| 45 |
The higher the number, the more messages will flash to say what |
|---|
| 46 |
it done. At zero, it will be totally mute; at five, it will |
|---|
| 47 |
display most important messages; and at ten, it will keep on |
|---|
| 48 |
jabbering all the time." |
|---|
| 49 |
:type 'integer |
|---|
| 50 |
:group 'gmm) |
|---|
| 51 |
|
|---|
| 52 |
|
|---|
| 53 |
(defun gmm-message (level &rest args) |
|---|
| 54 |
"If LEVEL is lower than `gmm-verbose' print ARGS using `message'. |
|---|
| 55 |
|
|---|
| 56 |
Guideline for numbers: |
|---|
| 57 |
1 - error messages, 3 - non-serious error messages, 5 - messages for things |
|---|
| 58 |
that take a long time, 7 - not very important messages on stuff, 9 - messages |
|---|
| 59 |
inside loops." |
|---|
| 60 |
(if (<= level gmm-verbose) |
|---|
| 61 |
(apply 'message args) |
|---|
| 62 |
|
|---|
| 63 |
|
|---|
| 64 |
|
|---|
| 65 |
(apply 'format args))) |
|---|
| 66 |
|
|---|
| 67 |
|
|---|
| 68 |
(defun gmm-error (level &rest args) |
|---|
| 69 |
"Beep an error if LEVEL is equal to or less than `gmm-verbose'. |
|---|
| 70 |
ARGS are passed to `message'." |
|---|
| 71 |
(when (<= (floor level) gmm-verbose) |
|---|
| 72 |
(apply 'message args) |
|---|
| 73 |
(ding) |
|---|
| 74 |
(let (duration) |
|---|
| 75 |
(when (and (floatp level) |
|---|
| 76 |
(not (zerop (setq duration (* 10 (- level (floor level))))))) |
|---|
| 77 |
(sit-for duration)))) |
|---|
| 78 |
nil) |
|---|
| 79 |
|
|---|
| 80 |
|
|---|
| 81 |
(defun gmm-widget-p (symbol) |
|---|
| 82 |
"Non-nil if SYMBOL is a widget." |
|---|
| 83 |
(get symbol 'widget-type)) |
|---|
| 84 |
|
|---|
| 85 |
|
|---|
| 86 |
(define-widget 'gmm-lazy 'default |
|---|
| 87 |
"Base widget for recursive datastructures. |
|---|
| 88 |
|
|---|
| 89 |
This is copy of the `lazy' widget in Emacs 22.1 provided for compatibility." |
|---|
| 90 |
:format "%{%t%}: %v" |
|---|
| 91 |
:convert-widget 'widget-value-convert-widget |
|---|
| 92 |
:value-create (lambda (widget) |
|---|
| 93 |
(let ((value (widget-get widget :value)) |
|---|
| 94 |
(type (widget-get widget :type))) |
|---|
| 95 |
(widget-put widget :children |
|---|
| 96 |
(list (widget-create-child-value |
|---|
| 97 |
widget (widget-convert type) value))))) |
|---|
| 98 |
:value-delete 'widget-children-value-delete |
|---|
| 99 |
:value-get (lambda (widget) |
|---|
| 100 |
(widget-value (car (widget-get widget :children)))) |
|---|
| 101 |
:value-inline (lambda (widget) |
|---|
| 102 |
(widget-apply (car (widget-get widget :children)) |
|---|
| 103 |
:value-inline)) |
|---|
| 104 |
:default-get (lambda (widget) |
|---|
| 105 |
(widget-default-get |
|---|
| 106 |
(widget-convert (widget-get widget :type)))) |
|---|
| 107 |
:match (lambda (widget value) |
|---|
| 108 |
(widget-apply (widget-convert (widget-get widget :type)) |
|---|
| 109 |
:match value)) |
|---|
| 110 |
:validate (lambda (widget) |
|---|
| 111 |
(widget-apply (car (widget-get widget :children)) :validate))) |
|---|
| 112 |
|
|---|
| 113 |
|
|---|
| 114 |
|
|---|
| 115 |
|
|---|
| 116 |
|
|---|
| 117 |
|
|---|
| 118 |
|
|---|
| 119 |
|
|---|
| 120 |
|
|---|
| 121 |
|
|---|
| 122 |
|
|---|
| 123 |
|
|---|
| 124 |
|
|---|
| 125 |
|
|---|
| 126 |
|
|---|
| 127 |
|
|---|
| 128 |
|
|---|
| 129 |
|
|---|
| 130 |
|
|---|
| 131 |
|
|---|
| 132 |
(define-widget 'gmm-tool-bar-item (if (gmm-widget-p 'lazy) 'lazy 'gmm-lazy) |
|---|
| 133 |
"Tool bar list item." |
|---|
| 134 |
:tag "Tool bar item" |
|---|
| 135 |
:type '(choice |
|---|
| 136 |
(list :tag "Command and Icon" |
|---|
| 137 |
(function :tag "Command") |
|---|
| 138 |
(string :tag "Icon file") |
|---|
| 139 |
(choice |
|---|
| 140 |
(const :tag "Default map" nil) |
|---|
| 141 |
|
|---|
| 142 |
(const :tag "No menu" t) |
|---|
| 143 |
(sexp :tag "Other map")) |
|---|
| 144 |
(plist :inline t :tag "Properties")) |
|---|
| 145 |
(list :tag "Separator" |
|---|
| 146 |
(const :tag "No command" gmm-ignore) |
|---|
| 147 |
(string :tag "Icon file") |
|---|
| 148 |
(const :tag "No map") |
|---|
| 149 |
(plist :inline t :tag "Properties")))) |
|---|
| 150 |
|
|---|
| 151 |
(define-widget 'gmm-tool-bar-zap-list (if (gmm-widget-p 'lazy) 'lazy 'gmm-lazy) |
|---|
| 152 |
"Tool bar zap list." |
|---|
| 153 |
:tag "Tool bar zap list" |
|---|
| 154 |
:type '(choice (const :tag "Zap all" t) |
|---|
| 155 |
(const :tag "Keep all" nil) |
|---|
| 156 |
(list |
|---|
| 157 |
|
|---|
| 158 |
|
|---|
| 159 |
|
|---|
| 160 |
|
|---|
| 161 |
|
|---|
| 162 |
(set :inline t |
|---|
| 163 |
(const new-file) |
|---|
| 164 |
(const open-file) |
|---|
| 165 |
(const dired) |
|---|
| 166 |
(const kill-buffer) |
|---|
| 167 |
(const save-buffer) |
|---|
| 168 |
(const write-file) |
|---|
| 169 |
(const undo) |
|---|
| 170 |
(const cut) |
|---|
| 171 |
(const copy) |
|---|
| 172 |
(const paste) |
|---|
| 173 |
(const search-forward) |
|---|
| 174 |
(const print-buffer) |
|---|
| 175 |
(const customize) |
|---|
| 176 |
(const help)) |
|---|
| 177 |
(repeat :inline t |
|---|
| 178 |
:tag "Other" |
|---|
| 179 |
(symbol :tag "Icon item"))))) |
|---|
| 180 |
|
|---|
| 181 |
|
|---|
| 182 |
|
|---|
| 183 |
|
|---|
| 184 |
|
|---|
| 185 |
|
|---|
| 186 |
|
|---|
| 187 |
|
|---|
| 188 |
|
|---|
| 189 |
|
|---|
| 190 |
|
|---|
| 191 |
|
|---|
| 192 |
|
|---|
| 193 |
|
|---|
| 194 |
|
|---|
| 195 |
|
|---|
| 196 |
(defcustom gmm-tool-bar-style |
|---|
| 197 |
(if (and (boundp 'tool-bar-mode) |
|---|
| 198 |
tool-bar-mode |
|---|
| 199 |
(and (fboundp 'display-visual-class) |
|---|
| 200 |
(not (memq (display-visual-class) |
|---|
| 201 |
(list 'static-gray 'gray-scale |
|---|
| 202 |
'static-color 'pseudo-color))))) |
|---|
| 203 |
'gnome |
|---|
| 204 |
'retro) |
|---|
| 205 |
"Prefered tool bar style." |
|---|
| 206 |
:type '(choice (const :tag "GNOME style" gnome) |
|---|
| 207 |
(const :tag "Retro look" retro)) |
|---|
| 208 |
:group 'gmm) |
|---|
| 209 |
|
|---|
| 210 |
(defvar tool-bar-map) |
|---|
| 211 |
|
|---|
| 212 |
|
|---|
| 213 |
(defun gmm-tool-bar-from-list (icon-list zap-list default-map) |
|---|
| 214 |
"Make a tool bar from ICON-LIST. |
|---|
| 215 |
|
|---|
| 216 |
Within each entry of ICON-LIST, the first element is a menu |
|---|
| 217 |
command, the second element is an icon file name and the third |
|---|
| 218 |
element is a test function. You can use \\[describe-key] |
|---|
| 219 |
<menu-entry> to find out the name of a menu command. The fourth |
|---|
| 220 |
and all following elements are passed as the PROPS argument to the |
|---|
| 221 |
function `tool-bar-local-item'. |
|---|
| 222 |
|
|---|
| 223 |
If ZAP-LIST is a list, remove those item from the default |
|---|
| 224 |
`tool-bar-map'. If it is t, start with a new sparse map. You |
|---|
| 225 |
can use \\[describe-key] <icon> to find out the name of an icon |
|---|
| 226 |
item. When \\[describe-key] <icon> shows \"<tool-bar> <new-file> |
|---|
| 227 |
runs the command find-file\", then use `new-file' in ZAP-LIST. |
|---|
| 228 |
|
|---|
| 229 |
DEFAULT-MAP specifies the default key map for ICON-LIST." |
|---|
| 230 |
(let ( |
|---|
| 231 |
|
|---|
| 232 |
(tool-bar-map (if (eq zap-list t) |
|---|
| 233 |
(make-sparse-keymap) |
|---|
| 234 |
(copy-keymap tool-bar-map)))) |
|---|
| 235 |
(when (listp zap-list) |
|---|
| 236 |
|
|---|
| 237 |
(dolist (key zap-list) |
|---|
| 238 |
(define-key tool-bar-map (vector key) nil))) |
|---|
| 239 |
(mapc (lambda (el) |
|---|
| 240 |
(let ((command (car el)) |
|---|
| 241 |
(icon (nth 1 el)) |
|---|
| 242 |
(fmap (or (nth 2 el) default-map)) |
|---|
| 243 |
(props (cdr (cdr (cdr el)))) ) |
|---|
| 244 |
|
|---|
| 245 |
(cond ((eq command 'gmm-ignore) |
|---|
| 246 |
|
|---|
| 247 |
|
|---|
| 248 |
(if (fboundp 'tool-bar-local-item) |
|---|
| 249 |
(apply 'tool-bar-local-item icon nil nil |
|---|
| 250 |
tool-bar-map :enable nil props) |
|---|
| 251 |
|
|---|
| 252 |
|
|---|
| 253 |
(apply 'tool-bar-add-item icon nil nil :enable nil props))) |
|---|
| 254 |
((equal fmap t) |
|---|
| 255 |
(if (fboundp 'tool-bar-local-item) |
|---|
| 256 |
(apply 'tool-bar-local-item |
|---|
| 257 |
icon command |
|---|
| 258 |
(intern icon) |
|---|
| 259 |
tool-bar-map props) |
|---|
| 260 |
|
|---|
| 261 |
(apply 'tool-bar-add-item |
|---|
| 262 |
icon command |
|---|
| 263 |
(intern icon) |
|---|
| 264 |
props))) |
|---|
| 265 |
(t |
|---|
| 266 |
(if (fboundp 'tool-bar-local-item-from-menu) |
|---|
| 267 |
(apply 'tool-bar-local-item-from-menu |
|---|
| 268 |
|
|---|
| 269 |
|
|---|
| 270 |
command icon tool-bar-map (symbol-value fmap) |
|---|
| 271 |
props) |
|---|
| 272 |
|
|---|
| 273 |
(apply 'tool-bar-add-item-from-menu |
|---|
| 274 |
command icon (symbol-value fmap) |
|---|
| 275 |
props)))) |
|---|
| 276 |
t)) |
|---|
| 277 |
(if (symbolp icon-list) |
|---|
| 278 |
(eval icon-list) |
|---|
| 279 |
icon-list)) |
|---|
| 280 |
tool-bar-map)) |
|---|
| 281 |
|
|---|
| 282 |
(defmacro defun-gmm (name function arg-list &rest body) |
|---|
| 283 |
"Create function NAME. |
|---|
| 284 |
If FUNCTION exists, then NAME becomes an alias for FUNCTION. |
|---|
| 285 |
Otherwise, create function NAME with ARG-LIST and BODY." |
|---|
| 286 |
(let ((defined-p (fboundp function))) |
|---|
| 287 |
(if defined-p |
|---|
| 288 |
`(defalias ',name ',function) |
|---|
| 289 |
`(defun ,name ,arg-list ,@body)))) |
|---|
| 290 |
|
|---|
| 291 |
(defun-gmm gmm-image-search-load-path |
|---|
| 292 |
image-search-load-path (file &optional path) |
|---|
| 293 |
"Emacs 21 and XEmacs don't have `image-search-load-path'. |
|---|
| 294 |
This function returns nil on those systems." |
|---|
| 295 |
nil) |
|---|
| 296 |
|
|---|
| 297 |
|
|---|
| 298 |
|
|---|
| 299 |
(defun-gmm gmm-image-load-path-for-library |
|---|
| 300 |
image-load-path-for-library (library image &optional path no-error) |
|---|
| 301 |
"Return a suitable search path for images used by LIBRARY. |
|---|
| 302 |
|
|---|
| 303 |
It searches for IMAGE in `image-load-path' (excluding |
|---|
| 304 |
\"`data-directory'/images\") and `load-path', followed by a path |
|---|
| 305 |
suitable for LIBRARY, which includes \"../../etc/images\" and |
|---|
| 306 |
\"../etc/images\" relative to the library file itself, and then |
|---|
| 307 |
in \"`data-directory'/images\". |
|---|
| 308 |
|
|---|
| 309 |
Then this function returns a list of directories which contains |
|---|
| 310 |
first the directory in which IMAGE was found, followed by the |
|---|
| 311 |
value of `load-path'. If PATH is given, it is used instead of |
|---|
| 312 |
`load-path'. |
|---|
| 313 |
|
|---|
| 314 |
If NO-ERROR is non-nil and a suitable path can't be found, don't |
|---|
| 315 |
signal an error. Instead, return a list of directories as before, |
|---|
| 316 |
except that nil appears in place of the image directory. |
|---|
| 317 |
|
|---|
| 318 |
Here is an example that uses a common idiom to provide |
|---|
| 319 |
compatibility with versions of Emacs that lack the variable |
|---|
| 320 |
`image-load-path': |
|---|
| 321 |
|
|---|
| 322 |
;; Shush compiler. |
|---|
| 323 |
(defvar image-load-path) |
|---|
| 324 |
|
|---|
| 325 |
(let* ((load-path (image-load-path-for-library \"mh-e\" \"mh-logo.xpm\")) |
|---|
| 326 |
(image-load-path (cons (car load-path) |
|---|
| 327 |
(when (boundp 'image-load-path) |
|---|
| 328 |
image-load-path)))) |
|---|
| 329 |
(mh-tool-bar-folder-buttons-init))" |
|---|
| 330 |
(unless library (error "No library specified")) |
|---|
| 331 |
(unless image (error "No image specified")) |
|---|
| 332 |
(let (image-directory image-directory-load-path) |
|---|
| 333 |
|
|---|
| 334 |
(let ((img image) |
|---|
| 335 |
(dir (or |
|---|
| 336 |
|
|---|
| 337 |
(gmm-image-search-load-path image) |
|---|
| 338 |
|
|---|
| 339 |
(locate-library image))) |
|---|
| 340 |
parent) |
|---|
| 341 |
|
|---|
| 342 |
|
|---|
| 343 |
|
|---|
| 344 |
(when dir |
|---|
| 345 |
(setq dir (file-name-directory dir)) |
|---|
| 346 |
(while (setq parent (file-name-directory img)) |
|---|
| 347 |
(setq img (directory-file-name parent) |
|---|
| 348 |
dir (expand-file-name "../" dir)))) |
|---|
| 349 |
(setq image-directory-load-path dir)) |
|---|
| 350 |
|
|---|
| 351 |
|
|---|
| 352 |
|
|---|
| 353 |
|
|---|
| 354 |
|
|---|
| 355 |
(cond |
|---|
| 356 |
|
|---|
| 357 |
((and image-directory-load-path |
|---|
| 358 |
(not (equal image-directory-load-path |
|---|
| 359 |
(file-name-as-directory |
|---|
| 360 |
(expand-file-name "images" data-directory))))) |
|---|
| 361 |
(setq image-directory image-directory-load-path)) |
|---|
| 362 |
|
|---|
| 363 |
((let (library-name d1ei d2ei) |
|---|
| 364 |
|
|---|
| 365 |
(setq library-name (locate-library library)) |
|---|
| 366 |
(if (not library-name) |
|---|
| 367 |
(error "Cannot find library %s in load-path" library)) |
|---|
| 368 |
|
|---|
| 369 |
(setq |
|---|
| 370 |
|
|---|
| 371 |
d2ei (file-name-as-directory |
|---|
| 372 |
(expand-file-name |
|---|
| 373 |
(concat (file-name-directory library-name) "../../etc/images"))) |
|---|
| 374 |
|
|---|
| 375 |
d1ei (file-name-as-directory |
|---|
| 376 |
(expand-file-name |
|---|
| 377 |
(concat (file-name-directory library-name) "../etc/images")))) |
|---|
| 378 |
(setq image-directory |
|---|
| 379 |
|
|---|
| 380 |
(cond ((file-exists-p (expand-file-name image d2ei)) d2ei) |
|---|
| 381 |
((file-exists-p (expand-file-name image d1ei)) d1ei))))) |
|---|
| 382 |
|
|---|
| 383 |
(image-directory-load-path |
|---|
| 384 |
(setq image-directory image-directory-load-path)) |
|---|
| 385 |
(no-error |
|---|
| 386 |
(message "Could not find image %s for library %s" image library)) |
|---|
| 387 |
(t |
|---|
| 388 |
(error "Could not find image %s for library %s" image library))) |
|---|
| 389 |
|
|---|
| 390 |
|
|---|
| 391 |
(nconc (list image-directory) |
|---|
| 392 |
(delete image-directory (copy-sequence (or path load-path)))))) |
|---|
| 393 |
|
|---|
| 394 |
(defun gmm-customize-mode (&optional mode) |
|---|
| 395 |
"Customize customization group for MODE. |
|---|
| 396 |
If mode is nil, use `major-mode' of the curent buffer." |
|---|
| 397 |
(interactive) |
|---|
| 398 |
(customize-group |
|---|
| 399 |
(or mode |
|---|
| 400 |
(intern (let ((mode (symbol-name major-mode))) |
|---|
| 401 |
(string-match "^\\(.+\\)-mode$" mode) |
|---|
| 402 |
(match-string 1 mode)))))) |
|---|
| 403 |
|
|---|
| 404 |
(defun gmm-write-region (start end filename &optional append visit |
|---|
| 405 |
lockname mustbenew) |
|---|
| 406 |
"Compatibility function for `write-region'. |
|---|
| 407 |
|
|---|
| 408 |
In XEmacs, the seventh argument of `write-region' specifies the |
|---|
| 409 |
coding-system." |
|---|
| 410 |
(if (and mustbenew |
|---|
| 411 |
(or (featurep 'xemacs) |
|---|
| 412 |
(= emacs-major-version 20))) |
|---|
| 413 |
(if (file-exists-p filename) |
|---|
| 414 |
(signal 'file-already-exists |
|---|
| 415 |
(list "File exists" filename)) |
|---|
| 416 |
(write-region start end filename append visit lockname)) |
|---|
| 417 |
(write-region start end filename append visit lockname mustbenew))) |
|---|
| 418 |
|
|---|
| 419 |
(provide 'gmm-utils) |
|---|
| 420 |
|
|---|
| 421 |
|
|---|
| 422 |
|
|---|
| 423 |
|
|---|