From: Andreas Gerler Date: Wed, 24 Dec 2025 13:51:40 +0000 (+0100) Subject: update color-identifiers-mode X-Git-Url: http://git.bundesbrandschatzamt.de/?a=commitdiff_plain;h=1b3fae1f5ae051ae908d1d96c245387d9a631efe;p=emacsconfig.git update color-identifiers-mode --- diff --git a/elpa/color-identifiers-mode-20241023.2217/color-identifiers-mode-autoloads.el b/elpa/color-identifiers-mode-20241023.2217/color-identifiers-mode-autoloads.el deleted file mode 100644 index a3627bf7..00000000 --- a/elpa/color-identifiers-mode-20241023.2217/color-identifiers-mode-autoloads.el +++ /dev/null @@ -1,71 +0,0 @@ -;;; color-identifiers-mode-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- -;; Generated by the `loaddefs-generate' function. - -;; This file is part of GNU Emacs. - -;;; Code: - -(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) - - - -;;; Generated autoloads from color-identifiers-mode.el - -(autoload 'color-identifiers-mode "color-identifiers-mode" "\ -Color the identifiers in the current buffer based on their names. - -This is a minor mode. If called interactively, toggle the -`Color-Identifiers mode' mode. If the prefix argument is positive, -enable the mode, and if it is zero or negative, disable the mode. - -If called from Lisp, toggle the mode if ARG is `toggle'. Enable the -mode if ARG is nil, omitted, or is a positive number. Disable the mode -if ARG is a negative number. - -To check whether the minor mode is enabled in the current buffer, -evaluate the variable `color-identifiers-mode'. - -The mode's hook is called both when the mode is enabled and when it is -disabled. - -(fn &optional ARG)" t) -(put 'global-color-identifiers-mode 'globalized-minor-mode t) -(defvar global-color-identifiers-mode nil "\ -Non-nil if Global Color-Identifiers mode is enabled. -See the `global-color-identifiers-mode' command -for a description of this minor mode. -Setting this variable directly does not take effect; -either customize it (see the info node `Easy Customization') -or call the function `global-color-identifiers-mode'.") -(custom-autoload 'global-color-identifiers-mode "color-identifiers-mode" nil) -(autoload 'global-color-identifiers-mode "color-identifiers-mode" "\ -Toggle Color-Identifiers mode in all buffers. -With prefix ARG, enable Global Color-Identifiers mode if ARG is -positive; otherwise, disable it. - -If called from Lisp, toggle the mode if ARG is `toggle'. -Enable the mode if ARG is nil, omitted, or is a positive number. -Disable the mode if ARG is a negative number. - -Color-Identifiers mode is enabled in all buffers where -`color-identifiers-mode-maybe' would do it. - -See `color-identifiers-mode' for more information on Color-Identifiers -mode. - -(fn &optional ARG)" t) -(register-definition-prefixes "color-identifiers-mode" '("color-identifiers")) - -;;; End of scraped data - -(provide 'color-identifiers-mode-autoloads) - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; no-native-compile: t -;; coding: utf-8-emacs-unix -;; End: - -;;; color-identifiers-mode-autoloads.el ends here diff --git a/elpa/color-identifiers-mode-20241023.2217/color-identifiers-mode-pkg.el b/elpa/color-identifiers-mode-20241023.2217/color-identifiers-mode-pkg.el deleted file mode 100644 index e69cbe9e..00000000 --- a/elpa/color-identifiers-mode-20241023.2217/color-identifiers-mode-pkg.el +++ /dev/null @@ -1,11 +0,0 @@ -;; -*- no-byte-compile: t; lexical-binding: nil -*- -(define-package "color-identifiers-mode" "20241023.2217" - "Color identifiers based on their names." - '((dash "2.5.0") - (emacs "24.4")) - :url "https://github.com/ankurdave/color-identifiers-mode" - :commit "89343c624ae64f568b5305ceca3db48d65711863" - :revdesc "89343c624ae6" - :keywords '("faces" "languages") - :authors '(("Ankur Dave" . "ankurdave@gmail.com")) - :maintainers '(("Ankur Dave" . "ankurdave@gmail.com"))) diff --git a/elpa/color-identifiers-mode-20241023.2217/color-identifiers-mode.el b/elpa/color-identifiers-mode-20241023.2217/color-identifiers-mode.el deleted file mode 100644 index 001a6b92..00000000 --- a/elpa/color-identifiers-mode-20241023.2217/color-identifiers-mode.el +++ /dev/null @@ -1,835 +0,0 @@ -;;; color-identifiers-mode.el --- Color identifiers based on their names -*- lexical-binding: t -*- - -;; Copyright (C) 2014 Ankur Dave - -;; Author: Ankur Dave -;; Url: https://github.com/ankurdave/color-identifiers-mode -;; Created: 24 Jan 2014 -;; Package-Version: 20241023.2217 -;; Package-Revision: 89343c624ae6 -;; Keywords: faces, languages -;; Package-Requires: ((dash "2.5.0") (emacs "24.4")) - -;; This file is not a part of GNU Emacs. - -;; This program is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see . - -;;; Commentary: - -;; Color Identifiers is a minor mode for Emacs that highlights each source code -;; identifier uniquely based on its name. It is inspired by a post by Evan -;; Brooks: https://medium.com/p/3a6db2743a1e/ - -;; Check out the project page, which has screenshots, a demo, and usage -;; instructions: https://github.com/ankurdave/color-identifiers-mode - -;;; Code: - -(require 'nadvice) -(require 'color) -(require 'dash) -(require 'cl-lib) -(require 'rx) -(require 'subr-x) - -(defgroup color-identifiers nil "Color identifiers based on their names." - :group 'faces) - -(defvar color-identifiers:timer nil - "Timer for running `color-identifiers:refresh'.") - -(defvar color-identifiers:recoloring-delay 2 - "The delay before running `color-identifiers:refresh'.") - -(defun color-identifiers:enable-timer () - (if color-identifiers:timer - ;; Someone set the timer. Activate in case we cancelled it. - (unless (memq color-identifiers:timer timer-idle-list) - (timer-activate-when-idle color-identifiers:timer)) - (setq color-identifiers:timer - (run-with-idle-timer color-identifiers:recoloring-delay t 'color-identifiers:refresh))) - ) - -(defvar-local color-identifiers:colorize-behavior nil - "For internal use. Stores the element of -`color-identifiers:modes-alist' that is relevant to the current -major mode") - -(defun color-identifiers:regen-on-theme-change(_) - "Regenerate colors for color-identifiers-mode on theme change." - (color-identifiers:regenerate-colors)) - -;;; USER-VISIBLE VARIABLES AND FUNCTIONS ======================================= - -(defcustom color-identifiers-coloring-method 'sequential - "How to assign colors: sequentially or using the hash of the identifier. -Sequential color assignment (the default) reduces collisions -between adjacent identifiers. Hash-based color assignment ensures -that a particular identifier is always assigned the same color -across buffers." - :type '(choice - (const :tag "Sequential" sequential) - (const :tag "Hash-based" hash))) - - -(defcustom color-identifiers-avoid-faces nil - "Which color faces to avoid: A list of faces whose foreground -color should be avoided when generating colors, this can be warning colors, -error colors etc." - :type '(repeat face)) - -(defcustom color-identifiers:extra-face-attributes nil - "Extra face attributes to apply to identifiers. Can be used to make -identifiers bold or italic, but avoid changing `:foreground' -because it is the color determined by the mode." - :type 'plist - :group 'color-identifiers) - -(defvar color-identifiers:modes-alist nil - "Alist of major modes and the ways to distinguish identifiers in those modes. -The value of each cons cell provides four constraints for finding -identifiers. A word must match all four constraints to be -colored as an identifier. The cons cell has the form (MAJOR-MODE -IDENTIFIER-CONTEXT-RE IDENTIFIER-RE IDENTIFIER-FACES -IDENTIFIER-EXCLUSION-RE). - -MAJOR-MODE is the name of the mode in which this rule should be used. -IDENTIFIER-CONTEXT-RE is a regexp matching the text that must precede an -identifier. -IDENTIFIER-RE is a regexp whose first capture group matches identifiers. -IDENTIFIER-FACES is a list of faces with which the major mode decorates -identifiers or a function returning such a list. If the list includes nil, -unfontified words will be considered. -IDENTIFIER-EXCLUSION-RE is a regexp that must not match identifiers, -or nil. - -If a scan function is registered for a mode, candidate -identifiers will be further restricted to those returned by the -scan function.") - -(defvar color-identifiers:num-colors 10 - "The number of different colors to generate.") - -(defvar color-identifiers:color-luminance nil - "HSL luminance of identifier colors. If nil, calculated from the luminance -of the default face.") - -(defvar color-identifiers:min-color-saturation 0.0 - "The minimum saturation that identifier colors will be generated with.") - -(defvar color-identifiers:max-color-saturation 1.0 - "The maximum saturation that identifier colors will be generated with.") - -(defvar color-identifiers:mode-to-scan-fn-alist nil - "Alist from major modes to their declaration scan functions, for internal use. -If no scan function is registered for a particular mode, all -candidates matching the constraints in -`color-identifiers:modes-alist' will be colored. - -Modify this variable using -`color-identifiers:set-declaration-scan-fn'.") - -(defvar color-identifiers-mode-hook nil - "List of functions to run every time the mode enabled") - -(defvar color-identifiers:re-not-inside-class-access - (rx (or (not (any ".")) line-start) - (zero-or-more space)) - "This regexp matches anything except inside a class instance - access, like foo.bar" ) - -(defun color-identifiers:set-declaration-scan-fn (mode scan-fn) - "Register SCAN-FN as the declaration scanner for MODE. -SCAN-FN must scan the entire current buffer and return the -identifiers to highlight as a list of strings. Only identifiers -produced by SCAN-FN that also match all constraints in -`color-identifiers:modes-alist' will be colored. - -See `color-identifiers:elisp-get-declarations' for an example -SCAN-FN." - (let ((entry (assoc mode color-identifiers:mode-to-scan-fn-alist))) - (if entry - (setcdr entry scan-fn) - (add-to-list 'color-identifiers:mode-to-scan-fn-alist - (cons mode scan-fn))))) - -(defsubst color-identifiers:curr-identifier-faces () - (if (functionp (nth 3 color-identifiers:colorize-behavior)) - (funcall (nth 3 color-identifiers:colorize-behavior)) - (nth 3 color-identifiers:colorize-behavior))) - -;;; MAJOR MODE SUPPORT ========================================================= - -(defun color-identifiers:get-declarations () - "Extract a list of identifiers declared in the current buffer." - (let ((result (make-hash-table :test 'equal)) - (identifier-faces (color-identifiers:curr-identifier-faces))) - ;; Entities that major mode highlighted as variables - (save-excursion - (let ((next-change (next-property-change (point-min)))) - (while next-change - (goto-char next-change) - (let ((face-at-point (get-text-property (point) 'face))) - (when (or (and face-at-point (memq face-at-point identifier-faces)) - ;; If we fontified X in the past, keep X in the list for - ;; consistency. Otherwise `scan-identifiers' will stop - ;; colorizing new Xes while older ones remain colorized. - (get-text-property (point) 'color-identifiers:fontified)) - (puthash (substring-no-properties (symbol-name (symbol-at-point))) t result))) - (setq next-change (next-property-change (point)))))) - (hash-table-keys result))) - -(dolist (maj-mode '(c-mode c++-mode java-mode rust-mode rust-ts-mode rustic-mode meson-mode typescript-mode cuda-mode tsx-ts-mode typescript-ts-mode)) - (add-to-list - 'color-identifiers:modes-alist - `(,maj-mode . ("" - "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)" - (nil font-lock-variable-name-face tree-sitter-hl-face:variable))))) - -;; Scala -(add-to-list - 'color-identifiers:modes-alist - `(scala-mode . (,color-identifiers:re-not-inside-class-access - "\\_<\\([[:lower:]]\\([_]??[[:lower:][:upper:]\\$0-9]+\\)*\\(_+[#:<=>@!%&*+/?\\\\^|~-]+\\|_\\)?\\)" - (nil scala-font-lock:var-face font-lock-variable-name-face tree-sitter-hl-face:variable)))) - -;;; JavaScript -(add-to-list - 'color-identifiers:modes-alist - `(js-mode . (,color-identifiers:re-not-inside-class-access - "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)" - (nil font-lock-variable-name-face)))) - -(add-to-list - 'color-identifiers:modes-alist - `(js2-mode . (,color-identifiers:re-not-inside-class-access - "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)" - (nil font-lock-variable-name-face js2-function-param)))) - -(add-to-list - 'color-identifiers:modes-alist - `(js3-mode . (,color-identifiers:re-not-inside-class-access - "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)" - (nil font-lock-variable-name-face js3-function-param-face)))) - -(add-to-list - 'color-identifiers:modes-alist - `(js-jsx-mode . (,color-identifiers:re-not-inside-class-access - "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)" - (nil font-lock-variable-name-face js2-function-param)))) - -(add-to-list - 'color-identifiers:modes-alist - `(js2-jsx-mode . (,color-identifiers:re-not-inside-class-access - "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)" - (nil font-lock-variable-name-face js2-function-param)))) - -;; CoffeeScript -;; May need to add the @ to the symbol syntax -;; (add-hook 'coffee-mode-hook (lambda () (modify-syntax-entry ?\@ "_"))) in .emacs -(add-to-list - 'color-identifiers:modes-alist - `(coffee-mode . (,color-identifiers:re-not-inside-class-access "\\_<\\([a-zA-Z_$@]\\(?:\\s_\\|\\sw\\)*\\)" (nil font-lock-variable-name-face)))) - -;; Sgml mode and the like -(dolist (maj-mode '(sgml-mode html-mode jinja2-mode)) - (add-to-list - 'color-identifiers:modes-alist - `(,maj-mode . (" binding-form init-expr - ((or `(let . ,rest) - `(loop . ,rest)) - (append (when (sequencep (car rest)) - (let* ((bindings (append (car rest) nil)) - (even-indices - (-filter 'cl-evenp (number-sequence 0 (1- (length bindings))))) - (binding-forms (-select-by-indices even-indices bindings))) - (color-identifiers:clojure-extract-params binding-forms))) - (color-identifiers:clojure-declarations-in-sexp rest))) - ;; (fn name? [binding-form*] exprs*) - ;; (fn name? ([binding-form*] exprs*)+) - (`(fn . ,rest) - (let* ((binding-forms+exprs (if (symbolp (car rest)) (cdr rest) rest)) - (binding-forms (if (vectorp (car binding-forms+exprs)) - (elt binding-forms+exprs 0) - (mapcar 'car binding-forms+exprs))) - (params (color-identifiers:clojure-extract-params binding-forms))) - (append params (color-identifiers:clojure-declarations-in-sexp rest)))) - ;; (defn name doc-string? attr-map? [binding-form*] body) - ;; (defn name doc-string? attr-map? ([binding-form*] body)+) - ((or `(defn ,_ . ,rest) - `(defn- ,_ . ,rest) - `(defmacro ,_ . ,rest)) - (let ((params (-mapcat (lambda (params+body) - (when (color-identifiers:clojure-contains-binding-forms-p params+body) - (color-identifiers:clojure-extract-params params+body))) - rest))) - (append params (color-identifiers:clojure-declarations-in-sexp rest)))) - (`nil nil) - ((pred consp) - (let ((cons sexp) - (result nil)) - (while (consp cons) - (let ((ids (color-identifiers:clojure-declarations-in-sexp (car cons)))) - (when ids - (setq result (append ids result)))) - (setq cons (cdr cons))) - (when cons - ;; `cons' is non-nil but also non-cons - (let ((ids (color-identifiers:clojure-declarations-in-sexp cons))) - (when ids - (setq result (append ids result))))) - result)) - ((pred arrayp) - (apply 'append (mapcar 'color-identifiers:clojure-declarations-in-sexp sexp))))) - -(defun color-identifiers:clojure-get-declarations () - "Extract a list of identifiers declared in the current buffer. -For Clojure support within color-identifiers-mode. - -TODO: Fails on top-level sexps containing Clojure syntax that is -incompatible with Emacs Lisp syntax, such as reader macros (#)." - (let ((result nil)) - (save-excursion - (goto-char (point-min)) - (condition-case nil - (while t - (condition-case nil - (let* ((sexp (read (current-buffer))) - (ids (color-identifiers:clojure-declarations-in-sexp sexp)) - (strs (-filter (lambda (id) (if (member id '("&" ":as")) nil id)) - (mapcar (lambda (id) - (when (symbolp id) (symbol-name id))) - ids)))) - (setq result (append strs result))) - (invalid-read-syntax nil) - (wrong-type-argument nil))) - (end-of-file nil))) - (delete-dups result) - result)) - -(color-identifiers:set-declaration-scan-fn - 'clojure-mode 'color-identifiers:clojure-get-declarations) - -(add-to-list - 'color-identifiers:modes-alist - `(clojure-mode . ("" - "\\_<\\(\\(?:\\s_\\|\\sw\\)+\\)" - (nil)))) - -(add-to-list - 'color-identifiers:modes-alist - `(clojurescript-mode . ("" - "\\_<\\(\\(?:\\s_\\|\\sw\\)+\\)" - (nil)))) - -(dolist (maj-mode '(tuareg-mode sml-mode)) - (add-to-list - 'color-identifiers:modes-alist - `(,maj-mode . ("" - "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\|'\\)*\\)" - (nil font-lock-variable-name-face))))) - -;; R support in ess-mode -(defun color-identifiers:remove-string-or-comment (str) - "Remove string or comment in str, based on font lock faces" - (let ((remove (memq (get-text-property 0 'face str) - '(font-lock-string-face font-lock-comment-face))) - (pos 0) - (nextpos) - (result "")) - (while (setq nextpos (next-single-property-change pos 'face str)) - (unless remove - (setq result (concat result (substring-no-properties str pos nextpos)))) - (setq pos nextpos) - (setq remove (memq (get-text-property pos 'face str) - '(font-lock-string-face font-lock-comment-face)))) - (unless remove - (setq result (concat result (substring-no-properties str pos nextpos)))) - result)) - -(defun color-identifiers:r-get-args (lend) - "Extract a list of function arg names. LEND is the point at -the left parenthesis, after `function' keyword." - (let* ((rend (save-excursion - (goto-char lend) - (forward-sexp) - (point))) - (str (color-identifiers:remove-string-or-comment - (buffer-substring (1+ lend) (1- rend))))) - (mapcar (lambda (s) (replace-regexp-in-string "\\s *=.*" "" s)) - (split-string str "," t " ")))) - -(defun color-identifiers:r-get-declarations () - "Extract a list of identifiers declared in the current buffer. -For Emacs Lisp support within color-identifiers-mode." - (let ((result nil)) - (save-excursion - (goto-char (point-min)) - (while (re-search-forward "\\(\\(?:\\w\\|\\s_\\)*\\)\\s *< (cdr x) (cdr y))) min-dists))) - (funcall choose-candidate (car best)))) - (setq color-identifiers:colors - (vconcat (-map (lambda (lab) - (let* ((srgb (apply 'color-lab-to-srgb lab)) - (rgb (mapcar 'color-clamp srgb))) - (apply 'color-rgb-to-hex rgb))) - chosens)))))) - -(defvar-local color-identifiers:color-index-for-identifier nil - "Hashtable of identifier-index pairs for internal use. -The index refers to `color-identifiers:colors'. Only used when -`color-identifiers-coloring-method' is `sequential'.") - -(defvar-local color-identifiers:identifiers nil - "Set of identifiers in the current buffer. -Only used when `color-identifiers-coloring-method' is `hash' and -a declaration scan function is registered for the current major -mode. This variable memoizes the result of the declaration scan function.") - -;;;###autoload -(define-minor-mode color-identifiers-mode - "Color the identifiers in the current buffer based on their names." - :init-value nil - :lighter " ColorIds" - (if color-identifiers-mode - (progn - (setq color-identifiers:colorize-behavior - (assoc major-mode color-identifiers:modes-alist)) - (if (not color-identifiers:colorize-behavior) - (progn - (print "Major mode is not supported by color-identifiers, disabling") - (color-identifiers-mode -1)) - (unless color-identifiers:colors - ;; When GUI emacs is used and additionally terminal-based `emacsclient' - ;; gets launched, that may cause colors for identifiers change globally. - ;; This is not a good user experience. Ideally we should keep two - ;; separate vectors, for graphics and terminal versions of colors. But - ;; it's unclear how that should communicate with theme changes, so unless - ;; there's demand, let's for now just make sure we don't toggle colors - ;; back and forth everywhere. - (color-identifiers:regenerate-colors)) - (when (null color-identifiers:color-index-for-identifier) - (setq color-identifiers:color-index-for-identifier (make-hash-table :test 'equal))) - (color-identifiers:refresh) - (add-to-list 'font-lock-extra-managed-props 'color-identifiers:fontified) - (font-lock-add-keywords nil '((color-identifiers:colorize . default)) t) - (color-identifiers:enable-timer) - (advice-add 'enable-theme :after #'color-identifiers:regen-on-theme-change))) - (when color-identifiers:timer - (cancel-timer color-identifiers:timer)) - (font-lock-remove-keywords nil '((color-identifiers:colorize . default))) - (advice-remove 'enable-theme #'color-identifiers:regen-on-theme-change)) - (color-identifiers:refontify)) - -;;;###autoload -(define-global-minor-mode global-color-identifiers-mode - color-identifiers-mode color-identifiers-mode-maybe) - -(defun color-identifiers:attribute-luminance (attribute) - "Find the HSL luminance of the specified ATTRIBUTE on the default face." - (let ((rgb (color-name-to-rgb (face-attribute 'default attribute)))) - (if rgb - (nth 2 (apply 'color-rgb-to-hsl rgb)) - 0.5))) - -(defun color-identifiers:attribute-lab (attribute) - "Find the LAB color value of the specified ATTRIBUTE on the default face." - (let ((rgb (color-name-to-rgb (face-attribute 'default attribute)))) - (if rgb - (apply 'color-srgb-to-lab rgb) - '(0.0 0.0 0.0)))) - -(defun color-identifiers:foreground-lab (face) - "Find the LAB color value of the foreground attribute on the -specified face." - (let ((rgb (color-name-to-rgb (face-attribute face :foreground)))) - (if rgb - (apply 'color-srgb-to-lab rgb) - '(0.0 0.0 0.0)))) - -(defun color-identifiers:refresh () - "Refresh the set of identifiers in the current buffer. -If `color-identifiers-coloring-method' is `sequential', -identifiers and their corresponding color indexes are saved to -`color-identifiers:color-index-for-identifier'. - -If `color-identifiers-coloring-method' is `hash' and a -declaration scan function is registered for the current buffer's -major mode, identifiers are saved to -`color-identifiers:identifiers'." - (interactive) - (when color-identifiers-mode - (cond - ((eq color-identifiers-coloring-method 'sequential) - (let ((i 0) - ;; to make sure subsequently added vars aren't colorized the same add a (point) - (randomize-subseq-calls (point))) - (dolist (identifier (color-identifiers:list-identifiers)) - (unless (gethash identifier color-identifiers:color-index-for-identifier) - (puthash identifier - (% (+ randomize-subseq-calls i) color-identifiers:num-colors) - color-identifiers:color-index-for-identifier) - (setq i (1+ i)))))) - ((and (eq color-identifiers-coloring-method 'hash) - (color-identifiers:get-declaration-scan-fn major-mode)) - (setq color-identifiers:identifiers - (color-identifiers:list-identifiers)))) - (color-identifiers:refontify))) - -(defun color-identifiers:list-identifiers () - "Return all identifiers in the current buffer." - (if (color-identifiers:get-declaration-scan-fn major-mode) - (funcall (color-identifiers:get-declaration-scan-fn major-mode)) - ;; When no scan function is registered, fall back to - ;; `color-identifiers:get-declarations', which returns all identifiers - (color-identifiers:get-declarations))) - -(defalias 'color-identifiers:refontify - (if (fboundp 'font-lock-flush) - 'font-lock-flush - (lambda () - "Refontify the buffer using font-lock." - (with-no-warnings - (and font-lock-mode (font-lock-fontify-buffer)))))) - -(defun color-identifiers:color-identifier (identifier) - "Return the hex color for IDENTIFIER, or nil if it should not -be colored." - (cond - ((eq color-identifiers-coloring-method 'sequential) - (let ((index (gethash identifier color-identifiers:color-index-for-identifier))) - (when index - (aref color-identifiers:colors index)))) - ((eq color-identifiers-coloring-method 'hash) - ;; If there is a declaration scan function for this major mode, the - ;; candidate identifier should only be colored if it is in the memoized list - ;; of identifiers. Otherwise, it should be colored unconditionally. - (when (or (not (color-identifiers:get-declaration-scan-fn major-mode)) - (member identifier color-identifiers:identifiers)) - (color-identifiers:hash-identifier identifier))))) - -(defun color-identifiers:hash-identifier (identifier) - "Return a color for IDENTIFIER based on its hash." - (aref color-identifiers:colors - (% (abs (sxhash identifier)) color-identifiers:num-colors))) - -(defun color-identifiers:scan-identifiers (fn limit) - "Run FN on all candidate identifiers from point up to LIMIT. -Candidate identifiers are defined by -`color-identifiers:modes-alist'. Declaration scan functions are -not applied. If supplied, iteration only continues if CONTINUE-P -evaluates to true." - (let ((identifier-context-re (nth 1 color-identifiers:colorize-behavior)) - (identifier-re (nth 2 color-identifiers:colorize-behavior)) - (identifier-faces (color-identifiers:curr-identifier-faces)) - (identifier-exclusion-re (nth 4 color-identifiers:colorize-behavior))) - ;; Skip forward to the next identifier that matches all four conditions - (condition-case nil - (while (< (point) limit) - (if (or (memq (get-text-property (point) 'face) identifier-faces) - (let ((flface-prop (get-text-property (point) 'font-lock-face))) - (and flface-prop (memq flface-prop identifier-faces)))) - (if (and (looking-back identifier-context-re (line-beginning-position)) - (or (not identifier-exclusion-re) (not (looking-at-p identifier-exclusion-re))) - (looking-at identifier-re)) - (progn - ;; Found an identifier. Run `fn' on it - (funcall fn (match-beginning 1) (match-end 1)) - (goto-char (match-end 1))) - (forward-char) - (re-search-forward identifier-re limit) - (goto-char (match-beginning 0))) - (goto-char (next-property-change (point) nil limit)))) - (search-failed nil)))) - -(defun color-identifiers:colorize (limit) - (color-identifiers:scan-identifiers - (lambda (start end) - (let* ((identifier (buffer-substring-no-properties start end)) - (hex (color-identifiers:color-identifier identifier))) - (when hex - (let ((face-spec (append `(:foreground ,hex) color-identifiers:extra-face-attributes))) - (put-text-property start end 'face face-spec) - (put-text-property start end 'color-identifiers:fontified t))))) - limit)) - -(defun color-identifiers-mode-maybe () - "Potentially enable `color-identifiers-mode' in the current buffer. - -Specifically, when `major-mode' is listed in -`color-identifiers:modes-alist', and the buffer isn't temporary." - ;; Avoid running in temp buffers created by `with-temp-buffer'. Most notably, - ;; package installation process is known to create one and then enable - ;; `emacs-lisp-mode' for the purpose of parsing autoloads, which in turn triggers - ;; color-identifers-mode for no reason. During a huge upgrade this may add up, - ;; especially given our ad hoc ELisp parsing code isn't the fastest. - (when (and (not (string-prefix-p " *temp" (buffer-name))) - (assoc major-mode color-identifiers:modes-alist)) - (color-identifiers-mode 1))) - -(provide 'color-identifiers-mode) - -;;; color-identifiers-mode.el ends here diff --git a/elpa/color-identifiers-mode-20251205.2247/color-identifiers-mode-autoloads.el b/elpa/color-identifiers-mode-20251205.2247/color-identifiers-mode-autoloads.el new file mode 100644 index 00000000..61d614e1 --- /dev/null +++ b/elpa/color-identifiers-mode-20251205.2247/color-identifiers-mode-autoloads.el @@ -0,0 +1,71 @@ +;;; color-identifiers-mode-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- +;; Generated by the `loaddefs-generate' function. + +;; This file is part of GNU Emacs. + +;;; Code: + +(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) + + + +;;; Generated autoloads from color-identifiers-mode.el + +(autoload 'color-identifiers-mode "color-identifiers-mode" "\ +Color the identifiers in the current buffer based on their names. + +This is a minor mode. If called interactively, toggle the +`Color-Identifiers mode' mode. If the prefix argument is positive, +enable the mode, and if it is zero or negative, disable the mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable the +mode if ARG is nil, omitted, or is a positive number. Disable the mode +if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate the variable `color-identifiers-mode'. + +The mode's hook is called both when the mode is enabled and when it is +disabled. + +(fn &optional ARG)" t) +(put 'global-color-identifiers-mode 'globalized-minor-mode t) +(defvar global-color-identifiers-mode nil "\ +Non-nil if Global Color-Identifiers mode is enabled. +See the `global-color-identifiers-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `global-color-identifiers-mode'.") +(custom-autoload 'global-color-identifiers-mode "color-identifiers-mode" nil) +(autoload 'global-color-identifiers-mode "color-identifiers-mode" "\ +Toggle Color-Identifiers mode in many buffers. +Specifically, Color-Identifiers mode is enabled in all buffers where +`color-identifiers-mode-maybe' would do it. + +With prefix ARG, enable Global Color-Identifiers mode if ARG is +positive; otherwise, disable it. + +If called from Lisp, toggle the mode if ARG is `toggle'. +Enable the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +See `color-identifiers-mode' for more information on Color-Identifiers +mode. + +(fn &optional ARG)" t) +(register-definition-prefixes "color-identifiers-mode" '("color-identifiers")) + +;;; End of scraped data + +(provide 'color-identifiers-mode-autoloads) + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; no-native-compile: t +;; coding: utf-8-emacs-unix +;; End: + +;;; color-identifiers-mode-autoloads.el ends here diff --git a/elpa/color-identifiers-mode-20251205.2247/color-identifiers-mode-pkg.el b/elpa/color-identifiers-mode-20251205.2247/color-identifiers-mode-pkg.el new file mode 100644 index 00000000..6de9b2ef --- /dev/null +++ b/elpa/color-identifiers-mode-20251205.2247/color-identifiers-mode-pkg.el @@ -0,0 +1,11 @@ +;; -*- no-byte-compile: t; lexical-binding: nil -*- +(define-package "color-identifiers-mode" "20251205.2247" + "Color identifiers based on their names." + '((dash "2.5.0") + (emacs "24.4")) + :url "https://github.com/ankurdave/color-identifiers-mode" + :commit "a868ccaeb2be5109391f8cb66004c9f457f0506f" + :revdesc "a868ccaeb2be" + :keywords '("faces" "languages") + :authors '(("Ankur Dave" . "ankurdave@gmail.com")) + :maintainers '(("Ankur Dave" . "ankurdave@gmail.com"))) diff --git a/elpa/color-identifiers-mode-20251205.2247/color-identifiers-mode.el b/elpa/color-identifiers-mode-20251205.2247/color-identifiers-mode.el new file mode 100644 index 00000000..030fa1fe --- /dev/null +++ b/elpa/color-identifiers-mode-20251205.2247/color-identifiers-mode.el @@ -0,0 +1,840 @@ +;;; color-identifiers-mode.el --- Color identifiers based on their names -*- lexical-binding: t -*- + +;; Copyright (C) 2014 Ankur Dave + +;; Author: Ankur Dave +;; Url: https://github.com/ankurdave/color-identifiers-mode +;; Created: 24 Jan 2014 +;; Package-Version: 20251205.2247 +;; Package-Revision: a868ccaeb2be +;; Keywords: faces, languages +;; Package-Requires: ((dash "2.5.0") (emacs "24.4")) + +;; This file is not a part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Color Identifiers is a minor mode for Emacs that highlights each source code +;; identifier uniquely based on its name. It is inspired by a post by Evan +;; Brooks: https://medium.com/p/3a6db2743a1e/ + +;; Check out the project page, which has screenshots, a demo, and usage +;; instructions: https://github.com/ankurdave/color-identifiers-mode + +;;; Code: + +(require 'nadvice) +(require 'color) +(require 'dash) +(require 'cl-lib) +(require 'rx) +(require 'subr-x) + +(defgroup color-identifiers nil "Color identifiers based on their names." + :group 'faces) + +(defvar color-identifiers:timer nil + "Timer for running `color-identifiers:refresh'.") + +(defvar color-identifiers:recoloring-delay 2 + "The delay before running `color-identifiers:refresh'.") + +(defun color-identifiers:enable-timer () + (if color-identifiers:timer + ;; Someone set the timer. Activate in case we cancelled it. + (unless (memq color-identifiers:timer timer-idle-list) + (timer-activate-when-idle color-identifiers:timer)) + (setq color-identifiers:timer + (run-with-idle-timer color-identifiers:recoloring-delay t 'color-identifiers:refresh))) + ) + +(defvar-local color-identifiers:colorize-behavior nil + "For internal use. Stores the element of +`color-identifiers:modes-alist' that is relevant to the current +major mode") + +(defun color-identifiers:regen-on-theme-change(_) + "Regenerate colors for color-identifiers-mode on theme change." + (color-identifiers:regenerate-colors)) + +;;; USER-VISIBLE VARIABLES AND FUNCTIONS ======================================= + +(defcustom color-identifiers-coloring-method 'sequential + "How to assign colors: sequentially or using the hash of the identifier. +Sequential color assignment (the default) reduces collisions +between adjacent identifiers. Hash-based color assignment ensures +that a particular identifier is always assigned the same color +across buffers." + :type '(choice + (const :tag "Sequential" sequential) + (const :tag "Hash-based" hash))) + + +(defcustom color-identifiers-avoid-faces nil + "Which color faces to avoid: A list of faces whose foreground +color should be avoided when generating colors, this can be warning colors, +error colors etc." + :type '(repeat face)) + +(defcustom color-identifiers:extra-face-attributes nil + "Extra face attributes to apply to identifiers. Can be used to make +identifiers bold or italic, but avoid changing `:foreground' +because it is the color determined by the mode." + :type 'plist + :group 'color-identifiers) + +(defvar color-identifiers:modes-alist nil + "Alist of major modes and the ways to distinguish identifiers in those modes. +The value of each cons cell provides four constraints for finding +identifiers. A word must match all four constraints to be +colored as an identifier. The cons cell has the form (MAJOR-MODE +IDENTIFIER-CONTEXT-RE IDENTIFIER-RE IDENTIFIER-FACES +IDENTIFIER-EXCLUSION-RE). + +MAJOR-MODE is the name of the mode in which this rule should be used. +IDENTIFIER-CONTEXT-RE is a regexp matching the text that must precede an +identifier. +IDENTIFIER-RE is a regexp whose first capture group matches identifiers. +IDENTIFIER-FACES is a list of faces with which the major mode decorates +identifiers or a function returning such a list. If the list includes nil, +unfontified words will be considered. +IDENTIFIER-EXCLUSION-RE is a regexp that must not match identifiers, +or nil. + +If a scan function is registered for a mode, candidate +identifiers will be further restricted to those returned by the +scan function.") + +(defvar color-identifiers:num-colors 10 + "The number of different colors to generate.") + +(defvar color-identifiers:color-luminance nil + "HSL luminance of identifier colors. If nil, calculated from the luminance +of the default face.") + +(defvar color-identifiers:min-color-saturation 0.0 + "The minimum saturation that identifier colors will be generated with.") + +(defvar color-identifiers:max-color-saturation 1.0 + "The maximum saturation that identifier colors will be generated with.") + +(defvar color-identifiers:mode-to-scan-fn-alist nil + "Alist from major modes to their declaration scan functions, for internal use. +If no scan function is registered for a particular mode, all +candidates matching the constraints in +`color-identifiers:modes-alist' will be colored. + +Modify this variable using +`color-identifiers:set-declaration-scan-fn'.") + +(defvar color-identifiers-mode-hook nil + "List of functions to run every time the mode enabled") + +(defvar color-identifiers:re-not-inside-class-access + (rx (or (not (any ".")) line-start) + (zero-or-more space)) + "This regexp matches anything except inside a class instance + access, like foo.bar" ) + +(defun color-identifiers:set-declaration-scan-fn (mode scan-fn) + "Register SCAN-FN as the declaration scanner for MODE. +SCAN-FN must scan the entire current buffer and return the +identifiers to highlight as a list of strings. Only identifiers +produced by SCAN-FN that also match all constraints in +`color-identifiers:modes-alist' will be colored. + +See `color-identifiers:elisp-get-declarations' for an example +SCAN-FN." + (let ((entry (assoc mode color-identifiers:mode-to-scan-fn-alist))) + (if entry + (setcdr entry scan-fn) + (add-to-list 'color-identifiers:mode-to-scan-fn-alist + (cons mode scan-fn))))) + +(defsubst color-identifiers:curr-identifier-faces () + (if (functionp (nth 3 color-identifiers:colorize-behavior)) + (funcall (nth 3 color-identifiers:colorize-behavior)) + (nth 3 color-identifiers:colorize-behavior))) + +;;; MAJOR MODE SUPPORT ========================================================= + +(defun color-identifiers:get-declarations () + "Extract a list of identifiers declared in the current buffer." + (let ((result (make-hash-table :test 'equal)) + (identifier-faces (color-identifiers:curr-identifier-faces))) + ;; Entities that major mode highlighted as variables + (save-excursion + (let ((next-change (next-property-change (point-min)))) + (while next-change + (goto-char next-change) + (let ((face-at-point (get-text-property (point) 'face))) + (when (or (and face-at-point (memq face-at-point identifier-faces)) + ;; If we fontified X in the past, keep X in the list for + ;; consistency. Otherwise `scan-identifiers' will stop + ;; colorizing new Xes while older ones remain colorized. + (get-text-property (point) 'color-identifiers:fontified)) + (puthash (substring-no-properties (symbol-name (symbol-at-point))) t result))) + (setq next-change (next-property-change (point)))))) + (hash-table-keys result))) + +(dolist (maj-mode '(c-mode c++-mode java-mode rust-mode rust-ts-mode rustic-mode meson-mode typescript-mode cuda-mode tsx-ts-mode typescript-ts-mode python-ts-mode)) + (add-to-list + 'color-identifiers:modes-alist + `(,maj-mode . ("" + "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)" + (nil font-lock-variable-name-face tree-sitter-hl-face:variable))))) + +;; Scala +(add-to-list + 'color-identifiers:modes-alist + `(scala-mode . (,color-identifiers:re-not-inside-class-access + "\\_<\\([[:lower:]]\\([_]??[[:lower:][:upper:]\\$0-9]+\\)*\\(_+[#:<=>@!%&*+/?\\\\^|~-]+\\|_\\)?\\)" + (nil scala-font-lock:var-face font-lock-variable-name-face tree-sitter-hl-face:variable)))) + +;;; JavaScript +(add-to-list + 'color-identifiers:modes-alist + `(js-mode . (,color-identifiers:re-not-inside-class-access + "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)" + (nil font-lock-variable-name-face)))) + +(add-to-list + 'color-identifiers:modes-alist + `(js2-mode . (,color-identifiers:re-not-inside-class-access + "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)" + (nil font-lock-variable-name-face js2-function-param)))) + +(add-to-list + 'color-identifiers:modes-alist + `(js3-mode . (,color-identifiers:re-not-inside-class-access + "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)" + (nil font-lock-variable-name-face js3-function-param-face)))) + +(add-to-list + 'color-identifiers:modes-alist + `(js-jsx-mode . (,color-identifiers:re-not-inside-class-access + "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)" + (nil font-lock-variable-name-face js2-function-param)))) + +(add-to-list + 'color-identifiers:modes-alist + `(js2-jsx-mode . (,color-identifiers:re-not-inside-class-access + "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)" + (nil font-lock-variable-name-face js2-function-param)))) + +;; CoffeeScript +;; May need to add the @ to the symbol syntax +;; (add-hook 'coffee-mode-hook (lambda () (modify-syntax-entry ?\@ "_"))) in .emacs +(add-to-list + 'color-identifiers:modes-alist + `(coffee-mode . (,color-identifiers:re-not-inside-class-access "\\_<\\([a-zA-Z_$@]\\(?:\\s_\\|\\sw\\)*\\)" (nil font-lock-variable-name-face)))) + +;; Sgml mode and the like +(dolist (maj-mode '(sgml-mode html-mode jinja2-mode)) + (add-to-list + 'color-identifiers:modes-alist + `(,maj-mode . (" binding-form init-expr + ((or `(let . ,rest) + `(loop . ,rest)) + (append (when (sequencep (car rest)) + (let* ((bindings (append (car rest) nil)) + (even-indices + (-filter 'cl-evenp (number-sequence 0 (1- (length bindings))))) + (binding-forms (-select-by-indices even-indices bindings))) + (color-identifiers:clojure-extract-params binding-forms))) + (color-identifiers:clojure-declarations-in-sexp rest))) + ;; (fn name? [binding-form*] exprs*) + ;; (fn name? ([binding-form*] exprs*)+) + (`(fn . ,rest) + (let* ((binding-forms+exprs (if (symbolp (car rest)) (cdr rest) rest)) + (binding-forms (if (vectorp (car binding-forms+exprs)) + (elt binding-forms+exprs 0) + (mapcar 'car binding-forms+exprs))) + (params (color-identifiers:clojure-extract-params binding-forms))) + (append params (color-identifiers:clojure-declarations-in-sexp rest)))) + ;; (defn name doc-string? attr-map? [binding-form*] body) + ;; (defn name doc-string? attr-map? ([binding-form*] body)+) + ((or `(defn ,_ . ,rest) + `(defn- ,_ . ,rest) + `(defmacro ,_ . ,rest)) + (let ((params (-mapcat (lambda (params+body) + (when (color-identifiers:clojure-contains-binding-forms-p params+body) + (color-identifiers:clojure-extract-params params+body))) + rest))) + (append params (color-identifiers:clojure-declarations-in-sexp rest)))) + (`nil nil) + ((pred consp) + (let ((cons sexp) + (result nil)) + (while (consp cons) + (let ((ids (color-identifiers:clojure-declarations-in-sexp (car cons)))) + (when ids + (setq result (append ids result)))) + (setq cons (cdr cons))) + (when cons + ;; `cons' is non-nil but also non-cons + (let ((ids (color-identifiers:clojure-declarations-in-sexp cons))) + (when ids + (setq result (append ids result))))) + result)) + ((pred arrayp) + (apply 'append (mapcar 'color-identifiers:clojure-declarations-in-sexp sexp))))) + +(defun color-identifiers:clojure-get-declarations () + "Extract a list of identifiers declared in the current buffer. +For Clojure support within color-identifiers-mode. + +TODO: Fails on top-level sexps containing Clojure syntax that is +incompatible with Emacs Lisp syntax, such as reader macros (#)." + (let ((result nil)) + (save-excursion + (goto-char (point-min)) + (condition-case nil + (while t + (condition-case nil + (let* ((sexp (read (current-buffer))) + (ids (color-identifiers:clojure-declarations-in-sexp sexp)) + (strs (-filter (lambda (id) (if (member id '("&" ":as")) nil id)) + (mapcar (lambda (id) + (when (symbolp id) (symbol-name id))) + ids)))) + (setq result (append strs result))) + (invalid-read-syntax nil) + (wrong-type-argument nil))) + (end-of-file nil))) + (delete-dups result) + result)) + +(dolist (mode '(clojure-mode + clojure-ts-mode + clojurescript-mode)) + (color-identifiers:set-declaration-scan-fn + mode 'color-identifiers:clojure-get-declarations) + (add-to-list + 'color-identifiers:modes-alist + `(,mode . ("" + "\\_<\\(\\(?:\\s_\\|\\sw\\)+\\)" + (nil))))) + +(dolist (maj-mode '(tuareg-mode sml-mode)) + (add-to-list + 'color-identifiers:modes-alist + `(,maj-mode . ("" + "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\|'\\)*\\)" + (nil font-lock-variable-name-face))))) + +;; R support in ess-mode +(defun color-identifiers:remove-string-or-comment (str) + "Remove string or comment in str, based on font lock faces" + (let ((remove (memq (get-text-property 0 'face str) + '(font-lock-string-face font-lock-comment-face))) + (pos 0) + (nextpos) + (result "")) + (while (setq nextpos (next-single-property-change pos 'face str)) + (unless remove + (setq result (concat result (substring-no-properties str pos nextpos)))) + (setq pos nextpos) + (setq remove (memq (get-text-property pos 'face str) + '(font-lock-string-face font-lock-comment-face)))) + (unless remove + (setq result (concat result (substring-no-properties str pos nextpos)))) + result)) + +(defun color-identifiers:r-get-args (lend) + "Extract a list of function arg names. LEND is the point at +the left parenthesis, after `function' keyword." + (let* ((rend (save-excursion + (goto-char lend) + (forward-sexp) + (point))) + (str (color-identifiers:remove-string-or-comment + (buffer-substring (1+ lend) (1- rend))))) + (mapcar (lambda (s) (replace-regexp-in-string "\\s *=.*" "" s)) + (split-string str "," t " ")))) + +(defun color-identifiers:r-get-declarations () + "Extract a list of identifiers declared in the current buffer. +For Emacs Lisp support within color-identifiers-mode." + (let ((result nil)) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward "\\(\\(?:\\w\\|\\s_\\)*\\)\\s *< (cdr x) (cdr y))) min-dists))) + (funcall choose-candidate (car best)))) + (setq color-identifiers:colors + (vconcat (-map (lambda (lab) + (let* ((srgb (apply 'color-lab-to-srgb lab)) + (rgb (mapcar 'color-clamp srgb))) + (apply 'color-rgb-to-hex rgb))) + chosens)))))) + +(defvar-local color-identifiers:color-index-for-identifier nil + "Hashtable of identifier-index pairs for internal use. +The index refers to `color-identifiers:colors'. Only used when +`color-identifiers-coloring-method' is `sequential'.") + +(defvar-local color-identifiers:identifiers nil + "Set of identifiers in the current buffer. +Only used when `color-identifiers-coloring-method' is `hash' and +a declaration scan function is registered for the current major +mode. This variable memoizes the result of the declaration scan function.") + +;;;###autoload +(define-minor-mode color-identifiers-mode + "Color the identifiers in the current buffer based on their names." + :init-value nil + :lighter " ColorIds" + (if color-identifiers-mode + (progn + (setq color-identifiers:colorize-behavior + (assoc major-mode color-identifiers:modes-alist)) + (if (not color-identifiers:colorize-behavior) + (progn + (print "Major mode is not supported by color-identifiers, disabling") + (color-identifiers-mode -1)) + (unless color-identifiers:colors + ;; When GUI emacs is used and additionally terminal-based `emacsclient' + ;; gets launched, that may cause colors for identifiers change globally. + ;; This is not a good user experience. Ideally we should keep two + ;; separate vectors, for graphics and terminal versions of colors. But + ;; it's unclear how that should communicate with theme changes, so unless + ;; there's demand, let's for now just make sure we don't toggle colors + ;; back and forth everywhere. + (color-identifiers:regenerate-colors)) + (when (null color-identifiers:color-index-for-identifier) + (setq color-identifiers:color-index-for-identifier (make-hash-table :test 'equal))) + (color-identifiers:refresh) + (add-to-list 'font-lock-extra-managed-props 'color-identifiers:fontified) + (font-lock-add-keywords nil '((color-identifiers:colorize . default)) t) + (color-identifiers:enable-timer) + (advice-add 'enable-theme :after #'color-identifiers:regen-on-theme-change))) + (when color-identifiers:timer + (cancel-timer color-identifiers:timer)) + (font-lock-remove-keywords nil '((color-identifiers:colorize . default))) + (advice-remove 'enable-theme #'color-identifiers:regen-on-theme-change)) + (color-identifiers:refontify)) + +;;;###autoload +(define-globalized-minor-mode global-color-identifiers-mode + color-identifiers-mode color-identifiers-mode-maybe) + +(defun color-identifiers:attribute-luminance (attribute) + "Find the HSL luminance of the specified ATTRIBUTE on the default face." + (let ((rgb (color-name-to-rgb (face-attribute 'default attribute)))) + (if rgb + (nth 2 (apply 'color-rgb-to-hsl rgb)) + 0.5))) + +(defun color-identifiers:attribute-lab (attribute) + "Find the LAB color value of the specified ATTRIBUTE on the default face." + (let ((rgb (color-name-to-rgb (face-attribute 'default attribute)))) + (if rgb + (apply 'color-srgb-to-lab rgb) + '(0.0 0.0 0.0)))) + +(defun color-identifiers:foreground-lab (face) + "Find the LAB color value of the foreground attribute on the +specified face." + (let ((rgb (color-name-to-rgb (face-attribute face :foreground)))) + (if rgb + (apply 'color-srgb-to-lab rgb) + '(0.0 0.0 0.0)))) + +(defun color-identifiers:refresh () + "Refresh the set of identifiers in the current buffer. +If `color-identifiers-coloring-method' is `sequential', +identifiers and their corresponding color indexes are saved to +`color-identifiers:color-index-for-identifier'. + +If `color-identifiers-coloring-method' is `hash' and a +declaration scan function is registered for the current buffer's +major mode, identifiers are saved to +`color-identifiers:identifiers'." + (interactive) + (when color-identifiers-mode + (cond + ((eq color-identifiers-coloring-method 'sequential) + (let ((i 0) + ;; to make sure subsequently added vars aren't colorized the same add a (point) + (randomize-subseq-calls (point))) + (dolist (identifier (color-identifiers:list-identifiers)) + (unless (gethash identifier color-identifiers:color-index-for-identifier) + (puthash identifier + (% (+ randomize-subseq-calls i) color-identifiers:num-colors) + color-identifiers:color-index-for-identifier) + (setq i (1+ i)))))) + ((and (eq color-identifiers-coloring-method 'hash) + (color-identifiers:get-declaration-scan-fn major-mode)) + (setq color-identifiers:identifiers + (color-identifiers:list-identifiers)))) + (color-identifiers:refontify))) + +(defun color-identifiers:list-identifiers () + "Return all identifiers in the current buffer." + (if (color-identifiers:get-declaration-scan-fn major-mode) + (funcall (color-identifiers:get-declaration-scan-fn major-mode)) + ;; When no scan function is registered, fall back to + ;; `color-identifiers:get-declarations', which returns all identifiers + (color-identifiers:get-declarations))) + +(defalias 'color-identifiers:refontify + (if (fboundp 'font-lock-flush) + 'font-lock-flush + (lambda () + "Refontify the buffer using font-lock." + (with-no-warnings + (and font-lock-mode (font-lock-fontify-buffer)))))) + +(defun color-identifiers:color-identifier (identifier) + "Return the hex color for IDENTIFIER, or nil if it should not +be colored." + (cond + ((eq color-identifiers-coloring-method 'sequential) + (let ((index (gethash identifier color-identifiers:color-index-for-identifier))) + (when index + (aref color-identifiers:colors index)))) + ((eq color-identifiers-coloring-method 'hash) + ;; If there is a declaration scan function for this major mode, the + ;; candidate identifier should only be colored if it is in the memoized list + ;; of identifiers. Otherwise, it should be colored unconditionally. + (when (or (not (color-identifiers:get-declaration-scan-fn major-mode)) + (member identifier color-identifiers:identifiers)) + (color-identifiers:hash-identifier identifier))))) + +(defun color-identifiers:hash-identifier (identifier) + "Return a color for IDENTIFIER based on its hash." + (aref color-identifiers:colors + (% (abs (sxhash identifier)) color-identifiers:num-colors))) + +(defun color-identifiers:scan-identifiers (fn limit) + "Run FN on all candidate identifiers from point up to LIMIT. + +Basically, this is the function that highlights all identifiers, with +highlight being done by applying FN. + +Candidate identifiers are defined by `color-identifiers:modes-alist'." + (let ((identifier-context-re (nth 1 color-identifiers:colorize-behavior)) + (identifier-re (nth 2 color-identifiers:colorize-behavior)) + (identifier-faces (color-identifiers:curr-identifier-faces)) + (identifier-exclusion-re (nth 4 color-identifiers:colorize-behavior))) + ;; Skip forward to the next identifier that matches all four conditions + (condition-case nil + (while (< (point) limit) + (if (or (let ((curr-face (get-text-property (point) 'face))) + (or + ;; Note: if `curr-face' is nil, the memq will usually + ;; succeed because nil is typically part of the list. + (memq curr-face identifier-faces) + ;; `font-lock-variable-use-face' isn't included in + ;; `identifier-faces' due to the latter being also used for + ;; initial scanning, so `font-lock-variable-use-face' being + ;; there would be an overhead with no benefit. + (eq curr-face 'font-lock-variable-use-face))) + (let ((flface-prop (get-text-property (point) 'font-lock-face))) + (and flface-prop (memq flface-prop identifier-faces)))) + (if (and (looking-back identifier-context-re (line-beginning-position)) + (or (not identifier-exclusion-re) (not (looking-at-p identifier-exclusion-re))) + (looking-at identifier-re)) + (progn + ;; Found an identifier. Run `fn' on it + (funcall fn (match-beginning 1) (match-end 1)) + (goto-char (match-end 1))) + (forward-char) + (re-search-forward identifier-re limit) + (goto-char (match-beginning 0))) + (goto-char (next-property-change (point) nil limit)))) + (search-failed nil)))) + +(defun color-identifiers:colorize (limit) + (color-identifiers:scan-identifiers + (lambda (start end) + (let* ((identifier (buffer-substring-no-properties start end)) + (hex (color-identifiers:color-identifier identifier))) + (when hex + (let ((face-spec (append `(:foreground ,hex) color-identifiers:extra-face-attributes))) + (add-text-properties start end `(face ,face-spec color-identifiers:fontified t)))))) + limit)) + +(defun color-identifiers-mode-maybe () + "Potentially enable `color-identifiers-mode' in the current buffer. + +Specifically, when `major-mode' is listed in +`color-identifiers:modes-alist', and the buffer isn't temporary." + ;; Avoid running in temp buffers created by `with-temp-buffer'. Most notably, + ;; package installation process is known to create one and then enable + ;; `emacs-lisp-mode' for the purpose of parsing autoloads, which in turn triggers + ;; color-identifers-mode for no reason. During a huge upgrade this may add up, + ;; especially given our ad hoc ELisp parsing code isn't the fastest. + (when (and (not (string-prefix-p " *temp" (buffer-name))) + (assoc major-mode color-identifiers:modes-alist)) + (color-identifiers-mode 1))) + +(provide 'color-identifiers-mode) + +;;; color-identifiers-mode.el ends here