aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Kangas2022-08-24 08:05:18 +0200
committerStefan Kangas2022-08-24 08:21:31 +0200
commit8d103e622c50db50826cbc451d1a4f5b99d8cd8e (patch)
tree097b414d7545958f9b784b790ea38e28c51081af
parent647e04e6ca072827f40f7c36756e9938eb2c1aa1 (diff)
downloademacs-scratch/icons.tar.gz
emacs-scratch/icons.zip
Merge skicons.el with icons.elscratch/icons
-rw-r--r--lisp/emacs-lisp/icons.el826
-rw-r--r--lisp/icons-material.el2
-rw-r--r--lisp/icons-octicons.el2
-rw-r--r--lisp/skicons.el846
-rw-r--r--test/lisp/emacs-lisp/icons-tests.el105
-rw-r--r--test/lisp/icons-tests.el131
6 files changed, 929 insertions, 983 deletions
diff --git a/lisp/emacs-lisp/icons.el b/lisp/emacs-lisp/icons.el
index 93749a3451e..807efd21d6e 100644
--- a/lisp/emacs-lisp/icons.el
+++ b/lisp/emacs-lisp/icons.el
@@ -1,9 +1,10 @@
1;;; icons.el --- Handling icons -*- lexical-binding:t -*- 1;;; icons.el --- Icon support in buffers, mode-line, etc. -*- lexical-binding:t -*-
2 2
3;; Copyright (C) 2022 Free Software Foundation, Inc. 3;; Copyright (C) 2022 Free Software Foundation, Inc.
4 4
5;; Author: Lars Ingebrigtsen <larsi@gnus.org> 5;; Author: Lars Ingebrigtsen <larsi@gnus.org>
6;; Keywords: icons buttons 6;; Stefan Kangas <stefankangas@gmail.com>
7;; Keywords: icons buttons faces multimedia
7 8
8;; This file is part of GNU Emacs. 9;; This file is part of GNU Emacs.
9 10
@@ -22,9 +23,60 @@
22 23
23;;; Commentary: 24;;; Commentary:
24 25
26;; * Introduction
27;;
28;; This library provides support for icons, that can be used for
29;; things like decorating a buffer, toolbar buttons or the mode-line.
30;; Emacs comes bundled with several sets of icons, but you can also
31;; install new sets from package archives like GNU ELPA.
32;;
33;; icons.el allows users to change the appearance of icons all over
34;; Emacs, in libraries supporting it, by customizing
35;; `icons-set-priority'. You can think of this as icon themes for
36;; Emacs.
37;;
38;; Run `M-x customize-group RET icons RET' to see all user options.
39;;
40;; * Using this library as an Emacs Lisp developer
41;;
42;; To use these icons from Lisp, see `icons-get' and `icons-insert'.
43;; To use an icon in the modeline, use `icons-get-for-modeline'.
44;; Type `M-x list-icons' to see a list of all supported icons.
45;;
46;; * Adding Icon sets
47;;
48;; If you want to add a new icon set, the best starting point is to
49;; study an existing icon set. It comes down to one file containing a
50;; `icons-define-set' form, and then the actual image files. It is
51;; highly recommended to use SVG icons, but consider providing XPM and
52;; PBM fall-backs for users on older machines.
53;;
54;; To add SVG icons, you need to make sure that the SVG files don't
55;; contain any unnecessary or incorrect markup that stops them from
56;; being displayed correctly.
57;;
58;; There is optional support for more than one size of the same
59;; icon. This is to avoid icons looking bad when resized, and adapt
60;; things like line thickness for display at various sizes. See also
61;; the explanation on this page:
62;; https://github.com/primer/octicons/blob/main/docs/content/guidelines/usage.mdx#sizing
63;;
64;; If you intend to distribute your icon set to others, it is
65;; important that they have a license that allows it. We cannot give
66;; legal advice, but typically this means a GPL compatible license.
67;; You can find more information about licenses here:
68;; https://www.gnu.org/licenses/license-list.html
69
25;;; Code: 70;;; Code:
26 71
72;; TODO:
73;; - UTF-8 icons
74;; - Icon aliases
75
27(require 'cl-lib) 76(require 'cl-lib)
77(with-eval-after-load 'icons
78 (require 'icons-material)
79 (require 'icons-octicons))
28 80
29(defface icon 81(defface icon
30 '((t :underline nil)) 82 '((t :underline nil))
@@ -42,18 +94,39 @@
42 :version "29.1" 94 :version "29.1"
43 :group 'customize) 95 :group 'customize)
44 96
97
98;;;; User options.
99
100(defgroup icons nil
101 "Graphical icons in Emacs."
102 :group 'multimedia
103 :version "29.1")
104
105(defcustom icons-enabled (display-graphic-p)
106 "If non-nil, enable graphical icons."
107 :type 'boolean
108 :version "29.1")
109
45(defcustom icon-preference '(image emoji symbol text) 110(defcustom icon-preference '(image emoji symbol text)
46 "List of icon types to use, in order of preference. 111 "List of icon types to use, in order of preference.
47Emacs will choose the icon of the highest preference possible 112Emacs will choose the icon of the highest preference possible
48on the current display, and \"degrade\" gracefully to an icon 113on the current display, and \"degrade\" gracefully to an icon
49type that's available." 114type that's available."
50 :version "29.1" 115 :version "29.1"
51 :group 'customize 116 :group 'icons
52 :type '(repeat (choice (const :tag "Images" image) 117 :type '(repeat (choice (const :tag "Images" image)
53 (const :tag "Colorful Emojis" emoji) 118 (const :tag "Colorful Emojis" emoji)
54 (const :tag "Monochrome Symbols" symbol) 119 (const :tag "Monochrome Symbols" symbol)
55 (const :tag "Text Only" text)))) 120 (const :tag "Text Only" text))))
56 121
122(defcustom icons-set-priority '(octicons)
123 "Priority of icon sets used by `icons-insert' et al."
124 :type '(list symbol)
125 :version "29.1")
126
127(defconst icons-type-priority '(svg png ppm xpm pbm)
128 "Priority of icon formats used by `icons-insert' et al.")
129
57(defmacro define-icon (name parent specification documentation &rest keywords) 130(defmacro define-icon (name parent specification documentation &rest keywords)
58 "Define an icon identified by NAME. 131 "Define an icon identified by NAME.
59If non-nil, inherit the specification from PARENT. Entries from 132If non-nil, inherit the specification from PARENT. Entries from
@@ -79,7 +152,7 @@ the icon is used as a button and you click it."
79 (unless (plist-get keywords :version) 152 (unless (plist-get keywords :version)
80 (error "There must be a :version keyword in `define-icon'")) 153 (error "There must be a :version keyword in `define-icon'"))
81 `(icons--register ',name ',parent ,specification ,documentation 154 `(icons--register ',name ',parent ,specification ,documentation
82 ',keywords)) 155 ',keywords))
83 156
84(defun icons--register (name parent spec doc keywords) 157(defun icons--register (name parent spec doc keywords)
85 (put name 'icon--properties (list parent spec doc keywords)) 158 (put name 'icon--properties (list parent spec doc keywords))
@@ -262,6 +335,751 @@ present if the icon is represented by an image."
262 (while keywords 335 (while keywords
263 (insert (format " %s: %s\n" (pop keywords) (pop keywords)))))))) 336 (insert (format " %s: %s\n" (pop keywords) (pop keywords))))))))
264 337
338
339;;;; Icon set data.
340
341;; FIXME: Is this needed?
342(defvar icons-defined-sets nil
343 "List of all icon sets defined with `icons-define-set'.")
344
345(defvar icons-alist nil
346 "Alist containing all icon sets defined by `icons-define-set'.
347Has the form (NAME . ICONS), where NAME is a symbol representing
348a particular icon, and ICONS is a list of `icons-icon'
349structures.
350
351Note that the list of icons might belong to different defined
352sets of icons, and which one is used depends on the user
353option `icons-set-priority' and `icons-type-priority'.")
354
355(cl-defstruct (icons-icon (:constructor icons-icon-create)
356 (:copier icons-icon-copy))
357 "Structure containing information about an individual icon file."
358 ( filename nil
359 :documentation "Filename of this icon (string)."
360 :type string)
361 ( type nil
362 :documentation "Image type of the icon (symbol)."
363 :type symbol)
364 ( size nil
365 :documentation "Size of this icon in pixels (integer).
366Specifies the size at which this icon is best viewed."
367 :type integer)
368 ( set nil
369 :documentation "Icon set that this icon belongs to (symbol)."
370 :type symbol))
371
372(defun icons-add-icon (name icon)
373 "Add `icons-icon' ICON with NAME to `icons-alist'."
374 (unless (icons-icon-p icon)
375 (error "Not an icon: %S" icon))
376 (if-let ((orig (cdr (assoc name icons-alist))))
377 (setf (cdr (assoc name icons-alist)) (cons icon orig))
378 (push (cons name (list icon)) icons-alist)))
379
380(defun icons--remove-set (set)
381 "Remove all icons belonging to SET from `icons-alist'."
382 (setq icons-alist
383 (seq-filter
384 (lambda (elem) (> (length elem) 1))
385 (mapcar (lambda (is)
386 (append
387 (list (car is))
388 (seq-filter (lambda (i)
389 (not (eq (icons-icon-set i) set)))
390 (cdr is))))
391 icons-alist))))
392
393(defun icons-define-set (set icons)
394 "Define a new icon SET from ICONS and add it to `icons-alist'.
395SET is a symbol naming the new set.
396
397ICONS is a list on the form (NAME FILE SIZE) where NAME is the
398name of the icon (a string), FILE is a filename, and SIZE is the
399pixel size at which this is best viewed."
400 (declare (indent defun))
401 (icons--remove-set set)
402 (cl-pushnew set icons-defined-sets)
403 (dolist (icon icons)
404 (let* ((name (car icon))
405 (filename (cadr icon))
406 (size (caddr icon))
407 ;; Infer the type from the filename.
408 (type (intern
409 (progn
410 (string-match (rx "." (group (+ alnum)) eos)
411 filename)
412 (match-string 1 filename)))))
413 (icons-add-icon name (icons-icon-create :filename filename
414 :size size
415 :type type
416 :set set)))))
417
418
419;;;; Inserting and getting icons.
420
421(defun icons--get-sorted-icons (name &optional _size)
422 "Return icons for NAME sorted by type and set.
423The order is given by `icons-type-priority', `icons-set-priority'
424and SIZE in that order.
425
426Optional argument SIZE, if non-nil."
427 (let ((icons (copy-sequence (cdr (assoc name icons-alist)))))
428 (sort icons
429 (lambda (A B)
430 (let ((Af (icons-icon-type A))
431 (Bf (icons-icon-type B))
432 (As (icons-icon-set A))
433 (Bs (icons-icon-set B)))
434 (or (< (or (cl-position Af icons-type-priority) most-positive-fixnum)
435 (or (cl-position Bf icons-type-priority) most-positive-fixnum))
436 (< (or (cl-position As icons-set-priority) most-positive-fixnum)
437 (or (cl-position Bs icons-set-priority) most-positive-fixnum))))))))
438
439(defun icons--image-spec-from-icon (icon)
440 "Return a specification for `find-image' based on `icons-icon' ICON."
441 (cl-assert (icons-icon-p icon))
442 (list :file (icons-icon-filename icon)
443 :type (icons-icon-type icon)
444 :ascent 'center
445 :height '(1 . em)))
446
447(defun icons--get-icon (name &optional _size)
448 "Return the best icon to use for NAME.
449The icon is found by `icons--get-sorted-icons' (which see)."
450 (or (when-let ((icons (icons--get-sorted-icons name)))
451 (find-image (mapcar #'icons--image-spec-from-icon icons)))
452 (error "Unable to find icon: `%s'" name)))
453
454;;;###autoload
455(defun icons-get (name &optional _size)
456 "Return icon NAME for inserting into a buffer.
457NAME is a string."
458 ;; FIXME: Size, based on default face.
459 ;; You should also be able to pass in a different face.
460 (if icons-enabled
461 (propertize " " 'display (icons--get-icon name))
462 ""))
463
464;;;###autoload
465(defun icons-get-filename (name &optional _size)
466 "Return filename of icon NAME.
467NAME is a string."
468 (plist-get (cdr (icons--get-icon name)) :file))
469
470;;;###autoload
471(defun icons-get-for-modeline (name)
472 "Return icon NAME for use in `mode-line-format'.
473NAME is as in `icons-get'."
474 (if icons-enabled
475 `(:propertize (" ") display ,(icons--get-icon name))
476 ""))
477
478;;;###autoload
479(defun icons-insert (name &optional _size) ; FIXME: Is this very useful?
480 "Insert icon NAME at point.
481NAME is as in `icons-get'."
482 (when icons-enabled
483 (insert (icons-get name))))
484
485;; (defun icons--filename-for-size (font-size filename-alist)
486;; "Return filename from FILENAME-ALIST closest to FONT-SIZE."
487;; (if (listp filename-alist)
488;; (let* ((sizes (map-keys filename-alist))
489;; (size (icons--closest-to font-size sizes)))
490;; (cdr (assq size filename-alist)))
491;; filename-alist))
492
493
494;;;; Describing icons.
495
496(defface icons-description-title '((t :inherit bold)) "")
497(defface icons-icon-075 '((t :height 0.75)) "")
498(defface icons-icon-100 '((t :height 1.0)) "")
499(defface icons-icon-150 '((t :height 1.5)) "")
500(defface icons-icon-200 '((t :height 2.0)) "")
501(defface icons-icon-300 '((t :height 3.0)) "")
502(defface icons-icon-400 '((t :height 4.0)) "")
503
504(defun describe-icon (name)
505 "Describe icon NAME."
506 (interactive (list (completing-read (format-prompt "Describe icon" nil)
507 (sort (mapcar #'car icons-alist) #'string<))))
508 (let ((icon (cadr (assoc name icons-alist))))
509 (help-setup-xref (list #'describe-icon name)
510 (called-interactively-p 'interactive))
511 (with-help-window (help-buffer)
512 (with-current-buffer standard-output
513 ;; TODO: Link the set name to corresponding `describe-icon-set'.
514 (insert (format-message "%S belongs to the icon set `%s'.\n\n"
515 name (icons-icon-set icon)))
516
517 (insert (propertize "Filename:" 'face 'icons-description-title)
518 " "
519 (icons-icon-filename icon)
520 "\n")
521 (insert (propertize "Size:" 'face 'icons-description-title)
522 " "
523 (format "%s" (icons-icon-size icon))
524 "\n")
525 (insert (propertize "Type:" 'face 'icons-description-title)
526 " "
527 (format "%s" (icons-icon-type icon))
528 "\n")
529
530 (insert "\n")
531 (dolist (face '( icons-icon-075 icons-icon-100 icons-icon-150
532 icons-icon-200 icons-icon-300 icons-icon-400))
533 (insert (propertize " " 'display '(space :align-to 2)))
534 (insert (propertize (icons-get name) 'face face))
535 (insert "\n\n"))))))
536
537;; (defun describe-icon-set (name)
538;; "Describe icon set NAME."
539;; (interactive
540;; (list (completing-read (format-prompt "Describe icon set" nil)
541;; (sort icons-defined-sets
542;; (lambda (a b)
543;; (string< (symbol-name a) (symbol-name b)))))))
544;; (help-setup-xref (list #'describe-icon-set name)
545;; (called-interactively-p 'interactive))
546;; (with-help-window (help-buffer)
547;; (with-current-buffer standard-output
548;; ;; TODO: Link the set name to corresponding `describe-icon-set'.
549;; (princ (format-message "Icon set `%s'.\n\n"
550;; (icons-icon-set icon)))
551;; ;; TODO: Show all alternative icons in different sizes.
552;; (icons-insert name))))
553
554
555;;;; Listing icons.
556
557(defconst icons-list-buffer-name "*Icons*")
558
559(defun icons-list-make-entries ()
560 "Make list of all icons for `tabulated-list-entries'."
561 (let (entries)
562 (dolist (ic icons-alist)
563 (let ((icon-name (car ic))
564 (icons (cdr ic)))
565 (dolist (icon icons)
566 (push (list (cons icon-name icon)
567 (vector (symbol-name (icons-icon-set icon))
568 icon-name
569 (format "%s" (or (icons-icon-size icon) ""))
570 (format "%s" (icons-icon-type icon))
571 (find-image (list (icons--image-spec-from-icon icon )))))
572 entries))))
573 entries))
574
575;; Ignore arguments to be usable for `revert-buffer-function'.
576(defun icons-list-display (&optional _ _ _)
577 "Prepare buffer for `tabulated-list-mode' based on `icons-alist'."
578 (setq tabulated-list-entries (icons-list-make-entries))
579 (tabulated-list-init-header)
580 (tabulated-list-print t))
581
582(defvar-keymap icons-list-mode-map
583 :doc "Keymap for `icons-list-mode'."
584 "w" #'icons-list-copy-name)
585
586(define-derived-mode icons-list-mode tabulated-list-mode "Icons List Mode"
587 "Major mode for listing icons."
588 :interactive nil
589 (setq tabulated-list-format [("Icon set" 13 icons-list--icon-set-predicate)
590 ("Name" 30 icons-list--name-predicate)
591 ("Size" 6 icons-list--size-predicate)
592 ("Type" 5)
593 ("Icon" -1)])
594 (setq revert-buffer-function #'icons-list-display)
595 (setq tabulated-list-sort-key (cons "Size" nil)))
596
597;;;###autoload
598(defun list-icons ()
599 "Display all defined icons."
600 (interactive)
601 (pop-to-buffer (get-buffer-create icons-list-buffer-name))
602 (icons-list-mode)
603 (icons-list-display))
604
605(defun icons-list--name-predicate (A B)
606 "Predicate to sort `list-icons' by \"Name\"."
607 (string< (caar A) (caar B)))
608
609(defun icons-list--size-predicate (A B)
610 "Predicate to sort `list-icons' by \"Size\"."
611 (< (string-to-number (aref (cadr A) 2))
612 (string-to-number (aref (cadr B) 2))))
613
614(defun icons-list--icon-set-predicate (A B)
615 "Predicate to sort `list-icons' by Icon Set."
616 (let ((Aset (aref (cadr A) 0))
617 (Bset (aref (cadr B) 0)))
618 (if (string= Aset Bset)
619 ;; Secondary sort keys.
620 (or (icons-list--size-predicate A B)
621 (icons-list--name-predicate A B))
622 (string< Aset Bset))))
623
624(defun icons-list-copy-name ()
625 "In `icons-list-mode', copy name of icon at point."
626 (interactive nil icons-list-mode)
627 (let ((icon-name (aref (get-text-property (point) 'tabulated-list-entry) 1)))
628 (when icon-name
629 (kill-new icon-name)
630 (message "%s" icon-name))))
631
632;; (get-char-property (point) 'read-face-name)
633;; (get-char-property (point) 'font-lock-face)
634;; (get-char-property (point) 'face)
635
636
637;;;; Util.
638
639(defun icons--face-height-at-point ()
640 "Return font height at point."
641 (let* ((scale (cadr (assoc :height (assoc 'default face-remapping-alist))))
642 (face (face-font (or (face-at-point t) 'default)))
643 (height (* (aref (font-info face) 2) (if scale scale 1))))
644 height))
645
646(defun icons--closest-to (num candidates)
647 "Return the closest number to NUM among CANDIDATES."
648 (car (sort candidates (lambda (a b) (<= (abs (- num a))
649 (abs (- num b)))))))
650
651(icons-define-set 'emacs
652 '(
653 ("attach" "attach.pbm")
654 ("attach" "attach.xpm")
655 ("back-arrow" "back-arrow.pbm")
656 ("back-arrow" "back-arrow.xpm")
657 ("bookmark_add" "bookmark_add.pbm")
658 ("bookmark_add" "bookmark_add.xpm")
659 ("cancel" "cancel.pbm")
660 ("cancel" "cancel.xpm")
661 ("checkbox-mixed" "checkbox-mixed.svg")
662 ("checked" "checked.svg")
663 ("checked" "checked.xpm")
664 ("close" "close.pbm")
665 ("close" "close.xpm")
666 ("connect" "connect.pbm")
667 ("connect" "connect.xpm")
668 ("contact" "contact.pbm")
669 ("contact" "contact.xpm")
670 ("copy" "copy.pbm")
671 ("copy" "copy.xpm")
672 ("custom/down" "custom/down.pbm")
673 ("custom/down" "custom/down.xpm")
674 ("custom/down-pushed" "custom/down-pushed.pbm")
675 ("custom/down-pushed" "custom/down-pushed.xpm")
676 ("custom/right" "custom/right.pbm")
677 ("custom/right" "custom/right.xpm")
678 ("custom/right-pushed" "custom/right-pushed.pbm")
679 ("custom/right-pushed" "custom/right-pushed.xpm")
680 ("cut" "cut.pbm")
681 ("cut" "cut.xpm")
682 ("data-save" "data-save.pbm")
683 ("data-save" "data-save.xpm")
684 ("delete" "delete.pbm")
685 ("delete" "delete.xpm")
686 ("describe" "describe.pbm")
687 ("describe" "describe.xpm")
688 ("diropen" "diropen.pbm")
689 ("diropen" "diropen.xpm")
690 ("disconnect" "disconnect.pbm")
691 ("disconnect" "disconnect.xpm")
692 ("down" "down.svg")
693 ("exit" "exit.pbm")
694 ("exit" "exit.xpm")
695 ("ezimage/bits" "ezimage/bits.pbm")
696 ("ezimage/bits" "ezimage/bits.xpm")
697 ("ezimage/bitsbang" "ezimage/bitsbang.pbm")
698 ("ezimage/bitsbang" "ezimage/bitsbang.xpm")
699 ("ezimage/box" "ezimage/box.pbm")
700 ("ezimage/box" "ezimage/box.xpm")
701 ("ezimage/box-minus" "ezimage/box-minus.pbm")
702 ("ezimage/box-minus" "ezimage/box-minus.xpm")
703 ("ezimage/box-plus" "ezimage/box-plus.pbm")
704 ("ezimage/box-plus" "ezimage/box-plus.xpm")
705 ("ezimage/checkmark" "ezimage/checkmark.pbm")
706 ("ezimage/checkmark" "ezimage/checkmark.xpm")
707 ("ezimage/dir" "ezimage/dir.pbm")
708 ("ezimage/dir" "ezimage/dir.xpm")
709 ("ezimage/dir-minus" "ezimage/dir-minus.pbm")
710 ("ezimage/dir-minus" "ezimage/dir-minus.xpm")
711 ("ezimage/dir-plus" "ezimage/dir-plus.pbm")
712 ("ezimage/dir-plus" "ezimage/dir-plus.xpm")
713 ("ezimage/doc" "ezimage/doc.pbm")
714 ("ezimage/doc" "ezimage/doc.xpm")
715 ("ezimage/doc-minus" "ezimage/doc-minus.pbm")
716 ("ezimage/doc-minus" "ezimage/doc-minus.xpm")
717 ("ezimage/doc-plus" "ezimage/doc-plus.pbm")
718 ("ezimage/doc-plus" "ezimage/doc-plus.xpm")
719 ("ezimage/info" "ezimage/info.pbm")
720 ("ezimage/info" "ezimage/info.xpm")
721 ("ezimage/key" "ezimage/key.pbm")
722 ("ezimage/key" "ezimage/key.xpm")
723 ("ezimage/label" "ezimage/label.pbm")
724 ("ezimage/label" "ezimage/label.xpm")
725 ("ezimage/lock" "ezimage/lock.pbm")
726 ("ezimage/lock" "ezimage/lock.xpm")
727 ("ezimage/mail" "ezimage/mail.pbm")
728 ("ezimage/mail" "ezimage/mail.xpm")
729 ("ezimage/page" "ezimage/page.pbm")
730 ("ezimage/page" "ezimage/page.xpm")
731 ("ezimage/page-minus" "ezimage/page-minus.pbm")
732 ("ezimage/page-minus" "ezimage/page-minus.xpm")
733 ("ezimage/page-plus" "ezimage/page-plus.pbm")
734 ("ezimage/page-plus" "ezimage/page-plus.xpm")
735 ("ezimage/tag" "ezimage/tag.pbm")
736 ("ezimage/tag" "ezimage/tag.xpm")
737 ("ezimage/tag-gt" "ezimage/tag-gt.pbm")
738 ("ezimage/tag-gt" "ezimage/tag-gt.xpm")
739 ("ezimage/tag-minus" "ezimage/tag-minus.pbm")
740 ("ezimage/tag-minus" "ezimage/tag-minus.xpm")
741 ("ezimage/tag-plus" "ezimage/tag-plus.pbm")
742 ("ezimage/tag-plus" "ezimage/tag-plus.xpm")
743 ("ezimage/tag-type" "ezimage/tag-type.pbm")
744 ("ezimage/tag-type" "ezimage/tag-type.xpm")
745 ("ezimage/tag-v" "ezimage/tag-v.pbm")
746 ("ezimage/tag-v" "ezimage/tag-v.xpm")
747 ("ezimage/unlock" "ezimage/unlock.pbm")
748 ("ezimage/unlock" "ezimage/unlock.xpm")
749 ("fwd-arrow" "fwd-arrow.pbm")
750 ("fwd-arrow" "fwd-arrow.xpm")
751 ("gnus" "gnus.pbm")
752 ("gnus/followup" "gnus/followup.pbm")
753 ("gnus/followup" "gnus/followup.xpm")
754 ("gnus/fuwo" "gnus/fuwo.pbm")
755 ("gnus/fuwo" "gnus/fuwo.xpm")
756 ("gnus/gnus" "gnus/gnus.png")
757 ("gnus/gnus" "gnus/gnus.svg")
758 ("gnus/gnus" "gnus/gnus.xbm")
759 ("gnus/gnus" "gnus/gnus.xpm")
760 ("gnus/gnus-pointer" "gnus/gnus-pointer.xbm")
761 ("gnus/gnus-pointer" "gnus/gnus-pointer.xpm")
762 ("gnus/kill-group" "gnus/kill-group.pbm")
763 ("gnus/kill-group" "gnus/kill-group.xpm")
764 ("gnus/mail-reply" "gnus/mail-reply.pbm")
765 ("gnus/mail-reply" "gnus/mail-reply.xpm")
766 ("gnus/mail-send" "gnus/mail-send.pbm")
767 ("gnus/mail-send" "gnus/mail-send.xpm")
768 ("gnus/preview" "gnus/preview.xbm")
769 ("gnus/preview" "gnus/preview.xpm")
770 ("gnus/toggle-subscription" "gnus/toggle-subscription.pbm")
771 ("gnus/toggle-subscription" "gnus/toggle-subscription.xpm")
772 ("gud/all" "gud/all.pbm")
773 ("gud/all" "gud/all.xpm")
774 ("gud/break" "gud/break.pbm")
775 ("gud/break" "gud/break.xpm")
776 ("gud/cont" "gud/cont.pbm")
777 ("gud/cont" "gud/cont.xpm")
778 ("gud/down" "gud/down.pbm")
779 ("gud/down" "gud/down.xpm")
780 ("gud/finish" "gud/finish.pbm")
781 ("gud/finish" "gud/finish.xpm")
782 ("gud/go" "gud/go.pbm")
783 ("gud/go" "gud/go.xpm")
784 ("gud/next" "gud/next.pbm")
785 ("gud/next" "gud/next.xpm")
786 ("gud/nexti" "gud/nexti.pbm")
787 ("gud/nexti" "gud/nexti.xpm")
788 ("gud/pp" "gud/pp.pbm")
789 ("gud/pp" "gud/pp.xpm")
790 ("gud/print" "gud/print.pbm")
791 ("gud/print" "gud/print.xpm")
792 ("gud/pstar" "gud/pstar.pbm")
793 ("gud/pstar" "gud/pstar.xpm")
794 ("gud/rcont" "gud/rcont.pbm")
795 ("gud/rcont" "gud/rcont.xpm")
796 ("gud/recstart" "gud/recstart.pbm")
797 ("gud/recstart" "gud/recstart.xpm")
798 ("gud/recstop" "gud/recstop.pbm")
799 ("gud/recstop" "gud/recstop.xpm")
800 ("gud/remove" "gud/remove.pbm")
801 ("gud/remove" "gud/remove.xpm")
802 ("gud/rfinish" "gud/rfinish.pbm")
803 ("gud/rfinish" "gud/rfinish.xpm")
804 ("gud/rnext" "gud/rnext.pbm")
805 ("gud/rnext" "gud/rnext.xpm")
806 ("gud/rnexti" "gud/rnexti.pbm")
807 ("gud/rnexti" "gud/rnexti.xpm")
808 ("gud/rstep" "gud/rstep.pbm")
809 ("gud/rstep" "gud/rstep.xpm")
810 ("gud/rstepi" "gud/rstepi.pbm")
811 ("gud/rstepi" "gud/rstepi.xpm")
812 ("gud/run" "gud/run.pbm")
813 ("gud/run" "gud/run.xpm")
814 ("gud/step" "gud/step.pbm")
815 ("gud/step" "gud/step.xpm")
816 ("gud/stepi" "gud/stepi.pbm")
817 ("gud/stepi" "gud/stepi.xpm")
818 ("gud/stop" "gud/stop.pbm")
819 ("gud/stop" "gud/stop.xpm")
820 ("gud/thread" "gud/thread.pbm")
821 ("gud/thread" "gud/thread.xpm")
822 ("gud/until" "gud/until.pbm")
823 ("gud/until" "gud/until.xpm")
824 ("gud/up" "gud/up.pbm")
825 ("gud/up" "gud/up.xpm")
826 ("gud/watch" "gud/watch.pbm")
827 ("gud/watch" "gud/watch.xpm")
828 ("help" "help.pbm")
829 ("help" "help.xpm")
830 ("home" "home.pbm")
831 ("home" "home.xpm")
832 ("index" "index.pbm")
833 ("index" "index.xpm")
834 ("info" "info.pbm")
835 ("info" "info.xpm")
836 ("jump-to" "jump-to.pbm")
837 ("jump-to" "jump-to.xpm")
838 ("left" "left.svg")
839 ("left-arrow" "left-arrow.pbm")
840 ("left-arrow" "left-arrow.xpm")
841 ("letter" "letter.pbm")
842 ("letter" "letter.xpm")
843 ("lock" "lock.pbm")
844 ("lock" "lock.xpm")
845 ("lock-broken" "lock-broken.pbm")
846 ("lock-broken" "lock-broken.xpm")
847 ("lock-ok" "lock-ok.pbm")
848 ("lock-ok" "lock-ok.xpm")
849 ("low-color/back-arrow" "low-color/back-arrow.xpm")
850 ("low-color/copy" "low-color/copy.xpm")
851 ("low-color/cut" "low-color/cut.xpm")
852 ("low-color/fwd-arrow" "low-color/fwd-arrow.xpm")
853 ("low-color/help" "low-color/help.xpm")
854 ("low-color/home" "low-color/home.xpm")
855 ("low-color/index" "low-color/index.xpm")
856 ("low-color/jump-to" "low-color/jump-to.xpm")
857 ("low-color/left-arrow" "low-color/left-arrow.xpm")
858 ("low-color/new" "low-color/new.xpm")
859 ("low-color/next-node" "low-color/next-node.xpm")
860 ("low-color/open" "low-color/open.xpm")
861 ("low-color/paste" "low-color/paste.xpm")
862 ("low-color/preferences" "low-color/preferences.xpm")
863 ("low-color/prev-node" "low-color/prev-node.xpm")
864 ("low-color/print" "low-color/print.xpm")
865 ("low-color/right-arrow" "low-color/right-arrow.xpm")
866 ("low-color/save" "low-color/save.xpm")
867 ("low-color/saveas" "low-color/saveas.xpm")
868 ("low-color/search" "low-color/search.xpm")
869 ("low-color/spell" "low-color/spell.xpm")
870 ("low-color/undo" "low-color/undo.xpm")
871 ("low-color/up-arrow" "low-color/up-arrow.xpm")
872 ("low-color/up-node" "low-color/up-node.xpm")
873 ("mail/compose" "mail/compose.pbm")
874 ("mail/compose" "mail/compose.xpm")
875 ("mail/copy" "mail/copy.pbm")
876 ("mail/copy" "mail/copy.xpm")
877 ("mail/flag-for-followup" "mail/flag-for-followup.pbm")
878 ("mail/flag-for-followup" "mail/flag-for-followup.xpm")
879 ("mail/forward" "mail/forward.pbm")
880 ("mail/forward" "mail/forward.xpm")
881 ("mail/inbox" "mail/inbox.pbm")
882 ("mail/inbox" "mail/inbox.xpm")
883 ("mail/move" "mail/move.pbm")
884 ("mail/move" "mail/move.xpm")
885 ("mail/not-spam" "mail/not-spam.pbm")
886 ("mail/not-spam" "mail/not-spam.xpm")
887 ("mail/outbox" "mail/outbox.pbm")
888 ("mail/outbox" "mail/outbox.xpm")
889 ("mail/preview" "mail/preview.pbm")
890 ("mail/preview" "mail/preview.xpm")
891 ("mail/repack" "mail/repack.pbm")
892 ("mail/repack" "mail/repack.xpm")
893 ("mail/reply" "mail/reply.pbm")
894 ("mail/reply" "mail/reply.xpm")
895 ("mail/reply-all" "mail/reply-all.pbm")
896 ("mail/reply-all" "mail/reply-all.xpm")
897 ("mail/reply-from" "mail/reply-from.pbm")
898 ("mail/reply-from" "mail/reply-from.xpm")
899 ("mail/reply-to" "mail/reply-to.pbm")
900 ("mail/reply-to" "mail/reply-to.xpm")
901 ("mail/save" "mail/save.xpm")
902 ("mail/save-draft" "mail/save-draft.pbm")
903 ("mail/save-draft" "mail/save-draft.xpm")
904 ("mail/send" "mail/send.pbm")
905 ("mail/send" "mail/send.xpm")
906 ("mail/spam" "mail/spam.xpm")
907 ("mh-logo" "mh-logo.pbm")
908 ("mh-logo" "mh-logo.xpm")
909 ("new" "new.pbm")
910 ("new" "new.xpm")
911 ("newsticker/browse-url" "newsticker/browse-url.xpm")
912 ("newsticker/get-all" "newsticker/get-all.xpm")
913 ("newsticker/mark-immortal" "newsticker/mark-immortal.xpm")
914 ("newsticker/mark-read" "newsticker/mark-read.xpm")
915 ("newsticker/narrow" "newsticker/narrow.xpm")
916 ("newsticker/next-feed" "newsticker/next-feed.xpm")
917 ("newsticker/next-item" "newsticker/next-item.xpm")
918 ("newsticker/prev-feed" "newsticker/prev-feed.xpm")
919 ("newsticker/prev-item" "newsticker/prev-item.xpm")
920 ("newsticker/rss-feed" "newsticker/rss-feed.png")
921 ("newsticker/rss-feed" "newsticker/rss-feed.svg")
922 ("newsticker/update" "newsticker/update.xpm")
923 ("next-node" "next-node.pbm")
924 ("next-node" "next-node.xpm")
925 ("next-page" "next-page.pbm")
926 ("next-page" "next-page.xpm")
927 ("open" "open.pbm")
928 ("open" "open.xpm")
929 ("paste" "paste.pbm")
930 ("paste" "paste.xpm")
931 ("preferences" "preferences.pbm")
932 ("preferences" "preferences.xpm")
933 ("prev-node" "prev-node.pbm")
934 ("prev-node" "prev-node.xpm")
935 ("print" "print.pbm")
936 ("print" "print.xpm")
937 ("radio" "radio.svg")
938 ("radio-checked" "radio-checked.svg")
939 ("radio-mixed" "radio-mixed.svg")
940 ("redo" "redo.pbm")
941 ("redo" "redo.xpm")
942 ("refresh" "refresh.pbm")
943 ("refresh" "refresh.xpm")
944 ("right" "right.svg")
945 ("right-arrow" "right-arrow.pbm")
946 ("right-arrow" "right-arrow.xpm")
947 ("save" "save.pbm")
948 ("save" "save.xpm")
949 ("saveas" "saveas.pbm")
950 ("saveas" "saveas.xpm")
951 ("search" "search.pbm")
952 ("search" "search.xpm")
953 ("search-replace" "search-replace.pbm")
954 ("search-replace" "search-replace.xpm")
955 ("separator" "separator.pbm")
956 ("separator" "separator.xpm")
957 ("show" "show.pbm")
958 ("show" "show.xpm")
959 ("smilies/blink" "smilies/blink.pbm")
960 ("smilies/blink" "smilies/blink.xpm")
961 ("smilies/braindamaged" "smilies/braindamaged.pbm")
962 ("smilies/braindamaged" "smilies/braindamaged.xpm")
963 ("smilies/cry" "smilies/cry.pbm")
964 ("smilies/cry" "smilies/cry.xpm")
965 ("smilies/dead" "smilies/dead.pbm")
966 ("smilies/dead" "smilies/dead.xpm")
967 ("smilies/evil" "smilies/evil.pbm")
968 ("smilies/evil" "smilies/evil.xpm")
969 ("smilies/forced" "smilies/forced.pbm")
970 ("smilies/forced" "smilies/forced.xpm")
971 ("smilies/frown" "smilies/frown.pbm")
972 ("smilies/frown" "smilies/frown.xpm")
973 ("smilies/grin" "smilies/grin.pbm")
974 ("smilies/grin" "smilies/grin.xpm")
975 ("smilies/indifferent" "smilies/indifferent.pbm")
976 ("smilies/indifferent" "smilies/indifferent.xpm")
977 ("smilies/sad" "smilies/sad.pbm")
978 ("smilies/sad" "smilies/sad.xpm")
979 ("smilies/smile" "smilies/smile.pbm")
980 ("smilies/smile" "smilies/smile.xpm")
981 ("smilies/wry" "smilies/wry.pbm")
982 ("smilies/wry" "smilies/wry.xpm")
983 ("sort-ascending" "sort-ascending.pbm")
984 ("sort-ascending" "sort-ascending.xpm")
985 ("sort-column-ascending" "sort-column-ascending.pbm")
986 ("sort-column-ascending" "sort-column-ascending.xpm")
987 ("sort-criteria" "sort-criteria.pbm")
988 ("sort-criteria" "sort-criteria.xpm")
989 ("sort-descending" "sort-descending.pbm")
990 ("sort-descending" "sort-descending.xpm")
991 ("sort-row-ascending" "sort-row-ascending.pbm")
992 ("sort-row-ascending" "sort-row-ascending.xpm")
993 ("spell" "spell.pbm")
994 ("spell" "spell.xpm")
995 ("tabs/close" "tabs/close.xpm")
996 ("tabs/left-arrow" "tabs/left-arrow.xpm")
997 ("tabs/new" "tabs/new.xpm")
998 ("tabs/right-arrow" "tabs/right-arrow.xpm")
999 ("tree-widget/default/close" "tree-widget/default/close.png")
1000 ("tree-widget/default/close" "tree-widget/default/close.xpm")
1001 ("tree-widget/default/empty" "tree-widget/default/empty.png")
1002 ("tree-widget/default/empty" "tree-widget/default/empty.xpm")
1003 ("tree-widget/default/end-guide" "tree-widget/default/end-guide.png")
1004 ("tree-widget/default/end-guide" "tree-widget/default/end-guide.xpm")
1005 ("tree-widget/default/guide" "tree-widget/default/guide.png")
1006 ("tree-widget/default/guide" "tree-widget/default/guide.xpm")
1007 ("tree-widget/default/handle" "tree-widget/default/handle.png")
1008 ("tree-widget/default/handle" "tree-widget/default/handle.xpm")
1009 ("tree-widget/default/leaf" "tree-widget/default/leaf.png")
1010 ("tree-widget/default/leaf" "tree-widget/default/leaf.xpm")
1011 ("tree-widget/default/no-guide" "tree-widget/default/no-guide.png")
1012 ("tree-widget/default/no-guide" "tree-widget/default/no-guide.xpm")
1013 ("tree-widget/default/no-handle" "tree-widget/default/no-handle.png")
1014 ("tree-widget/default/no-handle" "tree-widget/default/no-handle.xpm")
1015 ("tree-widget/default/open" "tree-widget/default/open.png")
1016 ("tree-widget/default/open" "tree-widget/default/open.xpm")
1017 ("tree-widget/folder/close" "tree-widget/folder/close.png")
1018 ("tree-widget/folder/close" "tree-widget/folder/close.xpm")
1019 ("tree-widget/folder/empty" "tree-widget/folder/empty.png")
1020 ("tree-widget/folder/empty" "tree-widget/folder/empty.xpm")
1021 ("tree-widget/folder/end-guide" "tree-widget/folder/end-guide.png")
1022 ("tree-widget/folder/end-guide" "tree-widget/folder/end-guide.xpm")
1023 ("tree-widget/folder/guide" "tree-widget/folder/guide.png")
1024 ("tree-widget/folder/guide" "tree-widget/folder/guide.xpm")
1025 ("tree-widget/folder/handle" "tree-widget/folder/handle.png")
1026 ("tree-widget/folder/handle" "tree-widget/folder/handle.xpm")
1027 ("tree-widget/folder/leaf" "tree-widget/folder/leaf.png")
1028 ("tree-widget/folder/leaf" "tree-widget/folder/leaf.xpm")
1029 ("tree-widget/folder/no-guide" "tree-widget/folder/no-guide.png")
1030 ("tree-widget/folder/no-guide" "tree-widget/folder/no-guide.xpm")
1031 ("tree-widget/folder/no-handle" "tree-widget/folder/no-handle.png")
1032 ("tree-widget/folder/no-handle" "tree-widget/folder/no-handle.xpm")
1033 ("tree-widget/folder/open" "tree-widget/folder/open.png")
1034 ("tree-widget/folder/open" "tree-widget/folder/open.xpm")
1035 ("unchecked" "unchecked.pbm")
1036 ("unchecked" "unchecked.svg")
1037 ("unchecked" "unchecked.xpm")
1038 ("undo" "undo.pbm")
1039 ("undo" "undo.xpm")
1040 ("up" "up.svg")
1041 ("up-arrow" "up-arrow.pbm")
1042 ("up-arrow" "up-arrow.xpm")
1043 ("up-node" "up-node.pbm")
1044 ("up-node" "up-node.xpm")
1045 ("zoom-in" "zoom-in.pbm")
1046 ("zoom-in" "zoom-in.xpm")
1047 ("zoom-out" "zoom-out.pbm")
1048 ("zoom-out" "zoom-out.xpm")
1049 ;; ("smilies/grayscale/blink" "smilies/grayscale/blink.xpm")
1050 ;; ("smilies/grayscale/braindamaged" "smilies/grayscale/braindamaged.xpm")
1051 ;; ("smilies/grayscale/cry" "smilies/grayscale/cry.xpm")
1052 ;; ("smilies/grayscale/dead" "smilies/grayscale/dead.xpm")
1053 ;; ("smilies/grayscale/evil" "smilies/grayscale/evil.xpm")
1054 ;; ("smilies/grayscale/forced" "smilies/grayscale/forced.xpm")
1055 ;; ("smilies/grayscale/frown" "smilies/grayscale/frown.xpm")
1056 ;; ("smilies/grayscale/grin" "smilies/grayscale/grin.xpm")
1057 ;; ("smilies/grayscale/indifferent" "smilies/grayscale/indifferent.xpm")
1058 ;; ("smilies/grayscale/reverse-smile" "smilies/grayscale/reverse-smile.xpm")
1059 ;; ("smilies/grayscale/sad" "smilies/grayscale/sad.xpm")
1060 ;; ("smilies/grayscale/smile" "smilies/grayscale/smile.xpm")
1061 ;; ("smilies/grayscale/wry" "smilies/grayscale/wry.xpm")
1062 ;; ("smilies/medium/blink" "smilies/medium/blink.xpm")
1063 ;; ("smilies/medium/braindamaged" "smilies/medium/braindamaged.xpm")
1064 ;; ("smilies/medium/cry" "smilies/medium/cry.xpm")
1065 ;; ("smilies/medium/dead" "smilies/medium/dead.xpm")
1066 ;; ("smilies/medium/evil" "smilies/medium/evil.xpm")
1067 ;; ("smilies/medium/forced" "smilies/medium/forced.xpm")
1068 ;; ("smilies/medium/frown" "smilies/medium/frown.xpm")
1069 ;; ("smilies/medium/grin" "smilies/medium/grin.xpm")
1070 ;; ("smilies/medium/indifferent" "smilies/medium/indifferent.xpm")
1071 ;; ("smilies/medium/reverse-smile" "smilies/medium/reverse-smile.xpm")
1072 ;; ("smilies/medium/sad" "smilies/medium/sad.xpm")
1073 ;; ("smilies/medium/smile" "smilies/medium/smile.xpm")
1074 ;; ("smilies/medium/wry" "smilies/medium/wry.xpm")
1075 ;; ("splash" "splash.bmp")
1076 ;; ("splash" "splash.pbm")
1077 ;; ("splash" "splash.png")
1078 ;; ("splash" "splash.svg")
1079 ;; ("splash" "splash.xpm")
1080 ))
1081
1082
265(provide 'icons) 1083(provide 'icons)
266 1084
267;;; icons.el ends here 1085;;; icons.el ends here
diff --git a/lisp/icons-material.el b/lisp/icons-material.el
index 5248d2ceb83..8d7d57d06a7 100644
--- a/lisp/icons-material.el
+++ b/lisp/icons-material.el
@@ -26,7 +26,7 @@
26 26
27;;; Code: 27;;; Code:
28 28
29(require 'icons) 29;; (require 'skicons)
30 30
31(icons-define-set 'material 31(icons-define-set 'material
32 '(("action/3d_rotation" "material/action/3d_rotation.svg" 24) 32 '(("action/3d_rotation" "material/action/3d_rotation.svg" 24)
diff --git a/lisp/icons-octicons.el b/lisp/icons-octicons.el
index 788dbc4d74b..0dd60118665 100644
--- a/lisp/icons-octicons.el
+++ b/lisp/icons-octicons.el
@@ -26,7 +26,7 @@
26 26
27;;; Code: 27;;; Code:
28 28
29(require 'icons) 29;; (require 'skicons)
30 30
31(icons-define-set 'octicons 31(icons-define-set 'octicons
32 '(("alert" "octicons/alert-16.svg" 16) 32 '(("alert" "octicons/alert-16.svg" 16)
diff --git a/lisp/skicons.el b/lisp/skicons.el
deleted file mode 100644
index a064676868f..00000000000
--- a/lisp/skicons.el
+++ /dev/null
@@ -1,846 +0,0 @@
1;;; icons.el --- Icon support in buffers, mode-line, etc. -*- lexical-binding: t -*-
2
3;; Copyright (C) 2022 Free Software Foundation, Inc.
4
5;; Author: Stefan Kangas <stefan@marxist.se>
6;; Keywords: faces, multimedia
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;; * Introduction
26;;
27;; This library provides support for icons, that can be used for
28;; things like decorating a buffer, toolbar buttons or the mode-line.
29;; Emacs comes bundled with several sets of icons, but you can also
30;; install new sets from package archives like GNU ELPA.
31;;
32;; icons.el allows users to change the appearance of icons all over
33;; Emacs, in libraries supporting it, by customizing
34;; `icons-set-priority'. You can think of this as icon themes for
35;; Emacs.
36;;
37;; Run `M-x customize-group RET icons RET' to see all user options.
38;;
39;; * Using this library as an Emacs Lisp developer
40;;
41;; To use these icons from Lisp, see `icons-get' and `icons-insert'.
42;; To use an icon in the modeline, use `icons-get-for-modeline'.
43;; Type `M-x list-icons' to see a list of all supported icons.
44;;
45;; * Adding Icon sets
46;;
47;; If you want to add a new icon set, the best starting point is to
48;; study an existing icon set. It comes down to one file containing a
49;; `icons-define-set' form, and then the actual image files. It is
50;; highly recommended to use SVG icons, but consider providing XPM and
51;; PBM fall-backs for users on older machines.
52;;
53;; To add SVG icons, you need to make sure that the SVG files don't
54;; contain any unnecessary or incorrect markup that stops them from
55;; being displayed correctly.
56;;
57;; There is optional support for more than one size of the same
58;; icon. This is to avoid icons looking bad when resized, and adapt
59;; things like line thickness for display at various sizes. See also
60;; the explanation on this page:
61;; https://github.com/primer/octicons/blob/main/docs/content/guidelines/usage.mdx#sizing
62;;
63;; If you intend to distribute your icon set to others, it is
64;; important that they have a license that allows it. We cannot give
65;; legal advice, but typically this means a GPL compatible license.
66;; You can find more information about licenses here:
67;; https://www.gnu.org/licenses/license-list.html
68
69;;; Code:
70
71;; TODO:
72;; - UTF-8 icons
73;; - Icon aliases
74
75(require 'cl-lib)
76(with-eval-after-load 'icons
77 (require 'icons-material)
78 (require 'icons-octicons))
79
80
81;;;; User options.
82
83(defgroup icons nil
84 "Graphical icons in Emacs."
85 :group 'multimedia
86 :version "29.1")
87
88(defcustom icons-enabled (display-graphic-p)
89 "If non-nil, enable graphical icons."
90 :type 'boolean
91 :version "29.1")
92
93(defcustom icons-set-priority '(octicons)
94 "Priority of icon sets used by `icons-insert' et al."
95 :type '(list symbol)
96 :version "29.1")
97
98(defconst icons-type-priority '(svg png ppm xpm pbm)
99 "Priority of icon formats used by `icons-insert' et al.")
100
101
102;;;; Data.
103
104;; FIXME: Is this needed?
105(defvar icons-defined-sets nil
106 "List of all icon sets defined with `icons-define-set'.")
107
108(defvar icons-alist nil
109 "Alist containing all icon sets defined by `icons-define-set'.
110Has the form (NAME . ICONS), where NAME is a symbol representing
111a particular icon, and ICONS is a list of `icons-icon'
112structures.
113
114Note that the list of icons might belong to different defined
115sets of icons, and which one is used depends on the user
116option `icons-set-priority' and `icons-type-priority'.")
117
118(cl-defstruct (icons-icon (:constructor icons-icon-create)
119 (:copier icons-icon-copy))
120 "Structure containing information about an individual icon file."
121 ( filename nil
122 :documentation "Filename of this icon (string)."
123 :type string)
124 ( type nil
125 :documentation "Image type of the icon (symbol)."
126 :type symbol)
127 ( size nil
128 :documentation "Size of this icon in pixels (integer).
129Specifies the size at which this icon is best viewed."
130 :type integer)
131 ( set nil
132 :documentation "Icon set that this icon belongs to (symbol)."
133 :type symbol))
134
135(defun icons-add-icon (name icon)
136 "Add `icons-icon' ICON with NAME to `icons-alist'."
137 (unless (icons-icon-p icon)
138 (error "Not an icon: %S" icon))
139 (if-let ((orig (cdr (assoc name icons-alist))))
140 (setf (cdr (assoc name icons-alist)) (cons icon orig))
141 (push (cons name (list icon)) icons-alist)))
142
143(defun icons--remove-set (set)
144 "Remove all icons belonging to SET from `icons-alist'."
145 (setq icons-alist
146 (seq-filter
147 (lambda (elem) (> (length elem) 1))
148 (mapcar (lambda (is)
149 (append
150 (list (car is))
151 (seq-filter (lambda (i)
152 (not (eq (icons-icon-set i) set)))
153 (cdr is))))
154 icons-alist))))
155
156(defun icons-define-set (set icons)
157 "Define a new icon SET from ICONS and add it to `icons-alist'.
158SET is a symbol naming the new set.
159
160ICONS is a list on the form (NAME FILE SIZE) where NAME is the
161name of the icon (a string), FILE is a filename, and SIZE is the
162pixel size at which this is best viewed."
163 (declare (indent defun))
164 (icons--remove-set set)
165 (cl-pushnew set icons-defined-sets)
166 (dolist (icon icons)
167 (let* ((name (car icon))
168 (filename (cadr icon))
169 (size (caddr icon))
170 ;; Infer the type from the filename.
171 (type (intern
172 (progn
173 (string-match (rx "." (group (+ alnum)) eos)
174 filename)
175 (match-string 1 filename)))))
176 (icons-add-icon name (icons-icon-create :filename filename
177 :size size
178 :type type
179 :set set)))))
180
181
182;;;; Inserting and getting icons.
183
184(defun icons--get-sorted-icons (name &optional _size)
185 "Return icons for NAME sorted by type and set.
186The order is given by `icons-type-priority', `icons-set-priority'
187and SIZE in that order.
188
189Optional argument SIZE, if non-nil."
190 (let ((icons (copy-sequence (cdr (assoc name icons-alist)))))
191 (sort icons
192 (lambda (A B)
193 (let ((Af (icons-icon-type A))
194 (Bf (icons-icon-type B))
195 (As (icons-icon-set A))
196 (Bs (icons-icon-set B)))
197 (or (< (or (cl-position Af icons-type-priority) most-positive-fixnum)
198 (or (cl-position Bf icons-type-priority) most-positive-fixnum))
199 (< (or (cl-position As icons-set-priority) most-positive-fixnum)
200 (or (cl-position Bs icons-set-priority) most-positive-fixnum))))))))
201
202(defun icons--image-spec-from-icon (icon)
203 "Return a specification for `find-image' based on `icons-icon' ICON."
204 (cl-assert (icons-icon-p icon))
205 (list :file (icons-icon-filename icon)
206 :type (icons-icon-type icon)
207 :ascent 'center
208 :height '(1 . em)))
209
210(defun icons--get-icon (name &optional _size)
211 "Return the best icon to use for NAME.
212The icon is found by `icons--get-sorted-icons' (which see)."
213 (or (when-let ((icons (icons--get-sorted-icons name)))
214 (find-image (mapcar #'icons--image-spec-from-icon icons)))
215 (error "Unable to find icon: `%s'" name)))
216
217;;;###autoload
218(defun icons-get (name &optional _size)
219 "Return icon NAME for inserting into a buffer.
220NAME is a string."
221 ;; FIXME: Size, based on default face.
222 ;; You should also be able to pass in a different face.
223 (if icons-enabled
224 (propertize " " 'display (icons--get-icon name))
225 ""))
226
227;;;###autoload
228(defun icons-get-filename (name &optional _size)
229 "Return filename of icon NAME.
230NAME is a string."
231 (plist-get (cdr (icons--get-icon name)) :file))
232
233;;;###autoload
234(defun icons-get-for-modeline (name)
235 "Return icon NAME for use in `mode-line-format'.
236NAME is as in `icons-get'."
237 (if icons-enabled
238 `(:propertize (" ") display ,(icons--get-icon name))
239 ""))
240
241;;;###autoload
242(defun icons-insert (name &optional _size) ; FIXME: Is this very useful?
243 "Insert icon NAME at point.
244NAME is as in `icons-get'."
245 (when icons-enabled
246 (insert (icons-get name))))
247
248;; (defun icons--filename-for-size (font-size filename-alist)
249;; "Return filename from FILENAME-ALIST closest to FONT-SIZE."
250;; (if (listp filename-alist)
251;; (let* ((sizes (map-keys filename-alist))
252;; (size (icons--closest-to font-size sizes)))
253;; (cdr (assq size filename-alist)))
254;; filename-alist))
255
256
257;;;; Describing icons.
258
259(defface icons-description-title '((t :inherit bold)) "")
260(defface icons-icon-075 '((t :height 0.75)) "")
261(defface icons-icon-100 '((t :height 1.0)) "")
262(defface icons-icon-150 '((t :height 1.5)) "")
263(defface icons-icon-200 '((t :height 2.0)) "")
264(defface icons-icon-300 '((t :height 3.0)) "")
265(defface icons-icon-400 '((t :height 4.0)) "")
266
267(defun describe-icon (name)
268 "Describe icon NAME."
269 (interactive (list (completing-read (format-prompt "Describe icon" nil)
270 (sort (mapcar #'car icons-alist) #'string<))))
271 (let ((icon (cadr (assoc name icons-alist))))
272 (help-setup-xref (list #'describe-icon name)
273 (called-interactively-p 'interactive))
274 (with-help-window (help-buffer)
275 (with-current-buffer standard-output
276 ;; TODO: Link the set name to corresponding `describe-icon-set'.
277 (insert (format-message "%S belongs to the icon set `%s'.\n\n"
278 name (icons-icon-set icon)))
279
280 (insert (propertize "Filename:" 'face 'icons-description-title)
281 " "
282 (icons-icon-filename icon)
283 "\n")
284 (insert (propertize "Size:" 'face 'icons-description-title)
285 " "
286 (format "%s" (icons-icon-size icon))
287 "\n")
288 (insert (propertize "Type:" 'face 'icons-description-title)
289 " "
290 (format "%s" (icons-icon-type icon))
291 "\n")
292
293 (insert "\n")
294 (dolist (face '( icons-icon-075 icons-icon-100 icons-icon-150
295 icons-icon-200 icons-icon-300 icons-icon-400))
296 (insert (propertize " " 'display '(space :align-to 2)))
297 (insert (propertize (icons-get name) 'face face))
298 (insert "\n\n"))))))
299
300;; (defun describe-icon-set (name)
301;; "Describe icon set NAME."
302;; (interactive
303;; (list (completing-read (format-prompt "Describe icon set" nil)
304;; (sort icons-defined-sets
305;; (lambda (a b)
306;; (string< (symbol-name a) (symbol-name b)))))))
307;; (help-setup-xref (list #'describe-icon-set name)
308;; (called-interactively-p 'interactive))
309;; (with-help-window (help-buffer)
310;; (with-current-buffer standard-output
311;; ;; TODO: Link the set name to corresponding `describe-icon-set'.
312;; (princ (format-message "Icon set `%s'.\n\n"
313;; (icons-icon-set icon)))
314;; ;; TODO: Show all alternative icons in different sizes.
315;; (icons-insert name))))
316
317
318;;;; Listing icons.
319
320(defconst icons-list-buffer-name "*Icons*")
321
322(defun icons-list-make-entries ()
323 "Make list of all icons for `tabulated-list-entries'."
324 (let (entries)
325 (dolist (ic icons-alist)
326 (let ((icon-name (car ic))
327 (icons (cdr ic)))
328 (dolist (icon icons)
329 (push (list (cons icon-name icon)
330 (vector (symbol-name (icons-icon-set icon))
331 icon-name
332 (format "%s" (or (icons-icon-size icon) ""))
333 (format "%s" (icons-icon-type icon))
334 (find-image (list (icons--image-spec-from-icon icon )))))
335 entries))))
336 entries))
337
338;; Ignore arguments to be usable for `revert-buffer-function'.
339(defun icons-list-display (&optional _ _ _)
340 "Prepare buffer for `tabulated-list-mode' based on `icons-alist'."
341 (setq tabulated-list-entries (icons-list-make-entries))
342 (tabulated-list-init-header)
343 (tabulated-list-print t))
344
345(defvar-keymap icons-list-mode-map
346 :doc "Keymap for `icons-list-mode'."
347 "w" #'icons-list-copy-name)
348
349(define-derived-mode icons-list-mode tabulated-list-mode "Icons List Mode"
350 "Major mode for listing icons."
351 :interactive nil
352 (setq tabulated-list-format [("Icon set" 13 icons-list--icon-set-predicate)
353 ("Name" 30 icons-list--name-predicate)
354 ("Size" 6 icons-list--size-predicate)
355 ("Type" 5)
356 ("Icon" -1)])
357 (setq revert-buffer-function #'icons-list-display)
358 (setq tabulated-list-sort-key (cons "Size" nil)))
359
360;;;###autoload
361(defun list-icons ()
362 "Display all defined icons."
363 (interactive)
364 (pop-to-buffer (get-buffer-create icons-list-buffer-name))
365 (icons-list-mode)
366 (icons-list-display))
367
368(defun icons-list--name-predicate (A B)
369 "Predicate to sort `list-icons' by \"Name\"."
370 (string< (caar A) (caar B)))
371
372(defun icons-list--size-predicate (A B)
373 "Predicate to sort `list-icons' by \"Size\"."
374 (< (string-to-number (aref (cadr A) 2))
375 (string-to-number (aref (cadr B) 2))))
376
377(defun icons-list--icon-set-predicate (A B)
378 "Predicate to sort `list-icons' by Icon Set."
379 (let ((Aset (aref (cadr A) 0))
380 (Bset (aref (cadr B) 0)))
381 (if (string= Aset Bset)
382 ;; Secondary sort keys.
383 (or (icons-list--size-predicate A B)
384 (icons-list--name-predicate A B))
385 (string< Aset Bset))))
386
387(defun icons-list-copy-name ()
388 "In `icons-list-mode', copy name of icon at point."
389 (interactive nil icons-list-mode)
390 (let ((icon-name (aref (get-text-property (point) 'tabulated-list-entry) 1)))
391 (when icon-name
392 (kill-new icon-name)
393 (message "%s" icon-name))))
394
395;; (get-char-property (point) 'read-face-name)
396;; (get-char-property (point) 'font-lock-face)
397;; (get-char-property (point) 'face)
398
399
400;;;; Util.
401
402(defun icons--face-height-at-point ()
403 "Return font height at point."
404 (let* ((scale (cadr (assoc :height (assoc 'default face-remapping-alist))))
405 (face (face-font (or (face-at-point t) 'default)))
406 (height (* (aref (font-info face) 2) (if scale scale 1))))
407 height))
408
409(defun icons--closest-to (num candidates)
410 "Return the closest number to NUM among CANDIDATES."
411 (car (sort candidates (lambda (a b) (<= (abs (- num a))
412 (abs (- num b)))))))
413
414(icons-define-set 'emacs
415 '(
416 ("attach" "attach.pbm")
417 ("attach" "attach.xpm")
418 ("back-arrow" "back-arrow.pbm")
419 ("back-arrow" "back-arrow.xpm")
420 ("bookmark_add" "bookmark_add.pbm")
421 ("bookmark_add" "bookmark_add.xpm")
422 ("cancel" "cancel.pbm")
423 ("cancel" "cancel.xpm")
424 ("checkbox-mixed" "checkbox-mixed.svg")
425 ("checked" "checked.svg")
426 ("checked" "checked.xpm")
427 ("close" "close.pbm")
428 ("close" "close.xpm")
429 ("connect" "connect.pbm")
430 ("connect" "connect.xpm")
431 ("contact" "contact.pbm")
432 ("contact" "contact.xpm")
433 ("copy" "copy.pbm")
434 ("copy" "copy.xpm")
435 ("custom/down" "custom/down.pbm")
436 ("custom/down" "custom/down.xpm")
437 ("custom/down-pushed" "custom/down-pushed.pbm")
438 ("custom/down-pushed" "custom/down-pushed.xpm")
439 ("custom/right" "custom/right.pbm")
440 ("custom/right" "custom/right.xpm")
441 ("custom/right-pushed" "custom/right-pushed.pbm")
442 ("custom/right-pushed" "custom/right-pushed.xpm")
443 ("cut" "cut.pbm")
444 ("cut" "cut.xpm")
445 ("data-save" "data-save.pbm")
446 ("data-save" "data-save.xpm")
447 ("delete" "delete.pbm")
448 ("delete" "delete.xpm")
449 ("describe" "describe.pbm")
450 ("describe" "describe.xpm")
451 ("diropen" "diropen.pbm")
452 ("diropen" "diropen.xpm")
453 ("disconnect" "disconnect.pbm")
454 ("disconnect" "disconnect.xpm")
455 ("down" "down.svg")
456 ("exit" "exit.pbm")
457 ("exit" "exit.xpm")
458 ("ezimage/bits" "ezimage/bits.pbm")
459 ("ezimage/bits" "ezimage/bits.xpm")
460 ("ezimage/bitsbang" "ezimage/bitsbang.pbm")
461 ("ezimage/bitsbang" "ezimage/bitsbang.xpm")
462 ("ezimage/box" "ezimage/box.pbm")
463 ("ezimage/box" "ezimage/box.xpm")
464 ("ezimage/box-minus" "ezimage/box-minus.pbm")
465 ("ezimage/box-minus" "ezimage/box-minus.xpm")
466 ("ezimage/box-plus" "ezimage/box-plus.pbm")
467 ("ezimage/box-plus" "ezimage/box-plus.xpm")
468 ("ezimage/checkmark" "ezimage/checkmark.pbm")
469 ("ezimage/checkmark" "ezimage/checkmark.xpm")
470 ("ezimage/dir" "ezimage/dir.pbm")
471 ("ezimage/dir" "ezimage/dir.xpm")
472 ("ezimage/dir-minus" "ezimage/dir-minus.pbm")
473 ("ezimage/dir-minus" "ezimage/dir-minus.xpm")
474 ("ezimage/dir-plus" "ezimage/dir-plus.pbm")
475 ("ezimage/dir-plus" "ezimage/dir-plus.xpm")
476 ("ezimage/doc" "ezimage/doc.pbm")
477 ("ezimage/doc" "ezimage/doc.xpm")
478 ("ezimage/doc-minus" "ezimage/doc-minus.pbm")
479 ("ezimage/doc-minus" "ezimage/doc-minus.xpm")
480 ("ezimage/doc-plus" "ezimage/doc-plus.pbm")
481 ("ezimage/doc-plus" "ezimage/doc-plus.xpm")
482 ("ezimage/info" "ezimage/info.pbm")
483 ("ezimage/info" "ezimage/info.xpm")
484 ("ezimage/key" "ezimage/key.pbm")
485 ("ezimage/key" "ezimage/key.xpm")
486 ("ezimage/label" "ezimage/label.pbm")
487 ("ezimage/label" "ezimage/label.xpm")
488 ("ezimage/lock" "ezimage/lock.pbm")
489 ("ezimage/lock" "ezimage/lock.xpm")
490 ("ezimage/mail" "ezimage/mail.pbm")
491 ("ezimage/mail" "ezimage/mail.xpm")
492 ("ezimage/page" "ezimage/page.pbm")
493 ("ezimage/page" "ezimage/page.xpm")
494 ("ezimage/page-minus" "ezimage/page-minus.pbm")
495 ("ezimage/page-minus" "ezimage/page-minus.xpm")
496 ("ezimage/page-plus" "ezimage/page-plus.pbm")
497 ("ezimage/page-plus" "ezimage/page-plus.xpm")
498 ("ezimage/tag" "ezimage/tag.pbm")
499 ("ezimage/tag" "ezimage/tag.xpm")
500 ("ezimage/tag-gt" "ezimage/tag-gt.pbm")
501 ("ezimage/tag-gt" "ezimage/tag-gt.xpm")
502 ("ezimage/tag-minus" "ezimage/tag-minus.pbm")
503 ("ezimage/tag-minus" "ezimage/tag-minus.xpm")
504 ("ezimage/tag-plus" "ezimage/tag-plus.pbm")
505 ("ezimage/tag-plus" "ezimage/tag-plus.xpm")
506 ("ezimage/tag-type" "ezimage/tag-type.pbm")
507 ("ezimage/tag-type" "ezimage/tag-type.xpm")
508 ("ezimage/tag-v" "ezimage/tag-v.pbm")
509 ("ezimage/tag-v" "ezimage/tag-v.xpm")
510 ("ezimage/unlock" "ezimage/unlock.pbm")
511 ("ezimage/unlock" "ezimage/unlock.xpm")
512 ("fwd-arrow" "fwd-arrow.pbm")
513 ("fwd-arrow" "fwd-arrow.xpm")
514 ("gnus" "gnus.pbm")
515 ("gnus/followup" "gnus/followup.pbm")
516 ("gnus/followup" "gnus/followup.xpm")
517 ("gnus/fuwo" "gnus/fuwo.pbm")
518 ("gnus/fuwo" "gnus/fuwo.xpm")
519 ("gnus/gnus" "gnus/gnus.png")
520 ("gnus/gnus" "gnus/gnus.svg")
521 ("gnus/gnus" "gnus/gnus.xbm")
522 ("gnus/gnus" "gnus/gnus.xpm")
523 ("gnus/gnus-pointer" "gnus/gnus-pointer.xbm")
524 ("gnus/gnus-pointer" "gnus/gnus-pointer.xpm")
525 ("gnus/kill-group" "gnus/kill-group.pbm")
526 ("gnus/kill-group" "gnus/kill-group.xpm")
527 ("gnus/mail-reply" "gnus/mail-reply.pbm")
528 ("gnus/mail-reply" "gnus/mail-reply.xpm")
529 ("gnus/mail-send" "gnus/mail-send.pbm")
530 ("gnus/mail-send" "gnus/mail-send.xpm")
531 ("gnus/preview" "gnus/preview.xbm")
532 ("gnus/preview" "gnus/preview.xpm")
533 ("gnus/toggle-subscription" "gnus/toggle-subscription.pbm")
534 ("gnus/toggle-subscription" "gnus/toggle-subscription.xpm")
535 ("gud/all" "gud/all.pbm")
536 ("gud/all" "gud/all.xpm")
537 ("gud/break" "gud/break.pbm")
538 ("gud/break" "gud/break.xpm")
539 ("gud/cont" "gud/cont.pbm")
540 ("gud/cont" "gud/cont.xpm")
541 ("gud/down" "gud/down.pbm")
542 ("gud/down" "gud/down.xpm")
543 ("gud/finish" "gud/finish.pbm")
544 ("gud/finish" "gud/finish.xpm")
545 ("gud/go" "gud/go.pbm")
546 ("gud/go" "gud/go.xpm")
547 ("gud/next" "gud/next.pbm")
548 ("gud/next" "gud/next.xpm")
549 ("gud/nexti" "gud/nexti.pbm")
550 ("gud/nexti" "gud/nexti.xpm")
551 ("gud/pp" "gud/pp.pbm")
552 ("gud/pp" "gud/pp.xpm")
553 ("gud/print" "gud/print.pbm")
554 ("gud/print" "gud/print.xpm")
555 ("gud/pstar" "gud/pstar.pbm")
556 ("gud/pstar" "gud/pstar.xpm")
557 ("gud/rcont" "gud/rcont.pbm")
558 ("gud/rcont" "gud/rcont.xpm")
559 ("gud/recstart" "gud/recstart.pbm")
560 ("gud/recstart" "gud/recstart.xpm")
561 ("gud/recstop" "gud/recstop.pbm")
562 ("gud/recstop" "gud/recstop.xpm")
563 ("gud/remove" "gud/remove.pbm")
564 ("gud/remove" "gud/remove.xpm")
565 ("gud/rfinish" "gud/rfinish.pbm")
566 ("gud/rfinish" "gud/rfinish.xpm")
567 ("gud/rnext" "gud/rnext.pbm")
568 ("gud/rnext" "gud/rnext.xpm")
569 ("gud/rnexti" "gud/rnexti.pbm")
570 ("gud/rnexti" "gud/rnexti.xpm")
571 ("gud/rstep" "gud/rstep.pbm")
572 ("gud/rstep" "gud/rstep.xpm")
573 ("gud/rstepi" "gud/rstepi.pbm")
574 ("gud/rstepi" "gud/rstepi.xpm")
575 ("gud/run" "gud/run.pbm")
576 ("gud/run" "gud/run.xpm")
577 ("gud/step" "gud/step.pbm")
578 ("gud/step" "gud/step.xpm")
579 ("gud/stepi" "gud/stepi.pbm")
580 ("gud/stepi" "gud/stepi.xpm")
581 ("gud/stop" "gud/stop.pbm")
582 ("gud/stop" "gud/stop.xpm")
583 ("gud/thread" "gud/thread.pbm")
584 ("gud/thread" "gud/thread.xpm")
585 ("gud/until" "gud/until.pbm")
586 ("gud/until" "gud/until.xpm")
587 ("gud/up" "gud/up.pbm")
588 ("gud/up" "gud/up.xpm")
589 ("gud/watch" "gud/watch.pbm")
590 ("gud/watch" "gud/watch.xpm")
591 ("help" "help.pbm")
592 ("help" "help.xpm")
593 ("home" "home.pbm")
594 ("home" "home.xpm")
595 ("index" "index.pbm")
596 ("index" "index.xpm")
597 ("info" "info.pbm")
598 ("info" "info.xpm")
599 ("jump-to" "jump-to.pbm")
600 ("jump-to" "jump-to.xpm")
601 ("left" "left.svg")
602 ("left-arrow" "left-arrow.pbm")
603 ("left-arrow" "left-arrow.xpm")
604 ("letter" "letter.pbm")
605 ("letter" "letter.xpm")
606 ("lock" "lock.pbm")
607 ("lock" "lock.xpm")
608 ("lock-broken" "lock-broken.pbm")
609 ("lock-broken" "lock-broken.xpm")
610 ("lock-ok" "lock-ok.pbm")
611 ("lock-ok" "lock-ok.xpm")
612 ("low-color/back-arrow" "low-color/back-arrow.xpm")
613 ("low-color/copy" "low-color/copy.xpm")
614 ("low-color/cut" "low-color/cut.xpm")
615 ("low-color/fwd-arrow" "low-color/fwd-arrow.xpm")
616 ("low-color/help" "low-color/help.xpm")
617 ("low-color/home" "low-color/home.xpm")
618 ("low-color/index" "low-color/index.xpm")
619 ("low-color/jump-to" "low-color/jump-to.xpm")
620 ("low-color/left-arrow" "low-color/left-arrow.xpm")
621 ("low-color/new" "low-color/new.xpm")
622 ("low-color/next-node" "low-color/next-node.xpm")
623 ("low-color/open" "low-color/open.xpm")
624 ("low-color/paste" "low-color/paste.xpm")
625 ("low-color/preferences" "low-color/preferences.xpm")
626 ("low-color/prev-node" "low-color/prev-node.xpm")
627 ("low-color/print" "low-color/print.xpm")
628 ("low-color/right-arrow" "low-color/right-arrow.xpm")
629 ("low-color/save" "low-color/save.xpm")
630 ("low-color/saveas" "low-color/saveas.xpm")
631 ("low-color/search" "low-color/search.xpm")
632 ("low-color/spell" "low-color/spell.xpm")
633 ("low-color/undo" "low-color/undo.xpm")
634 ("low-color/up-arrow" "low-color/up-arrow.xpm")
635 ("low-color/up-node" "low-color/up-node.xpm")
636 ("mail/compose" "mail/compose.pbm")
637 ("mail/compose" "mail/compose.xpm")
638 ("mail/copy" "mail/copy.pbm")
639 ("mail/copy" "mail/copy.xpm")
640 ("mail/flag-for-followup" "mail/flag-for-followup.pbm")
641 ("mail/flag-for-followup" "mail/flag-for-followup.xpm")
642 ("mail/forward" "mail/forward.pbm")
643 ("mail/forward" "mail/forward.xpm")
644 ("mail/inbox" "mail/inbox.pbm")
645 ("mail/inbox" "mail/inbox.xpm")
646 ("mail/move" "mail/move.pbm")
647 ("mail/move" "mail/move.xpm")
648 ("mail/not-spam" "mail/not-spam.pbm")
649 ("mail/not-spam" "mail/not-spam.xpm")
650 ("mail/outbox" "mail/outbox.pbm")
651 ("mail/outbox" "mail/outbox.xpm")
652 ("mail/preview" "mail/preview.pbm")
653 ("mail/preview" "mail/preview.xpm")
654 ("mail/repack" "mail/repack.pbm")
655 ("mail/repack" "mail/repack.xpm")
656 ("mail/reply" "mail/reply.pbm")
657 ("mail/reply" "mail/reply.xpm")
658 ("mail/reply-all" "mail/reply-all.pbm")
659 ("mail/reply-all" "mail/reply-all.xpm")
660 ("mail/reply-from" "mail/reply-from.pbm")
661 ("mail/reply-from" "mail/reply-from.xpm")
662 ("mail/reply-to" "mail/reply-to.pbm")
663 ("mail/reply-to" "mail/reply-to.xpm")
664 ("mail/save" "mail/save.xpm")
665 ("mail/save-draft" "mail/save-draft.pbm")
666 ("mail/save-draft" "mail/save-draft.xpm")
667 ("mail/send" "mail/send.pbm")
668 ("mail/send" "mail/send.xpm")
669 ("mail/spam" "mail/spam.xpm")
670 ("mh-logo" "mh-logo.pbm")
671 ("mh-logo" "mh-logo.xpm")
672 ("new" "new.pbm")
673 ("new" "new.xpm")
674 ("newsticker/browse-url" "newsticker/browse-url.xpm")
675 ("newsticker/get-all" "newsticker/get-all.xpm")
676 ("newsticker/mark-immortal" "newsticker/mark-immortal.xpm")
677 ("newsticker/mark-read" "newsticker/mark-read.xpm")
678 ("newsticker/narrow" "newsticker/narrow.xpm")
679 ("newsticker/next-feed" "newsticker/next-feed.xpm")
680 ("newsticker/next-item" "newsticker/next-item.xpm")
681 ("newsticker/prev-feed" "newsticker/prev-feed.xpm")
682 ("newsticker/prev-item" "newsticker/prev-item.xpm")
683 ("newsticker/rss-feed" "newsticker/rss-feed.png")
684 ("newsticker/rss-feed" "newsticker/rss-feed.svg")
685 ("newsticker/update" "newsticker/update.xpm")
686 ("next-node" "next-node.pbm")
687 ("next-node" "next-node.xpm")
688 ("next-page" "next-page.pbm")
689 ("next-page" "next-page.xpm")
690 ("open" "open.pbm")
691 ("open" "open.xpm")
692 ("paste" "paste.pbm")
693 ("paste" "paste.xpm")
694 ("preferences" "preferences.pbm")
695 ("preferences" "preferences.xpm")
696 ("prev-node" "prev-node.pbm")
697 ("prev-node" "prev-node.xpm")
698 ("print" "print.pbm")
699 ("print" "print.xpm")
700 ("radio" "radio.svg")
701 ("radio-checked" "radio-checked.svg")
702 ("radio-mixed" "radio-mixed.svg")
703 ("redo" "redo.pbm")
704 ("redo" "redo.xpm")
705 ("refresh" "refresh.pbm")
706 ("refresh" "refresh.xpm")
707 ("right" "right.svg")
708 ("right-arrow" "right-arrow.pbm")
709 ("right-arrow" "right-arrow.xpm")
710 ("save" "save.pbm")
711 ("save" "save.xpm")
712 ("saveas" "saveas.pbm")
713 ("saveas" "saveas.xpm")
714 ("search" "search.pbm")
715 ("search" "search.xpm")
716 ("search-replace" "search-replace.pbm")
717 ("search-replace" "search-replace.xpm")
718 ("separator" "separator.pbm")
719 ("separator" "separator.xpm")
720 ("show" "show.pbm")
721 ("show" "show.xpm")
722 ("smilies/blink" "smilies/blink.pbm")
723 ("smilies/blink" "smilies/blink.xpm")
724 ("smilies/braindamaged" "smilies/braindamaged.pbm")
725 ("smilies/braindamaged" "smilies/braindamaged.xpm")
726 ("smilies/cry" "smilies/cry.pbm")
727 ("smilies/cry" "smilies/cry.xpm")
728 ("smilies/dead" "smilies/dead.pbm")
729 ("smilies/dead" "smilies/dead.xpm")
730 ("smilies/evil" "smilies/evil.pbm")
731 ("smilies/evil" "smilies/evil.xpm")
732 ("smilies/forced" "smilies/forced.pbm")
733 ("smilies/forced" "smilies/forced.xpm")
734 ("smilies/frown" "smilies/frown.pbm")
735 ("smilies/frown" "smilies/frown.xpm")
736 ("smilies/grin" "smilies/grin.pbm")
737 ("smilies/grin" "smilies/grin.xpm")
738 ("smilies/indifferent" "smilies/indifferent.pbm")
739 ("smilies/indifferent" "smilies/indifferent.xpm")
740 ("smilies/sad" "smilies/sad.pbm")
741 ("smilies/sad" "smilies/sad.xpm")
742 ("smilies/smile" "smilies/smile.pbm")
743 ("smilies/smile" "smilies/smile.xpm")
744 ("smilies/wry" "smilies/wry.pbm")
745 ("smilies/wry" "smilies/wry.xpm")
746 ("sort-ascending" "sort-ascending.pbm")
747 ("sort-ascending" "sort-ascending.xpm")
748 ("sort-column-ascending" "sort-column-ascending.pbm")
749 ("sort-column-ascending" "sort-column-ascending.xpm")
750 ("sort-criteria" "sort-criteria.pbm")
751 ("sort-criteria" "sort-criteria.xpm")
752 ("sort-descending" "sort-descending.pbm")
753 ("sort-descending" "sort-descending.xpm")
754 ("sort-row-ascending" "sort-row-ascending.pbm")
755 ("sort-row-ascending" "sort-row-ascending.xpm")
756 ("spell" "spell.pbm")
757 ("spell" "spell.xpm")
758 ("tabs/close" "tabs/close.xpm")
759 ("tabs/left-arrow" "tabs/left-arrow.xpm")
760 ("tabs/new" "tabs/new.xpm")
761 ("tabs/right-arrow" "tabs/right-arrow.xpm")
762 ("tree-widget/default/close" "tree-widget/default/close.png")
763 ("tree-widget/default/close" "tree-widget/default/close.xpm")
764 ("tree-widget/default/empty" "tree-widget/default/empty.png")
765 ("tree-widget/default/empty" "tree-widget/default/empty.xpm")
766 ("tree-widget/default/end-guide" "tree-widget/default/end-guide.png")
767 ("tree-widget/default/end-guide" "tree-widget/default/end-guide.xpm")
768 ("tree-widget/default/guide" "tree-widget/default/guide.png")
769 ("tree-widget/default/guide" "tree-widget/default/guide.xpm")
770 ("tree-widget/default/handle" "tree-widget/default/handle.png")
771 ("tree-widget/default/handle" "tree-widget/default/handle.xpm")
772 ("tree-widget/default/leaf" "tree-widget/default/leaf.png")
773 ("tree-widget/default/leaf" "tree-widget/default/leaf.xpm")
774 ("tree-widget/default/no-guide" "tree-widget/default/no-guide.png")
775 ("tree-widget/default/no-guide" "tree-widget/default/no-guide.xpm")
776 ("tree-widget/default/no-handle" "tree-widget/default/no-handle.png")
777 ("tree-widget/default/no-handle" "tree-widget/default/no-handle.xpm")
778 ("tree-widget/default/open" "tree-widget/default/open.png")
779 ("tree-widget/default/open" "tree-widget/default/open.xpm")
780 ("tree-widget/folder/close" "tree-widget/folder/close.png")
781 ("tree-widget/folder/close" "tree-widget/folder/close.xpm")
782 ("tree-widget/folder/empty" "tree-widget/folder/empty.png")
783 ("tree-widget/folder/empty" "tree-widget/folder/empty.xpm")
784 ("tree-widget/folder/end-guide" "tree-widget/folder/end-guide.png")
785 ("tree-widget/folder/end-guide" "tree-widget/folder/end-guide.xpm")
786 ("tree-widget/folder/guide" "tree-widget/folder/guide.png")
787 ("tree-widget/folder/guide" "tree-widget/folder/guide.xpm")
788 ("tree-widget/folder/handle" "tree-widget/folder/handle.png")
789 ("tree-widget/folder/handle" "tree-widget/folder/handle.xpm")
790 ("tree-widget/folder/leaf" "tree-widget/folder/leaf.png")
791 ("tree-widget/folder/leaf" "tree-widget/folder/leaf.xpm")
792 ("tree-widget/folder/no-guide" "tree-widget/folder/no-guide.png")
793 ("tree-widget/folder/no-guide" "tree-widget/folder/no-guide.xpm")
794 ("tree-widget/folder/no-handle" "tree-widget/folder/no-handle.png")
795 ("tree-widget/folder/no-handle" "tree-widget/folder/no-handle.xpm")
796 ("tree-widget/folder/open" "tree-widget/folder/open.png")
797 ("tree-widget/folder/open" "tree-widget/folder/open.xpm")
798 ("unchecked" "unchecked.pbm")
799 ("unchecked" "unchecked.svg")
800 ("unchecked" "unchecked.xpm")
801 ("undo" "undo.pbm")
802 ("undo" "undo.xpm")
803 ("up" "up.svg")
804 ("up-arrow" "up-arrow.pbm")
805 ("up-arrow" "up-arrow.xpm")
806 ("up-node" "up-node.pbm")
807 ("up-node" "up-node.xpm")
808 ("zoom-in" "zoom-in.pbm")
809 ("zoom-in" "zoom-in.xpm")
810 ("zoom-out" "zoom-out.pbm")
811 ("zoom-out" "zoom-out.xpm")
812 ;; ("smilies/grayscale/blink" "smilies/grayscale/blink.xpm")
813 ;; ("smilies/grayscale/braindamaged" "smilies/grayscale/braindamaged.xpm")
814 ;; ("smilies/grayscale/cry" "smilies/grayscale/cry.xpm")
815 ;; ("smilies/grayscale/dead" "smilies/grayscale/dead.xpm")
816 ;; ("smilies/grayscale/evil" "smilies/grayscale/evil.xpm")
817 ;; ("smilies/grayscale/forced" "smilies/grayscale/forced.xpm")
818 ;; ("smilies/grayscale/frown" "smilies/grayscale/frown.xpm")
819 ;; ("smilies/grayscale/grin" "smilies/grayscale/grin.xpm")
820 ;; ("smilies/grayscale/indifferent" "smilies/grayscale/indifferent.xpm")
821 ;; ("smilies/grayscale/reverse-smile" "smilies/grayscale/reverse-smile.xpm")
822 ;; ("smilies/grayscale/sad" "smilies/grayscale/sad.xpm")
823 ;; ("smilies/grayscale/smile" "smilies/grayscale/smile.xpm")
824 ;; ("smilies/grayscale/wry" "smilies/grayscale/wry.xpm")
825 ;; ("smilies/medium/blink" "smilies/medium/blink.xpm")
826 ;; ("smilies/medium/braindamaged" "smilies/medium/braindamaged.xpm")
827 ;; ("smilies/medium/cry" "smilies/medium/cry.xpm")
828 ;; ("smilies/medium/dead" "smilies/medium/dead.xpm")
829 ;; ("smilies/medium/evil" "smilies/medium/evil.xpm")
830 ;; ("smilies/medium/forced" "smilies/medium/forced.xpm")
831 ;; ("smilies/medium/frown" "smilies/medium/frown.xpm")
832 ;; ("smilies/medium/grin" "smilies/medium/grin.xpm")
833 ;; ("smilies/medium/indifferent" "smilies/medium/indifferent.xpm")
834 ;; ("smilies/medium/reverse-smile" "smilies/medium/reverse-smile.xpm")
835 ;; ("smilies/medium/sad" "smilies/medium/sad.xpm")
836 ;; ("smilies/medium/smile" "smilies/medium/smile.xpm")
837 ;; ("smilies/medium/wry" "smilies/medium/wry.xpm")
838 ;; ("splash" "splash.bmp")
839 ;; ("splash" "splash.pbm")
840 ;; ("splash" "splash.png")
841 ;; ("splash" "splash.svg")
842 ;; ("splash" "splash.xpm")
843 ))
844
845(provide 'icons)
846;;; icons.el ends here
diff --git a/test/lisp/emacs-lisp/icons-tests.el b/test/lisp/emacs-lisp/icons-tests.el
index e6e71a8e4fd..11a7a567af0 100644
--- a/test/lisp/emacs-lisp/icons-tests.el
+++ b/test/lisp/emacs-lisp/icons-tests.el
@@ -1,5 +1,7 @@
1;;; icons-tests.el --- Tests for icons.el -*- lexical-binding: t; -*- 1;;; icons-tests.el --- Tests for icons.el -*- lexical-binding: t; -*-
2 2
3;; Author: Stefan Kangas <stefankangas@gmail.com>
4
3;; Copyright (C) 2022 Free Software Foundation, Inc. 5;; Copyright (C) 2022 Free Software Foundation, Inc.
4 6
5;; This file is part of GNU Emacs. 7;; This file is part of GNU Emacs.
@@ -60,4 +62,107 @@
60 (let ((icon-preference '(text))) 62 (let ((icon-preference '(text)))
61 (should (equal (icon-string 'icon-test2) "child")))) 63 (should (equal (icon-string 'icon-test2) "child"))))
62 64
65(defmacro with-icons-test (&rest body)
66 (declare (indent defun))
67 `(let (icons-alist
68 (image-load-path (cons
69 (ert-resource-directory)
70 image-load-path))
71 (icons-format-priority '(svg xpm pbm)))
72 (icons-define-set 'set1 `(("apple" "apple2.svg" 24)
73 ("orange" "orange.svg" 24)
74 ("lemon" "lemon.svg")))
75 (icons-define-set 'set2 `(("apple" "apple.svg")))
76 (icons-define-set 'xpmset `(("apple" "apple.xpm")))
77 (icons-define-set 'pbmset `(("apple" "apple.pbm")))
78 ,@body))
79
80;;;; Data.
81
82(ert-deftest icons-define-set ()
83 (with-icons-test
84 (should (= (length (cdr (assoc "apple" icons-alist))) 4))))
85
86;;;; Inserting and getting icons.
87
88(ert-deftest icons--get-icon ()
89 (with-icons-test
90 (let ((icon (cdr (icons--get-icon "apple"))))
91 (plist-get icon :file)
92 (should (string-match "apple\.svg\\'"
93 (plist-get icon :file))))))
94
95(ert-deftest icons--get-icon/missing ()
96 (with-icons-test
97 (should-error (icons--get-icon "foo-missing-icon"))))
98
99(ert-deftest icons--get-sorted-icons/format-priority ()
100 (with-icons-test
101 (should (eq (icons-icon-type (car (last (icons--get-sorted-icons "apple"))))
102 (car (last icons-format-priority))))))
103
104(ert-deftest icons--get-sorted-icons/set-priority ()
105 (let ((icons-set-priority '(set1 set2)))
106 (with-icons-test
107 (should (equal (icons-icon-filename (car (icons--get-sorted-icons "apple")))
108 "apple2.svg"))))
109 (let ((icons-set-priority '(set2 set1)))
110 (with-icons-test
111 (should (equal (icons-icon-filename (car (icons--get-sorted-icons "apple")))
112 "apple.svg")))))
113
114(ert-deftest icons-get/returns-space ()
115 (with-icons-test
116 (should (equal (with-icons-test (icons-get "apple")) " "))))
117
118(ert-deftest icons-get/has-display-property ()
119 (should (get-text-property 0 'display (with-icons-test (icons-get "apple")))))
120
121(ert-deftest icons-get-icon ()
122 (should (eq (car (with-icons-test (icons-get-for-modeline "apple")))
123 :propertize)))
124
125(ert-deftest icons-tests--remove-set ()
126 (with-icons-test
127 (icons--remove-set 'set1)
128 (icons--remove-set 'set2)
129 (icons--remove-set 'xpmset)
130 (icons--remove-set 'pbmset)
131 (should (not icons-alist))))
132
133;; (ert-deftest icons-add-icon ()
134;; (let (icons-alist
135;; (icon (icons-icon-create :filename "bar" :set 'set)))
136;; (icons-add-icon "foo" icon)
137;; (should (assoc "foo" icons-alist))
138;; ;; Invalid names.
139;; (should-error (icons-add-icon nil icon))
140;; (should-error (icons-add-icon 'foo icon))
141;; ;; Invalid icons.
142;; (should-error (icons-add-icon "foo" "not an icon"))))
143
144;; (ert-deftest test-list-make-entries ()
145;; (with-icons-test
146;; (let ((entries (icons-list-make-entries)))
147;; (should (listp entries))
148;; (should (= (length entries) 2)))))
149
150;; (ert-deftest test-icons--filename-for-size/string ()
151;; (should (equal (icons--filename-for-size 20 "foobar")
152;; "foobar")))
153
154;; (ert-deftest test-icons--filename-for-size/alist ()
155;; (should (equal (icons--filename-for-size 20 '((5 . "foo")
156;; (10 . "bar")))
157;; "bar")))
158
159;;;; Util.
160
161(ert-deftest test-icons--find-closest ()
162 (should (= (icons--closest-to 14 '(10 20)) 10))
163 (should (= (icons--closest-to 15 '(10 20)) 20))
164 (should (= (icons--closest-to 8 '(6 12)) 6))
165 (should (= (icons--closest-to 9 '(6 12)) 12))
166 (should (= (icons--closest-to 14 '(10 18 20)) 18)))
167
63;;; icons-tests.el ends here 168;;; icons-tests.el ends here
diff --git a/test/lisp/icons-tests.el b/test/lisp/icons-tests.el
deleted file mode 100644
index 39fc51635cc..00000000000
--- a/test/lisp/icons-tests.el
+++ /dev/null
@@ -1,131 +0,0 @@
1;;; icons-tests.el --- tests for icons.el -*- lexical-binding: t -*-
2
3;; Copyright (C) 2021 Free Software Foundation, Inc.
4
5;; Author: Stefan Kangas <stefankangas@gmail.com>
6
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software: you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
11;; the Free Software Foundation, either version 3 of the License, or
12;; (at your option) any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
20;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
21
22;;; Code:
23
24(require 'ert)
25(require 'ert-x)
26(require 'icons)
27
28(defmacro with-icons-test (&rest body)
29 (declare (indent defun))
30 `(let (icons-alist
31 (image-load-path (cons
32 (ert-resource-directory)
33 image-load-path))
34 (icons-format-priority '(svg xpm pbm)))
35 (icons-define-set 'set1 `(("apple" "apple2.svg" 24)
36 ("orange" "orange.svg" 24)
37 ("lemon" "lemon.svg")))
38 (icons-define-set 'set2 `(("apple" "apple.svg")))
39 (icons-define-set 'xpmset `(("apple" "apple.xpm")))
40 (icons-define-set 'pbmset `(("apple" "apple.pbm")))
41 ,@body))
42
43;;;; Data.
44
45(ert-deftest icons-define-set ()
46 (with-icons-test
47 (should (= (length (cdr (assoc "apple" icons-alist))) 4))))
48
49;;;; Inserting and getting icons.
50
51(ert-deftest icons--get-icon ()
52 (with-icons-test
53 (let ((icon (cdr (icons--get-icon "apple"))))
54 (plist-get icon :file)
55 (should (string-match "apple\.svg\\'"
56 (plist-get icon :file))))))
57
58(ert-deftest icons--get-icon/missing ()
59 (with-icons-test
60 (should-error (icons--get-icon "foo-missing-icon"))))
61
62(ert-deftest icons--get-sorted-icons/format-priority ()
63 (with-icons-test
64 (should (eq (icons-icon-type (car (last (icons--get-sorted-icons "apple"))))
65 (car (last icons-format-priority))))))
66
67(ert-deftest icons--get-sorted-icons/set-priority ()
68 (let ((icons-set-priority '(set1 set2)))
69 (with-icons-test
70 (should (equal (icons-icon-filename (car (icons--get-sorted-icons "apple")))
71 "apple2.svg"))))
72 (let ((icons-set-priority '(set2 set1)))
73 (with-icons-test
74 (should (equal (icons-icon-filename (car (icons--get-sorted-icons "apple")))
75 "apple.svg")))))
76
77(ert-deftest icons-get/returns-space ()
78 (with-icons-test
79 (should (equal (with-icons-test (icons-get "apple")) " "))))
80
81(ert-deftest icons-get/has-display-property ()
82 (should (get-text-property 0 'display (with-icons-test (icons-get "apple")))))
83
84(ert-deftest icons-get-icon ()
85 (should (eq (car (with-icons-test (icons-get-for-modeline "apple")))
86 :propertize)))
87
88(ert-deftest icons-tests--remove-set ()
89 (with-icons-test
90 (icons--remove-set 'set1)
91 (icons--remove-set 'set2)
92 (icons--remove-set 'xpmset)
93 (icons--remove-set 'pbmset)
94 (should (not icons-alist))))
95
96;; (ert-deftest icons-add-icon ()
97;; (let (icons-alist
98;; (icon (icons-icon-create :filename "bar" :set 'set)))
99;; (icons-add-icon "foo" icon)
100;; (should (assoc "foo" icons-alist))
101;; ;; Invalid names.
102;; (should-error (icons-add-icon nil icon))
103;; (should-error (icons-add-icon 'foo icon))
104;; ;; Invalid icons.
105;; (should-error (icons-add-icon "foo" "not an icon"))))
106
107;; (ert-deftest test-list-make-entries ()
108;; (with-icons-test
109;; (let ((entries (icons-list-make-entries)))
110;; (should (listp entries))
111;; (should (= (length entries) 2)))))
112
113;; (ert-deftest test-icons--filename-for-size/string ()
114;; (should (equal (icons--filename-for-size 20 "foobar")
115;; "foobar")))
116
117;; (ert-deftest test-icons--filename-for-size/alist ()
118;; (should (equal (icons--filename-for-size 20 '((5 . "foo")
119;; (10 . "bar")))
120;; "bar")))
121
122;;;; Util.
123
124(ert-deftest test-icons--find-closest ()
125 (should (= (icons--closest-to 14 '(10 20)) 10))
126 (should (= (icons--closest-to 15 '(10 20)) 20))
127 (should (= (icons--closest-to 8 '(6 12)) 6))
128 (should (= (icons--closest-to 9 '(6 12)) 12))
129 (should (= (icons--closest-to 14 '(10 18 20)) 18)))
130
131;;; icons-tests.el ends here