"HTTP/1.1 200 OK\nConnection: close\nContent-Length: 74296\nContent-Type: text/plain; charset=utf-8\nCache-Control: max-age=300\nContent-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; sandbox\nETag: W/\"82a2500572f4302d2a3cdb715970a5f43e00386ba86d23f3f296916611120e4f\"\nStrict-Transport-Security: max-age=31536000\nX-Content-Type-Options: nosniff\nX-Frame-Options: deny\nX-XSS-Protection: 1; mode=block\nVia: 1.1 varnish (Varnish/6.0), 1.1 varnish\nX-GitHub-Request-Id: B1F4:2764:E742CB:F49946:5FEEBFB4\nAccept-Ranges: bytes\nDate: Fri, 01 Jan 2021 06:25:09 GMT\nX-Served-By: cache-sin18050-SIN\nX-Cache: MISS, HIT\nX-Cache-Hits: 0, 1\nX-Timer: S1609482309.487910,VS0,VE1\nVary: Authorization,Accept-Encoding, Accept-Encoding\nAccess-Control-Allow-Origin: *\nX-Fastly-Request-ID: 75ffa31cee8b640efa3b52d992e630cab8847800\nExpires: Fri, 01 Jan 2021 06:30:09 GMT\nSource-Age: 144\n\n;;; straight.el --- Next-generation package manager -*- lexical-binding: t -*-\n\n;; Copyright (C) 2017-2019 Radon Rosborough and contributors\n\n;; Author: Radon Rosborough \n;; Created: 1 Jan 2017\n;; Homepage: https://github.com/raxod502/straight.el\n;; Keywords: extensions\n;; Package-Requires: ((emacs \"24.5\"))\n;; Version: prerelease\n\n;;; Commentary:\n\n;; straight.el is a next-generation package manager for Emacs. It\n;; clones packages into your ~/.emacs.d and handles byte-compilation,\n;; autoload generation, and load path management. Dependency\n;; management, powerful tools for managing your packages in bulk, and\n;; out-of-the-box compatibility with MELPA, GNU ELPA, and Emacsmirror\n;; are also included.\n\n;; straight.el improves on other package managers in several ways.\n;; Most importantly, it offers first-class support for easily\n;; modifying packages and contributing your changes upstream. It also\n;; supports complete reproducibility for your configuration by writing\n;; a lockfile with the versions of all your packages. Alternatively,\n;; straight.el will work with manually managed packages, if you prefer\n;; to merge in packages as subtrees.\n\n;; Please see https://github.com/raxod502/straight.el for more\n;; information.\n\n;;; Code:\n\n;; To see the outline of this file, run M-x outline-minor-mode and\n;; then press C-c @ C-t. To also show the top-level functions and\n;; variable declarations in each section, run M-x occur with the\n;; following query: ^;;;;* \\|^(\n\n;;;; Detect change in Emacs version\n\n;; This throws an error if you byte-compile it with one Emacs version\n;; and then try to run the byte-compiled code in another Emacs\n;; version. See bootstrap.el.\n(eval\n `(unless (equal\n (emacs-version)\n ,(eval-when-compile (emacs-version)))\n (throw 'emacs-version-changed nil)))\n\n;;;; Libraries\n\n(require 'cl-lib)\n(require 'subr-x)\n\n;;;; Backports\n\n;; Note that we use `eval-and-compile' even for macros, because\n;; otherwise libraries which load the byte-compiled version of this\n;; file won't be able to use those macros.\n\n;; Not defined before Emacs 25.1\n(eval-and-compile\n (unless (fboundp 'if-let)\n (defmacro if-let (varlist then &optional else)\n \"Bind variables according to VARLIST and eval THEN or ELSE.\nVARLIST must be of the form ((SYMBOL VALUEFORM)). Evaluate\nVALUEFORM and bind it to SYMBOL. If the result of evaluation is\nnon-nil, evaluate and return THEN. Otherwise, evaluate and return\nELSE (or nil).\"\n (let ((symbol (nth 0 (car varlist)))\n (valueform (nth 1 (car varlist))))\n `(let ((,symbol ,valueform))\n (if ,symbol\n ,then\n ,else))))))\n\n;; Not defined before Emacs 25.1\n(eval-and-compile\n (unless (fboundp 'when-let)\n (defmacro when-let (varlist &rest body)\n \"Bind variables according to VARLIST and conditionally eval BODY.\nVARLIST must be of the form ((SYMBOL VALUEFORM)). Evaluate\nVALUEFORM and bind it to SYMBOL. If the result of evaluation is\nnon-nil, evaluate and return BODY. Otherwise return nil.\"\n `(if-let ,varlist\n (progn ,@body)))))\n\n;; Not defined before Emacs 25.1\n(eval-and-compile\n (unless (fboundp 'alist-get)\n (defun alist-get (key alist)\n \"Return the value associated with KEY in ALIST, using `assq'.\"\n (cdr (assq key alist)))))\n\n;; Not defined before Emacs 25.1\n(eval-and-compile\n (unless (fboundp 'hash-table-empty-p)\n (defun hash-table-empty-p (hash-table)\n \"Check whether HASH-TABLE is empty (has 0 elements).\"\n (zerop (hash-table-count hash-table)))))\n\n;; Not defined before Emacs 25.3\n(eval-and-compile\n (unless (boundp 'inhibit-message)\n (defvar inhibit-message nil\n \"Non-nil means calls to \342\200\230message\342\200\231 are not displayed.\nThey are still logged to the *Messages* buffer.\")))\n\n;;;; Functions from other packages\n\n;; `finder-inf'\n(defvar package--builtins)\n\n;; `magit'\n(declare-function magit-status-setup-buffer \"magit-status\")\n\n;; `package'\n(defvar package-selected-packages)\n(declare-function package--ensure-init-file \"package\")\n(declare-function package--save-selected-packages \"package\")\n\n;; `use-package'\n(defvar use-package-defaults)\n(defvar use-package-ensure-function)\n(defvar use-package-keywords)\n(defvar use-package-pre-ensure-function)\n(declare-function use-package-as-symbol \"use-package\")\n(declare-function use-package-error \"use-package\")\n(declare-function use-package-handler/:ensure \"use-package\")\n(declare-function use-package-normalize/:ensure \"use-package\")\n(declare-function use-package-only-one \"use-package\")\n(declare-function use-package-process-keywords \"use-package\")\n\n;;;; Customization variables\n\n(defgroup straight nil\n \"Next-generation, purely functional package manager for the Emacs hacker.\"\n :group 'applications\n :prefix \"straight-\")\n\n(defcustom straight-arrow\n (if (char-displayable-p ?\342\206\222) \" \342\206\222 \" \" -> \")\n \"The string to use for an arrow in messages.\"\n :type 'string)\n\n(defcustom straight-profiles\n '((nil . \"default.el\"))\n \"Alist mapping package profile names to version lockfile names.\nThe profile names should be symbols, and the filenames may be\nrelative (to straight/versions/) or absolute.\"\n :type '(alist :key-type symbol :value-type string))\n\n(defcustom straight-current-profile nil\n \"Symbol identifying the current package profile.\nThis symbol should have an entry in `straight-profiles'. If you\nwish to take advantage of the multiple-profile system, you should\nbind this variable to different symbols using `let' over\ndifferent parts of your init-file.\"\n :type 'symbol)\n\n(defcustom straight-repository-user \"raxod502\"\n \"String identifying the GitHub user from which to clone straight.el.\nYou must set this variable before straight.el is bootstrapped for\nit to have an effect. (It is used in the default recipe for\nstraight.el which is registered during bootstrap.)\n\nIf you have forked raxod502/straight.el to your-name/straight.el,\nthen to use your fork you should set `straight-repository-user'\nto \\\"your-name\\\".\"\n :type 'string)\n\n(defcustom straight-repository-branch \"master\"\n \"String identifying the branch of straight.el to clone.\nYou must set this variable before straight.el is bootstrapped for\nit to have an effect. (It is used in the default recipe for\nstraight.el which is registered during bootstrap.)\"\n :type '(choice\n (const :tag \"Stable version (master)\" \"master\")\n (const :tag \"Development version (develop)\" \"develop\")\n (string :tag \"Use a custom branch\")))\n\n(defcustom straight-default-vc 'git\n \"VC backend to use by default, if a recipe has no `:type'.\nFunctions named like `straight-vc-TYPE-clone', etc. should be\ndefined, where TYPE is the value of this variable.\"\n :type 'symbol)\n\n(defcustom straight-recipe-repositories nil\n \"List of recipe repositories to find recipes in.\nThese are used when you provide only a package name, rather than\na full recipe, to `straight-use-package' or\n`straight-use-recipes'. The order in this list determines the\nprecedence. Functions named like `straight-recipes-NAME-list',\netc. should be defined, where NAME is any element of this list.\"\n :type '(list symbol))\n\n(defcustom straight-recipe-overrides nil\n \"Alist specifying recipes to override those provided explicitly.\nThe keys are symbols naming profiles, and the values are lists of\nMELPA-style package recipes. Because the car of a MELPA-style\nrecipe is the package name as a symbol, this means the values can\nalso be interpreted as alists whose keys are symbols naming\npackages.\n\nIf you have no need of the profile system, then using the default\nprofile (nil) will suffice without additional setup.\"\n :type '(alist :key-type symbol :value-type\n (alist :key-type symbol :value-type\n (plist :key-type symbol :value-type sexp))))\n\n(defcustom straight-allow-recipe-inheritance t\n \"Non-nil allows partially overriding recipes.\nIf you override a recipe, every component that is not explicitly\noverriden will be searched for in original recipe. If found, that\nvalue will be added to the overriden recipe. This allows you to\nonly override the recipe components you are interested in,\ninstead of being required to override them all. The supported\ncomponents are the ones listed by `straight-vc-git-keywords' and\n`:files'. Note that enabling this feature has the side effect\nthat all recipe repos (i.e. melpa, elpa) will always be cloned,\neven if you explicitly specify all your recipes.\n\nThe `:fork' keyword is handled specially. If its value is a\nstring instead of a list, then it is assigned as the `:repo' of\nthe fork. Also the fork recipe will inherit its `:host' component\nfrom the default recipe.\n\nFor example, the following are all equivalent with recipe\ninheritance enabled.\n\n\\\\='(package :host \\\\='gitlab :repo \\\"other-user/repo\\\"\n :fork (:host \\\\='gitlab :repo \\\"my-user/repo\\\"))\n\n\\\\='(package :fork (:host \\\\='gitlab :repo \\\"my-user/repo\\\"))\n\n\\\\='(package :fork (:repo \\\"my-user/repo\\\"))\n\n\\\\='(package :fork \\\"my-user/repo\\\")\"\n :type 'boolean)\n\n(defcustom straight-safe-mode nil\n \"Non-nil means avoid doing anything that modifies the filesystem.\nIn safe mode, package modifications will still be detected\naccording to `straight-check-for-modifications'. However, if a\npackage needs to be cloned, built, or rebuilt, straight.el\ninstead generates an error. The build cache will not be written\nback to disk, nor will the filesystem watcher be started (if\nenabled).\n\nAs one example of a use case for safe mode, suppose you want to\nbyte-compile your Emacs configuration asynchronously in the\nbackground. To avoid multiple Emacs processes modifying the\nfilesystem concurrently via straight.el, you might want to enable\nsafe mode for the background Emacs process.\n\nSafe mode is not guaranteed to be as performant as normal\noperation.\"\n :type 'boolean)\n\n;;;; Utility functions\n;;;;; Association lists\n\n(defun straight--normalize-alist (alist &optional test)\n \"Return copy of ALIST with duplicate keys removed.\nThe value for a duplicated key will be the last one in ALIST.\nDuplicates are tested with TEST, which must be accepted by the\n`make-hash-table' function and which defaults to `eq'. The order\nof the entries that are kept will be the same as in ALIST.\"\n (let ((hash (make-hash-table :test (or test #'eq)))\n (new-alist nil))\n (dolist (entry (reverse alist))\n (unless (gethash (car entry) hash)\n (push entry new-alist)\n (puthash (car entry) t hash)))\n new-alist))\n\n(defun straight--alist-set (key val alist &optional symbol)\n \"Set property KEY to VAL in ALIST. Return new alist.\nThis creates the association if it is missing, and otherwise sets\nthe cdr of the first matching association in the list. It does\nnot create duplicate associations. By default, key comparison is\ndone with `equal'. However, if SYMBOL is non-nil, then `eq' is\nused instead.\n\nThis method may mutate the original alist, but you still need to\nuse the return value of this method instead of the original\nalist, to ensure correct results.\"\n ;; See [1] for the genesis of this method, which should really be\n ;; built in.\n ;;\n ;; [1]: https://emacs.stackexchange.com/q/33892/12534\n (if-let ((pair (if symbol (assq key alist) (assoc key alist))))\n (setcdr pair val)\n (push (cons key val) alist))\n alist)\n\n;;;;; Property lists\n\n(defmacro straight--with-plist (plist props &rest body)\n \"Binding from PLIST the given PROPS, eval and return BODY.\nPROPS is a list of symbols. Each one is converted to a keyword\nand then its value is looked up in the PLIST and bound to the\nsymbol for the duration of BODY.\"\n (declare (indent 2) (debug (form sexp body)))\n (let ((plist-sym (make-symbol \"plist\")))\n `(let* ((,plist-sym ,plist)\n ,@(mapcar (lambda (prop)\n `(,prop\n (plist-get\n ,plist-sym\n ,(intern (concat \":\" (symbol-name prop))))))\n props))\n ,@body)))\n\n(defmacro straight--put (plist prop value)\n \"Make copy of PLIST with key PROP mapped to VALUE, and re-set it.\nPLIST must be a literal symbol naming a plist variable. PROP and\nVALUE are evaluated.\"\n `(progn\n (setq ,plist (copy-sequence ,plist))\n (setq ,plist (plist-put ,plist ,prop ,value))))\n\n(defmacro straight--remq (plist props)\n \"Make copy of PLIST with keys PROPS removed, and re-set it.\nPLIST must be a literal symbol naming a plist variable. PROPS is\nevaluated and should result in a list. Key comparison is done\nwith `eq'.\"\n ;; The following subroutine is adapted from [1].\n ;;\n ;; [1]: https://lists.gnu.org/archive/html/help-gnu-emacs/2015-08/msg00019.html\n (let ((props-sym (make-symbol \"props\")))\n `(let ((,props-sym ,props))\n (setq ,plist\n (cl-loop for (prop val) on ,plist by #'cddr\n unless (memq prop ,props-sym)\n collect prop and collect val)))))\n\n(defun straight--plist-get (plist prop default)\n \"Extract a value from a property list, or return a default.\nPLIST is a property list, PROP is the key to search for, and\nDEFAULT is the value to return if PROP is not in PLIST.\"\n (if-let ((result (plist-member plist prop)))\n (cadr result)\n default))\n\n;;;;; Hash tables\n\n(defun straight--insert (n key value table)\n \"Associate index N in KEY with VALUE in hash table TABLE.\nTABLE should be a hash whose values are lists. This function will\nset the Nth entry of the list mapped to KEY in TABLE to VALUE. If\nthe list does not have an Nth entry, it will be padded with nils\nso that it does, before the setting happens. The TABLE will be\nmodified and returned.\"\n (let ((list (gethash key table)))\n (if (>= n (length list))\n (puthash key\n (append list\n (make-list (- n (length list)) nil)\n (list value))\n table)\n (setcar (nthcdr n list) value))\n table))\n\n(defvar straight--not-present 'straight--not-present\n \"Value used as a default argument to `gethash'.\")\n\n(defvar straight--not-present-paranoid 'straight--not-present-paranoid\n \"Value used as a default argument to `gethash'.\nWhy do we need this? Because whoever wrote the Elisp hash table\nAPI didn't actually know how to write hash table APIs.\")\n\n(defun straight--checkhash (key table &optional paranoid)\n \"Return non-nil if KEY is present in hash TABLE.\nIf PARANOID is non-nil, ensure correctness even for hash tables\nthat may contain `straight--not-present' as a value.\"\n (not\n (and (eq (gethash key table straight--not-present) straight--not-present)\n (or paranoid\n (eq (gethash key table straight--not-present-paranoid)\n straight--not-present-paranoid)))))\n\n;;;;; Strings\n\n(defun straight--split-and-trim (string &optional indent max-lines)\n \"Split the STRING on newlines, returning a list.\nRemove any blank lines at the beginning or end. If INDENT is\nnon-nil, then add that many spaces to the beginning of each line\nand concatenate them with newlines, returning a string instead of\na list. If MAX-LINES is non-nil, then it should be a nonnegative\ninteger, and any lines past that many are discarded.\"\n (let ((parts (split-string string \"\\n\")))\n ;; Remove blank lines from beginning.\n (while (equal (car parts) \"\")\n (setq parts (cdr parts)))\n (setq parts (nreverse parts))\n ;; Remove blank lines from end.\n (while (equal (car parts) \"\")\n (setq parts (cdr parts)))\n (setq parts (nreverse parts))\n ;; Remove tail.\n (when (and max-lines (< max-lines (length parts)))\n (setf (nthcdr max-lines parts) nil))\n ;; Add indentation.\n (if indent\n (let ((indent (make-string (or indent 0) ? )))\n (string-join (mapcar (lambda (part)\n (concat indent part))\n parts)\n \"\\n\"))\n parts)))\n\n(cl-defun straight--uniquify (prefix taken)\n \"Generate a string with PREFIX that is not in list TAKEN.\nThis is done by trying PREFIX-1, PREFIX-2, etc. if PREFIX is\nalready in TAKEN.\"\n (if (member prefix taken)\n (let ((n 1))\n (while t\n (let ((candidate (format \"%s-%d\" prefix n)))\n (if (member candidate taken)\n (cl-incf n)\n (cl-return-from straight--uniquify candidate)))))\n prefix))\n\n;;;;; Functions\n\n(defmacro straight--functionp (object)\n \"Non-nil if OBJECT, an unquoted symbol, is bound to a function.\nHowever, if OBJECT evaluates to its own symbol value or t, then\nreturn nil. This is useful for allowing a function to be called\nwith nil, non-nil, or a function object, without worrying about\nthe non-nil value being interpreted as a function: just call the\nfunction with the quoted name of the argument, or use t.\"\n (let ((object-sym (make-symbol \"object\")))\n `(let ((,object-sym ,object))\n (and (not (memq ,object-sym '(,object t)))\n (functionp ,object-sym)))))\n\n;;;;; Messaging\n\n(defun straight--output (string &rest objects)\n \"Same as `message' (which see for STRING and OBJECTS) normally.\nHowever, in batch mode, print to stdout instead of stderr.\"\n (if noninteractive\n (progn\n (princ (apply #'format string objects))\n (terpri))\n (apply #'message string objects)))\n\n(defmacro straight--with-progress (task &rest body)\n \"Displaying TASK as a progress indicator, eval and return BODY.\nDisplay \\\"TASK...\\\", eval BODY, display \\\"TASK...done\\\", and\nreturn the result of evaluating BODY. If TASK is nil, no messages\nare displayed. TASK can also be a cons, whose car and cdr are\nused as the TASK for the beginning and end messages\nrespectively. (Either the car or cdr, or both, can be nil.) See\nalso `straight--progress-begin' and `straight--progress-end'.\"\n (declare (indent 1) (debug t))\n (let ((task-sym (make-symbol \"gensym--task\"))\n (task-car-sym (make-symbol \"gensym--task-car\"))\n (task-cdr-sym (make-symbol \"gensym--task-cdr\")))\n `(let* ((,task-sym ,task)\n (,task-car-sym (if (listp ,task-sym)\n (car ,task-sym)\n ,task-sym))\n (,task-cdr-sym (if (listp ,task-sym)\n (cdr ,task-sym)\n ,task-sym)))\n (prog2\n (when ,task-car-sym\n (straight--output \"%s...\" ,task-car-sym))\n (progn\n ,@body)\n (when ,task-cdr-sym\n (straight--output \"%s...done\" ,task-cdr-sym))))))\n\n(defun straight--progress-begin (message)\n \"Display a MESSAGE indicating ongoing progress.\nThe MESSAGE is postpended with \\\"...\\\" and then passed to\n`message'. See also `straight--with-progress' and\n`straight--progress-end'.\"\n (straight--output \"%s...\" message))\n\n(defun straight--progress-end (message)\n \"Display a MESSAGE indicating completed progress.\nThe MESSAGE is postpended with \\\"...done\\\" and then passed to\n`message'. See also `straight--with-progress' and\n`straight--progress-begin'.\"\n (straight--output \"%s...done\" message))\n\n(defvar straight--echo-area-dirty nil\n \"Non-nil if a progress message has been wiped from the echo area.\nThis is used as an internal bookkeeping variable to determine if\na progress message has been bumped out of the echo area by\nanother message, and needs to be redisplayed.\")\n\n(defun straight--warn (message &rest args)\n \"Display a warning from `straight'. Return nil.\nThe warning message is obtained by passing MESSAGE and ARGS to\n`format'.\"\n (ignore\n (display-warning 'straight (apply #'format message args))))\n\n;;;;; Buffers\n\n(defun straight--ensure-blank-lines (n)\n \"Ensure N newline characters preceding point, unless at beginning of buffer.\"\n (unless (= 1 (point))\n (let ((num-existing 0))\n (save-excursion\n (cl-dotimes (_ n)\n (when (or (= 1 (point))\n (not (= ?\\n (char-before))))\n (cl-return))\n (cl-incf num-existing)\n (backward-char)))\n (insert (make-string (- n num-existing) ?\\n)))))\n\n;;;;; Windows OS detection\n\n(defun straight--windows-os-p ()\n \"Check if the current operating system is Windows.\"\n (memq system-type '(ms-dos windows-nt)))\n\n;;;;; Paths\n\n(defcustom straight-base-dir user-emacs-directory\n \"Directory in which the straight/ subdirectory is created.\nDefaults to `user-emacs-directory'.\"\n :type 'string)\n\n(defcustom straight-build-dir \"build\"\n \"Name of the directory into which packages are built.\nRelative to the straight/ subdirectory of `straight-base-dir'.\nDefaults to \\\"build\\\".\n\nBy default, this variable also affects the name of the build\ncache file, set the variable `straight-build-cache-fixed-name'\nto override this.\"\n :type 'string)\n\n(defcustom straight-build-cache-fixed-name nil\n \"Name of the build cache file.\nIf it is nil, uses the default name, namely\n\\\"`straight-build-dir'-cache.el\\\".\n\nIf it is not nil, it has to be a string which is used as the\nname of the cache file.\n\nIn both cases, the path is relative to the \\\"straight/\\\"\nsubdirectory of `straight-base-dir'.\"\n :type '(choice (const :tag \"Default location\" nil)\n (string :tag \"Fixed location\")))\n\n(defvar straight--this-file\n (file-truename (or load-file-name buffer-file-name))\n \"Absolute real path to this file, straight.el.\")\n\n(defun straight--path-prefix-p (prefix-path full-path)\n \"Return non-nil if PREFIX-PATH is a prefix of FULL-PATH.\nThis takes into account case insensitivity on macOS.\"\n (string-prefix-p prefix-path full-path (eq system-type 'darwin)))\n\n(defun straight--emacs-dir (&rest segments)\n \"Get a subdirectory of the `user-emacs-directory'.\nThe SEGMENTS are path segments which are concatenated with\nslashes and postpended to the straight directory. With no\nSEGMENTS, return the `user-emacs-directory' itself.\n\n\\(straight--dir \\\"straight\\\" \\\"build\\\" \\\"esup\\\")\n=> \\\"~/.emacs.d/straight/build/esup/\\\"\"\n (let ((dir straight-base-dir))\n (while segments\n (setq dir (expand-file-name\n (file-name-as-directory (car segments)) dir))\n (setq segments (cdr segments)))\n dir))\n\n(defun straight--emacs-file (&rest segments)\n \"Get a file in the `user-emacs-directory'.\nThe SEGMENTS are path segments with are concatenated with slashes\nand postpended to the straight directory.\n\n\\(straight--file \\\"straight\\\" \\\"build\\\" \\\"esup\\\" \\\"esup-autoloads.el\\\")\n=> \\\"~/.emacs.d/straight/build/esup/esup-autoloads.el\\\"\"\n (expand-file-name\n (substring (apply 'straight--emacs-dir segments) 0 -1)))\n\n(defun straight--dir (&rest segments)\n \"Get a subdirectory of the straight/ directory.\nSEGMENTS are passed to `straight--emacs-dir'. With no SEGMENTS,\nreturn the straight/ directory itself.\"\n (apply #'straight--emacs-dir \"straight\" segments))\n\n(defun straight--file (&rest segments)\n \"Get a file in the straight/ directory.\nSEGMENTS are passed to `straight--emacs-file'.\"\n (apply #'straight--emacs-file \"straight\" segments))\n\n(defun straight--build-dir (&rest segments)\n \"Get a subdirectory of the straight/build/ directory.\nSEGMENTS are passed to `straight--dir'. With no SEGMENTS, return\nthe straight/build/ directory itself.\"\n (apply #'straight--dir straight-build-dir segments))\n\n(defun straight--build-file (&rest segments)\n \"Get a file in the straight/build/ directory.\nSEGMENTS are passed to `straight--file'.\"\n (apply #'straight--file straight-build-dir segments))\n\n(defun straight--autoloads-file (package)\n \"Get the filename of the autoloads file for PACKAGE.\nPACKAGE should be a string.\"\n (straight--build-file package (format \"%s-autoloads.el\" package)))\n\n(defun straight--build-cache-file ()\n \"Get the file containing straight.el's build cache.\"\n (straight--file\n (or straight-build-cache-fixed-name\n (concat straight-build-dir \"-cache.el\"))))\n\n(defun straight--links-dir (&rest segments)\n \"Get a subdirectory of straight/links/.\nSEGMENTS are passed to `straight--dir'. With no SEGMENTS, return\nthe straight/links/ directory itself.\"\n (apply #'straight--dir \"links\" segments))\n\n(defun straight--links-file (&rest segments)\n \"Get a file in the straight/links/ directory.\nSEGMENTS are passed to `straight--file'.\"\n (apply #'straight--file \"links\" segments))\n\n(defun straight--modified-dir (&rest segments)\n \"Get a subdirectory of straight/modified/.\nSEGMENTS are passed to `straight--dir'. With no SEGMENTS, return\nthe straight/modified/ directory itself.\"\n (apply #'straight--dir \"modified\" segments))\n\n(defun straight--modified-file (&rest segments)\n \"Get a file in the straight/modified/ directory.\nSEGMENTS are passed to `straight--file'.\"\n (apply #'straight--file \"modified\" segments))\n\n(defun straight--mtimes-dir (&rest segments)\n \"Get a subdirectory of straight/mtimes/.\nSEGMENTS are passed to `straight--dir'. With no SEGMENTS, return\nthe straight/mtimes/ directory itself.\"\n (apply #'straight--dir \"mtimes\" segments))\n\n(defun straight--mtimes-file (&rest segments)\n \"Get a file in the straight/mtimes/ directory.\nSEGMENTS are passed to `straight--file'.\"\n (apply #'straight--file \"mtimes\" segments))\n\n(defun straight--repos-dir (&rest segments)\n \"Get a subdirectory of the straight/repos/ directory.\nSEGMENTS are passed to `straight--dir'. With no SEGMENTS, return\nthe straight/repos/ directory itself.\"\n (apply #'straight--dir \"repos\" segments))\n\n(defun straight--repos-file (&rest segments)\n \"Get a file in the straight/repos/ directory.\nSEGMENTS are passed to `straight--file'.\"\n (apply #'straight--file \"repos\" segments))\n\n(defun straight--versions-dir (&rest segments)\n \"Get a subdirectory of the straight/versions/ directory.\nSEGMENTS are passed to `straight--dir'. With no SEGMENTS, return\nthe straight/versions/ directory itself.\"\n (apply #'straight--dir \"versions\" segments))\n\n(defun straight--versions-file (&rest segments)\n \"Get a file in the straight/versions/ directory.\nSEGMENTS are passed to `straight--file'.\"\n (apply #'straight--file \"versions\" segments))\n\n(defun straight--watcher-dir (&rest segments)\n \"Get a subdirectory of the straight/watcher/ directory.\nSEGMENTS are passed to `straight--dir'. With no SEGMENTS, return\nthe straight/watcher/ directory itself.\"\n (apply #'straight--dir \"watcher\" segments))\n\n(defun straight--watcher-file (&rest segments)\n \"Get a file in the straight/watcher/ directory.\nSEGMENTS are passed to `straight--file'.\"\n (apply #'straight--file \"watcher\" segments))\n\n(defun straight--watcher-python ()\n \"Get the path to the filesystem virtualenv's Python executable.\"\n (if (straight--windows-os-p)\n (straight--watcher-file \"virtualenv\" \"Scripts\" \"python.exe\")\n (straight--watcher-file \"virtualenv\" \"bin\" \"python\")))\n\n(defun straight--versions-lockfile (profile)\n \"Get the version lockfile for given PROFILE, a symbol.\"\n (if-let ((filename (alist-get profile straight-profiles)))\n (straight--versions-file filename)\n (error \"Unknown profile: %S\" profile)))\n\n(defun straight--determine-repo (path)\n \"Determine the local repository containing PATH, if any.\nIf PATH, a string, corresponds to a file or directory inside (or\nequal to) any subfolder of `straight--repos-dir', then return the\nname of the local repository (not a path), as a string.\nOtherwise, return nil.\"\n (let ((repos-dir (straight--repos-dir)))\n (when (straight--path-prefix-p repos-dir path)\n ;; Remove the ~/.emacs.d/straight/repos/ part.\n (let ((relative-path (substring path (length repos-dir))))\n ;; Trim off any more path components after hte local\n ;; repository.\n (replace-regexp-in-string\n \"/.*\" \"\" relative-path 'fixedcase 'literal)))))\n\n;;;;; Filesystem operations\n\n(defun straight--symlinks-are-usable-p ()\n \"Return non-nil if symlinks are well-supported by the OS.\nThis means that they are used to build packages rather than\ncopying files, which is slower and less space-efficient.\n\nAll operating systems support symlinks; however, on Microsoft\nWindows you may need additional system configuration (see\nvariable `straight-use-symlinks').\"\n (not (straight--windows-os-p)))\n\n(defcustom straight-use-symlinks (straight--symlinks-are-usable-p)\n \"Whether to use symlinks for building packages.\nUsing symlinks is always preferable.\n\nOn Microsoft Windows, this variable has to be set to non-nil\nmanually, if desired, as symlink-functionality is not always\navailable. On most versions of Windows 10, the user's account\nneeds to be assigned the right to \\\"Create symbolic links\\\" in\n\\\"secpol.msc\\\". For more information about the symlink-setup on\nMS Windows please refer to the section \\\"Customizing how packages\nare built\\\" in the user manual.\n\nBeware that copying is slower, less space-efficient, and\nrequiring of additional hacks.\"\n :type 'boolean)\n\n(defun straight--directory-files (&optional directory match full sort)\n \"Like `directory-files', but with better defaults.\nDIRECTORY, MATCH, and FULL are as in `directory-files', but their\norder has been changed. Also, DIRECTORY defaults to\n`default-directory' if omitted. The meaning of the last argument\nSORT has been inverted from `directory-files'. Finally, the . and\n.. entries are never returned, and .git is removed from the\nresults if present.\"\n (delete \".git\" (delete \".\" (delete \"..\" (directory-files\n (or directory default-directory)\n full match (not sort))))))\n\n(defun straight--symlink-recursively (link-target link-name)\n \"Make a symbolic link to LINK-TARGET, named LINK-NAME, recursively.\nThis means that if the link target is a directory, then a\ncorresponding directory is created (called LINK-NAME) and all\ndescendants of LINK-TARGET are linked separately into\nLINK-NAME (except for directories, which are created directly).\n\nIf `straight-use-symlinks' is nil, then instead of creating a\nsymlink, the file is copied directly, and a corresponding entry\nis created in the straight/links/ directory so that the file may\nbe interpreted later as a symlink.\"\n (if (and (file-directory-p link-target)\n (not (file-symlink-p link-target)))\n (progn\n (make-directory link-name 'parents)\n (dolist (entry (straight--directory-files link-target))\n (straight--symlink-recursively\n (expand-file-name entry link-target)\n (expand-file-name entry link-name))))\n (make-directory (file-name-directory link-name) 'parents)\n (condition-case _\n (if straight-use-symlinks\n (if (straight--windows-os-p)\n (straight--get-call\n \"cmd\" \"/c\" \"mklink\"\n (subst-char-in-string ?/ ?\\\\ link-name)\n (subst-char-in-string ?/ ?\\\\ link-target))\n (make-symbolic-link link-target link-name))\n (copy-file link-target link-name)\n (let ((build-dir (straight--build-dir)))\n (when (straight--path-prefix-p build-dir link-name)\n (let* ((relative-path (substring link-name (length build-dir)))\n (link-record (straight--links-file relative-path)))\n ;; This call may fail in the case that there was\n ;; previously a directory being symlinked, and now\n ;; there is a file by the same name being symlinked.\n ;; That edge case will need to be dealt with\n ;; eventually, but it's rather nontrivial so I'm not\n ;; doing it now.\n (make-directory (file-name-directory link-record) 'parents)\n (with-temp-file link-record\n (insert link-target))))))\n (file-already-exists\n ;; We're OK with the recipe specifying to create the symlink\n ;; twice, as long as it's pointing to the same place both\n ;; times. Otherwise, signal a warning.\n (unless (string= link-target\n (file-symlink-p link-name))\n (straight--warn \"Attempted to link %S to both %S and %S\"\n link-name (file-symlink-p link-name) link-target))))))\n\n;;;;; External processes\n\n(defcustom straight-process-buffer \"*straight-process*\"\n \"Name of buffer used for process output.\"\n :type 'string)\n\n(defun straight--process-get-buffer ()\n \"Return a buffer named `straight-process-buffer'.\"\n (or (get-buffer straight-process-buffer)\n (let ((buf (get-buffer-create straight-process-buffer)))\n (prog1 buf\n (with-current-buffer buf\n (special-mode))))))\n\n(defvar-local straight--process-output-beginning nil\n \"Marker at beginning of process output, or nil.\nThis is used in `straight-process-buffer'.\")\n\n(defvar-local straight--process-output-end nil\n \"Marker at end of process output, or nil.\nThis is used in `straight-process-buffer'.\")\n\n(defvar-local straight--process-return-code nil\n \"Return code of last process run, or nil.\nThis is used in `straight-process-buffer'.\")\n\n(defvar straight--process-inhibit-output nil\n \"Non-nil means do not insert process output into `straight-process-buffer'.\")\n\n(defvar straight--default-directory nil\n \"Overrides value of `default-directory'.\nThis is used because `default-directory' is buffer-local, which\nmeans binding it for the duration of a recursive edit causes fun\nside-effects like random buffers permanently forgetting which\ndirectory they're in, and straight.el executing Git commands\nagainst the wrong repositories.\n\nIf you set this globally to something other than nil, you may be\neaten by a grue.\")\n\n(defun straight--process-run (program &rest args)\n \"Run executable PROGRAM with given ARGS.\nOutput is logged to `straight-process-buffer' unless\n`straight--process-inhibit-output' is non-nil. See also\n`straight--process-get-return-code' and\n`straight--process-get-output'.\n\nThe return value of this function is undefined.\"\n (let ((directory (or straight--default-directory default-directory)))\n (prog1 nil\n (with-current-buffer (straight--process-get-buffer)\n (let ((inhibit-read-only t))\n (save-excursion\n (setq straight--process-output-beginning nil)\n (setq straight--process-output-end nil)\n (setq straight--process-return-code nil)\n (goto-char (point-max))\n (unless straight--process-inhibit-output\n (straight--ensure-blank-lines 2)\n (insert\n \"$ cd \"\n (shell-quote-argument (expand-file-name directory))\n \"\\n\")\n (insert\n \"$ \"\n (mapconcat #'shell-quote-argument (cons program args) \" \")\n \"\\n\\n\")\n (setq straight--process-output-beginning\n (point-marker)))\n (condition-case e\n (let* ((default-directory directory)\n (return (apply\n #'call-process\n program nil\n (unless straight--process-inhibit-output t)\n (get-buffer-window)\n args)))\n (unless straight--process-inhibit-output\n (setq straight--process-output-end\n (point-marker)))\n (setq straight--process-return-code return)\n (unless straight--process-inhibit-output\n (straight--ensure-blank-lines 2)\n (insert (format \"[Return code: %S]\\n\" return))))\n (file-missing\n (setq straight--process-output-beginning nil)\n (straight--ensure-blank-lines 2)\n (insert\n (format \"[File error while %s]\\n\" (downcase (cadr e))))))))))))\n\n(defun straight--process-run-p ()\n \"Return non-nil if the last process was run successfully.\nThis just means the executable was invoked, not that its return\ncode was zero.\"\n (with-current-buffer (straight--process-get-buffer)\n (when straight--process-return-code t)))\n\n(defun straight--process-get-return-code ()\n \"Get return code of last process run by `straight--process-run'.\nThis is nil if the process could not be run.\"\n (with-current-buffer (straight--process-get-buffer)\n straight--process-return-code))\n\n(defun straight--process-get-output ()\n \"Get output of last process run by `straight--process-run'.\nThis is nil if the process could not be run, or if\n`straight--process-inhibit-output' was non-nil when it was run.\"\n (with-current-buffer (straight--process-get-buffer)\n (when (and straight--process-output-beginning\n straight--process-output-end)\n (buffer-substring straight--process-output-beginning\n straight--process-output-end))))\n\n(defun straight--call (program &rest args)\n \"Run executable PROGRAM with given ARGS.\nReturn a cons cell whose car is a boolean indicating whether the\ncommand was run successfully with a return code of zero, and\nwhose cdr is its output.\"\n (apply #'straight--process-run program args)\n (cons\n (let ((return-code (straight--process-get-return-code)))\n (and return-code\n (zerop return-code)))\n (straight--process-get-output)))\n\n(defun straight--warn-call (program &rest args)\n \"Run executable PROGRAM with given ARGS, producing a warning if it fails.\nReturn non-nil if the command was run successfully with a return\ncode of zero, and nil otherwise.\"\n (let* ((result (apply #'straight--call program args)))\n (if (car result)\n t\n (prog1 nil\n (straight--warn \"Failed to run %S; see buffer %s\"\n program straight-process-buffer)))))\n\n(defun straight--check-call (program &rest args)\n \"Run executable PROGRAM with given ARGS, returning non-nil if it succeeds.\"\n (when (car (apply #'straight--call program args))\n t))\n\n(defun straight--get-call-raw (program &rest args)\n \"Run executable PROGRAM with given ARGS, returning its output as a string.\nIf the command cannot be run or its return code is nonzero, throw\nan error.\"\n (let ((result (apply #'straight--call program args)))\n (if (car result)\n (cdr result)\n (error \"Failed to run %S; see buffer %s\"\n program straight-process-buffer))))\n\n(defun straight--get-call (program &rest args)\n \"Run executable PROGRAM with given ARGS, returning its output.\nReturn a string with whitespace trimmed from both ends. If the\ncommand cannot be run or its return code is nonzero, throw an\nerror.\"\n (string-trim (apply #'straight--get-call-raw program args)))\n\n(defun straight--make-mtime (mtime)\n \"Ensure that the `straight--mtimes-file' for MTIME (a string) exists.\nThis creates a file in the appropriate directory that has the\ncorresponding mtime. Return the name of the file.\n\nThis function may not work on all operating systems.\"\n (make-directory (straight--mtimes-dir) 'parents)\n (let ((file (straight--mtimes-file mtime)))\n (unless (file-exists-p file)\n (straight--check-call \"touch\" \"-d\" mtime file))\n file))\n\n;;;;; Interactive popup windows\n\n(defmacro straight--catching-quit (&rest body)\n \"Exec BODY. If `quit' signaled, catch and return nil.\"\n (declare (indent defun))\n (let ((err (make-symbol \"err\")))\n `(condition-case ,err\n (progn ,@body)\n (quit))))\n\n(defun straight--popup-raw (prompt actions)\n \"Display PROMPT and allow user to choose between one of several ACTIONS.\nPROMPT is a string, generally a complete sentence. ACTIONS is a\nlist of lists (KEY DESC FUNC ARGS...). KEY is a string\nidentifying the key that triggers this action; it is passed to\n`kbd'. DESC is a description string to be displayed in the popup.\nIf it is nil, the action and its binding is not displayed in the\npopup, although it still takes effect. If the user selects an\naction, its FUNC is called with ARGS and the popup is dismissed.\nThe return value of `straight--popup-raw' is the return value of\nFUNC.\n\nACTIONS later in the list take precedence over earlier ones with\nregard to keybindings.\"\n (when noninteractive\n (error (format \"Cannot display prompt in batch mode: %s\" prompt)))\n (unless (assoc \"C-g\" actions)\n (setq actions (append actions '((\"C-g\" \"Cancel\" keyboard-quit)))))\n (let ((keymap (make-sparse-keymap))\n (func nil)\n (prompt (concat prompt \"\\n\"))\n (max-length (apply #'max (mapcar #'length (mapcar #'car actions)))))\n (dolist (action actions)\n (cl-destructuring-bind (key desc func . args) action\n (when desc\n (setq prompt\n (format \"%s\\n %s%s %s\" prompt\n (make-string (- max-length (length key)) ? )\n key desc)))\n (define-key keymap (kbd key)\n (lambda ()\n (interactive)\n (apply func args)))))\n (setq prompt (concat prompt \"\\n\\n\"))\n (let ((max-mini-window-height 1.0)\n (cursor-in-echo-area t))\n (when minibuffer-auto-raise\n (raise-frame (window-frame (minibuffer-window))))\n (while (not func)\n (setq func (lookup-key keymap (vector (read-key prompt))))))\n (funcall func)))\n\n(defmacro straight--popup (prompt &rest actions)\n \"Same as `straight--popup-raw', but with reduced need for quoting.\nPROMPT is still evaluated at runtime. So are all elements of\nACTIONS, except for FUNC, which is wrapped in a `lambda'\nautomatically, and ARGS, which are superfluous and therefore\ninstead used as additional forms to place in the `lambda' after\nFUNC.\"\n (declare (indent defun))\n `(straight--popup-raw\n ,prompt\n (list\n ,@(mapcar\n (lambda (action)\n (cl-destructuring-bind (key desc . args) action\n `(list ,key ,desc (lambda () ,@args))))\n actions))))\n\n(defun straight-are-you-sure (&optional prompt)\n \"Display a popup asking the user to confirm their questionable actions.\nPROMPT has a sensible default; otherwise it is a string. Return\nnon-nil if the user confirms; nil if they abort.\"\n (straight--popup (or prompt \"Are you sure?\")\n (\"y\" \"Yes, proceed\" t)\n (\"n\" \"No, abort\" nil)))\n\n;;;;; Transactions\n\n(defvar straight--transaction-alist nil\n \"Alist of actions being executed in the current transaction.\nSee `straight--transaction-exec'. The cars are their IDs, and the\ncdrs are their END-FUNCs.\n\nIf nil, no transaction is not live.\")\n\n(defun straight--transaction-finalize-at-top-level ()\n \"Schedule to finalize the current transaction when appropriate.\nThis means that `straight--transaction-finalize' will be invoked\non `post-command-hook', and it will wait until control is\nreturned to the top level before actually finalizing the\ntransaction and removing itself from the hook again. In batch\nmode, the transaction is finalized using `kill-emacs-hook' rather\nthan `post-command-hook' (because the latter is not run in batch\nmode).\"\n (if noninteractive\n (add-hook 'kill-emacs-hook #'straight--transaction-finalize)\n (add-hook 'post-command-hook #'straight--transaction-finalize)))\n\n(defun straight--transaction-finalize ()\n \"Finalize the current transaction.\nThis means clearing `straight--transaction-alist' and executing\nthe functions recorded in it.\"\n ;; If we're inside a recursive edit, then don't finalize the\n ;; transaction yet. Instead, arrange to schedule another idle timer\n ;; once the user exits the recursive edit via one of the functions\n ;; listed below.\n (when (zerop (recursion-depth))\n (let ((alist straight--transaction-alist))\n (setq straight--transaction-alist nil)\n (remove-hook 'post-command-hook #'straight--transaction-finalize)\n (dolist (end-func (mapcar #'cdr alist))\n (when end-func\n (funcall end-func))))))\n\n(cl-defun straight--transaction-exec (id &key now later manual)\n \"Execute functions within a transaction.\nID is a symbol that acts as a unique identifier of the action\nwithin the transaction. Only the first NOW and LATER functions\nwith a given ID are used within a transaction. NOW is invoked\nimmediately (with no arguments), and LATER is invoked at the end\nof the transaction (with no arguments). These functions wrap the\ntransaction, so the LATER functions are invoked in reverse order\nto the NOW functions. If either NOW or LATER is nil or omitted,\nit acts as a no-op, but the ID is still registered to block\nfuture `straight--transaction-exec' calls.\n\nIf MANUAL is non-nil, do not arrange for finalizing the\ntransaction. In this case, the caller must do this itself.\"\n ;; If `straight--transaction-alist' is non-nil, then we've already\n ;; started a transaction, but haven't yet finalized it. Don't\n ;; schedule more idle timers.\n (unless (or manual straight--transaction-alist)\n (straight--transaction-finalize-at-top-level))\n (unless (assq id straight--transaction-alist)\n ;; Push to start of list. At the end, we'll read forward, thus in\n ;; reverse order.\n (push (cons id later) straight--transaction-alist)\n (when now\n (funcall now))))\n\n(defun straight-interactive-transaction ()\n \"Start a recursive edit within a transaction.\"\n (interactive)\n (straight--transaction-exec 'interactive :manual t)\n (unwind-protect\n (recursive-edit)\n (straight--transaction-finalize)))\n\n;;;; Feature detection\n\n(defun straight--determine-find-flavor ()\n \"Determine the best default value of `straight-find-flavor'.\nThis uses -newermt if possible, and -newer otherwise.\"\n (if (straight--check-call\n \"find\" \"/dev/null\" \"-newermt\" \"2018-01-01 12:00:00\")\n `(newermt)\n nil))\n\n(defcustom straight-find-executable \"find\"\n \"Executable path of find command used by straight.el.\"\n :type 'string)\n\n(defcustom straight-find-flavor (straight--determine-find-flavor)\n \"What options the available find(1) binary supports.\nThis is a list of symbols. If `newermt' is in the list, then\nfind(1) is given the `-newermt' option to check for files newer\nthan a particular timestamp. Otherwise, it is given the `-newer'\noption instead (this requires creating temporary files with\nparticular mtimes, which is slower).\n\nFor backwards compatibility, the value of this variable may also\nbe a symbol, which is translated into a corresponding list as\nfollows:\n\n`gnu/bsd' => `(newermt)'\n`busybox' => nil\n\nThis usage is deprecated and will be removed.\"\n :type '(list\n (const :tag \"Supports -newermt\" newermt)))\n\n(defun straight--find-supports (symbol)\n \"Check if `straight-find-flavor' contains SYMBOL.\nHowever, if `straight-find-flavor' is itself one of the symbols\nsupported for backwards compatibility, account for that\nappropriately.\"\n (memq symbol\n (pcase straight-find-flavor\n (`gnu/bsd '(newermt))\n (`busybox nil)\n (lst lst))))\n\n;;;; Lockfile utility functions\n\n(defun straight--lockfile-read (lockfile)\n \"Read the given LOCKFILE and return an alist.\nLOCKFILE is a filename relative to `straight--versions-dir', as\nin `straight-profiles'. If the lockfile is missing, return nil.\nIf it is malformed, raise an error. (An informative error message\nis not guaranteed, but at least there will be an error now\ninstead of later.)\"\n (let ((lockfile-path (straight--versions-file lockfile)))\n\n (when (file-exists-p lockfile-path)\n (let ((alist (with-temp-buffer\n (insert-file-contents-literally lockfile-path)\n (read (current-buffer)))))\n (prog1 alist\n (unless (listp alist)\n (error \"Malformed lockfile: not a list\"))\n (mapc\n (lambda (cell)\n (unless (consp cell)\n (error \"Malformed lockfile: not an alist\"))\n (unless (stringp (car cell))\n (error \"Malformed lockfile: nil local repository\")))\n alist))))))\n\n(defun straight--lockfile-read-all ()\n \"Read version lockfiles and return merged alist of saved versions.\nThe alist maps repository names as strings to versions, whose\ninterpretations are defined by the relevant VC backend.\"\n (let ((versions nil))\n (dolist (spec straight-profiles)\n (cl-destructuring-bind (_profile . lockfile) spec\n (let ((versions-alist (straight--lockfile-read lockfile)))\n (dolist (spec versions-alist)\n (cl-destructuring-bind (local-repo . commit) spec\n (setq versions (straight--alist-set\n local-repo commit versions)))))))\n versions))\n\n;;;; Version control\n\n(defun straight-vc (method type &rest args)\n \"Call a VC backend method.\nMETHOD is a symbol naming a backend method, like symbol `clone'.\nTYPE is a symbol naming a VC backend, like symbol `git'. ARGS are\npassed to the method.\n\nFor example:\n (straight-vc \\\\='check-out-commit \\\\='git ...)\n=> (straight-vc-git-check-out-commit ...)\"\n (when (and straight-safe-mode\n (not (memq method '(local-repo-name keywords))))\n (error \"VC operation `%S %S' not allowed in safe mode\" type method))\n (let ((func (intern (format \"straight-vc-%S-%S\"\n type method))))\n (unless (fboundp func)\n (let ((regexp (format \"^straight-vc-%S-[a-z-]+$\" type)))\n ;; Check if *any* methods are defined for this VC backend. If\n ;; not, there is probably no such backend.\n (if (cl-block nil\n (prog1 nil\n (mapatoms\n (lambda (sym)\n (when (and\n (fboundp sym)\n (string-match-p regexp (symbol-name sym)))\n (cl-return t))))))\n (error \"VC backend `%S' does not implement method `%S'\"\n type method)\n (error \"No such VC backend `%S'\" type))))\n (apply func args)))\n\n(defun straight-vc-clone (recipe)\n \"Clone the local repository specified by straight.el-style RECIPE.\nIf a commit is specified in one of the lockfiles, attempt to\ncheck out that revision. If this fails, signal a warning.\n\nThis method sets `straight--default-directory' to the repos\ndirectory and delegates to the relevant `straight-vc-TYPE-clone'\nmethod, where TYPE is the `:type' specified in RECIPE. If the\nrepository already exists, throw an error.\"\n (straight--with-plist recipe\n (type local-repo)\n (let ((straight--default-directory (straight--repos-dir)))\n (when (file-exists-p (straight--repos-dir local-repo))\n (error \"Repository already exists: %S\" local-repo))\n ;; We're reading the lockfiles inline here, instead of caching\n ;; them like we do with the build cache. The reason is that\n ;; reading the lockfiles appears to be much faster than reading\n ;; the build cache (and we wouldn't want to engage in premature\n ;; optimization, now would we?), and also time is not really a\n ;; concern if we're already going to be cloning a repository.\n (let ((commit (cdr (assoc\n local-repo (straight--lockfile-read-all)))))\n (straight-vc 'clone type recipe commit)))))\n\n(defun straight-vc-normalize (recipe)\n \"Normalize the local repository specified by straight.el-style RECIPE.\nThe meaning of normalization is backend-defined, but typically\ninvolves validating repository configuration and cleaning the\nworking directory.\n\nIf the RECIPE does not specify a local repository, then no action\nis taken.\n\nThis method sets `straight--default-directory' to the local\nrepository directory and delegates to the relevant\n`straight-vc-TYPE-normalize' method, where TYPE is the `:type'\nspecified in RECIPE.\"\n (straight--with-plist recipe\n (local-repo type)\n (when local-repo\n (let ((straight--default-directory (straight--repos-dir local-repo)))\n (straight-vc 'normalize type recipe)))))\n\n(defun straight-vc-fetch-from-remote (recipe)\n \"Fetch from the primary remote for straight.el-style RECIPE.\n\nIf the RECIPE does not specify a local repository, then no action\nis taken.\n\nThis method sets `straight--default-directory' to the local\nrepository directory and delegates to the relevant\n`straight-vc-TYPE-fetch-from-remote' method, where TYPE is the\n`:type' specified in RECIPE.\"\n (straight--with-plist recipe\n (local-repo type)\n (when local-repo\n (let ((straight--default-directory (straight--repos-dir local-repo)))\n (straight-vc 'fetch-from-remote type recipe)))))\n\n(defun straight-vc-fetch-from-upstream (recipe)\n \"Fetch from the upstream remote for straight.el-style RECIPE.\nIf RECIPE does not configure a fork, do nothing.\n\nIf the RECIPE does not specify a local repository, then no action\nis taken.\n\nThis method sets `straight--default-directory' to the local\nrepository directory and delegates to the relevant\n`straight-vc-TYPE-fetch-from-upstream' method, where TYPE is the\n`:type' specified in RECIPE.\"\n (straight--with-plist recipe\n (local-repo type)\n (when local-repo\n (let ((straight--default-directory (straight--repos-dir local-repo)))\n (straight-vc 'fetch-from-upstream type recipe)))))\n\n(defun straight-vc-merge-from-remote (recipe)\n \"Merge from the primary remote for straight.el-style RECIPE.\n\nIf the RECIPE does not specify a local repository, then no action\nis taken.\n\nThis method sets `straight--default-directory' to the local\nrepository directory and delegates to the relevant\n`straight-vc-TYPE-merge-from-remote' method, where TYPE is the\n`:type' specified in RECIPE.\"\n (straight--with-plist recipe\n (local-repo type)\n (when local-repo\n (let ((straight--default-directory (straight--repos-dir local-repo)))\n (straight-vc 'merge-from-remote type recipe)))))\n\n(defun straight-vc-merge-from-upstream (recipe)\n \"Merge from the upstream remote for straight.el-style RECIPE.\nIf RECIPE does not configure a fork, do nothing.\n\nIf the RECIPE does not specify a local repository, then no action\nis taken.\n\nThis method sets `straight--default-directory' to the local\nrepository directory and delegates to the relevant\n`straight-vc-TYPE-merge-from-upstream' method, where TYPE is the\n`:type' specified in RECIPE.\"\n (straight--with-plist recipe\n (local-repo type)\n (when local-repo\n (let ((straight--default-directory (straight--repos-dir local-repo)))\n (straight-vc 'merge-from-upstream type recipe)))))\n\n(defun straight-vc-push-to-remote (recipe)\n \"Push to the primary remote for straight.el-style RECIPE, if necessary.\n\nIf the RECIPE does not specify a local repository, then no action\nis taken.\n\nThis method sets `straight--default-directory' to the local\nrepository directory and delegates to the relevant\n`straight-vc-TYPE-push-to-remote' method, where TYPE is the\n`:type' specified in RECIPE.\"\n (straight--with-plist recipe\n (local-repo type)\n (when local-repo\n (let ((straight--default-directory (straight--repos-dir local-repo)))\n (straight-vc 'push-to-remote type recipe)))))\n\n(defun straight-vc-check-out-commit (recipe commit)\n \"Normalize the repo for RECIPE and check out COMMIT.\n\nIf RECIPE does not specify a local repository, then no action is\ntaken.\n\nThe interpretation of COMMIT is defined by the backend, but it\nshould be compatible with `straight-vc-get-commit'.\n\nThis method sets `straight--default-directory' to the local\nrepository directory and delegates to the relevant\n`straight-vc-TYPE-check-out-commit'.\"\n (straight--with-plist recipe\n (local-repo type)\n (when local-repo\n (let ((straight--default-directory (straight--repos-dir local-repo)))\n (straight-vc 'check-out-commit type recipe commit)))))\n\n(defun straight-vc-commit-present-p (recipe commit)\n \"Check in RECIPE's repo if COMMIT can be checked out without fetching it.\nReturn non-nil if the commit is available.\"\n (straight--with-plist recipe\n (local-repo type)\n (let ((straight--default-directory (straight--repos-dir local-repo)))\n (straight-vc 'commit-present-p type local-repo commit))))\n\n(defun straight-vc-get-commit (type local-repo)\n \"Using VC backend TYPE, in LOCAL-REPO, return current commit.\nTYPE is a symbol like symbol `git', etc. LOCAL-REPO is a string\nnaming a local package repository. The type of object returned is\ndefined by the backend, but it should be compatible with\n`straight-vc-check-out-commit'.\n\nThis method sets `straight--default-directory' to the local\nrepository directory and delegates to the relevant\n`straight-vc-TYPE-get-commit' method.\"\n (let ((straight--default-directory (straight--repos-dir local-repo)))\n (straight-vc 'get-commit type local-repo)))\n\n(defun straight-vc-local-repo-name (recipe)\n \"Generate a repository name from straight.el-style RECIPE.\nIf a repository name cannot be generated, return nil. This is\nused for the default value of `:local-repo'. If nil is returned,\nthe package name is used instead.\n\nThis method sets `straight--default-directory' to the local\nrepository directory and delegates to the relevant\n`straight-vc-TYPE-local-repo-name' method, where TYPE is the\n`:type' specified in RECIPE.\"\n (straight--with-plist recipe\n (type)\n (straight-vc 'local-repo-name type recipe)))\n\n(defun straight-vc-keywords (type)\n \"Return a list of keywords used by the VC backend TYPE.\nThis does not include the `:type' keyword itself.\n\nThis method simply delegates to the relevant\n`straight-vc-TYPE-keywords' method.\"\n (straight-vc 'keywords type))\n\n;;;;; Built-in packages\n\n(defun straight-vc-built-in-get-commit (_local-repo)\n \"Get the currently checked-out commit object, given LOCAL-REPO name string.\nFor built-in packages, this is always nil because there cannot\nactually be a local repository.\"\n nil)\n\n(defun straight-vc-built-in-local-repo-name (_recipe)\n \"Generate a repository name from straight.el-style RECIPE.\nFor built-in packages, this is always nil.\"\n nil)\n\n;;;;; Git\n\n(defcustom straight-vc-git-default-branch \"master\"\n \"The default value for `:branch' when `:type' is symbol `git'.\"\n :type 'string)\n\n(defcustom straight-vc-git-primary-remote \"origin\"\n \"The remote name to use for the primary remote.\nThis variable is deprecated, and only applies to usage of the\ndeprecated `:upstream' keyword, except that if it is set to a\nnon-default value then it overrides the value of\n`straight-vc-git-default-remote-name', for backwards\ncompatibility.\"\n :type 'string)\n(make-obsolete-variable\n 'straight-vc-git-primary-remote\n \"see `straight-vc-git-default-remote-name' and\n `straight-vc-git-default-fork-name' instead,\n but note that the semantics are different.\"\n \"2018-08-22\")\n\n(defcustom straight-vc-git-upstream-remote \"upstream\"\n \"The remote name to use for the upstream remote.\nThis variable is deprecated, and only applies to usage of the\ndeprecated `:upstream' keyword.\"\n :type 'string)\n(make-obsolete-variable\n 'straight-vc-git-upstream-remote\n \"see `straight-vc-git-default-remote-name' and\n `straight-vc-git-default-fork-name' instead,\n but note that the semantics are different.\"\n \"2018-08-22\")\n\n(defcustom straight-vc-git-default-remote-name \"origin\"\n \"The remote name to use for the primary remote.\nFor a forked package, this means the upstream remote.\n\nYou can override the value of this variable on a per-package\nbasis using the `:remote' keyword.\"\n :type 'string)\n\n(defcustom straight-vc-git-default-fork-name \"fork\"\n \"The remote name to use for the fork remote in a forked package.\n\nYou can override the value of this variable on a per-package\nbasis using the `:remote' keyword in the `:fork' sub-plist.\"\n :type 'string)\n\n(defcustom straight-vc-git-default-protocol 'https\n \"The default protocol to use for auto-generated URLs.\nThis affects the URLs used when `:host' is `github', `gitlab', or\n`bitbucket'. It does not cause manually specified URLs to be\ntranslated.\n\nThis may be either `https' or `ssh'.\"\n :type '(choice (const :tag \"HTTPS\" https)\n (const :tag \"SSH\" ssh)))\n\n(defcustom straight-vc-git-force-protocol nil\n \"If non-nil, treat HTTPS and SSH URLs as incompatible.\nThis means that operations like `straight-normalize-package' will\nre-set the remote URLs for packages whose recipes have non-nil\n`:host' values, if they are using a different protocol than the\none specified in `straight-vc-git-default-protocol'.\"\n :type 'boolean)\n\n(defcustom straight-vc-git-auto-fast-forward t\n \"Whether to quietly fast-forward when pulling packages.\nThis suppresses popups for trivial remote changes (i.e. the\ncurrent HEAD is an ancestor to the remote HEAD).\nAlso re-attaches detached heads quietly when non-nil.\nA nil value allows for inspection of all remote changes.\"\n :type 'boolean)\n\n;;;;;; Utility functions\n\n(defmacro straight-vc-git--destructure (recipe props &rest body)\n \"Binding from RECIPE the given (virtual) PROPS, eval and return BODY.\nUnlike `straight--with-plist', this macro has special support for\nthe `:fork' sub-plist. In particular, the REPO, HOST, BRANCH, and\nREMOTE properties are taken from this sub-plist, while prepending\nthem with `upstream-' allows you to get the top-level values.\nPrepending with `fork-' is the same as the default behavior,\nexcept that if no `:fork' is configured then the values are bound\nto nil. Furthermore, default values for BRANCH and REMOTE are\ncomputed, based on the relevant user options, and the deprecated\n`:upstream' property and accompanying user options are handled\nappropriately.\"\n (declare\n (debug (form sexp body))\n (indent 2))\n (let ((recipe-sym (make-symbol \"--recipe--\"))\n (wrap-default\n (lambda (prop check value\n &optional fork upstream-check upstream-value)\n (pcase prop\n (`host\n `(cond\n (,check ,value)\n (,upstream-check ,upstream-value)\n (t nil)))\n (`branch\n `(cond\n (,check ,value)\n (,upstream-check ,upstream-value)\n (t straight-vc-git-default-branch)))\n (`remote\n `(cond\n (,check ,value)\n ,@(if fork\n `((t straight-vc-git-default-fork-name))\n `(((equal straight-vc-git-primary-remote \"origin\")\n straight-vc-git-default-remote-name)\n (t straight-vc-git-primary-remote)))))\n (_ value)))))\n `(let ((,recipe-sym ,recipe))\n (straight--with-plist ,recipe-sym\n (upstream repo host branch)\n (when upstream\n (setq ,recipe-sym (cl-copy-list ,recipe-sym))\n (setq ,recipe-sym\n (plist-put\n ,recipe-sym :fork\n ;; Can't use a backquote here because we're already\n ;; inside another backquote and we want to avoid\n ;; resolving variables like\n ;; `straight-vc-git-primary-remote' at\n ;; macroexpansion time.\n (list\n :repo repo\n :host host\n :branch (or branch straight-vc-git-default-branch)\n :remote straight-vc-git-primary-remote)))\n (dolist (kw '(:host :repo))\n (setq ,recipe-sym\n (plist-put ,recipe-sym kw (plist-get upstream kw))))\n (setq ,recipe-sym (plist-put ,recipe-sym :branch\n (or (plist-get upstream :branch)\n straight-vc-git-default-branch)))\n (setq ,recipe-sym\n (plist-put\n ,recipe-sym :remote straight-vc-git-upstream-remote))))\n (let (,@(mapcar (lambda (prop)\n `(,prop\n ,(let ((require-fork nil))\n (when (string-prefix-p\n \"fork-\" (symbol-name prop))\n (setq prop (intern\n (string-remove-prefix\n \"fork-\" (symbol-name prop))))\n (setq require-fork t))\n (let ((kw (intern (format \":%S\" prop))))\n (if (memq prop '(repo host branch remote))\n `(if-let ((fork (plist-get\n ,recipe-sym :fork)))\n ,(funcall\n wrap-default\n prop\n `(plist-member fork ',kw)\n `(plist-get fork ',kw)\n 'fork\n `(plist-member ,recipe-sym ',kw)\n `(plist-get ,recipe-sym ',kw))\n ,(unless require-fork\n (funcall\n wrap-default\n prop\n `(plist-member ,recipe-sym ',kw)\n `(plist-get ,recipe-sym ',kw))))\n (setq prop (intern\n (string-remove-prefix\n \"upstream-\"\n (symbol-name prop))))\n (setq kw (intern (format \":%S\" prop)))\n (funcall\n wrap-default\n prop\n `(plist-member ,recipe-sym ',kw)\n `(plist-get ,recipe-sym ',kw)))))))\n props))\n ,@body))))\n\n;; We don't define `straight--profile-cache' until later. I don't\n;; think it's possible to avoid the circular dependency in any sane\n;; way, since the VC layer is used to clone packages and we need to\n;; clone Magit here.\n(defvar straight--profile-cache)\n\n(cl-defun straight--magit-status (directory)\n \"Like `magit-status', but install Magit if necessary.\nMagit is only installed if the user responds to a `y-or-n-p'\nprompt. Return non-nil if Magit was installed. DIRECTORY is as in\n`magit-status'.\"\n (unless (or (require 'magit nil 'noerror)\n (gethash \"magit\" straight--profile-cache))\n (if (y-or-n-p \"Install Magit? \")\n (straight-use-package 'magit)\n (cl-return-from straight--magit-status)))\n (prog1 t\n (magit-status-setup-buffer directory)))\n\n(defun straight--recursive-edit ()\n \"Start a new recursive edit session.\nMake sure that other packages such as `server.el' don't cause us\nto loose our session.\"\n ;; Don't mess up recursive straight.el operations. The wonderful\n ;; thing about using our own variable is that since it's not\n ;; buffer-local, a recursive binding to nil is actually able to\n ;; undo the effects of the ambient binding.\n (cl-letf (((symbol-function 'top-level) #'ignore)\n (straight--default-directory nil))\n (recursive-edit)))\n\n(defun straight-vc-git--popup-raw (prompt actions)\n \"Same as `straight--popup-raw', but specialized for vc-git methods.\nTwo additional actions are inserted at the end of the list: \\\"e\\\"\nfor Dired and recursive edit, and \\\"g\\\" for Magit and recursive\nedit. Otherwise, PROMPT and ACTIONS are as for\n`straight--popup-raw'.\"\n (straight--popup-raw\n prompt\n (append\n actions\n '((\"e\" \"Dired and open recursive edit\"\n (lambda ()\n (dired (or straight--default-directory default-directory))\n (straight--recursive-edit)))\n (\"g\" \"Magit and open recursive edit\"\n (lambda ()\n (when (straight--magit-status\n (or straight--default-directory default-directory))\n (straight--recursive-edit))))))))\n\n(defmacro straight-vc-git--popup (prompt &rest actions)\n \"Same as `straight--popup', but specialized for vc-git methods.\nTwo additional actions are inserted at the end of the list: \\\"e\\\"\nfor Dired and recursive edit, and \\\"g\\\" for Magit and recursive\nedit. Otherwise, PROMPT and ACTIONS are as for\n`straight--popup'.\"\n (declare (indent defun))\n `(straight--popup\n ,prompt\n ,@actions\n (\"e\" \"Dired and open recursive edit\"\n (dired (or straight--default-directory default-directory))\n (straight--recursive-edit))\n (\"g\" \"Magit and open recursive edit\"\n (when (straight--magit-status\n (or straight--default-directory default-directory))\n (straight--recursive-edit)))))\n\n(defun straight-vc-git--encode-url (repo host &optional protocol)\n \"Generate a URL from a REPO depending on the value of HOST and PROTOCOL.\nREPO is a string which is either a URL or something of the form\n\\\"username/repo\\\", like \\\"raxod502/straight.el\\\". If HOST is one\nof the symbols `github', `gitlab', or `bitbucket', then REPO is\ntransformed into a standard SSH URL for the corresponding\nservice; otherwise, HOST should be nil, and in that case REPO is\nreturned unchanged. PROTOCOL must be either `https' or `ssh'; if\nit is omitted, it defaults to `straight-vc-git-default-protocol'.\nSee also `straight-vc-git--decode-url'.\"\n (pcase host\n ;; Use backquote instead of regular quote here for compatibility\n ;; with Emacs 24.5.\n (`nil repo)\n ((or `github `gitlab `bitbucket)\n (let ((domain (pcase host\n (`bitbucket \"bitbucket.org\")\n (_ (format \"%s.com\" host)))))\n (pcase (or protocol straight-vc-git-default-protocol)\n (`https\n (format \"https://%s/%s.git\" domain repo))\n (`ssh\n (format \"git@%s:%s.git\" domain repo))\n (_ (error \"Unknown protocol: %S\" protocol)))))\n (_ (error \"Unknown value for host: %S\" host))))\n\n(defun straight-vc-git--decode-url (url)\n \"Separate a URL into a REPO, HOST, and PROTOCOL, returning a list of them.\nAll common forms of HTTPS and SSH URLs are accepted for GitHub,\nGitLab, and Bitbucket. If one is recognized, then HOST is one of\nthe symbols `github', `gitlab', or `bitbucket', and REPO is a\nstring of the form \\\"username/repo\\\". Otherwise HOST is nil and\nREPO is just URL. In any case, PROTOCOL is either `https', `ssh',\nor nil (if the protocol cannot be determined, which happens when\nHOST is nil). See also `straight-vc-git--encode-url'.\"\n (let ((protocol nil)\n (matched t))\n (or (and (string-match\n \"^git@\\\\(.+?\\\\):\\\\(.+?\\\\)\\\\(?:\\\\.git\\\\)?$\"\n url)\n (setq protocol 'ssh))\n (and (string-match\n \"^ssh://git@\\\\(.+?\\\\)/\\\\(.+?\\\\)\\\\(?:\\\\.git\\\\)?$\"\n url)\n (setq protocol 'ssh))\n (and (string-match\n \"^https://\\\\(.+?\\\\)/\\\\(.+?\\\\)\\\\(?:\\\\.git\\\\)?$\"\n url)\n (setq protocol 'https))\n ;; We have to take care of this case separately because if\n ;; `string-match' doesn't actually match anything, then\n ;; `match-string' has undefined behavior.\n (setq matched nil))\n (pcase (and matched (match-string 1 url))\n (\"github.com\" (list (match-string 2 url) 'github protocol))\n (\"gitlab.com\" (list (match-string 2 url) 'gitlab protocol))\n (\"bitbucket.org\" (list (match-string 2 url) 'bitbucket protocol))\n (_ (list url nil nil)))))\n\n(defun straight-vc-git--urls-compatible-p (url1 url2)\n \"Return non-nil if URL1 and URL2 can be treated as equivalent.\nThis means that `straight-vc-git--decode-url' returns the same\nfor both (but if `straight-vc-git-force-protocol' is nil, then\nthe returned protocol is allowed to differ). For example, HTTPS\nand SSH URLs for the same repository are equivalent (unless\n`straight-vc-git-force-protocol' is non-nil), and it does not\nmatter if a GitHub URL is suffixed with .git or not.\"\n (let ((spec1 (straight-vc-git--decode-url url1))\n (spec2 (straight-vc-git--decode-url url2)))\n (if straight-vc-git-force-protocol\n (equal spec1 spec2)\n ;; Only compare the first two elements; ignore the third, which\n ;; is the protocol.\n (equal (cl-subseq spec1 0 2)\n (cl-subseq spec2 0 2)))))\n\n(defun straight-vc-git--list-remotes ()\n \"Return a list of Git remotes as strings for the current directory.\nDo not suppress unexpected errors.\"\n ;; Git remote names cannot have whitespace in them, thank goodness.\n (straight--split-and-trim (straight--get-call \"git\" \"remote\")))\n\n;;;;;; Validation functions\n\n(cl-defun straight-vc-git--ensure-remote (local-repo remote desired-url)\n \"Ensure that LOCAL-REPO has REMOTE set to DESIRED-URL or equivalent.\nAll three arguments are strings. The URL of the REMOTE does not\nnecessarily need to match DESIRED-URL; it just has to satisfy\n`straight-vc-git--urls-compatible-p'.\"\n ;; Always return nil unless we use `cl-return-from'.\n (ignore\n (if-let ((actual-url (condition-case nil\n (straight--get-call\n \"git\" \"remote\" \"get-url\" remote)\n (error nil))))\n (if (straight-vc-git--urls-compatible-p\n actual-url desired-url)\n ;; This is the only case where we return non-nil.\n (cl-return-from straight-vc-git--ensure-remote t)\n (let ((new-remote (straight--uniquify\n remote\n (straight-vc-git--list-remotes))))\n (straight-vc-git--popup\n (format \"In repository %S, remote %S has URL\n %S\nbut recipe specifies a URL of\n %S\"\n local-repo remote actual-url desired-url)\n (\"r\" (format (concat \"Rename remote %S to %S, \"\n \"re-create %S with correct URL, and fetch\")\n remote new-remote remote)\n (straight--get-call\n \"git\" \"remote\" \"rename\" remote new-remote)\n (straight--get-call\n \"git\" \"remote\" \"add\" remote desired-url)\n (straight--get-call\n \"git\" \"fetch\" remote))\n (\"R\" (format (concat \"Rename remote %S manually, re-create \"\n \"it with correct URL, and fetch\")\n remote)\n (straight--get-call\n \"git\" \"remote\" \"rename\" remote\n (read-string \"Enter new remote name: \"))\n (straight--get-call\n \"git\" \"remote\" \"add\" remote desired-url)\n (straight--get-call\n \"git\" \"fetch\" remote))\n (\"d\" (format (concat \"Delete remote %S, re-create it \"\n \"with correct URL, and fetch\")\n remote)\n (when (straight-are-you-sure\n (format \"Really delete remote %S?\" remote))\n (straight--get-call\n \"git\" \"remote\" \"remove\" remote)\n (straight--get-call\n \"git\" \"remote\" \"add\" remote desired-url)\n (straight--get-call\n \"git\" \"fetch\" remote)))\n (\"D\" (format (concat \"Delete remote %S, re-create it \"\n \"with manually set URL, and fetch\")\n remote)\n (when (straight-are-you-sure\n (format \"Really delete remote %S?\" remote))\n (straight--get-call\n \"git\" \"remote\" \"remove\" remote)\n (straight--get-call\n \"git\" \"remote\" \"add\" remote\n (read-string \"Enter new remote URL: \"))\n (straight--get-call\n \"git\" \"fetch\" remote))))))\n ;; General policy is that if we make any modifications\n ;; whatsoever, then validation fails. You never know when you\n ;; might run into a weird edge case of Git and have an operation\n ;; unexpectedly violate a previously established assumption.\n (straight--get-call\n \"git\" \"remote\" \"add\" remote desired-url))))\n\n(cl-defun straight-vc-git--ensure-remotes (recipe)\n \"Ensure that repository for RECIPE has remotes set correctly.\nRECIPE is a straight.el-style plist.\n\nThis means the primary and fork remotes, if configured, have\ntheir URLs set to the same as what is specified in the RECIPE.\nThe URLs do not necessarily need to match exactly; they just have\nto satisfy `straight-vc-git--urls-compatible-p'.\"\n (straight-vc-git--destructure recipe\n (local-repo upstream-repo upstream-host upstream-remote\n fork-repo fork-host fork-remote)\n (and (or (null upstream-repo)\n (straight-vc-git--ensure-remote\n local-repo\n upstream-remote\n (straight-vc-git--encode-url\n upstream-repo upstream-host)))\n (or (null fork-repo)\n (straight-vc-git--ensure-remote\n local-repo\n fork-remote\n (straight-vc-git--encode-url\n fork-repo fork-host))))))\n\n;; The following handles only merges, not rebases. See\n;; https://github.com/raxod502/straight.el/issues/271.\n(defun straight-vc-git--ensure-nothing-in-progress (local-repo)\n \"Ensure that no merge conflict is active in LOCAL-REPO.\nLOCAL-REPO is a string.\"\n (let ((conflicted-files\n (string-remove-suffix\n \"\\n\"\n (straight--get-call\n \"git\" \"ls-files\" \"--unmerged\"))))\n (or (string-empty-p conflicted-files)\n (ignore\n (straight-vc-git--popup\n (format \"Repository %S has a merge conflict:\\n%s\"\n local-repo\n (straight--split-and-trim\n conflicted-files 2))\n (\"a\" \"Abort merge\"\n (straight--get-call \"git\" \"merge\" \"--abort\")))))))\n\n(cl-defun straight-vc-git--ensure-worktree (local-repo)\n \"Ensure that LOCAL-REPO has a clean worktree.\nLOCAL-REPO is a string.\"\n (let ((status (straight--get-call-raw\n \"git\" \"-c\" \"status.branch=false\"\n \"status\" \"--short\")))\n (if (string-empty-p status)\n (cl-return-from straight-vc-git--ensure-worktree t)\n (straight-vc-git--popup\n (format \"Repository %S has a dirty worktree:\\n\\n%s\"\n local-repo\n (straight--split-and-trim\n status 2))\n (\"z\" \"Stash changes\"\n (let ((msg (read-string \"Optional stash message: \")))\n (if (string-empty-p msg)\n (straight--get-call\n \"git\" \"stash\" \"push\" \"--include-untracked\")\n (straight--get-call\n \"git\" \"stash\" \"save\" \"--include-untracked\" msg))))\n (\"d\" \"Discard changes\"\n (when (straight-are-you-sure\n (format \"Discard all local changes permanently?\"))\n (and (straight--get-call \"git\" \"reset\" \"--hard\")\n (straight--get-call \"git\" \"clean\" \"-ffd\"))))))))\n\n(cl-defun straight-vc-git--ensure-head (local-repo branch &optional ref)\n \"Ensure that LOCAL-REPO has BRANCH checked out.\nIf REF is non-nil, instead ensure that BRANCH is ahead of REF.\nAny untracked files created by checkout will be deleted without\nconfirmation, so this function should only be run after\n`straight-vc-git--ensure-worktree' has passed.\"\n (ignore\n (let* ((cur-branch (straight--get-call\n \"git\" \"rev-parse\" \"--abbrev-ref\" \"HEAD\"))\n (head-detached-p (string= cur-branch \"HEAD\"))\n (ref-name (or ref \"HEAD\"))\n (quoted-ref-name (if ref (format \"%S\" ref) \"HEAD\")))\n (cond\n ((and ref\n (not (straight--check-call\n \"git\" \"rev-parse\" ref)))\n (error \"Branch %S does not exist\" ref))\n ((and (null ref) (string= branch cur-branch))\n (cl-return-from straight-vc-git--ensure-head t))\n ((and (null ref) head-detached-p)\n ;; Detached HEAD, either attach to configured branch\n ;; automatically or ask the user.\n (if straight-vc-git-auto-fast-forward\n (straight--get-call \"git\" \"checkout\" branch)\n (straight-vc-git--popup\n (format\n \"In repository %S, HEAD is even with branch %S, but detached.\"\n local-repo branch)\n (\"a\" (format \"Attach HEAD to branch %S\" branch)\n (straight--get-call \"git\" \"checkout\" branch)))))\n (t\n (let ((ref-ahead-p (straight--check-call\n \"git\" \"merge-base\" \"--is-ancestor\"\n branch ref-name))\n (ref-behind-p (straight--check-call\n \"git\" \"merge-base\" \"--is-ancestor\"\n ref-name branch)))\n (when (and ref ref-behind-p)\n (cl-return-from straight-vc-git--ensure-head t))\n (when (and ref ref-ahead-p straight-vc-git-auto-fast-forward)\n ;; Local is behind, catch up.\n (straight--get-call \"git\" \"reset\" \"--hard\" ref-name)\n ;; Return nil to signal that we're not quite done. In some\n ;; cases a reset might leave untracked files.\n (cl-return-from straight-vc-git--ensure-head nil))\n (straight-vc-git--popup-raw\n (concat\n (format \"In repository %S, \" local-repo)\n (if ref\n (cond\n (ref-behind-p\n (cl-return-from straight-vc-git--ensure-head t))\n (ref-ahead-p\n (format \"branch %S is behind %S\" branch ref))\n (t (format \"branch %S has diverged from %S\" branch ref)))\n (let ((on-branch (if head-detached-p \"\"\n (format \" (on branch %S)\"\n cur-branch))))\n (cond\n (ref-ahead-p\n (format \"HEAD%s is ahead of branch %S\" on-branch branch))\n (ref-behind-p\n (format \"HEAD%s is behind branch %S\" on-branch branch))\n (t (format \"HEAD%s has diverged from branch %S\"\n on-branch branch))))))\n ;; Here be dragons! Watch the quoting very carefully in\n ;; order to get the lexical scoping to work right, and don't\n ;; confuse this syntax with the syntax of the\n ;; `straight--popup' macro.\n `(,@(when ref-ahead-p\n `((\"f\" ,(format \"Fast-forward branch %S to %s\"\n branch quoted-ref-name)\n ,(lambda ()\n (straight--get-call\n \"git\" \"reset\" \"--hard\" ref-name)))))\n ,@(when (and ref-behind-p (null ref))\n `((\"f\" ,(format \"Fast-forward HEAD to branch %S\" branch)\n ,(lambda ()\n (straight--get-call\n \"git\" \"checkout\" branch)))))\n ,@(unless (or ref-ahead-p ref-behind-p)\n `((\"m\" ,(format \"Merge %s to branch %S\" quoted-ref-name branch)\n ,(lambda ()\n (if ref\n (straight--check-call\n \"git\" \"merge\" ref)\n (let ((orig-head\n (straight--get-call\n \"git\" \"rev-parse\" \"HEAD\")))\n (straight--get-call\n \"git\" \"checkout\" branch)\n ;; Merge might not succeed, so don't throw\n ;; on error.\n (straight--check-call\n \"git\" \"merge\" orig-head)))))\n (\"r\" ,(format \"Reset branch %S to %s\"\n branch quoted-ref-name)\n ,(lambda ()\n (straight--get-call\n \"git\" \"reset\" \"--hard\" ref-name)))\n ,@(unless ref\n `((\"c\" ,(format \"Reset HEAD to branch %S\" branch)\n ,(lambda ()\n (straight--get-call\n \"git\" \"checkout\" branch)))))\n ,(if ref\n `(\"R\" ,(format \"Rebase branch %S onto %S\" branch ref)\n ,(lambda ()\n ;; Rebase might fail, don't throw on\n ;; error.\n (straight--check-call\n \"git\" \"rebase\" ref branch)))\n `(\"R\" ,(format (concat \"Rebase HEAD onto branch %S \"\n \"and fast-forward %S to HEAD\")\n branch branch)\n ,(lambda ()\n ;; If the rebase encounters a conflict, no\n ;; sweat: the possibility of a fast-forward\n ;; will be detected elsewhere in this\n ;; function the next time around. But we\n ;; might as well finish the job if we can.\n (and (straight--check-call\n \"git\" \"rebase\" branch)\n (straight--get-call\n \"git\" \"reset\" \"--hard\" ref-name)))))))))))))))\n\n(cl-defun straight-vc-git--merge-from-remote-raw (recipe remote remote-branch)\n \"Using straight.el-style RECIPE, merge from REMOTE.\nREMOTE is a string. REMOTE-BRANCH is the branch in REMOTE that is\nused; it should be a string that is not prefixed with a remote\nname.\"\n (straight-vc-git--destructure recipe\n (local-repo branch)\n (while t\n (and (straight-vc-git--ensure-local recipe)\n (or (straight-vc-git--ensure-head\n local-repo branch (format \"%s/%s\" remote remote-branch))\n (straight-register-repo-modification local-repo))\n (cl-return-from straight-vc-git--merge-from-remote-raw t)))))\n\n(cl-defun straight-vc-git--pull-from-remote-raw (recipe remote remote-branch)\n \"Using straight.el-style RECIPE, pull from REMOTE.\nREMOTE is a string. REMOTE-BRANCH is the branch in REMOTE that is\nused; it should be a string that is not prefixed with a remote\nname.\"\n (straight-vc-git-fetch-from-remote recipe)\n (straight-vc-git--merge-from-remote-raw recipe remote remote-branch))\n\n(cl-defun straight-vc-git--ensure-head-pushed\n (recipe)\n \"Ensure that in RECIPE's local repo, main branch is behind primary remote.\nReturn non-nil. If no local repository, do nothing and return non-nil.\"\n (cl-block nil\n (straight-vc-git--destructure recipe\n (local-repo repo branch remote)\n (unless repo\n (cl-return t))\n (let ((push-error-message nil))\n (while t\n (while (not (straight-vc-git--ensure-local recipe)))\n (let ((ref (format \"%s/%s\" remote branch)))\n (when (straight--check-call\n \"git\" \"merge-base\" \"--is-ancestor\"\n branch ref)\n (cl-return t))\n (let* ((log (straight--get-call\n \"git\" \"log\" \"--format=%h %s\"\n (concat ref \"..\" branch)))\n (num-commits (length (straight--split-and-trim log))))\n (straight-vc-git--popup\n (format\n (concat \"In repository %S, branch %S has %d \"\n \"commit%s unpushed to %S%s:\\n\\n%s\")\n local-repo branch num-commits (if (= num-commits 1) \"\" \"s\")\n ref (if (> num-commits 5) \", including\" \"\")\n (concat\n (straight--split-and-trim log 2 5)\n (when push-error-message\n (concat \"\\n\\nPush failed:\\n\\n \"\n push-error-message))))\n (\"f\" (format \"Pull %S into branch %S\" ref branch)\n (straight-vc-git--pull-from-remote-raw recipe remote branch))\n (\"p\" (format \"Push branch %S to %S\" branch ref)\n (when (straight-are-you-sure\n (format \"Really push to %S in %S?\" ref local-repo))\n (straight--catching-quit\n (let ((result\n (straight--call\n \"git\" \"push\" remote\n (format\n \"refs/heads/%s:refs/heads/%s\" branch branch))))\n (unless (car result)\n (setq push-error-message\n (string-trim (cdr result))))))))))))))))\n\n(defun straight-vc-git--ensure-local (recipe)\n \"Ensure that local repository for RECIPE is as expected.\nThis means that the remote URLs are set correctly; there is no\nmerge currently in progress; the worktree is pristine; and the\nprimary :branch is checked out. The reason for \\\"local\\\" in the\nname of this function is that no network communication is done\nwith the remotes.\"\n (straight-vc-git--destructure recipe\n (local-repo branch)\n (and (straight-vc-git--ensure-remotes recipe)\n (or (and (straight-vc-git--ensure-nothing-in-progress local-repo)\n (straight-vc-git--ensure-worktree local-repo)\n (straight-vc-git--ensure-head local-repo branch))\n (straight-register-repo-modification local-repo)))))\n\n(defcustom straight-vc-git-default-clone-depth 'full\n \"The default value for `:depth' when `:type' is the symbol `git'.\n\nThe value should be the symbol `full' or an integer. If the value\nis `full', clone the whole history of repositories. If the value is\nan integer N, remote repositories are cloned with the option --depth N,\nunless a commit is specified (e.g. by version lockfiles).\"\n :group 'straight\n :type '(choice integer (const full)))\n\n(cl-defun straight-vc-git--clone-internal\n (&key depth upstream-remote url repo-dir branch)\n \"Clone a remote repository from URL.\n\nIf DEPTH is the symbol `full', clone the whole history of the repository.\nIf DEPTH is an integer, clone with the option --depth DEPTH --branch BRANCH.\nIf this fails, try again to clone without the option --depth and --branch,\nas a fallback.\n\nUPSTREAM-REMOTE is the name of the remote to use for the upstream\n\\(e.g. \\\"origin\\\"; see `straight-vc-git-default-remote-name').\nURL and REPO-DIR are the positional arguments passed to\ngit-clone(1), and BRANCH is the name of the default\nbranch (although it won't be checked out as per --no-checkout).\"\n (cond\n ((eq depth 'full)\n ;; Clone the whole history of the repository.\n (straight--get-call\n \"git\" \"clone\" \"--origin\" upstream-remote\n \"--no-checkout\" url repo-dir))\n ((integerp depth)\n ;; Do a shallow clone.\n (condition-case nil\n (straight--get-call\n \"git\" \"clone\" \"--origin\" upstream-remote\n \"--no-checkout\" url repo-dir\n \"--depth\" (number-to-string depth)\n \"--branch\" branch)\n ;; Fallback for dumb http protocol.\n (error (straight-vc-git--clone-internal :depth 'full\n :upstream-remote upstream-remote\n :url url\n :repo-dir repo-dir))))\n (t (error \"Invalid value %S of depth for %s\" depth url))))\n\n;;;;;; API\n\n(defun straight-vc-git-clone (recipe commit)\n \"Clone local REPO for straight.el-style RECIPE, checking out COMMIT.\nCOMMIT is a 40-character SHA-1 Git hash. If it cannot be checked\nout, signal a warning. If COMMIT is nil, check out the branch\nspecified in RECIPE instead. If that fails, signal a warning.\"\n (straight-vc-git--destructure recipe\n (package local-repo branch remote upstream-repo upstream-host\n upstream-remote fork-repo fork-host\n fork-remote nonrecursive depth)\n (unless upstream-repo\n (error \"No `:repo' specified for package `%s'\" package))\n (let ((success nil)\n (repo-dir (straight--repos-dir local-repo))\n (url (straight-vc-git--encode-url upstream-repo upstream-host))\n (depth (or (when commit 'full)\n depth\n straight-vc-git-default-clone-depth)))\n (unwind-protect\n (progn\n (straight-vc-git--clone-internal :depth depth\n :upstream-remote upstream-remote\n :url url\n :repo-dir repo-dir\n :branch branch)\n (let ((straight--default-directory nil)\n (default-directory repo-dir))\n (when fork-repo\n (let ((url (straight-vc-git--encode-url fork-repo fork-host)))\n (straight--get-call \"git\" \"remote\" \"add\" fork-remote url)\n (straight--get-call \"git\" \"fetch\" fork-remote)))\n (when commit\n (unless (straight--check-call \"git\" \"checkout\" commit)\n (straight--warn\n \"Could not check out commit %S in repository %S\"\n commit local-repo)\n ;; We couldn't check out the commit, best to proceed\n ;; as if we weren't given one.\n (setq commit nil)))\n (unless commit\n (unless (straight--check-call\n \"git\" \"checkout\" \"-B\" branch\n (format \"%s/%s\" remote branch))\n (straight--warn\n \"Could not check out branch %S of repository %S\"\n branch local-repo)\n ;; Since we passed --no-checkout, we need to\n ;; explicitly check out *something*, even if it's\n ;; not the right thing.\n (straight--get-call \"git\" \"checkout\" \"HEAD\")))\n (unless nonrecursive\n (straight--get-call\n \"git\" \"submodule\" \"update\" \"--init\" \"--recursive\")))\n (setq success t))\n ;; Make cloning an atomic operation.\n (unless success\n (when (file-exists-p repo-dir)\n (delete-directory repo-dir 'recursive)))))))\n\n(cl-defun straight-vc-git-normalize (recipe)\n \"Using straight.el-style RECIPE, make the repository locally sane.\nThis means that its remote URLs are set correctly; there is no\nmerge currently in progress; its worktree is pristine; and the\nprimary :branch is checked out.\"\n (straight-vc-git--destructure recipe\n (local-repo)\n (while t\n (and (or (straight-vc-git--ensure-local recipe)\n (straight-register-repo-modification local-repo))\n (cl-return-from straight-vc-git-normalize t)))))\n\n(cl-defun straight-vc-git-fetch-from-remote (recipe &optional from-upstream)\n \"Using straight.el-style RECIPE, fetch from the primary remote.\nIf FROM-UPSTREAM is non-nil, fetch from the upstream remote\ninstead, if the recipe configures a fork. The FROM-UPSTREAM\nargument is not part of the VC API.\"\n (cl-block nil\n (straight-vc-git--destructure recipe\n (upstream-repo upstream-remote repo remote fork)\n (when (and from-upstream (not fork))\n (cl-return t))\n (let ((repo (if from-upstream upstream-repo repo))\n (remote (if from-upstream upstream-remote remote)))\n (unless repo\n (cl-return t))\n (while t\n (and (straight-vc-git--ensure-remotes recipe)\n (straight--get-call \"git\" \"fetch\" remote)\n (cl-return t)))))))\n\n(cl-defun straight-vc-git-fetch-from-upstream (recipe)\n \"Using straight.el-style RECIPE, fetch from the upstream remote.\nIf RECIPE does not configure a fork, do nothing.\"\n (straight-vc-git-fetch-from-remote recipe 'from-upstream))\n\n(cl-defun straight-vc-git-merge-from-remote (recipe &optional from-upstream)\n \"Using straight.el-style RECIPE, merge from the primary remote.\nIf FROM-UPSTREAM is non-nil, merge from the upstream remote\ninstead, if RECIPE configures a fork. The FROM-UPSTREAM argument\nis not part of the VC API.\"\n (cl-block nil\n (straight-vc-git--destructure recipe\n (upstream-repo upstream-branch upstream-remote\n repo branch remote fork)\n (when (and from-upstream (not fork))\n (cl-return t))\n (let ((remote-branch (if from-upstream upstream-branch branch))\n (repo (if from-upstream upstream-repo repo))\n (remote (if from-upstream upstream-remote remote)))\n (unless repo\n (cl-return t))\n (straight-vc-git--merge-from-remote-raw\n recipe remote remote-branch)))))\n\n(defun straight-vc-git-merge-from-upstream (recipe)\n \"Using straight.el-style RECIPE, merge from upstream.\nIf RECIPE does not configure a fork, do nothing.\"\n (straight-vc-git-merge-from-remote recipe 'from-upstream))\n\n(cl-defun straight-vc-git-push-to-remote (recipe)\n \"Using straight.el-style RECIPE, push to primary remote, if necessary.\"\n (straight-vc-git--ensure-head-pushed recipe))\n\n(cl-defun straight-vc-git-check-out-commit (recipe commit)\n \"In RECIPE's repo, normalize and check out COMMIT.\nRECIPE is a straight.el-style recipe. COMMIT is a 40-character\nstring identifying a Git commit.\"\n (straight-vc-git--destructure recipe\n (local-repo)\n (cl-block nil\n (while t\n (or (and (straight-vc-git--ensure-nothing-in-progress local-repo)\n (straight-vc-git--ensure-worktree local-repo)\n (straight-vc-git--ensure-local recipe)\n (or (equal\n commit (straight--get-call \"git\" \"rev-parse\" \"HEAD\"))\n (straight--get-call \"git\" \"reset\" \"--hard\" commit))\n (cl-return))\n (straight-register-repo-modification local-repo))))))\n\n(cl-defun straight-vc-git-commit-present-p (_local-repo commit)\n \"Return non-nil if LOCAL-REPO has COMMIT present locally.\"\n (straight--check-call \"git\" \"rev-parse\" \"-q\" \"--verify\"\n (format \"%s^{commit}\" commit)))\n\n(defun straight-vc-git-get-commit (_local-repo)\n \"Return the current commit for the current local repository.\nThis is a 40-character string identifying the current position of\nHEAD in the Git repository.\"\n (straight--get-call \"git\" \"rev-parse\" \"HEAD\"))\n\n(defun straight-vc-git-local-repo-name (recipe)\n \"Generate a repository name from straight.el-style RECIPE.\nFor the GitHub, GitLab, and Bitbucket hosts, the repository name\nis used as-is. Otherwise, an attempt is made to extract the\nrepository name from the URL. This may still fail, and nil is\nthen returned.\"\n (straight--with-plist recipe\n (repo host)\n (if host\n (replace-regexp-in-string\n \"^.+/\" \"\" repo)\n ;; The following is a half-hearted attempt to turn arbitrary\n ;; URLs into reasonable repository names.\n (let ((regexp \"^.*/\\\\(.+\\\\)\\\\.git$\"))\n ;; If this regexp does not match, just return nil.\n (when (string-match regexp repo)\n (match-string 1 repo))))))\n\n(defun straight-vc-git-keywords ()\n \"Return a list of keywords used by the VC backend for Git.\"\n '(:repo :host :branch :remote :nonrecursive :upstream :fork :depth))\n\n;;;; Fetching repositories\n\n(defun straight--repository-is-available-p (recipe)\n \"Determine if the repository for the RECIPE exists locally.\"\n (straight--with-plist recipe\n (local-repo)\n (file-exists-p (straight--repos-dir local-repo))))\n\n(defun straight--clone-repository (recipe &optional cause)\n \"Clone the repository for the RECIPE, erroring if it already exists.\nCAUSE is a string indicating the reason this repository is being\ncloned.\"\n (straight--with-plist recipe\n (package local-repo)\n (make-directory (straight--repos-dir) 'parents)\n (straight--with-progress\n (concat cause (when cause straight-arrow)\n (format \"Cloning %s\" local-repo)\n ;; If this `member' check fails, then it means the\n ;; repository has a name that is substantially\n ;; different than the package name, and the user might\n ;; be confused about why we are cloning it.\n (unless (member local-repo\n (list\n package\n (format \"%s.el\" package)\n (format \"emacs-%s\" package)))\n (format \" (for %s)\" package)))\n (straight-vc-clone recipe))\n ;; We messed up the echo area.\n (setq straight--echo-area-dirty t)))\n\n;;;; Recipe handling\n;;;;; Built-in packages\n\n(defvar straight--cached-built-in-packages nil\n \"Hash table mapping package names to booleans.\nAll packages that are built in are mapped to non-nil. The value\nof this variable is computed the first time\n`straight--package-built-in-p' is called.\")\n\n(defun straight--package-built-in-p (package)\n \"Given PACKAGE symbol, return non-nil if it's built in to Emacs.\nThe return value of this function might change between different\nversions of Emacs for the same package.\n\nIf a package is built in, then the package won't be listed in GNU\nELPA (Mirror) and it won't be an error if no recipe can be found\nfor it.\"\n (unless straight--cached-built-in-packages\n (require 'finder-inf)\n (let ((table (make-hash-table)))\n (dolist (cell package--builtins)\n (puthash (car cell) t table))\n (setq straight--cached-built-in-packages table)))\n (gethash package straight--cached-built-in-packages))\n\n;;;;; Declaration of caches\n\n(defvar straight--recipe-cache (make-hash-table :test #'equal)\n \"Hash table listing known recipes by package.\nThe keys are strings naming packages, and the values are the last\nknown recipe for that package. This is used for detecting\nconflicting recipes for the same package; managing the build\ncache and versions lockfile; and getting a list of all packages\nin use.\")\n\n(defvar straight--repo-cache (make-hash-table :test #'equal)\n \"Hash table listing known recipes by repository.\nThe keys are strings naming repositories, and the values are the\nlast known recipe that referenced the corresponding repository.\nThis is used for detecting conflicts (when multiple packages are\nversioned in the same repository, but are specified with\nincompatible recipes) and for silently adjusting recipes drawn\nfrom recipe repositories so as to avoid conflicts.\")\n\n(defvar straight--profile-cache (make-hash-table :test #'equal)\n \"Hash table mapping packages to lists of profiles.\nThe keys are strings naming packages, and the values are lists of\nsymbols identifying package profiles. These symbols are the\nvalues that you bind `straight-current-profile' to, and they\nshould each have an entry in `straight-profiles'.\")\n\n(defvar straight--recipe-lookup-cache nil\n \"Hash table keeping track of cached recipe lookups, or nil.\nThe keys are strings naming recipe repositories (i.e. specific\npackage names), and the values are hash tables recording cached\ndata for those recipe repositories. The value hash tables have\nkeys which are strings naming packages and values which are\nMELPA-style recipes, or nil (meaning that the recipe repository\ndid not have a recipe for the package).\")\n\n(defvar straight--profile-cache-valid nil\n \"Non-nil if `straight--profile-cache' accurately reflects the init-file.\nThe function `straight-freeze-versions' will be reluctant to\ncreate a version lockfile if this variable is nil. This variable\nis set to non-nil in the bootstrap code, and set back to nil when\n`straight-use-package' is invoked outside of init.\")\n\n(defvar straight--functional-p nil\n \"Non-nil if package operations are guaranteed to be functional.\nThis means they faithfully represent the contents of the\ninit-file. If package operations are performed when this variable\nis nil, then `straight--profile-cache-valid' is set to nil.\")\n\n(defun straight--reset-caches ()\n \"Reset caches tied to the init process.\nThis means `straight--recipe-cache', `straight--repo-cache', and\n`straight--profile-cache'. (We don't ever want to reset the build\ncache since it is a totally separate system from the caches\nemployed by `straight--convert-recipe', and we don't ever want to\nreset the success cache since that would mean the user would\nreceive a duplicate message if they called `straight-use-package'\ninteractively, reloaded their init-file, and then called\n`straight-use-package' on the same package again. The recipe\nlookup cache is also part of the build cache.)\n\nAlso manage the internal variables\n`straight--profile-cache-valid' and `straight--functional-p'\nusing the transaction system.\"\n (setq straight--recipe-cache (make-hash-table :test #'equal))\n (setq straight--repo-cache (make-hash-table :test #'equal))\n (setq straight--profile-cache (make-hash-table :test #'equal))\n (setq straight--profile-cache-valid t)\n (straight--transaction-exec\n 'reset-caches\n :now\n (lambda ()\n (setq straight--functional-p t))\n :later\n (lambda ()\n (setq straight--functional-p nil))))\n\n;;;;; Recipe repositories\n\n(defvar straight--recipe-repository-stack nil\n \"A list of recipe repositories that are currently being searched.\nThis is used to detect and prevent an infinite recursion when\nsearching for recipe repository recipes in other recipe\nrepositories.\n\nIf you set this globally to something other than nil, beware of\nvelociraptors.\")\n\n(defun straight-recipes (method name cause &rest args)\n \"Call a recipe backend method.\nMETHOD is a symbol naming a backend method, like symbol\n`retrieve'. NAME is a symbol naming the recipe repository, like\nsymbol `melpa'.\n\nIf the package repository is not available, clone it. If the\npackage cannot be found, return nil. CAUSE is a string explaining\nwhy the recipe repository might need to be cloned.\n\nARGS are passed to the method.\n\nThis function sets `default-directory' appropriately, handles\ncloning the repository if necessary, and then delegates to the\nappropriate `straight-recipes-NAME-METHOD' function.\n\nFor example:\n (straight-recipes \\\\='retrieve \\\\='melpa ...)\n=> (straight-recipes-melpa-retrieve ...)\"\n (unless (memq name straight--recipe-repository-stack)\n (let ((straight--recipe-repository-stack\n (cons name straight--recipe-repository-stack)))\n ;; This is purely for cloning the recipe repository. It's\n ;; explicitly *not* designed to support the use case of looking\n ;; up the recipe for one recipe repository inside another recipe\n ;; repository without first running `straight-register-package'\n ;; for the first recipe repository ahead of time (doing so\n ;; produces undefined behavior).\n (straight-use-package name nil nil cause)\n (let ((recipe (straight--convert-recipe name cause)))\n (straight--with-plist recipe\n (local-repo)\n (let ((default-directory\n ;; Only change directories if a local repository is\n ;; specified. If one is not, then we assume the\n ;; recipe repository code does not need to be in any\n ;; particular directory.\n (if local-repo\n (straight--repos-dir local-repo)\n default-directory))\n (func (intern (format \"straight-recipes-%S-%S\"\n name method))))\n (apply func args)))))))\n\n(defun straight-recipes-retrieve (package &optional sources cause)\n \"Look up a PACKAGE recipe in one or more SOURCES.\nPACKAGE should be a symbol, and SOURCES should be a list that is\na subset of `straight-recipe-repositories'. (If it is omitted, it\ndefaults to allowing all sources in\n`straight-recipe-repositories'.) If the recipe is not found in\nany of the provided sources, return nil. CAUSE is a string\nindicating the reason recipe repositories might need to be\ncloned.\"\n ;; Oh god, I lost so much time debugging this because package names\n ;; are usually strings at this level of the code.\n (setq package (symbol-name package))\n (let* (;; If `sources' is omitted, allow all sources.\n (sources (or sources straight-recipe-repositories))\n ;; Update the `cause' to explain why repositories might be\n ;; getting cloned.\n (cause (concat cause (when cause straight-arrow)\n (format \"Looking for %s recipe\" package))))\n (cl-dolist (source sources)\n (let ((table (gethash source straight--recipe-lookup-cache)))\n (if (and table (straight--checkhash package table))\n ;; Don't `cl-return' nil anywhere in this method. That will\n ;; prevent us from checking the other recipe repositories.\n (when-let ((recipe (gethash package table)))\n (cl-return recipe))\n (when-let\n ((recipe\n ;; NB: we use strings for the package names. This is\n ;; not just for convenience; it also allows us to\n ;; support having a package called `version' while\n ;; simultaneously using a symbol key called `version'\n ;; to keep track of the recipe repository lookup logic\n ;; version number.\n (puthash package\n (straight-recipes 'retrieve source cause\n (intern package))\n (or (gethash source straight--recipe-lookup-cache)\n (let ((table (make-hash-table :test #'equal))\n (func (intern\n (format\n \"straight-recipes-%S-version\"\n source))))\n (when-let ((version (and (fboundp func)\n (funcall func))))\n (puthash 'version version table))\n (puthash source table\n straight--recipe-lookup-cache)\n table)))))\n (cl-return recipe)))))))\n\n(defun straight-recipes-list (&optional sources cause)\n \"List recipes available in one or more SOURCES.\nPACKAGE should be a symbol, and SOURCES should be a list that is\na subset of `straight-recipe-repositories'. (If it is omitted, it\ndefaults to allowing all sources in\n`straight-recipe-repositories'.)\n\nCAUSE is a string indicating why recipe repositories might need\nto be cloned.\n\nReturn a list of package names as strings.\"\n (let ((sources (or sources straight-recipe-repositories))\n (recipes nil))\n (dolist (source sources (sort (delete-dups recipes)\n #'string-lessp))\n (let ((cause (concat cause (when cause straight-arrow)\n (format \"Listing %S recipes\" source))))\n (setq recipes (nconc recipes (straight-recipes\n 'list source cause)))))))\n\n;;;;;; Org\n\n(defun straight-recipes-org-elpa-retrieve (package)\n \"Look up a pseudo-PACKAGE recipe in Org ELPA.\nPACKAGE must be either `org' or `org-plus-contrib'. Otherwise\nreturn nil.\"\n (pcase package\n (`org\n '(org :type git :repo \"https://code.orgmode.org/bzg/org-mode.git\"\n :local-repo \"org\"))\n (`org-plus-contrib\n '(org-plus-contrib\n :type git :repo \"https://code.orgmode.org/bzg/org-mode.git\"\n :local-repo \"org\" :files (:defaults \"contrib/lisp/*.el\")))\n (_ nil)))\n\n(defun straight-recipes-org-elpa-list ()\n \"Return a list of Org ELPA pseudo-packages, as a list of strings.\"\n (list \"org\" \"org-plus-contrib\"))\n\n(defun straight-recipes-org-elpa-version ()\n \"Return the current version of the Org ELPA retriever.\"\n 1)\n\n;;;;;; MELPA\n\n(defun straight-recipes-melpa-retrieve (package)\n \"Look up a PACKAGE recipe in MELPA.\nPACKAGE should be a symbol. If the package has a recipe listed in\nMELPA that uses one of the Git fetchers, return it; otherwise\nreturn nil.\"\n (with-temp-buffer\n (condition-case nil\n (progn\n (insert-file-contents-literally\n (expand-file-name (symbol-name package) \"recipes/\"))\n (let ((melpa-recipe (read (current-buffer)))\n (plist nil))\n (cl-destructuring-bind (name . melpa-plist) melpa-recipe\n (straight--put plist :type 'git)\n (straight--put plist :flavor 'melpa)\n (when-let ((files (plist-get melpa-plist :files)))\n ;; We must include a *-pkg.el entry in the recipe\n ;; because that file always needs to be linked over,\n ;; if it is present, but the `:files' directive might\n ;; not include it (and doesn't need to, because MELPA\n ;; always re-creates a *-pkg.el file regardless). See\n ;; https://github.com/raxod502/straight.el/issues/336.\n (straight--put\n plist :files\n (append files (list (format \"%S-pkg.el\" package)))))\n (pcase (plist-get melpa-plist :fetcher)\n (`git (straight--put plist :repo (plist-get melpa-plist :url)))\n ((or `github `gitlab)\n (straight--put plist :host (plist-get melpa-plist :fetcher))\n (straight--put plist :repo (plist-get melpa-plist :repo)))\n ;; This error is caught by `condition-case', no need\n ;; for a message.\n (_ (error \"\")))\n (cons name plist))))\n (error nil))))\n\n(defun straight-recipes-melpa-list ()\n \"Return a list of recipes available in MELPA, as a list of strings.\"\n (straight--directory-files \"recipes\" \"^[^.]\"))\n\n(defun straight-recipes-melpa-version ()\n \"Return the current version of the MELPA retriever.\"\n 2)\n\n;;;;;; GNU ELPA\n\n(defcustom straight-recipes-gnu-elpa-use-mirror t\n \"Non-nil means to retrieve GNU ELPA packages via a mirror.\nThis means that all the packages work, even the `externals-list'\nones (e.g. `auctex'). However, you will not be able to contribute\nchanges back to GNU ELPA directly from the repository. This\nshould not be a major concern since the GNU ELPA build system\ndoes such a good job of discouraging contributions anyway.\"\n :type 'boolean)\n\n;;;;;;; GNU ELPA mirror\n\n(defun straight-recipes-gnu-elpa-mirror-retrieve (package)\n \"Look up a PACKAGE recipe in the GNU ELPA mirror.\nPACKAGE should be a symbol. If the package is maintained in GNU\nELPA (and should be retrieved from there, which isn't the case if\nthe package is built in to Emacs), return a MELPA-style recipe.\nOtherwise, return nil.\"\n (unless (straight--package-built-in-p package)\n (when (file-exists-p (symbol-name package))\n `(,package :type git\n :host github\n :repo ,(format \"emacs-straight/%S\" package)\n ;; Kinda weird, but in fact this is how package.el\n ;; works. So if we want to replicate the build\n ;; process, we should trust that the gnu-elpa-mirror\n ;; put the correct files into the repository, and\n ;; then just link *everything*. As an FYI, if we\n ;; don't do this, then AUCTeX suffers problems with\n ;; style files, see\n ;; .\n :files (\"*\" (:exclude \".git\"))))))\n\n(defun straight-recipes-gnu-elpa-mirror-list ()\n \"Return a list of recipe names available in the GNU ELPA mirror.\nThis is a list of strings.\"\n (cl-remove-if\n (lambda (package)\n (straight--package-built-in-p (intern package)))\n (straight--directory-files)))\n\n(defun straight-recipes-gnu-elpa-mirror-version ()\n \"Return the current version of the GNU ELPA mirror retriever.\"\n 3)\n\n;;;;;;; GNU ELPA source\n\n(defcustom straight-recipes-gnu-elpa-url\n \"https://git.savannah.gnu.org/git/emacs/elpa.git\"\n \"URL of the Git repository for the GNU ELPA package repository.\"\n :type 'string)\n\n(defun straight-recipes-gnu-elpa-retrieve (package)\n \"Look up a PACKAGE recipe in GNU ELPA.\nPACKAGE should be a symbol. If the package is maintained in GNU\nELPA (and should be retrieved from there, which isn't the case if\nthe package is built in to Emacs), return a MELPA-style recipe.\nOtherwise, return nil.\"\n (unless (straight--package-built-in-p package)\n (when (file-exists-p (expand-file-name (symbol-name package) \"packages/\"))\n ;; All the packages in GNU ELPA are just subdirectories of the\n ;; same repository.\n `(,package :type git\n :repo ,straight-recipes-gnu-elpa-url\n :files (,(format \"packages/%s/*.el\"\n (symbol-name package)))\n :local-repo \"elpa\"))))\n\n(defun straight-recipes-gnu-elpa-list ()\n \"Return a list of recipe names available in GNU ELPA, as a list of strings.\"\n (cl-remove-if\n (lambda (package)\n (straight--package-built-in-p (intern package)))\n (straight--directory-files \"packages/\")))\n\n(defun straight-recipes-gnu-elpa-version ()\n \"Return the current version of the GNU ELPA retriever.\"\n 2)\n\n;;;;;; Emacsmirror\n\n(defcustom straight-recipes-emacsmirror-use-mirror t\n \"Non-nil means to retrieve Emacsmirror packages via a mirror.\nThere is no disadvantage to doing this, and cloning the mirror is\nmuch faster than cloning the official Emacsmirror.\"\n :type 'boolean)\n\n;;;;;;; Emacsmirror mirror\n\n(defun straight-recipes-emacsmirror-mirror-retrieve (package)\n \"Look up a PACKAGE recipe in the Emacsmirror mirror.\nPACKAGE should be a symbol. If the package is available from\nEmacsmirror, return a MELPA-style recipe; otherwise return nil.\"\n (cl-block nil\n (let ((mirror-package (intern\n (replace-regexp-in-string\n \"\\\\+\" \"-plus\" (symbol-name package)\n 'fixedcase 'literal))))\n (dolist (org '(\"mirror\" \"attic\"))\n (with-temp-buffer\n (insert-file-contents-literally org)\n (when (re-search-forward\n (format \"^%S\\r?$\" mirror-package) nil 'noerror)\n (cl-return\n `(,package :type git :host github\n :repo ,(format \"emacs%s/%S\" org mirror-package)))))))))\n\n(defun straight-recipes-emacsmirror-mirror-list ()\n \"Return a list of recipes available in Emacsmirror, as a list of strings.\"\n (let ((packages nil))\n (dolist (org '(\"mirror\" \"attic\"))\n (with-temp-buffer\n (insert-file-contents-literally org)\n (setq packages (nconc (mapcar\n (lambda (package)\n (replace-regexp-in-string\n \"-plus\\\\b\" \"+\" package 'fixedcase 'literal))\n (split-string (buffer-string) \"\\n\" 'omit-nulls))\n packages))))\n packages))\n\n(defun straight-recipes-emacsmirror-mirror-version ()\n \"Return the current version of the Emacsmirror mirror retriever.\"\n 2)\n\n;;;;;;; Emacsmirror source\n\n(defun straight-recipes-emacsmirror-retrieve (package)\n \"Look up a PACKAGE recipe in Emacsmirror.\nPACKAGE should be a symbol. If the package is available from\nEmacsmirror, return a MELPA-style recipe; otherwise return nil.\"\n ;; Try to get the URL for the submodule. If it doesn't exist,\n ;; return nil. This will work both for packages in the mirror\n ;; and packages in the attic.\n (when-let ((url (condition-case nil\n (straight--get-call\n \"git\" \"config\" \"--file\" \".gitmodules\"\n \"--get\" (format \"submodule.%s.url\"\n (symbol-name package)))\n (error nil))))\n (and (not (string-empty-p url))\n ;; For the sake of elegance, we convert Github URLs to\n ;; use the `github' fetcher, if possible. At the time of\n ;; this writing, there are no Gitlab URLs (which makes\n ;; sense, since all the repositories should be hosted on\n ;; github.com/emacsmirror).\n (cl-destructuring-bind (repo host _protocol)\n (straight-vc-git--decode-url url)\n (if host\n `(,package :type git :host ,host\n :repo ,repo)\n `(,package :type git :repo ,repo))))))\n\n(defun straight-recipes-emacsmirror-list ()\n \"Return a list of recipes available in Emacsmirror, as a list of strings.\"\n (append\n (straight--directory-files \"mirror\")\n (straight--directory-files \"attic\")))\n\n(defun straight-recipes-emacsmirror-version ()\n \"Return the current version of the Emacsmirror retriever.\"\n 2)\n\n;;;;; Recipe conversion\n\n(defcustom straight-built-in-pseudo-packages '(emacs python)\n \"List of built-in packages that aren't real packages.\nIf any of these are specified as dependencies, straight.el will\njust skip them instead of looking for a recipe.\n\nNote that straight.el can deal with built-in packages even if\nthis variable is set to nil. This just allows you to tell\nstraight.el to not even bother cloning recipe repositories to\nlook for recipes for these packages.\"\n :type '(repeat symbol))\n\n(cl-defun straight--convert-recipe (melpa-style-recipe &optional cause)\n \"Convert a MELPA-STYLE-RECIPE to a normalized straight.el recipe.\nRecipe repositories specified in `straight-recipe-repositories'\nmay be cloned and searched for recipes if the MELPA-STYLE-RECIPE\nis just a package name; otherwise, the MELPA-STYLE-RECIPE should\nbe a list and it is modified slightly to conform to the internal\nstraight.el recipe format. CAUSE is a string indicating the\nreason recipe repositories might need to be cloned.\n\nReturn nil if MELPA-STYLE-RECIPE was just a symbol, and no recipe\ncould be found for it, and package.el indicates that the package\nis built in to Emacs (e.g. the \\\"emacs\\\" package). This is used\nfor dependency resolution.\"\n ;; Special case for the `emacs' pseudo-package and similar, so that\n ;; by default we don't try to look up a recipe in recipe\n ;; repositories.\n (when (memq melpa-style-recipe straight-built-in-pseudo-packages)\n (cl-return-from straight--convert-recipe\n `(:type built-in :package ,(symbol-name melpa-style-recipe))))\n ;; Firstly, if the recipe is only provided as a package name, and\n ;; we've already converted it before, then we should just return the\n ;; previous result. This has nothing to do with efficiency; it's\n ;; actually to reduce conflicts. There are a couple of common cases:\n ;;\n ;; 1. I'm overriding the standard recipe for a package with a custom\n ;; recipe, and then loading a second package that requires the\n ;; first one as a dependency. In that case, loading the second\n ;; package will cause the first package to be loaded again,\n ;; without any special information provided about its\n ;; recipe (i.e. the recipe is supposed to be looked up by\n ;; `straight--convert-recipe' in the recipe repositories). But\n ;; that will cause a conflict, since a different recipe was\n ;; already provided. This problem is solved by the following two\n ;; lines of code. (Note, though, that there is still a conflict\n ;; if you load the second package before its custom-recipe\n ;; dependency, as should be expected.)\n ;;\n ;; 2. I'm loading two different features from the same package with\n ;; `use-package', and providing a non-standard recipe for the\n ;; package. For example, this comes up when you need to load both\n ;; `tex-site' and `tex' from your fork of `auctex'. It's\n ;; inconvenient to specify your custom recipe in both\n ;; `use-package' declarations, but with the following two lines\n ;; of code, you can specify your custom recipe in the first\n ;; `use-package' declaration and then specify only `auctex' as\n ;; the recipe in the second `use-package' declaration.\n ;;\n ;; 3. I'm using `straight-rebuild-package' or\n ;; `straight-rebuild-all', which both call `straight-use-package'\n ;; with just the package name and expect this not to introduce\n ;; conflicts.\n (or (and (symbolp melpa-style-recipe)\n (gethash (symbol-name melpa-style-recipe) straight--recipe-cache))\n (let* (;; It's important to remember whether the recipe was\n ;; provided explicitly, or if it was just given as a\n ;; package name (meaning that the recipe needs to be\n ;; looked up in a recipe repository, i.e. something in\n ;; `straight-recipe-repositories'). Why, you ask? It's so\n ;; that we can be a little more tolerant of conflicts in\n ;; certain cases -- see the comment below, before the\n ;; block of code that runs when `recipe-specified-p' is\n ;; nil.\n (recipe-specified-p (listp melpa-style-recipe))\n ;; Now we normalize the provided recipe so that it is\n ;; still a MELPA-style recipe, but it is guaranteed to be\n ;; a list. This is the part where the recipe repositories\n ;; are consulted, if necessary.\n (full-melpa-style-recipe\n (if recipe-specified-p\n melpa-style-recipe\n (or (straight-recipes-retrieve\n ;; Second argument is the sources list, defaults\n ;; to all known sources.\n melpa-style-recipe nil cause)\n ;; Check if the package is considered as\n ;; \"built-in\". If so, it's not an issue if we\n ;; can't find it in any recipe repositories.\n (if (straight--package-built-in-p melpa-style-recipe)\n (cl-return-from straight--convert-recipe\n `(:type built-in :package\n ,(symbol-name melpa-style-recipe)))\n (error (concat \"Could not find package %S \"\n \"in recipe repositories: %S\")\n melpa-style-recipe\n straight-recipe-repositories))))))\n ;; MELPA-style recipe format is a list whose car is the\n ;; package name as a symbol, and whose cdr is a plist.\n (cl-destructuring-bind (package . plist) full-melpa-style-recipe\n ;; Recipes taken from recipe repositories would not normally\n ;; have `:local-repo' specified. But if the recipe was\n ;; specified manually, then you can specify `:local-repo' to\n ;; override the default value (which is determined according\n ;; to the selected VC backend).\n ;;\n (when straight-allow-recipe-inheritance\n ;; To keep overridden recipes simple, Some keywords can be\n ;; inherited from the original recipe. This is done by\n ;; looking in original and finding all keywords that are\n ;; not present in the override and adding them there.\n (let ((fork (plist-get plist :fork)))\n (when (stringp fork)\n (straight--put plist :fork `(:repo ,fork))))\n (let* ((default (cdr (straight-recipes-retrieve package)))\n (keywords (straight-vc-keywords\n (or (plist-get default :type) 'git))))\n (dolist (keyword (cons :files keywords))\n (if (eq keyword :fork)\n (dolist (keyword keywords)\n (let ((fork-plist (plist-get plist :fork))\n (value (plist-get default keyword)))\n (when (and value fork-plist\n (not (plist-member fork-plist keyword)))\n (straight--put\n plist :fork (plist-put fork-plist keyword value)))))\n (let ((value (plist-get default keyword)))\n (when (and value (not (plist-member plist keyword)))\n (straight--put plist keyword value)))))))\n ;; The normalized recipe format will have the package name\n ;; as a string, not a symbol.\n (let ((package (symbol-name package)))\n ;; Note that you can't override `:package'. That would\n ;; just be silly.\n (straight--put plist :package package)\n ;; If no `:type' is specified, use the default.\n (unless (plist-member plist :type)\n (straight--put plist :type straight-default-vc))\n ;; This `unless' allows overriding `:local-repo' in a\n ;; manual recipe specification, and also allows the\n ;; attribute to be set to nil to enforce that there is no\n ;; local repository (rather than a local repository name\n ;; being automatically generated).\n (unless (plist-member plist :local-repo)\n (straight--put\n plist :local-repo\n (or (straight-vc-local-repo-name plist)\n ;; If no sane repository name can be generated,\n ;; just use the package name.\n package)))\n ;; This code is here to deal with complications that can\n ;; arise with manual recipe specifications when multiple\n ;; packages are versioned in the same repository.\n ;;\n ;; Specifically, let's suppose packages `swiper' and `ivy'\n ;; are both versioned in repository \"swiper\", and let's\n ;; suppose that I load both of them in my init-file (`ivy'\n ;; first and then `swiper'). Now suppose that I discover a\n ;; bug in `ivy' and fix it in my fork, so that (until my\n ;; fix is merged) I need to provide an explicit recipe in\n ;; my init-file's call to `straight-use-package' for\n ;; `ivy', in order to use my fork. That will cause a\n ;; conflict, because the recipe for `swiper' is\n ;; automatically taken from MELPA, and it does not point\n ;; at my fork, but instead at the official repository. To\n ;; fix the problem, I would have to specify my fork in the\n ;; recipe for `swiper' (and also `counsel', a third\n ;; package versioned in the same repository). That\n ;; violates DRY and is a pain.\n ;;\n ;; Instead, this code makes it so that if a recipe has\n ;; been automatically retrieved from a recipe repository\n ;; (for example, MELPA, GNU ELPA, or Emacsmirror), and the\n ;; `:local-repo' specified in that recipe has already been\n ;; used for another package, then the configuration for\n ;; that repository will silently be copied over, and\n ;; everything should \"just work\".\n ;;\n ;; Note that this weird edge case is totally unrelated to\n ;; the weird edge cases discussed earlier (in the first\n ;; comment of this function), and has to be handled in a\n ;; totally different way. It's surprising how complicated\n ;; recipe specification turns out to be.\n (unless recipe-specified-p\n (straight--with-plist plist\n (local-repo)\n ;; Here we are checking to see if there is already a\n ;; formula with the same `:local-repo'. This is one of\n ;; the primary uses of `straight--repo-cache'.\n (when-let ((original-recipe (gethash local-repo\n straight--repo-cache)))\n ;; Remove all VC-specific attributes from the recipe\n ;; we got from the recipe repositories.\n (straight--remq\n plist (cons :type\n (straight-vc-keywords\n ;; To determine which keywords to\n ;; remove from `plist', we want to use\n ;; the VC backend specified for that\n ;; same recipe. This is important in\n ;; case the recipe repository and the\n ;; existing recipe specify different\n ;; values for `:type'.\n (plist-get plist :type))))\n ;; Now copy over all the VC-specific attributes from\n ;; the existing recipe.\n (dolist (keyword\n (cons :type\n (straight-vc-keywords\n ;; Same logic as above. This time\n ;; we're using the VC backend\n ;; specified by the original recipe.\n (plist-get original-recipe :type))))\n (when-let ((value (plist-get original-recipe keyword)))\n (straight--put plist keyword value))))))\n ;; Return the newly normalized recipe.\n plist)))))\n\n(defun straight--get-overridden-recipe (package)\n \"Given a PACKAGE symbol, check if it has an overridden recipe.\nThis means an entry in `straight-recipe-overrides'. If one is\nfound, return it as a MELPA-style recipe. Otherwise, return\nnil.\"\n (let ((recipe nil))\n (cl-dolist (profile (mapcar #'car straight-profiles))\n (when-let ((recipes (alist-get profile straight-recipe-overrides)))\n (when-let ((overridden-recipe (assoc package recipes)))\n (setq recipe overridden-recipe))))\n recipe))\n\n;;;;; Recipe registration\n\n(defvar straight--build-keywords\n '(:local-repo :files :flavor :no-autoloads :no-byte-compile)\n \"Keywords that affect how a package is built locally.\nIf the values for any of these keywords change, then package\nneeds to be rebuilt. See also `straight-vc-keywords'.\")\n\n(defun straight--register-recipe (recipe)\n \"Make the various caches aware of RECIPE.\nRECIPE should be a straight.el-style recipe plist.\"\n (straight--with-plist recipe\n (package local-repo type)\n ;; Skip conflict detection for built-in packages.\n (unless (eq type 'built-in)\n ;; Step 1 is to check if the given recipe conflicts with an\n ;; existing recipe for a *different* package with the *same*\n ;; repository.\n (when-let ((existing-recipe (gethash local-repo straight--repo-cache)))\n ;; Avoid signalling two warnings when you change the recipe\n ;; for a single package. We already get a warning down below\n ;; in Step 2, no need to show another one here. Only signal a\n ;; warning here when the packages are actually *different*\n ;; packages that share the same repository.\n (unless (equal (plist-get recipe :package)\n (plist-get existing-recipe :package))\n ;; Only the VC-specific keywords are relevant for this.\n (cl-dolist (keyword (cons :type (straight-vc-keywords type)))\n ;; Note that it doesn't matter which recipe we get `:type'\n ;; from. If the two are different, then the first\n ;; iteration of this loop will terminate with a warning,\n ;; as desired.\n (unless (equal (plist-get recipe keyword)\n (plist-get existing-recipe keyword))\n ;; We're using a warning rather than an error here,\n ;; because it's very frustrating if your package manager\n ;; simply refuses to install a package for no good\n ;; reason. Note that since we update\n ;; `straight--repo-cache' and `straight--recipe-cache'\n ;; at the end of this method, this warning will only be\n ;; displayed once per recipe modification.\n (straight--warn (concat \"Packages %S and %S have incompatible \"\n \"recipes (%S cannot be both %S and %S)\")\n (plist-get existing-recipe :package)\n package\n keyword\n (plist-get existing-recipe keyword)\n (plist-get recipe keyword))\n (cl-return)))))\n ;; Step 2 is to check if the given recipe conflicts with an\n ;; existing recipe for the *same* package.\n (when-let ((existing-recipe (gethash package straight--recipe-cache)))\n (cl-dolist (keyword\n (cons :type\n (append straight--build-keywords\n ;; As in Step 1, it doesn't matter which\n ;; recipe we get `:type' from.\n (straight-vc-keywords type))))\n (unless (equal (plist-get recipe keyword)\n (plist-get existing-recipe keyword))\n ;; Same reasoning as with the previous warning.\n (straight--warn\n (concat \"Recipe for %S has been overridden \"\n \"(%S changed from %S to %S)\")\n package\n keyword\n (plist-get existing-recipe keyword)\n (plist-get recipe keyword))\n (cl-return)))))\n ;; Step 3, now that we've signaled any necessary warnings, is to\n ;; actually update the caches. Just FYI, `straight--build-cache'\n ;; is updated later (namely, at build time -- which may be quite a\n ;; while later, or never, depending on the values of NO-CLONE and\n ;; NO-BUILD that were passed to `straight-use-package'.\n (puthash package recipe straight--recipe-cache)\n ;; Don't record recipes which have no local repositories.\n (when local-repo\n (puthash local-repo recipe straight--repo-cache))\n (cl-pushnew straight-current-profile\n (gethash package straight--profile-cache)\n ;; Profiles are symbols and can be compared more\n ;; efficiently using `eq'.\n :test #'eq)\n ;; If we've registered a new package, then we no longer know that\n ;; the set of registered packages actually corresponds to the\n ;; packages requested in the init-file. (For instance, this could\n ;; be an interactive call.) But we're OK if this operation is\n ;; guaranteed to be functional (e.g. because we're currently\n ;; loading the init-file).\n (unless straight--functional-p\n (setq straight--profile-cache-valid nil))))\n\n(defun straight--map-repos (func)\n \"Call FUNC for each local repository referenced in the known recipes.\nFUNC is passed one argument, the straight.el-style recipe plist.\nIt is called once for every local repository (i.e. each distinct\nvalue of `:local-repo'). This means that if multiple packages are\nversioned in the same local repository, then all but one of them\nwill be omitted.\"\n ;; Remember that `straight--repo-cache' only has the most recent\n ;; recipe that specified each `:local-repo'.\n (dolist (recipe (hash-table-values straight--repo-cache))\n (funcall func recipe)))\n\n(defun straight--map-repo-packages (func)\n \"Call FUNC for each local repository referenced in the known recipes.\nThe function FUNC is passed one argument, the name (as a string)\nof one of the packages using the local repository.\"\n (straight--map-repos\n (lambda (recipe)\n (straight--with-plist recipe\n (package)\n (funcall func package)))))\n\n;;;; Checking for package modifications\n\n(defun straight--determine-best-modification-checking ()\n \"Determine the best default value of `straight-check-for-modifications'.\nThis uses find(1) for all checking on most platforms, and\n`before-save-hook' on Microsoft Windows.\"\n (if (straight--windows-os-p)\n (list 'check-on-save)\n (list 'find-at-startup 'find-when-checking)))\n\n(defcustom straight-check-for-modifications\n (straight--determine-best-modification-checking)\n \"When to check for package modifications.\nThis is a list of symbols. If `find-at-startup' is in the list,\nthen find(1) is used to detect modifications of all packages\nbefore they are made available. If `find-when-checking' is in the\nlist, then find(1) is used to detect modifications in\n\\\\[straight-check-package] and \\\\[straight-check-all]. If\n`check-on-save' is in the list, then `before-save-hook' is used\nto detect modifications of packages that you perform within\nEmacs. If `watch-files' is in the list, then a filesystem watcher\nis automatically started by straight.el to detect modifications.\n\nNote that the functionality of `check-on-save' and `watch-files'\nonly covers modifications made within ~/.emacs.d/straight/repos,\nso if you wish to use these features you should move all of your\nlocal repositories into that directory.\n\nFor backwards compatibility, the value of this variable may also\nbe a symbol, which is translated into a corresponding list as\nfollows:\n\n`at-startup' => `(find-at-startup find-when-checking)'\n`live' => `(check-on-save)'\n`live-with-find' => `(check-on-save find-when-checking)'\n`never' => nil\n\nThis usage is deprecated and will be removed.\"\n :type\n '(list\n (choice\n (const :tag \"Use find(1) at startup\" find-at-startup)\n (const :tag \"Use find(1) in \\\\[straight-check-package]\"\n find-when-checking)\n (const :tag \"Use `before-save-hook' to detect changes\" check-on-save)\n (const :tag \"Use a filesystem watcher to detect changes\" watch-files))))\n\n(defun straight--modifications (symbol)\n \"Check if `straight-check-for-modifications' contains SYMBOL.\nHowever, if `straight-check-for-modifications' is itself one of\nthe symbols supported for backwards compatibility, account for\nthat appropriately.\"\n (memq symbol\n (pcase straight-check-for-modifications\n (`at-startup '(find-at-startup find-when-checking))\n (`live '(check-on-save))\n (`live-with-find '(check-on-save find-when-checking))\n (`never nil)\n (lst lst))))\n\n(defcustom straight-cache-autoloads t\n \"Non-nil means read autoloads in bulk to speed up startup.\nThe operation of this variable should be transparent to the user;\nno changes in configuration are necessary.\"\n :type 'boolean)\n\n;;;;; Build cache\n\n(defvar straight--build-cache nil\n \"Hash table keeping track of information about built packages, or nil.\nThe keys are strings naming packages, and the values are lists of\nlength three. The first entry is a timestamp identifying the last\ntime the package was successfully built; the second entry is a\nlist of the dependencies of the package, as strings; and the\nthird entry is the straight.el-normalized recipe plist for the\npackage. This information is used to determine whether or not a\npackage needs to be rebuilt.\n\nThe value of this variable is persisted in file pointed to in\n`straight-build-cache-file'.\")\n\n(defvar straight--autoloads-cache nil\n \"Hash table keeping track of autoloads extracted from packages, or nil.\nThe keys are strings naming packages, and the values are cons\ncells. The car of each is a list of features that seem to be\nprovided by the package, and the cdr is the autoloads provided by\nthe package, as a list of forms to evaluate.\")\n\n(defvar straight--eagerly-checked-packages nil\n \"List of packages that will be checked eagerly for modifications.\nThis list is read from the build cache, and is originally\ngenerated at the end of an init from the keys of\n`straight--profile-cache'.\")\n\n;; See http://stormlightarchive.wikia.com/wiki/Calendar for the\n;; schema.\n(defvar straight--build-cache-version :kak\n \"The current version of the build cache format.\nWhen the format on disk changes, this value is changed, so that\nstraight.el knows to regenerate the whole cache.\")\n\n(defvar straight--build-cache-text nil\n \"Literal text of the build cache.\nIf this is unchanged between loading and saving the build cache,\nthen the saving step is skipped for efficiency.\")\n\n(defun straight--load-build-cache ()\n \"Load data from the build cache into memory.\nThis sets the variables `straight--build-cache' and\n`straight--eagerly-checked-packages'. If the build cache is\nmalformed, don't signal an error, but set these variables to\nempty values (all packages will be rebuilt, with no caching).\"\n ;; Start by clearing the build cache. If the one on disk is\n ;; malformed (or outdated), these values will be used.\n (setq straight--build-cache (make-hash-table :test #'equal))\n (setq straight--autoloads-cache (make-hash-table :test #'equal))\n (setq straight--recipe-lookup-cache (make-hash-table :test #'eq))\n (setq straight--eagerly-checked-packages nil)\n (setq straight--build-cache-text nil)\n (let ((needs-immediate-save nil))\n (ignore-errors\n (with-temp-buffer\n ;; Using `insert-file-contents-literally' avoids\n ;; `find-file-hook', etc.\n (insert-file-contents-literally\n (straight--build-cache-file))\n (let ((version (read (current-buffer)))\n (last-emacs-version (read (current-buffer)))\n (build-cache (read (current-buffer)))\n (autoloads-cache (read (current-buffer)))\n (recipe-lookup-cache (read (current-buffer)))\n (eager-packages (read (current-buffer)))\n (use-symlinks (read (current-buffer)))\n ;; This gets set to nil if we detect a specific problem\n ;; with the build cache other than it being malformed,\n ;; so that we don't subsequently emit a second message\n ;; claiming that the cache is malformed.\n (malformed t))\n (unless (and\n ;; Format version should be the symbol currently in\n ;; use.\n (symbolp version)\n (or (eq version straight--build-cache-version)\n (prog1 (setq malformed nil)\n (straight--output\n (concat\n \"Rebuilding all packages due to \"\n \"build cache schema change\"))))\n ;; Emacs version should be the same as our current\n ;; one.\n (stringp last-emacs-version)\n (or (string= last-emacs-version emacs-version)\n (prog1 (setq malformed nil)\n (straight--output\n (concat\n \"Rebuilding all packages due to \"\n \"change in Emacs version\"))))\n ;; Build cache should be a hash table.\n (hash-table-p build-cache)\n (eq (hash-table-test build-cache) #'equal)\n ;; Autoloads cache should also be a hash table.\n (hash-table-p autoloads-cache)\n (eq (hash-table-test autoloads-cache) #'equal)\n ;; Eagerly checked packages should be a list of\n ;; strings.\n (listp eager-packages)\n (cl-every #'stringp eager-packages)\n ;; Symlink setting should not have changed.\n (eq use-symlinks straight-use-symlinks))\n ;; If anything is wrong, abort and use the default values.\n (when malformed\n (straight--output\n \"Rebuilding all packages due to malformed build cache\"))\n (setq needs-immediate-save t)\n (error \"Malformed or outdated build cache\"))\n ;; Otherwise, we can load from disk.\n (setq straight--build-cache build-cache)\n (setq straight--autoloads-cache autoloads-cache)\n (setq straight--recipe-lookup-cache recipe-lookup-cache)\n (setq straight--eagerly-checked-packages eager-packages)\n (setq straight--build-cache-text (buffer-string))\n (when (or (straight--modifications 'check-on-save)\n (straight--modifications 'watch-files))\n (when-let ((repos (condition-case _ (straight--directory-files\n (straight--modified-dir))\n (file-missing))))\n ;; Cause live-modified repos to have their packages\n ;; rebuilt when appropriate. Just in case init is\n ;; interrupted, however, we won't clear out the\n ;; `straight--modified-dir' until we write the build cache\n ;; back to disk.\n (dolist (package (hash-table-keys straight--build-cache))\n (ignore-errors\n (when (member\n (plist-get (nth 2 (gethash\n package straight--build-cache))\n :local-repo)\n repos)\n (remhash package straight--build-cache)))))))))\n ;; If we cleared out the build cache entirely due to a change in\n ;; Emacs version or similar, then we will be rebuilding all\n ;; packages during this init. However, the build cache will not be\n ;; written to disk until the end of init, so we can't rely on that\n ;; happening. If we rebuild a couple of packages and then init is\n ;; aborted before we can save the build cache, then it's possible\n ;; that the Emacs version (or similar) will have changed back to\n ;; its previous value. In this case, we should rebuild the\n ;; packages that we rebuilt during this init. However, since we\n ;; didn't write the build cache, the need for this can't be\n ;; detected. To solve the problem, we write the build cache\n ;; immediately in the case of needing to rebuild all packages.\n (when needs-immediate-save\n (straight--save-build-cache))))\n\n(defun straight--save-build-cache ()\n \"Write data from memory into the build cache file.\nThis uses the values of `straight--build-cache' and\n`straight--eagerly-checked-packages'.\n\nThe name of the cache file is stored in\n`straight-build-cache-file'.\"\n (unless straight-safe-mode\n (with-temp-buffer\n ;; Prevent mangling of the form being printed in the case that\n ;; this function was called by an `eval-expression' invocation\n ;; of `straight-use-package'.\n (let ((print-level nil)\n (print-length nil))\n ;; The version of the build cache.\n (print straight--build-cache-version (current-buffer))\n ;; Record the current Emacs version. If a different version of\n ;; Emacs is used, we have to rebuild all the packages (because\n ;; byte-compiled files cannot necessarily still be loaded).\n (print emacs-version (current-buffer))\n ;; The actual build cache.\n (print straight--build-cache (current-buffer))\n ;; The autoloads cache.\n (print straight--autoloads-cache (current-buffer))\n ;; The recipe lookup cache.\n (print straight--recipe-lookup-cache (current-buffer))\n ;; Which packages should be checked eagerly next init.\n (print (hash-table-keys straight--profile-cache) (current-buffer))\n ;; Whether packages were built using symlinks or copying.\n (print straight-use-symlinks (current-buffer)))\n (unless (and straight--build-cache-text\n (string= (buffer-string) straight--build-cache-text))\n (write-region nil nil (straight--build-cache-file) nil 0))\n (when (or (straight--modifications 'check-on-save)\n (straight--modifications 'watch-files))\n ;; We've imported data from `straight--modified-dir' into the\n ;; build cache when loading it. Now that we've written the\n ;; build cache back to disk, there's no more need for that\n ;; data (and indeed, it would produce spurious package\n ;; rebuilds on subsequent inits).\n (condition-case _\n (delete-directory (straight--modified-dir) 'recursive)\n (file-error))))))\n\n(cl-defun straight--make-build-cache-available (&key nosave)\n \"Make the build cache available until the end of the current transaction.\nIf NOSAVE is non-nil, then don't bother saving it. (In this case,\nyou ought not to make any changes to it.)\"\n (straight--transaction-exec\n 'build-cache\n :now #'straight--load-build-cache\n :later (unless nosave #'straight--save-build-cache)))\n\n;;;;; Live modification checking\n\n(defun straight-register-repo-modification (local-repo)\n \"Register a modification of the given LOCAL-REPO, a string.\nAlways return nil, for convenience of usage.\"\n (unless straight-safe-mode\n (prog1 nil\n (unless (string-match-p \"/\" local-repo)\n (make-directory (straight--modified-dir) 'parents)\n (with-temp-file (straight--modified-file local-repo))))))\n\n(defun straight-register-file-modification ()\n \"Register a modification of the current file.\nThis function is placed on `before-save-hook' by\n`straight-live-modifications-mode'.\"\n (when buffer-file-name\n (when-let ((local-repo (straight--determine-repo buffer-file-name)))\n (straight-register-repo-modification local-repo))))\n\n(define-minor-mode straight-live-modifications-mode\n \"Mode that causes straight.el to check for modifications as you make them.\nThis mode is automatically enabled or disabled as you bootstrap\nstraight.el, according to the value of\n`straight-check-for-modifications'.\"\n :global t\n :group 'straight\n (if straight-live-modifications-mode\n (add-hook 'before-save-hook #'straight-register-file-modification)\n (remove-hook 'before-save-hook #'straight-register-file-modification)))\n\n;;;;; Filesystem watcher\n\n(defcustom straight-watcher-process-buffer \" *straight-watcher*\"\n \"Name of buffer to use for the filesystem watcher.\"\n :type 'string)\n\n(defun straight-watcher--make-process-buffer ()\n \"Kill and recreate `straight-watcher-process-buffer'. Return it.\"\n (ignore-errors\n (kill-buffer straight-watcher-process-buffer))\n (let ((buf (get-buffer-create straight-watcher-process-buffer)))\n (prog1 buf\n (with-current-buffer buf\n (special-mode)))))\n\n(cl-defun straight-watcher--virtualenv-setup ()\n \"Set up the virtualenv for the filesystem watcher.\nIf it fails, signal a warning and return nil.\"\n (let* ((virtualenv (straight--watcher-dir \"virtualenv\"))\n (python (straight--watcher-python))\n (straight-dir (file-name-directory straight--this-file))\n (watcher-dir (expand-file-name \"watcher\" straight-dir))\n (version-from (expand-file-name \"version\" watcher-dir))\n (version-to (straight--watcher-file \"version\")))\n (condition-case _\n (delete-directory virtualenv 'recursive)\n (file-missing))\n (make-directory\n (file-name-directory\n (directory-file-name virtualenv))\n 'parents)\n (and (straight--warn-call \"python3\" \"-m\" \"venv\" virtualenv)\n (straight--warn-call\n python \"-m\" \"pip\" \"install\" \"-e\" watcher-dir)\n (prog1 t (copy-file version-from version-to\n 'ok-if-already-exists)))))\n\n(defun straight-watcher--virtualenv-outdated ()\n \"Return non-nil if the watcher virtualenv needs to be set up again.\nThis includes the case hwere it doesn't yet exist.\"\n (let* ((straight-dir (file-name-directory straight--this-file))\n (watcher-dir (expand-file-name \"watcher\" straight-dir))\n (version-from (expand-file-name \"version\" watcher-dir))\n (version-to (straight--watcher-file \"version\")))\n (not (straight--check-call \"diff\" \"-q\" version-from version-to))))\n\n(cl-defun straight-watcher-start ()\n \"Start the filesystem watcher, killing any previous instance.\nIf it fails, signal a warning and return nil.\"\n (interactive)\n (unless straight-safe-mode\n (unless (executable-find \"python3\")\n (straight--warn\n \"Cannot start filesystem watcher without 'python3' installed\")\n (cl-return-from straight-watcher-start))\n (unless (executable-find \"watchexec\")\n (straight--warn\n \"Cannot start filesystem watcher without 'watchexec' installed\")\n (cl-return-from straight-watcher-start))\n (when (straight-watcher--virtualenv-outdated)\n (straight--output \"Setting up filesystem watcher...\")\n (unless (straight-watcher--virtualenv-setup)\n (straight--output \"Setting up filesystem watcher...failed\")\n (cl-return-from straight-watcher-start))\n (straight--output \"Setting up filesystem watcher...done\"))\n (with-current-buffer (straight-watcher--make-process-buffer)\n (let* ((python (straight--watcher-python))\n (cmd (list\n ;; Need to disable buffering, otherwise we don't\n ;; get some important stuff printed.\n python \"-u\" \"-m\" \"straight_watch\" \"start\"\n (straight--watcher-file \"process\")\n (straight--repos-dir)\n (straight--modified-dir)))\n (sh (concat\n \"exec nohup \"\n (mapconcat #'shell-quote-argument cmd \" \"))))\n ;; Put the 'nohup.out' file in the ~/.emacs.d/straight/watcher/\n ;; directory.\n (setq default-directory (straight--watcher-dir))\n ;; Clear it out, since nohup(1) doesn't overwrite it.\n (condition-case _\n (delete-file (straight--watcher-file \"nohup.out\"))\n (file-missing))\n (let ((inhibit-read-only t))\n (insert \"$ \" sh \"\\n\\n\"))\n (start-file-process-shell-command\n \"straight-watcher\" straight-watcher-process-buffer sh)\n (set-process-query-on-exit-flag\n (get-buffer-process (current-buffer)) nil)))))\n\n(defun straight-watcher-stop ()\n \"Kill the filesystem watcher, if it is running.\nIf there is an unexpected error, signal a warning and return nil.\"\n (interactive)\n (unless straight-safe-mode\n (let ((python (straight--watcher-python)))\n (when (file-executable-p python)\n (straight--warn-call\n python \"-m\" \"straight_watch\" \"stop\"\n (straight--watcher-file \"process\"))))))\n\n;;;;; Bulk checking\n\n(defvar straight--cached-package-modifications (make-hash-table :test #'equal)\n \"Hash table indicating the modification status of cached packages.\nValid for the duration of a single transaction. It is a hash\ntable whose keys are local repository names as strings and whose\nvalues are booleans indicating whether the repositories have been\nmodified since their last builds.\")\n\n(cl-defun straight--cache-package-modifications ()\n \"Compute `straight--cached-package-modifications'.\"\n (let (;; Keep track of which local repositories we've processed\n ;; already. This table maps repo names to booleans.\n (repos (make-hash-table :test #'equal))\n ;; The systematically generated arguments for find(1).\n (args-paths nil)\n (args-primaries nil)\n (args nil)\n ;; This list is used to make sure we don't try to search a\n ;; directory that doesn't exist, which would cause the find(1)\n ;; command to fail.\n (existing-repos (straight--directory-files (straight--repos-dir))))\n (dolist (package straight--eagerly-checked-packages)\n (when-let ((build-info (gethash package straight--build-cache)))\n ;; Don't use `cl-destructuring-bind', as that will\n ;; error out on a list of insufficient length. We\n ;; want to be robust in the face of a malformed build\n ;; cache.\n (let ((mtime (nth 0 build-info))\n (recipe (nth 2 build-info)))\n (straight--with-plist recipe\n (local-repo)\n (when (and local-repo\n (not (gethash local-repo repos))\n (member local-repo existing-repos))\n (if mtime\n ;; The basic idea of the find(1) command here is\n ;; that we search all the local repositories, and\n ;; then the actual primaries evaluated are a\n ;; disjunction that first prevents any .git\n ;; directories from being traversed and then checks\n ;; for any files that are in a given local\n ;; repository *and* have a new enough mtime.\n ;;\n ;; See the following issue for an explanation about\n ;; why an extra pair of single quotes is used on\n ;; Windows:\n ;; \n (let ((newer-or-newermt nil)\n (mtime-or-file nil))\n (if (straight--find-supports 'newermt)\n (progn\n (setq newer-or-newermt \"-newermt\")\n (setq mtime-or-file mtime))\n (setq newer-or-newermt \"-newer\")\n (setq mtime-or-file (straight--make-mtime mtime)))\n (push (straight--repos-dir local-repo) args-paths)\n (setq args-primaries\n (append (list \"-o\"\n \"-path\"\n (expand-file-name\n (if (eq system-type 'windows-nt)\n \"'*'\"\n \"*\")\n (straight--repos-dir local-repo))\n newer-or-newermt\n mtime-or-file\n \"-print\")\n args-primaries)))\n ;; If no mtime is specified, it means the package\n ;; definitely needs to be (re)built. Probably there\n ;; was an error and we couldn't finish building the\n ;; package, but we wrote the build cache anyway.\n (puthash\n local-repo t straight--cached-package-modifications))\n ;; Don't create duplicate entries in the find(1) command\n ;; for this local repository.\n (puthash local-repo t repos))))))\n ;; If no packages, abort. This shouldn't happen, but might in the\n ;; face of other errors/undefined behavior.\n (unless args-paths\n (cl-return-from straight--cache-package-modifications))\n ;; Construct the final find(1) command.\n (setq args (append\n args-paths\n (list \"-name\" \".git\" \"-prune\")\n args-primaries))\n (let* ((default-directory (straight--repos-dir))\n (results (apply #'straight--get-call\n straight-find-executable args)))\n (maphash (lambda (local-repo _)\n (puthash\n local-repo (string-match-p\n (concat \"^\"\n (regexp-quote\n (file-name-as-directory\n (straight--repos-dir local-repo))))\n results)\n straight--cached-package-modifications))\n repos))))\n\n(defun straight--uncache-package-modifications ()\n \"Reset `straight--cached-package-modifications'.\"\n (setq straight--cached-package-modifications\n (make-hash-table :test #'equal)))\n\n(defun straight--make-package-modifications-available ()\n \"Make `straight--cached-package-modifications' available.\nIt is only available until the end of the current transaction.\"\n (straight--transaction-exec\n 'bulk-find\n :now #'straight--cache-package-modifications\n :later #'straight--uncache-package-modifications))\n\n;;;;; Individual checking\n\n(defvar straight--allow-find nil\n \"Bound to non-nil if find(1) can be used.\nThe value of this variable is only relevant when\n`straight-check-for-modifications' contains `find-when-checking'.\")\n\n(cl-defun straight--package-might-be-modified-p (recipe no-build)\n \"Check whether the package for the given RECIPE should be rebuilt.\nIf NO-BUILD is non-nil, then don't assume that the package should\nhave a build directory; only check for modifications since the\nlast time.\"\n (straight--with-plist recipe\n (package local-repo)\n (let* (;; `build-info' is a list of length three containing the\n ;; timestamp of the last build, the list of dependencies,\n ;; and the recipe plist, in that order.\n (build-info (gethash package straight--build-cache))\n (last-mtime (nth 0 build-info))\n (last-recipe (nth 2 build-info)))\n (or (null build-info)\n ;; Rebuild if relevant parts of the recipe have changed.\n (cl-dolist (keyword straight--build-keywords nil)\n (unless (equal (plist-get recipe keyword)\n (plist-get last-recipe keyword))\n (cl-return t)))\n ;; Somebody deleted the build directory...\n (and (not no-build)\n (not (file-exists-p (straight--build-dir package))))\n (progn\n ;; No local repository means we certainly can't have\n ;; changes to the package on disk. Since there's nothing\n ;; on disk, you know.\n (unless local-repo\n (cl-return-from straight--package-might-be-modified-p))\n ;; Don't look at mtimes unless we're told to. Otherwise,\n ;; rely on live modification checking/user attention.\n (unless (or (straight--modifications 'find-at-startup)\n (and (straight--modifications 'find-when-checking)\n straight--allow-find))\n (cl-return-from straight--package-might-be-modified-p))\n (straight--make-package-modifications-available)\n (if (straight--checkhash\n local-repo straight--cached-package-modifications)\n ;; Use the cached modification status if we've computed\n ;; one.\n (gethash local-repo straight--cached-package-modifications)\n ;; `last-mtime' should always be a string but you never\n ;; know.\n (or (not (stringp last-mtime))\n (with-temp-buffer\n (let ((newer-or-newermt nil)\n (mtime-or-file nil))\n (if (straight--find-supports 'newermt)\n (progn\n (setq newer-or-newermt \"-newermt\")\n (setq mtime-or-file last-mtime))\n (setq newer-or-newermt \"-newer\")\n (setq mtime-or-file\n (straight--make-mtime last-mtime)))\n (let* ((default-directory\n (straight--repos-dir local-repo))\n ;; This find(1) command ignores the .git\n ;; directory, and prints the names of any\n ;; files or directories with a newer\n ;; mtime than the one specified.\n (results (straight--get-call\n straight-find-executable\n \".\" \"-name\" \".git\" \"-prune\"\n \"-o\" newer-or-newermt mtime-or-file\n \"-print\")))\n ;; If anything was printed, the package has\n ;; (maybe) been modified.\n (not (string-empty-p results))))))))))))\n\n;;;; Building packages\n;;;;; Files directive processing\n\n(defvar straight-default-files-directive\n '(\"*.el\" \"*.el.in\" \"dir\"\n \"*.info\" \"*.texi\" \"*.texinfo\"\n \"doc/dir\" \"doc/*.info\" \"doc/*.texi\" \"doc/*.texinfo\" \"lisp/*.el\"\n (:exclude \".dir-locals.el\" \"test.el\" \"tests.el\" \"*-test.el\" \"*-tests.el\"))\n \"Default value for the `:files' directive in recipes.\nIt is also spliced in at any point where the `:defaults' keyword\nis used in a `:files' directive.\")\n\n(defun straight--expand-files-directive-internal (files src-dir prefix flavor)\n \"Expand FILES directive in SRC-DIR with path PREFIX.\nFILES is a list that can be used for the `:files' directive in a\nrecipe. SRC-DIR is an absolute path to the directory relative to\nwhich wildcards are to be expanded. PREFIX is a string, either\nempty or ending with a slash, that should be prepended to all\ntarget paths. FLAVOR is either the symbol `melpa' or nil; see\n`straight-expand-files-directive'.\n\nThe return value is a cons cell of a list of mappings and a list\nof exclusions. The mappings are of the same form that is returned\nby `straight-expand-files-directive', while the exclusions are\nanalogous except that they are only cars, and do not include\ndestinations.\"\n (unless (listp files)\n (error \"Invalid :files directive: %S\" files))\n (let ((mappings nil)\n (exclusions nil))\n ;; We have to do some funny business to get `:defaults' splicing\n ;; and wildcard expansion to work, hence `while' instead of\n ;; `dolist'.\n (while files\n ;; Pop off the first spec. We might add some new specs back in\n ;; later on.\n (let ((spec (car files)))\n (setq files (cdr files))\n (cond\n ((eq spec :defaults)\n (setq files (append straight-default-files-directive files)))\n ;; Replace string-only specs with a bunch of conses that have\n ;; already been wildcard-expanded.\n ((stringp spec)\n (setq files\n ;; Function `nconc' doesn't mutate its last argument.\n ;; We use it for efficiency over `append'.\n (nconc\n (mapcar\n (lambda (file)\n ;; Here we are using `file-name-nondirectory' to\n ;; achieve a default of linking to the root\n ;; directory of the target, but possibly with a\n ;; prefix if one was created by an enclosing list.\n (let ((filename (file-name-nondirectory file)))\n (when (eq flavor 'melpa)\n (setq filename\n (replace-regexp-in-string\n \"\\\\.in\\\\'\" \"\" filename 'fixedcase)))\n (cons file (concat prefix filename))))\n (file-expand-wildcards spec))\n files)))\n ;; The only other possibilities were already taken care of.\n ((not (consp spec))\n (error \"Invalid entry in :files directive: %S\" spec))\n ((eq (car spec) :exclude)\n (cl-destructuring-bind\n (rec-mappings . rec-exclusions)\n (straight--expand-files-directive-internal\n (cdr spec) src-dir prefix flavor)\n ;; We still want to make previously established mappings\n ;; subject to removal, but this time we're inverting the\n ;; meaning of the sub-list so that its mappings become our\n ;; exclusions.\n (setq mappings (cl-remove-if\n (lambda (mapping)\n (assoc (car mapping) rec-mappings))\n mappings))\n ;; Same as above. Mappings become exclusions. We drop the\n ;; actual exclusions of the `:exclude' sub-list, since\n ;; they are only supposed to apply to which elements\n ;; actually get excluded (a double exclusion does not make\n ;; an inclusion, at least here).\n (dolist (mapping rec-mappings)\n (push (car mapping) exclusions))))\n ;; Check if this is a proper list, rather than just a cons\n ;; cell.\n ((consp (cdr spec))\n ;; If so, the car should be a path prefix. We don't accept\n ;; `defaults' here obviously.\n (unless (stringp (car spec))\n (error \"Invalid sub-list head in :files directive: %S\" (car spec)))\n (cl-destructuring-bind\n ;; \"rec\" stands for \"recursive\".\n (rec-mappings . rec-exclusions)\n (straight--expand-files-directive-internal\n (cdr spec) src-dir (concat prefix (car spec) \"/\") flavor)\n ;; Any previously established mappings are subject to\n ;; removal from the `:exclude' clauses inside the\n ;; sub-list, if any.\n (setq mappings (cl-remove-if\n (lambda (mapping)\n (member (car mapping) rec-exclusions))\n mappings))\n ;; We have to do this after the `cl-remove-if' above,\n ;; since otherwise the mappings established within the\n ;; sub-list after the `:exclude' clauses there would also\n ;; be subject to removal.\n (dolist (mapping rec-mappings)\n ;; This is the place where mappings generated further\n ;; down are propagated all the way up to the top (unless\n ;; they get hit by a `cl-remove-if').\n (push mapping mappings))\n ;; The exclusions might also apply to some more mappings\n ;; that were established in higher-level sub-lists.\n (dolist (exclusion rec-exclusions)\n (push exclusion exclusions))))\n ((or (not (stringp (car spec)))\n (not (stringp (cdr spec))))\n (error \"Invalid entry in :files directive: %S\" spec))\n (t\n ;; Filter out nonexistent files silently. This only matters\n ;; when mappings are specified explicitly with cons cells,\n ;; since `file-expand-wildcards' will only report extant\n ;; files, even if there are no wildcards to expand.\n (when (file-exists-p (car spec))\n ;; This is the only place where mappings are actually\n ;; generated in the first place.\n (push spec mappings))))))\n ;; We've been using `push' to stick stuff onto the fronts of our\n ;; lists, so we need to reverse them. Not that it should matter\n ;; too much.\n (cons (reverse mappings) (reverse exclusions))))\n\n(defun straight-expand-files-directive\n (files src-dir dest-dir &optional flavor)\n \"Expand FILES directive mapping from SRC-DIR to DEST-DIR.\nSRC-DIR and DEST-DIR are absolute paths; the intention is that\nsymlinks are created in DEST-DIR pointing to SRC-DIR (but this\nfunction does not do that). Return a list of cons cells\nrepresenting the mappings from SRC-DIR to DEST-DIR. The paths in\nthe cons cells are absolute.\n\nFILES is a list, or nil. Each element of FILES can be a string, a\ncons cell, a list, or the symbol `:defaults'.\n\nIf an entry is a string, then it is expanded into a (possibly\nempty) list of extant files in SRC-DIR using\n`file-expand-wildcards'. Each of these files corresponds to a\nlink from the file in SRC-DIR to a file with the same name (sans\ndirectory) in DEST-DIR.\n\nIf an entry is a cons cell, then it is taken as a literal mapping\nfrom a file in SRC-DIR to a file in DEST-DIR (the directory is\nnot removed). In this case, wildcard expansion does not take\nplace.\n\nIf an entry is a list, then it must begin with either a string or\nthe symbol `:exclude'.\n\nIf the list begins with a string, then the remainder of the list\nis expanded as a top-level FILES directive, except that all\ntarget paths have the first element of the list prepended to\nthen. In other words, this form specifies further links to be\nplaced within a particular subdirectory of DEST-DIR.\n\nIf the list begins with the symbol `:exclude', then the remainder\nof the list is expanded as a top-level FILES directive, except\nthat all previously defined links pointing to any files in the\nresulting list are removed. Note that this means any links\nspecified previously in the current list are subject to removal,\nand also any links specified previously at any higher-level list,\nbut not any links specified afterwards in the current list, or\nany higher-level list. Note also that `:exclude' can be nested:\nin this case the inner `:exclude' results in some files being\nexcluded from the outer `:exclude', meaning that they will not\nactually be excluded.\n\nIf the entry is the symbol `:defaults', then the value of\n`straight-default-files-directive' is spliced into the enclosing\nlist to replace `:defaults'.\n\nIf FILES is nil, it defaults to\n`straight-default-files-directive'.\n\nIf two links are specified that take the same source path to\ndifferent target paths, the one that is specified textually later\nin FILES will win.\n\nNote that this specification is quite similar to the one used by\nthe MELPA recipe repository, with some minor differences:\n\n* MELPA recipes do not support cons cells to rename files or\n specify explicit subdirectories\n\n* MELPA recipes do not support putting `:defaults' anywhere\n except as the first element of the top-level list\n\n* When using `:exclude' in a MELPA recipe, the current DEST-DIR\n prefix created by enclosing lists is not respected.\n\n* Whenever a *.el.in file is linked in a MELPA recipe, the target\n of the link is named as *.el.\n\n* When using `:exclude' in a MELPA recipe, only links defined in\n the current list are subject to removal, and not links defined\n in higher-level lists.\n\nIf FLAVOR is nil or omitted, then expansion takes place as\ndescribed above. If FLAVOR is the symbol `melpa', then *.el.in\nfiles will be linked as *.el files as in MELPA. If FLAVOR is any\nother value, the behavior is not specified.\"\n ;; We bind `default-directory' here so we don't have to do it\n ;; repeatedly in the recursive section.\n (let* ((default-directory src-dir)\n (result (straight--expand-files-directive-internal\n (or files straight-default-files-directive)\n src-dir \"\" flavor))\n ;; We can safely discard the exclusions in the cdr of\n ;; `result', since any mappings that should have been\n ;; subject to removal have already had the exclusions\n ;; applied to them.\n (mappings (car result)))\n (straight--normalize-alist\n (mapcar (lambda (mapping)\n (cl-destructuring-bind (src . dest) mapping\n ;; Make the paths absolute.\n (cons (expand-file-name src src-dir)\n (expand-file-name dest dest-dir))))\n mappings)\n ;; Keys are strings.\n #'equal)))\n\n;;;;; Symlinking\n\n(defun straight--symlink-package (recipe)\n \"Symlink the package for the given RECIPE into the build directory.\nThis deletes any existing files in the relevant subdirectory of\nthe build directory, creating a pristine set of symlinks.\"\n (straight--with-plist recipe\n (package local-repo files flavor)\n ;; Remove the existing built package, if necessary.\n (let ((dir (straight--build-dir package)))\n (when (file-exists-p dir)\n (delete-directory dir 'recursive)))\n ;; Make a new directory for the built package.\n (make-directory (straight--build-dir package) 'parents)\n ;; Do the linking.\n (dolist (spec (straight-expand-files-directive\n files\n (straight--repos-dir local-repo)\n (straight--build-dir package)\n flavor))\n (cl-destructuring-bind (repo-file . build-file) spec\n (make-directory (file-name-directory build-file) 'parents)\n (straight--symlink-recursively repo-file build-file)))))\n\n(defun straight-maybe-emulate-symlink ()\n \"If visiting an emulated symlink, visit the link target instead.\nSee `straight-symlink-emulation-mode'.\"\n (let ((build-dir (straight--build-dir)))\n (when (and buffer-file-name\n (straight--path-prefix-p build-dir buffer-file-name))\n ;; Remove the ~/.emacs.d/straight/build/ part, and get the\n ;; corresponding path under straight/links/.\n (let* ((relative-path (substring buffer-file-name (length build-dir)))\n (link-record (straight--links-file relative-path)))\n (if (file-exists-p link-record)\n (find-alternate-file\n (with-temp-buffer\n (insert-file-contents-literally link-record)\n (buffer-string)))\n (straight--output\n \"Broken symlink, you are not editing the real file\"))))))\n\n(define-minor-mode straight-symlink-emulation-mode\n \"Minor mode for emulating symlinks in the software layer.\nThis means when a file in straight/build/ is visited, an advice\non `find-file-hook' causes straight.el to check if there is a\nrecord in straight/links/ identifying it as a symlink. If so,\nthen the file referenced there is used instead. This mode is\nautomatically enabled or disabled when you load straight.el,\naccording to the value of `straight-use-symlinks'.\"\n :global t\n :group 'straight\n (if straight-symlink-emulation-mode\n (add-hook 'find-file-hook #'straight-maybe-emulate-symlink)\n (remove-hook 'find-file-hook #'straight-maybe-emulate-symlink)))\n\n;;;;; Dependency management\n\n(defun straight--process-dependencies (dependencies)\n \"Normalize a package.el-style list of DEPENDENCIES.\nEach dependency is a list of length two containing a symbol\nnaming a package and a string naming the minimum version\nrequired (see the Package-Requires header in a\npackage.el-compliant Elisp package). The return value is a list\nof strings naming the packages that are mentioned in the\ndependency list.\"\n (mapcar\n (lambda (dep)\n (symbol-name\n (if (listp dep)\n (car dep)\n dep)))\n dependencies))\n\n(defun straight--compute-dependencies (package)\n \"Register the dependencies of PACKAGE in `straight--build-cache'.\nPACKAGE should be a string naming a package. Note that this\nfunction does *not* return the dependency list; see\n`straight--get-dependencies' for that. (The reason these two\nfunctions are separate is because dependencies are computed at\npackage build time, but they are retrieved later (when we are\nactivating autoloads, and may not have even built the package on\nthis run of straight.el).\"\n (let ((dependencies\n ;; There are actually two ways of specifying a package in\n ;; Emacs. The first is to include a file called\n ;; -pkg.el which contains a data structure with\n ;; a bunch of information (including the dependency alist).\n ;; The second is to put the information as headers in the\n ;; preamble of the file .el. We account for\n ;; both of them here.\n (or (ignore-errors\n (with-temp-buffer\n ;; Bypass `find-file-hook'.\n (insert-file-contents-literally\n (straight--build-file\n package\n (format \"%s-pkg.el\" package)))\n (straight--process-dependencies\n (eval (nth 4 (read (current-buffer)))))))\n (ignore-errors\n (with-temp-buffer\n (insert-file-contents-literally\n (straight--build-file\n package\n (format \"%s.el\" package)))\n ;; Who cares if the rest of the header is\n ;; well-formed? Maybe package.el does, but all we\n ;; really need is the dependency alist. If it's\n ;; missing or malformed, we just assume the package\n ;; has no dependencies.\n (let ((case-fold-search t))\n (re-search-forward \"^;; *Package-Requires *: *\"))\n (when (looking-at \"(\")\n (straight--process-dependencies\n (read (current-buffer)))))))))\n (straight--insert 1 package dependencies straight--build-cache)))\n\n(defun straight--get-dependencies (package)\n \"Get the dependencies of PACKAGE from `straight--build-cache'.\nPACKAGE should be a string naming a package. This assumes that\nthey were previously registered in the build cache by\n`straight--compute-dependencies'.\"\n (nth 1 (gethash package straight--build-cache)))\n\n;;;;; Autoload generation\n\n(defcustom straight-disable-autoloads nil\n \"Non-nil means do not generate or activate autoloads by default.\nThis can be overridden by the `:no-autoloads' property of an\nindividual package recipe.\"\n :type 'boolean)\n\n(cl-defun straight--generate-package-autoloads (recipe)\n \"Generate autoloads for the symlinked package specified by RECIPE.\nRECIPE should be a straight.el-style plist. See\n`straight--autoloads-file-name'. Note that this function only\nmodifies the build folder, not the original repository.\"\n (when (straight--plist-get recipe :no-autoloads straight-disable-autoloads)\n (cl-return-from straight--generate-package-autoloads))\n ;; The `eval-and-compile' here is extremely important. If you take\n ;; it out, then straight.el will fail with a mysterious error and\n ;; then cause Emacs to segfault if you start it with --debug-init.\n ;; This happens because if you take out `eval-and-compile', then\n ;; `autoload' will not be loaded at byte-compile time, and therefore\n ;; `generated-autoload-file' is not defined as a variable. Thus\n ;; Emacs generates bytecode corresponding to a lexical binding of\n ;; `generated-autoload-file', and then chokes badly when\n ;; `generated-autoload-file' turns into a dynamic variable at\n ;; runtime.\n (eval-and-compile\n (require 'autoload))\n (straight--with-plist recipe\n (package)\n (let (;; The full path to the autoload file.\n (generated-autoload-file (straight--autoloads-file package))\n ;; The following bindings are in\n ;; `package-generate-autoloads'. Presumably this is for a\n ;; good reason, so I just copied them here. It's a shame\n ;; that Emacs activates so many random features even when\n ;; you are accessing files programmatically.\n ;;\n ;; Note: we used to bind `noninteractive', like package.el,\n ;; but apparently that code was a bug in package.el. Sigh.\n ;; See .\n (backup-inhibited t)\n (version-control 'never)\n ;; Tell Emacs to shut up.\n (message-log-max nil) ; no *Messages*\n (inhibit-message t)) ; no echo area\n ;; If the package provides an autoload file already, then don't\n ;; overwrite it (which would actually write into the source\n ;; repository through the symlink).\n (unless (file-exists-p generated-autoload-file)\n ;; Prevent `update-directory-autoloads' from running hooks\n ;; (for example, adding to `recentf') when visiting the\n ;; autoload file.\n (let ((find-file-hook nil)\n (write-file-functions nil)\n ;; Apparently fixes a bug in Emacs 27, see\n ;; .\n (debug-on-error nil))\n ;; Actually generate the autoload file.\n (update-directory-autoloads\n (straight--build-dir package)))\n ;; And for some reason Emacs leaves a newly created buffer\n ;; lying around. Let's kill it.\n (when-let ((buf (find-buffer-visiting generated-autoload-file)))\n (kill-buffer buf))))))\n\n;;;;; Byte-compilation\n\n(defcustom straight-disable-byte-compilation nil\n \"Non-nil means do not byte-compile packages by default.\nThis can be overridden by the `:no-byte-compile' property of an\nindividual package recipe.\"\n :type 'boolean)\n\n(cl-defun straight--byte-compile-package (recipe)\n \"Byte-compile files for the symlinked package specified by RECIPE.\nRECIPE should be a straight.el-style plist. Note that this\nfunction only modifies the build folder, not the original\nrepository.\"\n (when (straight--plist-get recipe :no-byte-compile\n straight-disable-byte-compilation)\n (cl-return-from straight--byte-compile-package))\n ;; We need to load `bytecomp' so that the `symbol-function'\n ;; assignments below are sure to work. Since we byte-compile this\n ;; file, we need to `require' the feature at compilation time too.\n (eval-and-compile\n (require 'bytecomp))\n (straight--with-plist recipe\n (package)\n ;; These two `let' forms try very, very hard to make\n ;; byte-compilation an invisible process. Lots of packages have\n ;; byte-compile warnings; I don't need to know about them and\n ;; neither do straight.el users.\n (cl-letf (;; Prevent Emacs from asking the user to save all their\n ;; files before compiling.\n ((symbol-function #'save-some-buffers) #'ignore)\n ;; Die, byte-compile log, die!!!\n ((symbol-function #'byte-compile-log-1) #'ignore)\n ((symbol-function #'byte-compile-log-file) #'ignore)\n ((symbol-function #'byte-compile-log-warning) #'ignore))\n (let (;; Suppress messages about byte-compilation progress.\n (byte-compile-verbose nil)\n ;; Suppress messages about byte-compilation warnings.\n (byte-compile-warnings nil)\n ;; Suppress the remaining messages.\n (inhibit-message t)\n (message-log-max nil))\n ;; Note that there is in fact no `byte-compile-directory'\n ;; function.\n (byte-recompile-directory\n (straight--build-dir package)\n 0 'force)))))\n\n(defun straight--compile-package-texinfo (recipe)\n \"Compile .texi files into .info files for package specified by RECIPE.\nRECIPE should be a straight.el-style plist. Note that this\nfunction only modifies the build directory, not the original\nrepository.\"\n (when (and (executable-find \"makeinfo\")\n (executable-find \"install-info\"))\n (straight--with-plist recipe\n (package local-repo files flavor)\n (let (infos)\n (pcase-dolist (`(,repo-file . ,build-file)\n (straight-expand-files-directive\n files\n (straight--repos-dir local-repo)\n (straight--build-dir package)\n flavor))\n (cond\n ((string-match-p \"\\\\.info$\" build-file)\n (push build-file infos))\n ((string-match-p \"\\\\.texi\\\\(nfo\\\\)?$\" repo-file)\n (let ((texi repo-file)\n (info\n (concat (file-name-sans-extension build-file) \".info\")))\n (push info infos)\n (unless (file-exists-p info)\n (let ((default-directory (file-name-directory texi)))\n (straight--call \"makeinfo\" texi \"-o\" info)))))))\n (let ((dir (straight--build-file package \"dir\")))\n (unless (file-exists-p dir)\n (dolist (info infos)\n (when (file-exists-p info)\n (straight--call \"install-info\" info dir)))))))))\n\n;;;;; Cache handling\n\n(defun straight--format-timestamp (&optional timestamp)\n \"Format an Elisp TIMESTAMP for the operating system.\nSee `format-time-string' for the format of TIMESTAMP. The\nformatted string does not include millisecond precision because\nthis is not supported by find(1) commands on all operating\nsystems (thanks, Apple). Therefore, to avoid spurious rebuilds,\nthe time is rounded up to the next second.\"\n (format-time-string\n \"%F %T\" (time-add\n ;; Default is needed for Emacs 24.5 due to bad design.\n (or timestamp (current-time))\n ;; This format instead of just the integer 1 is needed for\n ;; Emacs 24.5 due to bad design.\n '(0 1))))\n\n(defun straight--declare-successful-build (recipe)\n \"Update `straight--build-cache' to reflect a successful build of RECIPE.\nRECIPE should be a straight.el-style plist. The build mtime and\nrecipe in `straight--build-cache' for the package are updated.\"\n (straight--with-plist recipe\n (package)\n ;; We've rebuilt the package, so its autoloads might have changed.\n (remhash package straight--autoloads-cache)\n (let (;; This time format is compatible with:\n ;;\n ;; * BSD find shipped with macOS >=10.11\n ;; * GNU find >=4.4.2\n (mtime (straight--format-timestamp)))\n (straight--insert 0 package mtime straight--build-cache))\n (straight--insert 2 package recipe straight--build-cache)))\n\n;;;;; Main entry point\n\n(defun straight--build-package (recipe &optional cause)\n \"Build the package specified by the RECIPE.\nThis includes symlinking the package files into the build\ndirectory, building dependencies, generating the autoload file,\nbyte-compiling, and updating the build cache. It is assumed that\nthe package repository has already been cloned.\n\nRECIPE is a straight.el-style plist. CAUSE is a string indicating\nthe reason this package is being built.\"\n (straight--with-plist recipe\n (package)\n (when straight-safe-mode\n (error \"Building %s not allowed in safe mode\" package))\n (let ((task (concat cause (when cause straight-arrow)\n (format \"Building %s\" package))))\n (straight--with-progress task\n (straight--symlink-package recipe)\n ;; The following function call causes the dependency list to\n ;; be written to the build cache. There is no need to save it\n ;; right away, as the transaction system ensures that in order\n ;; for the build cache to be loaded again, the current\n ;; transaction would first have to end, including saving the\n ;; build cache. (We know we're inside a transaction because\n ;; otherwise the build cache would not be available at all,\n ;; and hence this code would break immediately.)\n (straight--compute-dependencies package)\n ;; Before we (possibly) build the dependencies, we need to set\n ;; this flag so that we know if our progress message will need\n ;; to be redisplayed afterwards (before autoload generation\n ;; and byte-compilation).\n (setq straight--echo-area-dirty nil)\n ;; Yes, we do the following logic twice. Once here and again\n ;; in `straight-use-package'. Why? We need to do it here\n ;; because the dependencies need to be available before this\n ;; package can be byte-compiled. But the normal case is that\n ;; packages are already going to be built, so this code path\n ;; will not be hit and therefore autoloads will not be loaded\n ;; for the dependencies in that situation if we don't do it\n ;; again in `straight-use-package'.\n (when-let ((dependencies (straight--get-dependencies package)))\n (dolist (dependency dependencies)\n ;; The implicit meaning of the first argument to\n ;; `straight-use-package' here is that the default recipes\n ;; (taken from one of the recipe repositories) are used\n ;; for dependencies. (Well, maybe. See all the weird edge\n ;; cases and exceptions in `straight--convert-recipe'.)\n ;;\n ;; Note that the second and third arguments are always\n ;; nil. This means that dependencies will always be\n ;; eagerly cloned and built, if we got to building this\n ;; package.\n (straight-use-package (intern dependency) nil nil task))\n ;; We might need to redisplay the progress message from\n ;; `straight--with-progress' up above.\n (when straight--echo-area-dirty\n (straight--progress-begin task)))\n (straight--generate-package-autoloads recipe)\n (straight--byte-compile-package recipe)\n (straight--compile-package-texinfo recipe))\n ;; We messed up the echo area.\n (setq straight--echo-area-dirty t))))\n\n;;;; Loading packages\n\n(defun straight--add-package-to-load-path (recipe)\n \"Add the package specified by RECIPE to the `load-path'.\nRECIPE is a straight.el-style plist. It is assumed that the\npackage has already been built.\"\n (straight--with-plist recipe\n (package)\n (add-to-list 'load-path (directory-file-name\n (straight--build-dir package)))))\n\n(defun straight--add-package-to-info-path (recipe)\n \"Add the package specified by RECIPE to the `Info-directory-list'.\nRECIPE is a straight.el-style plist. It is assumed that the\npackage has already been built. This function calls\n`info-initialize'.\"\n (straight--with-plist recipe\n (package)\n ;; The `info-initialize' function is not autoloaded, for some\n ;; reason. Do `eval-and-compile' for the byte-compiler.\n (eval-and-compile\n (require 'info))\n ;; Initialize the `Info-directory-list' variable. We have to do\n ;; this before adding to it, since otherwise the default paths\n ;; won't get added later.\n (info-initialize)\n ;; Actually add the path. Only .info files at the top level will\n ;; be seen, which is fine. (It's the way MELPA works.)\n (add-to-list 'Info-directory-list (straight--build-dir package))))\n\n(defun straight--load-package-autoloads (package)\n \"Load autoloads provided by PACKAGE, a string, from disk.\"\n (let ((autoloads-file (straight--autoloads-file package)))\n ;; NB: autoloads file may not exist if no autoloads were provided,\n ;; in Emacs 26.\n (when (file-exists-p autoloads-file)\n (load autoloads-file nil 'nomessage))))\n\n(defun straight--determine-package-features (package)\n \"Determine what features are provided by PACKAGE, a string.\nInspect the build directory to find Emacs Lisp files that might\nbe loadable via `require'.\"\n (let ((files (straight--directory-files\n (straight--build-dir package)\n \"^.+\\\\.el$\")))\n (mapcar\n (lambda (fname)\n (intern (substring fname 0 -3)))\n files)))\n\n(defun straight--read-package-autoloads (package)\n \"Read and return autoloads provided by PACKAGE, a string, from disk.\nThe format is a list of Lisp forms to be evaluated.\"\n (let ((autoloads-file (straight--autoloads-file package)))\n ;; NB: autoloads file may not exist if no autoloads were provided,\n ;; in Emacs 26.\n (when (file-exists-p autoloads-file)\n (with-temp-buffer\n (insert-file-contents-literally autoloads-file)\n (let (;; Make the $# reader macro expand to the correct\n ;; filename.\n (load-file-name autoloads-file)\n (autoloads nil))\n (condition-case _\n (while t\n (push (read (current-buffer)) autoloads))\n (end-of-file))\n (nreverse autoloads))))))\n\n(defun straight--activate-package-autoloads (recipe)\n \"Evaluate the autoloads for the package specified by RECIPE.\nThis means that the functions with autoload cookies in the\npackage are now autoloaded and calling them will `require' the\npackage. It is assumed that the package has already been built.\nIf no autoload file exists (perhaps due to a non-nil\n`:no-autoloads' attribute on the package recipe or due to the\nglobal setting of `straight-disable-autoloads' or even because\nEmacs 26 seems to not generate an autoload file when there are no\nautoloads declared), then do nothing.\n\nIf `straight-cache-autoloads' is non-nil, read and write from the\nglobal autoloads cache in order to speed up this process.\n\nRECIPE is a straight.el-style plist.\"\n (straight--with-plist recipe\n (package)\n (if straight-cache-autoloads\n (progn\n (unless (straight--checkhash package straight--autoloads-cache)\n (let ((features (straight--determine-package-features package))\n (autoloads (straight--read-package-autoloads package)))\n (puthash package (cons features autoloads)\n straight--autoloads-cache)))\n ;; Some autoloads files expect to be loaded normally, rather\n ;; than read and evaluated separately. Fool them.\n (let ((load-file-name (straight--autoloads-file package)))\n ;; car is the feature list, cdr is the autoloads.\n (dolist (form (cdr (gethash package straight--autoloads-cache)))\n (eval form))))\n (straight--load-package-autoloads package))))\n\n;;;; Interactive helpers\n;;;;; Package selection\n\n(defun straight--select-package (message &optional for-build installed)\n \"Use `completing-read' to select a package.\nMESSAGE is displayed as the prompt; it should not end in\npunctuation or whitespace. If FOR-BUILD is non-nil, then only\npackages that have a nil `:no-build' property are considered. If\nINSTALLED is non-nil, then only packages that have an available\nrepo are considered.\"\n (completing-read\n (concat message \": \")\n (let ((packages nil))\n (maphash\n (lambda (package recipe)\n (unless (or (and for-build (plist-get recipe :no-build))\n (and installed\n (or (null (plist-get recipe :local-repo))\n (not (straight--repository-is-available-p\n recipe)))))\n (push package packages)))\n straight--recipe-cache)\n packages)\n (lambda (_) t)\n 'require-match))\n\n;;;;; Bookkeeping\n\n(defvar straight--success-cache (make-hash-table :test #'equal)\n \"Hash table containing successfully built packages as keys.\nThe keys are package names as strings; the values are\nmeaningless, and all non-nil.\")\n\n(defvar straight--packages-to-rebuild nil\n \"Hash table of packages for which to force a rebuild.\nThe keys are package names as strings; the values are\nmeaningless, and all non-nil. When not let-bound, this variable\nis nil. When `straight-use-package' is invoked for any of these\npackages, they will be rebuilt even if they have not changed. The\nspecial value `:all' is equivalent to a list of all possible\npackages. See also `straight-rebuild-package'.\")\n\n(defvar straight--packages-not-to-rebuild nil\n \"Hash table of packages for which rebuild forcing does not apply.\nThe keys are package names as strings; the values are\nmeaningless, and all non-nil. When not let-bound, this variable\nis nil. Any packages in this list are immune to the effects of\n`straight--packages-to-rebuild', even if it is set to `:all'.\nThis is used to prevent building dependencies twice when\n`straight-rebuild-package' or `straight-rebuild-all' is\ninvoked.\")\n\n;;;;; Interactive mapping\n\n(cl-defun straight--map-repos-interactively (func &optional predicate action)\n \"Apply function FUNC for all local repositories, interactively.\nFUNC is passed the name of one of the packages drawn from each\nlocal repository, as a string. If FUNC throws an error or a quit\nsignal, the user is asked about what to do. They can choose to\nskip the repository and come back to it later, cancel its\nprocessing entirely, or halt the entire operation (skipping the\nprocessing of all pending repositories). The return value of this\nfunction is the list of recipes for repositories that were not\nprocessed.\n\nPREDICATE, if provided, is passed the package name as a string,\nand should return a non-nil value to indicate that the package\nshould actually be processed.\n\nACTION is an optional string that describes the action being\nperformed on each repository, to be used for progress messages.\nThe default value is \\\"Processing\\\".\"\n (let ((next-repos nil)\n (skipped-repos nil)\n (canceled-repos nil))\n (straight--map-repos\n (lambda (recipe)\n (push recipe next-repos)))\n (while t\n (cond\n (next-repos\n (let ((recipe (car next-repos)))\n (straight--with-plist recipe\n (package local-repo)\n (if (or (null predicate)\n (funcall predicate package))\n (straight--with-progress\n (format \"%s repository %S\"\n (or action \"Processing\")\n local-repo)\n (cl-block loop\n (while t\n (straight--popup\n (if-let ((err\n (condition-case-unless-debug e\n (progn\n (funcall func package)\n (setq next-repos (cdr next-repos))\n (cl-return-from loop))\n (error e)\n ;; Emacs 24.5 has a bug where the\n ;; byte-compiler signals an unused\n ;; argument warning for the target\n ;; of a `condition-case' unless\n ;; it's used on every error\n ;; handler.\n (quit (ignore e)))))\n (format (concat \"While processing repository %S, \"\n \"an error occurred:\\n\\n %S\")\n local-repo (error-message-string err))\n (format (concat \"Processing of repository %S paused \"\n \"at your request.\")\n local-repo))\n (\"SPC\" \"Go back to processing this repository\")\n (\"s\" (concat \"Skip this repository for now and \"\n \"come back to it later\")\n (push recipe skipped-repos)\n (setq next-repos (cdr next-repos))\n (cl-return-from loop))\n (\"c\" (concat \"Cancel processing of this \"\n \"repository; move on and do not \"\n \"come back to it later\")\n (push recipe canceled-repos)\n (setq next-repos (cdr next-repos))\n (cl-return-from loop))\n (\"e\" \"Dired and open recursive edit\"\n (dired (straight--repos-dir local-repo))\n (straight--recursive-edit))\n (\"C-g\" (concat \"Stop immediately and do not process \"\n \"more repositories\")\n (keyboard-quit))))))\n (setq next-repos (cdr next-repos))))))\n (skipped-repos\n (setq next-repos skipped-repos)\n (setq skipped-repos nil))\n (t (cl-return-from straight--map-repos-interactively\n canceled-repos))))))\n\n(defun straight--map-existing-repos-interactively\n (func &optional predicate action)\n \"Apply function FUNC for all existing local repositories, interactively.\nPREDICATE and ACTION are as in\n`straight--map-repos-interactively'. The only difference is that\nthis function modifies PREDICATE to additionally require that the\nlocal repository is already on disk.\"\n (straight--map-repos-interactively\n func\n (lambda (package)\n (let ((recipe (gethash package straight--recipe-cache)))\n (straight--with-plist recipe\n (local-repo)\n (and local-repo\n (straight--repository-is-available-p recipe)\n (or (null predicate) (funcall predicate package))))))\n action))\n\n;;;; User-facing functions\n;;;;; Recipe acquiry\n\n;;;###autoload\n(defun straight-get-recipe (&optional sources action)\n \"Interactively select a recipe from one of the recipe repositories.\nAll recipe repositories in `straight-recipe-repositories' will\nfirst be cloned. After the recipe is selected, it will be copied\nto the kill ring. With a prefix argument, first prompt for a\nrecipe repository to search. Only that repository will be\ncloned.\n\nFrom Lisp code, SOURCES should be a subset of the symbols in\n`straight-recipe-repositories'. Only those recipe repositories\nare cloned and searched. If it is nil or omitted, then the value\nof `straight-recipe-repositories' is used. If SOURCES is the\nsymbol `interactive', then the user is prompted to select a\nrecipe repository, and a list containing that recipe repository\nis used for the value of SOURCES. ACTION may be `copy' (copy\nrecipe to the kill ring), `insert' (insert at point), or nil (no\naction, just return it).\"\n (interactive (list (when current-prefix-arg 'interactive) 'copy))\n (when (eq sources 'interactive)\n (setq sources (list\n (intern\n (completing-read\n \"Which recipe repository? \"\n straight-recipe-repositories\n nil\n 'require-match)))))\n (let ((sources (or sources straight-recipe-repositories)))\n (let* ((package (intern\n (completing-read\n \"Which recipe? \"\n (straight-recipes-list sources)\n (lambda (_) t)\n 'require-match)))\n ;; No need to provide a `cause' to\n ;; `straight-recipes-retrieve'; it should not be printing\n ;; any messages.\n (recipe (straight-recipes-retrieve package sources)))\n (unless recipe\n (user-error \"Recipe for %S is malformed\" package))\n (pcase action\n (`insert (insert (format \"%S\" recipe)))\n (`copy (kill-new (format \"%S\" recipe))\n (straight--output \"Copied \\\"%S\\\" to kill ring\" recipe))\n (_ recipe)))))\n\n;;;;; Jump to package website\n\n;;;###autoload\n(defun straight-visit-package-website ()\n \"Interactively select a recipe, and visit the package's website.\"\n (interactive)\n (let* ((melpa-recipe (straight-get-recipe))\n (recipe (straight--convert-recipe melpa-recipe)))\n (straight--with-plist recipe (host repo)\n (pcase host\n (`github (browse-url (format \"https://github.com/%s\" repo)))\n (`gitlab (browse-url (format \"https://gitlab.com/%s\" repo)))\n (_ (browse-url (format \"%s\" repo)))))))\n\n;;;;; Package registration\n\n(defcustom straight-use-package-prepare-functions nil\n \"Abnormal hook run before a package is (maybe) built.\nUnlike `straight-use-package-pre-build-functions', the functions\nin this hook are called even if the package does not need to be\nrebuilt. Each hook function is called with the name of the\npackage as a string. For forward compatibility, it should accept\nand ignore additional arguments.\"\n :type 'hook)\n\n(defcustom straight-use-package-pre-build-functions nil\n \"Abnormal hook run before building a package.\nEach hook function is called with the name of the package as a\nstring. For forward compatibility, it should accept and ignore\nadditional arguments.\"\n :type 'hook)\n\n;;;###autoload\n(cl-defun straight-use-package\n (melpa-style-recipe &optional no-clone no-build cause interactive)\n \"Register, clone, build, and activate a package and its dependencies.\nThis is the main entry point to the functionality of straight.el.\n\nMELPA-STYLE-RECIPE is either a symbol naming a package, or a list\nwhose car is a symbol naming a package and whose cdr is a\nproperty list containing e.g. `:type', `:local-repo', `:files',\nand VC backend specific keywords.\n\nFirst, the package recipe is registered with straight.el. If\nNO-CLONE is a function, then it is called with two arguments: the\npackage name as a string, and a boolean value indicating whether\nthe local repository for the package is available. In that case,\nthe return value of the function is used as the value of NO-CLONE\ninstead. In any case, if NO-CLONE is non-nil, then processing\nstops here.\n\nOtherwise, the repository is cloned, if it is missing. If\nNO-BUILD is a function, then it is called with one argument: the\npackage name as a string. In that case, the return value of the\nfunction is used as the value of NO-BUILD instead. In any case,\nif NO-BUILD is non-nil, then processing halts here. Otherwise,\nthe package is built and activated. Note that if the package\nrecipe has a non-nil `:no-build' entry, then NO-BUILD is ignored\nand processing always stops before building and activation\noccurs.\n\nCAUSE is a string explaining the reason why\n`straight-use-package' has been called. It is for internal use\nonly, and is used to construct progress messages. INTERACTIVE is\nnon-nil if the function has been called interactively. It is for\ninternal use only, and is used to determine whether to show a\nhint about how to install the package permanently.\n\nReturn non-nil if package was actually installed, and nil\notherwise (this can only happen if NO-CLONE is non-nil).\"\n (interactive\n (list (straight-get-recipe (when current-prefix-arg 'interactive))\n nil nil nil 'interactive))\n (let ((recipe (straight--convert-recipe\n (or\n (straight--get-overridden-recipe\n (if (listp melpa-style-recipe)\n (car melpa-style-recipe)\n melpa-style-recipe))\n melpa-style-recipe)\n cause)))\n ;; We need to register the recipe before building the package,\n ;; since the ability of `straight--convert-recipe' to deal\n ;; properly with dependencies versioned in the same repository of\n ;; their parent package will break unless the caches are updated\n ;; before we recur to the dependencies.\n ;;\n ;; Furthermore, we need to register it before executing the\n ;; transaction block, since otherwise conflicts between recipes\n ;; cannot be detected (the transaction block will only be run once\n ;; for any given package in a transaction).\n (straight--register-recipe recipe)\n (straight--with-plist recipe\n (package local-repo type)\n ;; Now, don't bother to go any further if the package was\n ;; built-in. Return non-nil.\n (when (eq type 'built-in)\n (cl-return-from straight-use-package t))\n (straight--transaction-exec\n ;; Ignore when the same package is requested twice (this will\n ;; happen many times during dependency resolution). However,\n ;; allow the user to request a package twice with different\n ;; recipes or build settings, and in that case re-check\n ;; everything.\n (intern (format \"use-package-%S-%S-%S\"\n recipe\n ;; If the NO-CLONE and NO-BUILD functions\n ;; compute their values dynamically, force\n ;; package rebuilding so the changed values may\n ;; be taken into account.\n (if (straight--functionp no-clone)\n (random)\n no-clone)\n (if (straight--functionp no-build)\n (random)\n no-build)))\n :now\n (lambda ()\n (let (;; Check if the package has been successfully built. If\n ;; not, and this is an interactive call, we'll want to\n ;; display a helpful hint message (see below). We have\n ;; to check this here, before the package is actually\n ;; built.\n (already-registered\n (gethash package straight--success-cache))\n (available\n ;; Package is vacuously available if nil local\n ;; repository was specified (if *no* local repository\n ;; was specified, which is different, then a default\n ;; name would have been generated).\n (or (null local-repo)\n (straight--repository-is-available-p recipe))))\n ;; Possibly abort based on NO-CLONE.\n (when (if (straight--functionp no-clone)\n (funcall no-clone package available)\n no-clone)\n (cl-return-from straight-use-package nil))\n ;; If we didn't abort, ensure the repository is cloned.\n (unless available\n ;; We didn't decide to abort, and the repository still\n ;; isn't available. Make it available.\n (straight--clone-repository recipe cause))\n ;; Do this even for packages with `no-build' enabled, as we\n ;; still want to check for modifications and (if any)\n ;; invalidate the relevant entry in the recipe lookup\n ;; cache.\n (straight--make-build-cache-available)\n (let* ((no-build\n (or\n ;; Remember that `no-build' can come both from the\n ;; arguments to `straight-use-package' and from\n ;; the actual recipe. We also refrain from trying\n ;; to build packages which have no local\n ;; repositories.\n (null local-repo)\n (plist-get recipe :no-build)\n (if (straight--functionp no-build)\n (funcall no-build package)\n no-build)))\n (modified\n (or\n ;; This clause provides support for\n ;; `straight-rebuild-package' and\n ;; `straight-rebuild-all'.\n (and\n straight--packages-to-rebuild\n (or (eq straight--packages-to-rebuild :all)\n (gethash package straight--packages-to-rebuild))\n (not (gethash\n package straight--packages-not-to-rebuild))\n ;; The following form returns non-nil, so it\n ;; doesn't affect the `and' logic.\n (puthash package t straight--packages-not-to-rebuild))\n (straight--package-might-be-modified-p\n recipe no-build))))\n (let ((func (intern (format \"straight-recipes-%s-version\"\n package)))\n (table (gethash (intern package)\n straight--recipe-lookup-cache)))\n ;; Invalidate recipe lookup cache when the recipe\n ;; repository is modified, or caching is disabled\n ;; because there's no version function defined for the\n ;; recipe repository, or because the version has\n ;; changed since the last time it was cached.\n (when (or modified\n (not (fboundp func))\n (not (equal\n ;; Avoid trying to look up a key in a\n ;; nil table.\n (and table (gethash 'version table))\n (funcall func))))\n (remhash (intern package) straight--recipe-lookup-cache)))\n (unless no-build\n ;; Multi-file packages will need to be on the\n ;; `load-path' in order to byte-compile properly. So we\n ;; do this before `straight--build-package'.\n (straight--add-package-to-load-path recipe))\n (run-hook-with-args\n 'straight-use-package-prepare-functions package)\n (when (and modified (not no-build))\n (run-hook-with-args\n 'straight-use-package-pre-build-functions package)\n (straight--build-package recipe cause))\n ;; We need to do this even if the package wasn't built,\n ;; so we can keep track of modifications.\n (straight--declare-successful-build recipe)\n (unless no-build\n ;; Here we are not actually trying to build the\n ;; dependencies, but activate their autoloads. (See the\n ;; comment in `straight--build-package' about this\n ;; code.)\n (dolist (dependency (straight--get-dependencies package))\n ;; There are three interesting things here. Firstly,\n ;; the recipe used is just the name of the\n ;; dependency. This causes the default recipe to be\n ;; looked up, unless one of the special cases in\n ;; `straight--convert-recipe' pops up. Secondly, the\n ;; values of NO-BUILD and NO-CLONE are always nil. If\n ;; the user has agreed to clone and build a package,\n ;; we assume that they also want to clone and build\n ;; all of its dependencies. Finally, we don't bother\n ;; to update `cause', since we're not expecting any\n ;; messages to be displayed here (all of the\n ;; dependencies should have already been cloned [if\n ;; necessary] and built back by\n ;; `straight--build-package').\n (straight-use-package (intern dependency) nil nil cause))\n ;; Only make the package available after everything is\n ;; kosher.\n (straight--add-package-to-info-path recipe)\n (straight--activate-package-autoloads recipe))\n ;; In interactive use, tell the user how to install\n ;; packages permanently.\n (when (and interactive (not already-registered))\n (straight--output\n (concat \"If you want to keep %s, put \"\n \"(straight-use-package %s%S) \"\n \"in your init-file.\")\n package \"'\" (intern package))))\n ;; The package was installed successfully.\n (puthash package t straight--success-cache)\n t))))))\n\n;;;###autoload\n(defun straight-register-package (melpa-style-recipe)\n \"Register a package without cloning, building, or activating it.\nThis function is equivalent to calling `straight-use-package'\nwith a non-nil argument for NO-CLONE. It is provided for\nconvenience. MELPA-STYLE-RECIPE is as for\n`straight-use-package'.\"\n (straight-use-package melpa-style-recipe 'no-clone))\n\n;;;###autoload\n(defun straight-use-package-no-build (melpa-style-recipe)\n \"Register and clone a package without building it.\nThis function is equivalent to calling `straight-use-package'\nwith nil for NO-CLONE but a non-nil argument for NO-BUILD. It is\nprovided for convenience. MELPA-STYLE-RECIPE is as for\n`straight-use-package'.\"\n (straight-use-package melpa-style-recipe nil 'no-build))\n\n;;;###autoload\n(defun straight-use-package-lazy (melpa-style-recipe)\n \"Register, build, and activate a package if it is already cloned.\nThis function is equivalent to calling `straight-use-package'\nwith symbol `lazy' for NO-CLONE. It is provided for convenience.\nMELPA-STYLE-RECIPE is as for `straight-use-package'.\"\n (straight-use-package\n melpa-style-recipe\n ;; Don't clone the package if it's not available.\n (lambda (_package available)\n (not available))))\n\n;;;###autoload\n(defun straight-use-recipes (melpa-style-recipe)\n \"Register a recipe repository using MELPA-STYLE-RECIPE.\nThis registers the recipe and builds it if it is already cloned.\nNote that you probably want the recipe for a recipe repository to\ninclude a non-nil `:no-build' property, to unconditionally\ninhibit the build phase.\n\nThis function also adds the recipe repository to\n`straight-recipe-repositories', at the end of the list.\"\n (straight-use-package-lazy melpa-style-recipe)\n (add-to-list 'straight-recipe-repositories\n (if (listp melpa-style-recipe)\n (car melpa-style-recipe)\n melpa-style-recipe)\n 'append))\n\n;;;;; Recipe overrides\n\n;;;###autoload\n(defun straight-override-recipe (melpa-style-recipe)\n \"Register MELPA-STYLE-RECIPE as a recipe override.\nThis puts it in `straight-recipe-overrides', depending on the\nvalue of `straight-current-profile'.\"\n (setq straight-recipe-overrides\n (straight--alist-set\n straight-current-profile\n (straight--alist-set\n (car melpa-style-recipe)\n (cdr melpa-style-recipe)\n (alist-get straight-current-profile straight-recipe-overrides)\n 'symbol)\n straight-recipe-overrides\n 'symbol)))\n\n;;;;; Rebuilding packages\n\n;;;###autoload\n(defun straight-check-package (package)\n \"Rebuild a PACKAGE if it has been modified.\nPACKAGE is a string naming a package. Interactively, select\nPACKAGE from the known packages in the current Emacs session\nusing `completing-read'. See also `straight-rebuild-package' and\n`straight-check-all'.\"\n (interactive (list (straight--select-package \"Check package\"\n 'for-build\n 'installed)))\n (let ((straight--allow-find t))\n (straight-use-package (intern package))))\n\n;;;###autoload\n(defun straight-check-all ()\n \"Rebuild any packages that have been modified.\nSee also `straight-rebuild-all' and `straight-check-package'.\nThis function should not be called during init.\"\n (interactive)\n (let ((straight--allow-find t))\n (dolist (package (hash-table-keys straight--recipe-cache))\n (straight-use-package (intern package)))))\n\n;;;###autoload\n(defun straight-rebuild-package (package &optional recursive)\n \"Rebuild a PACKAGE.\nPACKAGE is a string naming a package. Interactively, select\nPACKAGE from the known packages in the current Emacs session\nusing `completing-read'. With prefix argument RECURSIVE, rebuild\nall dependencies as well. See also `straight-check-package' and\n`straight-rebuild-all'.\"\n (interactive\n (list\n (straight--select-package \"Rebuild package\" 'for-build 'installed)\n current-prefix-arg))\n (let ((straight--packages-to-rebuild\n (if recursive\n :all\n (let ((table (make-hash-table :test #'equal)))\n (puthash package t table)\n table)))\n ;; Because we bind this here, the table will be deleted and\n ;; the variable reset to nil when we break out of the let. No\n ;; need to clear the hash explicitly.\n (straight--packages-not-to-rebuild\n (make-hash-table :test #'equal)))\n (straight-use-package (intern package))))\n\n;;;###autoload\n(defun straight-rebuild-all ()\n \"Rebuild all packages.\nSee also `straight-check-all' and `straight-rebuild-package'.\"\n (interactive)\n (let ((straight--packages-to-rebuild :all)\n (straight--packages-not-to-rebuild\n (make-hash-table :test #'equal)))\n (dolist (package (hash-table-keys straight--recipe-cache))\n (straight-use-package (intern package)))))\n\n;;;;; Cleanup\n\n;;;###autoload\n(defun straight-prune-build-cache ()\n \"Prune the build cache.\nThis means that only packages that were built in the last init\nrun and subsequent interactive session will remain; other\npackages will have their build mtime information and any cached\nautoloads discarded.\"\n (straight--make-build-cache-available)\n (dolist (package (hash-table-keys straight--build-cache))\n (unless (gethash package straight--profile-cache)\n (remhash package straight--build-cache)\n (remhash package straight--autoloads-cache)))\n (dolist (source (hash-table-keys straight--recipe-lookup-cache))\n (if (gethash (symbol-name source) straight--profile-cache)\n (let ((table (gethash source straight--recipe-lookup-cache)))\n (dolist (package (hash-table-keys table))\n (unless (or (equal package 'version)\n (gethash package straight--profile-cache))\n (remhash package table))))\n (remhash source straight--recipe-lookup-cache))))\n\n;;;###autoload\n(defun straight-prune-build-directory ()\n \"Prune the build directory.\nThis means that only packages that were built in the last init\nrun and subsequent interactive session will remain; other\npackages will have their build directories deleted.\"\n (straight--make-build-cache-available)\n (dolist (package (straight--directory-files\n (straight--build-dir)))\n ;; So, let me tell you a funny story. Once upon a time I didn't\n ;; have this `string-match-p' condition. But Emacs helpfully\n ;; returns . and .. from the call to `directory-files',\n ;; resulting in the entire build directory and its parent\n ;; directory also being deleted. Fun fun fun. (Now that I've\n ;; replaced `directory-files' with `straight--directory-files',\n ;; . and .. are no longer returned. But it's always good to be\n ;; paranoid with recursive deletes.)\n (unless (or (string-match-p \"^\\\\.\\\\.?$\" package)\n (gethash package straight--profile-cache))\n (delete-directory (straight--build-dir package) 'recursive))))\n\n;;;###autoload\n(defun straight-prune-build ()\n \"Prune the build cache and build directory.\nThis means that only packages that were built in the last init\nrun and subsequent interactive session will remain; other\npackages will have their build mtime information discarded and\ntheir build directories deleted.\"\n (interactive)\n (straight-prune-build-cache)\n (straight-prune-build-directory))\n\n;;;;; Normalization, pushing, pulling\n\n;;;###autoload\n(defun straight-normalize-package (package)\n \"Normalize a PACKAGE's local repository to its recipe's configuration.\nPACKAGE is a string naming a package. Interactively, select\nPACKAGE from the known packages in the current Emacs session\nusing `completing-read'.\"\n (interactive (list (straight--select-package \"Normalize package\"\n nil\n 'installed)))\n (let ((recipe (gethash package straight--recipe-cache)))\n (straight-vc-normalize recipe)))\n\n;;;###autoload\n(defun straight-normalize-all (&optional predicate)\n \"Normalize all packages. See `straight-normalize-package'.\nReturn a list of recipes for packages that were not successfully\nnormalized. If multiple packages come from the same local\nrepository, only one is normalized.\n\nPREDICATE, if provided, filters the packages that are normalized.\nIt is called with the package name as a string, and should return\nnon-nil if the package should actually be normalized.\"\n (interactive)\n (straight--map-existing-repos-interactively #'straight-normalize-package\n predicate))\n\n(defun straight--get-transitive-dependencies (package)\n \"Get the (transitive) dependencies of PACKAGE.\nPACKAGE should be a string naming a package. Return a list of\nstrings naming packages which are the dependencies, dependencies\nof dependencies, etc. of PACKAGE. The list includes PACKAGE\nitself. It is in no particular order.\"\n (straight--make-build-cache-available :nosave t)\n (let ((all-packages (make-hash-table :test #'equal))\n (unprocessed (make-hash-table :test #'equal)))\n (puthash package t unprocessed)\n (while (not (hash-table-empty-p unprocessed))\n (let* ((cur-package (car (hash-table-keys unprocessed)))\n (deps (nth 1 (gethash cur-package straight--build-cache))))\n (puthash cur-package t all-packages)\n (remhash cur-package unprocessed)\n (dolist (dep deps)\n (unless (gethash dep all-packages)\n (puthash dep t unprocessed)))))\n (hash-table-keys all-packages)))\n\n;;;###autoload\n(defun straight-fetch-package (package &optional from-upstream)\n \"Try to fetch a PACKAGE from the primary remote.\nPACKAGE is a string naming a package. Interactively, select\nPACKAGE from the known packages in the current Emacs session\nusing `completing-read'. With prefix argument FROM-UPSTREAM,\nfetch not just from primary remote but also from upstream (for\nforked packages).\"\n (interactive (list (straight--select-package \"Fetch package\" nil 'installed)\n current-prefix-arg))\n (let ((recipe (gethash package straight--recipe-cache)))\n (and (straight-vc-fetch-from-remote recipe)\n (when from-upstream\n (straight-vc-fetch-from-upstream recipe)))))\n\n;;;###autoload\n(defun straight-fetch-package-and-deps (package &optional from-upstream)\n \"Try to fetch a PACKAGE and its (transitive) dependencies.\nPACKAGE, its dependencies, their dependencies, etc. are fetched\nfrom their primary remotes.\n\nPACKAGE is a string naming a package. Interactively, select\nPACKAGE from the known packages in the current Emacs session\nusing `completing-read'. With prefix argument FROM-UPSTREAM,\nfetch not just from primary remote but also from upstream (for\nforked packages).\"\n (interactive (list (straight--select-package\n \"Fetch package and dependencies\" nil 'installed)\n current-prefix-arg))\n (let ((deps (make-hash-table :test #'equal)))\n (dolist (dep (straight--get-transitive-dependencies package))\n (puthash dep t deps))\n (straight--map-existing-repos-interactively\n (lambda (cur-package)\n (straight-fetch-package cur-package from-upstream))\n (lambda (cur-package)\n (gethash cur-package deps)))))\n\n;;;###autoload\n(defun straight-fetch-all (&optional from-upstream predicate)\n \"Try to fetch all packages from their primary remotes.\nWith prefix argument FROM-UPSTREAM, fetch not just from primary\nremotes but also from upstreams (for forked packages).\n\nReturn a list of recipes for packages that were not successfully\nfetched. If multiple packages come from the same local\nrepository, only one is fetched.\n\nPREDICATE, if provided, filters the packages that are fetched. It\nis called with the package name as a string, and should return\nnon-nil if the package should actually be fetched.\"\n (interactive \"P\")\n (straight--map-existing-repos-interactively\n (lambda (package)\n (straight-fetch-package package from-upstream))\n predicate))\n\n;;;###autoload\n(defun straight-merge-package (package &optional from-upstream)\n \"Try to merge a PACKAGE from the primary remote.\nPACKAGE is a string naming a package. Interactively, select\nPACKAGE from the known packages in the current Emacs session\nusing `completing-read'. With prefix argument FROM-UPSTREAM,\nmerge not just from primary remote but also from upstream (for\nforked packages).\"\n (interactive (list (straight--select-package \"Merge package\" nil 'installed)\n current-prefix-arg))\n (let ((recipe (gethash package straight--recipe-cache)))\n (and (straight-vc-merge-from-remote recipe)\n (when from-upstream\n (straight-vc-merge-from-upstream recipe)))))\n\n;;;###autoload\n(defun straight-merge-package-and-deps (package &optional from-upstream)\n \"Try to merge a PACKAGE and its (transitive) dependencies.\nPACKAGE, its dependencies, their dependencies, etc. are merged\nfrom their primary remotes.\n\nPACKAGE is a string naming a package. Interactively, select\nPACKAGE from the known packages in the current Emacs session\nusing `completing-read'. With prefix argument FROM-UPSTREAM,\nmerge not just from primary remote but also from upstream (for\nforked packages).\"\n (interactive (list (straight--select-package\n \"Merge package and dependencies\" nil 'installed)\n current-prefix-arg))\n (let ((deps (make-hash-table :test #'equal)))\n (dolist (dep (straight--get-transitive-dependencies package))\n (puthash dep t deps))\n (straight--map-existing-repos-interactively\n (lambda (cur-package)\n (straight-merge-package cur-package from-upstream))\n (lambda (cur-package)\n (gethash cur-package deps)))))\n\n;;;###autoload\n(defun straight-merge-all (&optional from-upstream predicate)\n \"Try to merge all packages from their primary remotes.\nWith prefix argument FROM-UPSTREAM, merge not just from primary\nremotes but also from upstreams (for forked packages).\n\nReturn a list of recipes for packages that were not successfully\nmerged. If multiple packages come from the same local\nrepository, only one is merged.\n\nPREDICATE, if provided, filters the packages that are merged. It\nis called with the package name as a string, and should return\nnon-nil if the package should actually be merged.\"\n (interactive \"P\")\n (straight--map-existing-repos-interactively\n (lambda (package)\n (straight-merge-package package from-upstream))\n predicate))\n\n;;;###autoload\n(defun straight-pull-package (package &optional from-upstream)\n \"Try to pull a PACKAGE from the primary remote.\nPACKAGE is a string naming a package. Interactively, select\nPACKAGE from the known packages in the current Emacs session\nusing `completing-read'. With prefix argument FROM-UPSTREAM, pull\nnot just from primary remote but also from upstream (for forked\npackages).\"\n (interactive (list (straight--select-package \"Pull package\" nil 'installed)\n current-prefix-arg))\n (let ((recipe (gethash package straight--recipe-cache)))\n (and (straight-vc-fetch-from-remote recipe)\n (straight-vc-merge-from-remote recipe)\n (when from-upstream\n (and (straight-vc-fetch-from-upstream recipe)\n (straight-vc-merge-from-upstream recipe))))))\n\n;;;###autoload\n(defun straight-pull-package-and-deps (package &optional from-upstream)\n \"Try to pull a PACKAGE and its (transitive) dependencies.\nPACKAGE, its dependencies, their dependencies, etc. are pulled\nfrom their primary remotes.\n\nPACKAGE is a string naming a package. Interactively, select\nPACKAGE from the known packages in the current Emacs session\nusing `completing-read'. With prefix argument FROM-UPSTREAM,\npull not just from primary remote but also from upstream (for\nforked packages).\"\n (interactive (list (straight--select-package\n \"Pull package and dependencies\" nil 'installed)\n current-prefix-arg))\n (let ((deps (make-hash-table :test #'equal)))\n (dolist (dep (straight--get-transitive-dependencies package))\n (puthash dep t deps))\n (straight--map-existing-repos-interactively\n (lambda (cur-package)\n (straight-pull-package cur-package from-upstream))\n (lambda (cur-package)\n (gethash cur-package deps)))))\n\n;;;###autoload\n(defun straight-pull-all (&optional from-upstream predicate)\n \"Try to pull all packages from their primary remotes.\nWith prefix argument FROM-UPSTREAM, pull not just from primary\nremotes but also from upstreams (for forked packages).\n\nReturn a list of recipes for packages that were not successfully\npulled. If multiple packages come from the same local repository,\nonly one is pulled.\n\nPREDICATE, if provided, filters the packages that are pulled. It\nis called with the package name as a string, and should return\nnon-nil if the package should actually be pulled.\"\n (interactive \"P\")\n (straight-fetch-all from-upstream predicate)\n (straight-merge-all from-upstream predicate))\n\n;;;###autoload\n(defun straight-push-package (package)\n \"Push a PACKAGE to its primary remote, if necessary.\nPACKAGE is a string naming a package. Interactively, select\nPACKAGE from the known packages in the current Emacs session\nusing `completing-read'.\"\n (interactive (list (straight--select-package \"Push package\" nil 'installed)))\n (let ((recipe (gethash package straight--recipe-cache)))\n (straight-vc-push-to-remote recipe)))\n\n;;;###autoload\n(defun straight-push-all (&optional predicate)\n \"Try to push all packages to their primary remotes.\n\nReturn a list of recipes for packages that were not successfully\npushed. If multiple packages come from the same local repository,\nonly one is pushed.\n\nPREDICATE, if provided, filters the packages that are normalized.\nIt is called with the package name as a string, and should return\nnon-nil if the package should actually be normalized.\"\n (interactive)\n (straight--map-existing-repos-interactively\n #'straight-push-package predicate))\n\n;;;;; Lockfile management\n\n(cl-defun straight--ensure-profile-cache-valid ()\n \"Ensure that `straight--profile-cache' reflects the init-file correctly.\nIf not, prompt the user to reload the init-file.\"\n (when straight--profile-cache-valid\n (cl-return-from straight--ensure-profile-cache-valid t))\n (unless (y-or-n-p \"Caches are outdated, reload init-file? \")\n (cl-return-from straight--ensure-profile-cache-valid nil))\n (straight--output \"Reloading %S...\" user-init-file)\n (load user-init-file nil 'nomessage)\n (straight--output \"Reloading %S...done\" user-init-file)\n (when straight--profile-cache-valid\n (cl-return-from straight--ensure-profile-cache-valid t))\n (error \"Caches are still outdated; something is seriously wrong\"))\n\n;;;###autoload\n(defun straight-freeze-versions (&optional force)\n \"Write version lockfiles for currently activated packages.\nThis implies first pushing all packages that have unpushed local\nchanges. If the package management system has been used since the\nlast time the init-file was reloaded, offer to fix the situation\nby reloading the init-file again. If FORCE is\nnon-nil (interactively, if a prefix argument is provided), skip\nall checks and write the lockfile anyway.\n\nCurrently, writing version lockfiles requires cloning all lazily\ninstalled packages. Hopefully, this inconvenient requirement will\nbe removed in the future.\n\nMultiple lockfiles may be written (one for each profile),\naccording to the value of `straight-profiles'.\"\n (interactive \"P\")\n (when (or force\n (progn\n (straight--ensure-profile-cache-valid)\n (let ((unpushed-recipes\n (straight-push-all\n (lambda (package)\n (let ((recipe\n (gethash package straight--recipe-cache)))\n (straight--with-plist recipe\n (local-repo)\n (and local-repo\n (straight--repository-is-available-p\n recipe))))))))\n (or\n (null unpushed-recipes)\n (straight-are-you-sure\n (format (concat \"The following packages were not pushed:\"\n \"\\n\\n %s\\n\\nReally write lockfiles?\")\n (string-join\n (mapcar (lambda (recipe)\n (plist-get recipe :local-repo))\n unpushed-recipes)\n \", \")))))))\n (straight--map-repos\n (lambda (recipe)\n (straight--with-plist recipe\n (local-repo package)\n (unless (or (null local-repo)\n (straight--repository-is-available-p recipe))\n (straight-use-package (intern package) nil 'no-build)))))\n (dolist (spec straight-profiles)\n (cl-destructuring-bind (profile . versions-lockfile) spec\n (let ((versions-alist nil)\n (lockfile-path (straight--versions-file versions-lockfile)))\n (straight--map-repos\n (lambda (recipe)\n (straight--with-plist recipe\n (package local-repo type)\n (when (and local-repo\n (memq profile\n (gethash package straight--profile-cache))\n (not (assoc local-repo versions-alist)))\n (when-let ((commit (straight-vc-get-commit type local-repo)))\n (push (cons local-repo commit) versions-alist))))))\n (setq versions-alist\n (cl-sort versions-alist #'string-lessp :key #'car))\n (make-directory (file-name-directory lockfile-path) 'parents)\n (with-temp-file lockfile-path\n (insert\n (format\n ;; When the recipe format is updated, this version\n ;; keyword will be updated. It tells install.el which\n ;; version of straight.el to use to interpret the recipe\n ;; that must be used to clone straight.el itself. I'm\n ;; using the Greek alphabet, for diversity (and\n ;; because using consecutive integers would make it\n ;; confusing when somebody else made a fork of the\n ;; project and needed to fork the version sequence as\n ;; well).\n ;;\n ;; The version keyword comes after the versions alist so\n ;; that you can ignore it if you don't need it.\n \"(%s)\\n:beta\\n\"\n (mapconcat\n (apply-partially #'format \"%S\")\n versions-alist\n \"\\n \"))))\n (straight--output \"Wrote %s\" lockfile-path))))))\n\n;;;###autoload\n(defun straight-thaw-versions ()\n \"Read version lockfiles and restore package versions to those listed.\"\n (interactive)\n (let ((versions-alist (straight--lockfile-read-all)))\n (straight--map-repos-interactively\n (lambda (package)\n (let ((recipe (gethash package straight--recipe-cache)))\n (when (straight--repository-is-available-p recipe)\n (straight--with-plist recipe\n (local-repo)\n ;; We can't use `alist-get' here because that uses\n ;; `eq', and our hash-table keys are strings.\n (when-let ((commit (cdr (assoc local-repo versions-alist))))\n (unless (straight-vc-commit-present-p recipe commit)\n (straight-vc-fetch-from-remote recipe))\n (straight-vc-check-out-commit recipe commit)))))))))\n\n;;;; Integration with other packages\n;;;;; package.el \"integration\"\n\n(defvaralias 'straight-\340\262\240_\340\262\240 'straight-enable-package-integration\n \"The alias expresses how I feel about package.el sometimes.\")\n\n(defcustom straight-enable-package-integration t\n \"Whether to enable \\\"integration\\\" with package.el.\nThis means that `package-enable-at-startup' is disabled, and\nadvices are put on `package--ensure-init-file' and\n`package--save-selected-packages' to prevent package.el from\nmodifying the init-file.\"\n :type 'boolean)\n\n;;;;;; Mode variables\n\n(defvar straight-package--last-enable-at-startup t\n \"Value of `package-enable-at-startup' at last mode toggle.\")\n\n;;;;;; Utility functions\n\n(defun straight-package-advice-ensure-init-file ()\n \"Prevent package.el from modifying the init-file.\n\nThis is an `:override' advice for `package--ensure-init-file'.\")\n\n(defun straight-package-advice-save-selected-packages (&optional value)\n \"Set and save `package-selected-packages' to VALUE.\nBut don't mess with the init-file.\n\nThis is an `:override' advice for `package--save-selected-packages'.\"\n (when value\n (setq package-selected-packages value)))\n\n;;;;;; Mode definition\n\n(define-minor-mode straight-package-neutering-mode\n \"Minor mode to neuter package.el by inhibiting some offensive features.\n\nThis mode is enabled or disabled automatically when straight.el\nis loaded, according to the value of\n`straight-enable-package-integration'.\"\n :global t\n :group 'straight\n (with-eval-after-load 'package\n (if straight-package-neutering-mode\n (progn\n (when (boundp 'package-enable-at-startup)\n (setq straight-package--last-enable-at-startup\n package-enable-at-startup))\n (setq package-enable-at-startup nil)\n (advice-add #'package--ensure-init-file :override\n #'straight-package-advice-ensure-init-file)\n (advice-add #'package--save-selected-packages :override\n #'straight-package-advice-save-selected-packages))\n (setq package-enable-at-startup\n straight-package--last-enable-at-startup)\n (advice-remove #'package--ensure-init-file\n #'straight-package-advice-ensure-init-file)\n (advice-remove #'package--save-selected-packages\n #'straight-package-advice-save-selected-packages))))\n\n(defalias 'straight-\340\262\240_\340\262\240-mode #'straight-package-neutering-mode\n \"The alias expresses how I feel about package.el sometimes.\")\n\n;;;;; use-package integration\n\n(defcustom straight-enable-use-package-integration t\n \"Whether to enable integration with `use-package'.\nSee `straight-use-package-version' for details.\"\n :type 'boolean)\n\n;;;;;; Mode variables\n\n(defcustom straight-use-package-version 'straight\n \"Symbol identifying the version of `use-package' in use.\n\nValue `ensure' is for older versions of `use-package' (before\ncommit 418e90c3 on Dec. 3, 2017). With this value, specifying a\nnon-nil value for `:ensure' in a `use-package' form causes the\npackage to be installed using straight.el. The value for\n`:ensure' can be t, meaning use the feature name as the package\nname; a symbol, meaning install that package; a plist, meaning\nuse the feature name as the package name and append the plist to\nform a custom recipe; and a list whose cdr is a plist, meaning\nuse it as the recipe. If `:ensure' is t and you provide a non-nil\nvalue for `:recipe', then that value is used instead. You can\ncause `:ensure' to receive a value of t unless otherwise\nspecified by setting `use-package-always-ensure' to a non-nil\nvalue.\n\nValue `straight' is for the current version of `use-package'.\nWith this value, specifying a non-nil value for `:straight' in a\n`use-package' form causes the package to be installed using\nstraight.el. The value for `:straight' can be t, which is\nreplaced with the feature name; a symbol, which is used as is; a\nplist, which is prepended with the feature name; or a list whose\ncdr is a plist, which is used as is.\"\n :type '(choice\n (const :tag \"Classic (uses `:ensure' for all package managers)\"\n ensure)\n (const :tag \"Modern (uses `:package', `:straight', etc.)\" straight)))\n\n(defvar straight-use-package--last-version nil\n \"Value of `straight-use-package-version' at last mode toggle.\")\n\n(defcustom straight-use-package-by-default nil\n \"Non-nil means install packages by default in `use-package' forms.\nThis only works when `straight-use-package-version' is\n`straight'. When `straight-use-package-version' is `ensure', use\n`use-package-always-ensure' instead.\"\n :type 'boolean)\n\n;;;;;; Utility functions\n\n(defun straight-use-package-ensure-function\n (name ensure state &optional context)\n \"Value for `use-package-ensure-function' to use straight.el.\nThis is used for integration with `use-package' when\n`straight-use-package-version' is `ensure'. NAME is a symbol\nnaming the feature for the `use-package' form in question; ENSURE\nis the form passed to the `:ensure' keyword (a symbol or list);\nSTATE is the internal plist used during `use-package' expansion.\nIn older versions of `use-package' (before commit 93bf693b on\nDec. 1, 2017), an additional argument CONTEXT was passed. This\nargument was used to identify whether package installation should\nhappen or not, and whether the user should be prompted before\ndoing it. When CONTEXT is not passed, straight.el has no way of\ndeciding and instead just installs the package unconditionally.\"\n (when ensure\n (straight-use-package\n (or (and (not (eq ensure t)) ensure)\n (plist-get state :recipe)\n name)\n (lambda (package available)\n (cond\n ;; If available, go ahead.\n (available nil)\n ;; When doing lazy installation, don't clone if not\n ;; available.\n ((eq context :pre-ensure) t)\n ;; In cases where installation should be automatic, do\n ;; it.\n ((memq context '(:byte-compile :ensure\n :config :pre-ensure\n :interactive nil))\n nil)\n ;; Otherwise, prompt the user.\n (t (not (y-or-n-p (format \"Install package %S? \" package)))))))))\n\n(defun straight-use-package-pre-ensure-function\n (name ensure state)\n \"Value for `use-package-pre-ensure-function' to use straight.el.\nThe meanings of NAME, ENSURE, and STATE are the same as in\n`straight-use-package-ensure-function'.\"\n (straight-use-package-ensure-function\n name ensure state :pre-ensure))\n\n(defvar straight-use-package--last-ensure-function nil\n \"Value of `use-package-ensure-function' at last mode toggle.\")\n\n(defvar straight-use-package--last-pre-ensure-function nil\n \"Value of `use-package-pre-ensure-function' at last mode toggle.\")\n\n(defun straight-use-package--ensure-normalizer\n (name-symbol keyword args)\n \"Normalizer for `:ensure' and `:recipe' in `use-package' forms.\nNAME-SYMBOL, KEYWORD, and ARGS are explained by the `use-package'\ndocumentation.\"\n (use-package-only-one (symbol-name keyword) args\n (lambda (_label arg)\n (if (keywordp (car-safe arg))\n (cons name-symbol arg)\n arg))))\n\n(defun straight-use-package--recipe-handler\n (name _keyword recipe rest state)\n \"Handler for `:recipe' in `use-package' forms.\nNAME, KEYWORD, RECIPE, REST, and STATE are explained by the\n`use-package' documentation.\"\n (use-package-process-keywords\n name rest (plist-put state :recipe recipe)))\n\n(defun straight-use-package--straight-normalizer\n (name-symbol _keyword args)\n \"Normalizer for `:straight' in `use-package' forms.\nNAME-SYMBOL, KEYWORD, and ARGS are explained by the `use-package'\ndocumentation.\"\n (let ((parsed-args nil))\n (dolist (arg args)\n (cond\n ((null arg) (setq parsed-args nil))\n ((eq arg t) (push name-symbol parsed-args))\n ((symbolp arg) (push arg parsed-args))\n ((not (listp arg))\n (use-package-error \":straight wants a symbol or list\"))\n ((keywordp (car arg))\n ;; recipe without package name\n (push (cons name-symbol arg) parsed-args))\n ((cl-some #'keywordp arg)\n ;; assume it's a recipe\n (push arg parsed-args))\n (t\n (setq parsed-args\n (append (straight-use-package--straight-normalizer\n name-symbol nil arg)\n parsed-args)))))\n parsed-args))\n\n(defun straight-use-package--straight-handler\n (name _keyword args rest state)\n \"Handler for `:straight' in `use-package' forms.\nNAME, KEYWORD, ARGS, REST, and STATE are explained by the\n`use-package' documentation.\"\n ;; Disable `:ensure' when `:straight' is present. This part only\n ;; works when `:straight' is processed before `:ensure'. See below\n ;; for the other case.\n ;;\n ;; See .\n (when args\n (straight--remq rest '(:ensure)))\n (let ((body (use-package-process-keywords name rest state)))\n (mapc (lambda (arg)\n (push `(straight-use-package\n ;; The following is an unfortunate hack because\n ;; `use-package-defaults' currently operates on\n ;; the post-normalization values, rather than the\n ;; pre-normalization ones.\n ',(if (eq arg t)\n name arg))\n body))\n args)\n body))\n\n(defun straight-use-package--ensure-handler-advice\n (handler name keyword args rest state)\n \"Advice for `:ensure' handler in `use-package' forms.\nHANDLER is the original handler function. NAME, KEYWORD, ARGS,\nREST, and STATE are explained by the `use-package' documentation.\n\nDisables `:ensure' when `:straight' is present. This part only\nworks when `:ensure' is processed before `:straight'. See above\nfor the other case.\"\n (if (plist-get rest :straight)\n (use-package-process-keywords name rest state)\n (funcall handler name keyword args rest state)))\n\n;;;;;; Mode definition\n\n(define-minor-mode straight-use-package-mode\n \"Minor mode to enable `use-package' support in straight.el.\nThe behavior is controlled by variables\n`straight-use-package-version' and\n`straight-use-package-by-default'. If these variables are\nchanged, you must toggle the mode function to update the\nintegration.\n\nThis mode is enabled or disabled automatically when straight.el\nis loaded, according to the value of\n`straight-enable-use-package-integration'.\"\n :global t\n :group 'straight\n (pcase straight-use-package--last-version\n (`ensure\n (with-eval-after-load 'use-package\n (when (and (boundp 'use-package-ensure-function)\n (eq use-package-ensure-function\n #'straight-use-package-ensure-function)\n straight-use-package--last-ensure-function)\n (setq use-package-ensure-function\n straight-use-package--last-ensure-function))\n (when (and (boundp 'use-package-pre-ensure-function)\n (eq use-package-pre-ensure-function\n #'straight-use-package-pre-ensure-function)\n straight-use-package--last-pre-ensure-function)\n (setq use-package-pre-ensure-function\n straight-use-package--last-pre-ensure-function))\n (when (and (boundp 'use-package-keywords)\n (listp use-package-keywords))\n (setq use-package-keywords (remq :recipe use-package-keywords)))\n (fmakunbound 'use-package-normalize/:recipe)\n (fmakunbound 'use-package-handler/:recipe)\n (advice-remove #'use-package-normalize/:ensure\n #'straight-use-package--ensure-normalizer)))\n (`straight\n (with-eval-after-load 'use-package-core\n (when (and (boundp 'use-package-keywords)\n (listp use-package-keywords))\n (setq use-package-keywords (remq :straight use-package-keywords)))\n (fmakunbound 'use-package-normalize/:straight)\n (fmakunbound 'use-package-handler/:straight)\n (advice-remove #'use-package-handler/:ensure\n #'straight-use-package--ensure-handler-advice)\n (when (and (boundp 'use-package-defaults)\n (listp use-package-defaults))\n (setq use-package-defaults\n (assq-delete-all :straight use-package-defaults))))))\n (setq straight-use-package--last-version nil)\n (when straight-use-package-mode\n (setq straight-use-package--last-version straight-use-package-version)\n (pcase straight-use-package-version\n (`ensure\n (with-eval-after-load 'use-package\n (when (boundp 'use-package-ensure-function)\n (setq straight-use-package--last-ensure-function\n use-package-ensure-function))\n (setq use-package-ensure-function\n #'straight-use-package-ensure-function)\n (when (boundp 'use-package-pre-ensure-function)\n (setq straight-use-package--last-pre-ensure-function\n use-package-pre-ensure-function))\n (setq use-package-pre-ensure-function\n #'straight-use-package-pre-ensure-function)\n (when (and (boundp 'use-package-keywords)\n (listp use-package-keywords)\n (memq :ensure use-package-keywords))\n (unless (memq :recipe use-package-keywords)\n (setq use-package-keywords\n (let* ((pos (cl-position :ensure use-package-keywords))\n (head (cl-subseq use-package-keywords 0 pos))\n (tail (cl-subseq use-package-keywords pos)))\n (append head (list :recipe) tail)))))\n (defalias 'use-package-normalize/:recipe\n #'straight-use-package--ensure-normalizer)\n (defalias 'use-package-handler/:recipe\n #'straight-use-package--recipe-handler)\n (advice-add #'use-package-normalize/:ensure :override\n #'straight-use-package--ensure-normalizer)))\n (`straight\n (with-eval-after-load 'use-package-core\n (when (and (boundp 'use-package-keywords)\n (listp use-package-keywords))\n (push :straight use-package-keywords))\n (defalias 'use-package-normalize/:straight\n #'straight-use-package--straight-normalizer)\n (defalias 'use-package-handler/:straight\n #'straight-use-package--straight-handler)\n (advice-add #'use-package-handler/:ensure :around\n #'straight-use-package--ensure-handler-advice)\n (when (and (boundp 'use-package-defaults)\n (listp use-package-defaults))\n (setq use-package-defaults (straight--alist-set\n :straight\n '('(t) straight-use-package-by-default)\n use-package-defaults\n 'symbol))))))))\n\n;;;;; Org integration\n\n(defcustom straight-fix-org t\n \"If non-nil, install a workaround for a problem with Org.\nSee for\ndiscussion.\n\nThis variable must be set before straight.el is loaded in order\nto take effect.\"\n :type 'boolean)\n\n(defun straight--fix-org-function (package &rest _)\n \"Pre-build function to fix Org. See `straight-fix-org'.\nPACKAGE is the name of the package being built, as a string.\n\nThis function is for use on the hook\n`straight-use-package-pre-build-functions'.\"\n (when (member package '(\"org\" \"org-plus-contrib\"))\n\n (defun org-git-version ()\n \"The Git version of org-mode.\nInserted by installing org-mode or when a release is made.\"\n (let ((default-directory (straight--repos-dir \"org\")))\n (string-trim\n (with-output-to-string\n (with-current-buffer standard-output\n (call-process\n \"git\" nil t nil\n \"describe\"\n \"--match=release*\"\n \"--abbrev=6\"\n \"HEAD\"))))))\n\n (defun org-release ()\n \"The release version of org-mode.\nInserted by installing org-mode or when a release is made.\"\n (let ((default-directory (straight--repos-dir \"org\")))\n (string-trim\n (string-remove-prefix\n \"release_\"\n (with-output-to-string\n (with-current-buffer standard-output\n (call-process\n \"git\" nil t nil\n \"describe\"\n \"--match=release*\"\n \"--abbrev=0\"\n \"HEAD\")))))))\n\n (provide 'org-version)))\n\n(if straight-fix-org\n (add-hook 'straight-use-package-prepare-functions\n #'straight--fix-org-function)\n (remove-hook 'straight-use-package-prepare-functions\n #'straight--fix-org-function))\n\n;;;; Closing remarks\n\n(provide 'straight)\n\n;;; straight.el ends here\n\n;; Local Variables:\n;; checkdoc-symbol-words: (\"byte-compile\" \"top-level\")\n;; checkdoc-verb-check-experimental-flag: nil\n;; indent-tabs-mode: nil\n;; outline-regexp: \";;;;* \"\n;; End:\n"