1;;; gmm-utils.el --- Utility functions for Gnus, Message and MML 2 3;; Copyright (C) 2006-2021 Free Software Foundation, Inc. 4 5;; Author: Reiner Steib <reiner.steib@gmx.de> 6;; Keywords: news 7 8;; This file is part of GNU Emacs. 9 10;; GNU Emacs 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 3 of the License, or 13;; (at your option) any later version. 14 15;; GNU Emacs 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. 19 20;; You should have received a copy of the GNU General Public License 21;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. 22 23;;; Commentary: 24 25;; This library provides self-contained utility functions. The functions are 26;; used in Gnus, Message and MML, but within this library there are no 27;; dependencies on Gnus, Message, or MML. 28 29;;; Code: 30 31(defgroup gmm nil 32 "Utility functions for Gnus, Message and MML." 33 :prefix "gmm-" 34 :version "22.1" ;; Gnus 5.10.9 35 :group 'lisp) 36 37;; Helper functions from `gnus-utils.el': gmm-verbose, gmm-message, gmm-error 38 39(defcustom gmm-verbose 7 40 "Integer that says how verbose gmm should be. 41The higher the number, the more messages will flash to say what 42it did. At zero, it will be totally mute; at five, it will 43display most important messages; and at ten, it will keep on 44jabbering all the time." 45 :type 'integer 46 :group 'gmm) 47 48;;;###autoload 49(defun gmm-regexp-concat (regexp) 50 "Potentially concat a list of regexps into a single one. 51The concatenation is done with logical ORs." 52 (cond ((null regexp) 53 nil) 54 ((stringp regexp) 55 regexp) 56 ((listp regexp) 57 (mapconcat (lambda (elt) (concat "\\(" elt "\\)")) 58 regexp 59 "\\|")))) 60 61;;;###autoload 62(defun gmm-message (level &rest args) 63 "If LEVEL is lower than `gmm-verbose' print ARGS using `message'. 64 65Guideline for numbers: 661 - error messages 673 - non-serious error messages 685 - messages for things that take a long time 697 - not very important messages on stuff 709 - messages inside loops." 71 (if (<= level gmm-verbose) 72 (apply 'message args) 73 ;; We have to do this format thingy here even if the result isn't 74 ;; shown - the return value has to be the same as the return value 75 ;; from `message'. 76 (apply 'format args))) 77 78;;;###autoload 79(defun gmm-error (level &rest args) 80 "Beep an error if LEVEL is equal to or less than `gmm-verbose'. 81ARGS are passed to `message'." 82 (when (<= (floor level) gmm-verbose) 83 (apply 'message args) 84 (ding) 85 (let (duration) 86 (when (and (floatp level) 87 (not (zerop (setq duration (* 10 (- level (floor level))))))) 88 (sit-for duration)))) 89 nil) 90 91;;;###autoload 92(defun gmm-widget-p (symbol) 93 "Non-nil if SYMBOL is a widget." 94 (get symbol 'widget-type)) 95 96(autoload 'widget-create-child-value "wid-edit") 97(autoload 'widget-convert "wid-edit") 98(autoload 'widget-default-get "wid-edit") 99 100;; Note: The format of `gmm-tool-bar-item' may change if some future Emacs 101;; version will provide customizable tool bar buttons using a different 102;; interface. 103 104;; TODO: Extend API so that the "Command" entry can be a function or a plist. 105;; In case of a list it should have the format... 106;; 107;; (:none command-without-modifier 108;; :shift command-with-shift-pressed 109;; :control command-with-ctrl-pressed 110;; :control-shift command-with-control-and-shift-pressed 111;; ;; mouse-2 and mouse-3 can't be used in Emacs yet. 112;; :mouse-2 command-on-mouse-2-press 113;; :mouse-3 command-on-mouse-3-press) ;; typically a menu of related commands 114;; 115;; Combinations of mouse-[23] plus shift and/or control might be overkill. 116;; 117;; Then use (plist-get rs-command :none), (plist-get rs-command :shift) 118 119(define-widget 'gmm-tool-bar-item 'lazy 120 "Tool bar list item." 121 :tag "Tool bar item" 122 :type '(choice 123 (list :tag "Command and Icon" 124 (function :tag "Command") 125 (string :tag "Icon file") 126 (choice 127 (const :tag "Default map" nil) 128 ;; Note: Usually we need non-nil attributes if map is t. 129 (const :tag "No menu" t) 130 (sexp :tag "Other map")) 131 (plist :inline t :tag "Properties")) 132 (list :tag "Separator" 133 (const :tag "No command" gmm-ignore) 134 (string :tag "Icon file") 135 (const :tag "No map") 136 (plist :inline t :tag "Properties")))) 137 138(define-widget 'gmm-tool-bar-zap-list 'lazy 139 "Tool bar zap list." 140 :tag "Tool bar zap list" 141 :type '(choice (const :tag "Zap all" t) 142 (const :tag "Keep all" nil) 143 (list 144 ;; :value 145 ;; Work around (bug in customize?), see 146 ;; <news:v9is48jrj1.fsf@marauder.physik.uni-ulm.de> 147 ;; (new-file open-file dired kill-buffer write-file 148 ;; print-buffer customize help) 149 (set :inline t 150 (const new-file) 151 (const open-file) 152 (const dired) 153 (const kill-buffer) 154 (const save-buffer) 155 (const write-file) 156 (const undo) 157 (const cut) 158 (const copy) 159 (const paste) 160 (const search-forward) 161 (const print-buffer) 162 (const customize) 163 (const help)) 164 (repeat :inline t 165 :tag "Other" 166 (symbol :tag "Icon item"))))) 167 168(defcustom gmm-tool-bar-style 169 (if (and (boundp 'tool-bar-mode) 170 tool-bar-mode 171 (memq (display-visual-class) 172 (list 'static-gray 'gray-scale 173 'static-color 'pseudo-color))) 174 'gnome 175 'retro) 176 "Preferred tool bar style." 177 :type '(choice (const :tag "GNOME style" gnome) 178 (const :tag "Retro look" retro)) 179 :group 'gmm) 180 181(defvar tool-bar-map) 182 183;;;###autoload 184(defun gmm-tool-bar-from-list (icon-list zap-list default-map) 185 "Make a tool bar from ICON-LIST. 186 187Within each entry of ICON-LIST, the first element is a menu 188command, the second element is an icon file name and the third 189element is a test function. You can use \\[describe-key] 190<menu-entry> to find out the name of a menu command. The fourth 191and all following elements are passed as the PROPS argument to the 192function `tool-bar-local-item'. 193 194If ZAP-LIST is a list, remove those item from the default 195`tool-bar-map'. If it is t, start with a new sparse map. You 196can use \\[describe-key] <icon> to find out the name of an icon 197item. When \\[describe-key] <icon> shows \"<tool-bar> <new-file> 198runs the command find-file\", then use `new-file' in ZAP-LIST. 199 200DEFAULT-MAP specifies the default key map for ICON-LIST." 201 (let ((map (if (eq zap-list t) 202 (make-sparse-keymap) 203 (copy-keymap tool-bar-map)))) 204 (when (listp zap-list) 205 ;; Zap some items which aren't relevant for this mode and take up space. 206 (dolist (key zap-list) 207 (define-key map (vector key) nil))) 208 (mapc (lambda (el) 209 (let ((command (car el)) 210 (icon (nth 1 el)) 211 (fmap (or (nth 2 el) default-map)) 212 (props (cdr (cdr (cdr el)))) ) 213 ;; command may stem from different from-maps: 214 (cond ((eq command 'gmm-ignore) 215 ;; The dummy `gmm-ignore', see `gmm-tool-bar-item' 216 ;; widget. Suppress tooltip by adding `:enable nil'. 217 (if (fboundp 'tool-bar-local-item) 218 (apply 'tool-bar-local-item icon nil nil 219 map :enable nil props) 220 ;; (tool-bar-local-item ICON DEF KEY MAP &rest PROPS) 221 ;; (tool-bar-add-item ICON DEF KEY &rest PROPS) 222 (apply 'tool-bar-add-item icon nil nil :enable nil props))) 223 ((equal fmap t) ;; Not a menu command 224 (apply 'tool-bar-local-item 225 icon command 226 (intern icon) ;; reuse icon or fmap here? 227 map props)) 228 (t ;; A menu command 229 (apply 'tool-bar-local-item-from-menu 230 ;; (apply 'tool-bar-local-item icon def key 231 ;; tool-bar-map props) 232 command icon map (symbol-value fmap) 233 props))) 234 t)) 235 (if (symbolp icon-list) 236 (eval icon-list) 237 icon-list)) 238 map)) 239 240(defmacro defun-gmm (name function arg-list &rest body) 241 "Create function NAME. 242If FUNCTION exists, then NAME becomes an alias for FUNCTION. 243Otherwise, create function NAME with ARG-LIST and BODY." 244 (let ((defined-p (fboundp function))) 245 (if defined-p 246 `(defalias ',name ',function) 247 `(defun ,name ,arg-list ,@body)))) 248 249(defun gmm-customize-mode (&optional mode) 250 "Customize customization group for MODE. 251If mode is nil, use `major-mode' of the current buffer." 252 (interactive) 253 (customize-group 254 (or mode 255 (intern (let ((mode (symbol-name major-mode))) 256 (string-match "^\\(.+\\)-mode$" mode) 257 (match-string 1 mode)))))) 258 259(define-obsolete-function-alias 'gmm-format-time-string 'format-time-string 260 "26.1") 261 262(provide 'gmm-utils) 263 264;;; gmm-utils.el ends here 265